]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
support trees
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Wed, 1 Dec 2010 15:22:51 +0000 (16:22 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Wed, 1 Dec 2010 15:22:51 +0000 (16:22 +0100)
grub-core/fs/btrfs.c

index 780327702c53798e66e847b24d1c7617a0e82382..ff169e8c47dd6d94a11b24d523593f4194adf4d8 100644 (file)
@@ -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,65 +309,128 @@ 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;
-      if (head.level)
-       {
-         grub_printf ("No trees\n");
-         return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
-                            "trees aren't implemented yet");
-       }
       addr += sizeof (head);
-      for (i = 0; i < grub_le_to_cpu32 (head.nitems); i++)
+      if (head.level)
        {
-         err = grub_btrfs_read_logical (data, disk, addr + i * sizeof (leaf),
-                                        &leaf, sizeof (leaf));
-         if (err)
-           return err;
-
-         grub_dprintf ("btrfs",
-                       "%" PRIxGRUB_UINT64_T " %x %" PRIxGRUB_UINT64_T "\n",
-                      leaf.key.object_id, leaf.key.type, leaf.key.offset);
-
-         if (key_cmp (&leaf.key, key_in) == 0)
+         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;
+               }
+             if (key_cmp (&node.key, key_in) > 0)
+               break;
+             node_last = node;
+             have_last = 1;
+           }
+         if (have_last)
            {
-             grub_memcpy (key_out, &leaf.key, sizeof(*key_out));
-             *outsize = grub_le_to_cpu32 (leaf.size);
-             *outaddr = addr + grub_le_to_cpu32 (leaf.offset);
+             addr = grub_le_to_cpu64 (node_last.blockn);
+             err = GRUB_ERR_NONE;
              if (desc)
-               return save_ref (desc, addr - sizeof (head), i,
-                                grub_le_to_cpu32 (head.nitems), 1);
-             return GRUB_ERR_NONE;           
+               err = save_ref (desc, addr - sizeof (head), i - 1,
+                                grub_le_to_cpu32 (head.nitems), 0);
+             if (err)
+               return err;
+             goto reiter;
            }
-
-         if (key_cmp (&leaf.key, key_in) > 0)
-           break;
-         
-         have_last = 1;
-         leaf_last = leaf;
-       }
-
-      if (have_last)
-       {
-         grub_memcpy (key_out, &leaf_last.key, sizeof(*key_out));
-         *outsize = grub_le_to_cpu32 (leaf_last.size);
-         *outaddr = addr + grub_le_to_cpu32 (leaf_last.offset);
+         *outsize = 0;
+         *outaddr = 0;
+         grub_memset (key_out, 0, sizeof (*key_out));
          if (desc)
-           return save_ref (desc, addr - sizeof (head), i - 1,
-                            grub_le_to_cpu32 (head.nitems), 1);
-         return GRUB_ERR_NONE;       
+           return save_ref (desc, addr - sizeof (head), -1,
+                            grub_le_to_cpu32 (head.nitems), 0);
+         return GRUB_ERR_NONE;
        }
-      *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), 1);
-      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),
+                                          &leaf, sizeof (leaf));
+           if (err)
+             return err;
+           
+           grub_dprintf ("btrfs",
+                         "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)
+             {
+               grub_memcpy (key_out, &leaf.key, sizeof(*key_out));
+               *outsize = grub_le_to_cpu32 (leaf.size);
+               *outaddr = addr + grub_le_to_cpu32 (leaf.offset);
+               if (desc)
+                 return save_ref (desc, addr - sizeof (head), i,
+                                  grub_le_to_cpu32 (head.nitems), 1);
+               return GRUB_ERR_NONE;         
+             }
+           
+           if (key_cmp (&leaf.key, key_in) > 0)
+             break;
+           
+           have_last = 1;
+           leaf_last = leaf;
+         }
+
+       if (have_last)
+         {
+           grub_memcpy (key_out, &leaf_last.key, sizeof(*key_out));
+           *outsize = grub_le_to_cpu32 (leaf_last.size);
+           *outaddr = addr + grub_le_to_cpu32 (leaf_last.offset);
+           if (desc)
+             return save_ref (desc, addr - sizeof (head), i - 1,
+                              grub_le_to_cpu32 (head.nitems), 1);
+           return GRUB_ERR_NONE;             
+         }
+       *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), 1);
+       return GRUB_ERR_NONE;
+      }
     }
 }
 
@@ -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);