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