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