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 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
38 #include <linux/stat.h>
40 #include "ext4_common.h"
42 static void ext4fs_update(void)
45 ext4fs_update_journal();
46 struct ext_filesystem
*fs
= get_fs();
48 /* update super block */
49 put_ext4((uint64_t)(SUPERBLOCK_SIZE
),
50 (struct ext2_sblock
*)fs
->sb
, (uint32_t)SUPERBLOCK_SIZE
);
52 /* update block groups */
53 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
54 fs
->bgd
[i
].bg_checksum
= ext4fs_checksum_update(i
);
55 put_ext4((uint64_t)(fs
->bgd
[i
].block_id
* fs
->blksz
),
56 fs
->blk_bmaps
[i
], fs
->blksz
);
59 /* update inode table groups */
60 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
61 put_ext4((uint64_t) (fs
->bgd
[i
].inode_id
* fs
->blksz
),
62 fs
->inode_bmaps
[i
], fs
->blksz
);
65 /* update the block group descriptor table */
66 put_ext4((uint64_t)(fs
->gdtable_blkno
* fs
->blksz
),
67 (struct ext2_block_group
*)fs
->gdtable
,
68 (fs
->blksz
* fs
->no_blk_pergdt
));
70 ext4fs_dump_metadata();
76 int ext4fs_get_bgdtable(void)
80 struct ext_filesystem
*fs
= get_fs();
81 grp_desc_size
= sizeof(struct ext2_block_group
);
82 fs
->no_blk_pergdt
= (fs
->no_blkgrp
* grp_desc_size
) / fs
->blksz
;
83 if ((fs
->no_blkgrp
* grp_desc_size
) % fs
->blksz
)
86 /* allocate memory for gdtable */
87 fs
->gdtable
= zalloc(fs
->blksz
* fs
->no_blk_pergdt
);
90 /* read the group descriptor table */
91 status
= ext4fs_devread((lbaint_t
)fs
->gdtable_blkno
* fs
->sect_perblk
,
92 0, fs
->blksz
* fs
->no_blk_pergdt
, fs
->gdtable
);
96 if (ext4fs_log_gdt(fs
->gdtable
)) {
97 printf("Error in ext4fs_log_gdt\n");
109 static void delete_single_indirect_block(struct ext2_inode
*inode
)
111 struct ext2_block_group
*bgd
= NULL
;
112 static int prev_bg_bmap_idx
= -1;
117 unsigned int blk_per_grp
= ext4fs_root
->sblock
.blocks_per_group
;
118 struct ext_filesystem
*fs
= get_fs();
119 char *journal_buffer
= zalloc(fs
->blksz
);
120 if (!journal_buffer
) {
121 printf("No memory\n");
124 /* get block group descriptor table */
125 bgd
= (struct ext2_block_group
*)fs
->gdtable
;
127 /* deleting the single indirect block associated with inode */
128 if (inode
->b
.blocks
.indir_block
!= 0) {
129 debug("SIPB releasing %u\n", inode
->b
.blocks
.indir_block
);
130 blknr
= inode
->b
.blocks
.indir_block
;
131 if (fs
->blksz
!= 1024) {
132 bg_idx
= blknr
/ blk_per_grp
;
134 bg_idx
= blknr
/ blk_per_grp
;
135 remainder
= blknr
% blk_per_grp
;
139 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
], bg_idx
);
140 bgd
[bg_idx
].free_blocks
++;
141 fs
->sb
->free_blocks
++;
143 if (prev_bg_bmap_idx
!= bg_idx
) {
145 ext4fs_devread((lbaint_t
)bgd
[bg_idx
].block_id
*
146 fs
->sect_perblk
, 0, fs
->blksz
,
150 if (ext4fs_log_journal
151 (journal_buffer
, bgd
[bg_idx
].block_id
))
153 prev_bg_bmap_idx
= bg_idx
;
157 free(journal_buffer
);
160 static void delete_double_indirect_block(struct ext2_inode
*inode
)
164 static int prev_bg_bmap_idx
= -1;
168 unsigned int blk_per_grp
= ext4fs_root
->sblock
.blocks_per_group
;
169 unsigned int *di_buffer
= NULL
;
170 unsigned int *DIB_start_addr
= NULL
;
171 struct ext2_block_group
*bgd
= NULL
;
172 struct ext_filesystem
*fs
= get_fs();
173 char *journal_buffer
= zalloc(fs
->blksz
);
174 if (!journal_buffer
) {
175 printf("No memory\n");
178 /* get the block group descriptor table */
179 bgd
= (struct ext2_block_group
*)fs
->gdtable
;
181 if (inode
->b
.blocks
.double_indir_block
!= 0) {
182 di_buffer
= zalloc(fs
->blksz
);
184 printf("No memory\n");
187 DIB_start_addr
= (unsigned int *)di_buffer
;
188 blknr
= inode
->b
.blocks
.double_indir_block
;
189 status
= ext4fs_devread((lbaint_t
)blknr
* fs
->sect_perblk
, 0,
190 fs
->blksz
, (char *)di_buffer
);
191 for (i
= 0; i
< fs
->blksz
/ sizeof(int); i
++) {
195 debug("DICB releasing %u\n", *di_buffer
);
196 if (fs
->blksz
!= 1024) {
197 bg_idx
= (*di_buffer
) / blk_per_grp
;
199 bg_idx
= (*di_buffer
) / blk_per_grp
;
200 remainder
= (*di_buffer
) % blk_per_grp
;
204 ext4fs_reset_block_bmap(*di_buffer
,
205 fs
->blk_bmaps
[bg_idx
], bg_idx
);
207 bgd
[bg_idx
].free_blocks
++;
208 fs
->sb
->free_blocks
++;
210 if (prev_bg_bmap_idx
!= bg_idx
) {
211 status
= ext4fs_devread((lbaint_t
)
213 * fs
->sect_perblk
, 0,
219 if (ext4fs_log_journal(journal_buffer
,
220 bgd
[bg_idx
].block_id
))
222 prev_bg_bmap_idx
= bg_idx
;
226 /* removing the parent double indirect block */
227 blknr
= inode
->b
.blocks
.double_indir_block
;
228 if (fs
->blksz
!= 1024) {
229 bg_idx
= blknr
/ blk_per_grp
;
231 bg_idx
= blknr
/ blk_per_grp
;
232 remainder
= blknr
% blk_per_grp
;
236 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
], bg_idx
);
237 bgd
[bg_idx
].free_blocks
++;
238 fs
->sb
->free_blocks
++;
240 if (prev_bg_bmap_idx
!= bg_idx
) {
241 memset(journal_buffer
, '\0', fs
->blksz
);
242 status
= ext4fs_devread((lbaint_t
)bgd
[bg_idx
].block_id
*
243 fs
->sect_perblk
, 0, fs
->blksz
,
248 if (ext4fs_log_journal(journal_buffer
,
249 bgd
[bg_idx
].block_id
))
251 prev_bg_bmap_idx
= bg_idx
;
253 debug("DIPB releasing %ld\n", blknr
);
256 free(DIB_start_addr
);
257 free(journal_buffer
);
260 static void delete_triple_indirect_block(struct ext2_inode
*inode
)
264 static int prev_bg_bmap_idx
= -1;
268 unsigned int blk_per_grp
= ext4fs_root
->sblock
.blocks_per_group
;
269 unsigned int *tigp_buffer
= NULL
;
270 unsigned int *tib_start_addr
= NULL
;
271 unsigned int *tip_buffer
= NULL
;
272 unsigned int *tipb_start_addr
= NULL
;
273 struct ext2_block_group
*bgd
= NULL
;
274 struct ext_filesystem
*fs
= get_fs();
275 char *journal_buffer
= zalloc(fs
->blksz
);
276 if (!journal_buffer
) {
277 printf("No memory\n");
280 /* get block group descriptor table */
281 bgd
= (struct ext2_block_group
*)fs
->gdtable
;
283 if (inode
->b
.blocks
.triple_indir_block
!= 0) {
284 tigp_buffer
= zalloc(fs
->blksz
);
286 printf("No memory\n");
289 tib_start_addr
= (unsigned int *)tigp_buffer
;
290 blknr
= inode
->b
.blocks
.triple_indir_block
;
291 status
= ext4fs_devread((lbaint_t
)blknr
* fs
->sect_perblk
, 0,
292 fs
->blksz
, (char *)tigp_buffer
);
293 for (i
= 0; i
< fs
->blksz
/ sizeof(int); i
++) {
294 if (*tigp_buffer
== 0)
296 debug("tigp buffer releasing %u\n", *tigp_buffer
);
298 tip_buffer
= zalloc(fs
->blksz
);
301 tipb_start_addr
= (unsigned int *)tip_buffer
;
302 status
= ext4fs_devread((lbaint_t
)(*tigp_buffer
) *
303 fs
->sect_perblk
, 0, fs
->blksz
,
305 for (j
= 0; j
< fs
->blksz
/ sizeof(int); j
++) {
306 if (*tip_buffer
== 0)
308 if (fs
->blksz
!= 1024) {
309 bg_idx
= (*tip_buffer
) / blk_per_grp
;
311 bg_idx
= (*tip_buffer
) / blk_per_grp
;
313 remainder
= (*tip_buffer
) % blk_per_grp
;
318 ext4fs_reset_block_bmap(*tip_buffer
,
319 fs
->blk_bmaps
[bg_idx
],
323 bgd
[bg_idx
].free_blocks
++;
324 fs
->sb
->free_blocks
++;
326 if (prev_bg_bmap_idx
!= bg_idx
) {
330 bgd
[bg_idx
].block_id
*
337 if (ext4fs_log_journal(journal_buffer
,
341 prev_bg_bmap_idx
= bg_idx
;
344 free(tipb_start_addr
);
345 tipb_start_addr
= NULL
;
348 * removing the grand parent blocks
349 * which is connected to inode
351 if (fs
->blksz
!= 1024) {
352 bg_idx
= (*tigp_buffer
) / blk_per_grp
;
354 bg_idx
= (*tigp_buffer
) / blk_per_grp
;
356 remainder
= (*tigp_buffer
) % blk_per_grp
;
360 ext4fs_reset_block_bmap(*tigp_buffer
,
361 fs
->blk_bmaps
[bg_idx
], bg_idx
);
364 bgd
[bg_idx
].free_blocks
++;
365 fs
->sb
->free_blocks
++;
367 if (prev_bg_bmap_idx
!= bg_idx
) {
368 memset(journal_buffer
, '\0', fs
->blksz
);
370 ext4fs_devread((lbaint_t
)
371 bgd
[bg_idx
].block_id
*
373 fs
->blksz
, journal_buffer
);
377 if (ext4fs_log_journal(journal_buffer
,
378 bgd
[bg_idx
].block_id
))
380 prev_bg_bmap_idx
= bg_idx
;
384 /* removing the grand parent triple indirect block */
385 blknr
= inode
->b
.blocks
.triple_indir_block
;
386 if (fs
->blksz
!= 1024) {
387 bg_idx
= blknr
/ blk_per_grp
;
389 bg_idx
= blknr
/ blk_per_grp
;
390 remainder
= blknr
% blk_per_grp
;
394 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
], bg_idx
);
395 bgd
[bg_idx
].free_blocks
++;
396 fs
->sb
->free_blocks
++;
398 if (prev_bg_bmap_idx
!= bg_idx
) {
399 memset(journal_buffer
, '\0', fs
->blksz
);
400 status
= ext4fs_devread((lbaint_t
)bgd
[bg_idx
].block_id
*
401 fs
->sect_perblk
, 0, fs
->blksz
,
406 if (ext4fs_log_journal(journal_buffer
,
407 bgd
[bg_idx
].block_id
))
409 prev_bg_bmap_idx
= bg_idx
;
411 debug("tigp buffer itself releasing %ld\n", blknr
);
414 free(tib_start_addr
);
415 free(tipb_start_addr
);
416 free(journal_buffer
);
419 static int ext4fs_delete_file(int inodeno
)
421 struct ext2_inode inode
;
428 char *read_buffer
= NULL
;
429 char *start_block_address
= NULL
;
430 unsigned int no_blocks
;
432 static int prev_bg_bmap_idx
= -1;
433 unsigned int inodes_per_block
;
436 unsigned int blk_per_grp
= ext4fs_root
->sblock
.blocks_per_group
;
437 unsigned int inode_per_grp
= ext4fs_root
->sblock
.inodes_per_group
;
438 struct ext2_inode
*inode_buffer
= NULL
;
439 struct ext2_block_group
*bgd
= NULL
;
440 struct ext_filesystem
*fs
= get_fs();
441 char *journal_buffer
= zalloc(fs
->blksz
);
444 /* get the block group descriptor table */
445 bgd
= (struct ext2_block_group
*)fs
->gdtable
;
446 status
= ext4fs_read_inode(ext4fs_root
, inodeno
, &inode
);
450 /* read the block no allocated to a file */
451 no_blocks
= inode
.size
/ fs
->blksz
;
452 if (inode
.size
% fs
->blksz
)
455 if (le32_to_cpu(inode
.flags
) & EXT4_EXTENTS_FL
) {
456 struct ext2fs_node
*node_inode
=
457 zalloc(sizeof(struct ext2fs_node
));
460 node_inode
->data
= ext4fs_root
;
461 node_inode
->ino
= inodeno
;
462 node_inode
->inode_read
= 0;
463 memcpy(&(node_inode
->inode
), &inode
, sizeof(struct ext2_inode
));
465 for (i
= 0; i
< no_blocks
; i
++) {
466 blknr
= read_allocated_block(&(node_inode
->inode
), i
);
467 if (fs
->blksz
!= 1024) {
468 bg_idx
= blknr
/ blk_per_grp
;
470 bg_idx
= blknr
/ blk_per_grp
;
471 remainder
= blknr
% blk_per_grp
;
475 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
],
477 debug("EXT4_EXTENTS Block releasing %ld: %d\n",
480 bgd
[bg_idx
].free_blocks
++;
481 fs
->sb
->free_blocks
++;
484 if (prev_bg_bmap_idx
!= bg_idx
) {
486 ext4fs_devread((lbaint_t
)
487 bgd
[bg_idx
].block_id
*
489 fs
->blksz
, journal_buffer
);
492 if (ext4fs_log_journal(journal_buffer
,
493 bgd
[bg_idx
].block_id
))
495 prev_bg_bmap_idx
= bg_idx
;
504 delete_single_indirect_block(&inode
);
505 delete_double_indirect_block(&inode
);
506 delete_triple_indirect_block(&inode
);
508 /* read the block no allocated to a file */
509 no_blocks
= inode
.size
/ fs
->blksz
;
510 if (inode
.size
% fs
->blksz
)
512 for (i
= 0; i
< no_blocks
; i
++) {
513 blknr
= read_allocated_block(&inode
, i
);
514 if (fs
->blksz
!= 1024) {
515 bg_idx
= blknr
/ blk_per_grp
;
517 bg_idx
= blknr
/ blk_per_grp
;
518 remainder
= blknr
% blk_per_grp
;
522 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
],
524 debug("ActualB releasing %ld: %d\n", blknr
, bg_idx
);
526 bgd
[bg_idx
].free_blocks
++;
527 fs
->sb
->free_blocks
++;
529 if (prev_bg_bmap_idx
!= bg_idx
) {
530 memset(journal_buffer
, '\0', fs
->blksz
);
531 status
= ext4fs_devread((lbaint_t
)
538 if (ext4fs_log_journal(journal_buffer
,
539 bgd
[bg_idx
].block_id
))
541 prev_bg_bmap_idx
= bg_idx
;
546 /* from the inode no to blockno */
547 inodes_per_block
= fs
->blksz
/ fs
->inodesz
;
548 ibmap_idx
= inodeno
/ inode_per_grp
;
550 /* get the block no */
552 blkno
= __le32_to_cpu(bgd
[ibmap_idx
].inode_table_id
) +
553 (inodeno
% __le32_to_cpu(inode_per_grp
)) / inodes_per_block
;
555 /* get the offset of the inode */
556 blkoff
= ((inodeno
) % inodes_per_block
) * fs
->inodesz
;
558 /* read the block no containing the inode */
559 read_buffer
= zalloc(fs
->blksz
);
562 start_block_address
= read_buffer
;
563 status
= ext4fs_devread((lbaint_t
)blkno
* fs
->sect_perblk
,
564 0, fs
->blksz
, read_buffer
);
568 if (ext4fs_log_journal(read_buffer
, blkno
))
571 read_buffer
= read_buffer
+ blkoff
;
572 inode_buffer
= (struct ext2_inode
*)read_buffer
;
573 memset(inode_buffer
, '\0', sizeof(struct ext2_inode
));
575 /* write the inode to original position in inode table */
576 if (ext4fs_put_metadata(start_block_address
, blkno
))
579 /* update the respective inode bitmaps */
581 ext4fs_reset_inode_bmap(inodeno
, fs
->inode_bmaps
[ibmap_idx
], ibmap_idx
);
582 bgd
[ibmap_idx
].free_inodes
++;
583 fs
->sb
->free_inodes
++;
585 memset(journal_buffer
, '\0', fs
->blksz
);
586 status
= ext4fs_devread((lbaint_t
)bgd
[ibmap_idx
].inode_id
*
587 fs
->sect_perblk
, 0, fs
->blksz
, journal_buffer
);
590 if (ext4fs_log_journal(journal_buffer
, bgd
[ibmap_idx
].inode_id
))
596 if (ext4fs_init() != 0) {
597 printf("error in File System init\n");
601 free(start_block_address
);
602 free(journal_buffer
);
606 free(start_block_address
);
607 free(journal_buffer
);
612 int ext4fs_init(void)
616 unsigned int real_free_blocks
= 0;
617 struct ext_filesystem
*fs
= get_fs();
620 fs
->blksz
= EXT2_BLOCK_SIZE(ext4fs_root
);
621 fs
->inodesz
= INODE_SIZE_FILESYSTEM(ext4fs_root
);
622 fs
->sect_perblk
= fs
->blksz
>> fs
->dev_desc
->log2blksz
;
624 /* get the superblock */
625 fs
->sb
= zalloc(SUPERBLOCK_SIZE
);
628 if (!ext4_read_superblock((char *)fs
->sb
))
632 if (ext4fs_init_journal())
635 /* get total no of blockgroups */
636 fs
->no_blkgrp
= (uint32_t)ext4fs_div_roundup(
637 (ext4fs_root
->sblock
.total_blocks
-
638 ext4fs_root
->sblock
.first_data_block
),
639 ext4fs_root
->sblock
.blocks_per_group
);
641 /* get the block group descriptor table */
642 fs
->gdtable_blkno
= ((EXT2_MIN_BLOCK_SIZE
== fs
->blksz
) + 1);
643 if (ext4fs_get_bgdtable() == -1) {
644 printf("Error in getting the block group descriptor table\n");
647 fs
->bgd
= (struct ext2_block_group
*)fs
->gdtable
;
649 /* load all the available bitmap block of the partition */
650 fs
->blk_bmaps
= zalloc(fs
->no_blkgrp
* sizeof(char *));
653 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
654 fs
->blk_bmaps
[i
] = zalloc(fs
->blksz
);
655 if (!fs
->blk_bmaps
[i
])
659 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
661 ext4fs_devread((lbaint_t
)fs
->bgd
[i
].block_id
*
663 fs
->blksz
, (char *)fs
->blk_bmaps
[i
]);
668 /* load all the available inode bitmap of the partition */
669 fs
->inode_bmaps
= zalloc(fs
->no_blkgrp
* sizeof(unsigned char *));
670 if (!fs
->inode_bmaps
)
672 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
673 fs
->inode_bmaps
[i
] = zalloc(fs
->blksz
);
674 if (!fs
->inode_bmaps
[i
])
678 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
679 status
= ext4fs_devread((lbaint_t
)fs
->bgd
[i
].inode_id
*
682 (char *)fs
->inode_bmaps
[i
]);
688 * check filesystem consistency with free blocks of file system
689 * some time we observed that superblock freeblocks does not match
690 * with the blockgroups freeblocks when improper
691 * reboot of a linux kernel
693 for (i
= 0; i
< fs
->no_blkgrp
; i
++)
694 real_free_blocks
= real_free_blocks
+ fs
->bgd
[i
].free_blocks
;
695 if (real_free_blocks
!= fs
->sb
->free_blocks
)
696 fs
->sb
->free_blocks
= real_free_blocks
;
705 void ext4fs_deinit(void)
708 struct ext2_inode inode_journal
;
709 struct journal_superblock_t
*jsb
;
711 struct ext_filesystem
*fs
= get_fs();
714 char *temp_buff
= zalloc(fs
->blksz
);
716 ext4fs_read_inode(ext4fs_root
, EXT2_JOURNAL_INO
,
718 blknr
= read_allocated_block(&inode_journal
,
719 EXT2_JOURNAL_SUPERBLOCK
);
720 ext4fs_devread((lbaint_t
)blknr
* fs
->sect_perblk
, 0, fs
->blksz
,
722 jsb
= (struct journal_superblock_t
*)temp_buff
;
723 jsb
->s_start
= cpu_to_be32(0);
724 put_ext4((uint64_t) (blknr
* fs
->blksz
),
725 (struct journal_superblock_t
*)temp_buff
, fs
->blksz
);
728 ext4fs_free_journal();
730 /* get the superblock */
731 ext4_read_superblock((char *)fs
->sb
);
732 fs
->sb
->feature_incompat
&= ~EXT3_FEATURE_INCOMPAT_RECOVER
;
733 put_ext4((uint64_t)(SUPERBLOCK_SIZE
),
734 (struct ext2_sblock
*)fs
->sb
, (uint32_t)SUPERBLOCK_SIZE
);
739 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
740 free(fs
->blk_bmaps
[i
]);
741 fs
->blk_bmaps
[i
] = NULL
;
744 fs
->blk_bmaps
= NULL
;
747 if (fs
->inode_bmaps
) {
748 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
749 free(fs
->inode_bmaps
[i
]);
750 fs
->inode_bmaps
[i
] = NULL
;
752 free(fs
->inode_bmaps
);
753 fs
->inode_bmaps
= NULL
;
761 * reinitiliazed the global inode and
762 * block bitmap first execution check variables
764 fs
->first_pass_ibmap
= 0;
765 fs
->first_pass_bbmap
= 0;
766 fs
->curr_inode_no
= 0;
770 static int ext4fs_write_file(struct ext2_inode
*file_inode
,
771 int pos
, unsigned int len
, char *buf
)
775 unsigned int filesize
= __le32_to_cpu(file_inode
->size
);
776 struct ext_filesystem
*fs
= get_fs();
777 int log2blksz
= fs
->dev_desc
->log2blksz
;
778 int log2_fs_blocksize
= LOG2_BLOCK_SIZE(ext4fs_root
) - log2blksz
;
779 int previous_block_number
= -1;
780 int delayed_start
= 0;
781 int delayed_extent
= 0;
782 int delayed_next
= 0;
783 char *delayed_buf
= NULL
;
785 /* Adjust len so it we can't read past the end of the file. */
789 blockcnt
= ((len
+ pos
) + fs
->blksz
- 1) / fs
->blksz
;
791 for (i
= pos
/ fs
->blksz
; i
< blockcnt
; i
++) {
793 int blockend
= fs
->blksz
;
795 blknr
= read_allocated_block(file_inode
, i
);
799 blknr
= blknr
<< log2_fs_blocksize
;
802 if (previous_block_number
!= -1) {
803 if (delayed_next
== blknr
) {
804 delayed_extent
+= blockend
;
805 delayed_next
+= blockend
>> log2blksz
;
808 (delayed_start
<< log2blksz
),
810 (uint32_t) delayed_extent
);
811 previous_block_number
= blknr
;
812 delayed_start
= blknr
;
813 delayed_extent
= blockend
;
815 delayed_next
= blknr
+
816 (blockend
>> log2blksz
);
819 previous_block_number
= blknr
;
820 delayed_start
= blknr
;
821 delayed_extent
= blockend
;
823 delayed_next
= blknr
+
824 (blockend
>> log2blksz
);
827 if (previous_block_number
!= -1) {
829 put_ext4((uint64_t) (delayed_start
<<
832 (uint32_t) delayed_extent
);
833 previous_block_number
= -1;
835 memset(buf
, 0, fs
->blksz
- skipfirst
);
837 buf
+= fs
->blksz
- skipfirst
;
839 if (previous_block_number
!= -1) {
841 put_ext4((uint64_t) (delayed_start
<< log2blksz
),
842 delayed_buf
, (uint32_t) delayed_extent
);
843 previous_block_number
= -1;
849 int ext4fs_write(const char *fname
, unsigned char *buffer
,
850 unsigned long sizebytes
)
853 struct ext2_inode
*file_inode
= NULL
;
854 unsigned char *inode_buffer
= NULL
;
857 time_t timestamp
= 0;
859 uint64_t bytes_reqd_for_file
;
860 unsigned int blks_reqd_for_file
;
861 unsigned int blocks_remaining
;
862 int existing_file_inodeno
;
863 char *temp_ptr
= NULL
;
864 long int itable_blkno
;
865 long int parent_itable_blkno
;
867 struct ext2_sblock
*sblock
= &(ext4fs_root
->sblock
);
868 unsigned int inodes_per_block
;
869 unsigned int ibmap_idx
;
870 struct ext_filesystem
*fs
= get_fs();
871 ALLOC_CACHE_ALIGN_BUFFER(char, filename
, 256);
872 memset(filename
, 0x00, sizeof(filename
));
874 g_parent_inode
= zalloc(sizeof(struct ext2_inode
));
878 if (ext4fs_init() != 0) {
879 printf("error in File System init\n");
882 inodes_per_block
= fs
->blksz
/ fs
->inodesz
;
883 parent_inodeno
= ext4fs_get_parent_inode_num(fname
, filename
, F_FILE
);
884 if (parent_inodeno
== -1)
886 if (ext4fs_iget(parent_inodeno
, g_parent_inode
))
888 /* check if the filename is already present in root */
889 existing_file_inodeno
= ext4fs_filename_check(filename
);
890 if (existing_file_inodeno
!= -1) {
891 ret
= ext4fs_delete_file(existing_file_inodeno
);
892 fs
->first_pass_bbmap
= 0;
895 fs
->first_pass_ibmap
= 0;
896 fs
->curr_inode_no
= 0;
900 /* calucalate how many blocks required */
901 bytes_reqd_for_file
= sizebytes
;
902 blks_reqd_for_file
= lldiv(bytes_reqd_for_file
, fs
->blksz
);
903 if (do_div(bytes_reqd_for_file
, fs
->blksz
) != 0) {
904 blks_reqd_for_file
++;
905 debug("total bytes for a file %u\n", blks_reqd_for_file
);
907 blocks_remaining
= blks_reqd_for_file
;
908 /* test for available space in partition */
909 if (fs
->sb
->free_blocks
< blks_reqd_for_file
) {
910 printf("Not enough space on partition !!!\n");
914 ext4fs_update_parent_dentry(filename
, &inodeno
, FILETYPE_REG
);
915 /* prepare file inode */
916 inode_buffer
= zalloc(fs
->inodesz
);
919 file_inode
= (struct ext2_inode
*)inode_buffer
;
920 file_inode
->mode
= S_IFREG
| S_IRWXU
|
921 S_IRGRP
| S_IROTH
| S_IXGRP
| S_IXOTH
;
922 /* ToDo: Update correct time */
923 file_inode
->mtime
= timestamp
;
924 file_inode
->atime
= timestamp
;
925 file_inode
->ctime
= timestamp
;
926 file_inode
->nlinks
= 1;
927 file_inode
->size
= sizebytes
;
929 /* Allocate data blocks */
930 ext4fs_allocate_blocks(file_inode
, blocks_remaining
,
931 &blks_reqd_for_file
);
932 file_inode
->blockcnt
= (blks_reqd_for_file
* fs
->blksz
) >>
933 fs
->dev_desc
->log2blksz
;
935 temp_ptr
= zalloc(fs
->blksz
);
938 ibmap_idx
= inodeno
/ ext4fs_root
->sblock
.inodes_per_group
;
940 itable_blkno
= __le32_to_cpu(fs
->bgd
[ibmap_idx
].inode_table_id
) +
941 (inodeno
% __le32_to_cpu(sblock
->inodes_per_group
)) /
943 blkoff
= (inodeno
% inodes_per_block
) * fs
->inodesz
;
944 ext4fs_devread((lbaint_t
)itable_blkno
* fs
->sect_perblk
, 0, fs
->blksz
,
946 if (ext4fs_log_journal(temp_ptr
, itable_blkno
))
949 memcpy(temp_ptr
+ blkoff
, inode_buffer
, fs
->inodesz
);
950 if (ext4fs_put_metadata(temp_ptr
, itable_blkno
))
952 /* copy the file content into data blocks */
953 if (ext4fs_write_file(file_inode
, 0, sizebytes
, (char *)buffer
) == -1) {
954 printf("Error in copying content\n");
957 ibmap_idx
= parent_inodeno
/ ext4fs_root
->sblock
.inodes_per_group
;
959 parent_itable_blkno
= __le32_to_cpu(fs
->bgd
[ibmap_idx
].inode_table_id
) +
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
,
971 sizeof(struct ext2_inode
));
972 if (ext4fs_put_metadata(temp_ptr
, parent_itable_blkno
))
977 * If parent and child fall in same inode table block
978 * both should be kept in 1 buffer
980 memcpy(temp_ptr
+ blkoff
, g_parent_inode
,
981 sizeof(struct ext2_inode
));
983 if (ext4fs_put_metadata(temp_ptr
, itable_blkno
))
990 fs
->first_pass_bbmap
= 0;
992 fs
->first_pass_ibmap
= 0;
993 fs
->curr_inode_no
= 0;
995 free(g_parent_inode
);
996 g_parent_inode
= NULL
;
1002 free(g_parent_inode
);
1003 g_parent_inode
= NULL
;