Fix long symlinks on reiserfs.

* grub-core/fs/reiserfs.c (grub_fshelp_node): New field size.
	(grub_reiserfs_read_symlink): Use grub_reiserfs_read_real.
	(grub_reiserfs_iterate_dir): Save size for non-directories.
	(grub_reiserfs_open): Don't reread stat block as we already know the
	size.
	(grub_reiserfs_read): Split into...
	(grub_reiserfs_read_real): ... and ...
	(grub_reiserfs_read): ...this.
This commit is contained in:
Vladimir 'phcoder' Serbinenko 2012-05-09 12:55:43 +02:00
parent ae16024d92
commit 607d282b29
2 changed files with 52 additions and 81 deletions

View File

@ -1,3 +1,16 @@
2012-05-09 Vladimir Serbinenko <phcoder@gmail.com>
Fix long symlinks on reiserfs.
* grub-core/fs/reiserfs.c (grub_fshelp_node): New field size.
(grub_reiserfs_read_symlink): Use grub_reiserfs_read_real.
(grub_reiserfs_iterate_dir): Save size for non-directories.
(grub_reiserfs_open): Don't reread stat block as we already know the
size.
(grub_reiserfs_read): Split into...
(grub_reiserfs_read_real): ... and ...
(grub_reiserfs_read): ...this.
2012-05-09 Vladimir Serbinenko <phcoder@gmail.com>
Fix non-indexed JFS.

View File

