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