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>
7 * ext4ls and ext4load : Based on ext2 ls and load support in Uboot.
8 * Ext4 read optimization taken from Open-Moko
12 * esd gmbh <www.esd-electronics.com>
13 * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
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.
19 * ext4write : Based on generic ext4 protocol.
21 * SPDX-License-Identifier: GPL-2.0+
27 #include <linux/stat.h>
29 #include "ext4_common.h"
31 static inline void ext4fs_sb_free_inodes_inc(struct ext2_sblock
*sb
)
33 sb
->free_inodes
= cpu_to_le32(le32_to_cpu(sb
->free_inodes
) + 1);
36 static inline void ext4fs_sb_free_blocks_inc(struct ext2_sblock
*sb
)
38 sb
->free_blocks
= cpu_to_le32(le32_to_cpu(sb
->free_blocks
) + 1);
41 static inline void ext4fs_bg_free_inodes_inc
42 (struct ext2_block_group
*bg
, const struct ext_filesystem
*fs
)
44 uint32_t free_inodes
= le16_to_cpu(bg
->free_inodes
);
46 free_inodes
+= le16_to_cpu(bg
->free_inodes_high
) << 16;
49 bg
->free_inodes
= cpu_to_le16(free_inodes
& 0xffff);
51 bg
->free_inodes_high
= cpu_to_le16(free_inodes
>> 16);
54 static inline void ext4fs_bg_free_blocks_inc
55 (struct ext2_block_group
*bg
, const struct ext_filesystem
*fs
)
57 uint32_t free_blocks
= le16_to_cpu(bg
->free_blocks
);
59 free_blocks
+= le16_to_cpu(bg
->free_blocks_high
) << 16;
62 bg
->free_blocks
= cpu_to_le16(free_blocks
& 0xffff);
64 bg
->free_blocks_high
= cpu_to_le16(free_blocks
>> 16);
67 static void ext4fs_update(void)
70 ext4fs_update_journal();
71 struct ext_filesystem
*fs
= get_fs();
72 struct ext2_block_group
*bgd
= NULL
;
74 /* update super block */
75 put_ext4((uint64_t)(SUPERBLOCK_SIZE
),
76 (struct ext2_sblock
*)fs
->sb
, (uint32_t)SUPERBLOCK_SIZE
);
78 /* update block bitmaps */
79 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
80 bgd
= ext4fs_get_group_descriptor(fs
, i
);
81 bgd
->bg_checksum
= cpu_to_le16(ext4fs_checksum_update(i
));
82 uint64_t b_bitmap_blk
= ext4fs_bg_get_block_id(bgd
, fs
);
83 put_ext4(b_bitmap_blk
* fs
->blksz
,
84 fs
->blk_bmaps
[i
], fs
->blksz
);
87 /* update inode bitmaps */
88 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
89 bgd
= ext4fs_get_group_descriptor(fs
, i
);
90 uint64_t i_bitmap_blk
= ext4fs_bg_get_inode_id(bgd
, fs
);
91 put_ext4(i_bitmap_blk
* fs
->blksz
,
92 fs
->inode_bmaps
[i
], fs
->blksz
);
95 /* update the block group descriptor table */
96 put_ext4((uint64_t)((uint64_t)fs
->gdtable_blkno
* (uint64_t)fs
->blksz
),
97 (struct ext2_block_group
*)fs
->gdtable
,
98 (fs
->blksz
* fs
->no_blk_pergdt
));
100 ext4fs_dump_metadata();
106 int ext4fs_get_bgdtable(void)
109 struct ext_filesystem
*fs
= get_fs();
110 int gdsize_total
= ROUND(fs
->no_blkgrp
* fs
->gdsize
, fs
->blksz
);
111 fs
->no_blk_pergdt
= gdsize_total
/ fs
->blksz
;
113 /* allocate memory for gdtable */
114 fs
->gdtable
= zalloc(gdsize_total
);
117 /* read the group descriptor table */
118 status
= ext4fs_devread((lbaint_t
)fs
->gdtable_blkno
* fs
->sect_perblk
,
119 0, fs
->blksz
* fs
->no_blk_pergdt
, fs
->gdtable
);
123 if (ext4fs_log_gdt(fs
->gdtable
)) {
124 printf("Error in ext4fs_log_gdt\n");
136 static void delete_single_indirect_block(struct ext2_inode
*inode
)
138 struct ext2_block_group
*bgd
= NULL
;
139 static int prev_bg_bmap_idx
= -1;
144 uint32_t blk_per_grp
= le32_to_cpu(ext4fs_root
->sblock
.blocks_per_group
);
145 struct ext_filesystem
*fs
= get_fs();
146 char *journal_buffer
= zalloc(fs
->blksz
);
147 if (!journal_buffer
) {
148 printf("No memory\n");
152 /* deleting the single indirect block associated with inode */
153 if (inode
->b
.blocks
.indir_block
!= 0) {
154 blknr
= le32_to_cpu(inode
->b
.blocks
.indir_block
);
155 debug("SIPB releasing %u\n", blknr
);
156 bg_idx
= blknr
/ blk_per_grp
;
157 if (fs
->blksz
== 1024) {
158 remainder
= blknr
% blk_per_grp
;
162 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
], bg_idx
);
163 /* get block group descriptor table */
164 bgd
= ext4fs_get_group_descriptor(fs
, bg_idx
);
165 ext4fs_bg_free_blocks_inc(bgd
, fs
);
166 ext4fs_sb_free_blocks_inc(fs
->sb
);
168 if (prev_bg_bmap_idx
!= bg_idx
) {
169 uint64_t b_bitmap_blk
= ext4fs_bg_get_block_id(bgd
, fs
);
170 status
= ext4fs_devread(
171 b_bitmap_blk
* fs
->sect_perblk
,
172 0, fs
->blksz
, journal_buffer
);
175 if (ext4fs_log_journal(journal_buffer
, b_bitmap_blk
))
177 prev_bg_bmap_idx
= bg_idx
;
181 free(journal_buffer
);
184 static void delete_double_indirect_block(struct ext2_inode
*inode
)
188 static int prev_bg_bmap_idx
= -1;
192 uint32_t blk_per_grp
= le32_to_cpu(ext4fs_root
->sblock
.blocks_per_group
);
193 __le32
*di_buffer
= NULL
;
194 void *dib_start_addr
= NULL
;
195 struct ext2_block_group
*bgd
= NULL
;
196 struct ext_filesystem
*fs
= get_fs();
197 char *journal_buffer
= zalloc(fs
->blksz
);
198 if (!journal_buffer
) {
199 printf("No memory\n");
203 if (inode
->b
.blocks
.double_indir_block
!= 0) {
204 di_buffer
= zalloc(fs
->blksz
);
206 printf("No memory\n");
209 dib_start_addr
= di_buffer
;
210 blknr
= le32_to_cpu(inode
->b
.blocks
.double_indir_block
);
211 status
= ext4fs_devread((lbaint_t
)blknr
* fs
->sect_perblk
, 0,
212 fs
->blksz
, (char *)di_buffer
);
213 for (i
= 0; i
< fs
->blksz
/ sizeof(int); i
++) {
217 debug("DICB releasing %u\n", *di_buffer
);
218 bg_idx
= le32_to_cpu(*di_buffer
) / blk_per_grp
;
219 if (fs
->blksz
== 1024) {
220 remainder
= le32_to_cpu(*di_buffer
) % blk_per_grp
;
224 /* get block group descriptor table */
225 bgd
= ext4fs_get_group_descriptor(fs
, bg_idx
);
226 ext4fs_reset_block_bmap(le32_to_cpu(*di_buffer
),
227 fs
->blk_bmaps
[bg_idx
], bg_idx
);
229 ext4fs_bg_free_blocks_inc(bgd
, fs
);
230 ext4fs_sb_free_blocks_inc(fs
->sb
);
232 if (prev_bg_bmap_idx
!= bg_idx
) {
233 uint64_t b_bitmap_blk
=
234 ext4fs_bg_get_block_id(bgd
, fs
);
235 status
= ext4fs_devread(b_bitmap_blk
236 * fs
->sect_perblk
, 0,
242 if (ext4fs_log_journal(journal_buffer
,
245 prev_bg_bmap_idx
= bg_idx
;
249 /* removing the parent double indirect block */
250 blknr
= le32_to_cpu(inode
->b
.blocks
.double_indir_block
);
251 bg_idx
= blknr
/ blk_per_grp
;
252 if (fs
->blksz
== 1024) {
253 remainder
= blknr
% blk_per_grp
;
257 /* get block group descriptor table */
258 bgd
= ext4fs_get_group_descriptor(fs
, bg_idx
);
259 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
], bg_idx
);
260 ext4fs_bg_free_blocks_inc(bgd
, fs
);
261 ext4fs_sb_free_blocks_inc(fs
->sb
);
263 if (prev_bg_bmap_idx
!= bg_idx
) {
264 uint64_t b_bitmap_blk
= ext4fs_bg_get_block_id(bgd
, fs
);
265 status
= ext4fs_devread(b_bitmap_blk
* fs
->sect_perblk
,
266 0, fs
->blksz
, journal_buffer
);
270 if (ext4fs_log_journal(journal_buffer
, b_bitmap_blk
))
272 prev_bg_bmap_idx
= bg_idx
;
274 debug("DIPB releasing %d\n", blknr
);
277 free(dib_start_addr
);
278 free(journal_buffer
);
281 static void delete_triple_indirect_block(struct ext2_inode
*inode
)
285 static int prev_bg_bmap_idx
= -1;
289 uint32_t blk_per_grp
= le32_to_cpu(ext4fs_root
->sblock
.blocks_per_group
);
290 __le32
*tigp_buffer
= NULL
;
291 void *tib_start_addr
= NULL
;
292 __le32
*tip_buffer
= NULL
;
293 void *tipb_start_addr
= NULL
;
294 struct ext2_block_group
*bgd
= NULL
;
295 struct ext_filesystem
*fs
= get_fs();
296 char *journal_buffer
= zalloc(fs
->blksz
);
297 if (!journal_buffer
) {
298 printf("No memory\n");
302 if (inode
->b
.blocks
.triple_indir_block
!= 0) {
303 tigp_buffer
= zalloc(fs
->blksz
);
305 printf("No memory\n");
308 tib_start_addr
= tigp_buffer
;
309 blknr
= le32_to_cpu(inode
->b
.blocks
.triple_indir_block
);
310 status
= ext4fs_devread((lbaint_t
)blknr
* fs
->sect_perblk
, 0,
311 fs
->blksz
, (char *)tigp_buffer
);
312 for (i
= 0; i
< fs
->blksz
/ sizeof(int); i
++) {
313 if (*tigp_buffer
== 0)
315 debug("tigp buffer releasing %u\n", *tigp_buffer
);
317 tip_buffer
= zalloc(fs
->blksz
);
320 tipb_start_addr
= tip_buffer
;
321 status
= ext4fs_devread((lbaint_t
)le32_to_cpu(*tigp_buffer
) *
322 fs
->sect_perblk
, 0, fs
->blksz
,
324 for (j
= 0; j
< fs
->blksz
/ sizeof(int); j
++) {
325 if (le32_to_cpu(*tip_buffer
) == 0)
327 bg_idx
= le32_to_cpu(*tip_buffer
) / blk_per_grp
;
328 if (fs
->blksz
== 1024) {
329 remainder
= le32_to_cpu(*tip_buffer
) % blk_per_grp
;
334 ext4fs_reset_block_bmap(le32_to_cpu(*tip_buffer
),
335 fs
->blk_bmaps
[bg_idx
],
339 /* get block group descriptor table */
340 bgd
= ext4fs_get_group_descriptor(fs
, bg_idx
);
341 ext4fs_bg_free_blocks_inc(bgd
, fs
);
342 ext4fs_sb_free_blocks_inc(fs
->sb
);
344 if (prev_bg_bmap_idx
!= bg_idx
) {
345 uint64_t b_bitmap_blk
=
346 ext4fs_bg_get_block_id(bgd
, fs
);
356 if (ext4fs_log_journal(journal_buffer
,
359 prev_bg_bmap_idx
= bg_idx
;
362 free(tipb_start_addr
);
363 tipb_start_addr
= NULL
;
366 * removing the grand parent blocks
367 * which is connected to inode
369 bg_idx
= le32_to_cpu(*tigp_buffer
) / blk_per_grp
;
370 if (fs
->blksz
== 1024) {
371 remainder
= le32_to_cpu(*tigp_buffer
) % blk_per_grp
;
375 ext4fs_reset_block_bmap(le32_to_cpu(*tigp_buffer
),
376 fs
->blk_bmaps
[bg_idx
], bg_idx
);
379 /* get block group descriptor table */
380 bgd
= ext4fs_get_group_descriptor(fs
, bg_idx
);
381 ext4fs_bg_free_blocks_inc(bgd
, fs
);
382 ext4fs_sb_free_blocks_inc(fs
->sb
);
384 if (prev_bg_bmap_idx
!= bg_idx
) {
385 uint64_t b_bitmap_blk
=
386 ext4fs_bg_get_block_id(bgd
, fs
);
387 memset(journal_buffer
, '\0', fs
->blksz
);
388 status
= ext4fs_devread(b_bitmap_blk
*
395 if (ext4fs_log_journal(journal_buffer
,
398 prev_bg_bmap_idx
= bg_idx
;
402 /* removing the grand parent triple indirect block */
403 blknr
= le32_to_cpu(inode
->b
.blocks
.triple_indir_block
);
404 bg_idx
= blknr
/ blk_per_grp
;
405 if (fs
->blksz
== 1024) {
406 remainder
= blknr
% blk_per_grp
;
410 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
], bg_idx
);
411 /* get block group descriptor table */
412 bgd
= ext4fs_get_group_descriptor(fs
, bg_idx
);
413 ext4fs_bg_free_blocks_inc(bgd
, fs
);
414 ext4fs_sb_free_blocks_inc(fs
->sb
);
416 if (prev_bg_bmap_idx
!= bg_idx
) {
417 uint64_t b_bitmap_blk
= ext4fs_bg_get_block_id(bgd
, fs
);
418 status
= ext4fs_devread(b_bitmap_blk
* fs
->sect_perblk
,
419 0, fs
->blksz
, journal_buffer
);
423 if (ext4fs_log_journal(journal_buffer
, b_bitmap_blk
))
425 prev_bg_bmap_idx
= bg_idx
;
427 debug("tigp buffer itself releasing %d\n", blknr
);
430 free(tib_start_addr
);
431 free(tipb_start_addr
);
432 free(journal_buffer
);
435 static int ext4fs_delete_file(int inodeno
)
437 struct ext2_inode inode
;
444 char *read_buffer
= NULL
;
445 char *start_block_address
= NULL
;
448 static int prev_bg_bmap_idx
= -1;
449 unsigned int inodes_per_block
;
452 uint32_t blk_per_grp
= le32_to_cpu(ext4fs_root
->sblock
.blocks_per_group
);
453 uint32_t inode_per_grp
= le32_to_cpu(ext4fs_root
->sblock
.inodes_per_group
);
454 struct ext2_inode
*inode_buffer
= NULL
;
455 struct ext2_block_group
*bgd
= NULL
;
456 struct ext_filesystem
*fs
= get_fs();
457 char *journal_buffer
= zalloc(fs
->blksz
);
460 status
= ext4fs_read_inode(ext4fs_root
, inodeno
, &inode
);
464 /* read the block no allocated to a file */
465 no_blocks
= le32_to_cpu(inode
.size
) / fs
->blksz
;
466 if (le32_to_cpu(inode
.size
) % fs
->blksz
)
469 if (le32_to_cpu(inode
.flags
) & EXT4_EXTENTS_FL
) {
470 /* FIXME delete extent index blocks, i.e. eh_depth >= 1 */
471 struct ext4_extent_header
*eh
=
472 (struct ext4_extent_header
*)
473 inode
.b
.blocks
.dir_blocks
;
474 debug("del: dep=%d entries=%d\n", eh
->eh_depth
, eh
->eh_entries
);
476 delete_single_indirect_block(&inode
);
477 delete_double_indirect_block(&inode
);
478 delete_triple_indirect_block(&inode
);
481 /* release data blocks */
482 for (i
= 0; i
< no_blocks
; i
++) {
483 blknr
= read_allocated_block(&inode
, i
);
488 bg_idx
= blknr
/ blk_per_grp
;
489 if (fs
->blksz
== 1024) {
490 remainder
= blknr
% blk_per_grp
;
494 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
],
496 debug("EXT4 Block releasing %ld: %d\n", blknr
, bg_idx
);
498 /* get block group descriptor table */
499 bgd
= ext4fs_get_group_descriptor(fs
, bg_idx
);
500 ext4fs_bg_free_blocks_inc(bgd
, fs
);
501 ext4fs_sb_free_blocks_inc(fs
->sb
);
503 if (prev_bg_bmap_idx
!= bg_idx
) {
504 uint64_t b_bitmap_blk
= ext4fs_bg_get_block_id(bgd
, fs
);
505 status
= ext4fs_devread(b_bitmap_blk
* fs
->sect_perblk
,
510 if (ext4fs_log_journal(journal_buffer
, b_bitmap_blk
))
512 prev_bg_bmap_idx
= bg_idx
;
517 /* from the inode no to blockno */
518 inodes_per_block
= fs
->blksz
/ fs
->inodesz
;
519 ibmap_idx
= inodeno
/ inode_per_grp
;
521 /* get the block no */
523 /* get block group descriptor table */
524 bgd
= ext4fs_get_group_descriptor(fs
, ibmap_idx
);
525 blkno
= ext4fs_bg_get_inode_table_id(bgd
, fs
) +
526 (inodeno
% inode_per_grp
) / inodes_per_block
;
528 /* get the offset of the inode */
529 blkoff
= ((inodeno
) % inodes_per_block
) * fs
->inodesz
;
531 /* read the block no containing the inode */
532 read_buffer
= zalloc(fs
->blksz
);
535 start_block_address
= read_buffer
;
536 status
= ext4fs_devread((lbaint_t
)blkno
* fs
->sect_perblk
,
537 0, fs
->blksz
, read_buffer
);
541 if (ext4fs_log_journal(read_buffer
, blkno
))
544 read_buffer
= read_buffer
+ blkoff
;
545 inode_buffer
= (struct ext2_inode
*)read_buffer
;
546 memset(inode_buffer
, '\0', fs
->inodesz
);
548 /* write the inode to original position in inode table */
549 if (ext4fs_put_metadata(start_block_address
, blkno
))
552 /* update the respective inode bitmaps */
554 ext4fs_reset_inode_bmap(inodeno
, fs
->inode_bmaps
[ibmap_idx
], ibmap_idx
);
555 ext4fs_bg_free_inodes_inc(bgd
, fs
);
556 ext4fs_sb_free_inodes_inc(fs
->sb
);
558 memset(journal_buffer
, '\0', fs
->blksz
);
559 status
= ext4fs_devread(ext4fs_bg_get_inode_id(bgd
, fs
) *
560 fs
->sect_perblk
, 0, fs
->blksz
, journal_buffer
);
563 if (ext4fs_log_journal(journal_buffer
, ext4fs_bg_get_inode_id(bgd
, fs
)))
568 ext4fs_reinit_global();
570 if (ext4fs_init() != 0) {
571 printf("error in File System init\n");
575 free(start_block_address
);
576 free(journal_buffer
);
580 free(start_block_address
);
581 free(journal_buffer
);
586 int ext4fs_init(void)
590 uint32_t real_free_blocks
= 0;
591 struct ext_filesystem
*fs
= get_fs();
594 fs
->blksz
= EXT2_BLOCK_SIZE(ext4fs_root
);
595 fs
->sect_perblk
= fs
->blksz
>> fs
->dev_desc
->log2blksz
;
597 /* get the superblock */
598 fs
->sb
= zalloc(SUPERBLOCK_SIZE
);
601 if (!ext4_read_superblock((char *)fs
->sb
))
605 if (ext4fs_init_journal())
608 /* get total no of blockgroups */
609 fs
->no_blkgrp
= (uint32_t)ext4fs_div_roundup(
610 le32_to_cpu(ext4fs_root
->sblock
.total_blocks
)
611 - le32_to_cpu(ext4fs_root
->sblock
.first_data_block
),
612 le32_to_cpu(ext4fs_root
->sblock
.blocks_per_group
));
614 /* get the block group descriptor table */
615 fs
->gdtable_blkno
= ((EXT2_MIN_BLOCK_SIZE
== fs
->blksz
) + 1);
616 if (ext4fs_get_bgdtable() == -1) {
617 printf("Error in getting the block group descriptor table\n");
621 /* load all the available bitmap block of the partition */
622 fs
->blk_bmaps
= zalloc(fs
->no_blkgrp
* sizeof(char *));
625 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
626 fs
->blk_bmaps
[i
] = zalloc(fs
->blksz
);
627 if (!fs
->blk_bmaps
[i
])
631 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
632 struct ext2_block_group
*bgd
=
633 ext4fs_get_group_descriptor(fs
, i
);
634 status
= ext4fs_devread(ext4fs_bg_get_block_id(bgd
, fs
) *
636 fs
->blksz
, (char *)fs
->blk_bmaps
[i
]);
641 /* load all the available inode bitmap of the partition */
642 fs
->inode_bmaps
= zalloc(fs
->no_blkgrp
* sizeof(unsigned char *));
643 if (!fs
->inode_bmaps
)
645 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
646 fs
->inode_bmaps
[i
] = zalloc(fs
->blksz
);
647 if (!fs
->inode_bmaps
[i
])
651 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
652 struct ext2_block_group
*bgd
=
653 ext4fs_get_group_descriptor(fs
, i
);
654 status
= ext4fs_devread(ext4fs_bg_get_inode_id(bgd
, fs
) *
657 (char *)fs
->inode_bmaps
[i
]);
663 * check filesystem consistency with free blocks of file system
664 * some time we observed that superblock freeblocks does not match
665 * with the blockgroups freeblocks when improper
666 * reboot of a linux kernel
668 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
669 struct ext2_block_group
*bgd
=
670 ext4fs_get_group_descriptor(fs
, i
);
671 real_free_blocks
= real_free_blocks
+
672 ext4fs_bg_get_free_blocks(bgd
, fs
);
674 if (real_free_blocks
!= ext4fs_sb_get_free_blocks(fs
->sb
))
675 ext4fs_sb_set_free_blocks(fs
->sb
, real_free_blocks
);
684 void ext4fs_deinit(void)
687 struct ext2_inode inode_journal
;
688 struct journal_superblock_t
*jsb
;
690 struct ext_filesystem
*fs
= get_fs();
691 uint32_t new_feature_incompat
;
694 char *temp_buff
= zalloc(fs
->blksz
);
696 ext4fs_read_inode(ext4fs_root
, EXT2_JOURNAL_INO
,
698 blknr
= read_allocated_block(&inode_journal
,
699 EXT2_JOURNAL_SUPERBLOCK
);
700 ext4fs_devread((lbaint_t
)blknr
* fs
->sect_perblk
, 0, fs
->blksz
,
702 jsb
= (struct journal_superblock_t
*)temp_buff
;
704 put_ext4((uint64_t) ((uint64_t)blknr
* (uint64_t)fs
->blksz
),
705 (struct journal_superblock_t
*)temp_buff
, fs
->blksz
);
708 ext4fs_free_journal();
710 /* get the superblock */
711 ext4_read_superblock((char *)fs
->sb
);
712 new_feature_incompat
= le32_to_cpu(fs
->sb
->feature_incompat
);
713 new_feature_incompat
&= ~EXT3_FEATURE_INCOMPAT_RECOVER
;
714 fs
->sb
->feature_incompat
= cpu_to_le32(new_feature_incompat
);
715 put_ext4((uint64_t)(SUPERBLOCK_SIZE
),
716 (struct ext2_sblock
*)fs
->sb
, (uint32_t)SUPERBLOCK_SIZE
);
721 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
722 free(fs
->blk_bmaps
[i
]);
723 fs
->blk_bmaps
[i
] = NULL
;
726 fs
->blk_bmaps
= NULL
;
729 if (fs
->inode_bmaps
) {
730 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
731 free(fs
->inode_bmaps
[i
]);
732 fs
->inode_bmaps
[i
] = NULL
;
734 free(fs
->inode_bmaps
);
735 fs
->inode_bmaps
= NULL
;
742 * reinitiliazed the global inode and
743 * block bitmap first execution check variables
745 fs
->first_pass_ibmap
= 0;
746 fs
->first_pass_bbmap
= 0;
747 fs
->curr_inode_no
= 0;
752 * Write data to filesystem blocks. Uses same optimization for
753 * contigous sectors as ext4fs_read_file
755 static int ext4fs_write_file(struct ext2_inode
*file_inode
,
756 int pos
, unsigned int len
, char *buf
)
760 uint32_t filesize
= le32_to_cpu(file_inode
->size
);
761 struct ext_filesystem
*fs
= get_fs();
762 int log2blksz
= fs
->dev_desc
->log2blksz
;
763 int log2_fs_blocksize
= LOG2_BLOCK_SIZE(ext4fs_root
) - log2blksz
;
764 int previous_block_number
= -1;
765 int delayed_start
= 0;
766 int delayed_extent
= 0;
767 int delayed_next
= 0;
768 char *delayed_buf
= NULL
;
770 /* Adjust len so it we can't read past the end of the file. */
774 blockcnt
= ((len
+ pos
) + fs
->blksz
- 1) / fs
->blksz
;
776 for (i
= pos
/ fs
->blksz
; i
< blockcnt
; i
++) {
778 int blockend
= fs
->blksz
;
780 blknr
= read_allocated_block(file_inode
, i
);
784 blknr
= blknr
<< log2_fs_blocksize
;
787 if (previous_block_number
!= -1) {
788 if (delayed_next
== blknr
) {
789 delayed_extent
+= blockend
;
790 delayed_next
+= blockend
>> log2blksz
;
793 ((uint64_t)delayed_start
<< log2blksz
),
795 (uint32_t) delayed_extent
);
796 previous_block_number
= blknr
;
797 delayed_start
= blknr
;
798 delayed_extent
= blockend
;
800 delayed_next
= blknr
+
801 (blockend
>> log2blksz
);
804 previous_block_number
= blknr
;
805 delayed_start
= blknr
;
806 delayed_extent
= blockend
;
808 delayed_next
= blknr
+
809 (blockend
>> log2blksz
);
812 if (previous_block_number
!= -1) {
814 put_ext4((uint64_t) ((uint64_t)delayed_start
<<
817 (uint32_t) delayed_extent
);
818 previous_block_number
= -1;
820 memset(buf
, 0, fs
->blksz
- skipfirst
);
822 buf
+= fs
->blksz
- skipfirst
;
824 if (previous_block_number
!= -1) {
826 put_ext4((uint64_t) ((uint64_t)delayed_start
<< log2blksz
),
827 delayed_buf
, (uint32_t) delayed_extent
);
828 previous_block_number
= -1;
834 int ext4fs_write(const char *fname
, unsigned char *buffer
,
835 unsigned long sizebytes
)
838 struct ext2_inode
*file_inode
= NULL
;
839 unsigned char *inode_buffer
= NULL
;
842 time_t timestamp
= 0;
844 uint64_t bytes_reqd_for_file
;
845 unsigned int blks_reqd_for_file
;
846 unsigned int blocks_remaining
;
847 int existing_file_inodeno
;
848 char *temp_ptr
= NULL
;
849 long int itable_blkno
;
850 long int parent_itable_blkno
;
852 struct ext2_sblock
*sblock
= &(ext4fs_root
->sblock
);
853 unsigned int inodes_per_block
;
854 unsigned int ibmap_idx
;
855 struct ext2_block_group
*bgd
= NULL
;
856 struct ext_filesystem
*fs
= get_fs();
857 ALLOC_CACHE_ALIGN_BUFFER(char, filename
, 256);
858 memset(filename
, 0x00, 256);
860 g_parent_inode
= zalloc(fs
->inodesz
);
864 if (ext4fs_init() != 0) {
865 printf("error in File System init\n");
868 inodes_per_block
= fs
->blksz
/ fs
->inodesz
;
869 parent_inodeno
= ext4fs_get_parent_inode_num(fname
, filename
, F_FILE
);
870 if (parent_inodeno
== -1)
872 if (ext4fs_iget(parent_inodeno
, g_parent_inode
))
874 /* do not mess up a directory using hash trees */
875 if (le32_to_cpu(g_parent_inode
->flags
) & EXT4_INDEX_FL
) {
876 printf("hash tree directory\n");
879 /* check if the filename is already present in root */
880 existing_file_inodeno
= ext4fs_filename_unlink(filename
);
881 if (existing_file_inodeno
!= -1) {
882 ret
= ext4fs_delete_file(existing_file_inodeno
);
883 fs
->first_pass_bbmap
= 0;
886 fs
->first_pass_ibmap
= 0;
887 fs
->curr_inode_no
= 0;
891 /* calucalate how many blocks required */
892 bytes_reqd_for_file
= sizebytes
;
893 blks_reqd_for_file
= lldiv(bytes_reqd_for_file
, fs
->blksz
);
894 if (do_div(bytes_reqd_for_file
, fs
->blksz
) != 0) {
895 blks_reqd_for_file
++;
896 debug("total bytes for a file %u\n", blks_reqd_for_file
);
898 blocks_remaining
= blks_reqd_for_file
;
899 /* test for available space in partition */
900 if (le32_to_cpu(fs
->sb
->free_blocks
) < blks_reqd_for_file
) {
901 printf("Not enough space on partition !!!\n");
905 inodeno
= ext4fs_update_parent_dentry(filename
, FILETYPE_REG
);
908 /* prepare file inode */
909 inode_buffer
= zalloc(fs
->inodesz
);
912 file_inode
= (struct ext2_inode
*)inode_buffer
;
913 file_inode
->mode
= cpu_to_le16(S_IFREG
| S_IRWXU
|
914 S_IRGRP
| S_IROTH
| S_IXGRP
| S_IXOTH
);
915 /* ToDo: Update correct time */
916 file_inode
->mtime
= cpu_to_le32(timestamp
);
917 file_inode
->atime
= cpu_to_le32(timestamp
);
918 file_inode
->ctime
= cpu_to_le32(timestamp
);
919 file_inode
->nlinks
= cpu_to_le16(1);
920 file_inode
->size
= cpu_to_le32(sizebytes
);
922 /* Allocate data blocks */
923 ext4fs_allocate_blocks(file_inode
, blocks_remaining
,
924 &blks_reqd_for_file
);
925 file_inode
->blockcnt
= cpu_to_le32((blks_reqd_for_file
* fs
->blksz
) >>
926 fs
->dev_desc
->log2blksz
);
928 temp_ptr
= zalloc(fs
->blksz
);
931 ibmap_idx
= inodeno
/ le32_to_cpu(ext4fs_root
->sblock
.inodes_per_group
);
933 bgd
= ext4fs_get_group_descriptor(fs
, ibmap_idx
);
934 itable_blkno
= ext4fs_bg_get_inode_table_id(bgd
, fs
) +
935 (inodeno
% le32_to_cpu(sblock
->inodes_per_group
)) /
937 blkoff
= (inodeno
% inodes_per_block
) * fs
->inodesz
;
938 ext4fs_devread((lbaint_t
)itable_blkno
* fs
->sect_perblk
, 0, fs
->blksz
,
940 if (ext4fs_log_journal(temp_ptr
, itable_blkno
))
943 memcpy(temp_ptr
+ blkoff
, inode_buffer
, fs
->inodesz
);
944 if (ext4fs_put_metadata(temp_ptr
, itable_blkno
))
946 /* copy the file content into data blocks */
947 if (ext4fs_write_file(file_inode
, 0, sizebytes
, (char *)buffer
) == -1) {
948 printf("Error in copying content\n");
949 /* FIXME: Deallocate data blocks */
952 ibmap_idx
= parent_inodeno
/ le32_to_cpu(ext4fs_root
->sblock
.inodes_per_group
);
954 bgd
= ext4fs_get_group_descriptor(fs
, ibmap_idx
);
955 parent_itable_blkno
= ext4fs_bg_get_inode_table_id(bgd
, fs
) +
957 le32_to_cpu(sblock
->inodes_per_group
)) / inodes_per_block
;
958 blkoff
= (parent_inodeno
% inodes_per_block
) * fs
->inodesz
;
959 if (parent_itable_blkno
!= itable_blkno
) {
960 memset(temp_ptr
, '\0', fs
->blksz
);
961 ext4fs_devread((lbaint_t
)parent_itable_blkno
* fs
->sect_perblk
,
962 0, fs
->blksz
, temp_ptr
);
963 if (ext4fs_log_journal(temp_ptr
, parent_itable_blkno
))
966 memcpy(temp_ptr
+ blkoff
, g_parent_inode
, fs
->inodesz
);
967 if (ext4fs_put_metadata(temp_ptr
, parent_itable_blkno
))
971 * If parent and child fall in same inode table block
972 * both should be kept in 1 buffer
974 memcpy(temp_ptr
+ blkoff
, g_parent_inode
, fs
->inodesz
);
976 if (ext4fs_put_metadata(temp_ptr
, itable_blkno
))
982 fs
->first_pass_bbmap
= 0;
984 fs
->first_pass_ibmap
= 0;
985 fs
->curr_inode_no
= 0;
987 free(g_parent_inode
);
989 g_parent_inode
= NULL
;
995 free(g_parent_inode
);
997 g_parent_inode
= NULL
;
1002 int ext4_write_file(const char *filename
, void *buf
, loff_t offset
,
1003 loff_t len
, loff_t
*actwrite
)
1008 printf("** Cannot support non-zero offset **\n");
1012 ret
= ext4fs_write(filename
, buf
, len
);
1014 printf("** Error ext4fs_write() **\n");