* grub-core/fs/xfs.c (grub_xfs_inode): New field fork_offset.

(GRUB_XFS_INO_AGBITS): Make into inline function.
	(GRUB_XFS_INO_INOINAG): Likewise.
	(GRUB_XFS_INO_AG): Likewise.
	(GRUB_XFS_FSB_TO_BLOCK): Likewise.
	(GRUB_XFS_EXTENT_OFFSET): Likewise.
	(GRUB_XFS_EXTENT_BLOCK): Likewise.
	(GRUB_XFS_EXTENT_SIZE): Likewise.
	(GRUB_XFS_ROUND_TO_DIRENT): Likewise.
	(GRUB_XFS_NEXT_DIRENT): Likewise.
	(grub_xfs_read_block): Rewrite the btree parsing. Fixes invalid BMAP.
	(grub_xfs_read_file): Fix offset type.
This commit is contained in:
Vladimir 'phcoder' Serbinenko 2011-10-16 11:48:54 +02:00
parent 8bcebcb8e4
commit 3b619ae116
2 changed files with 94 additions and 32 deletions

View file

@ -1,3 +1,18 @@
2011-10-16 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/fs/xfs.c (grub_xfs_inode): New field fork_offset.
(GRUB_XFS_INO_AGBITS): Make into inline function.
(GRUB_XFS_INO_INOINAG): Likewise.
(GRUB_XFS_INO_AG): Likewise.
(GRUB_XFS_FSB_TO_BLOCK): Likewise.
(GRUB_XFS_EXTENT_OFFSET): Likewise.
(GRUB_XFS_EXTENT_BLOCK): Likewise.
(GRUB_XFS_EXTENT_SIZE): Likewise.
(GRUB_XFS_ROUND_TO_DIRENT): Likewise.
(GRUB_XFS_NEXT_DIRENT): Likewise.
(grub_xfs_read_block): Rewrite the btree parsing. Fixes invalid BMAP.
(grub_xfs_read_file): Fix offset type.
2011-10-15 Robert Millan <rmh@gnu.org>
* util/getroot.c (grub_util_get_grub_dev): Fix OS selection #ifdefs.

View file

