Blame SOURCES/0441-Compressed-HFS-support.patch

f96e0b
From 14aa7e045965ce95779e17e20503191f8f6bc160 Mon Sep 17 00:00:00 2001
f96e0b
From: Vladimir 'phcoder' Serbinenko <phcoder@gmail.com>
f96e0b
Date: Tue, 7 May 2013 15:46:17 +0200
f96e0b
Subject: [PATCH 441/482] 	Compressed HFS+ support.
f96e0b
f96e0b
---
f96e0b
 ChangeLog                   |   4 +
f96e0b
 Makefile.util.def           |   1 +
f96e0b
 grub-core/Makefile.core.def |   5 +
f96e0b
 grub-core/fs/hfsplus.c      | 272 +++++++++++++--------------------------
f96e0b
 grub-core/fs/hfspluscomp.c  | 302 ++++++++++++++++++++++++++++++++++++++++++++
f96e0b
 include/grub/hfsplus.h      | 217 +++++++++++++++++++++++++++++++
f96e0b
 6 files changed, 618 insertions(+), 183 deletions(-)
f96e0b
 create mode 100644 grub-core/fs/hfspluscomp.c
f96e0b
 create mode 100644 include/grub/hfsplus.h
f96e0b
f96e0b
diff --git a/ChangeLog b/ChangeLog
f96e0b
index 8b77759..0430249 100644
f96e0b
--- a/ChangeLog
f96e0b
+++ b/ChangeLog
f96e0b
@@ -1,5 +1,9 @@
f96e0b
 2013-05-07  Vladimir Serbinenko  <phcoder@gmail.com>
f96e0b
 
f96e0b
+	Compressed HFS+ support.
f96e0b
+
f96e0b
+2013-05-07  Vladimir Serbinenko  <phcoder@gmail.com>
f96e0b
+
f96e0b
 	* grub-core/commands/videoinfo.c: Use "paletted" rather than "packed
f96e0b
 	pixel".
f96e0b
 
f96e0b
diff --git a/Makefile.util.def b/Makefile.util.def
f96e0b
index 5888314..dc621db 100644
f96e0b
--- a/Makefile.util.def
f96e0b
+++ b/Makefile.util.def
f96e0b
@@ -85,6 +85,7 @@ library = {
f96e0b
   common = grub-core/fs/fshelp.c;
f96e0b
   common = grub-core/fs/hfs.c;
f96e0b
   common = grub-core/fs/hfsplus.c;
f96e0b
+  common = grub-core/fs/hfspluscomp.c;
f96e0b
   common = grub-core/fs/iso9660.c;
f96e0b
   common = grub-core/fs/jfs.c;
f96e0b
   common = grub-core/fs/minix.c;
f96e0b
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
f96e0b
index 7dc106e..bb62dce 100644
f96e0b
--- a/grub-core/Makefile.core.def
f96e0b
+++ b/grub-core/Makefile.core.def
f96e0b
@@ -1186,6 +1186,11 @@ module = {
f96e0b
 };
f96e0b
 
f96e0b
 module = {
f96e0b
+  name = hfspluscomp;
f96e0b
+  common = fs/hfspluscomp.c;
f96e0b
+};
f96e0b
+
f96e0b
+module = {
f96e0b
   name = iso9660;
f96e0b
   common = fs/iso9660.c;
f96e0b
 };
f96e0b
diff --git a/grub-core/fs/hfsplus.c b/grub-core/fs/hfsplus.c
f96e0b
index a507c0f..7905624 100644
f96e0b
--- a/grub-core/fs/hfsplus.c
f96e0b
+++ b/grub-core/fs/hfsplus.c
f96e0b
@@ -19,6 +19,7 @@
f96e0b
 
f96e0b
 /* HFS+ is documented at http://developer.apple.com/technotes/tn/tn1150.html */
f96e0b
 
f96e0b
+#define grub_fshelp_node grub_hfsplus_file 
f96e0b
 #include <grub/err.h>
f96e0b
 #include <grub/file.h>
f96e0b
 #include <grub/mm.h>
f96e0b
@@ -29,6 +30,7 @@
f96e0b
 #include <grub/fshelp.h>
f96e0b
 #include <grub/hfs.h>
f96e0b
 #include <grub/charset.h>
f96e0b
+#include <grub/hfsplus.h>
f96e0b
 
f96e0b
 GRUB_MOD_LICENSE ("GPLv3+");
f96e0b
 
f96e0b
@@ -36,42 +38,6 @@ GRUB_MOD_LICENSE ("GPLv3+");
f96e0b
 #define GRUB_HFSPLUSX_MAGIC 0x4858
f96e0b
 #define GRUB_HFSPLUS_SBLOCK 2
f96e0b
 
f96e0b
-/* A HFS+ extent.  */
f96e0b
-struct grub_hfsplus_extent
f96e0b
-{
f96e0b
-  /* The first block of a file on disk.  */
f96e0b
-  grub_uint32_t start;
f96e0b
-  /* The amount of blocks described by this extent.  */
f96e0b
-  grub_uint32_t count;
f96e0b
-} __attribute__ ((packed));
f96e0b
-
f96e0b
-/* The descriptor of a fork.  */
f96e0b
-struct grub_hfsplus_forkdata
f96e0b
-{
f96e0b
-  grub_uint64_t size;
f96e0b
-  grub_uint32_t clumpsize;
f96e0b
-  grub_uint32_t blocks;
f96e0b
-  struct grub_hfsplus_extent extents[8];
f96e0b
-} __attribute__ ((packed));
f96e0b
-
f96e0b
-/* The HFS+ Volume Header.  */
f96e0b
-struct grub_hfsplus_volheader
f96e0b
-{
f96e0b
-  grub_uint16_t magic;
f96e0b
-  grub_uint16_t version;
f96e0b
-  grub_uint32_t attributes;
f96e0b
-  grub_uint8_t unused1[12];
f96e0b
-  grub_uint32_t utime;
f96e0b
-  grub_uint8_t unused2[16];
f96e0b
-  grub_uint32_t blksize;
f96e0b
-  grub_uint8_t unused3[60];
f96e0b
-  grub_uint64_t num_serial;
f96e0b
-  struct grub_hfsplus_forkdata allocations_file;
f96e0b
-  struct grub_hfsplus_forkdata extents_file;
f96e0b
-  struct grub_hfsplus_forkdata catalog_file;
f96e0b
-  struct grub_hfsplus_forkdata attrib_file;
f96e0b
-  struct grub_hfsplus_forkdata startup_file;
f96e0b
-} __attribute__ ((packed));
f96e0b
 
f96e0b
 /* The type of node.  */
f96e0b
 enum grub_hfsplus_btnode_type
f96e0b
@@ -82,16 +48,6 @@ enum grub_hfsplus_btnode_type
f96e0b
     GRUB_HFSPLUS_BTNODE_TYPE_MAP = 2,
f96e0b
   };
