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;
|
||||
} __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_key key;
|
||||
|
@ -200,6 +207,28 @@ free_iterator (struct grub_btrfs_leaf_descriptor *desc)
|
|||
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
|
||||
next (struct grub_btrfs_data *data, grub_disk_t disk,
|
||||
struct grub_btrfs_leaf_descriptor *desc,
|
||||
|
@ -224,8 +253,26 @@ next (struct grub_btrfs_data *data, grub_disk_t disk,
|
|||
return 0;
|
||||
while (!desc->data[desc->depth - 1].leaf)
|
||||
{
|
||||
grub_printf ("No trees\n");
|
||||
return -grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "no trees yet");
|
||||
struct grub_btrfs_internal_node node;
|
||||
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,
|
||||
desc->data[desc->depth - 1].iter
|
||||
|
@ -242,27 +289,6 @@ next (struct grub_btrfs_data *data, grub_disk_t disk,
|
|||
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
|
||||
lower_bound (struct grub_btrfs_data *data, grub_disk_t disk,
|
||||
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)
|
||||
{
|
||||
grub_disk_addr_t addr = root;
|
||||
struct btrfs_header head;
|
||||
grub_err_t err;
|
||||
unsigned i;
|
||||
struct grub_btrfs_leaf_node leaf, leaf_last;
|
||||
int have_last = 0;
|
||||
int depth = -1;
|
||||
|
||||
if (desc)
|
||||
{
|
||||
|
@ -287,19 +309,80 @@ lower_bound (struct grub_btrfs_data *data, grub_disk_t disk,
|
|||
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)
|
||||
{
|
||||
/* 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));
|
||||
if (err)
|
||||
return err;
|
||||
addr += sizeof (head);
|
||||
if (head.level)
|
||||
{
|
||||
grub_printf ("No trees\n");
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"trees aren't implemented yet");
|
||||
unsigned i;
|
||||
struct grub_btrfs_internal_node node, node_last;
|
||||
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++)
|
||||
{
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
if (key_cmp (&leaf.key, key_in) == 0)
|
||||
|
@ -348,6 +432,7 @@ lower_bound (struct grub_btrfs_data *data, grub_disk_t disk,
|
|||
return GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_btrfs_read_logical (struct grub_btrfs_data *data,
|
||||
|
@ -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)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FS, "extent not found");
|
||||
grub_printf ("no extent\n");
|
||||
return -1;
|
||||
}
|
||||
extent = grub_malloc (elemsize);
|
||||
|
|
Loading…
Reference in a new issue