This patch (sent mostly for Marco) adds HFS wrapper support to the HFS+ code. All Apple-created HFS+ partitions are contained in an HFS wrapper for some backwards compatibility. The code is based on information found at http://developer.apple.com/technotes/tn/tn1150.html#HFSWrapper .

I only moved the minimum HFS code and structures into hfs.h. More could go there if desired.

When I tested this patch, an embedded filesystem was recognized as HFS+, but the HFS+ code itself did not discover any files, so there is probably still something wrong.

-Hollis
Index: fs/hfs.c
===================================================================
RCS file: /cvsroot/grub/grub2/fs/hfs.c,v
retrieving revision 1.4
diff -u -p -r1.4 hfs.c
--- fs/hfs.c    13 Nov 2005 15:47:09 -0000      1.4
+++ fs/hfs.c    2 Jan 2006 20:30:21 -0000
@@ -18,6 +18,9 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+/* HFS is documented at
+   http://developer.apple.com/documentation/mac/Files/Files-2.html */
+
 #include <grub/err.h>
 #include <grub/file.h>
 #include <grub/mm.h>
@@ -25,9 +28,10 @@
 #include <grub/disk.h>
 #include <grub/dl.h>
 #include <grub/types.h>
+#include <grub/hfs.h>
 
 #define        GRUB_HFS_SBLOCK         2
-#define GRUB_HFS_MAGIC         0x4244
+#define GRUB_HFS_EMBED_HFSPLUS_SIG 0x482B
 
 #define GRUB_HFS_BLKS          (data->blksz >> 9)
 
@@ -40,37 +44,6 @@ enum
     GRUB_HFS_FILETYPE_FILE = 2
   };
 