f96e0b
 
f96e0b
-struct grub_hfsplus_btnode
f96e0b
-{
f96e0b
-  grub_uint32_t next;
f96e0b
-  grub_uint32_t prev;
f96e0b
-  grub_int8_t type;
f96e0b
-  grub_uint8_t height;
f96e0b
-  grub_uint16_t count;
f96e0b
-  grub_uint16_t unused;
f96e0b
-} __attribute__ ((packed));
f96e0b
-
f96e0b
 /* The header of a HFS+ B+ Tree.  */
f96e0b
 struct grub_hfsplus_btheader
f96e0b
 {
f96e0b
@@ -111,35 +67,6 @@ struct grub_hfsplus_btheader
f96e0b
   grub_uint32_t attributes;
f96e0b
 } __attribute__ ((packed));
f96e0b
 
f96e0b
-/* The on disk layout of a catalog key.  */
f96e0b
-struct grub_hfsplus_catkey
f96e0b
-{
f96e0b
-  grub_uint16_t keylen;
f96e0b
-  grub_uint32_t parent;
f96e0b
-  grub_uint16_t namelen;
f96e0b
-  grub_uint16_t name[30];
f96e0b
-} __attribute__ ((packed));
f96e0b
-
f96e0b
-/* The on disk layout of an extent overflow file key.  */
f96e0b
-struct grub_hfsplus_extkey
f96e0b
-{
f96e0b
-  grub_uint16_t keylen;
f96e0b
-  grub_uint8_t type;
f96e0b
-  grub_uint8_t unused;
f96e0b
-  grub_uint32_t fileid;
f96e0b
-  grub_uint32_t start;
f96e0b
-} __attribute__ ((packed));
f96e0b
-
f96e0b
-struct grub_hfsplus_key
f96e0b
-{
f96e0b
-  union
f96e0b
-  {
f96e0b
-    struct grub_hfsplus_extkey extkey;
f96e0b
-    struct grub_hfsplus_catkey catkey;
f96e0b
-    grub_uint16_t keylen;
f96e0b
-  };
f96e0b
-} __attribute__ ((packed));
f96e0b
-
f96e0b
 struct grub_hfsplus_catfile
