Several AFFS fixes.
* grub-core/fs/affs.c (grub_affs_bblock): Replace flags with version. (GRUB_AFFS_FLAG_FFS): Removed. (GRUB_AFFS_SYMLINK_SIZE): Likewise. (GRUB_AFFS_FILETYPE_DIR): Make positive and unsigned. (GRUB_AFFS_FILETYPE_DIR), (GRUB_AFFS_FILETYPE_REG): Fix a mix-up. (grub_fshelp_node): Make block 32-bit. Add block_cache and last_block_cache. (grub_affs_read_block): Fill and use block cache. (grub_affs_read_file): Removed. (grub_affs_mount): Zero-fill node. Fix version check. Don't reread boot block. (grub_affs_read_symlink): Fix symlink size. Add a \0 at the end for safety. (grub_affs_iterate_dir): Use more appropriate types. Zero-fill allocated space. (grub_affs_close): Free block cache. (grub_affs_read): Use grub_fshelp_read_file directly.
This commit is contained in:
parent
438a746a3f
commit
52b656c037
2 changed files with 74 additions and 59 deletions
22
ChangeLog
22
ChangeLog
|
@ -1,3 +1,25 @@
|
||||||
|
2011-11-09 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
|
Several AFFS fixes.
|
||||||
|
|
||||||
|
* grub-core/fs/affs.c (grub_affs_bblock): Replace flags with version.
|
||||||
|
(GRUB_AFFS_FLAG_FFS): Removed.
|
||||||
|
(GRUB_AFFS_SYMLINK_SIZE): Likewise.
|
||||||
|
(GRUB_AFFS_FILETYPE_DIR): Make positive and unsigned.
|
||||||
|
(GRUB_AFFS_FILETYPE_DIR), (GRUB_AFFS_FILETYPE_REG): Fix a mix-up.
|
||||||
|
(grub_fshelp_node): Make block 32-bit.
|
||||||
|
Add block_cache and last_block_cache.
|
||||||
|
(grub_affs_read_block): Fill and use block cache.
|
||||||
|
(grub_affs_read_file): Removed.
|
||||||
|
(grub_affs_mount): Zero-fill node. Fix version check. Don't reread
|
||||||
|
boot block.
|
||||||
|
(grub_affs_read_symlink): Fix symlink size. Add a \0 at the end for
|
||||||
|
safety.
|
||||||
|
(grub_affs_iterate_dir): Use more appropriate types. Zero-fill allocated
|
||||||
|
space.
|
||||||
|
(grub_affs_close): Free block cache.
|
||||||
|
(grub_affs_read): Use grub_fshelp_read_file directly.
|
||||||
|
|
||||||
2011-11-08 Vladimir Serbinenko <phcoder@gmail.com>
|
2011-11-08 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
* grub-core/fs/zfs/zfs.c (read_dva): Issue an error if read failed
|
* grub-core/fs/zfs/zfs.c (read_dva): Issue an error if read failed
|
||||||
|
|
|
@ -32,15 +32,11 @@ GRUB_MOD_LICENSE ("GPLv3+");
|
||||||
struct grub_affs_bblock
|
struct grub_affs_bblock
|
||||||
{
|
{
|
||||||
grub_uint8_t type[3];
|
grub_uint8_t type[3];
|
||||||
grub_uint8_t flags;
|
grub_uint8_t version;
|
||||||
grub_uint32_t checksum;
|
grub_uint32_t checksum;
|
||||||
grub_uint32_t rootblock;
|
grub_uint32_t rootblock;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
/* Set if the filesystem is a AFFS filesystem. Otherwise this is an
|
|
||||||
OFS filesystem. */
|
|
||||||
#define GRUB_AFFS_FLAG_FFS 1
|
|
||||||
|
|
||||||
/* The affs rootblock. */
|
/* The affs rootblock. */
|
||||||
struct grub_affs_rblock
|
struct grub_affs_rblock
|
||||||
{
|
{
|
||||||
|
@ -85,19 +81,19 @@ struct grub_affs_file
|
||||||
#define GRUB_AFFS_BLOCKPTR_OFFSET 24
|
#define GRUB_AFFS_BLOCKPTR_OFFSET 24
|
||||||
#define GRUB_AFFS_SYMLINK_OFFSET 24
|
#define GRUB_AFFS_SYMLINK_OFFSET 24
|
||||||
|
|
||||||
#define GRUB_AFFS_SYMLINK_SIZE(blocksize) ((blocksize) - 225)
|
#define GRUB_AFFS_FILETYPE_REG 0xfffffffd
|
||||||
|
#define GRUB_AFFS_FILETYPE_DIR 2
|
||||||
#define GRUB_AFFS_FILETYPE_DIR -3
|
|
||||||
#define GRUB_AFFS_FILETYPE_REG 2
|
|
||||||
#define GRUB_AFFS_FILETYPE_SYMLINK 3
|
#define GRUB_AFFS_FILETYPE_SYMLINK 3
|
||||||
|
|
||||||
|
|
||||||
struct grub_fshelp_node
|
struct grub_fshelp_node
|
||||||
{
|
{
|
||||||
struct grub_affs_data *data;
|
struct grub_affs_data *data;
|
||||||
grub_disk_addr_t block;
|
grub_uint32_t block;
|
||||||
struct grub_fshelp_node *parent;
|
struct grub_fshelp_node *parent;
|
||||||
struct grub_affs_file di;
|
struct grub_affs_file di;
|
||||||
|
grub_uint32_t *block_cache;
|
||||||
|
grub_uint32_t last_block_cache;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Information about a "mounted" affs filesystem. */
|
/* Information about a "mounted" affs filesystem. */
|
||||||
|
@ -120,32 +116,46 @@ static grub_dl_t my_mod;
|
||||||
static grub_disk_addr_t
|
static grub_disk_addr_t
|
||||||
grub_affs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
|
grub_affs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
|
||||||
{
|
{
|
||||||
int links;
|
grub_uint32_t target, curblock;
|
||||||
grub_uint32_t pos;
|
grub_uint32_t pos;
|
||||||
int block = node->block;
|
|
||||||
struct grub_affs_file file;
|
struct grub_affs_file file;
|
||||||
struct grub_affs_data *data = node->data;
|
struct grub_affs_data *data = node->data;
|
||||||
grub_uint64_t mod;
|
grub_uint64_t mod;
|
||||||
|
|
||||||
|
if (!node->block_cache)
|
||||||
|
{
|
||||||
|
node->block_cache = grub_malloc ((((grub_be_to_cpu32 (node->di.size)
|
||||||
|
+ 511) >> 9) / data->htsize + 1)
|
||||||
|
* sizeof (node->block_cache[0]));
|
||||||
|
if (!node->block_cache)
|
||||||
|
return -1;
|
||||||
|
node->last_block_cache = 0;
|
||||||
|
node->block_cache[0] = node->block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Files are at most 2G on AFFS, so no need for 64-bit division. */
|
||||||
|
target = (grub_uint32_t) fileblock / data->htsize;
|
||||||
|
mod = (grub_uint32_t) fileblock % data->htsize;
|
||||||
/* Find the block that points to the fileblock we are looking up by
|
/* Find the block that points to the fileblock we are looking up by
|
||||||
following the chain until the right table is reached. */
|
following the chain until the right table is reached. */
|
||||||
for (links = grub_divmod64 (fileblock, data->htsize, &mod); links; links--)
|
for (curblock = node->last_block_cache + 1; curblock <= target; curblock++)
|
||||||
{
|
{
|
||||||
grub_disk_read (data->disk, block + data->blocksize - 1,
|
grub_disk_read (data->disk,
|
||||||
|
node->block_cache[curblock - 1] + data->blocksize - 1,
|
||||||
data->blocksize * (GRUB_DISK_SECTOR_SIZE
|
data->blocksize * (GRUB_DISK_SECTOR_SIZE
|
||||||
- GRUB_AFFS_FILE_LOCATION),
|
- GRUB_AFFS_FILE_LOCATION),
|
||||||
sizeof (file), &file);
|
sizeof (file), &file);
|
||||||
if (grub_errno)
|
if (grub_errno)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
block = grub_be_to_cpu32 (file.extension);
|
node->block_cache[curblock] = grub_be_to_cpu32 (file.extension);
|
||||||
|
node->last_block_cache = curblock;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Translate the fileblock to the block within the right table. */
|
/* Translate the fileblock to the block within the right table. */
|
||||||
fileblock = mod;
|
grub_disk_read (data->disk, node->block_cache[target],
|
||||||
grub_disk_read (data->disk, block,
|
|
||||||
GRUB_AFFS_BLOCKPTR_OFFSET
|
GRUB_AFFS_BLOCKPTR_OFFSET
|
||||||
+ (data->htsize - fileblock - 1) * sizeof (pos),
|
+ (data->htsize - mod - 1) * sizeof (pos),
|
||||||
sizeof (pos), &pos);
|
sizeof (pos), &pos);
|
||||||
if (grub_errno)
|
if (grub_errno)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -153,21 +163,6 @@ grub_affs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
|
||||||
return grub_be_to_cpu32 (pos);
|
return grub_be_to_cpu32 (pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Read LEN bytes from the file described by DATA starting with byte
|
|
||||||
POS. Return the amount of read bytes in READ. */
|
|
||||||
static grub_ssize_t
|
|
||||||
grub_affs_read_file (grub_fshelp_node_t node,
|
|
||||||
void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
|
|
||||||
unsigned offset, unsigned length),
|
|
||||||
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_affs_read_block,
|
|
||||||
grub_be_to_cpu32 (node->di.size), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct grub_affs_data *
|
static struct grub_affs_data *
|
||||||
grub_affs_mount (grub_disk_t disk)
|
grub_affs_mount (grub_disk_t disk)
|
||||||
{
|
{
|
||||||
|
@ -178,7 +173,7 @@ grub_affs_mount (grub_disk_t disk)
|
||||||
int checksum = 0;
|
int checksum = 0;
|
||||||
int blocksize = 0;
|
int blocksize = 0;
|
||||||
|
|
||||||
data = grub_malloc (sizeof (struct grub_affs_data));
|
data = grub_zalloc (sizeof (struct grub_affs_data));
|
||||||
if (!data)
|
if (!data)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -196,18 +191,12 @@ grub_affs_mount (grub_disk_t disk)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Test if the filesystem is a OFS filesystem. */
|
/* Test if the filesystem is a OFS filesystem. */
|
||||||
if (! (data->bblock.flags & GRUB_AFFS_FLAG_FFS))
|
if (data->bblock.version < 1)
|
||||||
{
|
{
|
||||||
grub_error (GRUB_ERR_BAD_FS, "OFS not yet supported");
|
grub_error (GRUB_ERR_BAD_FS, "OFS not yet supported");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read the bootblock. */
|
|
||||||
grub_disk_read (disk, 0, 0, sizeof (struct grub_affs_bblock),
|
|
||||||
&data->bblock);
|
|
||||||
if (grub_errno)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
/* 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 * 16);
|
||||||
|
@ -270,18 +259,21 @@ grub_affs_read_symlink (grub_fshelp_node_t node)
|
||||||
{
|
{
|
||||||
struct grub_affs_data *data = node->data;
|
struct grub_affs_data *data = node->data;
|
||||||
char *symlink;
|
char *symlink;
|
||||||
|
const grub_size_t symlink_size = (data->blocksize * GRUB_DISK_SECTOR_SIZE
|
||||||
|
- 225);
|
||||||
|
|
||||||
symlink = grub_malloc (GRUB_AFFS_SYMLINK_SIZE (data->blocksize));
|
symlink = grub_malloc (symlink_size + 1);
|
||||||
if (!symlink)
|
if (!symlink)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
grub_disk_read (data->disk, node->block, GRUB_AFFS_SYMLINK_OFFSET,
|
grub_disk_read (data->disk, node->block, GRUB_AFFS_SYMLINK_OFFSET,
|
||||||
GRUB_AFFS_SYMLINK_SIZE (data->blocksize), symlink);
|
symlink_size, symlink);
|
||||||
if (grub_errno)
|
if (grub_errno)
|
||||||
{
|
{
|
||||||
grub_free (symlink);
|
grub_free (symlink);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
symlink[symlink_size] = 1;
|
||||||
grub_dprintf ("affs", "Symlink: `%s'\n", symlink);
|
grub_dprintf ("affs", "Symlink: `%s'\n", symlink);
|
||||||
return symlink;
|
return symlink;
|
||||||
}
|
}
|
||||||
|
@ -301,24 +293,24 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
||||||
grub_uint32_t *hashtable;
|
grub_uint32_t *hashtable;
|
||||||
|
|
||||||
auto int NESTED_FUNC_ATTR grub_affs_create_node (const char *name,
|
auto int NESTED_FUNC_ATTR grub_affs_create_node (const char *name,
|
||||||
grub_disk_addr_t block,
|
grub_uint32_t block,
|
||||||
const struct grub_affs_file *fil);
|
const struct grub_affs_file *fil);
|
||||||
|
|
||||||
int NESTED_FUNC_ATTR grub_affs_create_node (const char *name,
|
int NESTED_FUNC_ATTR grub_affs_create_node (const char *name,
|
||||||
grub_disk_addr_t block,
|
grub_uint32_t block,
|
||||||
const struct grub_affs_file *fil)
|
const struct grub_affs_file *fil)
|
||||||
{
|
{
|
||||||
int type;
|
int type;
|
||||||
node = grub_malloc (sizeof (*node));
|
node = grub_zalloc (sizeof (*node));
|
||||||
if (!node)
|
if (!node)
|
||||||
{
|
{
|
||||||
grub_free (hashtable);
|
grub_free (hashtable);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((int) grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_DIR)
|
if (grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_REG)
|
||||||
type = GRUB_FSHELP_REG;
|
type = GRUB_FSHELP_REG;
|
||||||
else if (grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_REG)
|
else if (grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_DIR)
|
||||||
type = GRUB_FSHELP_DIR;
|
type = GRUB_FSHELP_DIR;
|
||||||
else if (grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_SYMLINK)
|
else if (grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_SYMLINK)
|
||||||
type = GRUB_FSHELP_SYMLINK;
|
type = GRUB_FSHELP_SYMLINK;
|
||||||
|
@ -339,7 +331,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create the directory entries for `.' and `..'. */
|
/* Create the directory entries for `.' and `..'. */
|
||||||
node = grub_malloc (sizeof (*node));
|
node = grub_zalloc (sizeof (*node));
|
||||||
if (!node)
|
if (!node)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
@ -348,7 +340,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
||||||
return 1;
|
return 1;
|
||||||
if (dir->parent)
|
if (dir->parent)
|
||||||
{
|
{
|
||||||
node = grub_malloc (sizeof (*node));
|
node = grub_zalloc (sizeof (*node));
|
||||||
if (!node)
|
if (!node)
|
||||||
return 1;
|
return 1;
|
||||||
*node = *dir->parent;
|
*node = *dir->parent;
|
||||||
|
@ -356,7 +348,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
hashtable = grub_malloc (data->htsize * sizeof (*hashtable));
|
hashtable = grub_zalloc (data->htsize * sizeof (*hashtable));
|
||||||
if (!hashtable)
|
if (!hashtable)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
@ -367,7 +359,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
||||||
|
|
||||||
for (i = 0; i < data->htsize; i++)
|
for (i = 0; i < data->htsize; i++)
|
||||||
{
|
{
|
||||||
grub_uint64_t next;
|
grub_uint32_t next;
|
||||||
|
|
||||||
if (!hashtable[i])
|
if (!hashtable[i])
|
||||||
continue;
|
continue;
|
||||||
|
@ -441,10 +433,13 @@ grub_affs_open (struct grub_file *file, const char *name)
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
grub_affs_close (grub_file_t file)
|
grub_affs_close (grub_file_t file)
|
||||||
{
|
{
|
||||||
|
struct grub_affs_data *data =
|
||||||
|
(struct grub_affs_data *) file->data;
|
||||||
|
|
||||||
|
grub_free (data->diropen.block_cache);
|
||||||
grub_free (file->data);
|
grub_free (file->data);
|
||||||
|
|
||||||
grub_dl_unref (my_mod);
|
grub_dl_unref (my_mod);
|
||||||
|
@ -452,7 +447,6 @@ grub_affs_close (grub_file_t file)
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Read LEN bytes data from FILE into BUF. */
|
/* Read LEN bytes data from FILE into BUF. */
|
||||||
static grub_ssize_t
|
static grub_ssize_t
|
||||||
grub_affs_read (grub_file_t file, char *buf, grub_size_t len)
|
grub_affs_read (grub_file_t file, char *buf, grub_size_t len)
|
||||||
|
@ -460,13 +454,12 @@ grub_affs_read (grub_file_t file, char *buf, grub_size_t len)
|
||||||
struct grub_affs_data *data =
|
struct grub_affs_data *data =
|
||||||
(struct grub_affs_data *) file->data;
|
(struct grub_affs_data *) file->data;
|
||||||
|
|
||||||
int size = grub_affs_read_file (&data->diropen, file->read_hook,
|
return grub_fshelp_read_file (data->diropen.data->disk, &data->diropen,
|
||||||
file->offset, len, buf);
|
file->read_hook,
|
||||||
|
file->offset, len, buf, grub_affs_read_block,
|
||||||
return size;
|
grub_be_to_cpu32 (data->diropen.di.size), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
grub_affs_dir (grub_device_t device, const char *path,
|
grub_affs_dir (grub_device_t device, const char *path,
|
||||||
int (*hook) (const char *filename,
|
int (*hook) (const char *filename,
|
||||||
|
|
Loading…
Reference in a new issue