]> git.sur5r.net Git - u-boot/blob - fs/ext4/ext4fs.c
64d8a6d9723a7eedb00bc918b6d6f258568c2f4d
[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 <div64.h>
44 #include "ext4_common.h"
45
46 int ext4fs_symlinknest;
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_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->bgd[i].bg_checksum = ext4fs_checksum_update(i);
214                 put_ext4((uint64_t)(fs->bgd[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->bgd[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 *bgd = 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         bgd = (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                 bgd[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(bgd[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, bgd[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 *bgd = 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         bgd = (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                         bgd[bg_idx].free_blocks++;
367                         fs->sb->free_blocks++;
368                         /* journal backup */
369                         if (prev_bg_bmap_idx != bg_idx) {
370                                 status = ext4fs_devread(bgd[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                                                         bgd[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                 bgd[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(bgd[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                                                 bgd[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 *bgd = 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         bgd = (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                                 bgd[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(
487                                                         bgd[bg_idx].block_id *
488                                                         fs->sect_perblk, 0,
489                                                         fs->blksz,
490                                                         journal_buffer);
491                                         if (status == 0)
492                                                 goto fail;
493
494                                         if (ext4fs_log_journal(journal_buffer,
495                                                                bgd[bg_idx].
496                                                                block_id))
497                                                 goto fail;
498                                         prev_bg_bmap_idx = bg_idx;
499                                 }
500                         }
501                         free(tipb_start_addr);
502                         tipb_start_addr = NULL;
503
504                         /*
505                          * removing the grand parent blocks
506                          * which is connected to inode
507                          */
508                         if (fs->blksz != 1024) {
509                                 bg_idx = (*tigp_buffer) / blk_per_grp;
510                         } else {
511                                 bg_idx = (*tigp_buffer) / blk_per_grp;
512
513                                 remainder = (*tigp_buffer) % blk_per_grp;
514                                 if (!remainder)
515                                         bg_idx--;
516                         }
517                         ext4fs_reset_block_bmap(*tigp_buffer,
518                                                 fs->blk_bmaps[bg_idx], bg_idx);
519
520                         tigp_buffer++;
521                         bgd[bg_idx].free_blocks++;
522                         fs->sb->free_blocks++;
523                         /* journal backup */
524                         if (prev_bg_bmap_idx != bg_idx) {
525                                 memset(journal_buffer, '\0', fs->blksz);
526                                 status =
527                                     ext4fs_devread(bgd[bg_idx].block_id *
528                                                    fs->sect_perblk, 0,
529                                                    fs->blksz, journal_buffer);
530                                 if (status == 0)
531                                         goto fail;
532
533                                 if (ext4fs_log_journal(journal_buffer,
534                                                         bgd[bg_idx].block_id))
535                                         goto fail;
536                                 prev_bg_bmap_idx = bg_idx;
537                         }
538                 }
539
540                 /* removing the grand parent triple indirect block */
541                 blknr = inode->b.blocks.triple_indir_block;
542                 if (fs->blksz != 1024) {
543                         bg_idx = blknr / blk_per_grp;
544                 } else {
545                         bg_idx = blknr / blk_per_grp;
546                         remainder = blknr % blk_per_grp;
547                         if (!remainder)
548                                 bg_idx--;
549                 }
550                 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
551                 bgd[bg_idx].free_blocks++;
552                 fs->sb->free_blocks++;
553                 /* journal backup */
554                 if (prev_bg_bmap_idx != bg_idx) {
555                         memset(journal_buffer, '\0', fs->blksz);
556                         status = ext4fs_devread(bgd[bg_idx].block_id *
557                                                 fs->sect_perblk, 0, fs->blksz,
558                                                 journal_buffer);
559                         if (status == 0)
560                                 goto fail;
561
562                         if (ext4fs_log_journal(journal_buffer,
563                                                 bgd[bg_idx].block_id))
564                                 goto fail;
565                         prev_bg_bmap_idx = bg_idx;
566                 }
567                 debug("tigp buffer itself releasing %ld\n", blknr);
568         }
569 fail:
570         free(tib_start_addr);
571         free(tipb_start_addr);
572         free(journal_buffer);
573 }
574
575 static int ext4fs_delete_file(int inodeno)
576 {
577         struct ext2_inode inode;
578         short status;
579         int i;
580         int remainder;
581         long int blknr;
582         int bg_idx;
583         int ibmap_idx;
584         char *read_buffer = NULL;
585         char *start_block_address = NULL;
586         unsigned int no_blocks;
587
588         static int prev_bg_bmap_idx = -1;
589         unsigned int inodes_per_block;
590         long int blkno;
591         unsigned int blkoff;
592         unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
593         unsigned int inode_per_grp = ext4fs_root->sblock.inodes_per_group;
594         struct ext2_inode *inode_buffer = NULL;
595         struct ext2_block_group *bgd = NULL;
596         struct ext_filesystem *fs = get_fs();
597         char *journal_buffer = zalloc(fs->blksz);
598         if (!journal_buffer)
599                 return -ENOMEM;
600         /* get the block group descriptor table */
601         bgd = (struct ext2_block_group *)fs->gdtable;
602         status = ext4fs_read_inode(ext4fs_root, inodeno, &inode);
603         if (status == 0)
604                 goto fail;
605
606         /* read the block no allocated to a file */
607         no_blocks = inode.size / fs->blksz;
608         if (inode.size % fs->blksz)
609                 no_blocks++;
610
611         if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FL) {
612                 struct ext2fs_node *node_inode =
613                     zalloc(sizeof(struct ext2fs_node));
614                 if (!node_inode)
615                         goto fail;
616                 node_inode->data = ext4fs_root;
617                 node_inode->ino = inodeno;
618                 node_inode->inode_read = 0;
619                 memcpy(&(node_inode->inode), &inode, sizeof(struct ext2_inode));
620
621                 for (i = 0; i < no_blocks; i++) {
622                         blknr = read_allocated_block(&(node_inode->inode), i);
623                         if (fs->blksz != 1024) {
624                                 bg_idx = blknr / blk_per_grp;
625                         } else {
626                                 bg_idx = blknr / blk_per_grp;
627                                 remainder = blknr % blk_per_grp;
628                                 if (!remainder)
629                                         bg_idx--;
630                         }
631                         ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx],
632                                                 bg_idx);
633                         debug("EXT4_EXTENTS Block releasing %ld: %d\n",
634                               blknr, bg_idx);
635
636                         bgd[bg_idx].free_blocks++;
637                         fs->sb->free_blocks++;
638
639                         /* journal backup */
640                         if (prev_bg_bmap_idx != bg_idx) {
641                                 status =
642                                     ext4fs_devread(bgd[bg_idx].block_id *
643                                                    fs->sect_perblk, 0,
644                                                    fs->blksz, journal_buffer);
645                                 if (status == 0)
646                                         goto fail;
647                                 if (ext4fs_log_journal(journal_buffer,
648                                                         bgd[bg_idx].block_id))
649                                         goto fail;
650                                 prev_bg_bmap_idx = bg_idx;
651                         }
652                 }
653                 if (node_inode) {
654                         free(node_inode);
655                         node_inode = NULL;
656                 }
657         } else {
658
659                 delete_single_indirect_block(&inode);
660                 delete_double_indirect_block(&inode);
661                 delete_triple_indirect_block(&inode);
662
663                 /* read the block no allocated to a file */
664                 no_blocks = inode.size / fs->blksz;
665                 if (inode.size % fs->blksz)
666                         no_blocks++;
667                 for (i = 0; i < no_blocks; i++) {
668                         blknr = read_allocated_block(&inode, i);
669                         if (fs->blksz != 1024) {
670                                 bg_idx = blknr / blk_per_grp;
671                         } else {
672                                 bg_idx = blknr / blk_per_grp;
673                                 remainder = blknr % blk_per_grp;
674                                 if (!remainder)
675                                         bg_idx--;
676                         }
677                         ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx],
678                                                 bg_idx);
679                         debug("ActualB releasing %ld: %d\n", blknr, bg_idx);
680
681                         bgd[bg_idx].free_blocks++;
682                         fs->sb->free_blocks++;
683                         /* journal backup */
684                         if (prev_bg_bmap_idx != bg_idx) {
685                                 memset(journal_buffer, '\0', fs->blksz);
686                                 status = ext4fs_devread(bgd[bg_idx].block_id
687                                                         * fs->sect_perblk,
688                                                         0, fs->blksz,
689                                                         journal_buffer);
690                                 if (status == 0)
691                                         goto fail;
692                                 if (ext4fs_log_journal(journal_buffer,
693                                                 bgd[bg_idx].block_id))
694                                         goto fail;
695                                 prev_bg_bmap_idx = bg_idx;
696                         }
697                 }
698         }
699
700         /* from the inode no to blockno */
701         inodes_per_block = fs->blksz / fs->inodesz;
702         ibmap_idx = inodeno / inode_per_grp;
703
704         /* get the block no */
705         inodeno--;
706         blkno = __le32_to_cpu(bgd[ibmap_idx].inode_table_id) +
707                 (inodeno % __le32_to_cpu(inode_per_grp)) / inodes_per_block;
708
709         /* get the offset of the inode */
710         blkoff = ((inodeno) % inodes_per_block) * fs->inodesz;
711
712         /* read the block no containing the inode */
713         read_buffer = zalloc(fs->blksz);
714         if (!read_buffer)
715                 goto fail;
716         start_block_address = read_buffer;
717         status = ext4fs_devread(blkno * fs->sect_perblk,
718                                 0, fs->blksz, read_buffer);
719         if (status == 0)
720                 goto fail;
721
722         if (ext4fs_log_journal(read_buffer, blkno))
723                 goto fail;
724
725         read_buffer = read_buffer + blkoff;
726         inode_buffer = (struct ext2_inode *)read_buffer;
727         memset(inode_buffer, '\0', sizeof(struct ext2_inode));
728
729         /* write the inode to original position in inode table */
730         if (ext4fs_put_metadata(start_block_address, blkno))
731                 goto fail;
732
733         /* update the respective inode bitmaps */
734         inodeno++;
735         ext4fs_reset_inode_bmap(inodeno, fs->inode_bmaps[ibmap_idx], ibmap_idx);
736         bgd[ibmap_idx].free_inodes++;
737         fs->sb->free_inodes++;
738         /* journal backup */
739         memset(journal_buffer, '\0', fs->blksz);
740         status = ext4fs_devread(bgd[ibmap_idx].inode_id *
741                                 fs->sect_perblk, 0, fs->blksz, journal_buffer);
742         if (status == 0)
743                 goto fail;
744         if (ext4fs_log_journal(journal_buffer, bgd[ibmap_idx].inode_id))
745                 goto fail;
746
747         ext4fs_update();
748         ext4fs_deinit();
749
750         if (ext4fs_init() != 0) {
751                 printf("error in File System init\n");
752                 goto fail;
753         }
754
755         free(start_block_address);
756         free(journal_buffer);
757
758         return 0;
759 fail:
760         free(start_block_address);
761         free(journal_buffer);
762
763         return -1;
764 }
765
766 int ext4fs_init(void)
767 {
768         short status;
769         int i;
770         unsigned int real_free_blocks = 0;
771         struct ext_filesystem *fs = get_fs();
772
773         /* populate fs */
774         fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root);
775         fs->inodesz = INODE_SIZE_FILESYSTEM(ext4fs_root);
776         fs->sect_perblk = fs->blksz / SECTOR_SIZE;
777
778         /* get the superblock */
779         fs->sb = zalloc(SUPERBLOCK_SIZE);
780         if (!fs->sb)
781                 return -ENOMEM;
782         if (!ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE,
783                         (char *)fs->sb))
784                 goto fail;
785
786         /* init journal */
787         if (ext4fs_init_journal())
788                 goto fail;
789
790         /* get total no of blockgroups */
791         fs->no_blkgrp = (uint32_t)ext4fs_div_roundup(
792                         (ext4fs_root->sblock.total_blocks -
793                         ext4fs_root->sblock.first_data_block),
794                         ext4fs_root->sblock.blocks_per_group);
795
796         /* get the block group descriptor table */
797         fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1);
798         if (ext4fs_get_bgdtable() == -1) {
799                 printf("Error in getting the block group descriptor table\n");
800                 goto fail;
801         }
802         fs->bgd = (struct ext2_block_group *)fs->gdtable;
803
804         /* load all the available bitmap block of the partition */
805         fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *));
806         if (!fs->blk_bmaps)
807                 goto fail;
808         for (i = 0; i < fs->no_blkgrp; i++) {
809                 fs->blk_bmaps[i] = zalloc(fs->blksz);
810                 if (!fs->blk_bmaps[i])
811                         goto fail;
812         }
813
814         for (i = 0; i < fs->no_blkgrp; i++) {
815                 status =
816                     ext4fs_devread(fs->bgd[i].block_id * fs->sect_perblk, 0,
817                                    fs->blksz, (char *)fs->blk_bmaps[i]);
818                 if (status == 0)
819                         goto fail;
820         }
821
822         /* load all the available inode bitmap of the partition */
823         fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *));
824         if (!fs->inode_bmaps)
825                 goto fail;
826         for (i = 0; i < fs->no_blkgrp; i++) {
827                 fs->inode_bmaps[i] = zalloc(fs->blksz);
828                 if (!fs->inode_bmaps[i])
829                         goto fail;
830         }
831
832         for (i = 0; i < fs->no_blkgrp; i++) {
833                 status = ext4fs_devread(fs->bgd[i].inode_id * fs->sect_perblk,
834                                         0, fs->blksz,
835                                         (char *)fs->inode_bmaps[i]);
836                 if (status == 0)
837                         goto fail;
838         }
839
840         /*
841          * check filesystem consistency with free blocks of file system
842          * some time we observed that superblock freeblocks does not match
843          * with the  blockgroups freeblocks when improper
844          * reboot of a linux kernel
845          */
846         for (i = 0; i < fs->no_blkgrp; i++)
847                 real_free_blocks = real_free_blocks + fs->bgd[i].free_blocks;
848         if (real_free_blocks != fs->sb->free_blocks)
849                 fs->sb->free_blocks = real_free_blocks;
850
851         return 0;
852 fail:
853         ext4fs_deinit();
854
855         return -1;
856 }
857
858 void ext4fs_deinit(void)
859 {
860         int i;
861         struct ext2_inode inode_journal;
862         struct journal_superblock_t *jsb;
863         long int blknr;
864         struct ext_filesystem *fs = get_fs();
865
866         /* free journal */
867         char *temp_buff = zalloc(fs->blksz);
868         if (temp_buff) {
869                 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
870                                   &inode_journal);
871                 blknr = read_allocated_block(&inode_journal,
872                                         EXT2_JOURNAL_SUPERBLOCK);
873                 ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
874                                temp_buff);
875                 jsb = (struct journal_superblock_t *)temp_buff;
876                 jsb->s_start = cpu_to_be32(0);
877                 put_ext4((uint64_t) (blknr * fs->blksz),
878                          (struct journal_superblock_t *)temp_buff, fs->blksz);
879                 free(temp_buff);
880         }
881         ext4fs_free_journal();
882
883         /* get the superblock */
884         ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE, (char *)fs->sb);
885         fs->sb->feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
886         put_ext4((uint64_t)(SUPERBLOCK_SIZE),
887                  (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
888         free(fs->sb);
889         fs->sb = NULL;
890
891         if (fs->blk_bmaps) {
892                 for (i = 0; i < fs->no_blkgrp; i++) {
893                         free(fs->blk_bmaps[i]);
894                         fs->blk_bmaps[i] = NULL;
895                 }
896                 free(fs->blk_bmaps);
897                 fs->blk_bmaps = NULL;
898         }
899
900         if (fs->inode_bmaps) {
901                 for (i = 0; i < fs->no_blkgrp; i++) {
902                         free(fs->inode_bmaps[i]);
903                         fs->inode_bmaps[i] = NULL;
904                 }
905                 free(fs->inode_bmaps);
906                 fs->inode_bmaps = NULL;
907         }
908
909
910         free(fs->gdtable);
911         fs->gdtable = NULL;
912         fs->bgd = NULL;
913         /*
914          * reinitiliazed the global inode and
915          * block bitmap first execution check variables
916          */
917         fs->first_pass_ibmap = 0;
918         fs->first_pass_bbmap = 0;
919         fs->curr_inode_no = 0;
920         fs->curr_blkno = 0;
921 }
922
923 static int ext4fs_write_file(struct ext2_inode *file_inode,
924                              int pos, unsigned int len, char *buf)
925 {
926         int i;
927         int blockcnt;
928         int log2blocksize = LOG2_EXT2_BLOCK_SIZE(ext4fs_root);
929         unsigned int filesize = __le32_to_cpu(file_inode->size);
930         struct ext_filesystem *fs = get_fs();
931         int previous_block_number = -1;
932         int delayed_start = 0;
933         int delayed_extent = 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_buf = buf;
967                                         delayed_next = blknr +
968                                             (blockend >> SECTOR_BITS);
969                                 }
970                         } else {
971                                 previous_block_number = blknr;
972                                 delayed_start = blknr;
973                                 delayed_extent = blockend;
974                                 delayed_buf = buf;
975                                 delayed_next = blknr +
976                                     (blockend >> SECTOR_BITS);
977                         }
978                 } else {
979                         if (previous_block_number != -1) {
980                                 /* spill */
981                                 put_ext4((uint64_t) (delayed_start *
982                                                      SECTOR_SIZE), delayed_buf,
983                                          (uint32_t) delayed_extent);
984                                 previous_block_number = -1;
985                         }
986                         memset(buf, 0, fs->blksz - skipfirst);
987                 }
988                 buf += fs->blksz - skipfirst;
989         }
990         if (previous_block_number != -1) {
991                 /* spill */
992                 put_ext4((uint64_t) (delayed_start * SECTOR_SIZE),
993                          delayed_buf, (uint32_t) delayed_extent);
994                 previous_block_number = -1;
995         }
996
997         return len;
998 }
999
1000 int ext4fs_write(const char *fname, unsigned char *buffer,
1001                                         unsigned long sizebytes)
1002 {
1003         int ret = 0;
1004         struct ext2_inode *file_inode = NULL;
1005         unsigned char *inode_buffer = NULL;
1006         int parent_inodeno;
1007         int inodeno;
1008         time_t timestamp = 0;
1009
1010         uint64_t bytes_reqd_for_file;
1011         unsigned int blks_reqd_for_file;
1012         unsigned int blocks_remaining;
1013         int existing_file_inodeno;
1014         char filename[256];
1015
1016         char *temp_ptr = NULL;
1017         long int itable_blkno;
1018         long int parent_itable_blkno;
1019         long int blkoff;
1020         struct ext2_sblock *sblock = &(ext4fs_root->sblock);
1021         unsigned int inodes_per_block;
1022         unsigned int ibmap_idx;
1023         struct ext_filesystem *fs = get_fs();
1024         g_parent_inode = zalloc(sizeof(struct ext2_inode));
1025         if (!g_parent_inode)
1026                 goto fail;
1027
1028         if (ext4fs_init() != 0) {
1029                 printf("error in File System init\n");
1030                 return -1;
1031         }
1032         inodes_per_block = fs->blksz / fs->inodesz;
1033         parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE);
1034         if (parent_inodeno == -1)
1035                 goto fail;
1036         if (ext4fs_iget(parent_inodeno, g_parent_inode))
1037                 goto fail;
1038         /* check if the filename is already present in root */
1039         existing_file_inodeno = ext4fs_filename_check(filename);
1040         if (existing_file_inodeno != -1) {
1041                 ret = ext4fs_delete_file(existing_file_inodeno);
1042                 fs->first_pass_bbmap = 0;
1043                 fs->curr_blkno = 0;
1044
1045                 fs->first_pass_ibmap = 0;
1046                 fs->curr_inode_no = 0;
1047                 if (ret)
1048                         goto fail;
1049         }
1050         /* calucalate how many blocks required */
1051         bytes_reqd_for_file = sizebytes;
1052         blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz);
1053         if (do_div(bytes_reqd_for_file, fs->blksz) != 0) {
1054                 blks_reqd_for_file++;
1055                 debug("total bytes for a file %u\n", blks_reqd_for_file);
1056         }
1057         blocks_remaining = blks_reqd_for_file;
1058         /* test for available space in partition */
1059         if (fs->sb->free_blocks < blks_reqd_for_file) {
1060                 printf("Not enough space on partition !!!\n");
1061                 goto fail;
1062         }
1063
1064         ext4fs_update_parent_dentry(filename, &inodeno, FILETYPE_REG);
1065         /* prepare file inode */
1066         inode_buffer = zalloc(fs->inodesz);
1067         if (!inode_buffer)
1068                 goto fail;
1069         file_inode = (struct ext2_inode *)inode_buffer;
1070         file_inode->mode = S_IFREG | S_IRWXU |
1071             S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH;
1072         /* ToDo: Update correct time */
1073         file_inode->mtime = timestamp;
1074         file_inode->atime = timestamp;
1075         file_inode->ctime = timestamp;
1076         file_inode->nlinks = 1;
1077         file_inode->size = sizebytes;
1078
1079         /* Allocate data blocks */
1080         ext4fs_allocate_blocks(file_inode, blocks_remaining,
1081                                &blks_reqd_for_file);
1082         file_inode->blockcnt = (blks_reqd_for_file * fs->blksz) / SECTOR_SIZE;
1083
1084         temp_ptr = zalloc(fs->blksz);
1085         if (!temp_ptr)
1086                 goto fail;
1087         ibmap_idx = inodeno / ext4fs_root->sblock.inodes_per_group;
1088         inodeno--;
1089         itable_blkno = __le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
1090                         (inodeno % __le32_to_cpu(sblock->inodes_per_group)) /
1091                         inodes_per_block;
1092         blkoff = (inodeno % inodes_per_block) * fs->inodesz;
1093         ext4fs_devread(itable_blkno * fs->sect_perblk, 0, fs->blksz, temp_ptr);
1094         if (ext4fs_log_journal(temp_ptr, itable_blkno))
1095                 goto fail;
1096
1097         memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz);
1098         if (ext4fs_put_metadata(temp_ptr, itable_blkno))
1099                 goto fail;
1100         /* copy the file content into data blocks */
1101         if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) {
1102                 printf("Error in copying content\n");
1103                 goto fail;
1104         }
1105         ibmap_idx = parent_inodeno / ext4fs_root->sblock.inodes_per_group;
1106         parent_inodeno--;
1107         parent_itable_blkno = __le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
1108             (parent_inodeno %
1109              __le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
1110         blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz;
1111         if (parent_itable_blkno != itable_blkno) {
1112                 memset(temp_ptr, '\0', fs->blksz);
1113                 ext4fs_devread(parent_itable_blkno * fs->sect_perblk,
1114                                0, fs->blksz, temp_ptr);
1115                 if (ext4fs_log_journal(temp_ptr, parent_itable_blkno))
1116                         goto fail;
1117
1118                 memcpy(temp_ptr + blkoff, g_parent_inode,
1119                         sizeof(struct ext2_inode));
1120                 if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno))
1121                         goto fail;
1122                 free(temp_ptr);
1123         } else {
1124                 /*
1125                  * If parent and child fall in same inode table block
1126                  * both should be kept in 1 buffer
1127                  */
1128                 memcpy(temp_ptr + blkoff, g_parent_inode,
1129                        sizeof(struct ext2_inode));
1130                 gd_index--;
1131                 if (ext4fs_put_metadata(temp_ptr, itable_blkno))
1132                         goto fail;
1133                 free(temp_ptr);
1134         }
1135         ext4fs_update();
1136         ext4fs_deinit();
1137
1138         fs->first_pass_bbmap = 0;
1139         fs->curr_blkno = 0;
1140         fs->first_pass_ibmap = 0;
1141         fs->curr_inode_no = 0;
1142         free(inode_buffer);
1143         free(g_parent_inode);
1144         g_parent_inode = NULL;
1145
1146         return 0;
1147 fail:
1148         ext4fs_deinit();
1149         free(inode_buffer);
1150         free(g_parent_inode);
1151         g_parent_inode = NULL;
1152
1153         return -1;
1154 }
1155 #endif