1 /* hfspbless.c - set the hfs+ boot directory. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2003,2005,2007,2008,2009,2012,2013 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 GRUB_MOD_LICENSE ("GPLv3+");
35 struct find_node_context
37 grub_uint64_t inode_found
;
40 { FOUND_NONE
, FOUND_FILE
, FOUND_DIR
} found
;
44 find_inode (const char *filename
,
45 const struct grub_dirhook_info
*info
, void *data
)
47 struct find_node_context
*ctx
= data
;
51 if ((grub_strcmp (ctx
->dirname
, filename
) == 0
52 || (info
->case_insensitive
53 && grub_strcasecmp (ctx
->dirname
, filename
) == 0)))
55 ctx
->inode_found
= info
->inode
;
56 ctx
->found
= info
->dir
? FOUND_DIR
: FOUND_FILE
;
62 grub_mac_bless_inode (grub_device_t dev
, grub_uint32_t inode
, int is_dir
,
68 struct grub_hfs_sblock hfs
;
69 struct grub_hfsplus_volheader hfsplus
;
71 grub_disk_addr_t embedded_offset
;
74 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
75 "can't bless a directory for mactel");
76 if (!intel
&& !is_dir
)
77 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
78 "can't bless a file for mac PPC");
80 /* Read the bootblock. */
81 err
= grub_disk_read (dev
->disk
, GRUB_HFSPLUS_SBLOCK
, 0, sizeof (volheader
),
87 if (grub_be_to_cpu16 (volheader
.hfs
.magic
) == GRUB_HFS_MAGIC
)
93 /* See if there's an embedded HFS+ filesystem. */
94 if (grub_be_to_cpu16 (volheader
.hfs
.embed_sig
) != GRUB_HFSPLUS_MAGIC
)
97 volheader
.hfs
.intel_bootfile
= grub_be_to_cpu32 (inode
);
99 volheader
.hfs
.ppc_bootdir
= grub_be_to_cpu32 (inode
);
100 return GRUB_ERR_NONE
;
103 /* Calculate the offset needed to translate HFS+ sector numbers. */
105 grub_be_to_cpu16 (volheader
.hfs
.embed_extent
.first_block
);
106 ablk_size
= grub_be_to_cpu32 (volheader
.hfs
.blksz
);
107 ablk_start
= grub_be_to_cpu16 (volheader
.hfs
.first_block
);
108 embedded_offset
= (ablk_start
109 + ((grub_uint64_t
) extent_start
)
110 * (ablk_size
>> GRUB_DISK_SECTOR_BITS
));
113 grub_disk_read (dev
->disk
, embedded_offset
+ GRUB_HFSPLUS_SBLOCK
, 0,
114 sizeof (volheader
), (char *) &volheader
);
119 if ((grub_be_to_cpu16 (volheader
.hfsplus
.magic
) != GRUB_HFSPLUS_MAGIC
)
120 && (grub_be_to_cpu16 (volheader
.hfsplus
.magic
) != GRUB_HFSPLUSX_MAGIC
))
121 return grub_error (GRUB_ERR_BAD_FS
, "not a HFS+ filesystem");
123 volheader
.hfsplus
.intel_bootfile
= grub_be_to_cpu32 (inode
);
125 volheader
.hfsplus
.ppc_bootdir
= grub_be_to_cpu32 (inode
);
127 return grub_disk_write (dev
->disk
, embedded_offset
+ GRUB_HFSPLUS_SBLOCK
, 0,
128 sizeof (volheader
), (char *) &volheader
);
132 grub_mac_bless_file (grub_device_t dev
, const char *path_in
, int intel
)
137 struct find_node_context ctx
;
139 fs
= grub_fs_probe (dev
);
140 if (!fs
|| (grub_strcmp (fs
->name
, "hfsplus") != 0
141 && grub_strcmp (fs
->name
, "hfs") != 0))
142 return grub_error (GRUB_ERR_BAD_FS
, "no suitable FS found");
144 path
= grub_strdup (path_in
);
148 tail
= path
+ grub_strlen (path
) - 1;
150 /* Remove trailing '/'. */
151 while (tail
!= path
&& *tail
== '/')
154 tail
= grub_strrchr (path
, '/');
160 ctx
.dirname
= tail
+ 1;
162 (fs
->dir
) (dev
, *path
== 0 ? "/" : path
, find_inode
, &ctx
);
166 ctx
.dirname
= path
+ 1;
167 (fs
->dir
) (dev
, "/", find_inode
, &ctx
);
172 return grub_error (GRUB_ERR_FILE_NOT_FOUND
, N_("file `%s' not found"),
177 return grub_mac_bless_inode (dev
, (grub_uint32_t
) ctx
.inode_found
,
178 (ctx
.found
== FOUND_DIR
), intel
);
182 grub_cmd_macbless (grub_command_t cmd
, int argc
, char **args
)
186 grub_device_t dev
= 0;
190 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("one argument expected"));
191 device_name
= grub_file_get_device_name (args
[0]);
192 dev
= grub_device_open (device_name
);
194 path
= grub_strchr (args
[0], ')');
200 if (!path
|| *path
== 0 || !dev
)
203 grub_device_close (dev
);
205 grub_free (device_name
);
207 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "invalid argument");
210 err
= grub_mac_bless_file (dev
, path
, cmd
->name
[3] == 't');
212 grub_device_close (dev
);
213 grub_free (device_name
);
217 static grub_command_t cmd
, cmd_ppc
;
219 GRUB_MOD_INIT(macbless
)
221 cmd
= grub_register_command ("mactelbless", grub_cmd_macbless
,
224 ("Bless FILE of HFS or HFS+ partition for intel macs."));
226 grub_register_command ("macppcbless", grub_cmd_macbless
, N_("DIR"),
228 ("Bless DIR of HFS or HFS+ partition for PPC macs."));
231 GRUB_MOD_FINI(macbless
)
233 grub_unregister_command (cmd
);
234 grub_unregister_command (cmd_ppc
);