kern/fs: Honour file->read_hook() in grub_fs_blocklist_read()

Unlike files accessed via a normal file system, the file->read_hook() is
not honoured when using blocklist notation.

This means that when trying to use a dedicated, 1 KiB, raw partition
for the environment block and hence does something like

  save_env --file=(hd0,gpt9)0+2 X Y Z

this fails with "sparse file not allowed", which is rather unexpected,
as I've explicitly said exactly which blocks should be used. Adding
a little debugging reveals that grub_file_size(file) is 1024 as expected,
but total_length is 0, simply because the callback was never invoked, so
blocklists is an empty list.

Fix that by honouring the ->read_hook() set by the caller, also when
a "file" is specified with blocklist notation.

Signed-off-by: Rasmus Villemoes <rasmus.villemoes@prevas.dk>
Reviewed-by: Vladimir Serbinenko <phcoder@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
This commit is contained in:
Rasmus Villemoes 2024-08-29 13:01:02 +02:00 committed by Daniel Kiper
parent 792132c72a
commit 4f6c460917

View File

@ -215,12 +215,15 @@ grub_fs_blocklist_read (grub_file_t file, char *buf, grub_size_t len)
grub_disk_addr_t sector;
grub_off_t offset;
grub_ssize_t ret = 0;
grub_disk_t disk = file->device->disk;
if (len > file->size - file->offset)
len = file->size - file->offset;
sector = (file->offset >> GRUB_DISK_SECTOR_BITS);
offset = (file->offset & (GRUB_DISK_SECTOR_SIZE - 1));
disk->read_hook = file->read_hook;
disk->read_hook_data = file->read_hook_data;
for (p = file->data; p->length && len > 0; p++)
{
if (sector < p->length)
@ -232,9 +235,12 @@ grub_fs_blocklist_read (grub_file_t file, char *buf, grub_size_t len)
>> GRUB_DISK_SECTOR_BITS) > p->length - sector)
size = ((p->length - sector) << GRUB_DISK_SECTOR_BITS) - offset;
if (grub_disk_read (file->device->disk, p->offset + sector, offset,
if (grub_disk_read (disk, p->offset + sector, offset,
size, buf) != GRUB_ERR_NONE)
return -1;
{
ret = -1;
break;
}
ret += size;
len -= size;
@ -244,6 +250,8 @@ grub_fs_blocklist_read (grub_file_t file, char *buf, grub_size_t len)
else
sector -= p->length;
}
disk->read_hook = NULL;
disk->read_hook_data = NULL;
return ret;
}