symlink support
This commit is contained in:
parent
a43c4bc55f
commit
34018a7d1f
1 changed files with 235 additions and 132 deletions
|
@ -70,7 +70,11 @@ struct grub_btrfs_data
|
||||||
unsigned int sblock_number;
|
unsigned int sblock_number;
|
||||||
grub_uint64_t tree;
|
grub_uint64_t tree;
|
||||||
grub_uint64_t inode;
|
grub_uint64_t inode;
|
||||||
|
|
||||||
|
/* Cached extent data. */
|
||||||
grub_uint64_t extstart;
|
grub_uint64_t extstart;
|
||||||
|
grub_uint64_t extino;
|
||||||
|
grub_uint64_t exttree;
|
||||||
struct grub_btrfs_extent_data *extent;
|
struct grub_btrfs_extent_data *extent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -603,6 +607,139 @@ grub_btrfs_mount (grub_disk_t disk)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static grub_err_t
|
||||||
|
grub_btrfs_read_inode (struct grub_btrfs_data *data, grub_disk_t disk,
|
||||||
|
struct grub_btrfs_inode *inode, grub_uint64_t num,
|
||||||
|
grub_uint64_t tree)
|
||||||
|
{
|
||||||
|
struct grub_btrfs_key key_in, key_out;
|
||||||
|
grub_disk_addr_t elemaddr;
|
||||||
|
grub_size_t elemsize;
|
||||||
|
grub_err_t err;
|
||||||
|
|
||||||
|
key_in.object_id = num;
|
||||||
|
key_in.type = GRUB_BTRFS_ITEM_TYPE_INODE_ITEM;
|
||||||
|
key_in.offset = 0;
|
||||||
|
|
||||||
|
err = lower_bound (data,disk, &key_in, &key_out, tree,
|
||||||
|
&elemaddr, &elemsize, NULL);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
if (num != key_out.object_id
|
||||||
|
|| key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_ITEM)
|
||||||
|
return grub_error (GRUB_ERR_BAD_FS, "inode not found");
|
||||||
|
|
||||||
|
return grub_btrfs_read_logical (data, disk, elemaddr, inode, sizeof (*inode));
|
||||||
|
}
|
||||||
|
|
||||||
|
static grub_ssize_t
|
||||||
|
grub_btrfs_extent_read (struct grub_btrfs_data *data, grub_disk_t disk,
|
||||||
|
grub_uint64_t ino, grub_uint64_t tree,
|
||||||
|
grub_off_t pos0, char *buf, grub_size_t len)
|
||||||
|
{
|
||||||
|
grub_off_t pos = pos0;
|
||||||
|
while (len)
|
||||||
|
{
|
||||||
|
grub_size_t csize;
|
||||||
|
grub_err_t err;
|
||||||
|
grub_off_t extoff;
|
||||||
|
if (!data->extent || data->extstart > pos || data->extino != ino
|
||||||
|
|| data->exttree != tree
|
||||||
|
|| grub_le_to_cpu64 (data->extent->size) + data->extstart <= pos)
|
||||||
|
{
|
||||||
|
struct grub_btrfs_key key_in, key_out;
|
||||||
|
grub_disk_addr_t elemaddr;
|
||||||
|
grub_size_t elemsize;
|
||||||
|
grub_free (data->extent);
|
||||||
|
key_in.object_id = ino;
|
||||||
|
key_in.type = GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM;
|
||||||
|
key_in.offset = grub_cpu_to_le64 (pos);
|
||||||
|
err = lower_bound (data, disk, &key_in, &key_out, tree,
|
||||||
|
&elemaddr, &elemsize, NULL);
|
||||||
|
if (err)
|
||||||
|
return -1;
|
||||||
|
if (key_out.object_id != ino
|
||||||
|
|| key_out.type != GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM)
|
||||||
|
{
|
||||||
|
grub_error (GRUB_ERR_BAD_FS, "extent not found");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
data->extstart = grub_le_to_cpu64 (key_out.offset);
|
||||||
|
data->extent = grub_malloc (elemsize);
|
||||||
|
data->extino = ino;
|
||||||
|
data->exttree = tree;
|
||||||
|
if (!data->extent)
|
||||||
|
return grub_errno;
|
||||||
|
|
||||||
|
err = grub_btrfs_read_logical (data, disk, elemaddr,
|
||||||
|
data->extent, elemsize);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
if (grub_le_to_cpu64 (data->extent->size) + data->extstart <= pos)
|
||||||
|
return grub_error (GRUB_ERR_BAD_FS, "extent not found");
|
||||||
|
grub_dprintf ("btrfs", "extent 0x%" PRIxGRUB_UINT64_T "+0x%"
|
||||||
|
PRIxGRUB_UINT64_T "\n",
|
||||||
|
grub_le_to_cpu64 (key_out.offset),
|
||||||
|
grub_le_to_cpu64 (data->extent->size));
|
||||||
|
}
|
||||||
|
csize = grub_le_to_cpu64 (data->extent->size)
|
||||||
|
+ grub_le_to_cpu64 (data->extstart) - pos;
|
||||||
|
extoff = pos - data->extstart;
|
||||||
|
if (csize > len)
|
||||||
|
csize = len;
|
||||||
|
|
||||||
|
if (data->extent->encryption)
|
||||||
|
{
|
||||||
|
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||||
|
"encryption not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->extent->compression)
|
||||||
|
{
|
||||||
|
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||||
|
"compression not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (data->extent->encoding)
|
||||||
|
{
|
||||||
|
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||||
|
"encoding not supported");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (data->extent->type)
|
||||||
|
{
|
||||||
|
case GRUB_BTRFS_EXTENT_INLINE:
|
||||||
|
grub_memcpy (buf, data->extent->inl + extoff, csize);
|
||||||
|
break;
|
||||||
|
case GRUB_BTRFS_EXTENT_REGULAR:
|
||||||
|
if (!data->extent->laddr)
|
||||||
|
{
|
||||||
|
grub_memset (buf, 0, csize);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
err = grub_btrfs_read_logical (data, disk,
|
||||||
|
grub_le_to_cpu64 (data->extent->laddr)
|
||||||
|
+ extoff,
|
||||||
|
buf, csize);
|
||||||
|
if (err)
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||||
|
"unsupported extent type 0x%x", data->extent->type);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
buf += csize;
|
||||||
|
pos += csize;
|
||||||
|
len -= csize;
|
||||||
|
}
|
||||||
|
return pos - pos0;
|
||||||
|
}
|
||||||
|
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
find_path (struct grub_btrfs_data *data,
|
find_path (struct grub_btrfs_data *data,
|
||||||
grub_disk_t disk,
|
grub_disk_t disk,
|
||||||
|
@ -616,15 +753,17 @@ find_path (struct grub_btrfs_data *data,
|
||||||
grub_size_t allocated = 0;
|
grub_size_t allocated = 0;
|
||||||
struct grub_btrfs_dir_item *direl = NULL;
|
struct grub_btrfs_dir_item *direl = NULL;
|
||||||
struct grub_btrfs_key key_out;
|
struct grub_btrfs_key key_out;
|
||||||
int skip_default = 1;
|
int skip_default;
|
||||||
const char *ctoken;
|
const char *ctoken;
|
||||||
grub_size_t ctokenlen;
|
grub_size_t ctokenlen;
|
||||||
|
char *path_alloc = NULL;
|
||||||
|
|
||||||
*type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
|
*type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
|
||||||
*tree = data->sblock.root_tree;
|
*tree = data->sblock.root_tree;
|
||||||
key->object_id = data->sblock.root_dir_objectid;
|
key->object_id = data->sblock.root_dir_objectid;
|
||||||
key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
|
key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
|
||||||
key->offset = 0;
|
key->offset = 0;
|
||||||
|
skip_default = 1;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
|
@ -647,7 +786,10 @@ find_path (struct grub_btrfs_data *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY)
|
if (*type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY)
|
||||||
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
|
{
|
||||||
|
grub_free (path_alloc);
|
||||||
|
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
|
||||||
|
}
|
||||||
|
|
||||||
key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
|
key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
|
||||||
key->offset = grub_cpu_to_le64 (~grub_getcrc32c (1, ctoken, ctokenlen));
|
key->offset = grub_cpu_to_le64 (~grub_getcrc32c (1, ctoken, ctokenlen));
|
||||||
|
@ -657,11 +799,13 @@ find_path (struct grub_btrfs_data *data,
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
grub_free (direl);
|
grub_free (direl);
|
||||||
|
grub_free (path_alloc);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
if (key_cmp (key, &key_out) != 0)
|
if (key_cmp (key, &key_out) != 0)
|
||||||
{
|
{
|
||||||
grub_free (direl);
|
grub_free (direl);
|
||||||
|
grub_free (path_alloc);
|
||||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -672,7 +816,10 @@ find_path (struct grub_btrfs_data *data,
|
||||||
grub_free (direl);
|
grub_free (direl);
|
||||||
direl = grub_malloc (allocated + 1);
|
direl = grub_malloc (allocated + 1);
|
||||||
if (!direl)
|
if (!direl)
|
||||||
return grub_errno;
|
{
|
||||||
|
grub_free (path_alloc);
|
||||||
|
return grub_errno;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = grub_btrfs_read_logical (data, disk, elemaddr,
|
err = grub_btrfs_read_logical (data, disk, elemaddr,
|
||||||
|
@ -680,6 +827,7 @@ find_path (struct grub_btrfs_data *data,
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
grub_free (direl);
|
grub_free (direl);
|
||||||
|
grub_free (path_alloc);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -701,19 +849,60 @@ find_path (struct grub_btrfs_data *data,
|
||||||
>= (grub_ssize_t) elemsize)
|
>= (grub_ssize_t) elemsize)
|
||||||
{
|
{
|
||||||
grub_free (direl);
|
grub_free (direl);
|
||||||
|
grub_free (path_alloc);
|
||||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skip_default)
|
if (!skip_default)
|
||||||
path = slash;
|
path = slash;
|
||||||
skip_default = 0;
|
skip_default = 0;
|
||||||
*type = cdirel->type;
|
if (cdirel->type == GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK)
|
||||||
if (*type == GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK)
|
|
||||||
{
|
{
|
||||||
grub_free (direl);
|
struct grub_btrfs_inode inode;
|
||||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
char *tmp;
|
||||||
"symlinks not supported");
|
err = grub_btrfs_read_inode (data, disk, &inode,
|
||||||
|
cdirel->key.object_id, *tree);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
grub_free (direl);
|
||||||
|
grub_free (path_alloc);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
tmp = grub_malloc (grub_le_to_cpu64 (inode.size)
|
||||||
|
+ grub_strlen (path) + 1);
|
||||||
|
if (!tmp)
|
||||||
|
{
|
||||||
|
grub_free (direl);
|
||||||
|
grub_free (path_alloc);
|
||||||
|
return grub_errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (grub_btrfs_extent_read (data, disk, cdirel->key.object_id,
|
||||||
|
*tree, 0, tmp,
|
||||||
|
grub_le_to_cpu64 (inode.size))
|
||||||
|
!= (grub_ssize_t) grub_le_to_cpu64 (inode.size))
|
||||||
|
{
|
||||||
|
grub_free (direl);
|
||||||
|
grub_free (path_alloc);
|
||||||
|
grub_free (tmp);
|
||||||
|
return grub_errno;
|
||||||
|
}
|
||||||
|
grub_memcpy (tmp + grub_le_to_cpu64 (inode.size), path,
|
||||||
|
grub_strlen (path) + 1);
|
||||||
|
grub_free (path_alloc);
|
||||||
|
path = path_alloc = tmp;
|
||||||
|
if (path[0] == '/')
|
||||||
|
{
|
||||||
|
*type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
|
||||||
|
*tree = data->sblock.root_tree;
|
||||||
|
key->object_id = data->sblock.root_dir_objectid;
|
||||||
|
key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
|
||||||
|
key->offset = 0;
|
||||||
|
skip_default = 1;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
*type = cdirel->type;
|
||||||
|
|
||||||
switch (cdirel->key.type)
|
switch (cdirel->key.type)
|
||||||
{
|
{
|
||||||
|
@ -724,14 +913,26 @@ find_path (struct grub_btrfs_data *data,
|
||||||
data->sblock.root_tree,
|
data->sblock.root_tree,
|
||||||
&elemaddr, &elemsize, NULL);
|
&elemaddr, &elemsize, NULL);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
{
|
||||||
|
grub_free (direl);
|
||||||
|
grub_free (path_alloc);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
if (cdirel->key.object_id != key_out.object_id
|
if (cdirel->key.object_id != key_out.object_id
|
||||||
|| cdirel->key.type != key_out.type)
|
|| cdirel->key.type != key_out.type)
|
||||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
{
|
||||||
|
grub_free (direl);
|
||||||
|
grub_free (path_alloc);
|
||||||
|
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||||
|
}
|
||||||
err = grub_btrfs_read_logical (data, disk, elemaddr,
|
err = grub_btrfs_read_logical (data, disk, elemaddr,
|
||||||
&ri, sizeof (ri));
|
&ri, sizeof (ri));
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
{
|
||||||
|
grub_free (direl);
|
||||||
|
grub_free (path_alloc);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
|
key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
|
||||||
key->offset = 0;
|
key->offset = 0;
|
||||||
key->object_id = GRUB_BTRFS_OBJECT_ID_CHUNK;
|
key->object_id = GRUB_BTRFS_OBJECT_ID_CHUNK;
|
||||||
|
@ -740,19 +941,24 @@ find_path (struct grub_btrfs_data *data,
|
||||||
}
|
}
|
||||||
case GRUB_BTRFS_ITEM_TYPE_INODE_ITEM:
|
case GRUB_BTRFS_ITEM_TYPE_INODE_ITEM:
|
||||||
if (*slash && *type == GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR)
|
if (*slash && *type == GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR)
|
||||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
{
|
||||||
|
grub_free (direl);
|
||||||
|
grub_free (path_alloc);
|
||||||
|
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||||
|
}
|
||||||
*key = cdirel->key;
|
*key = cdirel->key;
|
||||||
if (*type == GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY)
|
if (*type == GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY)
|
||||||
key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
|
key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
grub_free (path_alloc);
|
||||||
|
grub_free (direl);
|
||||||
return grub_error (GRUB_ERR_BAD_FS, "unrecognised object type 0x%x",
|
return grub_error (GRUB_ERR_BAD_FS, "unrecognised object type 0x%x",
|
||||||
cdirel->key.type);
|
cdirel->key.type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
grub_free (direl);
|
grub_free (direl);
|
||||||
|
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -857,12 +1063,10 @@ static grub_err_t
|
||||||
grub_btrfs_open (struct grub_file *file, const char *name)
|
grub_btrfs_open (struct grub_file *file, const char *name)
|
||||||
{
|
{
|
||||||
struct grub_btrfs_data *data = grub_btrfs_mount (file->device->disk);
|
struct grub_btrfs_data *data = grub_btrfs_mount (file->device->disk);
|
||||||
struct grub_btrfs_key key_in, key_out;
|
|
||||||
grub_err_t err;
|
grub_err_t err;
|
||||||
grub_disk_addr_t elemaddr;
|
|
||||||
grub_size_t elemsize;
|
|
||||||
struct grub_btrfs_inode inode;
|
struct grub_btrfs_inode inode;
|
||||||
grub_uint8_t type;
|
grub_uint8_t type;
|
||||||
|
struct grub_btrfs_key key_in;
|
||||||
|
|
||||||
if (!data)
|
if (!data)
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
|
@ -874,28 +1078,24 @@ grub_btrfs_open (struct grub_file *file, const char *name)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
if (type != GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR)
|
if (type != GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR)
|
||||||
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a regular file");
|
{
|
||||||
|
grub_free (data);
|
||||||
|
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a regular file");
|
||||||
|
}
|
||||||
|
|
||||||
data->inode = key_in.object_id;
|
data->inode = key_in.object_id;
|
||||||
key_in.type = GRUB_BTRFS_ITEM_TYPE_INODE_ITEM;
|
err = grub_btrfs_read_inode (data, file->device->disk, &inode, data->inode,
|
||||||
|
data->tree);
|
||||||
err = lower_bound (data, file->device->disk, &key_in, &key_out,
|
|
||||||
data->tree,
|
|
||||||
&elemaddr, &elemsize, NULL);
|
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
{
|
||||||
if (data->inode != key_out.object_id
|
grub_free (data);
|
||||||
|| key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_ITEM)
|
return err;
|
||||||
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a regular file");
|
}
|
||||||
|
|
||||||
err = grub_btrfs_read_logical (data, file->device->disk, elemaddr,
|
|
||||||
&inode, sizeof (inode));
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
file->data = data;
|
file->data = data;
|
||||||
file->size = grub_le_to_cpu64 (inode.size);
|
file->size = grub_le_to_cpu64 (inode.size);
|
||||||
|
|
||||||
return GRUB_ERR_NONE;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
|
@ -913,106 +1113,9 @@ static grub_ssize_t
|
||||||
grub_btrfs_read (grub_file_t file, char *buf, grub_size_t len)
|
grub_btrfs_read (grub_file_t file, char *buf, grub_size_t len)
|
||||||
{
|
{
|
||||||
struct grub_btrfs_data *data = file->data;
|
struct grub_btrfs_data *data = file->data;
|
||||||
grub_off_t pos = file->offset;
|
|
||||||
|
|
||||||
while (len)
|
return grub_btrfs_extent_read (data, file->device->disk, data->inode,
|
||||||
{
|
data->tree, file->offset, buf, len);
|
||||||
grub_size_t csize;
|
|
||||||
grub_err_t err;
|
|
||||||
grub_off_t extoff;
|
|
||||||
if (!data->extent || data->extstart > pos ||
|
|
||||||
grub_le_to_cpu64 (data->extent->size) + data->extstart <= pos)
|
|
||||||
{
|
|
||||||
struct grub_btrfs_key key_in, key_out;
|
|
||||||
grub_disk_addr_t elemaddr;
|
|
||||||
grub_size_t elemsize;
|
|
||||||
grub_free (data->extent);
|
|
||||||
key_in.object_id = data->inode;
|
|
||||||
key_in.type = GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM;
|
|
||||||
key_in.offset = grub_cpu_to_le64 (pos);
|
|
||||||
err = lower_bound (data, file->device->disk, &key_in, &key_out,
|
|
||||||
data->tree,
|
|
||||||
&elemaddr, &elemsize, NULL);
|
|
||||||
if (err)
|
|
||||||
return -1;
|
|
||||||
if (key_out.object_id != data->inode
|
|
||||||
|| key_out.type != GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM)
|
|
||||||
{
|
|
||||||
grub_error (GRUB_ERR_BAD_FS, "extent not found");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
data->extstart = grub_le_to_cpu64 (key_out.offset);
|
|
||||||
data->extent = grub_malloc (elemsize);
|
|
||||||
if (!data->extent)
|
|
||||||
return grub_errno;
|
|
||||||
|
|
||||||
err = grub_btrfs_read_logical (data, file->device->disk, elemaddr,
|
|
||||||
data->extent, elemsize);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
if (grub_le_to_cpu64 (data->extent->size) + data->extstart <= pos)
|
|
||||||
return grub_error (GRUB_ERR_BAD_FS, "extent not found");
|
|
||||||
grub_dprintf ("btrfs", "extent 0x%" PRIxGRUB_UINT64_T "+0x%"
|
|
||||||
PRIxGRUB_UINT64_T "\n",
|
|
||||||
grub_le_to_cpu64 (key_out.offset),
|
|
||||||
grub_le_to_cpu64 (data->extent->size));
|
|
||||||
}
|
|
||||||
csize = grub_le_to_cpu64 (data->extent->size)
|
|
||||||
+ grub_le_to_cpu64 (data->extstart) - pos;
|
|
||||||
extoff = pos - data->extstart;
|
|
||||||
if (csize > len)
|
|
||||||
csize = len;
|
|
||||||
|
|
||||||
if (data->extent->encryption)
|
|
||||||
{
|
|
||||||
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
|
||||||
"encryption not supported");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data->extent->compression)
|
|
||||||
{
|
|
||||||
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
|
||||||
"compression not supported");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (data->extent->encoding)
|
|
||||||
{
|
|
||||||
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
|
||||||
"encoding not supported");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (data->extent->type)
|
|
||||||
{
|
|
||||||
case GRUB_BTRFS_EXTENT_INLINE:
|
|
||||||
grub_memcpy (buf, data->extent->inl + extoff, csize);
|
|
||||||
break;
|
|
||||||
case GRUB_BTRFS_EXTENT_REGULAR:
|
|
||||||
if (!data->extent->laddr)
|
|
||||||
{
|
|
||||||
grub_memset (buf, 0, csize);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
err = grub_btrfs_read_logical (data, file->device->disk,
|
|
||||||
grub_le_to_cpu64 (data->extent->laddr)
|
|
||||||
+ extoff,
|
|
||||||
buf, csize);
|
|
||||||
if (err)
|
|
||||||
return -1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
|
||||||
"unsupported extent type 0x%x", data->extent->type);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
buf += csize;
|
|
||||||
pos += csize;
|
|
||||||
len -= csize;
|
|
||||||
}
|
|
||||||
return pos - file->offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
|
|
Loading…
Reference in a new issue