* 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> 2011-10-15 Robert Millan <rmh@gnu.org>
* util/getroot.c (grub_util_get_grub_dev): Fix OS selection #ifdefs. * 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_uint64_t nblocks;
grub_uint32_t extsize; grub_uint32_t extsize;
grub_uint32_t nextents; grub_uint32_t nextents;
grub_uint8_t unused3[20]; grub_uint16_t unused3;
grub_uint8_t fork_offset;
grub_uint8_t unused4[17];
union union
{ {
char raw[156]; char raw[156];
@ -154,7 +156,7 @@ struct grub_xfs_data
grub_disk_t disk; grub_disk_t disk;
int pos; int pos;
int bsize; int bsize;
int agsize; grub_uint32_t agsize;
struct grub_fshelp_node diropen; struct grub_fshelp_node diropen;
}; };
@ -168,33 +170,67 @@ static grub_dl_t my_mod;
#define FILETYPE_INO_DIRECTORY 0040000 #define FILETYPE_INO_DIRECTORY 0040000
#define FILETYPE_INO_SYMLINK 0120000 #define FILETYPE_INO_SYMLINK 0120000
#define GRUB_XFS_INO_AGBITS(data) \ static inline int
((data)->sblock.log2_agblk + (data)->sblock.log2_inop) GRUB_XFS_INO_AGBITS(struct grub_xfs_data *data)
#define GRUB_XFS_INO_INOINAG(data, ino) \ {
(grub_be_to_cpu64 (ino) & ((1LL << GRUB_XFS_INO_AGBITS (data)) - 1)) return ((data)->sblock.log2_agblk + (data)->sblock.log2_inop);
#define GRUB_XFS_INO_AG(data,ino) \ }
(grub_be_to_cpu64 (ino) >> GRUB_XFS_INO_AGBITS (data))
#define GRUB_XFS_FSB_TO_BLOCK(data, fsb) \ static inline grub_uint64_t
(((fsb) >> (data)->sblock.log2_agblk) * (data)->agsize \ GRUB_XFS_INO_INOINAG (struct grub_xfs_data *data,
+ ((fsb) & ((1LL << (data)->sblock.log2_agblk) - 1))) grub_uint64_t ino)
{
return (grub_be_to_cpu64 (ino) & ((1LL << GRUB_XFS_INO_AGBITS (data)) - 1));
}
#define GRUB_XFS_EXTENT_OFFSET(exts,ex) \ static inline grub_uint64_t
((grub_be_to_cpu32 (exts[ex][0]) & ~(1 << 31)) << 23 \ GRUB_XFS_INO_AG (struct grub_xfs_data *data,
| grub_be_to_cpu32 (exts[ex][1]) >> 9) grub_uint64_t ino)
{
return (grub_be_to_cpu64 (ino) >> GRUB_XFS_INO_AGBITS (data));
}
#define GRUB_XFS_EXTENT_BLOCK(exts,ex) \ static inline grub_disk_addr_t
((grub_uint64_t) (grub_be_to_cpu32 (exts[ex][1]) \ GRUB_XFS_FSB_TO_BLOCK (struct grub_xfs_data *data, grub_disk_addr_t fsb)
& (0x1ff)) << 43 \ {
| (grub_uint64_t) grub_be_to_cpu32 (exts[ex][2]) << 11 \ return ((fsb >> data->sblock.log2_agblk) * data->agsize
| grub_be_to_cpu32 (exts[ex][3]) >> 21) + (fsb & ((1LL << data->sblock.log2_agblk) - 1)));
}
#define GRUB_XFS_EXTENT_SIZE(exts,ex) \ static inline grub_uint64_t
(grub_be_to_cpu32 (exts[ex][3]) & ((1 << 20) - 1)) 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 static inline grub_uint64_t
grub_xfs_inode_block (struct grub_xfs_data *data, 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) if (node->inode.format == XFS_INODE_FORMAT_BTREE)
{ {
grub_uint64_t *keys; grub_uint64_t *keys;
int recoffset;
leaf = grub_malloc (node->data->sblock.bsize); leaf = grub_malloc (node->data->bsize);
if (leaf == 0) if (leaf == 0)
return 0; return 0;
nrec = grub_be_to_cpu16 (node->inode.data.btree.numrecs); nrec = grub_be_to_cpu16 (node->inode.data.btree.numrecs);
keys = &node->inode.data.btree.keys[0]; 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 do
{ {
int i; int i;
@ -273,12 +319,9 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
grub_free (leaf); grub_free (leaf);
return 0; return 0;
} }
if (grub_disk_read (node->data->disk, if (grub_disk_read (node->data->disk,
grub_be_to_cpu64 (keys[i - 1 + nrec]) GRUB_XFS_FSB_TO_BLOCK (node->data, grub_be_to_cpu64 (keys[i - 1 + recoffset])) << (node->data->sblock.log2_bsize - GRUB_DISK_SECTOR_BITS),
<< (node->data->sblock.log2_bsize 0, node->data->bsize, leaf))
- GRUB_DISK_SECTOR_BITS),
0, node->data->sblock.bsize, leaf))
return 0; return 0;
if (grub_strncmp ((char *) leaf->magic, "BMAP", 4)) 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); nrec = grub_be_to_cpu16 (leaf->numrecs);
keys = &leaf->keys[0]; 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; exts = (grub_xfs_extent *) keys;
} }
else if (node->inode.format == XFS_INODE_FORMAT_EXT) 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, grub_xfs_read_file (grub_fshelp_node_t node,
void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector, void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
unsigned offset, unsigned length), 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, return grub_fshelp_read_file (node->data->disk, node, read_hook,
pos, len, buf, grub_xfs_read_block, pos, len, buf, grub_xfs_read_block,