]> git.sur5r.net Git - u-boot/blob - fs/ext4/ext4fs.c
ext4: remove init_fs/deinit_fs
[u-boot] / 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 struct ext_filesystem ext_fs;
48
49 struct ext_filesystem *get_fs(void)
50 {
51         return &ext_fs;
52 }
53
54 void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot)
55 {
56         if ((node != &ext4fs_root->diropen) && (node != currroot))
57                 free(node);
58 }
59
60 /*
61  * Taken from openmoko-kernel mailing list: By Andy green
62  * Optimized read file API : collects and defers contiguous sector
63  * reads into one potentially more efficient larger sequential read action
64  */
65 int ext4fs_read_file(struct ext2fs_node *node, int pos,
66                 unsigned int len, char *buf)
67 {
68         int i;
69         int blockcnt;
70         int log2blocksize = LOG2_EXT2_BLOCK_SIZE(node->data);
71         int blocksize = 1 << (log2blocksize + DISK_SECTOR_BITS);
72         unsigned int filesize = __le32_to_cpu(node->inode.size);
73         int previous_block_number = -1;
74         int delayed_start = 0;
75         int delayed_extent = 0;
76         int delayed_skipfirst = 0;
77         int delayed_next = 0;
78         char *delayed_buf = NULL;
79         short status;
80
81         /* Adjust len so it we can't read past the end of the file. */
82         if (len > filesize)
83                 len = filesize;
84
85         blockcnt = ((len + pos) + blocksize - 1) / blocksize;
86
87         for (i = pos / blocksize; i < blockcnt; i++) {
88                 int blknr;
89                 int blockoff = pos % blocksize;
90                 int blockend = blocksize;
91                 int skipfirst = 0;
92                 blknr = read_allocated_block(&(node->inode), i);
93                 if (blknr < 0)
94                         return -1;
95
96                 blknr = blknr << log2blocksize;
97
98                 /* Last block.  */
99                 if (i == blockcnt - 1) {
100                         blockend = (len + pos) % blocksize;
101
102                         /* The last portion is exactly blocksize. */
103                         if (!blockend)
104                                 blockend = blocksize;
105                 }
106
107                 /* First block. */
108                 if (i == pos / blocksize) {
109                         skipfirst = blockoff;
110                         blockend -= skipfirst;
111                 }
112                 if (blknr) {
113                         int status;
114
115                         if (previous_block_number != -1) {
116                                 if (delayed_next == blknr) {
117                                         delayed_extent += blockend;
118                                         delayed_next += blockend >> SECTOR_BITS;
119                                 } else {        /* spill */
120                                         status = ext4fs_devread(delayed_start,
121                                                         delayed_skipfirst,
122                                                         delayed_extent,
123                                                         delayed_buf);
124                                         if (status == 0)
125                                                 return -1;
126                                         previous_block_number = blknr;
127                                         delayed_start = blknr;
128                                         delayed_extent = blockend;
129                                         delayed_skipfirst = skipfirst;
130                                         delayed_buf = buf;
131                                         delayed_next = blknr +
132                                                 (blockend >> SECTOR_BITS);
133                                 }
134                         } else {
135                                 previous_block_number = blknr;
136                                 delayed_start = blknr;
137                                 delayed_extent = blockend;
138                                 delayed_skipfirst = skipfirst;
139                                 delayed_buf = buf;
140                                 delayed_next = blknr +
141                                         (blockend >> SECTOR_BITS);
142                         }
143                 } else {
144                         if (previous_block_number != -1) {
145                                 /* spill */
146                                 status = ext4fs_devread(delayed_start,
147                                                         delayed_skipfirst,
148                                                         delayed_extent,
149                                                         delayed_buf);
150                                 if (status == 0)
151                                         return -1;
152                                 previous_block_number = -1;
153                         }
154                         memset(buf, 0, blocksize - skipfirst);
155                 }
156                 buf += blocksize - skipfirst;
157         }
158         if (previous_block_number != -1) {
159                 /* spill */
160                 status = ext4fs_devread(delayed_start,
161                                         delayed_skipfirst, delayed_extent,
162                                         delayed_buf);
163                 if (status == 0)
164                         return -1;
165                 previous_block_number = -1;
166         }
167
168         return len;
169 }
170
171 int ext4fs_ls(const char *dirname)
172 {
173         struct ext2fs_node *dirnode;
174         int status;
175
176         if (dirname == NULL)
177                 return 0;
178
179         status = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode,
180                                   FILETYPE_DIRECTORY);
181         if (status != 1) {
182                 printf("** Can not find directory. **\n");
183                 return 1;
184         }
185
186         ext4fs_iterate_dir(dirnode, NULL, NULL, NULL);
187         ext4fs_free_node(dirnode, &ext4fs_root->diropen);
188
189         return 0;
190 }
191
192 int ext4fs_read(char *buf, unsigned len)
193 {
194         if (ext4fs_root == NULL || ext4fs_file == NULL)
195                 return 0;
196
197         return ext4fs_read_file(ext4fs_file, 0, len, buf);
198 }
199
200 #if defined(CONFIG_CMD_EXT4_WRITE)
201 static void ext4fs_update(void)
202 {
203         short i;
204         ext4fs_update_journal();
205         struct ext_filesystem *fs = get_fs();
206
207         /* update  super block */
208         put_ext4((uint64_t)(SUPERBLOCK_SIZE),
209                  (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
210
211         /* update block groups */
212         for (i = 0; i < fs->no_blkgrp; i++) {
213                 fs->gd[i].bg_checksum = ext4fs_checksum_update(i);
214                 put_ext4((uint64_t)(fs->gd[i].block_id * fs->blksz),
215                          fs->blk_bmaps[i], fs->blksz);
216         }
217
218         /* update inode table groups */
219         for (i = 0; i < fs->no_blkgrp; i++) {
220                 put_ext4((uint64_t) (fs->gd[i].inode_id * fs->blksz),
221                          fs->inode_bmaps[i], fs->blksz);
222         }
223
224         /* update the block group descriptor table */
225         put_ext4((uint64_t)(fs->gdtable_blkno * fs->blksz),
226                  (struct ext2_block_group *)fs->gdtable,
227                  (fs->blksz * fs->no_blk_pergdt));
228
229         ext4fs_dump_metadata();
230
231         gindex = 0;
232         gd_index = 0;
233 }
234
235 int ext4fs_get_bgdtable(void)
236 {
237         int status;
238         int grp_desc_size;
239         struct ext_filesystem *fs = get_fs();
240         grp_desc_size = sizeof(struct ext2_block_group);
241         fs->no_blk_pergdt = (fs->no_blkgrp * grp_desc_size) / fs->blksz;
242         if ((fs->no_blkgrp * grp_desc_size) % fs->blksz)
243                 fs->no_blk_pergdt++;
244
245         /* allocate memory for gdtable */
246         fs->gdtable = zalloc(fs->blksz * fs->no_blk_pergdt);
247         if (!fs->gdtable)
248                 return -ENOMEM;
249         /* read the group descriptor table */
250         status = ext4fs_devread(fs->gdtable_blkno * fs->sect_perblk, 0,
251                                 fs->blksz * fs->no_blk_pergdt, fs->gdtable);
252         if (status == 0)
253                 goto fail;
254
255         if (ext4fs_log_gdt(fs->gdtable)) {
256                 printf("Error in ext4fs_log_gdt\n");
257                 return -1;
258         }
259
260         return 0;
261 fail:
262         free(fs->gdtable);
263         fs->gdtable = NULL;
264
265         return -1;
266 }
267
268 static void delete_single_indirect_block(struct ext2_inode *inode)
269 {
270         struct ext2_block_group *gd = NULL;
271         static int prev_bg_bmap_idx = -1;
272         long int blknr;
273         int remainder;
274         int bg_idx;
275         int status;
276         unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
277         struct ext_filesystem *fs = get_fs();
278         char *journal_buffer = zalloc(fs->blksz);
279         if (!journal_buffer) {
280                 printf("No memory\n");
281                 return;
282         }
283         /* get  block group descriptor table */
284         gd = (struct ext2_block_group *)fs->gdtable;
285
286         /* deleting the single indirect block associated with inode */
287         if (inode->b.blocks.indir_block != 0) {
288                 debug("SIPB releasing %u\n", inode->b.blocks.indir_block);
289                 blknr = inode->b.blocks.indir_block;
290                 if (fs->blksz != 1024) {
291                         bg_idx = blknr / blk_per_grp;
292                 } else {
293                         bg_idx = blknr / blk_per_grp;
294                         remainder = blknr % blk_per_grp;
295                         if (!remainder)
296                                 bg_idx--;
297                 }
298                 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
299                 gd[bg_idx].free_blocks++;
300                 fs->sb->free_blocks++;
301                 /* journal backup */
302                 if (prev_bg_bmap_idx != bg_idx) {
303                         status =
304                             ext4fs_devread(gd[bg_idx].block_id *
305                                            fs->sect_perblk, 0, fs->blksz,
306                                            journal_buffer);
307                         if (status == 0)
308                                 goto fail;
309                         if (ext4fs_log_journal
310                             (journal_buffer, gd[bg_idx].block_id))
311                                 goto fail;
312                         prev_bg_bmap_idx = bg_idx;
313                 }
314         }
315 fail:
316         free(journal_buffer);
317 }
318
319 static void delete_double_indirect_block(struct ext2_inode *inode)
320 {
321         int i;
322         short status;
323         static int prev_bg_bmap_idx = -1;
324         long int blknr;
325         int remainder;
326         int bg_idx;
327         unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
328         unsigned int *di_buffer = NULL;
329         unsigned int *DIB_start_addr = NULL;
330         struct ext2_block_group *gd = NULL;
331         struct ext_filesystem *fs = get_fs();
332         char *journal_buffer = zalloc(fs->blksz);
333         if (!journal_buffer) {
334                 printf("No memory\n");
335                 return;
336         }
337         /* get the block group descriptor table */
338         gd = (struct ext2_block_group *)fs->gdtable;
339
340         if (inode->b.blocks.double_indir_block != 0) {
341                 di_buffer = zalloc(fs->blksz);
342                 if (!di_buffer) {
343                         printf("No memory\n");
344                         return;
345                 }
346                 DIB_start_addr = (unsigned int *)di_buffer;
347                 blknr = inode->b.blocks.double_indir_block;
348                 status = ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
349                                         (char *)di_buffer);
350                 for (i = 0; i < fs->blksz / sizeof(int); i++) {
351                         if (*di_buffer == 0)
352                                 break;
353
354                         debug("DICB releasing %u\n", *di_buffer);
355                         if (fs->blksz != 1024) {
356                                 bg_idx = (*di_buffer) / blk_per_grp;
357                         } else {
358                                 bg_idx = (*di_buffer) / blk_per_grp;
359                                 remainder = (*di_buffer) % blk_per_grp;
360                                 if (!remainder)
361                                         bg_idx--;
362                         }
363                         ext4fs_reset_block_bmap(*di_buffer,
364                                         fs->blk_bmaps[bg_idx], bg_idx);
365                         di_buffer++;
366                         gd[bg_idx].free_blocks++;
367                         fs->sb->free_blocks++;
368                         /* journal backup */
369                         if (prev_bg_bmap_idx != bg_idx) {
370                                 status = ext4fs_devread(gd[bg_idx].block_id
371                                                         * fs->sect_perblk, 0,
372                                                         fs->blksz,
373                                                         journal_buffer);
374                                 if (status == 0)
375                                         goto fail;
376
377                                 if (ext4fs_log_journal(journal_buffer,
378                                                         gd[bg_idx].block_id))
379                                         goto fail;
380                                 prev_bg_bmap_idx = bg_idx;
381                         }
382                 }
383
384                 /* removing the parent double indirect block */
385                 blknr = inode->b.blocks.double_indir_block;
386                 if (fs->blksz != 1024) {
387                         bg_idx = blknr / blk_per_grp;
388                 } else {
389                         bg_idx = blknr / blk_per_grp;
390                         remainder = blknr % blk_per_grp;
391                         if (!remainder)
392                                 bg_idx--;
393                 }
394                 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
395                 gd[bg_idx].free_blocks++;
396                 fs->sb->free_blocks++;
397                 /* journal backup */
398                 if (prev_bg_bmap_idx != bg_idx) {
399                         memset(journal_buffer, '\0', fs->blksz);
400                         status = ext4fs_devread(gd[bg_idx].block_id *
401                                                 fs->sect_perblk, 0, fs->blksz,
402                                                 journal_buffer);
403                         if (status == 0)
404                                 goto fail;
405
406                         if (ext4fs_log_journal(journal_buffer,
407                                                 gd[bg_idx].block_id))
408                                 goto fail;
409                         prev_bg_bmap_idx = bg_idx;
410                 }
411                 debug("DIPB releasing %ld\n", blknr);
412         }
413 fail:
414         free(DIB_start_addr);
415         free(journal_buffer);
416 }
417
418 static void delete_triple_indirect_block(struct ext2_inode *inode)
419 {
420         int i, j;
421         short status;
422         static int prev_bg_bmap_idx = -1;
423         long int blknr;
424         int remainder;
425         int bg_idx;
426         unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
427         unsigned int *tigp_buffer = NULL;
428         unsigned int *tib_start_addr = NULL;
429         unsigned int *tip_buffer = NULL;
430         unsigned int *tipb_start_addr = NULL;
431         struct ext2_block_group *gd = NULL;
432         struct ext_filesystem *fs = get_fs();
433         char *journal_buffer = zalloc(fs->blksz);
434         if (!journal_buffer) {
435                 printf("No memory\n");
436                 return;
437         }
438         /* get block group descriptor table */
439         gd = (struct ext2_block_group *)fs->gdtable;
440
441         if (inode->b.blocks.triple_indir_block != 0) {
442                 tigp_buffer = zalloc(fs->blksz);
443                 if (!tigp_buffer) {
444                         printf("No memory\n");
445                         return;
446                 }
447                 tib_start_addr = (unsigned int *)tigp_buffer;
448                 blknr = inode->b.blocks.triple_indir_block;
449                 status = ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
450                                         (char *)tigp_buffer);
451                 for (i = 0; i < fs->blksz / sizeof(int); i++) {
452                         if (*tigp_buffer == 0)
453                                 break;
454                         debug("tigp buffer releasing %u\n", *tigp_buffer);
455
456                         tip_buffer = zalloc(fs->blksz);
457                         if (!tip_buffer)
458                                 goto fail;
459                         tipb_start_addr = (unsigned int *)tip_buffer;
460                         status = ext4fs_devread((*tigp_buffer) *
461                                                 fs->sect_perblk, 0, fs->blksz,
462                                                 (char *)tip_buffer);
463                         for (j = 0; j < fs->blksz / sizeof(int); j++) {
464                                 if (*tip_buffer == 0)
465                                         break;
466                                 if (fs->blksz != 1024) {
467                                         bg_idx = (*tip_buffer) / blk_per_grp;
468                                 } else {
469                                         bg_idx = (*tip_buffer) / blk_per_grp;
470
471                                         remainder = (*tip_buffer) % blk_per_grp;
472                                         if (!remainder)
473                                                 bg_idx--;
474                                 }
475
476                                 ext4fs_reset_block_bmap(*tip_buffer,
477                                                         fs->blk_bmaps[bg_idx],
478                                                         bg_idx);
479
480                                 tip_buffer++;
481                                 gd[bg_idx].free_blocks++;
482                                 fs->sb->free_blocks++;
483                                 /* journal backup */
484                                 if (prev_bg_bmap_idx != bg_idx) {
485                                         status =
486                                             ext4fs_devread(gd[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                                                                gd[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                         gd[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(gd[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                                                         gd[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                 gd[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(gd[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                                                 gd[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 *gd = 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         gd = (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                         gd[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(gd[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                                                         gd[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                         gd[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(gd[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                                                 gd[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(gd[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         gd[ibmap_idx].free_inodes++;
736         fs->sb->free_inodes++;
737         /* journal backup */
738         memset(journal_buffer, '\0', fs->blksz);
739         status = ext4fs_devread(gd[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, gd[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->gd = (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->gd[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->gd[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->gd[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->gd = 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->gd[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->gd[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