]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - fs/ext4/ext4_write.c
Merge branch 'u-boot-sh/rmobile' into 'u-boot-arm/master'
[karo-tx-uboot.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         ext4fs_reinit_global();
566
567         if (ext4fs_init() != 0) {
568                 printf("error in File System init\n");
569                 goto fail;
570         }
571
572         free(start_block_address);
573         free(journal_buffer);
574
575         return 0;
576 fail:
577         free(start_block_address);
578         free(journal_buffer);
579
580         return -1;
581 }
582
583 int ext4fs_init(void)
584 {
585         short status;
586         int i;
587         unsigned int real_free_blocks = 0;
588         struct ext_filesystem *fs = get_fs();
589
590         /* populate fs */
591         fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root);
592         fs->inodesz = INODE_SIZE_FILESYSTEM(ext4fs_root);
593         fs->sect_perblk = fs->blksz >> fs->dev_desc->log2blksz;
594
595         /* get the superblock */
596         fs->sb = zalloc(SUPERBLOCK_SIZE);
597         if (!fs->sb)
598                 return -ENOMEM;
599         if (!ext4_read_superblock((char *)fs->sb))
600                 goto fail;
601
602         /* init journal */
603         if (ext4fs_init_journal())
604                 goto fail;
605
606         /* get total no of blockgroups */
607         fs->no_blkgrp = (uint32_t)ext4fs_div_roundup(
608                         (ext4fs_root->sblock.total_blocks -
609                         ext4fs_root->sblock.first_data_block),
610                         ext4fs_root->sblock.blocks_per_group);
611
612         /* get the block group descriptor table */
613         fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1);
614         if (ext4fs_get_bgdtable() == -1) {
615                 printf("Error in getting the block group descriptor table\n");
616                 goto fail;
617         }
618         fs->bgd = (struct ext2_block_group *)fs->gdtable;
619
620         /* load all the available bitmap block of the partition */
621         fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *));
622         if (!fs->blk_bmaps)
623                 goto fail;
624         for (i = 0; i < fs->no_blkgrp; i++) {
625                 fs->blk_bmaps[i] = zalloc(fs->blksz);
626                 if (!fs->blk_bmaps[i])
627                         goto fail;
628         }
629
630         for (i = 0; i < fs->no_blkgrp; i++) {
631                 status =
632                     ext4fs_devread((lbaint_t)fs->bgd[i].block_id *
633                                    fs->sect_perblk, 0,
634                                    fs->blksz, (char *)fs->blk_bmaps[i]);
635                 if (status == 0)
636                         goto fail;
637         }
638
639         /* load all the available inode bitmap of the partition */
640         fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *));
641         if (!fs->inode_bmaps)
642                 goto fail;
643         for (i = 0; i < fs->no_blkgrp; i++) {
644                 fs->inode_bmaps[i] = zalloc(fs->blksz);
645                 if (!fs->inode_bmaps[i])
646                         goto fail;
647         }
648
649         for (i = 0; i < fs->no_blkgrp; i++) {
650                 status = ext4fs_devread((lbaint_t)fs->bgd[i].inode_id *
651                                         fs->sect_perblk,
652                                         0, fs->blksz,
653                                         (char *)fs->inode_bmaps[i]);
654                 if (status == 0)
655                         goto fail;
656         }
657
658         /*
659          * check filesystem consistency with free blocks of file system
660          * some time we observed that superblock freeblocks does not match
661          * with the  blockgroups freeblocks when improper
662          * reboot of a linux kernel
663          */
664         for (i = 0; i < fs->no_blkgrp; i++)
665                 real_free_blocks = real_free_blocks + fs->bgd[i].free_blocks;
666         if (real_free_blocks != fs->sb->free_blocks)
667                 fs->sb->free_blocks = real_free_blocks;
668
669         return 0;
670 fail:
671         ext4fs_deinit();
672
673         return -1;
674 }
675
676 void ext4fs_deinit(void)
677 {
678         int i;
679         struct ext2_inode inode_journal;
680         struct journal_superblock_t *jsb;
681         long int blknr;
682         struct ext_filesystem *fs = get_fs();
683
684         /* free journal */
685         char *temp_buff = zalloc(fs->blksz);
686         if (temp_buff) {
687                 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
688                                   &inode_journal);
689                 blknr = read_allocated_block(&inode_journal,
690                                         EXT2_JOURNAL_SUPERBLOCK);
691                 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
692                                temp_buff);
693                 jsb = (struct journal_superblock_t *)temp_buff;
694                 jsb->s_start = cpu_to_be32(0);
695                 put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
696                          (struct journal_superblock_t *)temp_buff, fs->blksz);
697                 free(temp_buff);
698         }
699         ext4fs_free_journal();
700
701         /* get the superblock */
702         ext4_read_superblock((char *)fs->sb);
703         fs->sb->feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
704         put_ext4((uint64_t)(SUPERBLOCK_SIZE),
705                  (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
706         free(fs->sb);
707         fs->sb = NULL;
708
709         if (fs->blk_bmaps) {
710                 for (i = 0; i < fs->no_blkgrp; i++) {
711                         free(fs->blk_bmaps[i]);
712                         fs->blk_bmaps[i] = NULL;
713                 }
714                 free(fs->blk_bmaps);
715                 fs->blk_bmaps = NULL;
716         }
717
718         if (fs->inode_bmaps) {
719                 for (i = 0; i < fs->no_blkgrp; i++) {
720                         free(fs->inode_bmaps[i]);
721                         fs->inode_bmaps[i] = NULL;
722                 }
723                 free(fs->inode_bmaps);
724                 fs->inode_bmaps = NULL;
725         }
726
727
728         free(fs->gdtable);
729         fs->gdtable = NULL;
730         fs->bgd = NULL;
731         /*
732          * reinitiliazed the global inode and
733          * block bitmap first execution check variables
734          */
735         fs->first_pass_ibmap = 0;
736         fs->first_pass_bbmap = 0;
737         fs->curr_inode_no = 0;
738         fs->curr_blkno = 0;
739 }
740
741 static int ext4fs_write_file(struct ext2_inode *file_inode,
742                              int pos, unsigned int len, char *buf)
743 {
744         int i;
745         int blockcnt;
746         unsigned int filesize = __le32_to_cpu(file_inode->size);
747         struct ext_filesystem *fs = get_fs();
748         int log2blksz = fs->dev_desc->log2blksz;
749         int log2_fs_blocksize = LOG2_BLOCK_SIZE(ext4fs_root) - log2blksz;
750         int previous_block_number = -1;
751         int delayed_start = 0;
752         int delayed_extent = 0;
753         int delayed_next = 0;
754         char *delayed_buf = NULL;
755
756         /* Adjust len so it we can't read past the end of the file. */
757         if (len > filesize)
758                 len = filesize;
759
760         blockcnt = ((len + pos) + fs->blksz - 1) / fs->blksz;
761
762         for (i = pos / fs->blksz; i < blockcnt; i++) {
763                 long int blknr;
764                 int blockend = fs->blksz;
765                 int skipfirst = 0;
766                 blknr = read_allocated_block(file_inode, i);
767                 if (blknr < 0)
768                         return -1;
769
770                 blknr = blknr << log2_fs_blocksize;
771
772                 if (blknr) {
773                         if (previous_block_number != -1) {
774                                 if (delayed_next == blknr) {
775                                         delayed_extent += blockend;
776                                         delayed_next += blockend >> log2blksz;
777                                 } else {        /* spill */
778                                         put_ext4((uint64_t)
779                                                  ((uint64_t)delayed_start << log2blksz),
780                                                  delayed_buf,
781                                                  (uint32_t) delayed_extent);
782                                         previous_block_number = blknr;
783                                         delayed_start = blknr;
784                                         delayed_extent = blockend;
785                                         delayed_buf = buf;
786                                         delayed_next = blknr +
787                                             (blockend >> log2blksz);
788                                 }
789                         } else {
790                                 previous_block_number = blknr;
791                                 delayed_start = blknr;
792                                 delayed_extent = blockend;
793                                 delayed_buf = buf;
794                                 delayed_next = blknr +
795                                     (blockend >> log2blksz);
796                         }
797                 } else {
798                         if (previous_block_number != -1) {
799                                 /* spill */
800                                 put_ext4((uint64_t) ((uint64_t)delayed_start <<
801                                                      log2blksz),
802                                          delayed_buf,
803                                          (uint32_t) delayed_extent);
804                                 previous_block_number = -1;
805                         }
806                         memset(buf, 0, fs->blksz - skipfirst);
807                 }
808                 buf += fs->blksz - skipfirst;
809         }
810         if (previous_block_number != -1) {
811                 /* spill */
812                 put_ext4((uint64_t) ((uint64_t)delayed_start << log2blksz),
813                          delayed_buf, (uint32_t) delayed_extent);
814                 previous_block_number = -1;
815         }
816
817         return len;
818 }
819
820 int ext4fs_write(const char *fname, unsigned char *buffer,
821                                         unsigned long sizebytes)
822 {
823         int ret = 0;
824         struct ext2_inode *file_inode = NULL;
825         unsigned char *inode_buffer = NULL;
826         int parent_inodeno;
827         int inodeno;
828         time_t timestamp = 0;
829
830         uint64_t bytes_reqd_for_file;
831         unsigned int blks_reqd_for_file;
832         unsigned int blocks_remaining;
833         int existing_file_inodeno;
834         char *temp_ptr = NULL;
835         long int itable_blkno;
836         long int parent_itable_blkno;
837         long int blkoff;
838         struct ext2_sblock *sblock = &(ext4fs_root->sblock);
839         unsigned int inodes_per_block;
840         unsigned int ibmap_idx;
841         struct ext_filesystem *fs = get_fs();
842         ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256);
843         memset(filename, 0x00, 256);
844
845         g_parent_inode = zalloc(sizeof(struct ext2_inode));
846         if (!g_parent_inode)
847                 goto fail;
848
849         if (ext4fs_init() != 0) {
850                 printf("error in File System init\n");
851                 return -1;
852         }
853         inodes_per_block = fs->blksz / fs->inodesz;
854         parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE);
855         if (parent_inodeno == -1)
856                 goto fail;
857         if (ext4fs_iget(parent_inodeno, g_parent_inode))
858                 goto fail;
859         /* check if the filename is already present in root */
860         existing_file_inodeno = ext4fs_filename_check(filename);
861         if (existing_file_inodeno != -1) {
862                 ret = ext4fs_delete_file(existing_file_inodeno);
863                 fs->first_pass_bbmap = 0;
864                 fs->curr_blkno = 0;
865
866                 fs->first_pass_ibmap = 0;
867                 fs->curr_inode_no = 0;
868                 if (ret)
869                         goto fail;
870         }
871         /* calucalate how many blocks required */
872         bytes_reqd_for_file = sizebytes;
873         blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz);
874         if (do_div(bytes_reqd_for_file, fs->blksz) != 0) {
875                 blks_reqd_for_file++;
876                 debug("total bytes for a file %u\n", blks_reqd_for_file);
877         }
878         blocks_remaining = blks_reqd_for_file;
879         /* test for available space in partition */
880         if (fs->sb->free_blocks < blks_reqd_for_file) {
881                 printf("Not enough space on partition !!!\n");
882                 goto fail;
883         }
884
885         ext4fs_update_parent_dentry(filename, &inodeno, FILETYPE_REG);
886         /* prepare file inode */
887         inode_buffer = zalloc(fs->inodesz);
888         if (!inode_buffer)
889                 goto fail;
890         file_inode = (struct ext2_inode *)inode_buffer;
891         file_inode->mode = S_IFREG | S_IRWXU |
892             S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH;
893         /* ToDo: Update correct time */
894         file_inode->mtime = timestamp;
895         file_inode->atime = timestamp;
896         file_inode->ctime = timestamp;
897         file_inode->nlinks = 1;
898         file_inode->size = sizebytes;
899
900         /* Allocate data blocks */
901         ext4fs_allocate_blocks(file_inode, blocks_remaining,
902                                &blks_reqd_for_file);
903         file_inode->blockcnt = (blks_reqd_for_file * fs->blksz) >>
904                 fs->dev_desc->log2blksz;
905
906         temp_ptr = zalloc(fs->blksz);
907         if (!temp_ptr)
908                 goto fail;
909         ibmap_idx = inodeno / ext4fs_root->sblock.inodes_per_group;
910         inodeno--;
911         itable_blkno = __le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
912                         (inodeno % __le32_to_cpu(sblock->inodes_per_group)) /
913                         inodes_per_block;
914         blkoff = (inodeno % inodes_per_block) * fs->inodesz;
915         ext4fs_devread((lbaint_t)itable_blkno * fs->sect_perblk, 0, fs->blksz,
916                        temp_ptr);
917         if (ext4fs_log_journal(temp_ptr, itable_blkno))
918                 goto fail;
919
920         memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz);
921         if (ext4fs_put_metadata(temp_ptr, itable_blkno))
922                 goto fail;
923         /* copy the file content into data blocks */
924         if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) {
925                 printf("Error in copying content\n");
926                 goto fail;
927         }
928         ibmap_idx = parent_inodeno / ext4fs_root->sblock.inodes_per_group;
929         parent_inodeno--;
930         parent_itable_blkno = __le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
931             (parent_inodeno %
932              __le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
933         blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz;
934         if (parent_itable_blkno != itable_blkno) {
935                 memset(temp_ptr, '\0', fs->blksz);
936                 ext4fs_devread((lbaint_t)parent_itable_blkno * fs->sect_perblk,
937                                0, fs->blksz, temp_ptr);
938                 if (ext4fs_log_journal(temp_ptr, parent_itable_blkno))
939                         goto fail;
940
941                 memcpy(temp_ptr + blkoff, g_parent_inode,
942                         sizeof(struct ext2_inode));
943                 if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno))
944                         goto fail;
945                 free(temp_ptr);
946         } else {
947                 /*
948                  * If parent and child fall in same inode table block
949                  * both should be kept in 1 buffer
950                  */
951                 memcpy(temp_ptr + blkoff, g_parent_inode,
952                        sizeof(struct ext2_inode));
953                 gd_index--;
954                 if (ext4fs_put_metadata(temp_ptr, itable_blkno))
955                         goto fail;
956                 free(temp_ptr);
957         }
958         ext4fs_update();
959         ext4fs_deinit();
960
961         fs->first_pass_bbmap = 0;
962         fs->curr_blkno = 0;
963         fs->first_pass_ibmap = 0;
964         fs->curr_inode_no = 0;
965         free(inode_buffer);
966         free(g_parent_inode);
967         g_parent_inode = NULL;
968
969         return 0;
970 fail:
971         ext4fs_deinit();
972         free(inode_buffer);
973         free(g_parent_inode);
974         g_parent_inode = NULL;
975
976         return -1;
977 }