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