]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - fs/ext4/ext4fs.c
Merge branch 'master' of git://git.denx.de/u-boot-mpc85xx
[karo-tx-uboot.git] / fs / ext4 / ext4fs.c
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