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+
26 #include <linux/stat.h>
28 #include "ext4_common.h"
30 static void ext4fs_update(void)
33 ext4fs_update_journal();
34 struct ext_filesystem
*fs
= get_fs();
36 /* update super block */
37 put_ext4((uint64_t)(SUPERBLOCK_SIZE
),
38 (struct ext2_sblock
*)fs
->sb
, (uint32_t)SUPERBLOCK_SIZE
);
40 /* update block groups */
41 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
42 fs
->bgd
[i
].bg_checksum
= ext4fs_checksum_update(i
);
43 put_ext4((uint64_t)(fs
->bgd
[i
].block_id
* fs
->blksz
),
44 fs
->blk_bmaps
[i
], fs
->blksz
);
47 /* update inode table groups */
48 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
49 put_ext4((uint64_t) (fs
->bgd
[i
].inode_id
* fs
->blksz
),
50 fs
->inode_bmaps
[i
], fs
->blksz
);
53 /* update the block group descriptor table */
54 put_ext4((uint64_t)(fs
->gdtable_blkno
* fs
->blksz
),
55 (struct ext2_block_group
*)fs
->gdtable
,
56 (fs
->blksz
* fs
->no_blk_pergdt
));
58 ext4fs_dump_metadata();
64 int ext4fs_get_bgdtable(void)
68 struct ext_filesystem
*fs
= get_fs();
69 grp_desc_size
= sizeof(struct ext2_block_group
);
70 fs
->no_blk_pergdt
= (fs
->no_blkgrp
* grp_desc_size
) / fs
->blksz
;
71 if ((fs
->no_blkgrp
* grp_desc_size
) % fs
->blksz
)
74 /* allocate memory for gdtable */
75 fs
->gdtable
= zalloc(fs
->blksz
* fs
->no_blk_pergdt
);
78 /* read the group descriptor table */
79 status
= ext4fs_devread((lbaint_t
)fs
->gdtable_blkno
* fs
->sect_perblk
,
80 0, fs
->blksz
* fs
->no_blk_pergdt
, fs
->gdtable
);
84 if (ext4fs_log_gdt(fs
->gdtable
)) {
85 printf("Error in ext4fs_log_gdt\n");
97 static void delete_single_indirect_block(struct ext2_inode
*inode
)
99 struct ext2_block_group
*bgd
= NULL
;
100 static int prev_bg_bmap_idx
= -1;
105 unsigned int blk_per_grp
= ext4fs_root
->sblock
.blocks_per_group
;
106 struct ext_filesystem
*fs
= get_fs();
107 char *journal_buffer
= zalloc(fs
->blksz
);
108 if (!journal_buffer
) {
109 printf("No memory\n");
112 /* get block group descriptor table */
113 bgd
= (struct ext2_block_group
*)fs
->gdtable
;
115 /* deleting the single indirect block associated with inode */
116 if (inode
->b
.blocks
.indir_block
!= 0) {
117 debug("SIPB releasing %u\n", inode
->b
.blocks
.indir_block
);
118 blknr
= inode
->b
.blocks
.indir_block
;
119 if (fs
->blksz
!= 1024) {
120 bg_idx
= blknr
/ blk_per_grp
;
122 bg_idx
= blknr
/ blk_per_grp
;
123 remainder
= blknr
% blk_per_grp
;
127 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
], bg_idx
);
128 bgd
[bg_idx
].free_blocks
++;
129 fs
->sb
->free_blocks
++;
131 if (prev_bg_bmap_idx
!= bg_idx
) {
133 ext4fs_devread((lbaint_t
)bgd
[bg_idx
].block_id
*
134 fs
->sect_perblk
, 0, fs
->blksz
,
138 if (ext4fs_log_journal
139 (journal_buffer
, bgd
[bg_idx
].block_id
))
141 prev_bg_bmap_idx
= bg_idx
;
145 free(journal_buffer
);
148 static void delete_double_indirect_block(struct ext2_inode
*inode
)
152 static int prev_bg_bmap_idx
= -1;
156 unsigned int blk_per_grp
= ext4fs_root
->sblock
.blocks_per_group
;
157 unsigned int *di_buffer
= NULL
;
158 unsigned int *DIB_start_addr
= NULL
;
159 struct ext2_block_group
*bgd
= NULL
;
160 struct ext_filesystem
*fs
= get_fs();
161 char *journal_buffer
= zalloc(fs
->blksz
);
162 if (!journal_buffer
) {
163 printf("No memory\n");
166 /* get the block group descriptor table */
167 bgd
= (struct ext2_block_group
*)fs
->gdtable
;
169 if (inode
->b
.blocks
.double_indir_block
!= 0) {
170 di_buffer
= zalloc(fs
->blksz
);
172 printf("No memory\n");
175 DIB_start_addr
= (unsigned int *)di_buffer
;
176 blknr
= inode
->b
.blocks
.double_indir_block
;
177 status
= ext4fs_devread((lbaint_t
)blknr
* fs
->sect_perblk
, 0,
178 fs
->blksz
, (char *)di_buffer
);
179 for (i
= 0; i
< fs
->blksz
/ sizeof(int); i
++) {
183 debug("DICB releasing %u\n", *di_buffer
);
184 if (fs
->blksz
!= 1024) {
185 bg_idx
= (*di_buffer
) / blk_per_grp
;
187 bg_idx
= (*di_buffer
) / blk_per_grp
;
188 remainder
= (*di_buffer
) % blk_per_grp
;
192 ext4fs_reset_block_bmap(*di_buffer
,
193 fs
->blk_bmaps
[bg_idx
], bg_idx
);
195 bgd
[bg_idx
].free_blocks
++;
196 fs
->sb
->free_blocks
++;
198 if (prev_bg_bmap_idx
!= bg_idx
) {
199 status
= ext4fs_devread((lbaint_t
)
201 * fs
->sect_perblk
, 0,
207 if (ext4fs_log_journal(journal_buffer
,
208 bgd
[bg_idx
].block_id
))
210 prev_bg_bmap_idx
= bg_idx
;
214 /* removing the parent double indirect block */
215 blknr
= inode
->b
.blocks
.double_indir_block
;
216 if (fs
->blksz
!= 1024) {
217 bg_idx
= blknr
/ blk_per_grp
;
219 bg_idx
= blknr
/ blk_per_grp
;
220 remainder
= blknr
% blk_per_grp
;
224 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
], bg_idx
);
225 bgd
[bg_idx
].free_blocks
++;
226 fs
->sb
->free_blocks
++;
228 if (prev_bg_bmap_idx
!= bg_idx
) {
229 memset(journal_buffer
, '\0', fs
->blksz
);
230 status
= ext4fs_devread((lbaint_t
)bgd
[bg_idx
].block_id
*
231 fs
->sect_perblk
, 0, fs
->blksz
,
236 if (ext4fs_log_journal(journal_buffer
,
237 bgd
[bg_idx
].block_id
))
239 prev_bg_bmap_idx
= bg_idx
;
241 debug("DIPB releasing %ld\n", blknr
);
244 free(DIB_start_addr
);
245 free(journal_buffer
);
248 static void delete_triple_indirect_block(struct ext2_inode
*inode
)
252 static int prev_bg_bmap_idx
= -1;
256 unsigned int blk_per_grp
= ext4fs_root
->sblock
.blocks_per_group
;
257 unsigned int *tigp_buffer
= NULL
;
258 unsigned int *tib_start_addr
= NULL
;
259 unsigned int *tip_buffer
= NULL
;
260 unsigned int *tipb_start_addr
= NULL
;
261 struct ext2_block_group
*bgd
= NULL
;
262 struct ext_filesystem
*fs
= get_fs();
263 char *journal_buffer
= zalloc(fs
->blksz
);
264 if (!journal_buffer
) {
265 printf("No memory\n");
268 /* get block group descriptor table */
269 bgd
= (struct ext2_block_group
*)fs
->gdtable
;
271 if (inode
->b
.blocks
.triple_indir_block
!= 0) {
272 tigp_buffer
= zalloc(fs
->blksz
);
274 printf("No memory\n");
277 tib_start_addr
= (unsigned int *)tigp_buffer
;
278 blknr
= inode
->b
.blocks
.triple_indir_block
;
279 status
= ext4fs_devread((lbaint_t
)blknr
* fs
->sect_perblk
, 0,
280 fs
->blksz
, (char *)tigp_buffer
);
281 for (i
= 0; i
< fs
->blksz
/ sizeof(int); i
++) {
282 if (*tigp_buffer
== 0)
284 debug("tigp buffer releasing %u\n", *tigp_buffer
);
286 tip_buffer
= zalloc(fs
->blksz
);
289 tipb_start_addr
= (unsigned int *)tip_buffer
;
290 status
= ext4fs_devread((lbaint_t
)(*tigp_buffer
) *
291 fs
->sect_perblk
, 0, fs
->blksz
,
293 for (j
= 0; j
< fs
->blksz
/ sizeof(int); j
++) {
294 if (*tip_buffer
== 0)
296 if (fs
->blksz
!= 1024) {
297 bg_idx
= (*tip_buffer
) / blk_per_grp
;
299 bg_idx
= (*tip_buffer
) / blk_per_grp
;
301 remainder
= (*tip_buffer
) % blk_per_grp
;
306 ext4fs_reset_block_bmap(*tip_buffer
,
307 fs
->blk_bmaps
[bg_idx
],
311 bgd
[bg_idx
].free_blocks
++;
312 fs
->sb
->free_blocks
++;
314 if (prev_bg_bmap_idx
!= bg_idx
) {
318 bgd
[bg_idx
].block_id
*
325 if (ext4fs_log_journal(journal_buffer
,
329 prev_bg_bmap_idx
= bg_idx
;
332 free(tipb_start_addr
);
333 tipb_start_addr
= NULL
;
336 * removing the grand parent blocks
337 * which is connected to inode
339 if (fs
->blksz
!= 1024) {
340 bg_idx
= (*tigp_buffer
) / blk_per_grp
;
342 bg_idx
= (*tigp_buffer
) / blk_per_grp
;
344 remainder
= (*tigp_buffer
) % blk_per_grp
;
348 ext4fs_reset_block_bmap(*tigp_buffer
,
349 fs
->blk_bmaps
[bg_idx
], bg_idx
);
352 bgd
[bg_idx
].free_blocks
++;
353 fs
->sb
->free_blocks
++;
355 if (prev_bg_bmap_idx
!= bg_idx
) {
356 memset(journal_buffer
, '\0', fs
->blksz
);
358 ext4fs_devread((lbaint_t
)
359 bgd
[bg_idx
].block_id
*
361 fs
->blksz
, journal_buffer
);
365 if (ext4fs_log_journal(journal_buffer
,
366 bgd
[bg_idx
].block_id
))
368 prev_bg_bmap_idx
= bg_idx
;
372 /* removing the grand parent triple indirect block */
373 blknr
= inode
->b
.blocks
.triple_indir_block
;
374 if (fs
->blksz
!= 1024) {
375 bg_idx
= blknr
/ blk_per_grp
;
377 bg_idx
= blknr
/ blk_per_grp
;
378 remainder
= blknr
% blk_per_grp
;
382 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
], bg_idx
);
383 bgd
[bg_idx
].free_blocks
++;
384 fs
->sb
->free_blocks
++;
386 if (prev_bg_bmap_idx
!= bg_idx
) {
387 memset(journal_buffer
, '\0', fs
->blksz
);
388 status
= ext4fs_devread((lbaint_t
)bgd
[bg_idx
].block_id
*
389 fs
->sect_perblk
, 0, fs
->blksz
,
394 if (ext4fs_log_journal(journal_buffer
,
395 bgd
[bg_idx
].block_id
))
397 prev_bg_bmap_idx
= bg_idx
;
399 debug("tigp buffer itself releasing %ld\n", blknr
);
402 free(tib_start_addr
);
403 free(tipb_start_addr
);
404 free(journal_buffer
);
407 static int ext4fs_delete_file(int inodeno
)
409 struct ext2_inode inode
;
416 char *read_buffer
= NULL
;
417 char *start_block_address
= NULL
;
418 unsigned int no_blocks
;
420 static int prev_bg_bmap_idx
= -1;
421 unsigned int inodes_per_block
;
424 unsigned int blk_per_grp
= ext4fs_root
->sblock
.blocks_per_group
;
425 unsigned int inode_per_grp
= ext4fs_root
->sblock
.inodes_per_group
;
426 struct ext2_inode
*inode_buffer
= NULL
;
427 struct ext2_block_group
*bgd
= NULL
;
428 struct ext_filesystem
*fs
= get_fs();
429 char *journal_buffer
= zalloc(fs
->blksz
);
432 /* get the block group descriptor table */
433 bgd
= (struct ext2_block_group
*)fs
->gdtable
;
434 status
= ext4fs_read_inode(ext4fs_root
, inodeno
, &inode
);
438 /* read the block no allocated to a file */
439 no_blocks
= inode
.size
/ fs
->blksz
;
440 if (inode
.size
% fs
->blksz
)
443 if (le32_to_cpu(inode
.flags
) & EXT4_EXTENTS_FL
) {
444 struct ext2fs_node
*node_inode
=
445 zalloc(sizeof(struct ext2fs_node
));
448 node_inode
->data
= ext4fs_root
;
449 node_inode
->ino
= inodeno
;
450 node_inode
->inode_read
= 0;
451 memcpy(&(node_inode
->inode
), &inode
, sizeof(struct ext2_inode
));
453 for (i
= 0; i
< no_blocks
; i
++) {
454 blknr
= read_allocated_block(&(node_inode
->inode
), i
);
455 if (fs
->blksz
!= 1024) {
456 bg_idx
= blknr
/ blk_per_grp
;
458 bg_idx
= blknr
/ blk_per_grp
;
459 remainder
= blknr
% blk_per_grp
;
463 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
],
465 debug("EXT4_EXTENTS Block releasing %ld: %d\n",
468 bgd
[bg_idx
].free_blocks
++;
469 fs
->sb
->free_blocks
++;
472 if (prev_bg_bmap_idx
!= bg_idx
) {
474 ext4fs_devread((lbaint_t
)
475 bgd
[bg_idx
].block_id
*
477 fs
->blksz
, journal_buffer
);
480 if (ext4fs_log_journal(journal_buffer
,
481 bgd
[bg_idx
].block_id
))
483 prev_bg_bmap_idx
= bg_idx
;
492 delete_single_indirect_block(&inode
);
493 delete_double_indirect_block(&inode
);
494 delete_triple_indirect_block(&inode
);
496 /* read the block no allocated to a file */
497 no_blocks
= inode
.size
/ fs
->blksz
;
498 if (inode
.size
% fs
->blksz
)
500 for (i
= 0; i
< no_blocks
; i
++) {
501 blknr
= read_allocated_block(&inode
, i
);
502 if (fs
->blksz
!= 1024) {
503 bg_idx
= blknr
/ blk_per_grp
;
505 bg_idx
= blknr
/ blk_per_grp
;
506 remainder
= blknr
% blk_per_grp
;
510 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
],
512 debug("ActualB releasing %ld: %d\n", blknr
, bg_idx
);
514 bgd
[bg_idx
].free_blocks
++;
515 fs
->sb
->free_blocks
++;
517 if (prev_bg_bmap_idx
!= bg_idx
) {
518 memset(journal_buffer
, '\0', fs
->blksz
);
519 status
= ext4fs_devread((lbaint_t
)
526 if (ext4fs_log_journal(journal_buffer
,
527 bgd
[bg_idx
].block_id
))
529 prev_bg_bmap_idx
= bg_idx
;
534 /* from the inode no to blockno */
535 inodes_per_block
= fs
->blksz
/ fs
->inodesz
;
536 ibmap_idx
= inodeno
/ inode_per_grp
;
538 /* get the block no */
540 blkno
= __le32_to_cpu(bgd
[ibmap_idx
].inode_table_id
) +
541 (inodeno
% __le32_to_cpu(inode_per_grp
)) / inodes_per_block
;
543 /* get the offset of the inode */
544 blkoff
= ((inodeno
) % inodes_per_block
) * fs
->inodesz
;
546 /* read the block no containing the inode */
547 read_buffer
= zalloc(fs
->blksz
);
550 start_block_address
= read_buffer
;
551 status
= ext4fs_devread((lbaint_t
)blkno
* fs
->sect_perblk
,
552 0, fs
->blksz
, read_buffer
);
556 if (ext4fs_log_journal(read_buffer
, blkno
))
559 read_buffer
= read_buffer
+ blkoff
;
560 inode_buffer
= (struct ext2_inode
*)read_buffer
;
561 memset(inode_buffer
, '\0', sizeof(struct ext2_inode
));
563 /* write the inode to original position in inode table */
564 if (ext4fs_put_metadata(start_block_address
, blkno
))
567 /* update the respective inode bitmaps */
569 ext4fs_reset_inode_bmap(inodeno
, fs
->inode_bmaps
[ibmap_idx
], ibmap_idx
);
570 bgd
[ibmap_idx
].free_inodes
++;
571 fs
->sb
->free_inodes
++;
573 memset(journal_buffer
, '\0', fs
->blksz
);
574 status
= ext4fs_devread((lbaint_t
)bgd
[ibmap_idx
].inode_id
*
575 fs
->sect_perblk
, 0, fs
->blksz
, journal_buffer
);
578 if (ext4fs_log_journal(journal_buffer
, bgd
[ibmap_idx
].inode_id
))
584 if (ext4fs_init() != 0) {
585 printf("error in File System init\n");
589 free(start_block_address
);
590 free(journal_buffer
);
594 free(start_block_address
);
595 free(journal_buffer
);
600 int ext4fs_init(void)
604 unsigned int real_free_blocks
= 0;
605 struct ext_filesystem
*fs
= get_fs();
608 fs
->blksz
= EXT2_BLOCK_SIZE(ext4fs_root
);
609 fs
->inodesz
= INODE_SIZE_FILESYSTEM(ext4fs_root
);
610 fs
->sect_perblk
= fs
->blksz
>> fs
->dev_desc
->log2blksz
;
612 /* get the superblock */
613 fs
->sb
= zalloc(SUPERBLOCK_SIZE
);
616 if (!ext4_read_superblock((char *)fs
->sb
))
620 if (ext4fs_init_journal())
623 /* get total no of blockgroups */
624 fs
->no_blkgrp
= (uint32_t)ext4fs_div_roundup(
625 (ext4fs_root
->sblock
.total_blocks
-
626 ext4fs_root
->sblock
.first_data_block
),
627 ext4fs_root
->sblock
.blocks_per_group
);
629 /* get the block group descriptor table */
630 fs
->gdtable_blkno
= ((EXT2_MIN_BLOCK_SIZE
== fs
->blksz
) + 1);
631 if (ext4fs_get_bgdtable() == -1) {
632 printf("Error in getting the block group descriptor table\n");
635 fs
->bgd
= (struct ext2_block_group
*)fs
->gdtable
;
637 /* load all the available bitmap block of the partition */
638 fs
->blk_bmaps
= zalloc(fs
->no_blkgrp
* sizeof(char *));
641 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
642 fs
->blk_bmaps
[i
] = zalloc(fs
->blksz
);
643 if (!fs
->blk_bmaps
[i
])
647 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
649 ext4fs_devread((lbaint_t
)fs
->bgd
[i
].block_id
*
651 fs
->blksz
, (char *)fs
->blk_bmaps
[i
]);
656 /* load all the available inode bitmap of the partition */
657 fs
->inode_bmaps
= zalloc(fs
->no_blkgrp
* sizeof(unsigned char *));
658 if (!fs
->inode_bmaps
)
660 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
661 fs
->inode_bmaps
[i
] = zalloc(fs
->blksz
);
662 if (!fs
->inode_bmaps
[i
])
666 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
667 status
= ext4fs_devread((lbaint_t
)fs
->bgd
[i
].inode_id
*
670 (char *)fs
->inode_bmaps
[i
]);
676 * check filesystem consistency with free blocks of file system
677 * some time we observed that superblock freeblocks does not match
678 * with the blockgroups freeblocks when improper
679 * reboot of a linux kernel
681 for (i
= 0; i
< fs
->no_blkgrp
; i
++)
682 real_free_blocks
= real_free_blocks
+ fs
->bgd
[i
].free_blocks
;
683 if (real_free_blocks
!= fs
->sb
->free_blocks
)
684 fs
->sb
->free_blocks
= real_free_blocks
;
693 void ext4fs_deinit(void)
696 struct ext2_inode inode_journal
;
697 struct journal_superblock_t
*jsb
;
699 struct ext_filesystem
*fs
= get_fs();
702 char *temp_buff
= zalloc(fs
->blksz
);
704 ext4fs_read_inode(ext4fs_root
, EXT2_JOURNAL_INO
,
706 blknr
= read_allocated_block(&inode_journal
,
707 EXT2_JOURNAL_SUPERBLOCK
);
708 ext4fs_devread((lbaint_t
)blknr
* fs
->sect_perblk
, 0, fs
->blksz
,
710 jsb
= (struct journal_superblock_t
*)temp_buff
;
711 jsb
->s_start
= cpu_to_be32(0);
712 put_ext4((uint64_t) (blknr
* fs
->blksz
),
713 (struct journal_superblock_t
*)temp_buff
, fs
->blksz
);
716 ext4fs_free_journal();
718 /* get the superblock */
719 ext4_read_superblock((char *)fs
->sb
);
720 fs
->sb
->feature_incompat
&= ~EXT3_FEATURE_INCOMPAT_RECOVER
;
721 put_ext4((uint64_t)(SUPERBLOCK_SIZE
),
722 (struct ext2_sblock
*)fs
->sb
, (uint32_t)SUPERBLOCK_SIZE
);
727 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
728 free(fs
->blk_bmaps
[i
]);
729 fs
->blk_bmaps
[i
] = NULL
;
732 fs
->blk_bmaps
= NULL
;
735 if (fs
->inode_bmaps
) {
736 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
737 free(fs
->inode_bmaps
[i
]);
738 fs
->inode_bmaps
[i
] = NULL
;
740 free(fs
->inode_bmaps
);
741 fs
->inode_bmaps
= NULL
;
749 * reinitiliazed the global inode and
750 * block bitmap first execution check variables
752 fs
->first_pass_ibmap
= 0;
753 fs
->first_pass_bbmap
= 0;
754 fs
->curr_inode_no
= 0;
758 static int ext4fs_write_file(struct ext2_inode
*file_inode
,
759 int pos
, unsigned int len
, char *buf
)
763 unsigned int filesize
= __le32_to_cpu(file_inode
->size
);
764 struct ext_filesystem
*fs
= get_fs();
765 int log2blksz
= fs
->dev_desc
->log2blksz
;
766 int log2_fs_blocksize
= LOG2_BLOCK_SIZE(ext4fs_root
) - log2blksz
;
767 int previous_block_number
= -1;
768 int delayed_start
= 0;
769 int delayed_extent
= 0;
770 int delayed_next
= 0;
771 char *delayed_buf
= NULL
;
773 /* Adjust len so it we can't read past the end of the file. */
777 blockcnt
= ((len
+ pos
) + fs
->blksz
- 1) / fs
->blksz
;
779 for (i
= pos
/ fs
->blksz
; i
< blockcnt
; i
++) {
781 int blockend
= fs
->blksz
;
783 blknr
= read_allocated_block(file_inode
, i
);
787 blknr
= blknr
<< log2_fs_blocksize
;
790 if (previous_block_number
!= -1) {
791 if (delayed_next
== blknr
) {
792 delayed_extent
+= blockend
;
793 delayed_next
+= blockend
>> log2blksz
;
796 (delayed_start
<< log2blksz
),
798 (uint32_t) delayed_extent
);
799 previous_block_number
= blknr
;
800 delayed_start
= blknr
;
801 delayed_extent
= blockend
;
803 delayed_next
= blknr
+
804 (blockend
>> log2blksz
);
807 previous_block_number
= blknr
;
808 delayed_start
= blknr
;
809 delayed_extent
= blockend
;
811 delayed_next
= blknr
+
812 (blockend
>> log2blksz
);
815 if (previous_block_number
!= -1) {
817 put_ext4((uint64_t) (delayed_start
<<
820 (uint32_t) delayed_extent
);
821 previous_block_number
= -1;
823 memset(buf
, 0, fs
->blksz
- skipfirst
);
825 buf
+= fs
->blksz
- skipfirst
;
827 if (previous_block_number
!= -1) {
829 put_ext4((uint64_t) (delayed_start
<< log2blksz
),
830 delayed_buf
, (uint32_t) delayed_extent
);
831 previous_block_number
= -1;
837 int ext4fs_write(const char *fname
, unsigned char *buffer
,
838 unsigned long sizebytes
)
841 struct ext2_inode
*file_inode
= NULL
;
842 unsigned char *inode_buffer
= NULL
;
845 time_t timestamp
= 0;
847 uint64_t bytes_reqd_for_file
;
848 unsigned int blks_reqd_for_file
;
849 unsigned int blocks_remaining
;
850 int existing_file_inodeno
;
851 char *temp_ptr
= NULL
;
852 long int itable_blkno
;
853 long int parent_itable_blkno
;
855 struct ext2_sblock
*sblock
= &(ext4fs_root
->sblock
);
856 unsigned int inodes_per_block
;
857 unsigned int ibmap_idx
;
858 struct ext_filesystem
*fs
= get_fs();
859 ALLOC_CACHE_ALIGN_BUFFER(char, filename
, 256);
860 memset(filename
, 0x00, sizeof(filename
));
862 g_parent_inode
= zalloc(sizeof(struct ext2_inode
));
866 if (ext4fs_init() != 0) {
867 printf("error in File System init\n");
870 inodes_per_block
= fs
->blksz
/ fs
->inodesz
;
871 parent_inodeno
= ext4fs_get_parent_inode_num(fname
, filename
, F_FILE
);
872 if (parent_inodeno
== -1)
874 if (ext4fs_iget(parent_inodeno
, g_parent_inode
))
876 /* check if the filename is already present in root */
877 existing_file_inodeno
= ext4fs_filename_check(filename
);
878 if (existing_file_inodeno
!= -1) {
879 ret
= ext4fs_delete_file(existing_file_inodeno
);
880 fs
->first_pass_bbmap
= 0;
883 fs
->first_pass_ibmap
= 0;
884 fs
->curr_inode_no
= 0;
888 /* calucalate how many blocks required */
889 bytes_reqd_for_file
= sizebytes
;
890 blks_reqd_for_file
= lldiv(bytes_reqd_for_file
, fs
->blksz
);
891 if (do_div(bytes_reqd_for_file
, fs
->blksz
) != 0) {
892 blks_reqd_for_file
++;
893 debug("total bytes for a file %u\n", blks_reqd_for_file
);
895 blocks_remaining
= blks_reqd_for_file
;
896 /* test for available space in partition */
897 if (fs
->sb
->free_blocks
< blks_reqd_for_file
) {
898 printf("Not enough space on partition !!!\n");
902 ext4fs_update_parent_dentry(filename
, &inodeno
, FILETYPE_REG
);
903 /* prepare file inode */
904 inode_buffer
= zalloc(fs
->inodesz
);
907 file_inode
= (struct ext2_inode
*)inode_buffer
;
908 file_inode
->mode
= S_IFREG
| S_IRWXU
|
909 S_IRGRP
| S_IROTH
| S_IXGRP
| S_IXOTH
;
910 /* ToDo: Update correct time */
911 file_inode
->mtime
= timestamp
;
912 file_inode
->atime
= timestamp
;
913 file_inode
->ctime
= timestamp
;
914 file_inode
->nlinks
= 1;
915 file_inode
->size
= sizebytes
;
917 /* Allocate data blocks */
918 ext4fs_allocate_blocks(file_inode
, blocks_remaining
,
919 &blks_reqd_for_file
);
920 file_inode
->blockcnt
= (blks_reqd_for_file
* fs
->blksz
) >>
921 fs
->dev_desc
->log2blksz
;
923 temp_ptr
= zalloc(fs
->blksz
);
926 ibmap_idx
= inodeno
/ ext4fs_root
->sblock
.inodes_per_group
;
928 itable_blkno
= __le32_to_cpu(fs
->bgd
[ibmap_idx
].inode_table_id
) +
929 (inodeno
% __le32_to_cpu(sblock
->inodes_per_group
)) /
931 blkoff
= (inodeno
% inodes_per_block
) * fs
->inodesz
;
932 ext4fs_devread((lbaint_t
)itable_blkno
* fs
->sect_perblk
, 0, fs
->blksz
,
934 if (ext4fs_log_journal(temp_ptr
, itable_blkno
))
937 memcpy(temp_ptr
+ blkoff
, inode_buffer
, fs
->inodesz
);
938 if (ext4fs_put_metadata(temp_ptr
, itable_blkno
))
940 /* copy the file content into data blocks */
941 if (ext4fs_write_file(file_inode
, 0, sizebytes
, (char *)buffer
) == -1) {
942 printf("Error in copying content\n");
945 ibmap_idx
= parent_inodeno
/ ext4fs_root
->sblock
.inodes_per_group
;
947 parent_itable_blkno
= __le32_to_cpu(fs
->bgd
[ibmap_idx
].inode_table_id
) +
949 __le32_to_cpu(sblock
->inodes_per_group
)) / inodes_per_block
;
950 blkoff
= (parent_inodeno
% inodes_per_block
) * fs
->inodesz
;
951 if (parent_itable_blkno
!= itable_blkno
) {
952 memset(temp_ptr
, '\0', fs
->blksz
);
953 ext4fs_devread((lbaint_t
)parent_itable_blkno
* fs
->sect_perblk
,
954 0, fs
->blksz
, temp_ptr
);
955 if (ext4fs_log_journal(temp_ptr
, parent_itable_blkno
))
958 memcpy(temp_ptr
+ blkoff
, g_parent_inode
,
959 sizeof(struct ext2_inode
));
960 if (ext4fs_put_metadata(temp_ptr
, parent_itable_blkno
))
965 * If parent and child fall in same inode table block
966 * both should be kept in 1 buffer
968 memcpy(temp_ptr
+ blkoff
, g_parent_inode
,
969 sizeof(struct ext2_inode
));
971 if (ext4fs_put_metadata(temp_ptr
, itable_blkno
))
978 fs
->first_pass_bbmap
= 0;
980 fs
->first_pass_ibmap
= 0;
981 fs
->curr_inode_no
= 0;
983 free(g_parent_inode
);
984 g_parent_inode
= NULL
;
990 free(g_parent_inode
);
991 g_parent_inode
= NULL
;