1 // SPDX-License-Identifier: GPL-2.0+
3 * (C) Copyright 2011 - 2012 Samsung Electronics
4 * EXT4 filesystem implementation in Uboot by
5 * Uma Shankar <uma.shankar@samsung.com>
6 * Manjunatha C Achar <a.manjunatha@samsung.com>
8 * ext4ls and ext4load : Based on ext2 ls and load support in Uboot.
9 * Ext4 read optimization taken from Open-Moko
13 * esd gmbh <www.esd-electronics.com>
14 * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
16 * based on code from grub2 fs/ext2.c and fs/fshelp.c by
17 * GRUB -- GRand Unified Bootloader
18 * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
20 * ext4write : Based on generic ext4 protocol.
26 #include <linux/stat.h>
28 #include "ext4_common.h"
30 static inline void ext4fs_sb_free_inodes_inc(struct ext2_sblock
*sb
)
32 sb
->free_inodes
= cpu_to_le32(le32_to_cpu(sb
->free_inodes
) + 1);
35 static inline void ext4fs_sb_free_blocks_inc(struct ext2_sblock
*sb
)
37 sb
->free_blocks
= cpu_to_le32(le32_to_cpu(sb
->free_blocks
) + 1);
40 static inline void ext4fs_bg_free_inodes_inc
41 (struct ext2_block_group
*bg
, const struct ext_filesystem
*fs
)
43 uint32_t free_inodes
= le16_to_cpu(bg
->free_inodes
);
45 free_inodes
+= le16_to_cpu(bg
->free_inodes_high
) << 16;
48 bg
->free_inodes
= cpu_to_le16(free_inodes
& 0xffff);
50 bg
->free_inodes_high
= cpu_to_le16(free_inodes
>> 16);
53 static inline void ext4fs_bg_free_blocks_inc
54 (struct ext2_block_group
*bg
, const struct ext_filesystem
*fs
)
56 uint32_t free_blocks
= le16_to_cpu(bg
->free_blocks
);
58 free_blocks
+= le16_to_cpu(bg
->free_blocks_high
) << 16;
61 bg
->free_blocks
= cpu_to_le16(free_blocks
& 0xffff);
63 bg
->free_blocks_high
= cpu_to_le16(free_blocks
>> 16);
66 static void ext4fs_update(void)
69 ext4fs_update_journal();
70 struct ext_filesystem
*fs
= get_fs();
71 struct ext2_block_group
*bgd
= NULL
;
73 /* update super block */
74 put_ext4((uint64_t)(SUPERBLOCK_SIZE
),
75 (struct ext2_sblock
*)fs
->sb
, (uint32_t)SUPERBLOCK_SIZE
);
77 /* update block bitmaps */
78 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
79 bgd
= ext4fs_get_group_descriptor(fs
, i
);
80 bgd
->bg_checksum
= cpu_to_le16(ext4fs_checksum_update(i
));
81 uint64_t b_bitmap_blk
= ext4fs_bg_get_block_id(bgd
, fs
);
82 put_ext4(b_bitmap_blk
* fs
->blksz
,
83 fs
->blk_bmaps
[i
], fs
->blksz
);
86 /* update inode bitmaps */
87 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
88 bgd
= ext4fs_get_group_descriptor(fs
, i
);
89 uint64_t i_bitmap_blk
= ext4fs_bg_get_inode_id(bgd
, fs
);
90 put_ext4(i_bitmap_blk
* fs
->blksz
,
91 fs
->inode_bmaps
[i
], fs
->blksz
);
94 /* update the block group descriptor table */
95 put_ext4((uint64_t)((uint64_t)fs
->gdtable_blkno
* (uint64_t)fs
->blksz
),
96 (struct ext2_block_group
*)fs
->gdtable
,
97 (fs
->blksz
* fs
->no_blk_pergdt
));
99 ext4fs_dump_metadata();
105 int ext4fs_get_bgdtable(void)
108 struct ext_filesystem
*fs
= get_fs();
109 int gdsize_total
= ROUND(fs
->no_blkgrp
* fs
->gdsize
, fs
->blksz
);
110 fs
->no_blk_pergdt
= gdsize_total
/ fs
->blksz
;
112 /* allocate memory for gdtable */
113 fs
->gdtable
= zalloc(gdsize_total
);
116 /* read the group descriptor table */
117 status
= ext4fs_devread((lbaint_t
)fs
->gdtable_blkno
* fs
->sect_perblk
,
118 0, fs
->blksz
* fs
->no_blk_pergdt
, fs
->gdtable
);
122 if (ext4fs_log_gdt(fs
->gdtable
)) {
123 printf("Error in ext4fs_log_gdt\n");
135 static void delete_single_indirect_block(struct ext2_inode
*inode
)
137 struct ext2_block_group
*bgd
= NULL
;
138 static int prev_bg_bmap_idx
= -1;
143 uint32_t blk_per_grp
= le32_to_cpu(ext4fs_root
->sblock
.blocks_per_group
);
144 struct ext_filesystem
*fs
= get_fs();
145 char *journal_buffer
= zalloc(fs
->blksz
);
146 if (!journal_buffer
) {
147 printf("No memory\n");
151 /* deleting the single indirect block associated with inode */
152 if (inode
->b
.blocks
.indir_block
!= 0) {
153 blknr
= le32_to_cpu(inode
->b
.blocks
.indir_block
);
154 debug("SIPB releasing %u\n", blknr
);
155 bg_idx
= blknr
/ blk_per_grp
;
156 if (fs
->blksz
== 1024) {
157 remainder
= blknr
% blk_per_grp
;
161 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
], bg_idx
);
162 /* get block group descriptor table */
163 bgd
= ext4fs_get_group_descriptor(fs
, bg_idx
);
164 ext4fs_bg_free_blocks_inc(bgd
, fs
);
165 ext4fs_sb_free_blocks_inc(fs
->sb
);
167 if (prev_bg_bmap_idx
!= bg_idx
) {
168 uint64_t b_bitmap_blk
= ext4fs_bg_get_block_id(bgd
, fs
);
169 status
= ext4fs_devread(
170 b_bitmap_blk
* fs
->sect_perblk
,
171 0, fs
->blksz
, journal_buffer
);
174 if (ext4fs_log_journal(journal_buffer
, b_bitmap_blk
))
176 prev_bg_bmap_idx
= bg_idx
;
180 free(journal_buffer
);
183 static void delete_double_indirect_block(struct ext2_inode
*inode
)
187 static int prev_bg_bmap_idx
= -1;
191 uint32_t blk_per_grp
= le32_to_cpu(ext4fs_root
->sblock
.blocks_per_group
);
192 __le32
*di_buffer
= NULL
;
193 void *dib_start_addr
= NULL
;
194 struct ext2_block_group
*bgd
= NULL
;
195 struct ext_filesystem
*fs
= get_fs();
196 char *journal_buffer
= zalloc(fs
->blksz
);
197 if (!journal_buffer
) {
198 printf("No memory\n");
202 if (inode
->b
.blocks
.double_indir_block
!= 0) {
203 di_buffer
= zalloc(fs
->blksz
);
205 printf("No memory\n");
208 dib_start_addr
= di_buffer
;
209 blknr
= le32_to_cpu(inode
->b
.blocks
.double_indir_block
);
210 status
= ext4fs_devread((lbaint_t
)blknr
* fs
->sect_perblk
, 0,
211 fs
->blksz
, (char *)di_buffer
);
212 for (i
= 0; i
< fs
->blksz
/ sizeof(int); i
++) {
216 debug("DICB releasing %u\n", *di_buffer
);
217 bg_idx
= le32_to_cpu(*di_buffer
) / blk_per_grp
;
218 if (fs
->blksz
== 1024) {
219 remainder
= le32_to_cpu(*di_buffer
) % blk_per_grp
;
223 /* get block group descriptor table */
224 bgd
= ext4fs_get_group_descriptor(fs
, bg_idx
);
225 ext4fs_reset_block_bmap(le32_to_cpu(*di_buffer
),
226 fs
->blk_bmaps
[bg_idx
], bg_idx
);
228 ext4fs_bg_free_blocks_inc(bgd
, fs
);
229 ext4fs_sb_free_blocks_inc(fs
->sb
);
231 if (prev_bg_bmap_idx
!= bg_idx
) {
232 uint64_t b_bitmap_blk
=
233 ext4fs_bg_get_block_id(bgd
, fs
);
234 status
= ext4fs_devread(b_bitmap_blk
235 * fs
->sect_perblk
, 0,
241 if (ext4fs_log_journal(journal_buffer
,
244 prev_bg_bmap_idx
= bg_idx
;
248 /* removing the parent double indirect block */
249 blknr
= le32_to_cpu(inode
->b
.blocks
.double_indir_block
);
250 bg_idx
= blknr
/ blk_per_grp
;
251 if (fs
->blksz
== 1024) {
252 remainder
= blknr
% blk_per_grp
;
256 /* get block group descriptor table */
257 bgd
= ext4fs_get_group_descriptor(fs
, bg_idx
);
258 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
], bg_idx
);
259 ext4fs_bg_free_blocks_inc(bgd
, fs
);
260 ext4fs_sb_free_blocks_inc(fs
->sb
);
262 if (prev_bg_bmap_idx
!= bg_idx
) {
263 uint64_t b_bitmap_blk
= ext4fs_bg_get_block_id(bgd
, fs
);
264 status
= ext4fs_devread(b_bitmap_blk
* fs
->sect_perblk
,
265 0, fs
->blksz
, journal_buffer
);
269 if (ext4fs_log_journal(journal_buffer
, b_bitmap_blk
))
271 prev_bg_bmap_idx
= bg_idx
;
273 debug("DIPB releasing %d\n", blknr
);
276 free(dib_start_addr
);
277 free(journal_buffer
);
280 static void delete_triple_indirect_block(struct ext2_inode
*inode
)
284 static int prev_bg_bmap_idx
= -1;
288 uint32_t blk_per_grp
= le32_to_cpu(ext4fs_root
->sblock
.blocks_per_group
);
289 __le32
*tigp_buffer
= NULL
;
290 void *tib_start_addr
= NULL
;
291 __le32
*tip_buffer
= NULL
;
292 void *tipb_start_addr
= NULL
;
293 struct ext2_block_group
*bgd
= NULL
;
294 struct ext_filesystem
*fs
= get_fs();
295 char *journal_buffer
= zalloc(fs
->blksz
);
296 if (!journal_buffer
) {
297 printf("No memory\n");
301 if (inode
->b
.blocks
.triple_indir_block
!= 0) {
302 tigp_buffer
= zalloc(fs
->blksz
);
304 printf("No memory\n");
307 tib_start_addr
= tigp_buffer
;
308 blknr
= le32_to_cpu(inode
->b
.blocks
.triple_indir_block
);
309 status
= ext4fs_devread((lbaint_t
)blknr
* fs
->sect_perblk
, 0,
310 fs
->blksz
, (char *)tigp_buffer
);
311 for (i
= 0; i
< fs
->blksz
/ sizeof(int); i
++) {
312 if (*tigp_buffer
== 0)
314 debug("tigp buffer releasing %u\n", *tigp_buffer
);
316 tip_buffer
= zalloc(fs
->blksz
);
319 tipb_start_addr
= tip_buffer
;
320 status
= ext4fs_devread((lbaint_t
)le32_to_cpu(*tigp_buffer
) *
321 fs
->sect_perblk
, 0, fs
->blksz
,
323 for (j
= 0; j
< fs
->blksz
/ sizeof(int); j
++) {
324 if (le32_to_cpu(*tip_buffer
) == 0)
326 bg_idx
= le32_to_cpu(*tip_buffer
) / blk_per_grp
;
327 if (fs
->blksz
== 1024) {
328 remainder
= le32_to_cpu(*tip_buffer
) % blk_per_grp
;
333 ext4fs_reset_block_bmap(le32_to_cpu(*tip_buffer
),
334 fs
->blk_bmaps
[bg_idx
],
338 /* get block group descriptor table */
339 bgd
= ext4fs_get_group_descriptor(fs
, bg_idx
);
340 ext4fs_bg_free_blocks_inc(bgd
, fs
);
341 ext4fs_sb_free_blocks_inc(fs
->sb
);
343 if (prev_bg_bmap_idx
!= bg_idx
) {
344 uint64_t b_bitmap_blk
=
345 ext4fs_bg_get_block_id(bgd
, fs
);
355 if (ext4fs_log_journal(journal_buffer
,
358 prev_bg_bmap_idx
= bg_idx
;
361 free(tipb_start_addr
);
362 tipb_start_addr
= NULL
;
365 * removing the grand parent blocks
366 * which is connected to inode
368 bg_idx
= le32_to_cpu(*tigp_buffer
) / blk_per_grp
;
369 if (fs
->blksz
== 1024) {
370 remainder
= le32_to_cpu(*tigp_buffer
) % blk_per_grp
;
374 ext4fs_reset_block_bmap(le32_to_cpu(*tigp_buffer
),
375 fs
->blk_bmaps
[bg_idx
], bg_idx
);
378 /* get block group descriptor table */
379 bgd
= ext4fs_get_group_descriptor(fs
, bg_idx
);
380 ext4fs_bg_free_blocks_inc(bgd
, fs
);
381 ext4fs_sb_free_blocks_inc(fs
->sb
);
383 if (prev_bg_bmap_idx
!= bg_idx
) {
384 uint64_t b_bitmap_blk
=
385 ext4fs_bg_get_block_id(bgd
, fs
);
386 memset(journal_buffer
, '\0', fs
->blksz
);
387 status
= ext4fs_devread(b_bitmap_blk
*
394 if (ext4fs_log_journal(journal_buffer
,
397 prev_bg_bmap_idx
= bg_idx
;
401 /* removing the grand parent triple indirect block */
402 blknr
= le32_to_cpu(inode
->b
.blocks
.triple_indir_block
);
403 bg_idx
= blknr
/ blk_per_grp
;
404 if (fs
->blksz
== 1024) {
405 remainder
= blknr
% blk_per_grp
;
409 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
], bg_idx
);
410 /* get block group descriptor table */
411 bgd
= ext4fs_get_group_descriptor(fs
, bg_idx
);
412 ext4fs_bg_free_blocks_inc(bgd
, fs
);
413 ext4fs_sb_free_blocks_inc(fs
->sb
);
415 if (prev_bg_bmap_idx
!= bg_idx
) {
416 uint64_t b_bitmap_blk
= ext4fs_bg_get_block_id(bgd
, fs
);
417 status
= ext4fs_devread(b_bitmap_blk
* fs
->sect_perblk
,
418 0, fs
->blksz
, journal_buffer
);
422 if (ext4fs_log_journal(journal_buffer
, b_bitmap_blk
))
424 prev_bg_bmap_idx
= bg_idx
;
426 debug("tigp buffer itself releasing %d\n", blknr
);
429 free(tib_start_addr
);
430 free(tipb_start_addr
);
431 free(journal_buffer
);
434 static int ext4fs_delete_file(int inodeno
)
436 struct ext2_inode inode
;
443 char *read_buffer
= NULL
;
444 char *start_block_address
= NULL
;
447 static int prev_bg_bmap_idx
= -1;
448 unsigned int inodes_per_block
;
451 uint32_t blk_per_grp
= le32_to_cpu(ext4fs_root
->sblock
.blocks_per_group
);
452 uint32_t inode_per_grp
= le32_to_cpu(ext4fs_root
->sblock
.inodes_per_group
);
453 struct ext2_inode
*inode_buffer
= NULL
;
454 struct ext2_block_group
*bgd
= NULL
;
455 struct ext_filesystem
*fs
= get_fs();
456 char *journal_buffer
= zalloc(fs
->blksz
);
459 status
= ext4fs_read_inode(ext4fs_root
, inodeno
, &inode
);
463 /* read the block no allocated to a file */
464 no_blocks
= le32_to_cpu(inode
.size
) / fs
->blksz
;
465 if (le32_to_cpu(inode
.size
) % fs
->blksz
)
468 if (le32_to_cpu(inode
.flags
) & EXT4_EXTENTS_FL
) {
469 /* FIXME delete extent index blocks, i.e. eh_depth >= 1 */
470 struct ext4_extent_header
*eh
=
471 (struct ext4_extent_header
*)
472 inode
.b
.blocks
.dir_blocks
;
473 debug("del: dep=%d entries=%d\n", eh
->eh_depth
, eh
->eh_entries
);
475 delete_single_indirect_block(&inode
);
476 delete_double_indirect_block(&inode
);
477 delete_triple_indirect_block(&inode
);
480 /* release data blocks */
481 for (i
= 0; i
< no_blocks
; i
++) {
482 blknr
= read_allocated_block(&inode
, i
, NULL
);
487 bg_idx
= blknr
/ blk_per_grp
;
488 if (fs
->blksz
== 1024) {
489 remainder
= blknr
% blk_per_grp
;
493 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
],
495 debug("EXT4 Block releasing %ld: %d\n", blknr
, bg_idx
);
497 /* get block group descriptor table */
498 bgd
= ext4fs_get_group_descriptor(fs
, bg_idx
);
499 ext4fs_bg_free_blocks_inc(bgd
, fs
);
500 ext4fs_sb_free_blocks_inc(fs
->sb
);
502 if (prev_bg_bmap_idx
!= bg_idx
) {
503 uint64_t b_bitmap_blk
= ext4fs_bg_get_block_id(bgd
, fs
);
504 status
= ext4fs_devread(b_bitmap_blk
* fs
->sect_perblk
,
509 if (ext4fs_log_journal(journal_buffer
, b_bitmap_blk
))
511 prev_bg_bmap_idx
= bg_idx
;
516 /* from the inode no to blockno */
517 inodes_per_block
= fs
->blksz
/ fs
->inodesz
;
518 ibmap_idx
= inodeno
/ inode_per_grp
;
520 /* get the block no */
522 /* get block group descriptor table */
523 bgd
= ext4fs_get_group_descriptor(fs
, ibmap_idx
);
524 blkno
= ext4fs_bg_get_inode_table_id(bgd
, fs
) +
525 (inodeno
% inode_per_grp
) / inodes_per_block
;
527 /* get the offset of the inode */
528 blkoff
= ((inodeno
) % inodes_per_block
) * fs
->inodesz
;
530 /* read the block no containing the inode */
531 read_buffer
= zalloc(fs
->blksz
);
534 start_block_address
= read_buffer
;
535 status
= ext4fs_devread((lbaint_t
)blkno
* fs
->sect_perblk
,
536 0, fs
->blksz
, read_buffer
);
540 if (ext4fs_log_journal(read_buffer
, blkno
))
543 read_buffer
= read_buffer
+ blkoff
;
544 inode_buffer
= (struct ext2_inode
*)read_buffer
;
545 memset(inode_buffer
, '\0', fs
->inodesz
);
547 /* write the inode to original position in inode table */
548 if (ext4fs_put_metadata(start_block_address
, blkno
))
551 /* update the respective inode bitmaps */
553 ext4fs_reset_inode_bmap(inodeno
, fs
->inode_bmaps
[ibmap_idx
], ibmap_idx
);
554 ext4fs_bg_free_inodes_inc(bgd
, fs
);
555 ext4fs_sb_free_inodes_inc(fs
->sb
);
557 memset(journal_buffer
, '\0', fs
->blksz
);
558 status
= ext4fs_devread(ext4fs_bg_get_inode_id(bgd
, fs
) *
559 fs
->sect_perblk
, 0, fs
->blksz
, journal_buffer
);
562 if (ext4fs_log_journal(journal_buffer
, ext4fs_bg_get_inode_id(bgd
, fs
)))
567 ext4fs_reinit_global();
569 if (ext4fs_init() != 0) {
570 printf("error in File System init\n");
574 free(start_block_address
);
575 free(journal_buffer
);
579 free(start_block_address
);
580 free(journal_buffer
);
585 int ext4fs_init(void)
589 uint32_t real_free_blocks
= 0;
590 struct ext_filesystem
*fs
= get_fs();
593 fs
->blksz
= EXT2_BLOCK_SIZE(ext4fs_root
);
594 fs
->sect_perblk
= fs
->blksz
>> fs
->dev_desc
->log2blksz
;
596 /* get the superblock */
597 fs
->sb
= zalloc(SUPERBLOCK_SIZE
);
600 if (!ext4_read_superblock((char *)fs
->sb
))
604 if (ext4fs_init_journal())
607 /* get total no of blockgroups */
608 fs
->no_blkgrp
= (uint32_t)ext4fs_div_roundup(
609 le32_to_cpu(ext4fs_root
->sblock
.total_blocks
)
610 - le32_to_cpu(ext4fs_root
->sblock
.first_data_block
),
611 le32_to_cpu(ext4fs_root
->sblock
.blocks_per_group
));
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");
620 /* load all the available bitmap block of the partition */
621 fs
->blk_bmaps
= zalloc(fs
->no_blkgrp
* sizeof(char *));
624 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
625 fs
->blk_bmaps
[i
] = zalloc(fs
->blksz
);
626 if (!fs
->blk_bmaps
[i
])
630 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
631 struct ext2_block_group
*bgd
=
632 ext4fs_get_group_descriptor(fs
, i
);
633 status
= ext4fs_devread(ext4fs_bg_get_block_id(bgd
, fs
) *
635 fs
->blksz
, (char *)fs
->blk_bmaps
[i
]);
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
)
644 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
645 fs
->inode_bmaps
[i
] = zalloc(fs
->blksz
);
646 if (!fs
->inode_bmaps
[i
])
650 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
651 struct ext2_block_group
*bgd
=
652 ext4fs_get_group_descriptor(fs
, i
);
653 status
= ext4fs_devread(ext4fs_bg_get_inode_id(bgd
, fs
) *
656 (char *)fs
->inode_bmaps
[i
]);
662 * check filesystem consistency with free blocks of file system
663 * some time we observed that superblock freeblocks does not match
664 * with the blockgroups freeblocks when improper
665 * reboot of a linux kernel
667 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
668 struct ext2_block_group
*bgd
=
669 ext4fs_get_group_descriptor(fs
, i
);
670 real_free_blocks
= real_free_blocks
+
671 ext4fs_bg_get_free_blocks(bgd
, fs
);
673 if (real_free_blocks
!= ext4fs_sb_get_free_blocks(fs
->sb
))
674 ext4fs_sb_set_free_blocks(fs
->sb
, real_free_blocks
);
683 void ext4fs_deinit(void)
686 struct ext2_inode inode_journal
;
687 struct journal_superblock_t
*jsb
;
689 struct ext_filesystem
*fs
= get_fs();
690 uint32_t new_feature_incompat
;
693 char *temp_buff
= zalloc(fs
->blksz
);
695 ext4fs_read_inode(ext4fs_root
, EXT2_JOURNAL_INO
,
697 blknr
= read_allocated_block(&inode_journal
,
698 EXT2_JOURNAL_SUPERBLOCK
, NULL
);
699 ext4fs_devread((lbaint_t
)blknr
* fs
->sect_perblk
, 0, fs
->blksz
,
701 jsb
= (struct journal_superblock_t
*)temp_buff
;
703 put_ext4((uint64_t) ((uint64_t)blknr
* (uint64_t)fs
->blksz
),
704 (struct journal_superblock_t
*)temp_buff
, fs
->blksz
);
707 ext4fs_free_journal();
709 /* get the superblock */
710 ext4_read_superblock((char *)fs
->sb
);
711 new_feature_incompat
= le32_to_cpu(fs
->sb
->feature_incompat
);
712 new_feature_incompat
&= ~EXT3_FEATURE_INCOMPAT_RECOVER
;
713 fs
->sb
->feature_incompat
= cpu_to_le32(new_feature_incompat
);
714 put_ext4((uint64_t)(SUPERBLOCK_SIZE
),
715 (struct ext2_sblock
*)fs
->sb
, (uint32_t)SUPERBLOCK_SIZE
);
720 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
721 free(fs
->blk_bmaps
[i
]);
722 fs
->blk_bmaps
[i
] = NULL
;
725 fs
->blk_bmaps
= NULL
;
728 if (fs
->inode_bmaps
) {
729 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
730 free(fs
->inode_bmaps
[i
]);
731 fs
->inode_bmaps
[i
] = NULL
;
733 free(fs
->inode_bmaps
);
734 fs
->inode_bmaps
= NULL
;
741 * reinitiliazed the global inode and
742 * block bitmap first execution check variables
744 fs
->first_pass_ibmap
= 0;
745 fs
->first_pass_bbmap
= 0;
746 fs
->curr_inode_no
= 0;
751 * Write data to filesystem blocks. Uses same optimization for
752 * contigous sectors as ext4fs_read_file
754 static int ext4fs_write_file(struct ext2_inode
*file_inode
,
755 int pos
, unsigned int len
, const char *buf
)
759 uint32_t filesize
= le32_to_cpu(file_inode
->size
);
760 struct ext_filesystem
*fs
= get_fs();
761 int log2blksz
= fs
->dev_desc
->log2blksz
;
762 int log2_fs_blocksize
= LOG2_BLOCK_SIZE(ext4fs_root
) - log2blksz
;
763 int previous_block_number
= -1;
764 int delayed_start
= 0;
765 int delayed_extent
= 0;
766 int delayed_next
= 0;
767 const char *delayed_buf
= NULL
;
769 /* Adjust len so it we can't read past the end of the file. */
773 blockcnt
= ((len
+ pos
) + fs
->blksz
- 1) / fs
->blksz
;
775 for (i
= pos
/ fs
->blksz
; i
< blockcnt
; i
++) {
777 int blockend
= fs
->blksz
;
779 blknr
= read_allocated_block(file_inode
, i
, NULL
);
783 blknr
= blknr
<< log2_fs_blocksize
;
786 if (previous_block_number
!= -1) {
787 if (delayed_next
== blknr
) {
788 delayed_extent
+= blockend
;
789 delayed_next
+= blockend
>> log2blksz
;
792 ((uint64_t)delayed_start
<< log2blksz
),
794 (uint32_t) delayed_extent
);
795 previous_block_number
= blknr
;
796 delayed_start
= blknr
;
797 delayed_extent
= blockend
;
799 delayed_next
= blknr
+
800 (blockend
>> log2blksz
);
803 previous_block_number
= blknr
;
804 delayed_start
= blknr
;
805 delayed_extent
= blockend
;
807 delayed_next
= blknr
+
808 (blockend
>> log2blksz
);
811 if (previous_block_number
!= -1) {
813 put_ext4((uint64_t) ((uint64_t)delayed_start
<<
816 (uint32_t) delayed_extent
);
817 previous_block_number
= -1;
820 buf
+= fs
->blksz
- skipfirst
;
822 if (previous_block_number
!= -1) {
824 put_ext4((uint64_t) ((uint64_t)delayed_start
<< log2blksz
),
825 delayed_buf
, (uint32_t) delayed_extent
);
826 previous_block_number
= -1;
832 int ext4fs_write(const char *fname
, const char *buffer
,
833 unsigned long sizebytes
)
836 struct ext2_inode
*file_inode
= NULL
;
837 unsigned char *inode_buffer
= NULL
;
840 time_t timestamp
= 0;
842 uint64_t bytes_reqd_for_file
;
843 unsigned int blks_reqd_for_file
;
844 unsigned int blocks_remaining
;
845 int existing_file_inodeno
;
846 char *temp_ptr
= NULL
;
847 long int itable_blkno
;
848 long int parent_itable_blkno
;
850 struct ext2_sblock
*sblock
= &(ext4fs_root
->sblock
);
851 unsigned int inodes_per_block
;
852 unsigned int ibmap_idx
;
853 struct ext2_block_group
*bgd
= NULL
;
854 struct ext_filesystem
*fs
= get_fs();
855 ALLOC_CACHE_ALIGN_BUFFER(char, filename
, 256);
856 memset(filename
, 0x00, 256);
858 g_parent_inode
= zalloc(fs
->inodesz
);
862 if (ext4fs_init() != 0) {
863 printf("error in File System init\n");
867 if (le32_to_cpu(fs
->sb
->feature_ro_compat
) & EXT4_FEATURE_RO_COMPAT_METADATA_CSUM
) {
868 printf("Unsupported feature metadata_csum found, not writing.\n");
872 inodes_per_block
= fs
->blksz
/ fs
->inodesz
;
873 parent_inodeno
= ext4fs_get_parent_inode_num(fname
, filename
, F_FILE
);
874 if (parent_inodeno
== -1)
876 if (ext4fs_iget(parent_inodeno
, g_parent_inode
))
878 /* do not mess up a directory using hash trees */
879 if (le32_to_cpu(g_parent_inode
->flags
) & EXT4_INDEX_FL
) {
880 printf("hash tree directory\n");
883 /* check if the filename is already present in root */
884 existing_file_inodeno
= ext4fs_filename_unlink(filename
);
885 if (existing_file_inodeno
!= -1) {
886 ret
= ext4fs_delete_file(existing_file_inodeno
);
887 fs
->first_pass_bbmap
= 0;
890 fs
->first_pass_ibmap
= 0;
891 fs
->curr_inode_no
= 0;
895 /* calucalate how many blocks required */
896 bytes_reqd_for_file
= sizebytes
;
897 blks_reqd_for_file
= lldiv(bytes_reqd_for_file
, fs
->blksz
);
898 if (do_div(bytes_reqd_for_file
, fs
->blksz
) != 0) {
899 blks_reqd_for_file
++;
900 debug("total bytes for a file %u\n", blks_reqd_for_file
);
902 blocks_remaining
= blks_reqd_for_file
;
903 /* test for available space in partition */
904 if (le32_to_cpu(fs
->sb
->free_blocks
) < blks_reqd_for_file
) {
905 printf("Not enough space on partition !!!\n");
909 inodeno
= ext4fs_update_parent_dentry(filename
, FILETYPE_REG
);
912 /* prepare file inode */
913 inode_buffer
= zalloc(fs
->inodesz
);
916 file_inode
= (struct ext2_inode
*)inode_buffer
;
917 file_inode
->mode
= cpu_to_le16(S_IFREG
| S_IRWXU
|
918 S_IRGRP
| S_IROTH
| S_IXGRP
| S_IXOTH
);
919 /* ToDo: Update correct time */
920 file_inode
->mtime
= cpu_to_le32(timestamp
);
921 file_inode
->atime
= cpu_to_le32(timestamp
);
922 file_inode
->ctime
= cpu_to_le32(timestamp
);
923 file_inode
->nlinks
= cpu_to_le16(1);
924 file_inode
->size
= cpu_to_le32(sizebytes
);
926 /* Allocate data blocks */
927 ext4fs_allocate_blocks(file_inode
, blocks_remaining
,
928 &blks_reqd_for_file
);
929 file_inode
->blockcnt
= cpu_to_le32((blks_reqd_for_file
* fs
->blksz
) >>
930 fs
->dev_desc
->log2blksz
);
932 temp_ptr
= zalloc(fs
->blksz
);
935 ibmap_idx
= inodeno
/ le32_to_cpu(ext4fs_root
->sblock
.inodes_per_group
);
937 bgd
= ext4fs_get_group_descriptor(fs
, ibmap_idx
);
938 itable_blkno
= ext4fs_bg_get_inode_table_id(bgd
, fs
) +
939 (inodeno
% le32_to_cpu(sblock
->inodes_per_group
)) /
941 blkoff
= (inodeno
% inodes_per_block
) * fs
->inodesz
;
942 ext4fs_devread((lbaint_t
)itable_blkno
* fs
->sect_perblk
, 0, fs
->blksz
,
944 if (ext4fs_log_journal(temp_ptr
, itable_blkno
))
947 memcpy(temp_ptr
+ blkoff
, inode_buffer
, fs
->inodesz
);
948 if (ext4fs_put_metadata(temp_ptr
, itable_blkno
))
950 /* copy the file content into data blocks */
951 if (ext4fs_write_file(file_inode
, 0, sizebytes
, buffer
) == -1) {
952 printf("Error in copying content\n");
953 /* FIXME: Deallocate data blocks */
956 ibmap_idx
= parent_inodeno
/ le32_to_cpu(ext4fs_root
->sblock
.inodes_per_group
);
958 bgd
= ext4fs_get_group_descriptor(fs
, ibmap_idx
);
959 parent_itable_blkno
= ext4fs_bg_get_inode_table_id(bgd
, fs
) +
961 le32_to_cpu(sblock
->inodes_per_group
)) / inodes_per_block
;
962 blkoff
= (parent_inodeno
% inodes_per_block
) * fs
->inodesz
;
963 if (parent_itable_blkno
!= itable_blkno
) {
964 memset(temp_ptr
, '\0', fs
->blksz
);
965 ext4fs_devread((lbaint_t
)parent_itable_blkno
* fs
->sect_perblk
,
966 0, fs
->blksz
, temp_ptr
);
967 if (ext4fs_log_journal(temp_ptr
, parent_itable_blkno
))
970 memcpy(temp_ptr
+ blkoff
, g_parent_inode
, fs
->inodesz
);
971 if (ext4fs_put_metadata(temp_ptr
, parent_itable_blkno
))
975 * If parent and child fall in same inode table block
976 * both should be kept in 1 buffer
978 memcpy(temp_ptr
+ blkoff
, g_parent_inode
, fs
->inodesz
);
980 if (ext4fs_put_metadata(temp_ptr
, itable_blkno
))
986 fs
->first_pass_bbmap
= 0;
988 fs
->first_pass_ibmap
= 0;
989 fs
->curr_inode_no
= 0;
991 free(g_parent_inode
);
993 g_parent_inode
= NULL
;
999 free(g_parent_inode
);
1001 g_parent_inode
= NULL
;
1006 int ext4_write_file(const char *filename
, void *buf
, loff_t offset
,
1007 loff_t len
, loff_t
*actwrite
)
1012 printf("** Cannot support non-zero offset **\n");
1016 ret
= ext4fs_write(filename
, buf
, len
);
1018 printf("** Error ext4fs_write() **\n");