1 /* hfspbless.c - set the hfs+ boot directory. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2003,2005,2007,2008,2009 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/command.h>
22 #include <grub/misc.h>
24 #include <grub/device.h>
25 #include <grub/disk.h>
26 #include <grub/hfsplus.h>
28 #include <grub/partition.h>
29 #include <grub/file.h>
33 static grub_uint64_t inode
;
37 static int find_inode (const char *filename
,
38 const struct grub_dirhook_info
*info
)
43 if ((grub_strcmp (dirname
, filename
) == 0
44 || (info
->case_insensitive
&& grub_strcasecmp (dirname
, filename
) == 0)))
47 found
= info
->dir
? 2 : 1;
53 grub_cmd_hfsbless (grub_command_t cmd
__attribute__ ((unused
)),
54 int argc
, char **args
)
57 char *path
= 0, *tail
;
63 struct grub_hfs_sblock hfs
;
64 struct grub_hfsplus_volheader hfsplus
;
68 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "directory or file required");
69 device_name
= grub_file_get_device_name (args
[0]);
70 dev
= grub_device_open (device_name
);
72 path
= grub_strchr (args
[0], ')');
74 path
= grub_strdup (dirname
);
76 path
= grub_strdup (path
+ 1);
78 if (! path
|| *path
== 0 || ! device_name
)
81 grub_device_close (dev
);
83 grub_free (device_name
);
86 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "invalid argument");
89 fs
= grub_fs_probe (dev
);
90 if (! fs
|| grub_strcmp (fs
->name
, "hfsplus") != 0)
92 grub_device_close (dev
);
93 grub_free (device_name
);
96 return grub_error (GRUB_ERR_BAD_FS
, "no suitable FS found");
99 tail
= path
+ grub_strlen (path
) - 1;
101 /* Remove trailing '/'. */
102 while (tail
!= path
&& *tail
== '/')
105 tail
= grub_strrchr (path
, '/');
113 (fs
->dir
) (dev
, *path
== 0 ? "/" : path
, find_inode
);
118 (fs
->dir
) (dev
, "/", find_inode
);
124 grub_device_close (dev
);
125 grub_free (device_name
);
126 return grub_error (GRUB_ERR_FILE_NOT_FOUND
, "%s not found\n", args
[0]);
129 /* Read the bootblock. */
130 grub_disk_read (dev
->disk
, GRUB_HFSPLUS_SBLOCK
, 0, sizeof (volheader
),
131 (char *) &volheader
);
134 grub_device_close (dev
);
135 grub_free (device_name
);
140 if (grub_be_to_cpu16 (volheader
.hfs
.magic
) == GRUB_HFS_MAGIC
)
146 /* See if there's an embedded HFS+ filesystem. */
147 if (grub_be_to_cpu16 (volheader
.hfs
.embed_sig
) != GRUB_HFSPLUS_MAGIC
)
149 grub_device_close (dev
);
150 grub_free (device_name
);
154 /* Calculate the offset needed to translate HFS+ sector numbers. */
155 extent_start
= grub_be_to_cpu16 (volheader
.hfs
.embed_extent
.first_block
);
156 ablk_size
= grub_be_to_cpu32 (volheader
.hfs
.blksz
);
157 ablk_start
= grub_be_to_cpu16 (volheader
.hfs
.first_block
);
158 embedded_offset
= (ablk_start
160 * (ablk_size
>> GRUB_DISK_SECTOR_BITS
));
162 grub_disk_read (dev
->disk
, embedded_offset
+ GRUB_HFSPLUS_SBLOCK
, 0,
163 sizeof (volheader
), (char *) &volheader
);
166 grub_device_close (dev
);
167 grub_free (device_name
);
172 /* Make sure this is an HFS+ filesystem. XXX: Do we really support
174 if ((grub_be_to_cpu16 (volheader
.hfsplus
.magic
) != GRUB_HFSPLUS_MAGIC
)
175 && (grub_be_to_cpu16 (volheader
.hfsplus
.magic
) != GRUB_HFSPLUSX_MAGIC
))
177 grub_device_close (dev
);
178 grub_free (device_name
);
179 return grub_error (GRUB_ERR_BAD_FS
, "not a HFS+ filesystem");
182 volheader
.hfsplus
.bootdir
= grub_be_to_cpu32 (inode
);
184 volheader
.hfsplus
.bootfile
= grub_be_to_cpu32 (inode
);
186 grub_disk_write (dev
->disk
, embedded_offset
+ GRUB_HFSPLUS_SBLOCK
, 0,
187 sizeof (volheader
), (char *) &volheader
);
189 grub_device_close (dev
);
190 grub_free (device_name
);
194 static grub_command_t cmd
;
196 GRUB_MOD_INIT(hfsbless
)
198 cmd
= grub_register_command ("hfsbless", grub_cmd_hfsbless
,
199 "hfsbless [DIRECTORY|FILE]",
200 "Bless DIRECTORY or FILE of HFS+ partition.");
203 GRUB_MOD_FINI(hfsbless
)
205 grub_unregister_command (cmd
);