tizen 2.4 release
[kernel/u-boot-tm1.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 / SECTOR_SIZE;
618
619         /* get the superblock */
620         fs->sb = zalloc(SUPERBLOCK_SIZE);
621         if (!fs->sb)
622                 return -ENOMEM;
623         if (!ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE,
624                         (char *)fs->sb))
625                 goto fail;
626
627         /* init journal */
628         if (ext4fs_init_journal())
629                 goto fail;
630
631         /* get total no of blockgroups */
632         fs->no_blkgrp = (uint32_t)ext4fs_div_roundup(
633                         (ext4fs_root->sblock.total_blocks -
634                         ext4fs_root->sblock.first_data_block),
635                         ext4fs_root->sblock.blocks_per_group);
636
637         /* get the block group descriptor table */
638         fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1);
639         if (ext4fs_get_bgdtable() == -1) {
640                 printf("Error in getting the block group descriptor table\n");
641                 goto fail;
642         }
643         fs->bgd = (struct ext2_block_group *)fs->gdtable;
644
645         /* load all the available bitmap block of the partition */
646         fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *));
647         if (!fs->blk_bmaps)
648                 goto fail;
649         for (i = 0; i < fs->no_blkgrp; i++) {
650                 fs->blk_bmaps[i] = zalloc(fs->blksz);
651                 if (!fs->blk_bmaps[i])
652                         goto fail;
653         }
654
655         for (i = 0; i < fs->no_blkgrp; i++) {
656                 status =
657                     ext4fs_devread(fs->bgd[i].block_id * fs->sect_perblk, 0,
658                                    fs->blksz, (char *)fs->blk_bmaps[i]);
659                 if (status == 0)
660                         goto fail;
661         }
662
663         /* load all the available inode bitmap of the partition */
664         fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *));
665         if (!fs->inode_bmaps)
666                 goto fail;
667         for (i = 0; i < fs->no_blkgrp; i++) {
668                 fs->inode_bmaps[i] = zalloc(fs->blksz);
669                 if (!fs->inode_bmaps[i])
670                         goto fail;
671         }
672
673         for (i = 0; i < fs->no_blkgrp; i++) {
674                 status = ext4fs_devread(fs->bgd[i].inode_id * fs->sect_perblk,
675                                         0, fs->blksz,
676                                         (char *)fs->inode_bmaps[i]);
677                 if (status == 0)
678                         goto fail;
679         }
680
681         /*
682          * check filesystem consistency with free blocks of file system
683          * some time we observed that superblock freeblocks does not match
684          * with the  blockgroups freeblocks when improper
685          * reboot of a linux kernel
686          */
687         for (i = 0; i < fs->no_blkgrp; i++)
688                 real_free_blocks = real_free_blocks + fs->bgd[i].free_blocks;
689         if (real_free_blocks != fs->sb->free_blocks)
690                 fs->sb->free_blocks = real_free_blocks;
691
692         return 0;
693 fail:
694         ext4fs_deinit();
695
696         return -1;
697 }
698
699 void ext4fs_deinit(void)
700 {
701         int i;
702         struct ext2_inode inode_journal;
703         struct journal_superblock_t *jsb;
704         long int blknr;
705         struct ext_filesystem *fs = get_fs();
706
707         /* free journal */
708         char *temp_buff = zalloc(fs->blksz);
709         if (temp_buff) {
710                 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
711                                   &inode_journal);
712                 blknr = read_allocated_block(&inode_journal,
713                                         EXT2_JOURNAL_SUPERBLOCK);
714                 ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
715                                temp_buff);
716                 jsb = (struct journal_superblock_t *)temp_buff;
717                 jsb->s_start = cpu_to_be32(0);
718                 put_ext4((uint64_t) (blknr * fs->blksz),
719                          (struct journal_superblock_t *)temp_buff, fs->blksz);
720                 free(temp_buff);
721         }
722         ext4fs_free_journal();
723
724         /* get the superblock */
725         ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE, (char *)fs->sb);
726         fs->sb->feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
727         put_ext4((uint64_t)(SUPERBLOCK_SIZE),
728                  (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
729         free(fs->sb);
730         fs->sb = NULL;
731
732         if (fs->blk_bmaps) {
733                 for (i = 0; i < fs->no_blkgrp; i++) {
734                         free(fs->blk_bmaps[i]);
735                         fs->blk_bmaps[i] = NULL;
736                 }
737                 free(fs->blk_bmaps);
738                 fs->blk_bmaps = NULL;
739         }
740
741         if (fs->inode_bmaps) {
742                 for (i = 0; i < fs->no_blkgrp; i++) {
743                         free(fs->inode_bmaps[i]);
744                         fs->inode_bmaps[i] = NULL;
745                 }
746                 free(fs->inode_bmaps);
747                 fs->inode_bmaps = NULL;
748         }
749
750
751         free(fs->gdtable);
752         fs->gdtable = NULL;
753         fs->bgd = NULL;
754         /*
755          * reinitiliazed the global inode and
756          * block bitmap first execution check variables
757          */
758         fs->first_pass_ibmap = 0;
759         fs->first_pass_bbmap = 0;
760         fs->curr_inode_no = 0;
761         fs->curr_blkno = 0;
762 }
763
764 static int ext4fs_write_file(struct ext2_inode *file_inode,
765                              int pos, unsigned int len, char *buf)
766 {
767         int i;
768         int blockcnt;
769         int log2blocksize = LOG2_EXT2_BLOCK_SIZE(ext4fs_root);
770         unsigned int filesize = __le32_to_cpu(file_inode->size);
771         struct ext_filesystem *fs = get_fs();
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 << log2blocksize;
793
794                 if (blknr) {
795                         if (previous_block_number != -1) {
796                                 if (delayed_next == blknr) {
797                                         delayed_extent += blockend;
798                                         delayed_next += blockend >> SECTOR_BITS;
799                                 } else {        /* spill */
800                                         put_ext4((uint64_t) (delayed_start *
801                                                              SECTOR_SIZE),
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 >> SECTOR_BITS);
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 >> SECTOR_BITS);
818                         }
819                 } else {
820                         if (previous_block_number != -1) {
821                                 /* spill */
822                                 put_ext4((uint64_t) (delayed_start *
823                                                      SECTOR_SIZE), delayed_buf,
824                                          (uint32_t) delayed_extent);
825                                 previous_block_number = -1;
826                         }
827                         memset(buf, 0, fs->blksz - skipfirst);
828                 }
829                 buf += fs->blksz - skipfirst;
830         }
831         if (previous_block_number != -1) {
832                 /* spill */
833                 put_ext4((uint64_t) (delayed_start * SECTOR_SIZE),
834                          delayed_buf, (uint32_t) delayed_extent);
835                 previous_block_number = -1;
836         }
837
838         return len;
839 }
840
841 int ext4fs_write(const char *fname, unsigned char *buffer,
842                                         unsigned long sizebytes)
843 {
844         int ret = 0;
845         struct ext2_inode *file_inode = NULL;
846         unsigned char *inode_buffer = NULL;
847         int parent_inodeno;
848         int inodeno;
849         time_t timestamp = 0;
850
851         uint64_t bytes_reqd_for_file;
852         unsigned int blks_reqd_for_file;
853         unsigned int blocks_remaining;
854         int existing_file_inodeno;
855         char *temp_ptr = NULL;
856         long int itable_blkno;
857         long int parent_itable_blkno;
858         long int blkoff;
859         struct ext2_sblock *sblock = &(ext4fs_root->sblock);
860         unsigned int inodes_per_block;
861         unsigned int ibmap_idx;
862         struct ext_filesystem *fs = get_fs();
863         ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256);
864         memset(filename, 0x00, sizeof(filename));
865
866         g_parent_inode = zalloc(sizeof(struct ext2_inode));
867         if (!g_parent_inode)
868                 goto fail;
869
870         if (ext4fs_init() != 0) {
871                 printf("error in File System init\n");
872                 return -1;
873         }
874         inodes_per_block = fs->blksz / fs->inodesz;
875         parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE);
876         if (parent_inodeno == -1)
877                 goto fail;
878         if (ext4fs_iget(parent_inodeno, g_parent_inode))
879                 goto fail;
880         /* check if the filename is already present in root */
881         existing_file_inodeno = ext4fs_filename_check(filename);
882         if (existing_file_inodeno != -1) {
883                 ret = ext4fs_delete_file(existing_file_inodeno);
884                 fs->first_pass_bbmap = 0;
885                 fs->curr_blkno = 0;
886
887                 fs->first_pass_ibmap = 0;
888                 fs->curr_inode_no = 0;
889                 if (ret)
890                         goto fail;
891         }
892         /* calucalate how many blocks required */
893         bytes_reqd_for_file = sizebytes;
894         blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz);
895         if (do_div(bytes_reqd_for_file, fs->blksz) != 0) {
896                 blks_reqd_for_file++;
897                 debug("total bytes for a file %u\n", blks_reqd_for_file);
898         }
899         blocks_remaining = blks_reqd_for_file;
900         /* test for available space in partition */
901         if (fs->sb->free_blocks < blks_reqd_for_file) {
902                 printf("Not enough space on partition !!!\n");
903                 goto fail;
904         }
905
906         ext4fs_update_parent_dentry(filename, &inodeno, FILETYPE_REG);
907         /* prepare file inode */
908         inode_buffer = zalloc(fs->inodesz);
909         if (!inode_buffer)
910                 goto fail;
911         file_inode = (struct ext2_inode *)inode_buffer;
912         file_inode->mode = S_IFREG | S_IRWXU |
913             S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH;
914         /* ToDo: Update correct time */
915         file_inode->mtime = timestamp;
916         file_inode->atime = timestamp;
917         file_inode->ctime = timestamp;
918         file_inode->nlinks = 1;
919         file_inode->size = sizebytes;
920
921         /* Allocate data blocks */
922         ext4fs_allocate_blocks(file_inode, blocks_remaining,
923                                &blks_reqd_for_file);
924         file_inode->blockcnt = (blks_reqd_for_file * fs->blksz) / SECTOR_SIZE;
925
926         temp_ptr = zalloc(fs->blksz);
927         if (!temp_ptr)
928                 goto fail;
929         ibmap_idx = inodeno / ext4fs_root->sblock.inodes_per_group;
930         inodeno--;
931         itable_blkno = __le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
932                         (inodeno % __le32_to_cpu(sblock->inodes_per_group)) /
933                         inodes_per_block;
934         blkoff = (inodeno % inodes_per_block) * fs->inodesz;
935         ext4fs_devread(itable_blkno * fs->sect_perblk, 0, fs->blksz, temp_ptr);
936         if (ext4fs_log_journal(temp_ptr, itable_blkno))
937                 goto fail;
938
939         memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz);
940         if (ext4fs_put_metadata(temp_ptr, itable_blkno))
941                 goto fail;
942         /* copy the file content into data blocks */
943         if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) {
944                 printf("Error in copying content\n");
945                 goto fail;
946         }
947         ibmap_idx = parent_inodeno / ext4fs_root->sblock.inodes_per_group;
948         parent_inodeno--;
949         parent_itable_blkno = __le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
950             (parent_inodeno %
951              __le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
952         blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz;
953         if (parent_itable_blkno != itable_blkno) {
954                 memset(temp_ptr, '\0', fs->blksz);
955                 ext4fs_devread(parent_itable_blkno * fs->sect_perblk,
956                                0, fs->blksz, temp_ptr);
957                 if (ext4fs_log_journal(temp_ptr, parent_itable_blkno))
958                         goto fail;
959
960                 memcpy(temp_ptr + blkoff, g_parent_inode,
961                         sizeof(struct ext2_inode));
962                 if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno))
963                         goto fail;
964                 free(temp_ptr);
965         } else {
966                 /*
967                  * If parent and child fall in same inode table block
968                  * both should be kept in 1 buffer
969                  */
970                 memcpy(temp_ptr + blkoff, g_parent_inode,
971                        sizeof(struct ext2_inode));
972                 gd_index--;
973                 if (ext4fs_put_metadata(temp_ptr, itable_blkno))
974                         goto fail;
975                 free(temp_ptr);
976         }
977         ext4fs_update();
978         ext4fs_deinit();
979
980         fs->first_pass_bbmap = 0;
981         fs->curr_blkno = 0;
982         fs->first_pass_ibmap = 0;
983         fs->curr_inode_no = 0;
984         free(inode_buffer);
985         free(g_parent_inode);
986         g_parent_inode = NULL;
987
988         return 0;
989 fail:
990         ext4fs_deinit();
991         free(inode_buffer);
992         free(g_parent_inode);
993         g_parent_inode = NULL;
994
995         return -1;
996 }