f96e0b
 {
f96e0b
   grub_uint16_t type;
f96e0b
@@ -162,9 +89,13 @@ struct grub_hfsplus_catfile
f96e0b
 #define GRUB_HFSPLUS_FILEMODE_SYMLINK	0120000
f96e0b
 
f96e0b
 /* Some pre-defined file IDs.  */
f96e0b
-#define GRUB_HFSPLUS_FILEID_ROOTDIR	2
f96e0b
-#define GRUB_HFSPLUS_FILEID_OVERFLOW	3
f96e0b
-#define GRUB_HFSPLUS_FILEID_CATALOG	4
f96e0b
+enum
f96e0b
+  {
f96e0b
+    GRUB_HFSPLUS_FILEID_ROOTDIR = 2,
f96e0b
+    GRUB_HFSPLUS_FILEID_OVERFLOW = 3,
f96e0b
+    GRUB_HFSPLUS_FILEID_CATALOG	= 4,
f96e0b
+    GRUB_HFSPLUS_FILEID_ATTR	= 8
f96e0b
+  };
f96e0b
 
f96e0b
 enum grub_hfsplus_filetype
f96e0b
   {
f96e0b
@@ -177,98 +108,15 @@ enum grub_hfsplus_filetype
f96e0b
 #define GRUB_HFSPLUSX_BINARYCOMPARE	0xBC
f96e0b
 #define GRUB_HFSPLUSX_CASEFOLDING	0xCF
f96e0b
 
f96e0b
-/* Internal representation of a catalog key.  */
f96e0b
-struct grub_hfsplus_catkey_internal
f96e0b
-{
f96e0b
-  grub_uint32_t parent;
f96e0b
-  const grub_uint16_t *name;
f96e0b
-  grub_size_t namelen;
f96e0b
-};
f96e0b
-
f96e0b
-/* Internal representation of an extent overflow key.  */
f96e0b
-struct grub_hfsplus_extkey_internal
f96e0b
-{
f96e0b
-  grub_uint32_t fileid;
f96e0b
-  grub_uint8_t type;
f96e0b
-  grub_uint32_t start;
f96e0b
-};
f96e0b
-
f96e0b
-struct grub_hfsplus_key_internal
f96e0b
-{
f96e0b
-  union
f96e0b
-  {
f96e0b
-    struct grub_hfsplus_extkey_internal extkey;
f96e0b
-    struct grub_hfsplus_catkey_internal catkey;
f96e0b
-  };
f96e0b
-};
f96e0b
-
f96e0b
-
f96e0b
-
f96e0b
-struct grub_fshelp_node
f96e0b
-{
f96e0b
-  struct grub_hfsplus_data *data;
f96e0b
-  struct grub_hfsplus_extent extents[8];
f96e0b
-  grub_uint64_t size;
f96e0b
-  grub_uint32_t fileid;
f96e0b
-  grub_int32_t mtime;
f96e0b
-};
f96e0b
-
f96e0b
-struct grub_hfsplus_btree
f96e0b
-{
f96e0b
-  grub_uint32_t root;
f96e0b
-  grub_size_t nodesize;
f96e0b
-
f96e0b
-  /* Catalog file node.  */
f96e0b
-  struct grub_fshelp_node file;
f96e0b
-};
f96e0b
-
f96e0b
-/* Information about a "mounted" HFS+ filesystem.  */
f96e0b
-struct grub_hfsplus_data
f96e0b
-{
f96e0b
-  struct grub_hfsplus_volheader volheader;
f96e0b
-  grub_disk_t disk;
f96e0b
-
f96e0b
-  unsigned int log2blksize;
f96e0b
-
f96e0b
-  struct grub_hfsplus_btree catalog_tree;
f96e0b
-  struct grub_hfsplus_btree extoverflow_tree;
f96e0b
-
f96e0b
-  struct grub_fshelp_node dirroot;
f96e0b
-  struct grub_fshelp_node opened_file;
f96e0b
-
f96e0b
-  /* This is the offset into the physical disk for an embedded HFS+
f96e0b
-     filesystem (one inside a plain HFS wrapper).  */
f96e0b
-  grub_disk_addr_t embedded_offset;
f96e0b
-  int case_sensitive;
f96e0b
-};
f96e0b
-
f96e0b
 static grub_dl_t my_mod;
f96e0b
 
f96e0b
 
f96e0b
-/* Return the offset of the record with the index INDEX, in the node
f96e0b
-   NODE which is part of the B+ tree BTREE.  */
f96e0b
-static inline grub_off_t
f96e0b
-grub_hfsplus_btree_recoffset (struct grub_hfsplus_btree *btree,
f96e0b
-			   struct grub_hfsplus_btnode *node, int index)
f96e0b
-{
f96e0b
-  char *cnode = (char *) node;
f96e0b
-  void *recptr;
f96e0b
-  recptr = (&cnode[btree->nodesize - index * sizeof (grub_uint16_t) - 2]);
f96e0b
-  return grub_be_to_cpu16 (grub_get_unaligned16 (recptr));
f96e0b
-}
f96e0b
-
f96e0b
-/* Return a pointer to the record with the index INDEX, in the node
f96e0b
-   NODE which is part of the B+ tree BTREE.  */
f96e0b
-static inline struct grub_hfsplus_key *
f96e0b
-grub_hfsplus_btree_recptr (struct grub_hfsplus_btree *btree,
f96e0b
-			   struct grub_hfsplus_btnode *node, int index)
f96e0b
-{
f96e0b
-  char *cnode = (char *) node;
f96e0b
-  grub_off_t offset;
f96e0b
-  offset = grub_hfsplus_btree_recoffset (btree, node, index);
f96e0b
-  return (struct grub_hfsplus_key *) &cnode[offset];
f96e0b
-}
f96e0b
 
f96e0b
+grub_err_t (*grub_hfsplus_open_compressed) (struct grub_fshelp_node *node);
f96e0b
+grub_ssize_t (*grub_hfsplus_read_compressed) (struct grub_hfsplus_file *node,
f96e0b
+					      grub_off_t pos,
f96e0b
+					      grub_size_t len,
f96e0b
+					      char *buf);
f96e0b
 
f96e0b
 /* Find the extent that points to FILEBLOCK.  If it is not in one of
f96e0b
    the 8 extents described by EXTENT, return -1.  In that case set
f96e0b
@@ -292,14 +140,6 @@ grub_hfsplus_find_block (struct grub_hfsplus_extent *extent,
f96e0b
   return 0xffffffffffffffffULL;
f96e0b
 }
f96e0b
 
f96e0b
-static grub_err_t
f96e0b
-grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree,
f96e0b
-			   struct grub_hfsplus_key_internal *key,
f96e0b
-			   int (*compare_keys) (struct grub_hfsplus_key *keya,
f96e0b
-						struct grub_hfsplus_key_internal *keyb),
f96e0b
-			   struct grub_hfsplus_btnode **matchnode, 
f96e0b
-			   grub_off_t *keyoffset);
f96e0b
-
f96e0b
 static int grub_hfsplus_cmp_extkey (struct grub_hfsplus_key *keya,
f96e0b
 				    struct grub_hfsplus_key_internal *keyb);
f96e0b
 
f96e0b
@@ -310,7 +150,8 @@ grub_hfsplus_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
f96e0b
 {
f96e0b
   struct grub_hfsplus_btnode *nnode = 0;
f96e0b
   grub_disk_addr_t blksleft = fileblock;
f96e0b
-  struct grub_hfsplus_extent *extents = &node->extents[0];
f96e0b
+  struct grub_hfsplus_extent *extents = node->compressed 
f96e0b
+    ? &node->resource_extents[0] : &node->extents[0];
f96e0b
 
f96e0b
   while (1)
f96e0b
     {
f96e0b
@@ -344,10 +185,11 @@ grub_hfsplus_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
f96e0b
       extoverflow.extkey.fileid = node->fileid;
f96e0b
       extoverflow.extkey.type = 0;
f96e0b
       extoverflow.extkey.start = fileblock - blksleft;
f96e0b
-
f96e0b
+      extoverflow.extkey.type = node->compressed ? 0xff : 0;
f96e0b
       if (grub_hfsplus_btree_search (&node->data->extoverflow_tree,
f96e0b
 				     &extoverflow,
f96e0b
-				     grub_hfsplus_cmp_extkey, &nnode, &ptr))
f96e0b
+				     grub_hfsplus_cmp_extkey, &nnode, &ptr)
f96e0b
+	  || !nnode)
f96e0b
 	{
f96e0b
 	  grub_error (GRUB_ERR_READ_ERROR,
f96e0b
 		      "no block found for the file id 0x%x and the block offset 0x%x",
f96e0b
@@ -373,7 +215,7 @@ grub_hfsplus_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
f96e0b
 
f96e0b
 /* Read LEN bytes from the file described by DATA starting with byte
f96e0b
    POS.  Return the amount of read bytes in READ.  */
f96e0b
-static grub_ssize_t
f96e0b
+grub_ssize_t
f96e0b
 grub_hfsplus_read_file (grub_fshelp_node_t node,
f96e0b
 			grub_disk_read_hook_t read_hook, void *read_hook_data,
f96e0b
 			grub_off_t pos, grub_size_t len, char *buf)
f96e0b
@@ -460,15 +302,27 @@ grub_hfsplus_mount (grub_disk_t disk)
f96e0b
   /* Make a new node for the catalog tree.  */
f96e0b
   data->catalog_tree.file.data = data;
f96e0b
   data->catalog_tree.file.fileid = GRUB_HFSPLUS_FILEID_CATALOG;
f96e0b
+  data->catalog_tree.file.compressed = 0;
f96e0b
   grub_memcpy (&data->catalog_tree.file.extents,
f96e0b
 	       data->volheader.catalog_file.extents,
f96e0b
 	       sizeof data->volheader.catalog_file.extents);
f96e0b
   data->catalog_tree.file.size =
f96e0b
     grub_be_to_cpu64 (data->volheader.catalog_file.size);
f96e0b
 
f96e0b
+  data->attr_tree.file.data = data;
f96e0b
+  data->attr_tree.file.fileid = GRUB_HFSPLUS_FILEID_ATTR;
f96e0b
+  grub_memcpy (&data->attr_tree.file.extents,
f96e0b
+	       data->volheader.attr_file.extents,
f96e0b
+	       sizeof data->volheader.attr_file.extents);
f96e0b
+
f96e0b
+  data->attr_tree.file.size =
f96e0b
+    grub_be_to_cpu64 (data->volheader.attr_file.size);
f96e0b
+  data->attr_tree.file.compressed = 0;
f96e0b
+
f96e0b
   /* Make a new node for the extent overflow file.  */
f96e0b
   data->extoverflow_tree.file.data = data;
f96e0b
   data->extoverflow_tree.file.fileid = GRUB_HFSPLUS_FILEID_OVERFLOW;
f96e0b
+  data->extoverflow_tree.file.compressed = 0;
f96e0b
   grub_memcpy (&data->extoverflow_tree.file.extents,
f96e0b
 	       data->volheader.extents_file.extents,
f96e0b
 	       sizeof data->volheader.catalog_file.extents);
f96e0b
@@ -501,6 +355,20 @@ grub_hfsplus_mount (grub_disk_t disk)
f96e0b
   data->extoverflow_tree.root = grub_be_to_cpu32 (header.root);
f96e0b
   data->extoverflow_tree.nodesize = grub_be_to_cpu16 (header.nodesize);
f96e0b
 
f96e0b
+  if (grub_hfsplus_read_file (&data->attr_tree.file, 0, 0,
f96e0b
+			      sizeof (struct grub_hfsplus_btnode),
f96e0b
+			      sizeof (header), (char *) &header) <= 0)
f96e0b
+    {
f96e0b
+      grub_errno = 0;
f96e0b
+      data->attr_tree.root = 0;
f96e0b
+      data->attr_tree.nodesize = 0;
f96e0b
+    }
f96e0b
+  else
f96e0b
+    {
f96e0b
+      data->attr_tree.root = grub_be_to_cpu32 (header.root);
f96e0b
+      data->attr_tree.nodesize = grub_be_to_cpu16 (header.nodesize);
f96e0b
+    }
f96e0b
+
f96e0b
   data->dirroot.data = data;
f96e0b
   data->dirroot.fileid = GRUB_HFSPLUS_FILEID_ROOTDIR;
f96e0b
 
f96e0b
@@ -586,6 +454,12 @@ grub_hfsplus_cmp_extkey (struct grub_hfsplus_key *keya,
f96e0b
     return 1;
f96e0b
   if (extkey_a->type < extkey_b->type)
f96e0b
     return -1;
f96e0b
+
f96e0b
+  if (extkey_a->type > extkey_b->type)
f96e0b
+    return +1;
f96e0b
+
f96e0b
+  if (extkey_a->type < extkey_b->type)
f96e0b
+    return -1;
f96e0b
   
f96e0b
   akey = grub_be_to_cpu32 (extkey_a->start);
f96e0b
   if (akey > extkey_b->start)
f96e0b
@@ -668,7 +542,7 @@ grub_hfsplus_btree_iterate_node (struct grub_hfsplus_btree *btree,
f96e0b
    keys using the function COMPARE_KEYS.  When a match is found,
f96e0b
    return the node in MATCHNODE and a pointer to the data in this node
f96e0b
    in KEYOFFSET.  MATCHNODE should be freed by the caller.  */
f96e0b
-static grub_err_t
f96e0b
+grub_err_t
f96e0b
 grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree,
f96e0b
 			   struct grub_hfsplus_key_internal *key,
f96e0b
 			   int (*compare_keys) (struct grub_hfsplus_key *keya,
f96e0b
@@ -683,6 +557,12 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree,
f96e0b
   grub_uint64_t save_node;
f96e0b
   grub_uint64_t node_count = 0;
f96e0b
 
f96e0b
+  if (!btree->nodesize)
f96e0b
+    {
f96e0b
+      *matchnode = 0;
f96e0b
+      return 0;
f96e0b
+    }
f96e0b
+
f96e0b
   node = grub_malloc (btree->nodesize);
f96e0b
   if (! node)
f96e0b
     return grub_errno;
f96e0b
@@ -760,7 +640,7 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree,
f96e0b
 	{
f96e0b
 	  *matchnode = 0;
f96e0b
 	  grub_free (node);
f96e0b
-	  return 1;
f96e0b
+	  return 0;
f96e0b
 	}
f96e0b
     }
f96e0b
 }
f96e0b
@@ -872,11 +752,17 @@ list_nodes (void *record, void *hook_arg)
f96e0b
   if (!node)
f96e0b
     return 1;
f96e0b
   node->data = ctx->dir->data;
f96e0b
+  node->compressed = 0;
f96e0b
+  node->cbuf = 0;
f96e0b
+  node->compress_index = 0;
f96e0b
 
f96e0b
   grub_memcpy (node->extents, fileinfo->data.extents,
f96e0b
 	       sizeof (node->extents));
f96e0b
+  grub_memcpy (node->resource_extents, fileinfo->resource.extents,
f96e0b
+	       sizeof (node->resource_extents));
f96e0b
   node->mtime = grub_be_to_cpu32 (fileinfo->mtime) - 2082844800;
f96e0b
   node->size = grub_be_to_cpu64 (fileinfo->data.size);
f96e0b
+  node->resource_size = grub_be_to_cpu64 (fileinfo->resource.size);
f96e0b
   node->fileid = grub_be_to_cpu32 (fileinfo->fileid);
f96e0b
 
f96e0b
   ctx->ret = ctx->hook (filename, type, node, ctx->hook_data);
f96e0b
@@ -919,7 +805,8 @@ grub_hfsplus_iterate_dir (grub_fshelp_node_t dir,
f96e0b
 
f96e0b
   /* First lookup the first entry.  */
f96e0b
   if (grub_hfsplus_btree_search (&dir->data->catalog_tree, &intern,
f96e0b
-				 grub_hfsplus_cmp_catkey, &node, &ptr))
f96e0b
+				 grub_hfsplus_cmp_catkey, &node, &ptr)
f96e0b
+      || !node)
f96e0b
     return 0;
f96e0b
 
f96e0b
   /* Iterate over all entries in this directory.  */
f96e0b
@@ -950,6 +837,14 @@ grub_hfsplus_open (struct grub_file *file, const char *name)
f96e0b
   if (grub_errno)
f96e0b
     goto fail;
f96e0b
 
f96e0b
+  if (grub_hfsplus_open_compressed)
f96e0b
+    {
f96e0b
+      grub_err_t err;
f96e0b
+      err = grub_hfsplus_open_compressed (fdiro);
f96e0b
+      if (err)
f96e0b
+	goto fail;
f96e0b
+    }
f96e0b
+
f96e0b
   file->size = fdiro->size;
f96e0b
   data->opened_file = *fdiro;
f96e0b
   grub_free (fdiro);
f96e0b
@@ -973,7 +868,13 @@ grub_hfsplus_open (struct grub_file *file, const char *name)
f96e0b
 static grub_err_t
f96e0b
 grub_hfsplus_close (grub_file_t file)
f96e0b
 {
f96e0b
-  grub_free (file->data);
f96e0b
+  struct grub_hfsplus_data *data =
f96e0b
+    (struct grub_hfsplus_data *) file->data;
f96e0b
+
f96e0b
+  grub_free (data->opened_file.cbuf);
f96e0b
+  grub_free (data->opened_file.compress_index);
f96e0b
+
f96e0b
+  grub_free (data);
f96e0b
 
f96e0b
   grub_dl_unref (my_mod);
f96e0b
 
f96e0b
@@ -987,6 +888,10 @@ grub_hfsplus_read (grub_file_t file, char *buf, grub_size_t len)
f96e0b
   struct grub_hfsplus_data *data =
f96e0b
     (struct grub_hfsplus_data *) file->data;
f96e0b
 
f96e0b
+  if (grub_hfsplus_read_compressed && data->opened_file.compressed)
f96e0b
+    return grub_hfsplus_read_compressed (&data->opened_file,
f96e0b
+					 file->offset, len, buf);
f96e0b
+
f96e0b
   return grub_hfsplus_read_file (&data->opened_file,
f96e0b
 				 file->read_hook, file->read_hook_data,
f96e0b
 				 file->offset, len, buf);
f96e0b
@@ -1076,7 +981,8 @@ grub_hfsplus_label (grub_device_t device, char **label)
f96e0b
 
f96e0b
   /* First lookup the first entry.  */
f96e0b
   if (grub_hfsplus_btree_search (&data->catalog_tree, &intern,
f96e0b
-				 grub_hfsplus_cmp_catkey_id, &node, &ptr))
f96e0b
+				 grub_hfsplus_cmp_catkey_id, &node, &ptr)
f96e0b
+      || !node)
f96e0b
     {
f96e0b
       grub_free (data);
f96e0b
       return 0;
f96e0b
diff --git a/grub-core/fs/hfspluscomp.c b/grub-core/fs/hfspluscomp.c
f96e0b
new file mode 100644
f96e0b
index 0000000..b343441
f96e0b
--- /dev/null
f96e0b
+++ b/grub-core/fs/hfspluscomp.c
f96e0b
@@ -0,0 +1,302 @@
f96e0b
+/*
f96e0b
+ *  GRUB  --  GRand Unified Bootloader
f96e0b
+ *  Copyright (C) 2012  Free Software Foundation, Inc.
f96e0b
+ *
f96e0b
+ *  GRUB is free software: you can redistribute it and/or modify
f96e0b
+ *  it under the terms of the GNU General Public License as published by
f96e0b
+ *  the Free Software Foundation, either version 3 of the License, or
f96e0b
+ *  (at your option) any later version.
f96e0b
+ *
f96e0b
+ *  GRUB is distributed in the hope that it will be useful,
f96e0b
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
f96e0b
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
f96e0b
+ *  GNU General Public License for more details.
f96e0b
+ *
f96e0b
+ *  You should have received a copy of the GNU General Public License
f96e0b
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
f96e0b
+ */
f96e0b
+
f96e0b
+/* HFS+ is documented at http://developer.apple.com/technotes/tn/tn1150.html */
f96e0b
+
f96e0b
+#include <grub/hfsplus.h>
f96e0b
+#include <grub/dl.h>
f96e0b
+#include <grub/misc.h>
f96e0b
+#include <grub/mm.h>
f96e0b
+#include <grub/deflate.h>
f96e0b
+
f96e0b
+GRUB_MOD_LICENSE ("GPLv3+");
f96e0b
+
f96e0b
+/* big-endian.  */
f96e0b
+struct grub_hfsplus_compress_header1
f96e0b
+{
f96e0b
+  grub_uint32_t header_size;
f96e0b
+  grub_uint32_t end_descriptor_offset;
f96e0b
+  grub_uint32_t total_compressed_size_including_seek_blocks_and_header2;
f96e0b
+  grub_uint32_t value_0x32;
f96e0b
+  grub_uint8_t unused[0xf0];
f96e0b
+} __attribute__ ((packed));
f96e0b
+
f96e0b
+/* big-endian.  */
f96e0b
+struct grub_hfsplus_compress_header2
f96e0b
+{
f96e0b
+  grub_uint32_t total_compressed_size_including_seek_blocks;
f96e0b
+} __attribute__ ((packed));
f96e0b
+
f96e0b
+/* little-endian.  */
f96e0b
+struct grub_hfsplus_compress_header3
f96e0b
+{
f96e0b
+  grub_uint32_t num_chunks;
f96e0b
+} __attribute__ ((packed));
f96e0b
+
f96e0b
+/* little-endian.  */
f96e0b
+struct grub_hfsplus_compress_block_descriptor
f96e0b
+{
f96e0b
+  grub_uint32_t offset;
f96e0b
+  grub_uint32_t size;
f96e0b
+};
f96e0b
+
f96e0b
+struct grub_hfsplus_compress_end_descriptor
f96e0b
+{
f96e0b
+  grub_uint8_t always_the_same[50];
f96e0b
+} __attribute__ ((packed));
f96e0b
+
f96e0b
+struct grub_hfsplus_attr_header
f96e0b
+{
f96e0b
+  grub_uint8_t unused[3];
f96e0b
+  grub_uint8_t type;
f96e0b
+  grub_uint32_t unknown[1];
f96e0b
+  grub_uint64_t size;
f96e0b
+} __attribute__ ((packed));
f96e0b
+
f96e0b
+struct grub_hfsplus_compress_attr
f96e0b
+{
f96e0b
+  grub_uint32_t magic;
f96e0b
+  grub_uint32_t type;
f96e0b
+  grub_uint32_t uncompressed_inline_size;
f96e0b
+  grub_uint32_t always_0;
f96e0b
+};
f96e0b
+
f96e0b
+enum
f96e0b
+  {
f96e0b
+    HFSPLUS_COMPRESSION_INLINE = 3,
f96e0b
+    HFSPLUS_COMPRESSION_RESOURCE = 4
f96e0b
+  };
f96e0b
+
f96e0b
+static int
f96e0b
+grub_hfsplus_cmp_attrkey (struct grub_hfsplus_key *keya,
f96e0b
+			  struct grub_hfsplus_key_internal *keyb)
f96e0b
+{
f96e0b
+  struct grub_hfsplus_attrkey *attrkey_a = &keya->attrkey;
f96e0b
+  struct grub_hfsplus_attrkey_internal *attrkey_b = &keyb->attrkey;
f96e0b
+  grub_uint32_t aparent = grub_be_to_cpu32 (attrkey_a->cnid);
f96e0b
+  grub_size_t len;
f96e0b
+  int diff;
f96e0b
+
f96e0b
+  if (aparent > attrkey_b->cnid)
f96e0b
+    return 1;
f96e0b
+  if (aparent < attrkey_b->cnid)
f96e0b
+    return -1;
f96e0b
+
f96e0b
+  len = grub_be_to_cpu16 (attrkey_a->namelen);
f96e0b
+  if (len > attrkey_b->namelen)
f96e0b
+    len = attrkey_b->namelen;
f96e0b
+  /* Since it's big-endian memcmp gives the same result as manually comparing
f96e0b
+     uint16_t but may be faster.  */
f96e0b
+  diff = grub_memcmp (attrkey_a->name, attrkey_b->name,
f96e0b
+		      len * sizeof (attrkey_a->name[0]));
f96e0b
+  if (diff == 0)
f96e0b
+    diff = grub_be_to_cpu16 (attrkey_a->namelen) - attrkey_b->namelen;
f96e0b
+  return diff;
f96e0b
+}
f96e0b
+
f96e0b
+#define HFSPLUS_COMPRESS_BLOCK_SIZE 65536
f96e0b
+
f96e0b
+static grub_ssize_t
f96e0b
+hfsplus_read_compressed_real (struct grub_hfsplus_file *node,
f96e0b
+			      grub_off_t pos, grub_size_t len, char *buf)
f96e0b
+{
f96e0b
+  char *tmp_buf = 0;
f96e0b
+  grub_size_t len0 = len;
f96e0b
+
f96e0b
+  if (node->compressed == 1)
f96e0b
+    {
f96e0b
+      grub_memcpy (buf, node->cbuf + pos, len);
f96e0b
+      return len;
f96e0b
+    }
f96e0b
+
f96e0b
+  while (len)
f96e0b
+    {
f96e0b
+      grub_uint32_t block = pos / HFSPLUS_COMPRESS_BLOCK_SIZE;
f96e0b
+      grub_size_t curlen = HFSPLUS_COMPRESS_BLOCK_SIZE
f96e0b
+	- (pos % HFSPLUS_COMPRESS_BLOCK_SIZE);
f96e0b
+
f96e0b
+      if (curlen > len)
f96e0b
+	curlen = len;
f96e0b
+
f96e0b
+      if (node->cbuf_block != block)
f96e0b
+	{
f96e0b
+	  grub_uint32_t sz = grub_le_to_cpu32 (node->compress_index[block].size);
f96e0b
+	  grub_size_t ts;
f96e0b
+	  if (!tmp_buf)
f96e0b
+	    tmp_buf = grub_malloc (HFSPLUS_COMPRESS_BLOCK_SIZE);
f96e0b
+	  if (!tmp_buf)
f96e0b
+	    return -1;
f96e0b
+	  if (grub_hfsplus_read_file (node, 0, 0,
f96e0b
+				      grub_le_to_cpu32 (node->compress_index[block].start) + 0x104,
f96e0b
+				      sz, tmp_buf)
f96e0b
+	      != (grub_ssize_t) sz)
f96e0b
+	    {
f96e0b
+	      grub_free (tmp_buf);
f96e0b
+	      return -1;
f96e0b
+	    }
f96e0b
+	  ts = HFSPLUS_COMPRESS_BLOCK_SIZE;
f96e0b
+	  if (ts > node->size - (pos & ~(HFSPLUS_COMPRESS_BLOCK_SIZE)))
f96e0b
+	    ts = node->size - (pos & ~(HFSPLUS_COMPRESS_BLOCK_SIZE));
f96e0b
+	  if (grub_zlib_decompress (tmp_buf, sz, 0,
f96e0b
+				    node->cbuf, ts) < 0)
f96e0b
+	    {
f96e0b
+	      grub_free (tmp_buf);
f96e0b
+	      return -1;
f96e0b
+	    }
f96e0b
+	  node->cbuf_block = block;
f96e0b
+	}
f96e0b
+      grub_memcpy (buf, node->cbuf + (pos % HFSPLUS_COMPRESS_BLOCK_SIZE),
f96e0b
+		   curlen);
f96e0b
+      buf += curlen;
f96e0b
+      pos += curlen;
f96e0b
+      len -= curlen;
f96e0b
+    }
f96e0b
+  grub_free (tmp_buf);
f96e0b
+  return len0;
f96e0b
+}
f96e0b
+
f96e0b
+static grub_err_t 
f96e0b
+hfsplus_open_compressed_real (struct grub_hfsplus_file *node)
f96e0b
+{
f96e0b
+  grub_err_t err;
f96e0b
+  struct grub_hfsplus_btnode *attr_node;
f96e0b
+  grub_off_t attr_off;
f96e0b
+  struct grub_hfsplus_key_internal key;
f96e0b
+  struct grub_hfsplus_attr_header *attr_head;
f96e0b
+  struct grub_hfsplus_compress_attr *cmp_head;
f96e0b
+#define c grub_cpu_to_be16_compile_time
f96e0b
+  const grub_uint16_t compress_attr_name[] =
f96e0b
+    {
f96e0b
+      c('c'), c('o'), c('m'), c('.'), c('a'), c('p'), c('p'), c('l'), c('e'),
f96e0b
+      c('.'), c('d'), c('e'), c('c'), c('m'), c('p'), c('f'), c('s') };
f96e0b
+#undef c
f96e0b
+  if (node->size)
f96e0b
+    return 0;
f96e0b
+
f96e0b
+  key.attrkey.cnid = node->fileid;
f96e0b
+  key.attrkey.namelen = sizeof (compress_attr_name) / sizeof (compress_attr_name[0]);
f96e0b
+  key.attrkey.name = compress_attr_name;
f96e0b
+
f96e0b
+  err = grub_hfsplus_btree_search (&node->data->attr_tree, &key,
f96e0b
+				   grub_hfsplus_cmp_attrkey,
f96e0b
+				   &attr_node, &attr_off);
f96e0b
+  if (err || !attr_node)
f96e0b
+    {
f96e0b
+      grub_errno = 0;
f96e0b
+      return 0;
f96e0b
+    }
f96e0b
+
f96e0b
+  attr_head = (struct grub_hfsplus_attr_header *)
f96e0b
+    ((char *) grub_hfsplus_btree_recptr (&node->data->attr_tree,
f96e0b
+					 attr_node, attr_off)
f96e0b
+     + sizeof (struct grub_hfsplus_attrkey) + sizeof (compress_attr_name));
f96e0b
+  if (attr_head->type != 0x10
f96e0b
+      || !(attr_head->size & grub_cpu_to_be64_compile_time(~0xfULL)))
f96e0b
+    {
f96e0b
+      grub_free (attr_node);
f96e0b
+      return 0;
f96e0b
+    }
f96e0b
+  cmp_head = (struct grub_hfsplus_compress_attr *) (attr_head + 1);
f96e0b
+  if (cmp_head->magic != grub_cpu_to_be32_compile_time (0x66706d63))
f96e0b
+    {
f96e0b
+      grub_free (attr_node);
f96e0b
+      return 0;
f96e0b
+    }
f96e0b
+  node->size = grub_le_to_cpu32 (cmp_head->uncompressed_inline_size);
f96e0b
+
f96e0b
+  if (cmp_head->type == grub_cpu_to_le32_compile_time (HFSPLUS_COMPRESSION_RESOURCE))
f96e0b
+    {
f96e0b
+      grub_uint32_t index_size;
f96e0b
+      node->compressed = 2;
f96e0b
+
f96e0b
+      if (grub_hfsplus_read_file (node, 0, 0,
f96e0b
+				  0x104, sizeof (index_size),
f96e0b
+				  (char *) &index_size)
f96e0b
+	  != 4)
f96e0b
+	{
f96e0b
+	  node->compressed = 0;
f96e0b
+	  grub_free (attr_node);
f96e0b
+	  grub_errno = 0;
f96e0b
+	  return 0;
f96e0b
+	}
f96e0b
+      node->compress_index_size = grub_le_to_cpu32 (index_size);
f96e0b
+      node->compress_index = grub_malloc (node->compress_index_size
f96e0b
+					  * sizeof (node->compress_index[0]));
f96e0b
+      if (!node->compress_index)
f96e0b
+	{
f96e0b
+	  node->compressed = 0;
f96e0b
+	  grub_free (attr_node);
f96e0b
+	  return grub_errno;
f96e0b
+	}
f96e0b
+      if (grub_hfsplus_read_file (node, 0, 0,
f96e0b
+				  0x104 + sizeof (index_size),
f96e0b
+				  node->compress_index_size
f96e0b
+				  * sizeof (node->compress_index[0]),
f96e0b
+				  (char *) node->compress_index)
f96e0b
+	  != (grub_ssize_t) (node->compress_index_size
f96e0b
+			     * sizeof (node->compress_index[0])))
f96e0b
+	{
f96e0b
+	  node->compressed = 0;
f96e0b
+	  grub_free (attr_node);
f96e0b
+	  grub_free (node->compress_index);
f96e0b
+	  grub_errno = 0;
f96e0b
+	  return 0;
f96e0b
+	}
f96e0b
+
f96e0b
+      node->cbuf_block = -1;
f96e0b
+
f96e0b
+      node->cbuf = grub_malloc (HFSPLUS_COMPRESS_BLOCK_SIZE);
f96e0b
+      grub_free (attr_node);
f96e0b
+      if (!node->cbuf)
f96e0b
+	{
f96e0b
+	  node->compressed = 0;
f96e0b
+	  grub_free (node->compress_index);
f96e0b
+	  return grub_errno;
f96e0b
+	}
f96e0b
+      return 0;
f96e0b
+    }
f96e0b
+  if (cmp_head->type != HFSPLUS_COMPRESSION_INLINE)
f96e0b
+    {
f96e0b
+      grub_free (attr_node);
f96e0b
+      return 0;
f96e0b
+    }
f96e0b
+
f96e0b
+  node->cbuf = grub_malloc (node->size);
f96e0b
+  if (!node->cbuf)
f96e0b
+    return grub_errno;
f96e0b
+
f96e0b
+  if (grub_zlib_decompress ((char *) (cmp_head + 1),
f96e0b
+			    grub_cpu_to_be64 (attr_head->size)
f96e0b
+			    - sizeof (*cmp_head), 0,
f96e0b
+			    node->cbuf, node->size) < 0)
f96e0b
+    return grub_errno;
f96e0b
+  node->compressed = 1;
f96e0b
+  return 0;
f96e0b
+}
f96e0b
+
f96e0b
+GRUB_MOD_INIT(hfspluscomp)
f96e0b
+{
f96e0b
+  grub_hfsplus_open_compressed = hfsplus_open_compressed_real;  
f96e0b
+  grub_hfsplus_read_compressed = hfsplus_read_compressed_real;  
f96e0b
+}
f96e0b
+
f96e0b
+GRUB_MOD_FINI(hfspluscomp)
f96e0b
+{
f96e0b
+  grub_hfsplus_open_compressed = 0;
f96e0b
+  grub_hfsplus_read_compressed = 0;
f96e0b
+}
f96e0b
diff --git a/include/grub/hfsplus.h b/include/grub/hfsplus.h
f96e0b
new file mode 100644
f96e0b
index 0000000..0defd35
f96e0b
--- /dev/null
f96e0b
+++ b/include/grub/hfsplus.h
f96e0b
@@ -0,0 +1,217 @@
f96e0b
+
f96e0b
+#include <grub/types.h>
f96e0b
+#include <grub/disk.h>
f96e0b
+
f96e0b
+/* A HFS+ extent.  */
f96e0b
+struct grub_hfsplus_extent
f96e0b
+{
f96e0b
+  /* The first block of a file on disk.  */
f96e0b
+  grub_uint32_t start;
f96e0b
+  /* The amount of blocks described by this extent.  */
f96e0b
+  grub_uint32_t count;
f96e0b
+} __attribute__ ((packed));
f96e0b
+
f96e0b
+/* The descriptor of a fork.  */
f96e0b
+struct grub_hfsplus_forkdata
f96e0b
+{
f96e0b
+  grub_uint64_t size;
f96e0b
+  grub_uint32_t clumpsize;
f96e0b
+  grub_uint32_t blocks;
f96e0b
+  struct grub_hfsplus_extent extents[8];
f96e0b
+} __attribute__ ((packed));
f96e0b
+
f96e0b
+/* The HFS+ Volume Header.  */
f96e0b
+struct grub_hfsplus_volheader
f96e0b
+{
f96e0b
+  grub_uint16_t magic;
f96e0b
+  grub_uint16_t version;
f96e0b
+  grub_uint32_t attributes;
f96e0b
+  grub_uint8_t unused1[12];
f96e0b
+  grub_uint32_t utime;
f96e0b
+  grub_uint8_t unused2[16];
f96e0b
+  grub_uint32_t blksize;
f96e0b
+  grub_uint8_t unused3[60];
f96e0b
+  grub_uint64_t num_serial;
f96e0b
+  struct grub_hfsplus_forkdata allocations_file;
f96e0b
+  struct grub_hfsplus_forkdata extents_file;
f96e0b
+  struct grub_hfsplus_forkdata catalog_file;
f96e0b
+  struct grub_hfsplus_forkdata attr_file;
f96e0b
+  struct grub_hfsplus_forkdata startup_file;
f96e0b
+} __attribute__ ((packed));
f96e0b
+
f96e0b
+struct grub_hfsplus_compress_index
f96e0b
+{
f96e0b
+  grub_uint32_t start;
f96e0b
+  grub_uint32_t size;
f96e0b
+};
f96e0b
+
f96e0b
+struct grub_hfsplus_file
f96e0b
+{
f96e0b
+  struct grub_hfsplus_data *data;
f96e0b
+  struct grub_hfsplus_extent extents[8];
f96e0b
+  struct grub_hfsplus_extent resource_extents[8];
f96e0b
+  grub_uint64_t size;
f96e0b
+  grub_uint64_t resource_size;
f96e0b
+  grub_uint32_t fileid;
f96e0b
+  grub_int32_t mtime;
f96e0b
+  int compressed;
f96e0b
+  char *cbuf;
f96e0b
+  struct grub_hfsplus_compress_index *compress_index;
f96e0b
+  grub_uint32_t cbuf_block;
f96e0b
+  grub_uint32_t compress_index_size;
f96e0b
+};
f96e0b
+
f96e0b
+struct grub_hfsplus_btree
f96e0b
+{
f96e0b
+  grub_uint32_t root;
f96e0b
+  grub_size_t nodesize;
f96e0b
+
f96e0b
+  /* Catalog file node.  */
f96e0b
+  struct grub_hfsplus_file file;
f96e0b
+};
f96e0b
+
f96e0b
+/* Information about a "mounted" HFS+ filesystem.  */
f96e0b
+struct grub_hfsplus_data
f96e0b
+{
f96e0b
+  struct grub_hfsplus_volheader volheader;
f96e0b
+  grub_disk_t disk;
f96e0b
+
f96e0b
+  unsigned int log2blksize;
f96e0b
+
f96e0b
+  struct grub_hfsplus_btree catalog_tree;
f96e0b
+  struct grub_hfsplus_btree extoverflow_tree;
f96e0b
+  struct grub_hfsplus_btree attr_tree;
f96e0b
+
f96e0b
+  struct grub_hfsplus_file dirroot;
f96e0b
+  struct grub_hfsplus_file opened_file;
f96e0b
+
f96e0b
+  /* This is the offset into the physical disk for an embedded HFS+
f96e0b
+     filesystem (one inside a plain HFS wrapper).  */
f96e0b
+  grub_disk_addr_t embedded_offset;
f96e0b
+  int case_sensitive;
f96e0b
+};
f96e0b
+
f96e0b
+/* Internal representation of a catalog key.  */
f96e0b
+struct grub_hfsplus_catkey_internal
f96e0b
+{
f96e0b
+  grub_uint32_t parent;
f96e0b
+  const grub_uint16_t *name;
f96e0b
+  grub_size_t namelen;
f96e0b
+};
f96e0b
+
f96e0b
+/* Internal representation of an extent overflow key.  */
f96e0b
+struct grub_hfsplus_extkey_internal
f96e0b
+{
f96e0b
+  grub_uint32_t fileid;
f96e0b
+  grub_uint32_t start;
f96e0b
+  grub_uint8_t type;
f96e0b
+};
f96e0b
+
f96e0b
+struct grub_hfsplus_attrkey
f96e0b
+{
f96e0b
+  grub_uint16_t keylen;
f96e0b
+  grub_uint16_t unknown1[1];
f96e0b
+  grub_uint32_t cnid;
f96e0b
+  grub_uint16_t unknown2[2];
f96e0b
+  grub_uint16_t namelen;
f96e0b
+  grub_uint16_t name[0];
f96e0b
+} __attribute__ ((packed));
f96e0b
+
f96e0b
+struct grub_hfsplus_attrkey_internal
f96e0b
+{
f96e0b
+  grub_uint32_t cnid;
f96e0b
+  const grub_uint16_t *name;
f96e0b
+  grub_size_t namelen;
f96e0b
+};
f96e0b
+
f96e0b
+struct grub_hfsplus_key_internal
f96e0b
+{
f96e0b
+  union
f96e0b
+  {
f96e0b
+    struct grub_hfsplus_extkey_internal extkey;
f96e0b
+    struct grub_hfsplus_catkey_internal catkey;
f96e0b
+    struct grub_hfsplus_attrkey_internal attrkey;
f96e0b
+  };
f96e0b
+};
f96e0b
+
f96e0b
+/* The on disk layout of a catalog key.  */
f96e0b
+struct grub_hfsplus_catkey
f96e0b
+{
f96e0b
+  grub_uint16_t keylen;
f96e0b
+  grub_uint32_t parent;
f96e0b
+  grub_uint16_t namelen;
f96e0b
+  grub_uint16_t name[30];
f96e0b
+} __attribute__ ((packed));
f96e0b
+
f96e0b
+/* The on disk layout of an extent overflow file key.  */
f96e0b
+struct grub_hfsplus_extkey
f96e0b
+{
f96e0b
+  grub_uint16_t keylen;
f96e0b
+  grub_uint8_t type;
f96e0b
+  grub_uint8_t unused;
f96e0b
+  grub_uint32_t fileid;
f96e0b
+  grub_uint32_t start;
f96e0b
+} __attribute__ ((packed));
f96e0b
+
f96e0b
+struct grub_hfsplus_key
f96e0b
+{
f96e0b
+  union
f96e0b
+  {
f96e0b
+    struct grub_hfsplus_extkey extkey;
f96e0b
+    struct grub_hfsplus_catkey catkey;
f96e0b
+    struct grub_hfsplus_attrkey attrkey;
f96e0b
+    grub_uint16_t keylen;
f96e0b
+  };
f96e0b
+} __attribute__ ((packed));
f96e0b
+
f96e0b
+struct grub_hfsplus_btnode
f96e0b
+{
f96e0b
+  grub_uint32_t next;
f96e0b
+  grub_uint32_t prev;
f96e0b
+  grub_int8_t type;
f96e0b
+  grub_uint8_t height;
f96e0b
+  grub_uint16_t count;
f96e0b
+  grub_uint16_t unused;
f96e0b
+} __attribute__ ((packed));
f96e0b
+
f96e0b
+/* Return the offset of the record with the index INDEX, in the node
f96e0b
+   NODE which is part of the B+ tree BTREE.  */
f96e0b
+static inline grub_off_t
f96e0b
+grub_hfsplus_btree_recoffset (struct grub_hfsplus_btree *btree,
f96e0b
+			   struct grub_hfsplus_btnode *node, int index)
f96e0b
+{
f96e0b
+  char *cnode = (char *) node;
f96e0b
+  void *recptr;
f96e0b
+  recptr = (&cnode[btree->nodesize - index * sizeof (grub_uint16_t) - 2]);
f96e0b
+  return grub_be_to_cpu16 (grub_get_unaligned16 (recptr));
f96e0b
+}
f96e0b
+
f96e0b
+/* Return a pointer to the record with the index INDEX, in the node
f96e0b
+   NODE which is part of the B+ tree BTREE.  */
f96e0b
+static inline struct grub_hfsplus_key *
f96e0b
+grub_hfsplus_btree_recptr (struct grub_hfsplus_btree *btree,
f96e0b
+			   struct grub_hfsplus_btnode *node, int index)
f96e0b
+{
f96e0b
+  char *cnode = (char *) node;
f96e0b
+  grub_off_t offset;
f96e0b
+  offset = grub_hfsplus_btree_recoffset (btree, node, index);
f96e0b
+  return (struct grub_hfsplus_key *) &cnode[offset];
f96e0b
+}
f96e0b
+
f96e0b
+extern grub_err_t (*grub_hfsplus_open_compressed) (struct grub_hfsplus_file *node);
f96e0b
+extern grub_ssize_t (*grub_hfsplus_read_compressed) (struct grub_hfsplus_file *node,
f96e0b
+						     grub_off_t pos,
f96e0b
+						     grub_size_t len,
f96e0b
+						     char *buf);
f96e0b
+
f96e0b
+grub_ssize_t
f96e0b
+grub_hfsplus_read_file (struct grub_hfsplus_file *node,
f96e0b
+			grub_disk_read_hook_t read_hook, void *read_hook_data,
f96e0b
+			grub_off_t pos, grub_size_t len, char *buf);
f96e0b
+grub_err_t
f96e0b
+grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree,
f96e0b
+			   struct grub_hfsplus_key_internal *key,
f96e0b
+			   int (*compare_keys) (struct grub_hfsplus_key *keya,
f96e0b
+						struct grub_hfsplus_key_internal *keyb),
f96e0b
+			   struct grub_hfsplus_btnode **matchnode, 
f96e0b
+			   grub_off_t *keyoffset);
f96e0b
-- 
f96e0b
1.8.2.1
f96e0b