* grub-core/fs/ufs.c (grub_ufs_get_file_block): Support triple indirect.

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2012-05-03 09:25:25 +02:00
parent 59fd2aacd0
commit c82f16c1be
2 changed files with 49 additions and 12 deletions

View file

@ -1,3 +1,7 @@
2012-05-03 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/fs/ufs.c (grub_ufs_get_file_block): Support triple indirect.
2012-05-03 Vladimir Serbinenko <phcoder@gmail.com> 2012-05-03 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/fs/ufs.c (grub_ufs_lookup_symlink): Use proper check for * grub-core/fs/ufs.c (grub_ufs_lookup_symlink): Use proper check for

View file

@ -65,9 +65,9 @@ GRUB_MOD_LICENSE ("GPLv3+");
#define INODE_MODE(data) INODE_ENDIAN (data,mode,16,16) #define INODE_MODE(data) INODE_ENDIAN (data,mode,16,16)
#ifdef MODE_UFS2 #ifdef MODE_UFS2
#define INODE_BLKSZ 8 #define LOG_INODE_BLKSZ 3
#else #else
#define INODE_BLKSZ 4 #define LOG_INODE_BLKSZ 2
#endif #endif
#ifdef MODE_UFS2 #ifdef MODE_UFS2
#define UFS_INODE_PER_BLOCK 2 #define UFS_INODE_PER_BLOCK 2
@ -227,11 +227,11 @@ static grub_err_t grub_ufs_find_file (struct grub_ufs_data *data,
static grub_disk_addr_t static grub_disk_addr_t
grub_ufs_get_file_block (struct grub_ufs_data *data, unsigned int blk) grub_ufs_get_file_block (struct grub_ufs_data *data, grub_disk_addr_t blk)
{ {
struct grub_ufs_sblock *sblock = &data->sblock; struct grub_ufs_sblock *sblock = &data->sblock;
unsigned int indirsz; unsigned long indirsz;
int log2_blksz; int log2_blksz, log_indirsz;
/* Direct. */ /* Direct. */
if (blk < GRUB_UFS_DIRBLKS) if (blk < GRUB_UFS_DIRBLKS)
@ -241,7 +241,8 @@ grub_ufs_get_file_block (struct grub_ufs_data *data, unsigned int blk)
blk -= GRUB_UFS_DIRBLKS; blk -= GRUB_UFS_DIRBLKS;
indirsz = UFS_BLKSZ (sblock) / INODE_BLKSZ; log_indirsz = data->log2_blksz - LOG_INODE_BLKSZ;
indirsz = 1 << log_indirsz;
/* Single indirect block. */ /* Single indirect block. */
if (blk < indirsz) if (blk < indirsz)
{ {
@ -250,14 +251,16 @@ grub_ufs_get_file_block (struct grub_ufs_data *data, unsigned int blk)
#else #else
grub_uint32_t indir[UFS_BLKSZ (sblock) / sizeof (grub_uint32_t)]; grub_uint32_t indir[UFS_BLKSZ (sblock) / sizeof (grub_uint32_t)];
#endif #endif
grub_disk_read (data->disk, INODE_INDIRBLOCKS (data, 0) << log2_blksz, grub_disk_read (data->disk,
((grub_disk_addr_t) INODE_INDIRBLOCKS (data, 0))
<< log2_blksz,
0, sizeof (indir), indir); 0, sizeof (indir), indir);
return indir[blk]; return indir[blk];
} }
blk -= indirsz; blk -= indirsz;
/* Double indirect block. */ /* Double indirect block. */
if (blk < indirsz * indirsz) if (blk < (grub_disk_addr_t) indirsz * (grub_disk_addr_t) indirsz)
{ {
#ifdef MODE_UFS2 #ifdef MODE_UFS2
grub_uint64_t indir[UFS_BLKSZ (sblock) / sizeof (grub_uint64_t)]; grub_uint64_t indir[UFS_BLKSZ (sblock) / sizeof (grub_uint64_t)];
@ -265,19 +268,49 @@ grub_ufs_get_file_block (struct grub_ufs_data *data, unsigned int blk)
grub_uint32_t indir[UFS_BLKSZ (sblock) / sizeof (grub_uint32_t)]; grub_uint32_t indir[UFS_BLKSZ (sblock) / sizeof (grub_uint32_t)];
#endif #endif
grub_disk_read (data->disk, INODE_INDIRBLOCKS (data, 1) << log2_blksz, grub_disk_read (data->disk,
((grub_disk_addr_t) INODE_INDIRBLOCKS (data, 1))
<< log2_blksz,
0, sizeof (indir), indir); 0, sizeof (indir), indir);
grub_disk_read (data->disk, grub_disk_read (data->disk,
(indir [blk / indirsz]) ((grub_disk_addr_t) indir [blk >> log_indirsz])
<< log2_blksz, << log2_blksz,
0, sizeof (indir), indir); 0, sizeof (indir), indir);
return indir[blk % indirsz]; return indir[blk & ((1 << log_indirsz) - 1)];
} }
blk -= (grub_disk_addr_t) indirsz * (grub_disk_addr_t) indirsz;
/* Triple indirect block. */
if (!(blk >> (3 * log_indirsz)))
{
#ifdef MODE_UFS2
grub_uint64_t indir[UFS_BLKSZ (sblock) / sizeof (grub_uint64_t)];
#else
grub_uint32_t indir[UFS_BLKSZ (sblock) / sizeof (grub_uint32_t)];
#endif
grub_disk_read (data->disk,
((grub_disk_addr_t) INODE_INDIRBLOCKS (data, 2))
<< log2_blksz,
0, sizeof (indir), indir);
grub_disk_read (data->disk,
((grub_disk_addr_t) indir [blk >> (2 * log_indirsz)])
<< log2_blksz,
0, sizeof (indir), indir);
grub_disk_read (data->disk,
((grub_disk_addr_t) indir [(blk >> log_indirsz)
& ((1 << log_indirsz) - 1)])
<< log2_blksz,
0, sizeof (indir), indir);
return indir[blk & ((1 << log_indirsz) - 1)];
}
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"ufs does not support triple indirect blocks"); "ufs does not support quadruple indirect blocks");
return 0; return 0;
} }