123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- --- a/stage2/fsys_ext2fs.c
- +++ b/stage2/fsys_ext2fs.c
- @@ -51,6 +51,9 @@ typedef unsigned int __u32;
- #define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
- #define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
-
- +/* Inode flags */
- +#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */
- +
- /* include/linux/ext2_fs.h */
- struct ext2_super_block
- {
- @@ -191,6 +194,42 @@ struct ext2_dir_entry
- #define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
- ~EXT2_DIR_ROUND)
-
- +/* linux/ext4_fs_extents.h */
- +/*
- + * This is the extent on-disk structure.
- + * It's used at the bottom of the tree.
- + */
- +struct ext4_extent {
- + __u32 ee_block; /* first logical block extent covers */
- + __u16 ee_len; /* number of blocks covered by extent */
- + __u16 ee_start_hi; /* high 16 bits of physical block */
- + __u32 ee_start; /* low 32 bits of physical block */
- +};
- +
- +/*
- + * This is index on-disk structure.
- + * It's used at all the levels except the bottom.
- + */
- +struct ext4_extent_idx {
- + __u32 ei_block; /* index covers logical blocks from 'block' */
- + __u32 ei_leaf; /* pointer to the physical block of the next *
- + * level. leaf or next index could be there */
- + __u16 ei_leaf_hi; /* high 16 bits of physical block */
- + __u16 ei_unused;
- +};
- +
- +/*
- + * Each block (leaves and indexes), even inode-stored has header.
- + */
- +struct ext4_extent_header {
- + __u16 eh_magic; /* probably will support different formats */
- + __u16 eh_entries; /* number of valid entries */
- + __u16 eh_max; /* capacity of store in entries */
- + __u16 eh_depth; /* has tree real underlying blocks? */
- + __u32 eh_generation; /* generation of the tree */
- +};
- +
- +#define EXT4_EXT_MAGIC 0xf30a
-
- /* ext2/super.c */
- #define log2(n) ffz(~(n))
- @@ -279,6 +318,27 @@ ext2_rdfsb (int fsblock, int buffer)
- EXT2_BLOCK_SIZE (SUPERBLOCK), (char *) buffer);
- }
-
- +/* Walk through extents index tree to find the good leaf */
- +static struct ext4_extent_header *
- +ext4_recurse_extent_index(struct ext4_extent_header *extent_block, int logical_block)
- +{
- + int i;
- + struct ext4_extent_idx *index = (struct ext4_extent_idx *) (extent_block + 1);
- + if (extent_block->eh_magic != EXT4_EXT_MAGIC)
- + return NULL;
- + if (extent_block->eh_depth == 0)
- + return extent_block;
- + for (i = 0; i < extent_block->eh_entries; i++)
- + {
- + if (logical_block < index[i].ei_block)
- + break;
- + }
- + if (i == 0 || !ext2_rdfsb(index[i-1].ei_leaf, DATABLOCK1))
- + return NULL;
- + return (ext4_recurse_extent_index((struct ext4_extent_header *) DATABLOCK1, logical_block));
- +}
- +
- +
- /* from
- ext2/inode.c:ext2_bmap()
- */
- @@ -287,7 +347,6 @@ ext2_rdfsb (int fsblock, int buffer)
- static int
- ext2fs_block_map (int logical_block)
- {
- -
- #ifdef E2DEBUG
- unsigned char *i;
- for (i = (unsigned char *) INODE;
- @@ -308,82 +367,106 @@ ext2fs_block_map (int logical_block)
- printf ("logical block %d\n", logical_block);
- #endif /* E2DEBUG */
-
- - /* if it is directly pointed to by the inode, return that physical addr */
- - if (logical_block < EXT2_NDIR_BLOCKS)
- + if (!(INODE->i_flags & EXT4_EXTENTS_FL))
- {
- -#ifdef E2DEBUG
- - printf ("returning %d\n", (unsigned char *) (INODE->i_block[logical_block]));
- - printf ("returning %d\n", INODE->i_block[logical_block]);
- -#endif /* E2DEBUG */
- - return INODE->i_block[logical_block];
- - }
- - /* else */
- - logical_block -= EXT2_NDIR_BLOCKS;
- - /* try the indirect block */
- - if (logical_block < EXT2_ADDR_PER_BLOCK (SUPERBLOCK))
- - {
- - if (mapblock1 != 1
- - && !ext2_rdfsb (INODE->i_block[EXT2_IND_BLOCK], DATABLOCK1))
- - {
- - errnum = ERR_FSYS_CORRUPT;
- - return -1;
- - }
- - mapblock1 = 1;
- - return ((__u32 *) DATABLOCK1)[logical_block];
- - }
- - /* else */
- - logical_block -= EXT2_ADDR_PER_BLOCK (SUPERBLOCK);
- - /* now try the double indirect block */
- - if (logical_block < (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2)))
- - {
- - int bnum;
- - if (mapblock1 != 2
- - && !ext2_rdfsb (INODE->i_block[EXT2_DIND_BLOCK], DATABLOCK1))
- - {
- - errnum = ERR_FSYS_CORRUPT;
- - return -1;
- - }
- - mapblock1 = 2;
- - if ((bnum = (((__u32 *) DATABLOCK1)
- - [logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)]))
- - != mapblock2
- - && !ext2_rdfsb (bnum, DATABLOCK2))
- - {
- - errnum = ERR_FSYS_CORRUPT;
- - return -1;
- - }
- - mapblock2 = bnum;
- + /* if it is directly pointed to by the inode, return that physical addr */
- + if (logical_block < EXT2_NDIR_BLOCKS)
- + {
- +#ifdef E2DEBUG
- + printf ("returning %d\n", (unsigned char *) (INODE->i_block[logical_block]));
- + printf ("returning %d\n", INODE->i_block[logical_block]);
- +#endif /* E2DEBUG */
- + return INODE->i_block[logical_block];
- + }
- + /* else */
- + logical_block -= EXT2_NDIR_BLOCKS;
- + /* try the indirect block */
- + if (logical_block < EXT2_ADDR_PER_BLOCK (SUPERBLOCK))
- + {
- + if (mapblock1 != 1 && !ext2_rdfsb (INODE->i_block[EXT2_IND_BLOCK], DATABLOCK1))
- + {
- + errnum = ERR_FSYS_CORRUPT;
- + return -1;
- + }
- + mapblock1 = 1;
- + return ((__u32 *) DATABLOCK1)[logical_block];
- + }
- + /* else */
- + logical_block -= EXT2_ADDR_PER_BLOCK (SUPERBLOCK);
- + /* now try the double indirect block */
- + if (logical_block < (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2)))
- + {
- + int bnum;
- + if (mapblock1 != 2 && !ext2_rdfsb (INODE->i_block[EXT2_DIND_BLOCK], DATABLOCK1))
- + {
- + errnum = ERR_FSYS_CORRUPT;
- + return -1;
- + }
- + mapblock1 = 2;
- + if ((bnum = (((__u32 *) DATABLOCK1)
- + [logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)]))
- + != mapblock2
- + && !ext2_rdfsb (bnum, DATABLOCK2))
- + {
- + errnum = ERR_FSYS_CORRUPT;
- + return -1;
- + }
- + mapblock2 = bnum;
- + return ((__u32 *) DATABLOCK2)
- + [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
- + }
- + /* else */
- + mapblock2 = -1;
- + logical_block -= (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2));
- + if (mapblock1 != 3
- + && !ext2_rdfsb (INODE->i_block[EXT2_TIND_BLOCK], DATABLOCK1))
- + {
- + errnum = ERR_FSYS_CORRUPT;
- + return -1;
- + }
- + mapblock1 = 3;
- + if (!ext2_rdfsb (((__u32 *) DATABLOCK1)
- + [logical_block >> (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)
- + * 2)],
- + DATABLOCK2))
- + {
- + errnum = ERR_FSYS_CORRUPT;
- + return -1;
- + }
- + if (!ext2_rdfsb (((__u32 *) DATABLOCK2)
- + [(logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK))
- + & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)],
- + DATABLOCK2))
- + {
- + errnum = ERR_FSYS_CORRUPT;
- + return -1;
- + }
- +
- return ((__u32 *) DATABLOCK2)
- - [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
- + [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
- }
- - /* else */
- - mapblock2 = -1;
- - logical_block -= (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2));
- - if (mapblock1 != 3
- - && !ext2_rdfsb (INODE->i_block[EXT2_TIND_BLOCK], DATABLOCK1))
- - {
- - errnum = ERR_FSYS_CORRUPT;
- - return -1;
- - }
- - mapblock1 = 3;
- - if (!ext2_rdfsb (((__u32 *) DATABLOCK1)
- - [logical_block >> (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)
- - * 2)],
- - DATABLOCK2))
- - {
- - errnum = ERR_FSYS_CORRUPT;
- - return -1;
- - }
- - if (!ext2_rdfsb (((__u32 *) DATABLOCK2)
- - [(logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK))
- - & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)],
- - DATABLOCK2))
- + /* inode is in extents format */
- + else
- {
- + int i;
- + struct ext4_extent_header *extent_hdr =
- + ext4_recurse_extent_index((struct ext4_extent_header *) INODE->i_block, logical_block);
- + struct ext4_extent *extent = (struct ext4_extent *) (extent_hdr + 1);
- + if ( extent_hdr == NULL || extent_hdr->eh_magic != EXT4_EXT_MAGIC)
- + {
- + errnum = ERR_FSYS_CORRUPT;
- + return -1;
- + }
- + for (i = 0; i<extent_hdr->eh_entries; i++)
- + {
- + if (extent[i].ee_block <= logical_block && logical_block < extent[i].ee_block + extent[i].ee_len && !(extent[i].ee_len>>15))
- + return (logical_block - extent[i].ee_block + extent[i].ee_start);
- + }
- + /* We should not arrive here */
- +
- errnum = ERR_FSYS_CORRUPT;
- return -1;
- }
- - return ((__u32 *) DATABLOCK2)
- - [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
- }
-
- /* preconditions: all preconds of ext2fs_block_map */
|