@ -225,6 +225,7 @@ struct grub_fshelp_node
grub_uint16_t block_position;
grub_uint64_t next_offset;
grub_int32_t mtime;
grub_off_t size;
enum grub_reiserfs_item_type type; /* To know how to read the header. */
struct grub_reiserfs_item_header header;
};
@ -236,6 +237,13 @@ struct grub_reiserfs_data
grub_disk_t disk;
};
static grub_ssize_t
grub_reiserfs_read_real (struct grub_fshelp_node *node,
grub_off_t off, char *buf, grub_size_t len,
void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
unsigned offset,
unsigned length));
/* Internal-only functions. Not to be used outside of this file. */
/* Return the type of given v2 key. */
@ -659,43 +667,22 @@ static char *
grub_reiserfs_read_symlink (grub_fshelp_node_t node)
{
char *symlink_buffer = 0;
grub_uint16_t block_size;
grub_disk_addr_t block;
grub_off_t offset;
grub_size_t len;
struct grub_fshelp_node found;
struct grub_reiserfs_key key;
grub_memcpy (&key, &(node->header.key), sizeof (key));
grub_reiserfs_set_key_offset (&key, 1);
grub_reiserfs_set_key_type (&key, GRUB_REISERFS_DIRECT,
grub_reiserfs_get_key_version (&key));
if (grub_reiserfs_get_item (node->data, &key, &found, 1) != GRUB_ERR_NONE)
goto fail;
if (found.block_number == 0)
goto fail;
block_size = grub_le_to_cpu16 (node->data->superblock.block_size);
len = grub_le_to_cpu16 (found.header.item_size);
block = found.block_number * (block_size >> GRUB_DISK_SECTOR_BITS);
offset = grub_le_to_cpu16 (found.header.item_location);
grub_size_t len = node->size;
grub_ssize_t ret;
symlink_buffer = grub_malloc (len + 1);
if (! symlink_buffer)
goto fail;
return 0;
grub_disk_read (node->data->disk, block, offset, len, symlink_buffer);
if (grub_errno)
goto fail;
ret = grub_reiserfs_read_real (node, 0, symlink_buffer, len, 0);
if (ret < 0)
{
grub_free (symlink_buffer);
return 0;
}
symlink_buffer[len] = 0;
symlink_buffer[ret] = 0;
return symlink_buffer;
fail:
grub_free (symlink_buffer);
return 0;
}
/* Fill the mounted filesystem structure and return it. */
@ -897,6 +884,7 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item,
entry_type = GRUB_FSHELP_SYMLINK;
else
entry_type = GRUB_FSHELP_REG;
entry_item->size = (grub_off_t) grub_le_to_cpu64 (entry_v1_stat.size);
}
else
{
@ -939,6 +927,7 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item,
entry_v2_stat.first_direct_byte);
#endif
entry_item->mtime = grub_le_to_cpu32 (entry_v2_stat.mtime);
entry_item->size = (grub_off_t) grub_le_to_cpu64 (entry_v2_stat.size);
if ((grub_le_to_cpu16 (entry_v2_stat.mode) & S_IFLNK)
== S_IFLNK)
entry_type = GRUB_FSHELP_SYMLINK;
@ -1004,16 +993,13 @@ static grub_err_t
grub_reiserfs_open (struct grub_file *file, const char *name)
{
struct grub_reiserfs_data *data = 0;
struct grub_fshelp_node root, *found = 0, info;
struct grub_fshelp_node root, *found = 0;
struct grub_reiserfs_key key;
grub_uint32_t block_number;
grub_uint16_t entry_version, block_size, entry_location;
grub_dl_ref (my_mod);
data = grub_reiserfs_mount (file->device->disk);
if (! data)
goto fail;
block_size = grub_le_to_cpu16 (data->superblock.block_size);
key.directory_id = grub_cpu_to_le32 (1);
key.object_id = grub_cpu_to_le32 (2);
key.u.v2.offset_type = 0;
@ -1031,46 +1017,8 @@ grub_reiserfs_open (struct grub_file *file, const char *name)
grub_reiserfs_read_symlink, GRUB_FSHELP_REG);
if (grub_errno)
goto fail;
key.directory_id = found->header.key.directory_id;
key.object_id = found->header.key.object_id;
grub_reiserfs_set_key_type (&key, GRUB_REISERFS_STAT, 2);
grub_reiserfs_set_key_offset (&key, 0);
if (grub_reiserfs_get_item (data, &key, &info, 1) != GRUB_ERR_NONE)
goto fail;
if (info.block_number == 0)
{
grub_error (GRUB_ERR_BAD_FS, "unable to find searched item");
goto fail;
}
entry_version = grub_le_to_cpu16 (info.header.version);
entry_location = grub_le_to_cpu16 (info.header.item_location);
block_number = info.block_number;
if (entry_version == 0) /* Version 1 stat item. */
{
struct grub_reiserfs_stat_item_v1 entry_v1_stat;
grub_disk_read (data->disk,
block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
entry_location
+ (((grub_off_t) block_number * block_size)
& (GRUB_DISK_SECTOR_SIZE - 1)),
sizeof (entry_v1_stat), &entry_v1_stat);
if (grub_errno)
goto fail;
file->size = (grub_off_t) grub_le_to_cpu64 (entry_v1_stat.size);
}
else
{
struct grub_reiserfs_stat_item_v2 entry_v2_stat;
grub_disk_read (data->disk,
block_number * (block_size >> GRUB_DISK_SECTOR_BITS),
entry_location
+ (((grub_off_t) block_number * block_size)
& (GRUB_DISK_SECTOR_SIZE - 1)),
sizeof (entry_v2_stat), &entry_v2_stat);
if (grub_errno)
goto fail;
file->size = (grub_off_t) grub_le_to_cpu64 (entry_v2_stat.size);
}
file->size = found->size;
grub_dprintf ("reiserfs", "file size : %d (%08x%08x)\n",
(unsigned int) file->size,
(unsigned int) (file->size >> 32), (unsigned int) file->size);
@ -1087,11 +1035,14 @@ grub_reiserfs_open (struct grub_file *file, const char *name)
}
static grub_ssize_t
grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len)
grub_reiserfs_read_real (struct grub_fshelp_node *node,
grub_off_t off, char *buf, grub_size_t len,
void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
unsigned offset,
unsigned length))
{
unsigned int indirect_block, indirect_block_count;
struct grub_reiserfs_key key;
struct grub_fshelp_node *node = file->data;
struct grub_reiserfs_data *data = node->data;
struct grub_fshelp_node found;
grub_uint16_t block_size = grub_le_to_cpu16 (data->superblock.block_size);
@ -1106,9 +1057,9 @@ grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len)
key.object_id = node->header.key.object_id;
key.u.v2.offset_type = 0;
grub_reiserfs_set_key_type (&key, GRUB_REISERFS_ANY, 2);
initial_position = file->offset;
initial_position = off;
current_position = 0;
final_position = MIN (len + initial_position, file->size);
final_position = MIN (len + initial_position, node->size);
grub_dprintf ("reiserfs",
"Reading from %lld to %lld (%lld instead of requested %ld)\n",
(unsigned long long) initial_position,
@ -1154,7 +1105,7 @@ grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len)
"Reading direct block %u from %u to %u...\n",
(unsigned) block, (unsigned) offset,
(unsigned) (offset + length));
found.data->disk->read_hook = file->read_hook;
found.data->disk->read_hook = read_hook;
grub_disk_read (found.data->disk,
block,
offset
@ -1180,7 +1131,7 @@ grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len)
item_size, indirect_block_ptr);
if (grub_errno)
goto fail;
found.data->disk->read_hook = file->read_hook;
found.data->disk->read_hook = read_hook;
for (indirect_block = 0;
indirect_block < indirect_block_count
&& current_position < final_position;
@ -1282,6 +1233,13 @@ grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len)
return -1;
}
static grub_ssize_t
grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len)
{
return grub_reiserfs_read_real (file->data, file->offset, buf, len,
file->read_hook);
}
/* Close the file FILE. */
static grub_err_t
grub_reiserfs_close (grub_file_t file)