@ -120,7 +120,9 @@ struct grub_xfs_inode
grub_uint64_t nblocks;
grub_uint32_t extsize;
grub_uint32_t nextents;
grub_uint8_t unused3[20];
grub_uint16_t unused3;
grub_uint8_t fork_offset;
grub_uint8_t unused4[17];
union
{
char raw[156];
@ -154,7 +156,7 @@ struct grub_xfs_data
grub_disk_t disk;
int pos;
int bsize;
int agsize;
grub_uint32_t agsize;
struct grub_fshelp_node diropen;
};
@ -168,33 +170,67 @@ static grub_dl_t my_mod;
#define FILETYPE_INO_DIRECTORY 0040000
#define FILETYPE_INO_SYMLINK 0120000
#define GRUB_XFS_INO_AGBITS(data) \
((data)->sblock.log2_agblk + (data)->sblock.log2_inop)
#define GRUB_XFS_INO_INOINAG(data, ino) \
(grub_be_to_cpu64 (ino) & ((1LL << GRUB_XFS_INO_AGBITS (data)) - 1))
#define GRUB_XFS_INO_AG(data,ino) \
(grub_be_to_cpu64 (ino) >> GRUB_XFS_INO_AGBITS (data))
static inline int
GRUB_XFS_INO_AGBITS(struct grub_xfs_data *data)
{
return ((data)->sblock.log2_agblk + (data)->sblock.log2_inop);
}
#define GRUB_XFS_FSB_TO_BLOCK(data, fsb) \
(((fsb) >> (data)->sblock.log2_agblk) * (data)->agsize \
+ ((fsb) & ((1LL << (data)->sblock.log2_agblk) - 1)))
static inline grub_uint64_t
GRUB_XFS_INO_INOINAG (struct grub_xfs_data *data,
grub_uint64_t ino)
{
return (grub_be_to_cpu64 (ino) & ((1LL << GRUB_XFS_INO_AGBITS (data)) - 1));
}
#define GRUB_XFS_EXTENT_OFFSET(exts,ex) \
((grub_be_to_cpu32 (exts[ex][0]) & ~(1 << 31)) << 23 \
| grub_be_to_cpu32 (exts[ex][1]) >> 9)
static inline grub_uint64_t
GRUB_XFS_INO_AG (struct grub_xfs_data *data,
grub_uint64_t ino)
{
return (grub_be_to_cpu64 (ino) >> GRUB_XFS_INO_AGBITS (data));
}
#define GRUB_XFS_EXTENT_BLOCK(exts,ex) \
((grub_uint64_t) (grub_be_to_cpu32 (exts[ex][1]) \
& (0x1ff)) << 43 \
| (grub_uint64_t) grub_be_to_cpu32 (exts[ex][2]) << 11 \
| grub_be_to_cpu32 (exts[ex][3]) >> 21)
static inline grub_disk_addr_t
GRUB_XFS_FSB_TO_BLOCK (struct grub_xfs_data *data, grub_disk_addr_t fsb)
{
return ((fsb >> data->sblock.log2_agblk) * data->agsize
+ (fsb & ((1LL << data->sblock.log2_agblk) - 1)));
}
#define GRUB_XFS_EXTENT_SIZE(exts,ex) \
(grub_be_to_cpu32 (exts[ex][3]) & ((1 << 20) - 1))
static inline grub_uint64_t
GRUB_XFS_EXTENT_OFFSET (grub_xfs_extent *exts, int ex)
{
return ((grub_be_to_cpu32 (exts[ex][0]) & ~(1 << 31)) << 23
| grub_be_to_cpu32 (exts[ex][1]) >> 9);
}
static inline grub_uint64_t
GRUB_XFS_EXTENT_BLOCK (grub_xfs_extent *exts, int ex)
{
return ((grub_uint64_t) (grub_be_to_cpu32 (exts[ex][1])
& (0x1ff)) << 43
| (grub_uint64_t) grub_be_to_cpu32 (exts[ex][2]) << 11
| grub_be_to_cpu32 (exts[ex][3]) >> 21);
}
static inline grub_uint64_t
GRUB_XFS_EXTENT_SIZE (grub_xfs_extent *exts, int ex)
{
return (grub_be_to_cpu32 (exts[ex][3]) & ((1 << 20) - 1));
}
static inline int
GRUB_XFS_ROUND_TO_DIRENT (int pos)
{
return ((((pos) + 8 - 1) / 8) * 8);
}
static inline int
GRUB_XFS_NEXT_DIRENT (int pos, int len)
{
return (pos) + GRUB_XFS_ROUND_TO_DIRENT (8 + 1 + len + 2);
}
#define GRUB_XFS_ROUND_TO_DIRENT(pos) ((((pos) + 8 - 1) / 8) * 8)
#define GRUB_XFS_NEXT_DIRENT(pos,len) \
(pos) + GRUB_XFS_ROUND_TO_DIRENT (8 + 1 + len + 2)
static inline grub_uint64_t
grub_xfs_inode_block (struct grub_xfs_data *data,
@ -250,13 +286,23 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
if (node->inode.format == XFS_INODE_FORMAT_BTREE)
{
grub_uint64_t *keys;
int recoffset;
leaf = grub_malloc (node->data->sblock.bsize);
leaf = grub_malloc (node->data->bsize);
if (leaf == 0)
return 0;
nrec = grub_be_to_cpu16 (node->inode.data.btree.numrecs);
keys = &node->inode.data.btree.keys[0];
if (node->inode.fork_offset)
recoffset = (node->inode.fork_offset
- ((char *) &node->inode.data.btree.keys - (char *) &node->inode))
/ (2 * sizeof (grub_uint64_t));
else
recoffset = ((1 << node->data->sblock.log2_inode)
- ((char *) &node->inode.data.btree.keys
- (char *) &node->inode))
/ (2 * sizeof (grub_uint64_t));
do
{
int i;
@ -273,12 +319,9 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
grub_free (leaf);
return 0;
}
if (grub_disk_read (node->data->disk,
grub_be_to_cpu64 (keys[i - 1 + nrec])
<< (node->data->sblock.log2_bsize
- GRUB_DISK_SECTOR_BITS),
0, node->data->sblock.bsize, leaf))
GRUB_XFS_FSB_TO_BLOCK (node->data, grub_be_to_cpu64 (keys[i - 1 + recoffset])) << (node->data->sblock.log2_bsize - GRUB_DISK_SECTOR_BITS),
0, node->data->bsize, leaf))
return 0;
if (grub_strncmp ((char *) leaf->magic, "BMAP", 4))
@ -290,7 +333,11 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
nrec = grub_be_to_cpu16 (leaf->numrecs);
keys = &leaf->keys[0];
} while (leaf->level);
recoffset = ((node->data->bsize - ((char *) &leaf->keys
- (char *) leaf))
/ (2 * sizeof (grub_uint64_t)));
}
while (leaf->level);
exts = (grub_xfs_extent *) keys;
}
else if (node->inode.format == XFS_INODE_FORMAT_EXT)
@ -336,7 +383,7 @@ static grub_ssize_t
grub_xfs_read_file (grub_fshelp_node_t node,
void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
unsigned offset, unsigned length),
int pos, grub_size_t len, char *buf)
grub_off_t pos, grub_size_t len, char *buf)
{
return grub_fshelp_read_file (node->data->disk, node, read_hook,
pos, len, buf, grub_xfs_read_block,