-/* A single extent.  A file consists of suchs extents.  */
-struct grub_hfs_extent
-{
-  /* The first physical block.  */
-  grub_uint16_t first_block;
-  grub_uint16_t count;
-};
-
-/* HFS stores extents in groups of 3.  */
-typedef struct grub_hfs_extent grub_hfs_datarecord_t[3];
-
-/* The HFS superblock (The official name is `Master Directory
-   Block').  */
-struct grub_hfs_sblock
-{
-  grub_uint16_t magic;
-  grub_uint8_t unused[18];
-  grub_uint32_t blksz;
-  grub_uint8_t unused2[4];
-  grub_uint16_t first_block;
-  grub_uint8_t unused4[6];
-
-  /* A pascal style string that holds the volumename.  */
-  grub_uint8_t volname[28];
-  
-  grub_uint8_t unused5[70];
-  grub_hfs_datarecord_t extent_recs;
-  grub_uint32_t catalog_size;
-  grub_hfs_datarecord_t catalog_recs;
-} __attribute__ ((packed));
-
 /* A node desciptor.  This is the header of every node.  */
 struct grub_hfs_node
 {
@@ -345,7 +318,14 @@ grub_hfs_mount (grub_disk_t disk)
   /* Check if this is a HFS filesystem.  */
   if (grub_be_to_cpu16 (data->sblock.magic) != GRUB_HFS_MAGIC)
     {
-      grub_error (GRUB_ERR_BAD_FS, "not a hfs filesystem");
+      grub_error (GRUB_ERR_BAD_FS, "not an HFS filesystem");
+      goto fail;
+    }
+
+  /* Check if this is an embedded HFS+ filesystem.  */
+  if (grub_be_to_cpu16 (data->sblock.embed_sig) == GRUB_HFS_EMBED_HFSPLUS_SIG)
+    {
+      grub_error (GRUB_ERR_BAD_FS, "embedded HFS+ filesystem");
       goto fail;
     }
   
Index: fs/hfsplus.c
===================================================================
RCS file: /cvsroot/grub/grub2/fs/hfsplus.c,v
retrieving revision 1.1
diff -u -p -r1.1 hfsplus.c
--- fs/hfsplus.c        25 Dec 2005 15:59:50 -0000      1.1
+++ fs/hfsplus.c        2 Jan 2006 20:30:21 -0000
@@ -18,6 +18,8 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+/* HFS+ is documented at http://developer.apple.com/technotes/tn/tn1150.html */
+
 #include <grub/err.h>
 #include <grub/file.h>
 #include <grub/mm.h>
@@ -26,6 +28,11 @@
 #include <grub/dl.h>
 #include <grub/types.h>
 #include <grub/fshelp.h>
+#include <grub/hfs.h>
+
+#define GRUB_HFSPLUS_MAGIC 0x482B
+#define GRUB_HFSPLUSX_MAGIC 0x4858
+#define GRUB_HFSPLUS_SBLOCK 2
 
 /* A HFS+ extent.  */
 struct grub_hfsplus_extent
@@ -48,7 +55,7 @@ struct grub_hfsplus_forkdata
 /* The HFS+ Volume Header.  */
 struct grub_hfsplus_volheader
 {
-  grub_uint8_t magic[2];
+  grub_uint16_t magic;
   grub_uint16_t version;
   grub_uint32_t attributes;
   grub_uint8_t unused[32];
@@ -214,6 +221,10 @@ struct grub_hfsplus_data
 static grub_dl_t my_mod;
 #endif
 
+/* This is the offset into the physical disk for an embedded HFS+ filesystem
+ * (one inside a plain HFS wrapper).  */
+static int embedded_offset = 0;
+
 
 /* Find the extent that points to FILEBLOCK.  If it is not in one of
    the 8 extents described by EXTENT, return -1.  In that case set
@@ -268,7 +279,7 @@ grub_hfsplus_read_block (grub_fshelp_nod
       /* Try to find this block in the current set of extents.  */
       blk = grub_hfsplus_find_block (extents, fileblock, &retry);
       if (blk != -1)
-       return blk;
+       return blk + embedded_offset;
 
       /* The previous iteration of this loop allocated memory.  The
         code above used this memory, it can be free'ed now.  */
@@ -333,6 +344,10 @@ grub_hfsplus_mount (grub_disk_t disk)
   struct grub_hfsplus_data *data;
   struct grub_hfsplus_btheader header;
   struct grub_hfsplus_btnode node;
+  union {
+    struct grub_hfs_sblock hfs;
+    struct grub_hfsplus_volheader hfsplus;
+  } volheader;
 
   data = grub_malloc (sizeof (*data));
   if (!data)
@@ -341,20 +356,48 @@ grub_hfsplus_mount (grub_disk_t disk)
   data->disk = disk;
 
   /* Read the bootblock.  */
-  grub_disk_read (disk, 2, 0, sizeof (struct grub_hfsplus_volheader),
-                 (char *) &data->volheader);
+  grub_disk_read (disk, GRUB_HFSPLUS_SBLOCK, 0, sizeof (volheader),
+                 (char *) &volheader);
   if (grub_errno)
     goto fail;
 
-  /* Make sure this is an hfs+ filesystem.  XXX: Do we really support
+  if (volheader.hfs.magic == GRUB_HFS_MAGIC)
+    {
+      int extent_start;
+      int ablk_size;
+      int ablk_start;
+
+      /* See if there's an embedded HFS+ filesystem.  */
+      if (volheader.hfs.embed_sig != GRUB_HFSPLUS_MAGIC)
+       {
+         grub_error (GRUB_ERR_BAD_FS, "not a HFS+ filesystem");
+         goto fail;
+       }
+
+      /* Calculate the offset needed to translate HFS+ sector numbers.  */
+      extent_start = grub_be_to_cpu16 (volheader.hfs.embed_extent.first_block);
+      ablk_size = grub_be_to_cpu32 (volheader.hfs.blksz);
+      ablk_start = grub_be_to_cpu16 (volheader.hfs.first_block);
+      embedded_offset = ablk_start + extent_start * (ablk_size / 512);
+
+      grub_disk_read (disk, embedded_offset + GRUB_HFSPLUS_SBLOCK, 0,
+                     sizeof (volheader), (char *) &volheader);
+      if (grub_errno)
+       goto fail;
+    }
+
+  /* Make sure this is an HFS+ filesystem.  XXX: Do we really support
      HFX?  */
-  if (grub_strncmp (data->volheader.magic, "H+", 2)
-      && grub_strncmp (data->volheader.magic, "HX", 2))
+  if ((volheader.hfsplus.magic != GRUB_HFSPLUS_MAGIC)
+      && (volheader.hfsplus.magic != GRUB_HFSPLUSX_MAGIC))
     {
       grub_error (GRUB_ERR_BAD_FS, "not a HFS+ filesystem");
       goto fail;
     }
 
+  grub_memcpy (&data->volheader, &volheader.hfsplus,
+      sizeof (volheader.hfsplus));
+
   if (grub_fshelp_log2blksize (grub_be_to_cpu32 (data->volheader.blksize),
                               &data->log2blksize))
     goto fail;
Index: include/grub/hfs.h
===================================================================
RCS file: include/grub/hfs.h
diff -N include/grub/hfs.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ include/grub/hfs.h  2 Jan 2006 20:30:21 -0000
@@ -0,0 +1,61 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2005  Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef GRUB_HFS_HEADER
+#define GRUB_HFS_HEADER        1
+
+#include <grub/types.h>
+
+#define GRUB_HFS_MAGIC         0x4244
+
+/* A single extent.  A file consists of one or more extents.  */
+struct grub_hfs_extent
+{
+  /* The first physical block.  */
+  grub_uint16_t first_block;
+  grub_uint16_t count;
+};
+
+/* HFS stores extents in groups of 3.  */
+typedef struct grub_hfs_extent grub_hfs_datarecord_t[3];
+
+/* The HFS superblock (The official name is `Master Directory
+   Block').  */
+struct grub_hfs_sblock
+{
+  grub_uint16_t magic;
+  grub_uint8_t unused[18];
+  grub_uint32_t blksz;
+  grub_uint8_t unused2[4];
+  grub_uint16_t first_block;
+  grub_uint8_t unused4[6];
+
+  /* A pascal style string that holds the volumename.  */
+  grub_uint8_t volname[28];
+  
+  grub_uint8_t unused5[60];
+  grub_uint16_t embed_sig;
+  struct grub_hfs_extent embed_extent;
+  grub_uint8_t unused6[4];
+  grub_hfs_datarecord_t extent_recs;
+  grub_uint32_t catalog_size;
+  grub_hfs_datarecord_t catalog_recs;
+} __attribute__ ((packed));
+
+#endif /* ! GRUB_HFS_HEADER */
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to