Fix AFFS with non-512B blocks.
* grub-core/fs/affs.c (grub_affs_rblock): Make type uint32_t. (AFFS_MAX_LOG_BLOCK_SIZE): New definition. (grub_affs_data): Replace blocksize with log_blocksize. (grub_affs_read_block): Fix non-512B blocks. (grub_affs_read_symlink): Likewise. (grub_affs_iterate_dir): Likewise. Fix freeing corruption. (grub_affs_read): Fix non-512B blocks. (grub_affs_label): Likewise. (grub_affs_mtime): Likewise. (grub_affs_mount): Fix block detection routine.
This commit is contained in:
parent
d20fab8471
commit
6ae485aaef
2 changed files with 83 additions and 40 deletions
15
ChangeLog
15
ChangeLog
|
@ -1,3 +1,18 @@
|
||||||
|
2012-05-08 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
|
Fix AFFS with non-512B blocks.
|
||||||
|
|
||||||
|
* grub-core/fs/affs.c (grub_affs_rblock): Make type uint32_t.
|
||||||
|
(AFFS_MAX_LOG_BLOCK_SIZE): New definition.
|
||||||
|
(grub_affs_data): Replace blocksize with log_blocksize.
|
||||||
|
(grub_affs_read_block): Fix non-512B blocks.
|
||||||
|
(grub_affs_read_symlink): Likewise.
|
||||||
|
(grub_affs_iterate_dir): Likewise. Fix freeing corruption.
|
||||||
|
(grub_affs_read): Fix non-512B blocks.
|
||||||
|
(grub_affs_label): Likewise.
|
||||||
|
(grub_affs_mtime): Likewise.
|
||||||
|
(grub_affs_mount): Fix block detection routine.
|
||||||
|
|
||||||
2012-05-08 Vladimir Serbinenko <phcoder@gmail.com>
|
2012-05-08 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
Add filesystem mtime to AFFS.
|
Add filesystem mtime to AFFS.
|
||||||
|
|
|
@ -45,7 +45,7 @@ struct grub_affs_bblock
|
||||||
/* The affs rootblock. */
|
/* The affs rootblock. */
|
||||||
struct grub_affs_rblock
|
struct grub_affs_rblock
|
||||||
{
|
{
|
||||||
grub_uint8_t type[4];
|
grub_uint32_t type;
|
||||||
grub_uint8_t unused1[8];
|
grub_uint8_t unused1[8];
|
||||||
grub_uint32_t htsize;
|
grub_uint32_t htsize;
|
||||||
grub_uint32_t unused2;
|
grub_uint32_t unused2;
|
||||||
|
@ -89,6 +89,9 @@ struct grub_affs_file
|
||||||
#define GRUB_AFFS_FILETYPE_REG 0xfffffffd
|
#define GRUB_AFFS_FILETYPE_REG 0xfffffffd
|
||||||
#define GRUB_AFFS_FILETYPE_DIR 2
|
#define GRUB_AFFS_FILETYPE_DIR 2
|
||||||
#define GRUB_AFFS_FILETYPE_SYMLINK 3
|
#define GRUB_AFFS_FILETYPE_SYMLINK 3
|
||||||
|
|
||||||
|
#define AFFS_MAX_LOG_BLOCK_SIZE 4
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct grub_fshelp_node
|
struct grub_fshelp_node
|
||||||
|
@ -108,11 +111,11 @@ struct grub_affs_data
|
||||||
struct grub_fshelp_node diropen;
|
struct grub_fshelp_node diropen;
|
||||||
grub_disk_t disk;
|
grub_disk_t disk;
|
||||||
|
|
||||||
/* Blocksize in sectors. */
|
/* Log blocksize in sectors. */
|
||||||
int blocksize;
|
int log_blocksize;
|
||||||
|
|
||||||
/* The number of entries in the hashtable. */
|
/* The number of entries in the hashtable. */
|
||||||
int htsize;
|
unsigned int htsize;
|
||||||
};
|
};
|
||||||
|
|
||||||
static grub_dl_t my_mod;
|
static grub_dl_t my_mod;
|
||||||
|
@ -130,7 +133,8 @@ grub_affs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
|
||||||
if (!node->block_cache)
|
if (!node->block_cache)
|
||||||
{
|
{
|
||||||
node->block_cache = grub_malloc (((grub_be_to_cpu32 (node->di.size)
|
node->block_cache = grub_malloc (((grub_be_to_cpu32 (node->di.size)
|
||||||
>> 9) / data->htsize + 2)
|
>> (9 + node->data->log_blocksize))
|
||||||
|
/ data->htsize + 2)
|
||||||
* sizeof (node->block_cache[0]));
|
* sizeof (node->block_cache[0]));
|
||||||
if (!node->block_cache)
|
if (!node->block_cache)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -146,9 +150,9 @@ grub_affs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
|
||||||
for (curblock = node->last_block_cache + 1; curblock < target + 1; curblock++)
|
for (curblock = node->last_block_cache + 1; curblock < target + 1; curblock++)
|
||||||
{
|
{
|
||||||
grub_disk_read (data->disk,
|
grub_disk_read (data->disk,
|
||||||
node->block_cache[curblock - 1] + data->blocksize - 1,
|
(((grub_uint64_t) node->block_cache[curblock - 1] + 1)
|
||||||
data->blocksize * (GRUB_DISK_SECTOR_SIZE
|
<< data->log_blocksize) - 1,
|
||||||
- GRUB_AFFS_FILE_LOCATION),
|
GRUB_DISK_SECTOR_SIZE - GRUB_AFFS_FILE_LOCATION,
|
||||||
sizeof (file), &file);
|
sizeof (file), &file);
|
||||||
if (grub_errno)
|
if (grub_errno)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -158,7 +162,8 @@ grub_affs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Translate the fileblock to the block within the right table. */
|
/* Translate the fileblock to the block within the right table. */
|
||||||
grub_disk_read (data->disk, node->block_cache[target],
|
grub_disk_read (data->disk, (grub_uint64_t) node->block_cache[target]
|
||||||
|
<< data->log_blocksize,
|
||||||
GRUB_AFFS_BLOCKPTR_OFFSET
|
GRUB_AFFS_BLOCKPTR_OFFSET
|
||||||
+ (data->htsize - mod - 1) * sizeof (pos),
|
+ (data->htsize - mod - 1) * sizeof (pos),
|
||||||
sizeof (pos), &pos);
|
sizeof (pos), &pos);
|
||||||
|
@ -174,9 +179,7 @@ grub_affs_mount (grub_disk_t disk)
|
||||||
struct grub_affs_data *data;
|
struct grub_affs_data *data;
|
||||||
grub_uint32_t *rootblock = 0;
|
grub_uint32_t *rootblock = 0;
|
||||||
struct grub_affs_rblock *rblock;
|
struct grub_affs_rblock *rblock;
|
||||||
|
int log_blocksize = 0;
|
||||||
int checksum = 0;
|
|
||||||
int blocksize = 0;
|
|
||||||
|
|
||||||
data = grub_zalloc (sizeof (struct grub_affs_data));
|
data = grub_zalloc (sizeof (struct grub_affs_data));
|
||||||
if (!data)
|
if (!data)
|
||||||
|
@ -204,40 +207,52 @@ grub_affs_mount (grub_disk_t disk)
|
||||||
|
|
||||||
/* No sane person uses more than 8KB for a block. At least I hope
|
/* No sane person uses more than 8KB for a block. At least I hope
|
||||||
for that person because in that case this won't work. */
|
for that person because in that case this won't work. */
|
||||||
rootblock = grub_malloc (GRUB_DISK_SECTOR_SIZE * 16);
|
rootblock = grub_malloc (GRUB_DISK_SECTOR_SIZE << AFFS_MAX_LOG_BLOCK_SIZE);
|
||||||
if (!rootblock)
|
if (!rootblock)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
rblock = (struct grub_affs_rblock *) rootblock;
|
rblock = (struct grub_affs_rblock *) rootblock;
|
||||||
|
|
||||||
/* Read the rootblock. */
|
|
||||||
grub_disk_read (disk, grub_be_to_cpu32 (data->bblock.rootblock), 0,
|
|
||||||
GRUB_DISK_SECTOR_SIZE * 16, rootblock);
|
|
||||||
if (grub_errno)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
/* The filesystem blocksize is not stored anywhere in the filesystem
|
/* The filesystem blocksize is not stored anywhere in the filesystem
|
||||||
itself. One way to determine it is reading blocks for the
|
itself. One way to determine it is try reading blocks for the
|
||||||
rootblock until the checksum is correct. */
|
rootblock until the checksum is correct. */
|
||||||
for (blocksize = 0; blocksize < 8; blocksize++)
|
for (log_blocksize = 0; log_blocksize <= AFFS_MAX_LOG_BLOCK_SIZE;
|
||||||
|
log_blocksize++)
|
||||||
{
|
{
|
||||||
grub_uint32_t *currblock = rootblock + GRUB_DISK_SECTOR_SIZE * blocksize;
|
grub_uint32_t *currblock = rootblock;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
grub_uint32_t checksum = 0;
|
||||||
|
|
||||||
for (i = 0; i < GRUB_DISK_SECTOR_SIZE / sizeof (*currblock); i++)
|
/* Read the rootblock. */
|
||||||
|
grub_disk_read (disk,
|
||||||
|
(grub_uint64_t) grub_be_to_cpu32 (data->bblock.rootblock)
|
||||||
|
<< log_blocksize, 0,
|
||||||
|
GRUB_DISK_SECTOR_SIZE << log_blocksize, rootblock);
|
||||||
|
if (grub_errno)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (rblock->type != grub_cpu_to_be32_compile_time (2)
|
||||||
|
|| rblock->htsize == 0
|
||||||
|
|| currblock[(GRUB_DISK_SECTOR_SIZE << log_blocksize)
|
||||||
|
/ sizeof (*currblock) - 1]
|
||||||
|
!= grub_cpu_to_be32_compile_time (1))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (i = 0; i < (GRUB_DISK_SECTOR_SIZE << log_blocksize)
|
||||||
|
/ sizeof (*currblock);
|
||||||
|
i++)
|
||||||
checksum += grub_be_to_cpu32 (currblock[i]);
|
checksum += grub_be_to_cpu32 (currblock[i]);
|
||||||
|
|
||||||
if (checksum == 0)
|
if (checksum == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (checksum != 0)
|
if (log_blocksize > AFFS_MAX_LOG_BLOCK_SIZE)
|
||||||
{
|
{
|
||||||
grub_error (GRUB_ERR_BAD_FS, "AFFS blocksize couldn't be determined");
|
grub_error (GRUB_ERR_BAD_FS, "AFFS blocksize couldn't be determined");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
blocksize++;
|
|
||||||
|
|
||||||
data->blocksize = blocksize;
|
data->log_blocksize = log_blocksize;
|
||||||
data->disk = disk;
|
data->disk = disk;
|
||||||
data->htsize = grub_be_to_cpu32 (rblock->htsize);
|
data->htsize = grub_be_to_cpu32 (rblock->htsize);
|
||||||
data->diropen.data = data;
|
data->diropen.data = data;
|
||||||
|
@ -264,14 +279,16 @@ grub_affs_read_symlink (grub_fshelp_node_t node)
|
||||||
{
|
{
|
||||||
struct grub_affs_data *data = node->data;
|
struct grub_affs_data *data = node->data;
|
||||||
grub_uint8_t *latin1, *utf8;
|
grub_uint8_t *latin1, *utf8;
|
||||||
const grub_size_t symlink_size = (data->blocksize * GRUB_DISK_SECTOR_SIZE
|
const grub_size_t symlink_size = ((GRUB_DISK_SECTOR_SIZE
|
||||||
- 225);
|
<< data->log_blocksize) - 225);
|
||||||
|
|
||||||
latin1 = grub_malloc (symlink_size);
|
latin1 = grub_malloc (symlink_size);
|
||||||
if (!latin1)
|
if (!latin1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
grub_disk_read (data->disk, node->block, GRUB_AFFS_SYMLINK_OFFSET,
|
grub_disk_read (data->disk,
|
||||||
|
(grub_uint64_t) node->block << data->log_blocksize,
|
||||||
|
GRUB_AFFS_SYMLINK_OFFSET,
|
||||||
symlink_size, latin1);
|
symlink_size, latin1);
|
||||||
if (grub_errno)
|
if (grub_errno)
|
||||||
{
|
{
|
||||||
|
@ -298,7 +315,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
||||||
enum grub_fshelp_filetype filetype,
|
enum grub_fshelp_filetype filetype,
|
||||||
grub_fshelp_node_t node))
|
grub_fshelp_node_t node))
|
||||||
{
|
{
|
||||||
int i;
|
unsigned int i;
|
||||||
struct grub_affs_file file;
|
struct grub_affs_file file;
|
||||||
struct grub_fshelp_node *node = 0;
|
struct grub_fshelp_node *node = 0;
|
||||||
struct grub_affs_data *data = dir->data;
|
struct grub_affs_data *data = dir->data;
|
||||||
|
@ -345,8 +362,10 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
||||||
if (hook ((char *) name_u8, type, node))
|
if (hook ((char *) name_u8, type, node))
|
||||||
{
|
{
|
||||||
grub_free (hashtable);
|
grub_free (hashtable);
|
||||||
|
node = 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
node = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -372,7 +391,9 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
||||||
if (!hashtable)
|
if (!hashtable)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
grub_disk_read (data->disk, dir->block, GRUB_AFFS_HASHTABLE_OFFSET,
|
grub_disk_read (data->disk,
|
||||||
|
(grub_uint64_t) dir->block << data->log_blocksize,
|
||||||
|
GRUB_AFFS_HASHTABLE_OFFSET,
|
||||||
data->htsize * sizeof (*hashtable), (char *) hashtable);
|
data->htsize * sizeof (*hashtable), (char *) hashtable);
|
||||||
if (grub_errno)
|
if (grub_errno)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -390,9 +411,10 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
||||||
|
|
||||||
while (next)
|
while (next)
|
||||||
{
|
{
|
||||||
grub_disk_read (data->disk, next + data->blocksize - 1,
|
grub_disk_read (data->disk,
|
||||||
data->blocksize * GRUB_DISK_SECTOR_SIZE
|
(((grub_uint64_t) next + 1) << data->log_blocksize)
|
||||||
- GRUB_AFFS_FILE_LOCATION,
|
- 1,
|
||||||
|
GRUB_DISK_SECTOR_SIZE - GRUB_AFFS_FILE_LOCATION,
|
||||||
sizeof (file), (char *) &file);
|
sizeof (file), (char *) &file);
|
||||||
if (grub_errno)
|
if (grub_errno)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -475,7 +497,8 @@ grub_affs_read (grub_file_t file, char *buf, grub_size_t len)
|
||||||
return grub_fshelp_read_file (data->diropen.data->disk, &data->diropen,
|
return grub_fshelp_read_file (data->diropen.data->disk, &data->diropen,
|
||||||
file->read_hook,
|
file->read_hook,
|
||||||
file->offset, len, buf, grub_affs_read_block,
|
file->offset, len, buf, grub_affs_read_block,
|
||||||
grub_be_to_cpu32 (data->diropen.di.size), 0);
|
grub_be_to_cpu32 (data->diropen.di.size),
|
||||||
|
data->log_blocksize);
|
||||||
}
|
}
|
||||||
|
|
||||||
static grub_int32_t
|
static grub_int32_t
|
||||||
|
@ -551,9 +574,11 @@ grub_affs_label (grub_device_t device, char **label)
|
||||||
grub_size_t len;
|
grub_size_t len;
|
||||||
/* The rootblock maps quite well on a file header block, it's
|
/* The rootblock maps quite well on a file header block, it's
|
||||||
something we can use here. */
|
something we can use here. */
|
||||||
grub_disk_read (data->disk, grub_be_to_cpu32 (data->bblock.rootblock),
|
grub_disk_read (data->disk,
|
||||||
data->blocksize * (GRUB_DISK_SECTOR_SIZE
|
(((grub_uint64_t)
|
||||||
- GRUB_AFFS_FILE_LOCATION),
|
grub_be_to_cpu32 (data->bblock.rootblock) + 1)
|
||||||
|
<< data->log_blocksize) - 1,
|
||||||
|
GRUB_DISK_SECTOR_SIZE - GRUB_AFFS_FILE_LOCATION,
|
||||||
sizeof (file), &file);
|
sizeof (file), &file);
|
||||||
if (grub_errno)
|
if (grub_errno)
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
|
@ -591,8 +616,11 @@ grub_affs_mtime (grub_device_t device, grub_int32_t *t)
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
grub_disk_read (data->disk, grub_be_to_cpu32 (data->bblock.rootblock),
|
grub_disk_read (data->disk,
|
||||||
data->blocksize * GRUB_DISK_SECTOR_SIZE - 40,
|
(((grub_uint64_t)
|
||||||
|
grub_be_to_cpu32 (data->bblock.rootblock) + 1)
|
||||||
|
<< data->log_blocksize) - 1,
|
||||||
|
GRUB_DISK_SECTOR_SIZE - 40,
|
||||||
sizeof (af_time), &af_time);
|
sizeof (af_time), &af_time);
|
||||||
if (grub_errno)
|
if (grub_errno)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue