support trees
This commit is contained in:
parent
b18610feb5
commit
355b3eed0f
1 changed files with 161 additions and 77 deletions
|
@ -109,6 +109,13 @@ struct grub_btrfs_leaf_node
|
||||||
grub_uint32_t size;
|
grub_uint32_t size;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct grub_btrfs_internal_node
|
||||||
|
{
|
||||||
|
struct grub_btrfs_key key;
|
||||||
|
grub_uint64_t blockn;
|
||||||
|
grub_uint64_t dummy;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct grub_btrfs_dir_item
|
struct grub_btrfs_dir_item
|
||||||
{
|
{
|
||||||
struct grub_btrfs_key key;
|
struct grub_btrfs_key key;
|
||||||
|
@ -200,6 +207,28 @@ free_iterator (struct grub_btrfs_leaf_descriptor *desc)
|
||||||
grub_free (desc->data);
|
grub_free (desc->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static grub_err_t
|
||||||
|
save_ref (struct grub_btrfs_leaf_descriptor *desc,
|
||||||
|
grub_disk_addr_t addr, unsigned i, unsigned m, int l)
|
||||||
|
{
|
||||||
|
desc->depth++;
|
||||||
|
if (desc->allocated > desc->depth)
|
||||||
|
{
|
||||||
|
void *newdata;
|
||||||
|
desc->allocated *= 2;
|
||||||
|
newdata = grub_realloc (desc->data, sizeof (desc->data[0])
|
||||||
|
* desc->allocated);
|
||||||
|
if (!newdata)
|
||||||
|
return grub_errno;
|
||||||
|
desc->data = newdata;
|
||||||
|
}
|
||||||
|
desc->data[desc->depth - 1].addr = addr;
|
||||||
|
desc->data[desc->depth - 1].iter = i;
|
||||||
|
desc->data[desc->depth - 1].maxiter = m;
|
||||||
|
desc->data[desc->depth - 1].leaf = l;
|
||||||
|
return GRUB_ERR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
next (struct grub_btrfs_data *data, grub_disk_t disk,
|
next (struct grub_btrfs_data *data, grub_disk_t disk,
|
||||||
struct grub_btrfs_leaf_descriptor *desc,
|
struct grub_btrfs_leaf_descriptor *desc,
|
||||||
|
@ -224,8 +253,26 @@ next (struct grub_btrfs_data *data, grub_disk_t disk,
|
||||||
return 0;
|
return 0;
|
||||||
while (!desc->data[desc->depth - 1].leaf)
|
while (!desc->data[desc->depth - 1].leaf)
|
||||||
{
|
{
|
||||||
grub_printf ("No trees\n");
|
struct grub_btrfs_internal_node node;
|
||||||
return -grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "no trees yet");
|
struct btrfs_header head;
|
||||||
|
|
||||||
|
err = grub_btrfs_read_logical (data, disk,
|
||||||
|
desc->data[desc->depth - 1].iter
|
||||||
|
* sizeof (node)
|
||||||
|
+ sizeof (struct btrfs_header)
|
||||||
|
+ desc->data[desc->depth - 1].addr, &node,
|
||||||
|
sizeof (node));
|
||||||
|
if (err)
|
||||||
|
return -err;
|
||||||
|
|
||||||
|
err = grub_btrfs_read_logical (data, disk,
|
||||||
|
grub_le_to_cpu64 (node.blockn), &head,
|
||||||
|
sizeof (head));
|
||||||
|
if (err)
|
||||||
|
return -err;
|
||||||
|
|
||||||
|
save_ref (desc, grub_le_to_cpu64 (node.blockn), 0,
|
||||||
|
grub_le_to_cpu32 (head.nitems), !head.level);
|
||||||
}
|
}
|
||||||
err = grub_btrfs_read_logical (data, disk,
|
err = grub_btrfs_read_logical (data, disk,
|
||||||
desc->data[desc->depth - 1].iter
|
desc->data[desc->depth - 1].iter
|
||||||
|
@ -242,27 +289,6 @@ next (struct grub_btrfs_data *data, grub_disk_t disk,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static grub_err_t
|
|
||||||
save_ref (struct grub_btrfs_leaf_descriptor *desc,
|
|
||||||
grub_disk_addr_t addr, unsigned i, unsigned m, int l)
|
|
||||||
{
|
|
||||||
desc->depth++;
|
|
||||||
if (desc->allocated > desc->depth)
|
|
||||||
{
|
|
||||||
void *newdata;
|
|
||||||
desc->allocated *= 2;
|
|
||||||
newdata = grub_realloc (desc->data, sizeof (desc->data[0])
|
|
||||||
* desc->allocated);
|
|
||||||
if (!newdata)
|
|
||||||
return grub_errno;
|
|
||||||
}
|
|
||||||
desc->data[desc->depth - 1].addr = addr;
|
|
||||||
desc->data[desc->depth - 1].iter = i;
|
|
||||||
desc->data[desc->depth - 1].maxiter = m;
|
|
||||||
desc->data[desc->depth - 1].leaf = l;
|
|
||||||
return GRUB_ERR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
lower_bound (struct grub_btrfs_data *data, grub_disk_t disk,
|
lower_bound (struct grub_btrfs_data *data, grub_disk_t disk,
|
||||||
const struct grub_btrfs_key *key_in,
|
const struct grub_btrfs_key *key_in,
|
||||||
|
@ -272,11 +298,7 @@ lower_bound (struct grub_btrfs_data *data, grub_disk_t disk,
|
||||||
struct grub_btrfs_leaf_descriptor *desc)
|
struct grub_btrfs_leaf_descriptor *desc)
|
||||||
{
|
{
|
||||||
grub_disk_addr_t addr = root;
|
grub_disk_addr_t addr = root;
|
||||||
struct btrfs_header head;
|
int depth = -1;
|
||||||
grub_err_t err;
|
|
||||||
unsigned i;
|
|
||||||
struct grub_btrfs_leaf_node leaf, leaf_last;
|
|
||||||
int have_last = 0;
|
|
||||||
|
|
||||||
if (desc)
|
if (desc)
|
||||||
{
|
{
|
||||||
|
@ -287,19 +309,80 @@ lower_bound (struct grub_btrfs_data *data, grub_disk_t disk,
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
grub_dprintf ("btrfs",
|
||||||
|
"retrieving %" PRIxGRUB_UINT64_T
|
||||||
|
" %x %" PRIxGRUB_UINT64_T "\n",
|
||||||
|
key_in->object_id, key_in->type, key_in->offset);
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
/* FIXME: preread few leafs into buffer. */
|
grub_err_t err;
|
||||||
|
struct btrfs_header head;
|
||||||
|
|
||||||
|
reiter:
|
||||||
|
depth++;
|
||||||
|
/* FIXME: preread few nodes into buffer. */
|
||||||
err = grub_btrfs_read_logical (data, disk, addr, &head, sizeof (head));
|
err = grub_btrfs_read_logical (data, disk, addr, &head, sizeof (head));
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
addr += sizeof (head);
|
||||||
if (head.level)
|
if (head.level)
|
||||||
{
|
{
|
||||||
grub_printf ("No trees\n");
|
unsigned i;
|
||||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
struct grub_btrfs_internal_node node, node_last;
|
||||||
"trees aren't implemented yet");
|
int have_last = 0;
|
||||||
|
for (i = 0; i < grub_le_to_cpu32 (head.nitems); i++)
|
||||||
|
{
|
||||||
|
err = grub_btrfs_read_logical (data, disk, addr
|
||||||
|
+ i * sizeof (node),
|
||||||
|
&node, sizeof (node));
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
grub_dprintf ("btrfs",
|
||||||
|
"internal node (depth %d) %" PRIxGRUB_UINT64_T
|
||||||
|
" %x %" PRIxGRUB_UINT64_T "\n", depth,
|
||||||
|
node.key.object_id, node.key.type, node.key.offset);
|
||||||
|
|
||||||
|
if (key_cmp (&node.key, key_in) == 0)
|
||||||
|
{
|
||||||
|
err = GRUB_ERR_NONE;
|
||||||
|
if (desc)
|
||||||
|
err = save_ref (desc, addr - sizeof (head), i,
|
||||||
|
grub_le_to_cpu32 (head.nitems), 0);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
addr = grub_le_to_cpu64 (node.blockn);
|
||||||
|
goto reiter;
|
||||||
}
|
}
|
||||||
addr += sizeof (head);
|
if (key_cmp (&node.key, key_in) > 0)
|
||||||
|
break;
|
||||||
|
node_last = node;
|
||||||
|
have_last = 1;
|
||||||
|
}
|
||||||
|
if (have_last)
|
||||||
|
{
|
||||||
|
addr = grub_le_to_cpu64 (node_last.blockn);
|
||||||
|
err = GRUB_ERR_NONE;
|
||||||
|
if (desc)
|
||||||
|
err = save_ref (desc, addr - sizeof (head), i - 1,
|
||||||
|
grub_le_to_cpu32 (head.nitems), 0);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
goto reiter;
|
||||||
|
}
|
||||||
|
*outsize = 0;
|
||||||
|
*outaddr = 0;
|
||||||
|
grub_memset (key_out, 0, sizeof (*key_out));
|
||||||
|
if (desc)
|
||||||
|
return save_ref (desc, addr - sizeof (head), -1,
|
||||||
|
grub_le_to_cpu32 (head.nitems), 0);
|
||||||
|
return GRUB_ERR_NONE;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
struct grub_btrfs_leaf_node leaf, leaf_last;
|
||||||
|
int have_last = 0;
|
||||||
for (i = 0; i < grub_le_to_cpu32 (head.nitems); i++)
|
for (i = 0; i < grub_le_to_cpu32 (head.nitems); i++)
|
||||||
{
|
{
|
||||||
err = grub_btrfs_read_logical (data, disk, addr + i * sizeof (leaf),
|
err = grub_btrfs_read_logical (data, disk, addr + i * sizeof (leaf),
|
||||||
|
@ -308,7 +391,8 @@ lower_bound (struct grub_btrfs_data *data, grub_disk_t disk,
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
grub_dprintf ("btrfs",
|
grub_dprintf ("btrfs",
|
||||||
"%" PRIxGRUB_UINT64_T " %x %" PRIxGRUB_UINT64_T "\n",
|
"leaf (depth %d) %" PRIxGRUB_UINT64_T
|
||||||
|
" %x %" PRIxGRUB_UINT64_T "\n", depth,
|
||||||
leaf.key.object_id, leaf.key.type, leaf.key.offset);
|
leaf.key.object_id, leaf.key.type, leaf.key.offset);
|
||||||
|
|
||||||
if (key_cmp (&leaf.key, key_in) == 0)
|
if (key_cmp (&leaf.key, key_in) == 0)
|
||||||
|
@ -347,6 +431,7 @@ lower_bound (struct grub_btrfs_data *data, grub_disk_t disk,
|
||||||
grub_le_to_cpu32 (head.nitems), 1);
|
grub_le_to_cpu32 (head.nitems), 1);
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
|
@ -809,7 +894,6 @@ grub_btrfs_read (grub_file_t file, char *buf, grub_size_t len)
|
||||||
|| key_out.type != GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM)
|
|| key_out.type != GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM)
|
||||||
{
|
{
|
||||||
grub_error (GRUB_ERR_BAD_FS, "extent not found");
|
grub_error (GRUB_ERR_BAD_FS, "extent not found");
|
||||||
grub_printf ("no extent\n");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
extent = grub_malloc (elemsize);
|
extent = grub_malloc (elemsize);
|
||||||
|
|
Loading…
Reference in a new issue