* grub-core/fs/affs.c (grub_affs_mount): Support AFFS bootblock in

sector 1.
This commit is contained in:
Vladimir 'phcoder' Serbinenko 2012-09-26 09:33:41 +02:00
parent 473959f052
commit b78c312722
2 changed files with 76 additions and 72 deletions

View file

@ -1,3 +1,8 @@
2012-09-26 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/fs/affs.c (grub_affs_mount): Support AFFS bootblock in
sector 1.
2012-09-24 Colin Watson <cjwatson@ubuntu.com> 2012-09-24 Colin Watson <cjwatson@ubuntu.com>
* util/grub-install.in: Make the error message if $source_dir * util/grub-install.in: Make the error message if $source_dir

View file

@ -97,6 +97,7 @@ enum
}; };
#define AFFS_MAX_LOG_BLOCK_SIZE 4 #define AFFS_MAX_LOG_BLOCK_SIZE 4
#define AFFS_MAX_SUPERBLOCK 1
@ -184,94 +185,92 @@ 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 = 0;
int log_blocksize = 0; int log_blocksize = 0;
int bsnum = 0;
data = grub_zalloc (sizeof (struct grub_affs_data)); data = grub_zalloc (sizeof (struct grub_affs_data));
if (!data) if (!data)
return 0; return 0;
/* Read the bootblock. */ for (bsnum = 0; bsnum < AFFS_MAX_SUPERBLOCK + 1; bsnum++)
grub_disk_read (disk, 0, 0, sizeof (struct grub_affs_bblock),
&data->bblock);
if (grub_errno)
goto fail;
/* Make sure this is an affs filesystem. */
if (grub_strncmp ((char *) (data->bblock.type), "DOS", 3))
{ {
grub_error (GRUB_ERR_BAD_FS, "not an AFFS filesystem"); /* Read the bootblock. */
goto fail; grub_disk_read (disk, bsnum, 0, sizeof (struct grub_affs_bblock),
} &data->bblock);
/* Test if the filesystem is a OFS filesystem. */
if (! (data->bblock.flags & GRUB_AFFS_FLAG_FFS))
{
grub_error (GRUB_ERR_BAD_FS, "OFS not yet supported");
goto fail;
}
/* 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. */
rootblock = grub_malloc (GRUB_DISK_SECTOR_SIZE << AFFS_MAX_LOG_BLOCK_SIZE);
if (!rootblock)
goto fail;
rblock = (struct grub_affs_rblock *) rootblock;
/* The filesystem blocksize is not stored anywhere in the filesystem
itself. One way to determine it is try reading blocks for the
rootblock until the checksum is correct. */
for (log_blocksize = 0; log_blocksize <= AFFS_MAX_LOG_BLOCK_SIZE;
log_blocksize++)
{
grub_uint32_t *currblock = rootblock;
unsigned int i;
grub_uint32_t checksum = 0;
/* 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) if (grub_errno)
goto fail; goto fail;
if (rblock->type != grub_cpu_to_be32_compile_time (2) /* Make sure this is an affs filesystem. */
|| rblock->htsize == 0 if (grub_strncmp ((char *) (data->bblock.type), "DOS", 3) != 0
|| currblock[(GRUB_DISK_SECTOR_SIZE << log_blocksize) /* Test if the filesystem is a OFS filesystem. */
/ sizeof (*currblock) - 1] || !(data->bblock.flags & GRUB_AFFS_FLAG_FFS))
!= grub_cpu_to_be32_compile_time (1))
continue; continue;
for (i = 0; i < (GRUB_DISK_SECTOR_SIZE << log_blocksize) /* No sane person uses more than 8KB for a block. At least I hope
/ sizeof (*currblock); for that person because in that case this won't work. */
i++) if (!rootblock)
checksum += grub_be_to_cpu32 (currblock[i]); rootblock = grub_malloc (GRUB_DISK_SECTOR_SIZE
<< AFFS_MAX_LOG_BLOCK_SIZE);
if (!rootblock)
goto fail;
if (checksum == 0) rblock = (struct grub_affs_rblock *) rootblock;
break;
/* The filesystem blocksize is not stored anywhere in the filesystem
itself. One way to determine it is try reading blocks for the
rootblock until the checksum is correct. */
for (log_blocksize = 0; log_blocksize <= AFFS_MAX_LOG_BLOCK_SIZE;
log_blocksize++)
{
grub_uint32_t *currblock = rootblock;
unsigned int i;
grub_uint32_t checksum = 0;
/* 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 == GRUB_ERR_OUT_OF_RANGE)
{
grub_errno = 0;
break;
}
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]);
if (checksum == 0)
{
data->log_blocksize = log_blocksize;
data->disk = disk;
data->htsize = grub_be_to_cpu32 (rblock->htsize);
data->diropen.data = data;
data->diropen.block = grub_be_to_cpu32 (data->bblock.rootblock);
data->diropen.parent = NULL;
grub_memcpy (&data->diropen.di, rootblock,
sizeof (data->diropen.di));
grub_free (rootblock);
return data;
}
}
} }
if (log_blocksize > AFFS_MAX_LOG_BLOCK_SIZE)
{
grub_error (GRUB_ERR_BAD_FS, "AFFS blocksize couldn't be determined");
goto fail;
}
data->log_blocksize = log_blocksize;
data->disk = disk;
data->htsize = grub_be_to_cpu32 (rblock->htsize);
data->diropen.data = data;
data->diropen.block = grub_be_to_cpu32 (data->bblock.rootblock);
data->diropen.parent = NULL;
grub_memcpy (&data->diropen.di, rootblock, sizeof (data->diropen.di));
grub_free (rootblock);
return data;
fail: fail:
if (grub_errno == GRUB_ERR_OUT_OF_RANGE) if (grub_errno == GRUB_ERR_NONE || grub_errno == GRUB_ERR_OUT_OF_RANGE)
grub_error (GRUB_ERR_BAD_FS, "not an AFFS filesystem"); grub_error (GRUB_ERR_BAD_FS, "not an AFFS filesystem");
grub_free (data); grub_free (data);