xref: /rk3399_rockchip-uboot/fs/ext4/ext4fs.c (revision ed34f34dbaf206dfe223f4bc2147d600fe1b0f58)
1a1596438SUma Shankar /*
2a1596438SUma Shankar  * (C) Copyright 2011 - 2012 Samsung Electronics
3a1596438SUma Shankar  * EXT4 filesystem implementation in Uboot by
4a1596438SUma Shankar  * Uma Shankar <uma.shankar@samsung.com>
5a1596438SUma Shankar  * Manjunatha C Achar <a.manjunatha@samsung.com>
6a1596438SUma Shankar  *
7a1596438SUma Shankar  * ext4ls and ext4load : Based on ext2 ls and load support in Uboot.
8a1596438SUma Shankar  *		       Ext4 read optimization taken from Open-Moko
9a1596438SUma Shankar  *		       Qi bootloader
10a1596438SUma Shankar  *
11a1596438SUma Shankar  * (C) Copyright 2004
12a1596438SUma Shankar  * esd gmbh <www.esd-electronics.com>
13a1596438SUma Shankar  * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
14a1596438SUma Shankar  *
15a1596438SUma Shankar  * based on code from grub2 fs/ext2.c and fs/fshelp.c by
16a1596438SUma Shankar  * GRUB  --  GRand Unified Bootloader
17a1596438SUma Shankar  * Copyright (C) 2003, 2004  Free Software Foundation, Inc.
18a1596438SUma Shankar  *
19*ed34f34dSUma Shankar  * ext4write : Based on generic ext4 protocol.
20*ed34f34dSUma Shankar  *
21a1596438SUma Shankar  * This program is free software; you can redistribute it and/or modify
22a1596438SUma Shankar  * it under the terms of the GNU General Public License as published by
23a1596438SUma Shankar  * the Free Software Foundation; either version 2 of the License, or
24a1596438SUma Shankar  * (at your option) any later version.
25a1596438SUma Shankar  *
26a1596438SUma Shankar  * This program is distributed in the hope that it will be useful,
27a1596438SUma Shankar  * but WITHOUT ANY WARRANTY; without even the implied warranty of
28a1596438SUma Shankar  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
29a1596438SUma Shankar  * GNU General Public License for more details.
30a1596438SUma Shankar  *
31a1596438SUma Shankar  * You should have received a copy of the GNU General Public License
32a1596438SUma Shankar  * along with this program; if not, write to the Free Software
33a1596438SUma Shankar  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
34a1596438SUma Shankar  */
35a1596438SUma Shankar 
36a1596438SUma Shankar #include <common.h>
37a1596438SUma Shankar #include <malloc.h>
38a1596438SUma Shankar #include <ext_common.h>
39a1596438SUma Shankar #include <ext4fs.h>
40a1596438SUma Shankar #include <linux/stat.h>
41a1596438SUma Shankar #include <linux/time.h>
42a1596438SUma Shankar #include <asm/byteorder.h>
43a1596438SUma Shankar #include "ext4_common.h"
44a1596438SUma Shankar 
45a1596438SUma Shankar int ext4fs_symlinknest;
46a1596438SUma Shankar block_dev_desc_t *ext4_dev_desc;
47a1596438SUma Shankar 
48a1596438SUma Shankar struct ext_filesystem *get_fs(void)
49a1596438SUma Shankar {
50a1596438SUma Shankar 	if (ext4_dev_desc == NULL || ext4_dev_desc->priv == NULL)
51a1596438SUma Shankar 		printf("Invalid Input Arguments %s\n", __func__);
52a1596438SUma Shankar 
53a1596438SUma Shankar 	return ext4_dev_desc->priv;
54a1596438SUma Shankar }
55a1596438SUma Shankar 
56a1596438SUma Shankar int init_fs(block_dev_desc_t *dev_desc)
57a1596438SUma Shankar {
58a1596438SUma Shankar 	struct ext_filesystem *fs;
59a1596438SUma Shankar 	if (dev_desc == NULL) {
60a1596438SUma Shankar 		printf("Invalid Input Arguments %s\n", __func__);
61a1596438SUma Shankar 		return -EINVAL;
62a1596438SUma Shankar 	}
63a1596438SUma Shankar 
64a1596438SUma Shankar 	fs = zalloc(sizeof(struct ext_filesystem));
65a1596438SUma Shankar 	if (fs == NULL) {
66a1596438SUma Shankar 		printf("malloc failed: %s\n", __func__);
67a1596438SUma Shankar 		return -ENOMEM;
68a1596438SUma Shankar 	}
69a1596438SUma Shankar 
70a1596438SUma Shankar 	fs->dev_desc = dev_desc;
71a1596438SUma Shankar 	dev_desc->priv = fs;
72a1596438SUma Shankar 
73a1596438SUma Shankar 	return 0;
74a1596438SUma Shankar }
75a1596438SUma Shankar 
76a1596438SUma Shankar void deinit_fs(block_dev_desc_t *dev_desc)
77a1596438SUma Shankar {
78a1596438SUma Shankar 	if (dev_desc == NULL) {
79a1596438SUma Shankar 		printf("Invalid Input Arguments %s\n", __func__);
80a1596438SUma Shankar 		return;
81a1596438SUma Shankar 	}
82a1596438SUma Shankar 	free(dev_desc->priv);
83a1596438SUma Shankar 	dev_desc->priv = NULL;
84a1596438SUma Shankar }
85a1596438SUma Shankar 
86a1596438SUma Shankar void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot)
87a1596438SUma Shankar {
88a1596438SUma Shankar 	if ((node != &ext4fs_root->diropen) && (node != currroot))
89a1596438SUma Shankar 		free(node);
90a1596438SUma Shankar }
91a1596438SUma Shankar 
92a1596438SUma Shankar /*
93a1596438SUma Shankar  * Taken from openmoko-kernel mailing list: By Andy green
94a1596438SUma Shankar  * Optimized read file API : collects and defers contiguous sector
95a1596438SUma Shankar  * reads into one potentially more efficient larger sequential read action
96a1596438SUma Shankar  */
97a1596438SUma Shankar int ext4fs_read_file(struct ext2fs_node *node, int pos,
98a1596438SUma Shankar 		unsigned int len, char *buf)
99a1596438SUma Shankar {
100a1596438SUma Shankar 	int i;
101a1596438SUma Shankar 	int blockcnt;
102a1596438SUma Shankar 	int log2blocksize = LOG2_EXT2_BLOCK_SIZE(node->data);
103a1596438SUma Shankar 	int blocksize = 1 << (log2blocksize + DISK_SECTOR_BITS);
104a1596438SUma Shankar 	unsigned int filesize = __le32_to_cpu(node->inode.size);
105a1596438SUma Shankar 	int previous_block_number = -1;
106a1596438SUma Shankar 	int delayed_start = 0;
107a1596438SUma Shankar 	int delayed_extent = 0;
108a1596438SUma Shankar 	int delayed_skipfirst = 0;
109a1596438SUma Shankar 	int delayed_next = 0;
110a1596438SUma Shankar 	char *delayed_buf = NULL;
111a1596438SUma Shankar 	short status;
112a1596438SUma Shankar 
113a1596438SUma Shankar 	/* Adjust len so it we can't read past the end of the file. */
114a1596438SUma Shankar 	if (len > filesize)
115a1596438SUma Shankar 		len = filesize;
116a1596438SUma Shankar 
117a1596438SUma Shankar 	blockcnt = ((len + pos) + blocksize - 1) / blocksize;
118a1596438SUma Shankar 
119a1596438SUma Shankar 	for (i = pos / blocksize; i < blockcnt; i++) {
120a1596438SUma Shankar 		int blknr;
121a1596438SUma Shankar 		int blockoff = pos % blocksize;
122a1596438SUma Shankar 		int blockend = blocksize;
123a1596438SUma Shankar 		int skipfirst = 0;
124a1596438SUma Shankar 		blknr = read_allocated_block(&(node->inode), i);
125a1596438SUma Shankar 		if (blknr < 0)
126a1596438SUma Shankar 			return -1;
127a1596438SUma Shankar 
128a1596438SUma Shankar 		blknr = blknr << log2blocksize;
129a1596438SUma Shankar 
130a1596438SUma Shankar 		/* Last block.  */
131a1596438SUma Shankar 		if (i == blockcnt - 1) {
132a1596438SUma Shankar 			blockend = (len + pos) % blocksize;
133a1596438SUma Shankar 
134a1596438SUma Shankar 			/* The last portion is exactly blocksize. */
135a1596438SUma Shankar 			if (!blockend)
136a1596438SUma Shankar 				blockend = blocksize;
137a1596438SUma Shankar 		}
138a1596438SUma Shankar 
139a1596438SUma Shankar 		/* First block. */
140a1596438SUma Shankar 		if (i == pos / blocksize) {
141a1596438SUma Shankar 			skipfirst = blockoff;
142a1596438SUma Shankar 			blockend -= skipfirst;
143a1596438SUma Shankar 		}
144a1596438SUma Shankar 		if (blknr) {
145a1596438SUma Shankar 			int status;
146a1596438SUma Shankar 
147a1596438SUma Shankar 			if (previous_block_number != -1) {
148a1596438SUma Shankar 				if (delayed_next == blknr) {
149a1596438SUma Shankar 					delayed_extent += blockend;
150a1596438SUma Shankar 					delayed_next += blockend >> SECTOR_BITS;
151a1596438SUma Shankar 				} else {	/* spill */
152a1596438SUma Shankar 					status = ext4fs_devread(delayed_start,
153a1596438SUma Shankar 							delayed_skipfirst,
154a1596438SUma Shankar 							delayed_extent,
155a1596438SUma Shankar 							delayed_buf);
156a1596438SUma Shankar 					if (status == 0)
157a1596438SUma Shankar 						return -1;
158a1596438SUma Shankar 					previous_block_number = blknr;
159a1596438SUma Shankar 					delayed_start = blknr;
160a1596438SUma Shankar 					delayed_extent = blockend;
161a1596438SUma Shankar 					delayed_skipfirst = skipfirst;
162a1596438SUma Shankar 					delayed_buf = buf;
163a1596438SUma Shankar 					delayed_next = blknr +
164a1596438SUma Shankar 						(blockend >> SECTOR_BITS);
165a1596438SUma Shankar 				}
166a1596438SUma Shankar 			} else {
167a1596438SUma Shankar 				previous_block_number = blknr;
168a1596438SUma Shankar 				delayed_start = blknr;
169a1596438SUma Shankar 				delayed_extent = blockend;
170a1596438SUma Shankar 				delayed_skipfirst = skipfirst;
171a1596438SUma Shankar 				delayed_buf = buf;
172a1596438SUma Shankar 				delayed_next = blknr +
173a1596438SUma Shankar 					(blockend >> SECTOR_BITS);
174a1596438SUma Shankar 			}
175a1596438SUma Shankar 		} else {
176a1596438SUma Shankar 			if (previous_block_number != -1) {
177a1596438SUma Shankar 				/* spill */
178a1596438SUma Shankar 				status = ext4fs_devread(delayed_start,
179a1596438SUma Shankar 							delayed_skipfirst,
180a1596438SUma Shankar 							delayed_extent,
181a1596438SUma Shankar 							delayed_buf);
182a1596438SUma Shankar 				if (status == 0)
183a1596438SUma Shankar 					return -1;
184a1596438SUma Shankar 				previous_block_number = -1;
185a1596438SUma Shankar 			}
186a1596438SUma Shankar 			memset(buf, 0, blocksize - skipfirst);
187a1596438SUma Shankar 		}
188a1596438SUma Shankar 		buf += blocksize - skipfirst;
189a1596438SUma Shankar 	}
190a1596438SUma Shankar 	if (previous_block_number != -1) {
191a1596438SUma Shankar 		/* spill */
192a1596438SUma Shankar 		status = ext4fs_devread(delayed_start,
193a1596438SUma Shankar 					delayed_skipfirst, delayed_extent,
194a1596438SUma Shankar 					delayed_buf);
195a1596438SUma Shankar 		if (status == 0)
196a1596438SUma Shankar 			return -1;
197a1596438SUma Shankar 		previous_block_number = -1;
198a1596438SUma Shankar 	}
199a1596438SUma Shankar 
200a1596438SUma Shankar 	return len;
201a1596438SUma Shankar }
202a1596438SUma Shankar 
203a1596438SUma Shankar int ext4fs_ls(const char *dirname)
204a1596438SUma Shankar {
205a1596438SUma Shankar 	struct ext2fs_node *dirnode;
206a1596438SUma Shankar 	int status;
207a1596438SUma Shankar 
208a1596438SUma Shankar 	if (dirname == NULL)
209a1596438SUma Shankar 		return 0;
210a1596438SUma Shankar 
211a1596438SUma Shankar 	status = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode,
212a1596438SUma Shankar 				  FILETYPE_DIRECTORY);
213a1596438SUma Shankar 	if (status != 1) {
214a1596438SUma Shankar 		printf("** Can not find directory. **\n");
215a1596438SUma Shankar 		return 1;
216a1596438SUma Shankar 	}
217a1596438SUma Shankar 
218a1596438SUma Shankar 	ext4fs_iterate_dir(dirnode, NULL, NULL, NULL);
219a1596438SUma Shankar 	ext4fs_free_node(dirnode, &ext4fs_root->diropen);
220a1596438SUma Shankar 
221a1596438SUma Shankar 	return 0;
222a1596438SUma Shankar }
223a1596438SUma Shankar 
224a1596438SUma Shankar int ext4fs_read(char *buf, unsigned len)
225a1596438SUma Shankar {
226a1596438SUma Shankar 	if (ext4fs_root == NULL || ext4fs_file == NULL)
227a1596438SUma Shankar 		return 0;
228a1596438SUma Shankar 
229a1596438SUma Shankar 	return ext4fs_read_file(ext4fs_file, 0, len, buf);
230a1596438SUma Shankar }
231*ed34f34dSUma Shankar 
232*ed34f34dSUma Shankar #if defined(CONFIG_CMD_EXT4_WRITE)
233*ed34f34dSUma Shankar static void ext4fs_update(void)
234*ed34f34dSUma Shankar {
235*ed34f34dSUma Shankar 	short i;
236*ed34f34dSUma Shankar 	ext4fs_update_journal();
237*ed34f34dSUma Shankar 	struct ext_filesystem *fs = get_fs();
238*ed34f34dSUma Shankar 
239*ed34f34dSUma Shankar 	/* update  super block */
240*ed34f34dSUma Shankar 	put_ext4((uint64_t)(SUPERBLOCK_SIZE),
241*ed34f34dSUma Shankar 		 (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
242*ed34f34dSUma Shankar 
243*ed34f34dSUma Shankar 	/* update block groups */
244*ed34f34dSUma Shankar 	for (i = 0; i < fs->no_blkgrp; i++) {
245*ed34f34dSUma Shankar 		fs->gd[i].bg_checksum = ext4fs_checksum_update(i);
246*ed34f34dSUma Shankar 		put_ext4((uint64_t)(fs->gd[i].block_id * fs->blksz),
247*ed34f34dSUma Shankar 			 fs->blk_bmaps[i], fs->blksz);
248*ed34f34dSUma Shankar 	}
249*ed34f34dSUma Shankar 
250*ed34f34dSUma Shankar 	/* update inode table groups */
251*ed34f34dSUma Shankar 	for (i = 0; i < fs->no_blkgrp; i++) {
252*ed34f34dSUma Shankar 		put_ext4((uint64_t) (fs->gd[i].inode_id * fs->blksz),
253*ed34f34dSUma Shankar 			 fs->inode_bmaps[i], fs->blksz);
254*ed34f34dSUma Shankar 	}
255*ed34f34dSUma Shankar 
256*ed34f34dSUma Shankar 	/* update the block group descriptor table */
257*ed34f34dSUma Shankar 	put_ext4((uint64_t)(fs->gdtable_blkno * fs->blksz),
258*ed34f34dSUma Shankar 		 (struct ext2_block_group *)fs->gdtable,
259*ed34f34dSUma Shankar 		 (fs->blksz * fs->no_blk_pergdt));
260*ed34f34dSUma Shankar 
261*ed34f34dSUma Shankar 	ext4fs_dump_metadata();
262*ed34f34dSUma Shankar 
263*ed34f34dSUma Shankar 	gindex = 0;
264*ed34f34dSUma Shankar 	gd_index = 0;
265*ed34f34dSUma Shankar }
266*ed34f34dSUma Shankar 
267*ed34f34dSUma Shankar int ext4fs_get_bgdtable(void)
268*ed34f34dSUma Shankar {
269*ed34f34dSUma Shankar 	int status;
270*ed34f34dSUma Shankar 	int grp_desc_size;
271*ed34f34dSUma Shankar 	struct ext_filesystem *fs = get_fs();
272*ed34f34dSUma Shankar 	grp_desc_size = sizeof(struct ext2_block_group);
273*ed34f34dSUma Shankar 	fs->no_blk_pergdt = (fs->no_blkgrp * grp_desc_size) / fs->blksz;
274*ed34f34dSUma Shankar 	if ((fs->no_blkgrp * grp_desc_size) % fs->blksz)
275*ed34f34dSUma Shankar 		fs->no_blk_pergdt++;
276*ed34f34dSUma Shankar 
277*ed34f34dSUma Shankar 	/* allocate memory for gdtable */
278*ed34f34dSUma Shankar 	fs->gdtable = zalloc(fs->blksz * fs->no_blk_pergdt);
279*ed34f34dSUma Shankar 	if (!fs->gdtable)
280*ed34f34dSUma Shankar 		return -ENOMEM;
281*ed34f34dSUma Shankar 	/* read the group descriptor table */
282*ed34f34dSUma Shankar 	status = ext4fs_devread(fs->gdtable_blkno * fs->sect_perblk, 0,
283*ed34f34dSUma Shankar 				fs->blksz * fs->no_blk_pergdt, fs->gdtable);
284*ed34f34dSUma Shankar 	if (status == 0)
285*ed34f34dSUma Shankar 		goto fail;
286*ed34f34dSUma Shankar 
287*ed34f34dSUma Shankar 	if (ext4fs_log_gdt(fs->gdtable)) {
288*ed34f34dSUma Shankar 		printf("Error in ext4fs_log_gdt\n");
289*ed34f34dSUma Shankar 		return -1;
290*ed34f34dSUma Shankar 	}
291*ed34f34dSUma Shankar 
292*ed34f34dSUma Shankar 	return 0;
293*ed34f34dSUma Shankar fail:
294*ed34f34dSUma Shankar 	free(fs->gdtable);
295*ed34f34dSUma Shankar 	fs->gdtable = NULL;
296*ed34f34dSUma Shankar 
297*ed34f34dSUma Shankar 	return -1;
298*ed34f34dSUma Shankar }
299*ed34f34dSUma Shankar 
300*ed34f34dSUma Shankar static void delete_single_indirect_block(struct ext2_inode *inode)
301*ed34f34dSUma Shankar {
302*ed34f34dSUma Shankar 	struct ext2_block_group *gd = NULL;
303*ed34f34dSUma Shankar 	static int prev_bg_bmap_idx = -1;
304*ed34f34dSUma Shankar 	long int blknr;
305*ed34f34dSUma Shankar 	int remainder;
306*ed34f34dSUma Shankar 	int bg_idx;
307*ed34f34dSUma Shankar 	int status;
308*ed34f34dSUma Shankar 	unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
309*ed34f34dSUma Shankar 	struct ext_filesystem *fs = get_fs();
310*ed34f34dSUma Shankar 	char *journal_buffer = zalloc(fs->blksz);
311*ed34f34dSUma Shankar 	if (!journal_buffer) {
312*ed34f34dSUma Shankar 		printf("No memory\n");
313*ed34f34dSUma Shankar 		return;
314*ed34f34dSUma Shankar 	}
315*ed34f34dSUma Shankar 	/* get  block group descriptor table */
316*ed34f34dSUma Shankar 	gd = (struct ext2_block_group *)fs->gdtable;
317*ed34f34dSUma Shankar 
318*ed34f34dSUma Shankar 	/* deleting the single indirect block associated with inode */
319*ed34f34dSUma Shankar 	if (inode->b.blocks.indir_block != 0) {
320*ed34f34dSUma Shankar 		debug("SIPB releasing %u\n", inode->b.blocks.indir_block);
321*ed34f34dSUma Shankar 		blknr = inode->b.blocks.indir_block;
322*ed34f34dSUma Shankar 		if (fs->blksz != 1024) {
323*ed34f34dSUma Shankar 			bg_idx = blknr / blk_per_grp;
324*ed34f34dSUma Shankar 		} else {
325*ed34f34dSUma Shankar 			bg_idx = blknr / blk_per_grp;
326*ed34f34dSUma Shankar 			remainder = blknr % blk_per_grp;
327*ed34f34dSUma Shankar 			if (!remainder)
328*ed34f34dSUma Shankar 				bg_idx--;
329*ed34f34dSUma Shankar 		}
330*ed34f34dSUma Shankar 		ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
331*ed34f34dSUma Shankar 		gd[bg_idx].free_blocks++;
332*ed34f34dSUma Shankar 		fs->sb->free_blocks++;
333*ed34f34dSUma Shankar 		/* journal backup */
334*ed34f34dSUma Shankar 		if (prev_bg_bmap_idx != bg_idx) {
335*ed34f34dSUma Shankar 			status =
336*ed34f34dSUma Shankar 			    ext4fs_devread(gd[bg_idx].block_id *
337*ed34f34dSUma Shankar 					   fs->sect_perblk, 0, fs->blksz,
338*ed34f34dSUma Shankar 					   journal_buffer);
339*ed34f34dSUma Shankar 			if (status == 0)
340*ed34f34dSUma Shankar 				goto fail;
341*ed34f34dSUma Shankar 			if (ext4fs_log_journal
342*ed34f34dSUma Shankar 			    (journal_buffer, gd[bg_idx].block_id))
343*ed34f34dSUma Shankar 				goto fail;
344*ed34f34dSUma Shankar 			prev_bg_bmap_idx = bg_idx;
345*ed34f34dSUma Shankar 		}
346*ed34f34dSUma Shankar 	}
347*ed34f34dSUma Shankar fail:
348*ed34f34dSUma Shankar 	free(journal_buffer);
349*ed34f34dSUma Shankar }
350*ed34f34dSUma Shankar 
351*ed34f34dSUma Shankar static void delete_double_indirect_block(struct ext2_inode *inode)
352*ed34f34dSUma Shankar {
353*ed34f34dSUma Shankar 	int i;
354*ed34f34dSUma Shankar 	short status;
355*ed34f34dSUma Shankar 	static int prev_bg_bmap_idx = -1;
356*ed34f34dSUma Shankar 	long int blknr;
357*ed34f34dSUma Shankar 	int remainder;
358*ed34f34dSUma Shankar 	int bg_idx;
359*ed34f34dSUma Shankar 	unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
360*ed34f34dSUma Shankar 	unsigned int *di_buffer = NULL;
361*ed34f34dSUma Shankar 	unsigned int *DIB_start_addr = NULL;
362*ed34f34dSUma Shankar 	struct ext2_block_group *gd = NULL;
363*ed34f34dSUma Shankar 	struct ext_filesystem *fs = get_fs();
364*ed34f34dSUma Shankar 	char *journal_buffer = zalloc(fs->blksz);
365*ed34f34dSUma Shankar 	if (!journal_buffer) {
366*ed34f34dSUma Shankar 		printf("No memory\n");
367*ed34f34dSUma Shankar 		return;
368*ed34f34dSUma Shankar 	}
369*ed34f34dSUma Shankar 	/* get the block group descriptor table */
370*ed34f34dSUma Shankar 	gd = (struct ext2_block_group *)fs->gdtable;
371*ed34f34dSUma Shankar 
372*ed34f34dSUma Shankar 	if (inode->b.blocks.double_indir_block != 0) {
373*ed34f34dSUma Shankar 		di_buffer = zalloc(fs->blksz);
374*ed34f34dSUma Shankar 		if (!di_buffer) {
375*ed34f34dSUma Shankar 			printf("No memory\n");
376*ed34f34dSUma Shankar 			return;
377*ed34f34dSUma Shankar 		}
378*ed34f34dSUma Shankar 		DIB_start_addr = (unsigned int *)di_buffer;
379*ed34f34dSUma Shankar 		blknr = inode->b.blocks.double_indir_block;
380*ed34f34dSUma Shankar 		status = ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
381*ed34f34dSUma Shankar 					(char *)di_buffer);
382*ed34f34dSUma Shankar 		for (i = 0; i < fs->blksz / sizeof(int); i++) {
383*ed34f34dSUma Shankar 			if (*di_buffer == 0)
384*ed34f34dSUma Shankar 				break;
385*ed34f34dSUma Shankar 
386*ed34f34dSUma Shankar 			debug("DICB releasing %u\n", *di_buffer);
387*ed34f34dSUma Shankar 			if (fs->blksz != 1024) {
388*ed34f34dSUma Shankar 				bg_idx = (*di_buffer) / blk_per_grp;
389*ed34f34dSUma Shankar 			} else {
390*ed34f34dSUma Shankar 				bg_idx = (*di_buffer) / blk_per_grp;
391*ed34f34dSUma Shankar 				remainder = (*di_buffer) % blk_per_grp;
392*ed34f34dSUma Shankar 				if (!remainder)
393*ed34f34dSUma Shankar 					bg_idx--;
394*ed34f34dSUma Shankar 			}
395*ed34f34dSUma Shankar 			ext4fs_reset_block_bmap(*di_buffer,
396*ed34f34dSUma Shankar 					fs->blk_bmaps[bg_idx], bg_idx);
397*ed34f34dSUma Shankar 			di_buffer++;
398*ed34f34dSUma Shankar 			gd[bg_idx].free_blocks++;
399*ed34f34dSUma Shankar 			fs->sb->free_blocks++;
400*ed34f34dSUma Shankar 			/* journal backup */
401*ed34f34dSUma Shankar 			if (prev_bg_bmap_idx != bg_idx) {
402*ed34f34dSUma Shankar 				status = ext4fs_devread(gd[bg_idx].block_id
403*ed34f34dSUma Shankar 							* fs->sect_perblk, 0,
404*ed34f34dSUma Shankar 							fs->blksz,
405*ed34f34dSUma Shankar 							journal_buffer);
406*ed34f34dSUma Shankar 				if (status == 0)
407*ed34f34dSUma Shankar 					goto fail;
408*ed34f34dSUma Shankar 
409*ed34f34dSUma Shankar 				if (ext4fs_log_journal(journal_buffer,
410*ed34f34dSUma Shankar 							gd[bg_idx].block_id))
411*ed34f34dSUma Shankar 					goto fail;
412*ed34f34dSUma Shankar 				prev_bg_bmap_idx = bg_idx;
413*ed34f34dSUma Shankar 			}
414*ed34f34dSUma Shankar 		}
415*ed34f34dSUma Shankar 
416*ed34f34dSUma Shankar 		/* removing the parent double indirect block */
417*ed34f34dSUma Shankar 		blknr = inode->b.blocks.double_indir_block;
418*ed34f34dSUma Shankar 		if (fs->blksz != 1024) {
419*ed34f34dSUma Shankar 			bg_idx = blknr / blk_per_grp;
420*ed34f34dSUma Shankar 		} else {
421*ed34f34dSUma Shankar 			bg_idx = blknr / blk_per_grp;
422*ed34f34dSUma Shankar 			remainder = blknr % blk_per_grp;
423*ed34f34dSUma Shankar 			if (!remainder)
424*ed34f34dSUma Shankar 				bg_idx--;
425*ed34f34dSUma Shankar 		}
426*ed34f34dSUma Shankar 		ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
427*ed34f34dSUma Shankar 		gd[bg_idx].free_blocks++;
428*ed34f34dSUma Shankar 		fs->sb->free_blocks++;
429*ed34f34dSUma Shankar 		/* journal backup */
430*ed34f34dSUma Shankar 		if (prev_bg_bmap_idx != bg_idx) {
431*ed34f34dSUma Shankar 			memset(journal_buffer, '\0', fs->blksz);
432*ed34f34dSUma Shankar 			status = ext4fs_devread(gd[bg_idx].block_id *
433*ed34f34dSUma Shankar 						fs->sect_perblk, 0, fs->blksz,
434*ed34f34dSUma Shankar 						journal_buffer);
435*ed34f34dSUma Shankar 			if (status == 0)
436*ed34f34dSUma Shankar 				goto fail;
437*ed34f34dSUma Shankar 
438*ed34f34dSUma Shankar 			if (ext4fs_log_journal(journal_buffer,
439*ed34f34dSUma Shankar 						gd[bg_idx].block_id))
440*ed34f34dSUma Shankar 				goto fail;
441*ed34f34dSUma Shankar 			prev_bg_bmap_idx = bg_idx;
442*ed34f34dSUma Shankar 		}
443*ed34f34dSUma Shankar 		debug("DIPB releasing %ld\n", blknr);
444*ed34f34dSUma Shankar 	}
445*ed34f34dSUma Shankar fail:
446*ed34f34dSUma Shankar 	free(DIB_start_addr);
447*ed34f34dSUma Shankar 	free(journal_buffer);
448*ed34f34dSUma Shankar }
449*ed34f34dSUma Shankar 
450*ed34f34dSUma Shankar static void delete_triple_indirect_block(struct ext2_inode *inode)
451*ed34f34dSUma Shankar {
452*ed34f34dSUma Shankar 	int i, j;
453*ed34f34dSUma Shankar 	short status;
454*ed34f34dSUma Shankar 	static int prev_bg_bmap_idx = -1;
455*ed34f34dSUma Shankar 	long int blknr;
456*ed34f34dSUma Shankar 	int remainder;
457*ed34f34dSUma Shankar 	int bg_idx;
458*ed34f34dSUma Shankar 	unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
459*ed34f34dSUma Shankar 	unsigned int *tigp_buffer = NULL;
460*ed34f34dSUma Shankar 	unsigned int *tib_start_addr = NULL;
461*ed34f34dSUma Shankar 	unsigned int *tip_buffer = NULL;
462*ed34f34dSUma Shankar 	unsigned int *tipb_start_addr = NULL;
463*ed34f34dSUma Shankar 	struct ext2_block_group *gd = NULL;
464*ed34f34dSUma Shankar 	struct ext_filesystem *fs = get_fs();
465*ed34f34dSUma Shankar 	char *journal_buffer = zalloc(fs->blksz);
466*ed34f34dSUma Shankar 	if (!journal_buffer) {
467*ed34f34dSUma Shankar 		printf("No memory\n");
468*ed34f34dSUma Shankar 		return;
469*ed34f34dSUma Shankar 	}
470*ed34f34dSUma Shankar 	/* get block group descriptor table */
471*ed34f34dSUma Shankar 	gd = (struct ext2_block_group *)fs->gdtable;
472*ed34f34dSUma Shankar 
473*ed34f34dSUma Shankar 	if (inode->b.blocks.triple_indir_block != 0) {
474*ed34f34dSUma Shankar 		tigp_buffer = zalloc(fs->blksz);
475*ed34f34dSUma Shankar 		if (!tigp_buffer) {
476*ed34f34dSUma Shankar 			printf("No memory\n");
477*ed34f34dSUma Shankar 			return;
478*ed34f34dSUma Shankar 		}
479*ed34f34dSUma Shankar 		tib_start_addr = (unsigned int *)tigp_buffer;
480*ed34f34dSUma Shankar 		blknr = inode->b.blocks.triple_indir_block;
481*ed34f34dSUma Shankar 		status = ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
482*ed34f34dSUma Shankar 					(char *)tigp_buffer);
483*ed34f34dSUma Shankar 		for (i = 0; i < fs->blksz / sizeof(int); i++) {
484*ed34f34dSUma Shankar 			if (*tigp_buffer == 0)
485*ed34f34dSUma Shankar 				break;
486*ed34f34dSUma Shankar 			debug("tigp buffer releasing %u\n", *tigp_buffer);
487*ed34f34dSUma Shankar 
488*ed34f34dSUma Shankar 			tip_buffer = zalloc(fs->blksz);
489*ed34f34dSUma Shankar 			if (!tip_buffer)
490*ed34f34dSUma Shankar 				goto fail;
491*ed34f34dSUma Shankar 			tipb_start_addr = (unsigned int *)tip_buffer;
492*ed34f34dSUma Shankar 			status = ext4fs_devread((*tigp_buffer) *
493*ed34f34dSUma Shankar 						fs->sect_perblk, 0, fs->blksz,
494*ed34f34dSUma Shankar 						(char *)tip_buffer);
495*ed34f34dSUma Shankar 			for (j = 0; j < fs->blksz / sizeof(int); j++) {
496*ed34f34dSUma Shankar 				if (*tip_buffer == 0)
497*ed34f34dSUma Shankar 					break;
498*ed34f34dSUma Shankar 				if (fs->blksz != 1024) {
499*ed34f34dSUma Shankar 					bg_idx = (*tip_buffer) / blk_per_grp;
500*ed34f34dSUma Shankar 				} else {
501*ed34f34dSUma Shankar 					bg_idx = (*tip_buffer) / blk_per_grp;
502*ed34f34dSUma Shankar 
503*ed34f34dSUma Shankar 					remainder = (*tip_buffer) % blk_per_grp;
504*ed34f34dSUma Shankar 					if (!remainder)
505*ed34f34dSUma Shankar 						bg_idx--;
506*ed34f34dSUma Shankar 				}
507*ed34f34dSUma Shankar 
508*ed34f34dSUma Shankar 				ext4fs_reset_block_bmap(*tip_buffer,
509*ed34f34dSUma Shankar 							fs->blk_bmaps[bg_idx],
510*ed34f34dSUma Shankar 							bg_idx);
511*ed34f34dSUma Shankar 
512*ed34f34dSUma Shankar 				tip_buffer++;
513*ed34f34dSUma Shankar 				gd[bg_idx].free_blocks++;
514*ed34f34dSUma Shankar 				fs->sb->free_blocks++;
515*ed34f34dSUma Shankar 				/* journal backup */
516*ed34f34dSUma Shankar 				if (prev_bg_bmap_idx != bg_idx) {
517*ed34f34dSUma Shankar 					status =
518*ed34f34dSUma Shankar 					    ext4fs_devread(gd[bg_idx].block_id *
519*ed34f34dSUma Shankar 							   fs->sect_perblk, 0,
520*ed34f34dSUma Shankar 							   fs->blksz,
521*ed34f34dSUma Shankar 							   journal_buffer);
522*ed34f34dSUma Shankar 					if (status == 0)
523*ed34f34dSUma Shankar 						goto fail;
524*ed34f34dSUma Shankar 
525*ed34f34dSUma Shankar 					if (ext4fs_log_journal(journal_buffer,
526*ed34f34dSUma Shankar 							       gd[bg_idx].
527*ed34f34dSUma Shankar 							       block_id))
528*ed34f34dSUma Shankar 						goto fail;
529*ed34f34dSUma Shankar 					prev_bg_bmap_idx = bg_idx;
530*ed34f34dSUma Shankar 				}
531*ed34f34dSUma Shankar 			}
532*ed34f34dSUma Shankar 			free(tipb_start_addr);
533*ed34f34dSUma Shankar 			tipb_start_addr = NULL;
534*ed34f34dSUma Shankar 
535*ed34f34dSUma Shankar 			/*
536*ed34f34dSUma Shankar 			 * removing the grand parent blocks
537*ed34f34dSUma Shankar 			 * which is connected to inode
538*ed34f34dSUma Shankar 			 */
539*ed34f34dSUma Shankar 			if (fs->blksz != 1024) {
540*ed34f34dSUma Shankar 				bg_idx = (*tigp_buffer) / blk_per_grp;
541*ed34f34dSUma Shankar 			} else {
542*ed34f34dSUma Shankar 				bg_idx = (*tigp_buffer) / blk_per_grp;
543*ed34f34dSUma Shankar 
544*ed34f34dSUma Shankar 				remainder = (*tigp_buffer) % blk_per_grp;
545*ed34f34dSUma Shankar 				if (!remainder)
546*ed34f34dSUma Shankar 					bg_idx--;
547*ed34f34dSUma Shankar 			}
548*ed34f34dSUma Shankar 			ext4fs_reset_block_bmap(*tigp_buffer,
549*ed34f34dSUma Shankar 						fs->blk_bmaps[bg_idx], bg_idx);
550*ed34f34dSUma Shankar 
551*ed34f34dSUma Shankar 			tigp_buffer++;
552*ed34f34dSUma Shankar 			gd[bg_idx].free_blocks++;
553*ed34f34dSUma Shankar 			fs->sb->free_blocks++;
554*ed34f34dSUma Shankar 			/* journal backup */
555*ed34f34dSUma Shankar 			if (prev_bg_bmap_idx != bg_idx) {
556*ed34f34dSUma Shankar 				memset(journal_buffer, '\0', fs->blksz);
557*ed34f34dSUma Shankar 				status =
558*ed34f34dSUma Shankar 				    ext4fs_devread(gd[bg_idx].block_id *
559*ed34f34dSUma Shankar 						   fs->sect_perblk, 0,
560*ed34f34dSUma Shankar 						   fs->blksz, journal_buffer);
561*ed34f34dSUma Shankar 				if (status == 0)
562*ed34f34dSUma Shankar 					goto fail;
563*ed34f34dSUma Shankar 
564*ed34f34dSUma Shankar 				if (ext4fs_log_journal(journal_buffer,
565*ed34f34dSUma Shankar 							gd[bg_idx].block_id))
566*ed34f34dSUma Shankar 					goto fail;
567*ed34f34dSUma Shankar 				prev_bg_bmap_idx = bg_idx;
568*ed34f34dSUma Shankar 			}
569*ed34f34dSUma Shankar 		}
570*ed34f34dSUma Shankar 
571*ed34f34dSUma Shankar 		/* removing the grand parent triple indirect block */
572*ed34f34dSUma Shankar 		blknr = inode->b.blocks.triple_indir_block;
573*ed34f34dSUma Shankar 		if (fs->blksz != 1024) {
574*ed34f34dSUma Shankar 			bg_idx = blknr / blk_per_grp;
575*ed34f34dSUma Shankar 		} else {
576*ed34f34dSUma Shankar 			bg_idx = blknr / blk_per_grp;
577*ed34f34dSUma Shankar 			remainder = blknr % blk_per_grp;
578*ed34f34dSUma Shankar 			if (!remainder)
579*ed34f34dSUma Shankar 				bg_idx--;
580*ed34f34dSUma Shankar 		}
581*ed34f34dSUma Shankar 		ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
582*ed34f34dSUma Shankar 		gd[bg_idx].free_blocks++;
583*ed34f34dSUma Shankar 		fs->sb->free_blocks++;
584*ed34f34dSUma Shankar 		/* journal backup */
585*ed34f34dSUma Shankar 		if (prev_bg_bmap_idx != bg_idx) {
586*ed34f34dSUma Shankar 			memset(journal_buffer, '\0', fs->blksz);
587*ed34f34dSUma Shankar 			status = ext4fs_devread(gd[bg_idx].block_id *
588*ed34f34dSUma Shankar 						fs->sect_perblk, 0, fs->blksz,
589*ed34f34dSUma Shankar 						journal_buffer);
590*ed34f34dSUma Shankar 			if (status == 0)
591*ed34f34dSUma Shankar 				goto fail;
592*ed34f34dSUma Shankar 
593*ed34f34dSUma Shankar 			if (ext4fs_log_journal(journal_buffer,
594*ed34f34dSUma Shankar 						gd[bg_idx].block_id))
595*ed34f34dSUma Shankar 				goto fail;
596*ed34f34dSUma Shankar 			prev_bg_bmap_idx = bg_idx;
597*ed34f34dSUma Shankar 		}
598*ed34f34dSUma Shankar 		debug("tigp buffer itself releasing %ld\n", blknr);
599*ed34f34dSUma Shankar 	}
600*ed34f34dSUma Shankar fail:
601*ed34f34dSUma Shankar 	free(tib_start_addr);
602*ed34f34dSUma Shankar 	free(tipb_start_addr);
603*ed34f34dSUma Shankar 	free(journal_buffer);
604*ed34f34dSUma Shankar }
605*ed34f34dSUma Shankar 
606*ed34f34dSUma Shankar static int ext4fs_delete_file(int inodeno)
607*ed34f34dSUma Shankar {
608*ed34f34dSUma Shankar 	struct ext2_inode inode;
609*ed34f34dSUma Shankar 	short status;
610*ed34f34dSUma Shankar 	int i;
611*ed34f34dSUma Shankar 	int remainder;
612*ed34f34dSUma Shankar 	long int blknr;
613*ed34f34dSUma Shankar 	int bg_idx;
614*ed34f34dSUma Shankar 	int ibmap_idx;
615*ed34f34dSUma Shankar 	char *read_buffer = NULL;
616*ed34f34dSUma Shankar 	char *start_block_address = NULL;
617*ed34f34dSUma Shankar 	unsigned int no_blocks;
618*ed34f34dSUma Shankar 
619*ed34f34dSUma Shankar 	static int prev_bg_bmap_idx = -1;
620*ed34f34dSUma Shankar 	unsigned int inodes_per_block;
621*ed34f34dSUma Shankar 	long int blkno;
622*ed34f34dSUma Shankar 	unsigned int blkoff;
623*ed34f34dSUma Shankar 	unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
624*ed34f34dSUma Shankar 	unsigned int inode_per_grp = ext4fs_root->sblock.inodes_per_group;
625*ed34f34dSUma Shankar 	struct ext2_inode *inode_buffer = NULL;
626*ed34f34dSUma Shankar 	struct ext2_block_group *gd = NULL;
627*ed34f34dSUma Shankar 	struct ext_filesystem *fs = get_fs();
628*ed34f34dSUma Shankar 	char *journal_buffer = zalloc(fs->blksz);
629*ed34f34dSUma Shankar 	if (!journal_buffer)
630*ed34f34dSUma Shankar 		return -ENOMEM;
631*ed34f34dSUma Shankar 	/* get the block group descriptor table */
632*ed34f34dSUma Shankar 	gd = (struct ext2_block_group *)fs->gdtable;
633*ed34f34dSUma Shankar 	status = ext4fs_read_inode(ext4fs_root, inodeno, &inode);
634*ed34f34dSUma Shankar 	if (status == 0)
635*ed34f34dSUma Shankar 		goto fail;
636*ed34f34dSUma Shankar 
637*ed34f34dSUma Shankar 	/* read the block no allocated to a file */
638*ed34f34dSUma Shankar 	no_blocks = inode.size / fs->blksz;
639*ed34f34dSUma Shankar 	if (inode.size % fs->blksz)
640*ed34f34dSUma Shankar 		no_blocks++;
641*ed34f34dSUma Shankar 
642*ed34f34dSUma Shankar 	if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FL) {
643*ed34f34dSUma Shankar 		struct ext2fs_node *node_inode =
644*ed34f34dSUma Shankar 		    zalloc(sizeof(struct ext2fs_node));
645*ed34f34dSUma Shankar 		if (!node_inode)
646*ed34f34dSUma Shankar 			goto fail;
647*ed34f34dSUma Shankar 		node_inode->data = ext4fs_root;
648*ed34f34dSUma Shankar 		node_inode->ino = inodeno;
649*ed34f34dSUma Shankar 		node_inode->inode_read = 0;
650*ed34f34dSUma Shankar 		memcpy(&(node_inode->inode), &inode, sizeof(struct ext2_inode));
651*ed34f34dSUma Shankar 
652*ed34f34dSUma Shankar 		for (i = 0; i < no_blocks; i++) {
653*ed34f34dSUma Shankar 			blknr = read_allocated_block(&(node_inode->inode), i);
654*ed34f34dSUma Shankar 			if (fs->blksz != 1024) {
655*ed34f34dSUma Shankar 				bg_idx = blknr / blk_per_grp;
656*ed34f34dSUma Shankar 			} else {
657*ed34f34dSUma Shankar 				bg_idx = blknr / blk_per_grp;
658*ed34f34dSUma Shankar 				remainder = blknr % blk_per_grp;
659*ed34f34dSUma Shankar 				if (!remainder)
660*ed34f34dSUma Shankar 					bg_idx--;
661*ed34f34dSUma Shankar 			}
662*ed34f34dSUma Shankar 			ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx],
663*ed34f34dSUma Shankar 						bg_idx);
664*ed34f34dSUma Shankar 			debug("EXT4_EXTENTS Block releasing %ld: %d\n",
665*ed34f34dSUma Shankar 			      blknr, bg_idx);
666*ed34f34dSUma Shankar 
667*ed34f34dSUma Shankar 			gd[bg_idx].free_blocks++;
668*ed34f34dSUma Shankar 			fs->sb->free_blocks++;
669*ed34f34dSUma Shankar 
670*ed34f34dSUma Shankar 			/* journal backup */
671*ed34f34dSUma Shankar 			if (prev_bg_bmap_idx != bg_idx) {
672*ed34f34dSUma Shankar 				status =
673*ed34f34dSUma Shankar 				    ext4fs_devread(gd[bg_idx].block_id *
674*ed34f34dSUma Shankar 						   fs->sect_perblk, 0,
675*ed34f34dSUma Shankar 						   fs->blksz, journal_buffer);
676*ed34f34dSUma Shankar 				if (status == 0)
677*ed34f34dSUma Shankar 					goto fail;
678*ed34f34dSUma Shankar 				if (ext4fs_log_journal(journal_buffer,
679*ed34f34dSUma Shankar 							gd[bg_idx].block_id))
680*ed34f34dSUma Shankar 					goto fail;
681*ed34f34dSUma Shankar 				prev_bg_bmap_idx = bg_idx;
682*ed34f34dSUma Shankar 			}
683*ed34f34dSUma Shankar 		}
684*ed34f34dSUma Shankar 		if (node_inode) {
685*ed34f34dSUma Shankar 			free(node_inode);
686*ed34f34dSUma Shankar 			node_inode = NULL;
687*ed34f34dSUma Shankar 		}
688*ed34f34dSUma Shankar 	} else {
689*ed34f34dSUma Shankar 
690*ed34f34dSUma Shankar 		delete_single_indirect_block(&inode);
691*ed34f34dSUma Shankar 		delete_double_indirect_block(&inode);
692*ed34f34dSUma Shankar 		delete_triple_indirect_block(&inode);
693*ed34f34dSUma Shankar 
694*ed34f34dSUma Shankar 		/* read the block no allocated to a file */
695*ed34f34dSUma Shankar 		no_blocks = inode.size / fs->blksz;
696*ed34f34dSUma Shankar 		if (inode.size % fs->blksz)
697*ed34f34dSUma Shankar 			no_blocks++;
698*ed34f34dSUma Shankar 		for (i = 0; i < no_blocks; i++) {
699*ed34f34dSUma Shankar 			blknr = read_allocated_block(&inode, i);
700*ed34f34dSUma Shankar 			if (fs->blksz != 1024) {
701*ed34f34dSUma Shankar 				bg_idx = blknr / blk_per_grp;
702*ed34f34dSUma Shankar 			} else {
703*ed34f34dSUma Shankar 				bg_idx = blknr / blk_per_grp;
704*ed34f34dSUma Shankar 				remainder = blknr % blk_per_grp;
705*ed34f34dSUma Shankar 				if (!remainder)
706*ed34f34dSUma Shankar 					bg_idx--;
707*ed34f34dSUma Shankar 			}
708*ed34f34dSUma Shankar 			ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx],
709*ed34f34dSUma Shankar 						bg_idx);
710*ed34f34dSUma Shankar 			debug("ActualB releasing %ld: %d\n", blknr, bg_idx);
711*ed34f34dSUma Shankar 
712*ed34f34dSUma Shankar 			gd[bg_idx].free_blocks++;
713*ed34f34dSUma Shankar 			fs->sb->free_blocks++;
714*ed34f34dSUma Shankar 			/* journal backup */
715*ed34f34dSUma Shankar 			if (prev_bg_bmap_idx != bg_idx) {
716*ed34f34dSUma Shankar 				memset(journal_buffer, '\0', fs->blksz);
717*ed34f34dSUma Shankar 				status = ext4fs_devread(gd[bg_idx].block_id
718*ed34f34dSUma Shankar 							* fs->sect_perblk,
719*ed34f34dSUma Shankar 							0, fs->blksz,
720*ed34f34dSUma Shankar 							journal_buffer);
721*ed34f34dSUma Shankar 				if (status == 0)
722*ed34f34dSUma Shankar 					goto fail;
723*ed34f34dSUma Shankar 				if (ext4fs_log_journal(journal_buffer,
724*ed34f34dSUma Shankar 						gd[bg_idx].block_id))
725*ed34f34dSUma Shankar 					goto fail;
726*ed34f34dSUma Shankar 				prev_bg_bmap_idx = bg_idx;
727*ed34f34dSUma Shankar 			}
728*ed34f34dSUma Shankar 		}
729*ed34f34dSUma Shankar 	}
730*ed34f34dSUma Shankar 
731*ed34f34dSUma Shankar 	/* from the inode no to blockno */
732*ed34f34dSUma Shankar 	inodes_per_block = fs->blksz / fs->inodesz;
733*ed34f34dSUma Shankar 	ibmap_idx = inodeno / inode_per_grp;
734*ed34f34dSUma Shankar 
735*ed34f34dSUma Shankar 	/* get the block no */
736*ed34f34dSUma Shankar 	inodeno--;
737*ed34f34dSUma Shankar 	blkno = __le32_to_cpu(gd[ibmap_idx].inode_table_id) +
738*ed34f34dSUma Shankar 		(inodeno % __le32_to_cpu(inode_per_grp)) / inodes_per_block;
739*ed34f34dSUma Shankar 
740*ed34f34dSUma Shankar 	/* get the offset of the inode */
741*ed34f34dSUma Shankar 	blkoff = ((inodeno) % inodes_per_block) * fs->inodesz;
742*ed34f34dSUma Shankar 
743*ed34f34dSUma Shankar 	/* read the block no containing the inode */
744*ed34f34dSUma Shankar 	read_buffer = zalloc(fs->blksz);
745*ed34f34dSUma Shankar 	if (!read_buffer)
746*ed34f34dSUma Shankar 		goto fail;
747*ed34f34dSUma Shankar 	start_block_address = read_buffer;
748*ed34f34dSUma Shankar 	status = ext4fs_devread(blkno * fs->sect_perblk,
749*ed34f34dSUma Shankar 				0, fs->blksz, read_buffer);
750*ed34f34dSUma Shankar 	if (status == 0)
751*ed34f34dSUma Shankar 		goto fail;
752*ed34f34dSUma Shankar 
753*ed34f34dSUma Shankar 	if (ext4fs_log_journal(read_buffer, blkno))
754*ed34f34dSUma Shankar 		goto fail;
755*ed34f34dSUma Shankar 
756*ed34f34dSUma Shankar 	read_buffer = read_buffer + blkoff;
757*ed34f34dSUma Shankar 	inode_buffer = (struct ext2_inode *)read_buffer;
758*ed34f34dSUma Shankar 	memset(inode_buffer, '\0', sizeof(struct ext2_inode));
759*ed34f34dSUma Shankar 
760*ed34f34dSUma Shankar 	/* write the inode to original position in inode table */
761*ed34f34dSUma Shankar 	if (ext4fs_put_metadata(start_block_address, blkno))
762*ed34f34dSUma Shankar 		goto fail;
763*ed34f34dSUma Shankar 
764*ed34f34dSUma Shankar 	/* update the respective inode bitmaps */
765*ed34f34dSUma Shankar 	inodeno++;
766*ed34f34dSUma Shankar 	ext4fs_reset_inode_bmap(inodeno, fs->inode_bmaps[ibmap_idx], ibmap_idx);
767*ed34f34dSUma Shankar 	gd[ibmap_idx].free_inodes++;
768*ed34f34dSUma Shankar 	fs->sb->free_inodes++;
769*ed34f34dSUma Shankar 	/* journal backup */
770*ed34f34dSUma Shankar 	memset(journal_buffer, '\0', fs->blksz);
771*ed34f34dSUma Shankar 	status = ext4fs_devread(gd[ibmap_idx].inode_id *
772*ed34f34dSUma Shankar 				fs->sect_perblk, 0, fs->blksz, journal_buffer);
773*ed34f34dSUma Shankar 	if (status == 0)
774*ed34f34dSUma Shankar 		goto fail;
775*ed34f34dSUma Shankar 	if (ext4fs_log_journal(journal_buffer, gd[ibmap_idx].inode_id))
776*ed34f34dSUma Shankar 		goto fail;
777*ed34f34dSUma Shankar 
778*ed34f34dSUma Shankar 	ext4fs_update();
779*ed34f34dSUma Shankar 	ext4fs_deinit();
780*ed34f34dSUma Shankar 
781*ed34f34dSUma Shankar 	if (ext4fs_init() != 0) {
782*ed34f34dSUma Shankar 		printf("error in File System init\n");
783*ed34f34dSUma Shankar 		goto fail;
784*ed34f34dSUma Shankar 	}
785*ed34f34dSUma Shankar 
786*ed34f34dSUma Shankar 	free(start_block_address);
787*ed34f34dSUma Shankar 	free(journal_buffer);
788*ed34f34dSUma Shankar 
789*ed34f34dSUma Shankar 	return 0;
790*ed34f34dSUma Shankar fail:
791*ed34f34dSUma Shankar 	free(start_block_address);
792*ed34f34dSUma Shankar 	free(journal_buffer);
793*ed34f34dSUma Shankar 
794*ed34f34dSUma Shankar 	return -1;
795*ed34f34dSUma Shankar }
796*ed34f34dSUma Shankar 
797*ed34f34dSUma Shankar int ext4fs_init(void)
798*ed34f34dSUma Shankar {
799*ed34f34dSUma Shankar 	short status;
800*ed34f34dSUma Shankar 	int i;
801*ed34f34dSUma Shankar 	unsigned int real_free_blocks = 0;
802*ed34f34dSUma Shankar 	struct ext_filesystem *fs = get_fs();
803*ed34f34dSUma Shankar 
804*ed34f34dSUma Shankar 	/* populate fs */
805*ed34f34dSUma Shankar 	fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root);
806*ed34f34dSUma Shankar 	fs->inodesz = INODE_SIZE_FILESYSTEM(ext4fs_root);
807*ed34f34dSUma Shankar 	fs->sect_perblk = fs->blksz / SECTOR_SIZE;
808*ed34f34dSUma Shankar 
809*ed34f34dSUma Shankar 	/* get the superblock */
810*ed34f34dSUma Shankar 	fs->sb = zalloc(SUPERBLOCK_SIZE);
811*ed34f34dSUma Shankar 	if (!fs->sb)
812*ed34f34dSUma Shankar 		return -ENOMEM;
813*ed34f34dSUma Shankar 	if (!ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE,
814*ed34f34dSUma Shankar 			(char *)fs->sb))
815*ed34f34dSUma Shankar 		goto fail;
816*ed34f34dSUma Shankar 
817*ed34f34dSUma Shankar 	/* init journal */
818*ed34f34dSUma Shankar 	if (ext4fs_init_journal())
819*ed34f34dSUma Shankar 		goto fail;
820*ed34f34dSUma Shankar 
821*ed34f34dSUma Shankar 	/* get total no of blockgroups */
822*ed34f34dSUma Shankar 	fs->no_blkgrp = (uint32_t)ext4fs_div_roundup(
823*ed34f34dSUma Shankar 			(ext4fs_root->sblock.total_blocks -
824*ed34f34dSUma Shankar 			ext4fs_root->sblock.first_data_block),
825*ed34f34dSUma Shankar 			ext4fs_root->sblock.blocks_per_group);
826*ed34f34dSUma Shankar 
827*ed34f34dSUma Shankar 	/* get the block group descriptor table */
828*ed34f34dSUma Shankar 	fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1);
829*ed34f34dSUma Shankar 	if (ext4fs_get_bgdtable() == -1) {
830*ed34f34dSUma Shankar 		printf("Error in getting the block group descriptor table\n");
831*ed34f34dSUma Shankar 		goto fail;
832*ed34f34dSUma Shankar 	}
833*ed34f34dSUma Shankar 	fs->gd = (struct ext2_block_group *)fs->gdtable;
834*ed34f34dSUma Shankar 
835*ed34f34dSUma Shankar 	/* load all the available bitmap block of the partition */
836*ed34f34dSUma Shankar 	fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *));
837*ed34f34dSUma Shankar 	if (!fs->blk_bmaps)
838*ed34f34dSUma Shankar 		goto fail;
839*ed34f34dSUma Shankar 	for (i = 0; i < fs->no_blkgrp; i++) {
840*ed34f34dSUma Shankar 		fs->blk_bmaps[i] = zalloc(fs->blksz);
841*ed34f34dSUma Shankar 		if (!fs->blk_bmaps[i])
842*ed34f34dSUma Shankar 			goto fail;
843*ed34f34dSUma Shankar 	}
844*ed34f34dSUma Shankar 
845*ed34f34dSUma Shankar 	for (i = 0; i < fs->no_blkgrp; i++) {
846*ed34f34dSUma Shankar 		status =
847*ed34f34dSUma Shankar 		    ext4fs_devread(fs->gd[i].block_id * fs->sect_perblk, 0,
848*ed34f34dSUma Shankar 				   fs->blksz, (char *)fs->blk_bmaps[i]);
849*ed34f34dSUma Shankar 		if (status == 0)
850*ed34f34dSUma Shankar 			goto fail;
851*ed34f34dSUma Shankar 	}
852*ed34f34dSUma Shankar 
853*ed34f34dSUma Shankar 	/* load all the available inode bitmap of the partition */
854*ed34f34dSUma Shankar 	fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *));
855*ed34f34dSUma Shankar 	if (!fs->inode_bmaps)
856*ed34f34dSUma Shankar 		goto fail;
857*ed34f34dSUma Shankar 	for (i = 0; i < fs->no_blkgrp; i++) {
858*ed34f34dSUma Shankar 		fs->inode_bmaps[i] = zalloc(fs->blksz);
859*ed34f34dSUma Shankar 		if (!fs->inode_bmaps[i])
860*ed34f34dSUma Shankar 			goto fail;
861*ed34f34dSUma Shankar 	}
862*ed34f34dSUma Shankar 
863*ed34f34dSUma Shankar 	for (i = 0; i < fs->no_blkgrp; i++) {
864*ed34f34dSUma Shankar 		status = ext4fs_devread(fs->gd[i].inode_id * fs->sect_perblk,
865*ed34f34dSUma Shankar 					0, fs->blksz,
866*ed34f34dSUma Shankar 					(char *)fs->inode_bmaps[i]);
867*ed34f34dSUma Shankar 		if (status == 0)
868*ed34f34dSUma Shankar 			goto fail;
869*ed34f34dSUma Shankar 	}
870*ed34f34dSUma Shankar 
871*ed34f34dSUma Shankar 	/*
872*ed34f34dSUma Shankar 	 * check filesystem consistency with free blocks of file system
873*ed34f34dSUma Shankar 	 * some time we observed that superblock freeblocks does not match
874*ed34f34dSUma Shankar 	 * with the  blockgroups freeblocks when improper
875*ed34f34dSUma Shankar 	 * reboot of a linux kernel
876*ed34f34dSUma Shankar 	 */
877*ed34f34dSUma Shankar 	for (i = 0; i < fs->no_blkgrp; i++)
878*ed34f34dSUma Shankar 		real_free_blocks = real_free_blocks + fs->gd[i].free_blocks;
879*ed34f34dSUma Shankar 	if (real_free_blocks != fs->sb->free_blocks)
880*ed34f34dSUma Shankar 		fs->sb->free_blocks = real_free_blocks;
881*ed34f34dSUma Shankar 
882*ed34f34dSUma Shankar 	return 0;
883*ed34f34dSUma Shankar fail:
884*ed34f34dSUma Shankar 	ext4fs_deinit();
885*ed34f34dSUma Shankar 
886*ed34f34dSUma Shankar 	return -1;
887*ed34f34dSUma Shankar }
888*ed34f34dSUma Shankar 
889*ed34f34dSUma Shankar void ext4fs_deinit(void)
890*ed34f34dSUma Shankar {
891*ed34f34dSUma Shankar 	int i;
892*ed34f34dSUma Shankar 	struct ext2_inode inode_journal;
893*ed34f34dSUma Shankar 	struct journal_superblock_t *jsb;
894*ed34f34dSUma Shankar 	long int blknr;
895*ed34f34dSUma Shankar 	struct ext_filesystem *fs = get_fs();
896*ed34f34dSUma Shankar 
897*ed34f34dSUma Shankar 	/* free journal */
898*ed34f34dSUma Shankar 	char *temp_buff = zalloc(fs->blksz);
899*ed34f34dSUma Shankar 	if (temp_buff) {
900*ed34f34dSUma Shankar 		ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
901*ed34f34dSUma Shankar 				  &inode_journal);
902*ed34f34dSUma Shankar 		blknr = read_allocated_block(&inode_journal,
903*ed34f34dSUma Shankar 					EXT2_JOURNAL_SUPERBLOCK);
904*ed34f34dSUma Shankar 		ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
905*ed34f34dSUma Shankar 			       temp_buff);
906*ed34f34dSUma Shankar 		jsb = (struct journal_superblock_t *)temp_buff;
907*ed34f34dSUma Shankar 		jsb->s_start = cpu_to_be32(0);
908*ed34f34dSUma Shankar 		put_ext4((uint64_t) (blknr * fs->blksz),
909*ed34f34dSUma Shankar 			 (struct journal_superblock_t *)temp_buff, fs->blksz);
910*ed34f34dSUma Shankar 		free(temp_buff);
911*ed34f34dSUma Shankar 	}
912*ed34f34dSUma Shankar 	ext4fs_free_journal();
913*ed34f34dSUma Shankar 
914*ed34f34dSUma Shankar 	/* get the superblock */
915*ed34f34dSUma Shankar 	ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE, (char *)fs->sb);
916*ed34f34dSUma Shankar 	fs->sb->feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
917*ed34f34dSUma Shankar 	put_ext4((uint64_t)(SUPERBLOCK_SIZE),
918*ed34f34dSUma Shankar 		 (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
919*ed34f34dSUma Shankar 	free(fs->sb);
920*ed34f34dSUma Shankar 	fs->sb = NULL;
921*ed34f34dSUma Shankar 
922*ed34f34dSUma Shankar 	if (fs->blk_bmaps) {
923*ed34f34dSUma Shankar 		for (i = 0; i < fs->no_blkgrp; i++) {
924*ed34f34dSUma Shankar 			free(fs->blk_bmaps[i]);
925*ed34f34dSUma Shankar 			fs->blk_bmaps[i] = NULL;
926*ed34f34dSUma Shankar 		}
927*ed34f34dSUma Shankar 		free(fs->blk_bmaps);
928*ed34f34dSUma Shankar 		fs->blk_bmaps = NULL;
929*ed34f34dSUma Shankar 	}
930*ed34f34dSUma Shankar 
931*ed34f34dSUma Shankar 	if (fs->inode_bmaps) {
932*ed34f34dSUma Shankar 		for (i = 0; i < fs->no_blkgrp; i++) {
933*ed34f34dSUma Shankar 			free(fs->inode_bmaps[i]);
934*ed34f34dSUma Shankar 			fs->inode_bmaps[i] = NULL;
935*ed34f34dSUma Shankar 		}
936*ed34f34dSUma Shankar 		free(fs->inode_bmaps);
937*ed34f34dSUma Shankar 		fs->inode_bmaps = NULL;
938*ed34f34dSUma Shankar 	}
939*ed34f34dSUma Shankar 
940*ed34f34dSUma Shankar 
941*ed34f34dSUma Shankar 	free(fs->gdtable);
942*ed34f34dSUma Shankar 	fs->gdtable = NULL;
943*ed34f34dSUma Shankar 	fs->gd = NULL;
944*ed34f34dSUma Shankar 	/*
945*ed34f34dSUma Shankar 	 * reinitiliazed the global inode and
946*ed34f34dSUma Shankar 	 * block bitmap first execution check variables
947*ed34f34dSUma Shankar 	 */
948*ed34f34dSUma Shankar 	fs->first_pass_ibmap = 0;
949*ed34f34dSUma Shankar 	fs->first_pass_bbmap = 0;
950*ed34f34dSUma Shankar 	fs->curr_inode_no = 0;
951*ed34f34dSUma Shankar 	fs->curr_blkno = 0;
952*ed34f34dSUma Shankar }
953*ed34f34dSUma Shankar 
954*ed34f34dSUma Shankar static int ext4fs_write_file(struct ext2_inode *file_inode,
955*ed34f34dSUma Shankar 			     int pos, unsigned int len, char *buf)
956*ed34f34dSUma Shankar {
957*ed34f34dSUma Shankar 	int i;
958*ed34f34dSUma Shankar 	int blockcnt;
959*ed34f34dSUma Shankar 	int log2blocksize = LOG2_EXT2_BLOCK_SIZE(ext4fs_root);
960*ed34f34dSUma Shankar 	unsigned int filesize = __le32_to_cpu(file_inode->size);
961*ed34f34dSUma Shankar 	struct ext_filesystem *fs = get_fs();
962*ed34f34dSUma Shankar 	int previous_block_number = -1;
963*ed34f34dSUma Shankar 	int delayed_start = 0;
964*ed34f34dSUma Shankar 	int delayed_extent = 0;
965*ed34f34dSUma Shankar 	int delayed_skipfirst = 0;
966*ed34f34dSUma Shankar 	int delayed_next = 0;
967*ed34f34dSUma Shankar 	char *delayed_buf = NULL;
968*ed34f34dSUma Shankar 
969*ed34f34dSUma Shankar 	/* Adjust len so it we can't read past the end of the file. */
970*ed34f34dSUma Shankar 	if (len > filesize)
971*ed34f34dSUma Shankar 		len = filesize;
972*ed34f34dSUma Shankar 
973*ed34f34dSUma Shankar 	blockcnt = ((len + pos) + fs->blksz - 1) / fs->blksz;
974*ed34f34dSUma Shankar 
975*ed34f34dSUma Shankar 	for (i = pos / fs->blksz; i < blockcnt; i++) {
976*ed34f34dSUma Shankar 		long int blknr;
977*ed34f34dSUma Shankar 		int blockend = fs->blksz;
978*ed34f34dSUma Shankar 		int skipfirst = 0;
979*ed34f34dSUma Shankar 		blknr = read_allocated_block(file_inode, i);
980*ed34f34dSUma Shankar 		if (blknr < 0)
981*ed34f34dSUma Shankar 			return -1;
982*ed34f34dSUma Shankar 
983*ed34f34dSUma Shankar 		blknr = blknr << log2blocksize;
984*ed34f34dSUma Shankar 
985*ed34f34dSUma Shankar 		if (blknr) {
986*ed34f34dSUma Shankar 			if (previous_block_number != -1) {
987*ed34f34dSUma Shankar 				if (delayed_next == blknr) {
988*ed34f34dSUma Shankar 					delayed_extent += blockend;
989*ed34f34dSUma Shankar 					delayed_next += blockend >> SECTOR_BITS;
990*ed34f34dSUma Shankar 				} else {	/* spill */
991*ed34f34dSUma Shankar 					put_ext4((uint64_t) (delayed_start *
992*ed34f34dSUma Shankar 							     SECTOR_SIZE),
993*ed34f34dSUma Shankar 						 delayed_buf,
994*ed34f34dSUma Shankar 						 (uint32_t) delayed_extent);
995*ed34f34dSUma Shankar 					previous_block_number = blknr;
996*ed34f34dSUma Shankar 					delayed_start = blknr;
997*ed34f34dSUma Shankar 					delayed_extent = blockend;
998*ed34f34dSUma Shankar 					delayed_skipfirst = skipfirst;
999*ed34f34dSUma Shankar 					delayed_buf = buf;
1000*ed34f34dSUma Shankar 					delayed_next = blknr +
1001*ed34f34dSUma Shankar 					    (blockend >> SECTOR_BITS);
1002*ed34f34dSUma Shankar 				}
1003*ed34f34dSUma Shankar 			} else {
1004*ed34f34dSUma Shankar 				previous_block_number = blknr;
1005*ed34f34dSUma Shankar 				delayed_start = blknr;
1006*ed34f34dSUma Shankar 				delayed_extent = blockend;
1007*ed34f34dSUma Shankar 				delayed_skipfirst = skipfirst;
1008*ed34f34dSUma Shankar 				delayed_buf = buf;
1009*ed34f34dSUma Shankar 				delayed_next = blknr +
1010*ed34f34dSUma Shankar 				    (blockend >> SECTOR_BITS);
1011*ed34f34dSUma Shankar 			}
1012*ed34f34dSUma Shankar 		} else {
1013*ed34f34dSUma Shankar 			if (previous_block_number != -1) {
1014*ed34f34dSUma Shankar 				/* spill */
1015*ed34f34dSUma Shankar 				put_ext4((uint64_t) (delayed_start *
1016*ed34f34dSUma Shankar 						     SECTOR_SIZE), delayed_buf,
1017*ed34f34dSUma Shankar 					 (uint32_t) delayed_extent);
1018*ed34f34dSUma Shankar 				previous_block_number = -1;
1019*ed34f34dSUma Shankar 			}
1020*ed34f34dSUma Shankar 			memset(buf, 0, fs->blksz - skipfirst);
1021*ed34f34dSUma Shankar 		}
1022*ed34f34dSUma Shankar 		buf += fs->blksz - skipfirst;
1023*ed34f34dSUma Shankar 	}
1024*ed34f34dSUma Shankar 	if (previous_block_number != -1) {
1025*ed34f34dSUma Shankar 		/* spill */
1026*ed34f34dSUma Shankar 		put_ext4((uint64_t) (delayed_start * SECTOR_SIZE),
1027*ed34f34dSUma Shankar 			 delayed_buf, (uint32_t) delayed_extent);
1028*ed34f34dSUma Shankar 		previous_block_number = -1;
1029*ed34f34dSUma Shankar 	}
1030*ed34f34dSUma Shankar 
1031*ed34f34dSUma Shankar 	return len;
1032*ed34f34dSUma Shankar }
1033*ed34f34dSUma Shankar 
1034*ed34f34dSUma Shankar int ext4fs_write(const char *fname, unsigned char *buffer,
1035*ed34f34dSUma Shankar 					unsigned long sizebytes)
1036*ed34f34dSUma Shankar {
1037*ed34f34dSUma Shankar 	int ret = 0;
1038*ed34f34dSUma Shankar 	struct ext2_inode *file_inode = NULL;
1039*ed34f34dSUma Shankar 	unsigned char *inode_buffer = NULL;
1040*ed34f34dSUma Shankar 	int parent_inodeno;
1041*ed34f34dSUma Shankar 	int inodeno;
1042*ed34f34dSUma Shankar 	time_t timestamp = 0;
1043*ed34f34dSUma Shankar 
1044*ed34f34dSUma Shankar 	uint64_t bytes_reqd_for_file;
1045*ed34f34dSUma Shankar 	unsigned int blks_reqd_for_file;
1046*ed34f34dSUma Shankar 	unsigned int blocks_remaining;
1047*ed34f34dSUma Shankar 	int existing_file_inodeno;
1048*ed34f34dSUma Shankar 	char filename[256];
1049*ed34f34dSUma Shankar 
1050*ed34f34dSUma Shankar 	char *temp_ptr = NULL;
1051*ed34f34dSUma Shankar 	long int itable_blkno;
1052*ed34f34dSUma Shankar 	long int parent_itable_blkno;
1053*ed34f34dSUma Shankar 	long int blkoff;
1054*ed34f34dSUma Shankar 	struct ext2_sblock *sblock = &(ext4fs_root->sblock);
1055*ed34f34dSUma Shankar 	unsigned int inodes_per_block;
1056*ed34f34dSUma Shankar 	unsigned int ibmap_idx;
1057*ed34f34dSUma Shankar 	struct ext_filesystem *fs = get_fs();
1058*ed34f34dSUma Shankar 	g_parent_inode = zalloc(sizeof(struct ext2_inode));
1059*ed34f34dSUma Shankar 	if (!g_parent_inode)
1060*ed34f34dSUma Shankar 		goto fail;
1061*ed34f34dSUma Shankar 
1062*ed34f34dSUma Shankar 	if (ext4fs_init() != 0) {
1063*ed34f34dSUma Shankar 		printf("error in File System init\n");
1064*ed34f34dSUma Shankar 		return -1;
1065*ed34f34dSUma Shankar 	}
1066*ed34f34dSUma Shankar 	inodes_per_block = fs->blksz / fs->inodesz;
1067*ed34f34dSUma Shankar 	parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE);
1068*ed34f34dSUma Shankar 	if (parent_inodeno == -1)
1069*ed34f34dSUma Shankar 		goto fail;
1070*ed34f34dSUma Shankar 	if (ext4fs_iget(parent_inodeno, g_parent_inode))
1071*ed34f34dSUma Shankar 		goto fail;
1072*ed34f34dSUma Shankar 	/* check if the filename is already present in root */
1073*ed34f34dSUma Shankar 	existing_file_inodeno = ext4fs_filename_check(filename);
1074*ed34f34dSUma Shankar 	if (existing_file_inodeno != -1) {
1075*ed34f34dSUma Shankar 		ret = ext4fs_delete_file(existing_file_inodeno);
1076*ed34f34dSUma Shankar 		fs->first_pass_bbmap = 0;
1077*ed34f34dSUma Shankar 		fs->curr_blkno = 0;
1078*ed34f34dSUma Shankar 
1079*ed34f34dSUma Shankar 		fs->first_pass_ibmap = 0;
1080*ed34f34dSUma Shankar 		fs->curr_inode_no = 0;
1081*ed34f34dSUma Shankar 		if (ret)
1082*ed34f34dSUma Shankar 			goto fail;
1083*ed34f34dSUma Shankar 	}
1084*ed34f34dSUma Shankar 	/* calucalate how many blocks required */
1085*ed34f34dSUma Shankar 	bytes_reqd_for_file = sizebytes;
1086*ed34f34dSUma Shankar 	blks_reqd_for_file = bytes_reqd_for_file / fs->blksz;
1087*ed34f34dSUma Shankar 	if (bytes_reqd_for_file % fs->blksz != 0) {
1088*ed34f34dSUma Shankar 		blks_reqd_for_file++;
1089*ed34f34dSUma Shankar 		debug("total bytes for a file %u\n", blks_reqd_for_file);
1090*ed34f34dSUma Shankar 	}
1091*ed34f34dSUma Shankar 	blocks_remaining = blks_reqd_for_file;
1092*ed34f34dSUma Shankar 	/* test for available space in partition */
1093*ed34f34dSUma Shankar 	if (fs->sb->free_blocks < blks_reqd_for_file) {
1094*ed34f34dSUma Shankar 		printf("Not enough space on partition !!!\n");
1095*ed34f34dSUma Shankar 		goto fail;
1096*ed34f34dSUma Shankar 	}
1097*ed34f34dSUma Shankar 
1098*ed34f34dSUma Shankar 	ext4fs_update_parent_dentry(filename, &inodeno, FILETYPE_REG);
1099*ed34f34dSUma Shankar 	/* prepare file inode */
1100*ed34f34dSUma Shankar 	inode_buffer = zalloc(fs->inodesz);
1101*ed34f34dSUma Shankar 	if (!inode_buffer)
1102*ed34f34dSUma Shankar 		goto fail;
1103*ed34f34dSUma Shankar 	file_inode = (struct ext2_inode *)inode_buffer;
1104*ed34f34dSUma Shankar 	file_inode->mode = S_IFREG | S_IRWXU |
1105*ed34f34dSUma Shankar 	    S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH;
1106*ed34f34dSUma Shankar 	/* ToDo: Update correct time */
1107*ed34f34dSUma Shankar 	file_inode->mtime = timestamp;
1108*ed34f34dSUma Shankar 	file_inode->atime = timestamp;
1109*ed34f34dSUma Shankar 	file_inode->ctime = timestamp;
1110*ed34f34dSUma Shankar 	file_inode->nlinks = 1;
1111*ed34f34dSUma Shankar 	file_inode->size = sizebytes;
1112*ed34f34dSUma Shankar 
1113*ed34f34dSUma Shankar 	/* Allocate data blocks */
1114*ed34f34dSUma Shankar 	ext4fs_allocate_blocks(file_inode, blocks_remaining,
1115*ed34f34dSUma Shankar 			       &blks_reqd_for_file);
1116*ed34f34dSUma Shankar 	file_inode->blockcnt = (blks_reqd_for_file * fs->blksz) / SECTOR_SIZE;
1117*ed34f34dSUma Shankar 
1118*ed34f34dSUma Shankar 	temp_ptr = zalloc(fs->blksz);
1119*ed34f34dSUma Shankar 	if (!temp_ptr)
1120*ed34f34dSUma Shankar 		goto fail;
1121*ed34f34dSUma Shankar 	ibmap_idx = inodeno / ext4fs_root->sblock.inodes_per_group;
1122*ed34f34dSUma Shankar 	inodeno--;
1123*ed34f34dSUma Shankar 	itable_blkno = __le32_to_cpu(fs->gd[ibmap_idx].inode_table_id) +
1124*ed34f34dSUma Shankar 			(inodeno % __le32_to_cpu(sblock->inodes_per_group)) /
1125*ed34f34dSUma Shankar 			inodes_per_block;
1126*ed34f34dSUma Shankar 	blkoff = (inodeno % inodes_per_block) * fs->inodesz;
1127*ed34f34dSUma Shankar 	ext4fs_devread(itable_blkno * fs->sect_perblk, 0, fs->blksz, temp_ptr);
1128*ed34f34dSUma Shankar 	if (ext4fs_log_journal(temp_ptr, itable_blkno))
1129*ed34f34dSUma Shankar 		goto fail;
1130*ed34f34dSUma Shankar 
1131*ed34f34dSUma Shankar 	memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz);
1132*ed34f34dSUma Shankar 	if (ext4fs_put_metadata(temp_ptr, itable_blkno))
1133*ed34f34dSUma Shankar 		goto fail;
1134*ed34f34dSUma Shankar 	/* copy the file content into data blocks */
1135*ed34f34dSUma Shankar 	if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) {
1136*ed34f34dSUma Shankar 		printf("Error in copying content\n");
1137*ed34f34dSUma Shankar 		goto fail;
1138*ed34f34dSUma Shankar 	}
1139*ed34f34dSUma Shankar 	ibmap_idx = parent_inodeno / ext4fs_root->sblock.inodes_per_group;
1140*ed34f34dSUma Shankar 	parent_inodeno--;
1141*ed34f34dSUma Shankar 	parent_itable_blkno = __le32_to_cpu(fs->gd[ibmap_idx].inode_table_id) +
1142*ed34f34dSUma Shankar 	    (parent_inodeno %
1143*ed34f34dSUma Shankar 	     __le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
1144*ed34f34dSUma Shankar 	blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz;
1145*ed34f34dSUma Shankar 	if (parent_itable_blkno != itable_blkno) {
1146*ed34f34dSUma Shankar 		memset(temp_ptr, '\0', fs->blksz);
1147*ed34f34dSUma Shankar 		ext4fs_devread(parent_itable_blkno * fs->sect_perblk,
1148*ed34f34dSUma Shankar 			       0, fs->blksz, temp_ptr);
1149*ed34f34dSUma Shankar 		if (ext4fs_log_journal(temp_ptr, parent_itable_blkno))
1150*ed34f34dSUma Shankar 			goto fail;
1151*ed34f34dSUma Shankar 
1152*ed34f34dSUma Shankar 		memcpy(temp_ptr + blkoff, g_parent_inode,
1153*ed34f34dSUma Shankar 			sizeof(struct ext2_inode));
1154*ed34f34dSUma Shankar 		if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno))
1155*ed34f34dSUma Shankar 			goto fail;
1156*ed34f34dSUma Shankar 		free(temp_ptr);
1157*ed34f34dSUma Shankar 	} else {
1158*ed34f34dSUma Shankar 		/*
1159*ed34f34dSUma Shankar 		 * If parent and child fall in same inode table block
1160*ed34f34dSUma Shankar 		 * both should be kept in 1 buffer
1161*ed34f34dSUma Shankar 		 */
1162*ed34f34dSUma Shankar 		memcpy(temp_ptr + blkoff, g_parent_inode,
1163*ed34f34dSUma Shankar 		       sizeof(struct ext2_inode));
1164*ed34f34dSUma Shankar 		gd_index--;
1165*ed34f34dSUma Shankar 		if (ext4fs_put_metadata(temp_ptr, itable_blkno))
1166*ed34f34dSUma Shankar 			goto fail;
1167*ed34f34dSUma Shankar 		free(temp_ptr);
1168*ed34f34dSUma Shankar 	}
1169*ed34f34dSUma Shankar 	ext4fs_update();
1170*ed34f34dSUma Shankar 	ext4fs_deinit();
1171*ed34f34dSUma Shankar 
1172*ed34f34dSUma Shankar 	fs->first_pass_bbmap = 0;
1173*ed34f34dSUma Shankar 	fs->curr_blkno = 0;
1174*ed34f34dSUma Shankar 	fs->first_pass_ibmap = 0;
1175*ed34f34dSUma Shankar 	fs->curr_inode_no = 0;
1176*ed34f34dSUma Shankar 	free(inode_buffer);
1177*ed34f34dSUma Shankar 	free(g_parent_inode);
1178*ed34f34dSUma Shankar 	g_parent_inode = NULL;
1179*ed34f34dSUma Shankar 
1180*ed34f34dSUma Shankar 	return 0;
1181*ed34f34dSUma Shankar fail:
1182*ed34f34dSUma Shankar 	ext4fs_deinit();
1183*ed34f34dSUma Shankar 	free(inode_buffer);
1184*ed34f34dSUma Shankar 	free(g_parent_inode);
1185*ed34f34dSUma Shankar 	g_parent_inode = NULL;
1186*ed34f34dSUma Shankar 
1187*ed34f34dSUma Shankar 	return -1;
1188*ed34f34dSUma Shankar }
1189*ed34f34dSUma Shankar #endif
1190