support trees

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-12-01 16:22:51 +01:00
parent b18610feb5
commit 355b3eed0f

View file

@ -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);