diff --git a/commands/hfspbless.c b/commands/hfspbless.c
new file mode 100644
index 0000000..c2bddee
--- /dev/null
+++ b/commands/hfspbless.c
@@ -0,0 +1,207 @@
+/* hfspbless.c - set the hfs+ boot directory. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2005,2007,2008 Free Software Foundation, Inc.
+ *
+ * GRUB 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB 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 GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static grub_uint64_t inode;
+static char *dirname;
+static int found;
+
+static int find_inode (const char *filename,
+ const struct grub_dirhook_info *info)
+{
+ if ((grub_strcmp (dirname, filename) == 0
+ || (info->case_insensitive && grub_strcasecmp (dirname, filename) == 0))
+ && info->inodeset)
+ {
+ inode = info->inode;
+ found = info->dir ? 2 : 1;
+ }
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_hfspbless (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ char *device_name;
+ char *path = 0, *tail;
+ int embedded_offset;
+ grub_device_t dev;
+ grub_fs_t fs;
+
+ union {
+ struct grub_hfs_sblock hfs;
+ struct grub_hfsplus_volheader hfsplus;
+ } volheader;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "directory required");
+ device_name = grub_file_get_device_name (args[0]);
+ dev = grub_device_open (device_name);
+
+ path = grub_strchr (args[0], ')');
+ if (! path)
+ path = grub_strdup (dirname);
+ else
+ path = grub_strdup (path + 1);
+
+ if (! path || *path == 0 || ! device_name)
+ {
+ if (dev)
+ grub_device_close (dev);
+
+ grub_free (device_name);
+ grub_free (path);
+
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid argument");
+ }
+
+ fs = grub_fs_probe (dev);
+ if (! fs || grub_strcmp (fs->name, "hfsplus") != 0)
+ {
+ grub_device_close (dev);
+ grub_free (device_name);
+ grub_free (path);
+
+ return grub_error (GRUB_ERR_BAD_FS, "no suitable FS found");
+ }
+
+ tail = path + grub_strlen (path) - 1;
+
+ /* Remove trailing '/'. */
+ while (tail != path && *tail == '/')
+ *(tail--) = 0;
+
+ tail = grub_strrchr (path, '/');
+ found = 0;
+
+ if (tail)
+ {
+ *tail = 0;
+ dirname = tail + 1;
+
+ (fs->dir) (dev, *path == 0 ?"/":path, find_inode);
+ }
+ else
+ {
+ dirname = path + 1;
+ (fs->dir) (dev, "/", find_inode);
+ }
+ grub_free (path);
+
+ if (! found)
+ {
+ grub_device_close (dev);
+ grub_free (device_name);
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND,
+ "%s not found\n",
+ args[0]);
+ }
+
+ /* Read the bootblock. */
+ grub_disk_read (dev->disk, GRUB_HFSPLUS_SBLOCK, 0, sizeof (volheader),
+ (char *) &volheader);
+ if (grub_errno)
+ {
+ grub_device_close (dev);
+ grub_free (device_name);
+ return grub_errno;
+ }
+
+ embedded_offset = 0;
+ if (grub_be_to_cpu16 (volheader.hfs.magic) == GRUB_HFS_MAGIC)
+ {
+ int extent_start;
+ int ablk_size;
+ int ablk_start;
+
+ /* See if there's an embedded HFS+ filesystem. */
+ if (grub_be_to_cpu16 (volheader.hfs.embed_sig) != GRUB_HFSPLUS_MAGIC)
+ {
+ grub_device_close (dev);
+ grub_free (device_name);
+ return grub_errno;
+ }
+
+ /* 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 >> GRUB_DISK_SECTOR_BITS));
+
+ grub_disk_read (dev->disk, embedded_offset + GRUB_HFSPLUS_SBLOCK, 0,
+ sizeof (volheader), (char *) &volheader);
+ if (grub_errno)
+ {
+ grub_device_close (dev);
+ grub_free (device_name);
+ return grub_errno;
+ }
+ }
+
+ /* Make sure this is an HFS+ filesystem. XXX: Do we really support
+ HFX? */
+ if ((grub_be_to_cpu16 (volheader.hfsplus.magic) != GRUB_HFSPLUS_MAGIC)
+ && (grub_be_to_cpu16 (volheader.hfsplus.magic) != GRUB_HFSPLUSX_MAGIC))
+ {
+ grub_device_close (dev);
+ grub_free (device_name);
+ return grub_error (GRUB_ERR_BAD_FS, "not a HFS+ filesystem");
+ }
+ if (found == 2)
+ volheader.hfsplus.bootdir = grub_be_to_cpu32 (inode);
+ else
+ volheader.hfsplus.bootfile = grub_be_to_cpu32 (inode);
+
+ grub_disk_write (dev->disk, embedded_offset + GRUB_HFSPLUS_SBLOCK, 0,
+ sizeof (volheader), (char *) &volheader);
+
+ grub_device_close (dev);
+ grub_free (device_name);
+ return grub_errno;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(hfspbless)
+{
+ (void) mod; /* To stop warning. */
+ cmd = grub_register_command ("hfspbless", grub_cmd_hfspbless,
+ "hfspbless DIRECTORY",
+ "Bless DIRECTORY of HFS+ partition.");
+}
+
+GRUB_MOD_FINI(hfspbless)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/conf/common.rmk b/conf/common.rmk
index 0e63da6..14b6184 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -531,3 +531,10 @@ gzio_mod_LDFLAGS = $(COMMON_LDFLAGS)
bufio_mod_SOURCES = io/bufio.c
bufio_mod_CFLAGS = $(COMMON_CFLAGS)
bufio_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+pkglib_MODULES += hfspbless.mod
+
+# For hfspbless.mod.
+hfspbless_mod_SOURCES = commands/hfspbless.c
+hfspbless_mod_CFLAGS = $(COMMON_CFLAGS)
+hfspbless_mod_LDFLAGS = $(COMMON_LDFLAGS)
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index 265b250..8662c11 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -122,6 +122,7 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \
commands/configfile.c commands/echo.c commands/help.c \
commands/handler.c commands/ls.c commands/test.c \
commands/search.c commands/blocklist.c commands/hexdump.c \
+ commands/hfspbless.c \
lib/hexdump.c commands/i386/pc/halt.c commands/reboot.c \
commands/i386/cpuid.c \
disk/host.c disk/loopback.c disk/scsi.c \
@@ -154,7 +155,7 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \
\
disk/raid.c disk/raid5_recover.c disk/raid6_recover.c \
disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c \
- commands/parttool.c parttool/pcpart.c \
+ commands/parttool.c parttool/pcpart.c \
grub_emu_init.c
grub_emu_LDFLAGS = $(LIBCURSES)
diff --git a/fs/hfsplus.c b/fs/hfsplus.c
index 82ec880..9831a3c 100644
--- a/fs/hfsplus.c
+++ b/fs/hfsplus.c
@@ -28,140 +28,7 @@
#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
-{
- /* The first block of a file on disk. */
- grub_uint32_t start;
- /* The amount of blocks described by this extent. */
- grub_uint32_t count;
-} __attribute__ ((packed));
-
-/* The descriptor of a fork. */
-struct grub_hfsplus_forkdata
-{
- grub_uint64_t size;
- grub_uint32_t clumpsize;
- grub_uint32_t blocks;
- struct grub_hfsplus_extent extents[8];
-} __attribute__ ((packed));
-
-/* The HFS+ Volume Header. */
-struct grub_hfsplus_volheader
-{
- grub_uint16_t magic;
- grub_uint16_t version;
- grub_uint32_t attributes;
- grub_uint8_t unused1[12];
- grub_uint32_t utime;
- grub_uint8_t unused2[16];
- grub_uint32_t blksize;
- grub_uint8_t unused3[68];
- struct grub_hfsplus_forkdata allocations_file;
- struct grub_hfsplus_forkdata extents_file;
- struct grub_hfsplus_forkdata catalog_file;
- struct grub_hfsplus_forkdata attrib_file;
- struct grub_hfsplus_forkdata startup_file;
-} __attribute__ ((packed));
-
-/* The type of node. */
-enum grub_hfsplus_btnode_type
- {
- GRUB_HFSPLUS_BTNODE_TYPE_LEAF = -1,
- GRUB_HFSPLUS_BTNODE_TYPE_INDEX = 0,
- GRUB_HFSPLUS_BTNODE_TYPE_HEADER = 1,
- GRUB_HFSPLUS_BTNODE_TYPE_MAP = 2,
- };
-
-struct grub_hfsplus_btnode
-{
- grub_uint32_t next;
- grub_uint32_t prev;
- grub_int8_t type;
- grub_uint8_t height;
- grub_uint16_t count;
- grub_uint16_t unused;
-} __attribute__ ((packed));
-
-/* The header of a HFS+ B+ Tree. */
-struct grub_hfsplus_btheader
-{
- grub_uint16_t depth;
- grub_uint32_t root;
- grub_uint32_t leaf_records;
- grub_uint32_t first_leaf_node;
- grub_uint32_t last_leaf_node;
- grub_uint16_t nodesize;
- grub_uint16_t keysize;
-} __attribute__ ((packed));
-
-/* The on disk layout of a catalog key. */
-struct grub_hfsplus_catkey
-{
- grub_uint16_t keylen;
- grub_uint32_t parent;
- grub_uint16_t namelen;
- grub_uint16_t name[30];
-} __attribute__ ((packed));
-
-/* The on disk layout of an extent overflow file key. */
-struct grub_hfsplus_extkey
-{
- grub_uint16_t keylen;
- grub_uint8_t type;
- grub_uint8_t unused;
- grub_uint32_t fileid;
- grub_uint32_t start;
-} __attribute__ ((packed));
-
-struct grub_hfsplus_key
-{
- union
- {
- struct grub_hfsplus_extkey extkey;
- struct grub_hfsplus_catkey catkey;
- grub_uint16_t keylen;
- };
-} __attribute__ ((packed));
-
-struct grub_hfsplus_catfile
-{
- grub_uint16_t type;
- grub_uint16_t flags;
- grub_uint32_t reserved;
- grub_uint32_t fileid;
- grub_uint8_t unused1[4];
- grub_uint32_t mtime;
- grub_uint8_t unused2[22];
- grub_uint16_t mode;
- grub_uint8_t unused3[44];
- struct grub_hfsplus_forkdata data;
- struct grub_hfsplus_forkdata resource;
-} __attribute__ ((packed));
-
-/* Filetype information as used in inodes. */
-#define GRUB_HFSPLUS_FILEMODE_MASK 0170000
-#define GRUB_HFSPLUS_FILEMODE_REG 0100000
-#define GRUB_HFSPLUS_FILEMODE_DIRECTORY 0040000
-#define GRUB_HFSPLUS_FILEMODE_SYMLINK 0120000
-
-/* Some pre-defined file IDs. */
-#define GRUB_HFSPLUS_FILEID_ROOTDIR 2
-#define GRUB_HFSPLUS_FILEID_OVERFLOW 3
-#define GRUB_HFSPLUS_FILEID_CATALOG 4
-
-enum grub_hfsplus_filetype
- {
- GRUB_HFSPLUS_FILETYPE_DIR = 1,
- GRUB_HFSPLUS_FILETYPE_REG = 2,
- GRUB_HFSPLUS_FILETYPE_DIR_THREAD = 3,
- GRUB_HFSPLUS_FILETYPE_REG_THREAD = 4
- };
+#include
/* Internal representation of a catalog key. */
struct grub_hfsplus_catkey_internal
@@ -225,6 +92,7 @@ struct grub_hfsplus_data
int embedded_offset;
};
+
#ifndef GRUB_UTIL
static grub_dl_t my_mod;
#endif
@@ -910,6 +778,8 @@ grub_hfsplus_dir (grub_device_t device, const char *path,
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
info.mtimeset = 1;
info.mtime = node->mtime;
+ info.inodeset = 1;
+ info.inode = node->fileid;
info.case_insensitive = !! (filetype & GRUB_FSHELP_CASE_INSENSITIVE);
grub_free (node);
return hook (filename, &info);
diff --git a/include/grub/fs.h b/include/grub/fs.h
index fa2c070..1aee621 100644
--- a/include/grub/fs.h
+++ b/include/grub/fs.h
@@ -32,7 +32,9 @@ struct grub_dirhook_info
int dir:1;
int mtimeset:1;
int case_insensitive:1;
+ int inodeset:1;
grub_int32_t mtime;
+ grub_uint64_t inode;
};
/* Filesystem descriptor. */
diff --git a/include/grub/hfsplus.h b/include/grub/hfsplus.h
new file mode 100644
index 0000000..e711165
--- /dev/null
+++ b/include/grub/hfsplus.h
@@ -0,0 +1,167 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2005,2006,2007,2008,2009 Free Software Foundation, Inc.
+ *
+ * GRUB 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB 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 GRUB. If not, see .
+ */
+
+#ifndef GRUB_HFSPLUS_HEADER
+#define GRUB_HFSPLUS_HEADER 1
+
+#include
+
+#define GRUB_HFSPLUS_MAGIC 0x482B
+#define GRUB_HFSPLUSX_MAGIC 0x4858
+#define GRUB_HFSPLUS_SBLOCK 2
+
+/* A HFS+ extent. */
+struct grub_hfsplus_extent
+{
+ /* The first block of a file on disk. */
+ grub_uint32_t start;
+ /* The amount of blocks described by this extent. */
+ grub_uint32_t count;
+} __attribute__ ((packed));
+
+/* The descriptor of a fork. */
+struct grub_hfsplus_forkdata
+{
+ grub_uint64_t size;
+ grub_uint32_t clumpsize;
+ grub_uint32_t blocks;
+ struct grub_hfsplus_extent extents[8];
+} __attribute__ ((packed));
+
+/* The HFS+ Volume Header. */
+struct grub_hfsplus_volheader
+{
+ grub_uint16_t magic;
+ grub_uint16_t version;
+ grub_uint32_t attributes;
+ grub_uint8_t unused1[12];
+ grub_uint32_t utime;
+ grub_uint8_t unused2[16];
+ grub_uint32_t blksize;
+ grub_uint8_t unused3[36];
+ grub_uint32_t bootdir;
+ grub_uint32_t bootfile;
+
+ /* Folder opened when disk is mounted. Unused by GRUB. */
+ grub_uint32_t showfolder;
+ grub_uint32_t os9folder;
+ grub_uint8_t unused4[4];
+ grub_uint32_t osxfolder;
+ grub_uint8_t volheader[8];
+ struct grub_hfsplus_forkdata allocations_file;
+ struct grub_hfsplus_forkdata extents_file;
+ struct grub_hfsplus_forkdata catalog_file;
+ struct grub_hfsplus_forkdata attrib_file;
+ struct grub_hfsplus_forkdata startup_file;
+} __attribute__ ((packed));
+
+/* The type of node. */
+enum grub_hfsplus_btnode_type
+ {
+ GRUB_HFSPLUS_BTNODE_TYPE_LEAF = -1,
+ GRUB_HFSPLUS_BTNODE_TYPE_INDEX = 0,
+ GRUB_HFSPLUS_BTNODE_TYPE_HEADER = 1,
+ GRUB_HFSPLUS_BTNODE_TYPE_MAP = 2,
+ };
+
+struct grub_hfsplus_btnode
+{
+ grub_uint32_t next;
+ grub_uint32_t prev;
+ grub_int8_t type;
+ grub_uint8_t height;
+ grub_uint16_t count;
+ grub_uint16_t unused;
+} __attribute__ ((packed));
+
+/* The header of a HFS+ B+ Tree. */
+struct grub_hfsplus_btheader
+{
+ grub_uint16_t depth;
+ grub_uint32_t root;
+ grub_uint32_t leaf_records;
+ grub_uint32_t first_leaf_node;
+ grub_uint32_t last_leaf_node;
+ grub_uint16_t nodesize;
+ grub_uint16_t keysize;
+} __attribute__ ((packed));
+
+/* The on disk layout of a catalog key. */
+struct grub_hfsplus_catkey
+{
+ grub_uint16_t keylen;
+ grub_uint32_t parent;
+ grub_uint16_t namelen;
+ grub_uint16_t name[30];
+} __attribute__ ((packed));
+
+/* The on disk layout of an extent overflow file key. */
+struct grub_hfsplus_extkey
+{
+ grub_uint16_t keylen;
+ grub_uint8_t type;
+ grub_uint8_t unused;
+ grub_uint32_t fileid;
+ grub_uint32_t start;
+} __attribute__ ((packed));
+
+struct grub_hfsplus_key
+{
+ union
+ {
+ struct grub_hfsplus_extkey extkey;
+ struct grub_hfsplus_catkey catkey;
+ grub_uint16_t keylen;
+ };
+} __attribute__ ((packed));
+
+struct grub_hfsplus_catfile
+{
+ grub_uint16_t type;
+ grub_uint16_t flags;
+ grub_uint32_t reserved;
+ grub_uint32_t fileid;
+ grub_uint8_t unused1[4];
+ grub_uint32_t mtime;
+ grub_uint8_t unused2[22];
+ grub_uint16_t mode;
+ grub_uint8_t unused3[44];
+ struct grub_hfsplus_forkdata data;
+ struct grub_hfsplus_forkdata resource;
+} __attribute__ ((packed));
+
+/* Filetype information as used in inodes. */
+#define GRUB_HFSPLUS_FILEMODE_MASK 0170000
+#define GRUB_HFSPLUS_FILEMODE_REG 0100000
+#define GRUB_HFSPLUS_FILEMODE_DIRECTORY 0040000
+#define GRUB_HFSPLUS_FILEMODE_SYMLINK 0120000
+
+/* Some pre-defined file IDs. */
+#define GRUB_HFSPLUS_FILEID_ROOTDIR 2
+#define GRUB_HFSPLUS_FILEID_OVERFLOW 3
+#define GRUB_HFSPLUS_FILEID_CATALOG 4
+
+enum grub_hfsplus_filetype
+ {
+ GRUB_HFSPLUS_FILETYPE_DIR = 1,
+ GRUB_HFSPLUS_FILETYPE_REG = 2,
+ GRUB_HFSPLUS_FILETYPE_DIR_THREAD = 3,
+ GRUB_HFSPLUS_FILETYPE_REG_THREAD = 4
+ };
+
+#endif