Sorry, forgot to attach the file
On Sat, Apr 18, 2009 at 8:59 PM, Vladimir Serbinenko phco...@gmail.comwrote:
Hello, due to request by ams I wrote this. It's an analog of bless
command available under OSX rewritten using grub2 fs functions and according
to apple specification of hfs+ on-disk format. This command only update the
blessed folder on a partition it doesn't change which drive is used for
booting. The later will be a separate command. Also you can choose which
volume to boot from by holding option key. Syntax:
hfspbless DIRECTORY
It works only on HFS+ volumes. Also due to the lack of hardware I wasn't
unable to test this in vivo
diff --git a/commands/hfspbless.c b/commands/hfspbless.c
new file mode 100644
index 000..318a77c
--- /dev/null
+++ b/commands/hfspbless.c
@@ -0,0 +1,199 @@
+/* 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 http://www.gnu.org/licenses/.
+ */
+
+#include grub/command.h
+#include grub/fs.h
+#include grub/misc.h
+#include grub/dl.h
+#include grub/device.h
+#include grub/disk.h
+#include grub/hfsplus.h
+#include grub/hfs.h
+#include grub/partition.h
+#include grub/file.h
+#include grub/mm.h
+#include grub/err.h
+
+static grub_uint64_t inode;
+static char *dirname;
+
+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-dir info-inodeset)
+inode = info-inode;
+ 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, '/');
+ inode = 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 (inode == 0)
+{
+ grub_device_close (dev);
+ grub_free (device_name);
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND,
+ %s not found or isn't a directory\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);
+