2008-07-13 Bean <bean123ch@gmail.com>

* fs/ext2.c (EXT4_EXTENTS_FLAG): New macro.
	(grub_ext4_extent_header): New structure.
	(grub_ext4_extent): Likewise.
	(grub_ext4_extent_idx): Likewise.
	(grub_ext4_find_leaf): New function.
	(grub_ext2_read_block): Handle extents.
This commit is contained in:
bean 2008-07-13 01:13:12 +00:00
parent 9a745147b8
commit 4ae821ac9a
2 changed files with 121 additions and 0 deletions

View File

@ -1,3 +1,12 @@
2008-07-13 Bean <bean123ch@gmail.com>
* fs/ext2.c (EXT4_EXTENTS_FLAG): New macro.
(grub_ext4_extent_header): New structure.
(grub_ext4_extent): Likewise.
(grub_ext4_extent_idx): Likewise.
(grub_ext4_find_leaf): New function.
(grub_ext2_read_block): Handle extents.
2008-07-12 Robert Millan <rmh@aybabtu.com>
* util/i386/pc/grub-mkrescue.in: s/grub-install/grub-mkrescue/g.

112
fs/ext2.c
View File

@ -86,6 +86,8 @@
#define EXT3_JOURNAL_FLAG_DELETED 4
#define EXT3_JOURNAL_FLAG_LAST_TAG 8
#define EXT4_EXTENTS_FLAG 0x80000
/* The ext2 superblock. */
struct grub_ext2_sblock
{
@ -226,6 +228,33 @@ struct grub_ext3_journal_sblock
grub_uint32_t start;
};
#define EXT4_EXT_MAGIC 0xf30a
struct grub_ext4_extent_header
{
grub_uint16_t magic;
grub_uint16_t entries;
grub_uint16_t max;
grub_uint16_t depth;
grub_uint32_t generation;
};
struct grub_ext4_extent
{
grub_uint32_t block;
grub_uint16_t len;
grub_uint16_t start_hi;
grub_uint32_t start;
};
struct grub_ext4_extent_idx
{
grub_uint32_t block;
grub_uint32_t leaf;
grub_uint16_t leaf_hi;
grub_uint16_t unused;
};
struct grub_fshelp_node
{
struct grub_ext2_data *data;
@ -262,6 +291,45 @@ grub_ext2_blockgroup (struct grub_ext2_data *data, int group,
sizeof (struct grub_ext2_block_group), (char *) blkgrp);
}
static struct grub_ext4_extent_header *
grub_ext4_find_leaf (struct grub_ext2_data *data, char *buf,
struct grub_ext4_extent_header *ext_block,
grub_uint32_t fileblock)
{
struct grub_ext4_extent_idx *index;
while (1)
{
int i;
grub_disk_addr_t block;
index = (struct grub_ext4_extent_idx *) (ext_block + 1);
if (grub_le_to_cpu16(ext_block->magic) != EXT4_EXT_MAGIC)
return 0;
if (ext_block->depth == 0)
return ext_block;
for (i = 0; i < grub_le_to_cpu16 (ext_block->entries); i++)
{
if (fileblock < grub_le_to_cpu32(index[i].block))
break;
}
if (--i < 0)
return 0;
block = grub_le_to_cpu16 (index[i].leaf_hi);
block = (block << 32) + grub_le_to_cpu32 (index[i].leaf);
if (grub_disk_read (data->disk,
block << LOG2_EXT2_BLOCK_SIZE (data),
0, EXT2_BLOCK_SIZE(data), buf))
return 0;
ext_block = (struct grub_ext4_extent_header *) buf;
}
}
static grub_disk_addr_t
grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
@ -272,6 +340,50 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
unsigned int blksz = EXT2_BLOCK_SIZE (data);
int log2_blksz = LOG2_EXT2_BLOCK_SIZE (data);
if (inode->flags & EXT4_EXTENTS_FLAG)
{
char buf[EXT2_BLOCK_SIZE(data)];
struct grub_ext4_extent_header *leaf;
struct grub_ext4_extent *ext;
int i;
leaf = grub_ext4_find_leaf (data, buf,
(struct grub_ext4_extent_header *) inode->blocks.dir_blocks,
fileblock);
if (! leaf)
{
grub_error (GRUB_ERR_BAD_FS, "invalid extent");
return -1;
}
ext = (struct grub_ext4_extent *) (leaf + 1);
for (i = 0; i < grub_le_to_cpu16 (leaf->entries); i++)
{
if (fileblock < grub_le_to_cpu32 (ext[i].block))
break;
}
if (--i >= 0)
{
fileblock -= grub_le_to_cpu32 (ext[i].block);
if (fileblock >= grub_le_to_cpu16 (ext[i].len))
return 0;
else
{
grub_disk_addr_t start;
start = grub_le_to_cpu16 (ext[i].start_hi);
start = (start << 32) + grub_le_to_cpu32 (ext[i].start);
return fileblock + start;
}
}
else
{
grub_error (GRUB_ERR_BAD_FS, "something wrong with extent");
return -1;
}
}
/* Direct blocks. */
if (fileblock < INDIRECT_BLOCKS)
blknr = grub_le_to_cpu32 (inode->blocks.dir_blocks[fileblock]);