removed accidental commit
[grub2/phcoder.git] / commands / hfspbless.c
blob42e9d3fd9e6ca49f24af05a9704f31601b5b688b
1 /* hfspbless.c - set the hfs+ boot directory. */
2 /*
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>
21 #include <grub/fs.h>
22 #include <grub/misc.h>
23 #include <grub/dl.h>
24 #include <grub/device.h>
25 #include <grub/disk.h>
26 #include <grub/hfsplus.h>
27 #include <grub/hfs.h>
28 #include <grub/partition.h>
29 #include <grub/file.h>
30 #include <grub/mm.h>
31 #include <grub/err.h>
33 static grub_uint64_t inode;
34 static char *dirname;
35 static int found;
37 static int find_inode (const char *filename,
38 const struct grub_dirhook_info *info)
40 if (! info->inodeset)
41 return 0;
43 if ((grub_strcmp (dirname, filename) == 0
44 || (info->case_insensitive && grub_strcasecmp (dirname, filename) == 0)))
46 inode = info->inode;
47 found = info->dir ? 2 : 1;
49 return 0;
52 static grub_err_t
53 grub_cmd_hfsbless (grub_command_t cmd __attribute__ ((unused)),
54 int argc, char **args)
56 char *device_name;
57 char *path = 0, *tail;
58 int embedded_offset;
59 grub_device_t dev;
60 grub_fs_t fs;
62 union {
63 struct grub_hfs_sblock hfs;
64 struct grub_hfsplus_volheader hfsplus;
65 } volheader;
67 if (argc != 1)
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], ')');
73 if (! path)
74 path = grub_strdup (dirname);
75 else
76 path = grub_strdup (path + 1);
78 if (! path || *path == 0 || ! device_name)
80 if (dev)
81 grub_device_close (dev);
83 grub_free (device_name);
84 grub_free (path);
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);
94 grub_free (path);
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 == '/')
103 *(tail--) = 0;
105 tail = grub_strrchr (path, '/');
106 found = 0;
108 if (tail)
110 *tail = 0;
111 dirname = tail + 1;
113 (fs->dir) (dev, *path == 0 ? "/" : path, find_inode);
115 else
117 dirname = path + 1;
118 (fs->dir) (dev, "/", find_inode);
120 grub_free (path);
122 if (! found)
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);
132 if (grub_errno)
134 grub_device_close (dev);
135 grub_free (device_name);
136 return grub_errno;
139 embedded_offset = 0;
140 if (grub_be_to_cpu16 (volheader.hfs.magic) == GRUB_HFS_MAGIC)
142 int extent_start;
143 int ablk_size;
144 int ablk_start;
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);
151 return grub_errno;
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
159 + extent_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);
164 if (grub_errno)
166 grub_device_close (dev);
167 grub_free (device_name);
168 return grub_errno;
172 /* Make sure this is an HFS+ filesystem. XXX: Do we really support
173 HFX? */
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");
181 if (found == 2)
182 volheader.hfsplus.bootdir = grub_be_to_cpu32 (inode);
183 else
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);
191 return grub_errno;
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);