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 load support in Uboot.
10 * esd gmbh <www.esd-electronics.com>
11 * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
13 * based on code from grub2 fs/ext2.c and fs/fshelp.c by
14 * GRUB -- GRand Unified Bootloader
15 * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
17 * ext4write : Based on generic ext4 protocol.
19 * SPDX-License-Identifier: GPL-2.0+
23 #include <ext_common.h>
27 #include <linux/stat.h>
28 #include <linux/time.h>
29 #include <asm/byteorder.h>
30 #include "ext4_common.h"
32 struct ext2_data
*ext4fs_root
;
33 struct ext2fs_node
*ext4fs_file
;
34 uint32_t *ext4fs_indir1_block
;
35 int ext4fs_indir1_size
;
36 int ext4fs_indir1_blkno
= -1;
37 uint32_t *ext4fs_indir2_block
;
38 int ext4fs_indir2_size
;
39 int ext4fs_indir2_blkno
= -1;
41 uint32_t *ext4fs_indir3_block
;
42 int ext4fs_indir3_size
;
43 int ext4fs_indir3_blkno
= -1;
44 struct ext2_inode
*g_parent_inode
;
45 static int symlinknest
;
47 #if defined(CONFIG_EXT4_WRITE)
48 uint32_t ext4fs_div_roundup(uint32_t size
, uint32_t n
)
50 uint32_t res
= size
/ n
;
57 void put_ext4(uint64_t off
, void *buf
, uint32_t size
)
61 unsigned char *temp_ptr
= NULL
;
62 struct ext_filesystem
*fs
= get_fs();
63 int log2blksz
= fs
->dev_desc
->log2blksz
;
64 ALLOC_CACHE_ALIGN_BUFFER(unsigned char, sec_buf
, fs
->dev_desc
->blksz
);
66 startblock
= off
>> log2blksz
;
67 startblock
+= part_offset
;
68 remainder
= off
& (uint64_t)(fs
->dev_desc
->blksz
- 1);
70 if (fs
->dev_desc
== NULL
)
73 if ((startblock
+ (size
>> log2blksz
)) >
74 (part_offset
+ fs
->total_sect
)) {
75 printf("part_offset is " LBAFU
"\n", part_offset
);
76 printf("total_sector is %llu\n", fs
->total_sect
);
77 printf("error: overflow occurs\n");
82 if (fs
->dev_desc
->block_read
) {
83 fs
->dev_desc
->block_read(fs
->dev_desc
->dev
,
84 startblock
, 1, sec_buf
);
86 memcpy((temp_ptr
+ remainder
),
87 (unsigned char *)buf
, size
);
88 fs
->dev_desc
->block_write(fs
->dev_desc
->dev
,
89 startblock
, 1, sec_buf
);
92 if (size
>> log2blksz
!= 0) {
93 fs
->dev_desc
->block_write(fs
->dev_desc
->dev
,
96 (unsigned long *)buf
);
98 fs
->dev_desc
->block_read(fs
->dev_desc
->dev
,
99 startblock
, 1, sec_buf
);
101 memcpy(temp_ptr
, buf
, size
);
102 fs
->dev_desc
->block_write(fs
->dev_desc
->dev
,
104 (unsigned long *)sec_buf
);
109 static int _get_new_inode_no(unsigned char *buffer
)
111 struct ext_filesystem
*fs
= get_fs();
117 /* get the blocksize of the filesystem */
118 unsigned char *ptr
= buffer
;
119 while (*ptr
== 255) {
122 if (count
> ext4fs_root
->sblock
.inodes_per_group
)
126 for (j
= 0; j
< fs
->blksz
; j
++) {
131 status
= input
& operand
;
146 static int _get_new_blk_no(unsigned char *buffer
)
152 unsigned char *ptr
= buffer
;
153 struct ext_filesystem
*fs
= get_fs();
155 if (fs
->blksz
!= 1024)
160 while (*ptr
== 255) {
163 if (count
== (fs
->blksz
* 8))
167 for (j
= 0; j
< fs
->blksz
; j
++) {
172 status
= input
& operand
;
187 int ext4fs_set_block_bmap(long int blockno
, unsigned char *buffer
, int index
)
189 int i
, remainder
, status
;
190 unsigned char *ptr
= buffer
;
191 unsigned char operand
;
193 remainder
= blockno
% 8;
194 int blocksize
= EXT2_BLOCK_SIZE(ext4fs_root
);
196 i
= i
- (index
* blocksize
);
197 if (blocksize
!= 1024) {
199 operand
= 1 << remainder
;
200 status
= *ptr
& operand
;
204 *ptr
= *ptr
| operand
;
207 if (remainder
== 0) {
212 operand
= (1 << (remainder
- 1));
214 status
= *ptr
& operand
;
218 *ptr
= *ptr
| operand
;
223 void ext4fs_reset_block_bmap(long int blockno
, unsigned char *buffer
, int index
)
225 int i
, remainder
, status
;
226 unsigned char *ptr
= buffer
;
227 unsigned char operand
;
229 remainder
= blockno
% 8;
230 int blocksize
= EXT2_BLOCK_SIZE(ext4fs_root
);
232 i
= i
- (index
* blocksize
);
233 if (blocksize
!= 1024) {
235 operand
= (1 << remainder
);
236 status
= *ptr
& operand
;
238 *ptr
= *ptr
& ~(operand
);
240 if (remainder
== 0) {
245 operand
= (1 << (remainder
- 1));
247 status
= *ptr
& operand
;
249 *ptr
= *ptr
& ~(operand
);
253 int ext4fs_set_inode_bmap(int inode_no
, unsigned char *buffer
, int index
)
255 int i
, remainder
, status
;
256 unsigned char *ptr
= buffer
;
257 unsigned char operand
;
259 inode_no
-= (index
* ext4fs_root
->sblock
.inodes_per_group
);
261 remainder
= inode_no
% 8;
262 if (remainder
== 0) {
267 operand
= (1 << (remainder
- 1));
269 status
= *ptr
& operand
;
273 *ptr
= *ptr
| operand
;
278 void ext4fs_reset_inode_bmap(int inode_no
, unsigned char *buffer
, int index
)
280 int i
, remainder
, status
;
281 unsigned char *ptr
= buffer
;
282 unsigned char operand
;
284 inode_no
-= (index
* ext4fs_root
->sblock
.inodes_per_group
);
286 remainder
= inode_no
% 8;
287 if (remainder
== 0) {
292 operand
= (1 << (remainder
- 1));
294 status
= *ptr
& operand
;
296 *ptr
= *ptr
& ~(operand
);
299 int ext4fs_checksum_update(unsigned int i
)
301 struct ext2_block_group
*desc
;
302 struct ext_filesystem
*fs
= get_fs();
305 desc
= (struct ext2_block_group
*)&fs
->bgd
[i
];
306 if (fs
->sb
->feature_ro_compat
& EXT4_FEATURE_RO_COMPAT_GDT_CSUM
) {
307 int offset
= offsetof(struct ext2_block_group
, bg_checksum
);
309 crc
= ext2fs_crc16(~0, fs
->sb
->unique_id
,
310 sizeof(fs
->sb
->unique_id
));
311 crc
= ext2fs_crc16(crc
, &i
, sizeof(i
));
312 crc
= ext2fs_crc16(crc
, desc
, offset
);
313 offset
+= sizeof(desc
->bg_checksum
); /* skip checksum */
314 assert(offset
== sizeof(*desc
));
320 static int check_void_in_dentry(struct ext2_dirent
*dir
, char *filename
)
323 int sizeof_void_space
;
324 int new_entry_byte_reqd
;
325 short padding_factor
= 0;
327 if (dir
->namelen
% 4 != 0)
328 padding_factor
= 4 - (dir
->namelen
% 4);
330 dentry_length
= sizeof(struct ext2_dirent
) +
331 dir
->namelen
+ padding_factor
;
332 sizeof_void_space
= dir
->direntlen
- dentry_length
;
333 if (sizeof_void_space
== 0)
337 if (strlen(filename
) % 4 != 0)
338 padding_factor
= 4 - (strlen(filename
) % 4);
340 new_entry_byte_reqd
= strlen(filename
) +
341 sizeof(struct ext2_dirent
) + padding_factor
;
342 if (sizeof_void_space
>= new_entry_byte_reqd
) {
343 dir
->direntlen
= dentry_length
;
344 return sizeof_void_space
;
350 void ext4fs_update_parent_dentry(char *filename
, int *p_ino
, int file_type
)
352 unsigned int *zero_buffer
= NULL
;
353 char *root_first_block_buffer
= NULL
;
356 long int first_block_no_of_root
= 0;
357 long int previous_blknr
= -1;
359 short int padding_factor
= 0;
360 unsigned int new_entry_byte_reqd
;
361 unsigned int last_entry_dirlen
;
362 int sizeof_void_space
= 0;
366 struct ext_filesystem
*fs
= get_fs();
367 /* directory entry */
368 struct ext2_dirent
*dir
;
369 char *temp_dir
= NULL
;
371 zero_buffer
= zalloc(fs
->blksz
);
373 printf("No Memory\n");
376 root_first_block_buffer
= zalloc(fs
->blksz
);
377 if (!root_first_block_buffer
) {
379 printf("No Memory\n");
384 /* read the block no allocated to a file */
385 for (direct_blk_idx
= 0; direct_blk_idx
< INDIRECT_BLOCKS
;
387 root_blknr
= read_allocated_block(g_parent_inode
,
389 if (root_blknr
== 0) {
390 first_block_no_of_root
= previous_blknr
;
393 previous_blknr
= root_blknr
;
396 status
= ext4fs_devread((lbaint_t
)first_block_no_of_root
398 0, fs
->blksz
, root_first_block_buffer
);
402 if (ext4fs_log_journal(root_first_block_buffer
, first_block_no_of_root
))
404 dir
= (struct ext2_dirent
*)root_first_block_buffer
;
406 while (dir
->direntlen
> 0) {
408 * blocksize-totalbytes because last directory length
409 * i.e. dir->direntlen is free availble space in the
410 * block that means it is a last entry of directory
414 /* traversing the each directory entry */
415 if (fs
->blksz
- totalbytes
== dir
->direntlen
) {
416 if (strlen(filename
) % 4 != 0)
417 padding_factor
= 4 - (strlen(filename
) % 4);
419 new_entry_byte_reqd
= strlen(filename
) +
420 sizeof(struct ext2_dirent
) + padding_factor
;
423 * update last directory entry length to its
424 * length because we are creating new directory
427 if (dir
->namelen
% 4 != 0)
428 padding_factor
= 4 - (dir
->namelen
% 4);
430 last_entry_dirlen
= dir
->namelen
+
431 sizeof(struct ext2_dirent
) + padding_factor
;
432 if ((fs
->blksz
- totalbytes
- last_entry_dirlen
) <
433 new_entry_byte_reqd
) {
434 printf("1st Block Full:Allocate new block\n");
436 if (direct_blk_idx
== INDIRECT_BLOCKS
- 1) {
437 printf("Directory exceeds limit\n");
440 g_parent_inode
->b
.blocks
.dir_blocks
441 [direct_blk_idx
] = ext4fs_get_new_blk_no();
442 if (g_parent_inode
->b
.blocks
.dir_blocks
443 [direct_blk_idx
] == -1) {
444 printf("no block left to assign\n");
448 ((uint64_t)g_parent_inode
->b
.
449 blocks
.dir_blocks
[direct_blk_idx
] *
450 (uint64_t)fs
->blksz
)), zero_buffer
, fs
->blksz
);
451 g_parent_inode
->size
=
452 g_parent_inode
->size
+ fs
->blksz
;
453 g_parent_inode
->blockcnt
=
454 g_parent_inode
->blockcnt
+ fs
->sect_perblk
;
455 if (ext4fs_put_metadata
456 (root_first_block_buffer
,
457 first_block_no_of_root
))
461 dir
->direntlen
= last_entry_dirlen
;
465 templength
= dir
->direntlen
;
466 totalbytes
= totalbytes
+ templength
;
467 sizeof_void_space
= check_void_in_dentry(dir
, filename
);
468 if (sizeof_void_space
)
471 dir
= (struct ext2_dirent
*)((char *)dir
+ templength
);
474 /* make a pointer ready for creating next directory entry */
475 templength
= dir
->direntlen
;
476 totalbytes
= totalbytes
+ templength
;
477 dir
= (struct ext2_dirent
*)((char *)dir
+ templength
);
479 /* get the next available inode number */
480 inodeno
= ext4fs_get_new_inode_no();
482 printf("no inode left to assign\n");
485 dir
->inode
= inodeno
;
486 if (sizeof_void_space
)
487 dir
->direntlen
= sizeof_void_space
;
489 dir
->direntlen
= fs
->blksz
- totalbytes
;
491 dir
->namelen
= strlen(filename
);
492 dir
->filetype
= FILETYPE_REG
; /* regular file */
493 temp_dir
= (char *)dir
;
494 temp_dir
= temp_dir
+ sizeof(struct ext2_dirent
);
495 memcpy(temp_dir
, filename
, strlen(filename
));
499 /* update or write the 1st block of root inode */
500 if (ext4fs_put_metadata(root_first_block_buffer
,
501 first_block_no_of_root
))
506 free(root_first_block_buffer
);
509 static int search_dir(struct ext2_inode
*parent_inode
, char *dirname
)
519 unsigned char *block_buffer
= NULL
;
520 struct ext2_dirent
*dir
= NULL
;
521 struct ext2_dirent
*previous_dir
= NULL
;
522 struct ext_filesystem
*fs
= get_fs();
524 /* read the block no allocated to a file */
525 for (direct_blk_idx
= 0; direct_blk_idx
< INDIRECT_BLOCKS
;
527 blknr
= read_allocated_block(parent_inode
, direct_blk_idx
);
531 /* read the blocks of parenet inode */
532 block_buffer
= zalloc(fs
->blksz
);
536 status
= ext4fs_devread((lbaint_t
)blknr
* fs
->sect_perblk
,
537 0, fs
->blksz
, (char *)block_buffer
);
541 dir
= (struct ext2_dirent
*)block_buffer
;
544 while (dir
->direntlen
>= 0) {
546 * blocksize-totalbytes because last directory
547 * length i.e.,*dir->direntlen is free availble
548 * space in the block that means
549 * it is a last entry of directory entry
551 if (strlen(dirname
) == dir
->namelen
) {
552 if (strncmp(dirname
, ptr
+
553 sizeof(struct ext2_dirent
),
554 dir
->namelen
) == 0) {
555 previous_dir
->direntlen
+=
557 inodeno
= dir
->inode
;
564 if (fs
->blksz
- totalbytes
== dir
->direntlen
)
567 /* traversing the each directory entry */
568 templength
= dir
->direntlen
;
569 totalbytes
= totalbytes
+ templength
;
571 dir
= (struct ext2_dirent
*)((char *)dir
+ templength
);
591 static int find_dir_depth(char *dirname
)
593 char *token
= strtok(dirname
, "/");
595 while (token
!= NULL
) {
596 token
= strtok(NULL
, "/");
599 return count
+ 1 + 1;
601 * for example for string /home/temp
602 * depth=home(1)+temp(1)+1 extra for NULL;
607 static int parse_path(char **arr
, char *dirname
)
609 char *token
= strtok(dirname
, "/");
613 arr
[i
] = zalloc(strlen("/") + 1);
619 /* add each path entry after root */
620 while (token
!= NULL
) {
621 arr
[i
] = zalloc(strlen(token
) + 1);
624 memcpy(arr
[i
++], token
, strlen(token
));
625 token
= strtok(NULL
, "/");
632 int ext4fs_iget(int inode_no
, struct ext2_inode
*inode
)
634 if (ext4fs_read_inode(ext4fs_root
, inode_no
, inode
) == 0)
641 * Function: ext4fs_get_parent_inode_num
642 * Return Value: inode Number of the parent directory of file/Directory to be
644 * dirname : Input parmater, input path name of the file/directory to be created
645 * dname : Output parameter, to be filled with the name of the directory
646 * extracted from dirname
648 int ext4fs_get_parent_inode_num(const char *dirname
, char *dname
, int flags
)
652 int matched_inode_no
;
653 int result_inode_no
= -1;
655 char *depth_dirname
= NULL
;
656 char *parse_dirname
= NULL
;
657 struct ext2_inode
*parent_inode
= NULL
;
658 struct ext2_inode
*first_inode
= NULL
;
659 struct ext2_inode temp_inode
;
661 if (*dirname
!= '/') {
662 printf("Please supply Absolute path\n");
666 /* TODO: input validation make equivalent to linux */
667 depth_dirname
= zalloc(strlen(dirname
) + 1);
671 memcpy(depth_dirname
, dirname
, strlen(dirname
));
672 depth
= find_dir_depth(depth_dirname
);
673 parse_dirname
= zalloc(strlen(dirname
) + 1);
676 memcpy(parse_dirname
, dirname
, strlen(dirname
));
678 /* allocate memory for each directory level */
679 ptr
= zalloc((depth
) * sizeof(char *));
682 if (parse_path(ptr
, parse_dirname
))
684 parent_inode
= zalloc(sizeof(struct ext2_inode
));
687 first_inode
= zalloc(sizeof(struct ext2_inode
));
690 memcpy(parent_inode
, ext4fs_root
->inode
, sizeof(struct ext2_inode
));
691 memcpy(first_inode
, parent_inode
, sizeof(struct ext2_inode
));
693 result_inode_no
= EXT2_ROOT_INO
;
694 for (i
= 1; i
< depth
; i
++) {
695 matched_inode_no
= search_dir(parent_inode
, ptr
[i
]);
696 if (matched_inode_no
== -1) {
697 if (ptr
[i
+ 1] == NULL
&& i
== 1) {
698 result_inode_no
= EXT2_ROOT_INO
;
701 if (ptr
[i
+ 1] == NULL
)
703 printf("Invalid path\n");
704 result_inode_no
= -1;
708 if (ptr
[i
+ 1] != NULL
) {
709 memset(parent_inode
, '\0',
710 sizeof(struct ext2_inode
));
711 if (ext4fs_iget(matched_inode_no
,
713 result_inode_no
= -1;
716 result_inode_no
= matched_inode_no
;
725 matched_inode_no
= search_dir(first_inode
, ptr
[i
]);
727 matched_inode_no
= search_dir(parent_inode
, ptr
[i
]);
729 if (matched_inode_no
!= -1) {
730 ext4fs_iget(matched_inode_no
, &temp_inode
);
731 if (temp_inode
.mode
& S_IFDIR
) {
732 printf("It is a Directory\n");
733 result_inode_no
= -1;
738 if (strlen(ptr
[i
]) > 256) {
739 result_inode_no
= -1;
742 memcpy(dname
, ptr
[i
], strlen(ptr
[i
]));
751 return result_inode_no
;
754 static int check_filename(char *filename
, unsigned int blknr
)
756 unsigned int first_block_no_of_root
;
761 char *root_first_block_buffer
= NULL
;
762 char *root_first_block_addr
= NULL
;
763 struct ext2_dirent
*dir
= NULL
;
764 struct ext2_dirent
*previous_dir
= NULL
;
766 struct ext_filesystem
*fs
= get_fs();
768 /* get the first block of root */
769 first_block_no_of_root
= blknr
;
770 root_first_block_buffer
= zalloc(fs
->blksz
);
771 if (!root_first_block_buffer
)
773 root_first_block_addr
= root_first_block_buffer
;
774 status
= ext4fs_devread((lbaint_t
)first_block_no_of_root
*
776 fs
->blksz
, root_first_block_buffer
);
780 if (ext4fs_log_journal(root_first_block_buffer
, first_block_no_of_root
))
782 dir
= (struct ext2_dirent
*)root_first_block_buffer
;
785 while (dir
->direntlen
>= 0) {
787 * blocksize-totalbytes because last
788 * directory length i.e., *dir->direntlen
789 * is free availble space in the block that
790 * means it is a last entry of directory entry
792 if (strlen(filename
) == dir
->namelen
) {
793 if (strncmp(filename
, ptr
+ sizeof(struct ext2_dirent
),
794 dir
->namelen
) == 0) {
795 printf("file found deleting\n");
796 previous_dir
->direntlen
+= dir
->direntlen
;
797 inodeno
= dir
->inode
;
804 if (fs
->blksz
- totalbytes
== dir
->direntlen
)
807 /* traversing the each directory entry */
808 templength
= dir
->direntlen
;
809 totalbytes
= totalbytes
+ templength
;
811 dir
= (struct ext2_dirent
*)((char *)dir
+ templength
);
817 if (ext4fs_put_metadata(root_first_block_addr
,
818 first_block_no_of_root
))
823 free(root_first_block_buffer
);
828 int ext4fs_filename_check(char *filename
)
830 short direct_blk_idx
= 0;
834 /* read the block no allocated to a file */
835 for (direct_blk_idx
= 0; direct_blk_idx
< INDIRECT_BLOCKS
;
837 blknr
= read_allocated_block(g_parent_inode
, direct_blk_idx
);
840 inodeno
= check_filename(filename
, blknr
);
848 long int ext4fs_get_new_blk_no(void)
854 static int prev_bg_bitmap_index
= -1;
855 unsigned int blk_per_grp
= ext4fs_root
->sblock
.blocks_per_group
;
856 struct ext_filesystem
*fs
= get_fs();
857 char *journal_buffer
= zalloc(fs
->blksz
);
858 char *zero_buffer
= zalloc(fs
->blksz
);
859 if (!journal_buffer
|| !zero_buffer
)
861 struct ext2_block_group
*bgd
= (struct ext2_block_group
*)fs
->gdtable
;
863 if (fs
->first_pass_bbmap
== 0) {
864 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
865 if (bgd
[i
].free_blocks
) {
866 if (bgd
[i
].bg_flags
& EXT4_BG_BLOCK_UNINIT
) {
867 put_ext4(((uint64_t) ((uint64_t)bgd
[i
].block_id
*
868 (uint64_t)fs
->blksz
)),
869 zero_buffer
, fs
->blksz
);
872 bg_flags
& ~EXT4_BG_BLOCK_UNINIT
;
873 memcpy(fs
->blk_bmaps
[i
], zero_buffer
,
877 _get_new_blk_no(fs
->blk_bmaps
[i
]);
878 if (fs
->curr_blkno
== -1)
879 /* if block bitmap is completely fill */
881 fs
->curr_blkno
= fs
->curr_blkno
+
883 fs
->first_pass_bbmap
++;
884 bgd
[i
].free_blocks
--;
885 fs
->sb
->free_blocks
--;
886 status
= ext4fs_devread((lbaint_t
)
893 if (ext4fs_log_journal(journal_buffer
,
898 debug("no space left on block group %d\n", i
);
906 /* get the blockbitmap index respective to blockno */
907 bg_idx
= fs
->curr_blkno
/ blk_per_grp
;
908 if (fs
->blksz
== 1024) {
909 remainder
= fs
->curr_blkno
% blk_per_grp
;
915 * To skip completely filled block group bitmaps
916 * Optimize the block allocation
918 if (bg_idx
>= fs
->no_blkgrp
)
921 if (bgd
[bg_idx
].free_blocks
== 0) {
922 debug("block group %u is full. Skipping\n", bg_idx
);
923 fs
->curr_blkno
= fs
->curr_blkno
+ blk_per_grp
;
928 if (bgd
[bg_idx
].bg_flags
& EXT4_BG_BLOCK_UNINIT
) {
929 memset(zero_buffer
, '\0', fs
->blksz
);
930 put_ext4(((uint64_t) ((uint64_t)bgd
[bg_idx
].block_id
*
931 (uint64_t)fs
->blksz
)), zero_buffer
, fs
->blksz
);
932 memcpy(fs
->blk_bmaps
[bg_idx
], zero_buffer
, fs
->blksz
);
933 bgd
[bg_idx
].bg_flags
= bgd
[bg_idx
].bg_flags
&
934 ~EXT4_BG_BLOCK_UNINIT
;
937 if (ext4fs_set_block_bmap(fs
->curr_blkno
, fs
->blk_bmaps
[bg_idx
],
939 debug("going for restart for the block no %ld %u\n",
940 fs
->curr_blkno
, bg_idx
);
945 if (prev_bg_bitmap_index
!= bg_idx
) {
946 memset(journal_buffer
, '\0', fs
->blksz
);
947 status
= ext4fs_devread((lbaint_t
)bgd
[bg_idx
].block_id
949 0, fs
->blksz
, journal_buffer
);
952 if (ext4fs_log_journal(journal_buffer
,
953 bgd
[bg_idx
].block_id
))
956 prev_bg_bitmap_index
= bg_idx
;
958 bgd
[bg_idx
].free_blocks
--;
959 fs
->sb
->free_blocks
--;
963 free(journal_buffer
);
966 return fs
->curr_blkno
;
968 free(journal_buffer
);
974 int ext4fs_get_new_inode_no(void)
978 unsigned int ibmap_idx
;
979 static int prev_inode_bitmap_index
= -1;
980 unsigned int inodes_per_grp
= ext4fs_root
->sblock
.inodes_per_group
;
981 struct ext_filesystem
*fs
= get_fs();
982 char *journal_buffer
= zalloc(fs
->blksz
);
983 char *zero_buffer
= zalloc(fs
->blksz
);
984 if (!journal_buffer
|| !zero_buffer
)
986 struct ext2_block_group
*bgd
= (struct ext2_block_group
*)fs
->gdtable
;
988 if (fs
->first_pass_ibmap
== 0) {
989 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
990 if (bgd
[i
].free_inodes
) {
991 if (bgd
[i
].bg_itable_unused
!=
993 bgd
[i
].bg_itable_unused
=
995 if (bgd
[i
].bg_flags
& EXT4_BG_INODE_UNINIT
) {
997 ((uint64_t)bgd
[i
].inode_id
*
998 (uint64_t)fs
->blksz
)),
999 zero_buffer
, fs
->blksz
);
1000 bgd
[i
].bg_flags
= bgd
[i
].bg_flags
&
1001 ~EXT4_BG_INODE_UNINIT
;
1002 memcpy(fs
->inode_bmaps
[i
],
1003 zero_buffer
, fs
->blksz
);
1006 _get_new_inode_no(fs
->inode_bmaps
[i
]);
1007 if (fs
->curr_inode_no
== -1)
1008 /* if block bitmap is completely fill */
1010 fs
->curr_inode_no
= fs
->curr_inode_no
+
1011 (i
* inodes_per_grp
);
1012 fs
->first_pass_ibmap
++;
1013 bgd
[i
].free_inodes
--;
1014 bgd
[i
].bg_itable_unused
--;
1015 fs
->sb
->free_inodes
--;
1016 status
= ext4fs_devread((lbaint_t
)
1023 if (ext4fs_log_journal(journal_buffer
,
1028 debug("no inode left on block group %d\n", i
);
1033 fs
->curr_inode_no
++;
1034 /* get the blockbitmap index respective to blockno */
1035 ibmap_idx
= fs
->curr_inode_no
/ inodes_per_grp
;
1036 if (bgd
[ibmap_idx
].bg_flags
& EXT4_BG_INODE_UNINIT
) {
1037 memset(zero_buffer
, '\0', fs
->blksz
);
1038 put_ext4(((uint64_t) ((uint64_t)bgd
[ibmap_idx
].inode_id
*
1039 (uint64_t)fs
->blksz
)), zero_buffer
,
1041 bgd
[ibmap_idx
].bg_flags
=
1042 bgd
[ibmap_idx
].bg_flags
& ~EXT4_BG_INODE_UNINIT
;
1043 memcpy(fs
->inode_bmaps
[ibmap_idx
], zero_buffer
,
1047 if (ext4fs_set_inode_bmap(fs
->curr_inode_no
,
1048 fs
->inode_bmaps
[ibmap_idx
],
1050 debug("going for restart for the block no %d %u\n",
1051 fs
->curr_inode_no
, ibmap_idx
);
1055 /* journal backup */
1056 if (prev_inode_bitmap_index
!= ibmap_idx
) {
1057 memset(journal_buffer
, '\0', fs
->blksz
);
1058 status
= ext4fs_devread((lbaint_t
)
1059 bgd
[ibmap_idx
].inode_id
1061 0, fs
->blksz
, journal_buffer
);
1064 if (ext4fs_log_journal(journal_buffer
,
1065 bgd
[ibmap_idx
].inode_id
))
1067 prev_inode_bitmap_index
= ibmap_idx
;
1069 if (bgd
[ibmap_idx
].bg_itable_unused
!=
1070 bgd
[ibmap_idx
].free_inodes
)
1071 bgd
[ibmap_idx
].bg_itable_unused
=
1072 bgd
[ibmap_idx
].free_inodes
;
1073 bgd
[ibmap_idx
].free_inodes
--;
1074 bgd
[ibmap_idx
].bg_itable_unused
--;
1075 fs
->sb
->free_inodes
--;
1080 free(journal_buffer
);
1083 return fs
->curr_inode_no
;
1085 free(journal_buffer
);
1093 static void alloc_single_indirect_block(struct ext2_inode
*file_inode
,
1094 unsigned int *total_remaining_blocks
,
1095 unsigned int *no_blks_reqd
)
1099 long int actual_block_no
;
1100 long int si_blockno
;
1101 /* si :single indirect */
1102 unsigned int *si_buffer
= NULL
;
1103 unsigned int *si_start_addr
= NULL
;
1104 struct ext_filesystem
*fs
= get_fs();
1106 if (*total_remaining_blocks
!= 0) {
1107 si_buffer
= zalloc(fs
->blksz
);
1109 printf("No Memory\n");
1112 si_start_addr
= si_buffer
;
1113 si_blockno
= ext4fs_get_new_blk_no();
1114 if (si_blockno
== -1) {
1115 printf("no block left to assign\n");
1119 debug("SIPB %ld: %u\n", si_blockno
, *total_remaining_blocks
);
1121 status
= ext4fs_devread((lbaint_t
)si_blockno
* fs
->sect_perblk
,
1122 0, fs
->blksz
, (char *)si_buffer
);
1123 memset(si_buffer
, '\0', fs
->blksz
);
1127 for (i
= 0; i
< (fs
->blksz
/ sizeof(int)); i
++) {
1128 actual_block_no
= ext4fs_get_new_blk_no();
1129 if (actual_block_no
== -1) {
1130 printf("no block left to assign\n");
1133 *si_buffer
= actual_block_no
;
1134 debug("SIAB %u: %u\n", *si_buffer
,
1135 *total_remaining_blocks
);
1138 (*total_remaining_blocks
)--;
1139 if (*total_remaining_blocks
== 0)
1143 /* write the block to disk */
1144 put_ext4(((uint64_t) ((uint64_t)si_blockno
* (uint64_t)fs
->blksz
)),
1145 si_start_addr
, fs
->blksz
);
1146 file_inode
->b
.blocks
.indir_block
= si_blockno
;
1149 free(si_start_addr
);
1152 static void alloc_double_indirect_block(struct ext2_inode
*file_inode
,
1153 unsigned int *total_remaining_blocks
,
1154 unsigned int *no_blks_reqd
)
1159 long int actual_block_no
;
1160 /* di:double indirect */
1161 long int di_blockno_parent
;
1162 long int di_blockno_child
;
1163 unsigned int *di_parent_buffer
= NULL
;
1164 unsigned int *di_child_buff
= NULL
;
1165 unsigned int *di_block_start_addr
= NULL
;
1166 unsigned int *di_child_buff_start
= NULL
;
1167 struct ext_filesystem
*fs
= get_fs();
1169 if (*total_remaining_blocks
!= 0) {
1170 /* double indirect parent block connecting to inode */
1171 di_blockno_parent
= ext4fs_get_new_blk_no();
1172 if (di_blockno_parent
== -1) {
1173 printf("no block left to assign\n");
1176 di_parent_buffer
= zalloc(fs
->blksz
);
1177 if (!di_parent_buffer
)
1180 di_block_start_addr
= di_parent_buffer
;
1182 debug("DIPB %ld: %u\n", di_blockno_parent
,
1183 *total_remaining_blocks
);
1185 status
= ext4fs_devread((lbaint_t
)di_blockno_parent
*
1187 fs
->blksz
, (char *)di_parent_buffer
);
1190 printf("%s: Device read error!\n", __func__
);
1193 memset(di_parent_buffer
, '\0', fs
->blksz
);
1196 * start:for each double indirect parent
1197 * block create one more block
1199 for (i
= 0; i
< (fs
->blksz
/ sizeof(int)); i
++) {
1200 di_blockno_child
= ext4fs_get_new_blk_no();
1201 if (di_blockno_child
== -1) {
1202 printf("no block left to assign\n");
1205 di_child_buff
= zalloc(fs
->blksz
);
1209 di_child_buff_start
= di_child_buff
;
1210 *di_parent_buffer
= di_blockno_child
;
1213 debug("DICB %ld: %u\n", di_blockno_child
,
1214 *total_remaining_blocks
);
1216 status
= ext4fs_devread((lbaint_t
)di_blockno_child
*
1219 (char *)di_child_buff
);
1222 printf("%s: Device read error!\n", __func__
);
1225 memset(di_child_buff
, '\0', fs
->blksz
);
1226 /* filling of actual datablocks for each child */
1227 for (j
= 0; j
< (fs
->blksz
/ sizeof(int)); j
++) {
1228 actual_block_no
= ext4fs_get_new_blk_no();
1229 if (actual_block_no
== -1) {
1230 printf("no block left to assign\n");
1233 *di_child_buff
= actual_block_no
;
1234 debug("DIAB %ld: %u\n", actual_block_no
,
1235 *total_remaining_blocks
);
1238 (*total_remaining_blocks
)--;
1239 if (*total_remaining_blocks
== 0)
1242 /* write the block table */
1243 put_ext4(((uint64_t) ((uint64_t)di_blockno_child
* (uint64_t)fs
->blksz
)),
1244 di_child_buff_start
, fs
->blksz
);
1245 free(di_child_buff_start
);
1246 di_child_buff_start
= NULL
;
1248 if (*total_remaining_blocks
== 0)
1251 put_ext4(((uint64_t) ((uint64_t)di_blockno_parent
* (uint64_t)fs
->blksz
)),
1252 di_block_start_addr
, fs
->blksz
);
1253 file_inode
->b
.blocks
.double_indir_block
= di_blockno_parent
;
1256 free(di_block_start_addr
);
1259 static void alloc_triple_indirect_block(struct ext2_inode
*file_inode
,
1260 unsigned int *total_remaining_blocks
,
1261 unsigned int *no_blks_reqd
)
1266 long int actual_block_no
;
1267 /* ti: Triple Indirect */
1268 long int ti_gp_blockno
;
1269 long int ti_parent_blockno
;
1270 long int ti_child_blockno
;
1271 unsigned int *ti_gp_buff
= NULL
;
1272 unsigned int *ti_parent_buff
= NULL
;
1273 unsigned int *ti_child_buff
= NULL
;
1274 unsigned int *ti_gp_buff_start_addr
= NULL
;
1275 unsigned int *ti_pbuff_start_addr
= NULL
;
1276 unsigned int *ti_cbuff_start_addr
= NULL
;
1277 struct ext_filesystem
*fs
= get_fs();
1278 if (*total_remaining_blocks
!= 0) {
1279 /* triple indirect grand parent block connecting to inode */
1280 ti_gp_blockno
= ext4fs_get_new_blk_no();
1281 if (ti_gp_blockno
== -1) {
1282 printf("no block left to assign\n");
1285 ti_gp_buff
= zalloc(fs
->blksz
);
1289 ti_gp_buff_start_addr
= ti_gp_buff
;
1291 debug("TIGPB %ld: %u\n", ti_gp_blockno
,
1292 *total_remaining_blocks
);
1294 /* for each 4 byte grand parent entry create one more block */
1295 for (i
= 0; i
< (fs
->blksz
/ sizeof(int)); i
++) {
1296 ti_parent_blockno
= ext4fs_get_new_blk_no();
1297 if (ti_parent_blockno
== -1) {
1298 printf("no block left to assign\n");
1301 ti_parent_buff
= zalloc(fs
->blksz
);
1302 if (!ti_parent_buff
)
1305 ti_pbuff_start_addr
= ti_parent_buff
;
1306 *ti_gp_buff
= ti_parent_blockno
;
1309 debug("TIPB %ld: %u\n", ti_parent_blockno
,
1310 *total_remaining_blocks
);
1312 /* for each 4 byte entry parent create one more block */
1313 for (j
= 0; j
< (fs
->blksz
/ sizeof(int)); j
++) {
1314 ti_child_blockno
= ext4fs_get_new_blk_no();
1315 if (ti_child_blockno
== -1) {
1316 printf("no block left assign\n");
1319 ti_child_buff
= zalloc(fs
->blksz
);
1323 ti_cbuff_start_addr
= ti_child_buff
;
1324 *ti_parent_buff
= ti_child_blockno
;
1327 debug("TICB %ld: %u\n", ti_parent_blockno
,
1328 *total_remaining_blocks
);
1330 /* fill actual datablocks for each child */
1331 for (k
= 0; k
< (fs
->blksz
/ sizeof(int));
1334 ext4fs_get_new_blk_no();
1335 if (actual_block_no
== -1) {
1336 printf("no block left\n");
1339 *ti_child_buff
= actual_block_no
;
1340 debug("TIAB %ld: %u\n", actual_block_no
,
1341 *total_remaining_blocks
);
1344 (*total_remaining_blocks
)--;
1345 if (*total_remaining_blocks
== 0)
1348 /* write the child block */
1349 put_ext4(((uint64_t) ((uint64_t)ti_child_blockno
*
1350 (uint64_t)fs
->blksz
)),
1351 ti_cbuff_start_addr
, fs
->blksz
);
1352 free(ti_cbuff_start_addr
);
1354 if (*total_remaining_blocks
== 0)
1357 /* write the parent block */
1358 put_ext4(((uint64_t) ((uint64_t)ti_parent_blockno
* (uint64_t)fs
->blksz
)),
1359 ti_pbuff_start_addr
, fs
->blksz
);
1360 free(ti_pbuff_start_addr
);
1362 if (*total_remaining_blocks
== 0)
1365 /* write the grand parent block */
1366 put_ext4(((uint64_t) ((uint64_t)ti_gp_blockno
* (uint64_t)fs
->blksz
)),
1367 ti_gp_buff_start_addr
, fs
->blksz
);
1368 file_inode
->b
.blocks
.triple_indir_block
= ti_gp_blockno
;
1371 free(ti_gp_buff_start_addr
);
1374 void ext4fs_allocate_blocks(struct ext2_inode
*file_inode
,
1375 unsigned int total_remaining_blocks
,
1376 unsigned int *total_no_of_block
)
1379 long int direct_blockno
;
1380 unsigned int no_blks_reqd
= 0;
1382 /* allocation of direct blocks */
1383 for (i
= 0; i
< INDIRECT_BLOCKS
; i
++) {
1384 direct_blockno
= ext4fs_get_new_blk_no();
1385 if (direct_blockno
== -1) {
1386 printf("no block left to assign\n");
1389 file_inode
->b
.blocks
.dir_blocks
[i
] = direct_blockno
;
1390 debug("DB %ld: %u\n", direct_blockno
, total_remaining_blocks
);
1392 total_remaining_blocks
--;
1393 if (total_remaining_blocks
== 0)
1397 alloc_single_indirect_block(file_inode
, &total_remaining_blocks
,
1399 alloc_double_indirect_block(file_inode
, &total_remaining_blocks
,
1401 alloc_triple_indirect_block(file_inode
, &total_remaining_blocks
,
1403 *total_no_of_block
+= no_blks_reqd
;
1408 static struct ext4_extent_header
*ext4fs_get_extent_block
1409 (struct ext2_data
*data
, char *buf
,
1410 struct ext4_extent_header
*ext_block
,
1411 uint32_t fileblock
, int log2_blksz
)
1413 struct ext4_extent_idx
*index
;
1414 unsigned long long block
;
1415 int blksz
= EXT2_BLOCK_SIZE(data
);
1419 index
= (struct ext4_extent_idx
*)(ext_block
+ 1);
1421 if (le16_to_cpu(ext_block
->eh_magic
) != EXT4_EXT_MAGIC
)
1424 if (ext_block
->eh_depth
== 0)
1429 if (i
>= le16_to_cpu(ext_block
->eh_entries
))
1431 } while (fileblock
>= le32_to_cpu(index
[i
].ei_block
));
1436 block
= le16_to_cpu(index
[i
].ei_leaf_hi
);
1437 block
= (block
<< 32) + le32_to_cpu(index
[i
].ei_leaf_lo
);
1439 if (ext4fs_devread((lbaint_t
)block
<< log2_blksz
, 0, blksz
,
1441 ext_block
= (struct ext4_extent_header
*)buf
;
1447 static int ext4fs_blockgroup
1448 (struct ext2_data
*data
, int group
, struct ext2_block_group
*blkgrp
)
1451 unsigned int blkoff
, desc_per_blk
;
1452 int log2blksz
= get_fs()->dev_desc
->log2blksz
;
1454 desc_per_blk
= EXT2_BLOCK_SIZE(data
) / sizeof(struct ext2_block_group
);
1456 blkno
= __le32_to_cpu(data
->sblock
.first_data_block
) + 1 +
1457 group
/ desc_per_blk
;
1458 blkoff
= (group
% desc_per_blk
) * sizeof(struct ext2_block_group
);
1460 debug("ext4fs read %d group descriptor (blkno %ld blkoff %u)\n",
1461 group
, blkno
, blkoff
);
1463 return ext4fs_devread((lbaint_t
)blkno
<<
1464 (LOG2_BLOCK_SIZE(data
) - log2blksz
),
1465 blkoff
, sizeof(struct ext2_block_group
),
1469 int ext4fs_read_inode(struct ext2_data
*data
, int ino
, struct ext2_inode
*inode
)
1471 struct ext2_block_group blkgrp
;
1472 struct ext2_sblock
*sblock
= &data
->sblock
;
1473 struct ext_filesystem
*fs
= get_fs();
1474 int log2blksz
= get_fs()->dev_desc
->log2blksz
;
1475 int inodes_per_block
, status
;
1477 unsigned int blkoff
;
1479 /* It is easier to calculate if the first inode is 0. */
1481 status
= ext4fs_blockgroup(data
, ino
/ __le32_to_cpu
1482 (sblock
->inodes_per_group
), &blkgrp
);
1486 inodes_per_block
= EXT2_BLOCK_SIZE(data
) / fs
->inodesz
;
1487 blkno
= __le32_to_cpu(blkgrp
.inode_table_id
) +
1488 (ino
% __le32_to_cpu(sblock
->inodes_per_group
)) / inodes_per_block
;
1489 blkoff
= (ino
% inodes_per_block
) * fs
->inodesz
;
1490 /* Read the inode. */
1491 status
= ext4fs_devread((lbaint_t
)blkno
<< (LOG2_BLOCK_SIZE(data
) -
1493 sizeof(struct ext2_inode
), (char *)inode
);
1500 long int read_allocated_block(struct ext2_inode
*inode
, int fileblock
)
1507 long int perblock_parent
;
1508 long int perblock_child
;
1509 unsigned long long start
;
1510 /* get the blocksize of the filesystem */
1511 blksz
= EXT2_BLOCK_SIZE(ext4fs_root
);
1512 log2_blksz
= LOG2_BLOCK_SIZE(ext4fs_root
)
1513 - get_fs()->dev_desc
->log2blksz
;
1515 if (le32_to_cpu(inode
->flags
) & EXT4_EXTENTS_FL
) {
1516 char *buf
= zalloc(blksz
);
1519 struct ext4_extent_header
*ext_block
;
1520 struct ext4_extent
*extent
;
1523 ext4fs_get_extent_block(ext4fs_root
, buf
,
1524 (struct ext4_extent_header
*)
1525 inode
->b
.blocks
.dir_blocks
,
1526 fileblock
, log2_blksz
);
1528 printf("invalid extent block\n");
1533 extent
= (struct ext4_extent
*)(ext_block
+ 1);
1537 if (i
>= le16_to_cpu(ext_block
->eh_entries
))
1539 } while (fileblock
>= le32_to_cpu(extent
[i
].ee_block
));
1541 fileblock
-= le32_to_cpu(extent
[i
].ee_block
);
1542 if (fileblock
>= le16_to_cpu(extent
[i
].ee_len
)) {
1547 start
= le16_to_cpu(extent
[i
].ee_start_hi
);
1548 start
= (start
<< 32) +
1549 le32_to_cpu(extent
[i
].ee_start_lo
);
1551 return fileblock
+ start
;
1554 printf("Extent Error\n");
1559 /* Direct blocks. */
1560 if (fileblock
< INDIRECT_BLOCKS
)
1561 blknr
= __le32_to_cpu(inode
->b
.blocks
.dir_blocks
[fileblock
]);
1564 else if (fileblock
< (INDIRECT_BLOCKS
+ (blksz
/ 4))) {
1565 if (ext4fs_indir1_block
== NULL
) {
1566 ext4fs_indir1_block
= zalloc(blksz
);
1567 if (ext4fs_indir1_block
== NULL
) {
1568 printf("** SI ext2fs read block (indir 1)"
1569 "malloc failed. **\n");
1572 ext4fs_indir1_size
= blksz
;
1573 ext4fs_indir1_blkno
= -1;
1575 if (blksz
!= ext4fs_indir1_size
) {
1576 free(ext4fs_indir1_block
);
1577 ext4fs_indir1_block
= NULL
;
1578 ext4fs_indir1_size
= 0;
1579 ext4fs_indir1_blkno
= -1;
1580 ext4fs_indir1_block
= zalloc(blksz
);
1581 if (ext4fs_indir1_block
== NULL
) {
1582 printf("** SI ext2fs read block (indir 1):"
1583 "malloc failed. **\n");
1586 ext4fs_indir1_size
= blksz
;
1588 if ((__le32_to_cpu(inode
->b
.blocks
.indir_block
) <<
1589 log2_blksz
) != ext4fs_indir1_blkno
) {
1591 ext4fs_devread((lbaint_t
)__le32_to_cpu
1593 indir_block
) << log2_blksz
, 0,
1594 blksz
, (char *)ext4fs_indir1_block
);
1596 printf("** SI ext2fs read block (indir 1)"
1600 ext4fs_indir1_blkno
=
1601 __le32_to_cpu(inode
->b
.blocks
.
1602 indir_block
) << log2_blksz
;
1604 blknr
= __le32_to_cpu(ext4fs_indir1_block
1605 [fileblock
- INDIRECT_BLOCKS
]);
1607 /* Double indirect. */
1608 else if (fileblock
< (INDIRECT_BLOCKS
+ (blksz
/ 4 *
1609 (blksz
/ 4 + 1)))) {
1611 long int perblock
= blksz
/ 4;
1612 long int rblock
= fileblock
- (INDIRECT_BLOCKS
+ blksz
/ 4);
1614 if (ext4fs_indir1_block
== NULL
) {
1615 ext4fs_indir1_block
= zalloc(blksz
);
1616 if (ext4fs_indir1_block
== NULL
) {
1617 printf("** DI ext2fs read block (indir 2 1)"
1618 "malloc failed. **\n");
1621 ext4fs_indir1_size
= blksz
;
1622 ext4fs_indir1_blkno
= -1;
1624 if (blksz
!= ext4fs_indir1_size
) {
1625 free(ext4fs_indir1_block
);
1626 ext4fs_indir1_block
= NULL
;
1627 ext4fs_indir1_size
= 0;
1628 ext4fs_indir1_blkno
= -1;
1629 ext4fs_indir1_block
= zalloc(blksz
);
1630 if (ext4fs_indir1_block
== NULL
) {
1631 printf("** DI ext2fs read block (indir 2 1)"
1632 "malloc failed. **\n");
1635 ext4fs_indir1_size
= blksz
;
1637 if ((__le32_to_cpu(inode
->b
.blocks
.double_indir_block
) <<
1638 log2_blksz
) != ext4fs_indir1_blkno
) {
1640 ext4fs_devread((lbaint_t
)__le32_to_cpu
1642 double_indir_block
) << log2_blksz
,
1644 (char *)ext4fs_indir1_block
);
1646 printf("** DI ext2fs read block (indir 2 1)"
1650 ext4fs_indir1_blkno
=
1651 __le32_to_cpu(inode
->b
.blocks
.double_indir_block
) <<
1655 if (ext4fs_indir2_block
== NULL
) {
1656 ext4fs_indir2_block
= zalloc(blksz
);
1657 if (ext4fs_indir2_block
== NULL
) {
1658 printf("** DI ext2fs read block (indir 2 2)"
1659 "malloc failed. **\n");
1662 ext4fs_indir2_size
= blksz
;
1663 ext4fs_indir2_blkno
= -1;
1665 if (blksz
!= ext4fs_indir2_size
) {
1666 free(ext4fs_indir2_block
);
1667 ext4fs_indir2_block
= NULL
;
1668 ext4fs_indir2_size
= 0;
1669 ext4fs_indir2_blkno
= -1;
1670 ext4fs_indir2_block
= zalloc(blksz
);
1671 if (ext4fs_indir2_block
== NULL
) {
1672 printf("** DI ext2fs read block (indir 2 2)"
1673 "malloc failed. **\n");
1676 ext4fs_indir2_size
= blksz
;
1678 if ((__le32_to_cpu(ext4fs_indir1_block
[rblock
/ perblock
]) <<
1679 log2_blksz
) != ext4fs_indir2_blkno
) {
1680 status
= ext4fs_devread((lbaint_t
)__le32_to_cpu
1681 (ext4fs_indir1_block
1683 perblock
]) << log2_blksz
, 0,
1685 (char *)ext4fs_indir2_block
);
1687 printf("** DI ext2fs read block (indir 2 2)"
1691 ext4fs_indir2_blkno
=
1692 __le32_to_cpu(ext4fs_indir1_block
[rblock
1697 blknr
= __le32_to_cpu(ext4fs_indir2_block
[rblock
% perblock
]);
1699 /* Tripple indirect. */
1701 rblock
= fileblock
- (INDIRECT_BLOCKS
+ blksz
/ 4 +
1702 (blksz
/ 4 * blksz
/ 4));
1703 perblock_child
= blksz
/ 4;
1704 perblock_parent
= ((blksz
/ 4) * (blksz
/ 4));
1706 if (ext4fs_indir1_block
== NULL
) {
1707 ext4fs_indir1_block
= zalloc(blksz
);
1708 if (ext4fs_indir1_block
== NULL
) {
1709 printf("** TI ext2fs read block (indir 2 1)"
1710 "malloc failed. **\n");
1713 ext4fs_indir1_size
= blksz
;
1714 ext4fs_indir1_blkno
= -1;
1716 if (blksz
!= ext4fs_indir1_size
) {
1717 free(ext4fs_indir1_block
);
1718 ext4fs_indir1_block
= NULL
;
1719 ext4fs_indir1_size
= 0;
1720 ext4fs_indir1_blkno
= -1;
1721 ext4fs_indir1_block
= zalloc(blksz
);
1722 if (ext4fs_indir1_block
== NULL
) {
1723 printf("** TI ext2fs read block (indir 2 1)"
1724 "malloc failed. **\n");
1727 ext4fs_indir1_size
= blksz
;
1729 if ((__le32_to_cpu(inode
->b
.blocks
.triple_indir_block
) <<
1730 log2_blksz
) != ext4fs_indir1_blkno
) {
1731 status
= ext4fs_devread
1733 __le32_to_cpu(inode
->b
.blocks
.triple_indir_block
)
1734 << log2_blksz
, 0, blksz
,
1735 (char *)ext4fs_indir1_block
);
1737 printf("** TI ext2fs read block (indir 2 1)"
1741 ext4fs_indir1_blkno
=
1742 __le32_to_cpu(inode
->b
.blocks
.triple_indir_block
) <<
1746 if (ext4fs_indir2_block
== NULL
) {
1747 ext4fs_indir2_block
= zalloc(blksz
);
1748 if (ext4fs_indir2_block
== NULL
) {
1749 printf("** TI ext2fs read block (indir 2 2)"
1750 "malloc failed. **\n");
1753 ext4fs_indir2_size
= blksz
;
1754 ext4fs_indir2_blkno
= -1;
1756 if (blksz
!= ext4fs_indir2_size
) {
1757 free(ext4fs_indir2_block
);
1758 ext4fs_indir2_block
= NULL
;
1759 ext4fs_indir2_size
= 0;
1760 ext4fs_indir2_blkno
= -1;
1761 ext4fs_indir2_block
= zalloc(blksz
);
1762 if (ext4fs_indir2_block
== NULL
) {
1763 printf("** TI ext2fs read block (indir 2 2)"
1764 "malloc failed. **\n");
1767 ext4fs_indir2_size
= blksz
;
1769 if ((__le32_to_cpu(ext4fs_indir1_block
[rblock
/
1770 perblock_parent
]) <<
1772 != ext4fs_indir2_blkno
) {
1773 status
= ext4fs_devread((lbaint_t
)__le32_to_cpu
1774 (ext4fs_indir1_block
1776 perblock_parent
]) <<
1777 log2_blksz
, 0, blksz
,
1778 (char *)ext4fs_indir2_block
);
1780 printf("** TI ext2fs read block (indir 2 2)"
1784 ext4fs_indir2_blkno
=
1785 __le32_to_cpu(ext4fs_indir1_block
[rblock
/
1790 if (ext4fs_indir3_block
== NULL
) {
1791 ext4fs_indir3_block
= zalloc(blksz
);
1792 if (ext4fs_indir3_block
== NULL
) {
1793 printf("** TI ext2fs read block (indir 2 2)"
1794 "malloc failed. **\n");
1797 ext4fs_indir3_size
= blksz
;
1798 ext4fs_indir3_blkno
= -1;
1800 if (blksz
!= ext4fs_indir3_size
) {
1801 free(ext4fs_indir3_block
);
1802 ext4fs_indir3_block
= NULL
;
1803 ext4fs_indir3_size
= 0;
1804 ext4fs_indir3_blkno
= -1;
1805 ext4fs_indir3_block
= zalloc(blksz
);
1806 if (ext4fs_indir3_block
== NULL
) {
1807 printf("** TI ext2fs read block (indir 2 2)"
1808 "malloc failed. **\n");
1811 ext4fs_indir3_size
= blksz
;
1813 if ((__le32_to_cpu(ext4fs_indir2_block
[rblock
1816 log2_blksz
) != ext4fs_indir3_blkno
) {
1818 ext4fs_devread((lbaint_t
)__le32_to_cpu
1819 (ext4fs_indir2_block
1820 [(rblock
/ perblock_child
)
1821 % (blksz
/ 4)]) << log2_blksz
, 0,
1822 blksz
, (char *)ext4fs_indir3_block
);
1824 printf("** TI ext2fs read block (indir 2 2)"
1828 ext4fs_indir3_blkno
=
1829 __le32_to_cpu(ext4fs_indir2_block
[(rblock
/
1836 blknr
= __le32_to_cpu(ext4fs_indir3_block
1837 [rblock
% perblock_child
]);
1839 debug("read_allocated_block %ld\n", blknr
);
1844 void ext4fs_close(void)
1846 if ((ext4fs_file
!= NULL
) && (ext4fs_root
!= NULL
)) {
1847 ext4fs_free_node(ext4fs_file
, &ext4fs_root
->diropen
);
1850 if (ext4fs_root
!= NULL
) {
1854 if (ext4fs_indir1_block
!= NULL
) {
1855 free(ext4fs_indir1_block
);
1856 ext4fs_indir1_block
= NULL
;
1857 ext4fs_indir1_size
= 0;
1858 ext4fs_indir1_blkno
= -1;
1860 if (ext4fs_indir2_block
!= NULL
) {
1861 free(ext4fs_indir2_block
);
1862 ext4fs_indir2_block
= NULL
;
1863 ext4fs_indir2_size
= 0;
1864 ext4fs_indir2_blkno
= -1;
1866 if (ext4fs_indir3_block
!= NULL
) {
1867 free(ext4fs_indir3_block
);
1868 ext4fs_indir3_block
= NULL
;
1869 ext4fs_indir3_size
= 0;
1870 ext4fs_indir3_blkno
= -1;
1874 int ext4fs_iterate_dir(struct ext2fs_node
*dir
, char *name
,
1875 struct ext2fs_node
**fnode
, int *ftype
)
1877 unsigned int fpos
= 0;
1879 struct ext2fs_node
*diro
= (struct ext2fs_node
*) dir
;
1883 printf("Iterate dir %s\n", name
);
1884 #endif /* of DEBUG */
1885 if (!diro
->inode_read
) {
1886 status
= ext4fs_read_inode(diro
->data
, diro
->ino
, &diro
->inode
);
1890 /* Search the file. */
1891 while (fpos
< __le32_to_cpu(diro
->inode
.size
)) {
1892 struct ext2_dirent dirent
;
1894 status
= ext4fs_read_file(diro
, fpos
,
1895 sizeof(struct ext2_dirent
),
1900 if (dirent
.namelen
!= 0) {
1901 char filename
[dirent
.namelen
+ 1];
1902 struct ext2fs_node
*fdiro
;
1903 int type
= FILETYPE_UNKNOWN
;
1905 status
= ext4fs_read_file(diro
,
1907 sizeof(struct ext2_dirent
),
1908 dirent
.namelen
, filename
);
1912 fdiro
= zalloc(sizeof(struct ext2fs_node
));
1916 fdiro
->data
= diro
->data
;
1917 fdiro
->ino
= __le32_to_cpu(dirent
.inode
);
1919 filename
[dirent
.namelen
] = '\0';
1921 if (dirent
.filetype
!= FILETYPE_UNKNOWN
) {
1922 fdiro
->inode_read
= 0;
1924 if (dirent
.filetype
== FILETYPE_DIRECTORY
)
1925 type
= FILETYPE_DIRECTORY
;
1926 else if (dirent
.filetype
== FILETYPE_SYMLINK
)
1927 type
= FILETYPE_SYMLINK
;
1928 else if (dirent
.filetype
== FILETYPE_REG
)
1929 type
= FILETYPE_REG
;
1931 status
= ext4fs_read_inode(diro
->data
,
1939 fdiro
->inode_read
= 1;
1941 if ((__le16_to_cpu(fdiro
->inode
.mode
) &
1942 FILETYPE_INO_MASK
) ==
1943 FILETYPE_INO_DIRECTORY
) {
1944 type
= FILETYPE_DIRECTORY
;
1945 } else if ((__le16_to_cpu(fdiro
->inode
.mode
)
1946 & FILETYPE_INO_MASK
) ==
1947 FILETYPE_INO_SYMLINK
) {
1948 type
= FILETYPE_SYMLINK
;
1949 } else if ((__le16_to_cpu(fdiro
->inode
.mode
)
1950 & FILETYPE_INO_MASK
) ==
1952 type
= FILETYPE_REG
;
1956 printf("iterate >%s<\n", filename
);
1957 #endif /* of DEBUG */
1958 if ((name
!= NULL
) && (fnode
!= NULL
)
1959 && (ftype
!= NULL
)) {
1960 if (strcmp(filename
, name
) == 0) {
1966 if (fdiro
->inode_read
== 0) {
1967 status
= ext4fs_read_inode(diro
->data
,
1975 fdiro
->inode_read
= 1;
1978 case FILETYPE_DIRECTORY
:
1981 case FILETYPE_SYMLINK
:
1992 __le32_to_cpu(fdiro
->inode
.size
),
1997 fpos
+= __le16_to_cpu(dirent
.direntlen
);
2002 static char *ext4fs_read_symlink(struct ext2fs_node
*node
)
2005 struct ext2fs_node
*diro
= node
;
2008 if (!diro
->inode_read
) {
2009 status
= ext4fs_read_inode(diro
->data
, diro
->ino
, &diro
->inode
);
2013 symlink
= zalloc(__le32_to_cpu(diro
->inode
.size
) + 1);
2017 if (__le32_to_cpu(diro
->inode
.size
) <= 60) {
2018 strncpy(symlink
, diro
->inode
.b
.symlink
,
2019 __le32_to_cpu(diro
->inode
.size
));
2021 status
= ext4fs_read_file(diro
, 0,
2022 __le32_to_cpu(diro
->inode
.size
),
2029 symlink
[__le32_to_cpu(diro
->inode
.size
)] = '\0';
2033 static int ext4fs_find_file1(const char *currpath
,
2034 struct ext2fs_node
*currroot
,
2035 struct ext2fs_node
**currfound
, int *foundtype
)
2037 char fpath
[strlen(currpath
) + 1];
2041 int type
= FILETYPE_DIRECTORY
;
2042 struct ext2fs_node
*currnode
= currroot
;
2043 struct ext2fs_node
*oldnode
= currroot
;
2045 strncpy(fpath
, currpath
, strlen(currpath
) + 1);
2047 /* Remove all leading slashes. */
2048 while (*name
== '/')
2052 *currfound
= currnode
;
2059 /* Extract the actual part from the pathname. */
2060 next
= strchr(name
, '/');
2062 /* Remove all leading slashes. */
2063 while (*next
== '/')
2067 if (type
!= FILETYPE_DIRECTORY
) {
2068 ext4fs_free_node(currnode
, currroot
);
2074 /* Iterate over the directory. */
2075 found
= ext4fs_iterate_dir(currnode
, name
, &currnode
, &type
);
2082 /* Read in the symlink and follow it. */
2083 if (type
== FILETYPE_SYMLINK
) {
2086 /* Test if the symlink does not loop. */
2087 if (++symlinknest
== 8) {
2088 ext4fs_free_node(currnode
, currroot
);
2089 ext4fs_free_node(oldnode
, currroot
);
2093 symlink
= ext4fs_read_symlink(currnode
);
2094 ext4fs_free_node(currnode
, currroot
);
2097 ext4fs_free_node(oldnode
, currroot
);
2101 debug("Got symlink >%s<\n", symlink
);
2103 if (symlink
[0] == '/') {
2104 ext4fs_free_node(oldnode
, currroot
);
2105 oldnode
= &ext4fs_root
->diropen
;
2108 /* Lookup the node the symlink points to. */
2109 status
= ext4fs_find_file1(symlink
, oldnode
,
2115 ext4fs_free_node(oldnode
, currroot
);
2120 ext4fs_free_node(oldnode
, currroot
);
2122 /* Found the node! */
2123 if (!next
|| *next
== '\0') {
2124 *currfound
= currnode
;
2133 int ext4fs_find_file(const char *path
, struct ext2fs_node
*rootnode
,
2134 struct ext2fs_node
**foundnode
, int expecttype
)
2137 int foundtype
= FILETYPE_DIRECTORY
;
2143 status
= ext4fs_find_file1(path
, rootnode
, foundnode
, &foundtype
);
2147 /* Check if the node that was found was of the expected type. */
2148 if ((expecttype
== FILETYPE_REG
) && (foundtype
!= expecttype
))
2150 else if ((expecttype
== FILETYPE_DIRECTORY
)
2151 && (foundtype
!= expecttype
))
2157 int ext4fs_open(const char *filename
)
2159 struct ext2fs_node
*fdiro
= NULL
;
2163 if (ext4fs_root
== NULL
)
2167 status
= ext4fs_find_file(filename
, &ext4fs_root
->diropen
, &fdiro
,
2172 if (!fdiro
->inode_read
) {
2173 status
= ext4fs_read_inode(fdiro
->data
, fdiro
->ino
,
2178 len
= __le32_to_cpu(fdiro
->inode
.size
);
2179 ext4fs_file
= fdiro
;
2183 ext4fs_free_node(fdiro
, &ext4fs_root
->diropen
);
2188 int ext4fs_mount(unsigned part_length
)
2190 struct ext2_data
*data
;
2192 struct ext_filesystem
*fs
= get_fs();
2193 data
= zalloc(SUPERBLOCK_SIZE
);
2197 /* Read the superblock. */
2198 status
= ext4_read_superblock((char *)&data
->sblock
);
2203 /* Make sure this is an ext2 filesystem. */
2204 if (__le16_to_cpu(data
->sblock
.magic
) != EXT2_MAGIC
)
2207 if (__le32_to_cpu(data
->sblock
.revision_level
== 0))
2210 fs
->inodesz
= __le16_to_cpu(data
->sblock
.inode_size
);
2212 debug("EXT2 rev %d, inode_size %d\n",
2213 __le32_to_cpu(data
->sblock
.revision_level
), fs
->inodesz
);
2215 data
->diropen
.data
= data
;
2216 data
->diropen
.ino
= 2;
2217 data
->diropen
.inode_read
= 1;
2218 data
->inode
= &data
->diropen
.inode
;
2220 status
= ext4fs_read_inode(data
, 2, data
->inode
);
2228 printf("Failed to mount ext2 filesystem...\n");