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