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 #include #include @@ -25,9 +28,10 @@ #include #include #include +#include #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 #include #include @@ -26,6 +28,11 @@ #include #include #include +#include + +#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 + +#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 */