]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Read label on HFS+.
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Tue, 25 Oct 2011 22:32:17 +0000 (00:32 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Tue, 25 Oct 2011 22:32:17 +0000 (00:32 +0200)
* grub-core/fs/hfsplus.c (grub_hfsplus_cmp_catkey_id): New function.
(grub_hfsplus_btree_search): Fix types.
(grub_hfsplus_label): Implement.

ChangeLog
grub-core/fs/hfsplus.c

index 3b0b4697a23cfe620294866b42f98b25579f2b58..17e215b6228771afef829f0c41d9742642e9f371 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2011-10-25  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Read label on HFS+.
+
+       * grub-core/fs/hfsplus.c (grub_hfsplus_cmp_catkey_id): New function.
+       (grub_hfsplus_btree_search): Fix types.
+       (grub_hfsplus_label): Implement.
+
 2011-10-25  Vladimir Serbinenko  <phcoder@gmail.com>
 
        * grub-core/fs/ntfs.c (grub_ntfs_uuid): Fix a memory leak.
index 245cd93a5d181fd111e60131b0eadc22d34f65be..3d9bc42fa4279324c70a16a7f1e1a958391eb3ea 100644 (file)
@@ -553,6 +553,25 @@ grub_hfsplus_cmp_catkey (struct grub_hfsplus_key *keya,
   return diff;
 }
 
+/* Compare the on disk catalog key KEYA with the catalog key we are
+   looking for (KEYB).  */
+static int
+grub_hfsplus_cmp_catkey_id (struct grub_hfsplus_key *keya,
+                        struct grub_hfsplus_key_internal *keyb)
+{
+  struct grub_hfsplus_catkey *catkey_a = &keya->catkey;
+  struct grub_hfsplus_catkey_internal *catkey_b = &keyb->catkey;
+
+  /* Safe unsigned comparison */
+  grub_uint32_t aparent = grub_be_to_cpu32 (catkey_a->parent);
+  if (aparent > catkey_b->parent)
+    return 1;
+  if (aparent < catkey_b->parent)
+    return -1;
+
+  return 0;
+}
+
 /* Compare the on disk extent overflow key KEYA with the extent
    overflow key we are looking for (KEYB).  */
 static int
@@ -662,7 +681,8 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree,
 
       /* Read a node.  */
       if (grub_hfsplus_read_file (&btree->file, 0,
-                                 (long)currnode * (long)btree->nodesize,
+                                 (grub_disk_addr_t) currnode
+                                 * (grub_disk_addr_t) btree->nodesize,
                                  btree->nodesize, (char *) node) <= 0)
        {
          grub_free (node);
@@ -961,13 +981,66 @@ grub_hfsplus_dir (grub_device_t device, const char *path,
 
 
 static grub_err_t
-grub_hfsplus_label (grub_device_t device __attribute__((unused))
-                   , char **label __attribute__((unused)))
+grub_hfsplus_label (grub_device_t device, char **label)
 {
-  /* XXX: It's not documented how to read a label.  */
-  return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
-                    "reading the label of a HFS+ "
-                    "partition is not implemented");
+  struct grub_hfsplus_data *data;
+  grub_disk_t disk = device->disk;
+  struct grub_hfsplus_catkey *catkey;
+  int i, label_len;
+  struct grub_hfsplus_key_internal intern;
+  struct grub_hfsplus_btnode *node;
+  grub_disk_addr_t ptr;
+
+  *label = 0;
+
+  data = grub_hfsplus_mount (disk);
+  if (!data)
+    return grub_errno;
+
+  /* Create a key that points to the label.  */
+  intern.catkey.parent = 1;
+  intern.catkey.name = "";
+
+  /* First lookup the first entry.  */
+  if (grub_hfsplus_btree_search (&data->catalog_tree, &intern,
+                                grub_hfsplus_cmp_catkey_id, &node, &ptr))
+    {
+      grub_free (data);
+      return 0;
+    }
+
+  catkey = (struct grub_hfsplus_catkey *)
+    grub_hfsplus_btree_recptr (&data->catalog_tree, node, 0);
+
+  label_len = grub_be_to_cpu16 (catkey->namelen);
+  for (i = 0; i < label_len; i++)
+    {
+      catkey->name[i] = grub_be_to_cpu16 (catkey->name[i]);
+
+      /* If the name is obviously invalid, skip this node.  */
+      if (catkey->name[i] == 0)
+       return 0;
+    }
+
+  *label = grub_malloc (label_len + 1);
+  if (! *label)
+    return grub_errno;
+
+  if (! grub_utf16_to_utf8 ((grub_uint8_t *) (*label), catkey->name,
+                           label_len))
+    {
+      grub_free (node);
+      grub_free (*label);
+      grub_free (data);
+      *label = 0;
+      return grub_errno;
+    }
+  (*label)[label_len] = '\0';
+
+  grub_free (node);
+  grub_free (data);
+
+  return GRUB_ERR_NONE;
 }
 
 /* Get mtime.  */