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