2 * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org>
3 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
5 * This file may be redistributed under the terms of the
6 * GNU Lesser General Public License.
14 #include "superblocks.h"
18 struct hfs_finder_info {
26 } __attribute__((packed));
47 uint32_t xt_clump_size;
48 uint32_t ct_clump_size;
49 uint16_t num_root_dirs;
52 struct hfs_finder_info finder_info;
54 uint16_t embed_startblock;
55 uint16_t embed_blockcount;
56 } __attribute__((packed));
59 #define HFS_NODE_LEAF 0xff
60 #define HFSPLUS_POR_CNID 1
62 struct hfsplus_bnode_descriptor {
69 } __attribute__((packed));
71 struct hfsplus_bheader_record {
78 } __attribute__((packed));
80 struct hfsplus_catalog_key {
84 uint8_t unicode[255 * 2];
85 } __attribute__((packed));
87 struct hfsplus_extent {
90 } __attribute__((packed));
92 #define HFSPLUS_EXTENT_COUNT 8
96 uint32_t total_blocks;
97 struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
98 } __attribute__((packed));
100 struct hfsplus_vol_header {
101 uint8_t signature[2];
104 uint32_t last_mount_vers;
106 uint32_t create_date;
107 uint32_t modify_date;
108 uint32_t backup_date;
109 uint32_t checked_date;
111 uint32_t folder_count;
113 uint32_t total_blocks;
114 uint32_t free_blocks;
116 uint32_t rsrc_clump_sz;
117 uint32_t data_clump_sz;
119 uint32_t write_count;
120 uint64_t encodings_bmp;
121 struct hfs_finder_info finder_info;
122 struct hfsplus_fork alloc_file;
123 struct hfsplus_fork ext_file;
124 struct hfsplus_fork cat_file;
125 struct hfsplus_fork attr_file;
126 struct hfsplus_fork start_file;
127 } __attribute__((packed));
129 #define HFSPLUS_SECTOR_SIZE 512
131 static int hfs_set_uuid(blkid_probe pr, unsigned char const *hfs_info, size_t len)
133 /* static unsigned char const hash_init[MD5LENGTH] = {
134 0xb3, 0xe2, 0x0f, 0x39, 0xf2, 0x92, 0x11, 0xd6,
135 0x97, 0xa4, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac
137 unsigned char uuid[MD5LENGTH];
138 struct MD5Context md5c;
140 if (memcmp(hfs_info, "\0\0\0\0\0\0\0\0", len) == 0)
143 MD5Update(&md5c, hash_init, MD5LENGTH);
144 MD5Update(&md5c, hfs_info, len);
145 MD5Final(uuid, &md5c);
146 uuid[6] = 0x30 | (uuid[6] & 0x0f);
147 uuid[8] = 0x80 | (uuid[8] & 0x3f);
148 return blkid_probe_set_uuid(pr, uuid);*/
152 static int probe_hfs(blkid_probe pr, const struct blkid_idmag *mag)
156 hfs = blkid_probe_get_sb(pr, mag, struct hfs_mdb);
160 if ((memcmp(hfs->embed_sig, "H+", 2) == 0) ||
161 (memcmp(hfs->embed_sig, "HX", 2) == 0))
162 return 1; /* Not hfs, but an embedded HFS+ */
164 hfs_set_uuid(pr, hfs->finder_info.id, sizeof(hfs->finder_info.id));
166 blkid_probe_set_label(pr, hfs->label, hfs->label_len);
170 static int probe_hfsplus(blkid_probe pr, const struct blkid_idmag *mag)
172 struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
173 struct hfsplus_bnode_descriptor *descr;
174 struct hfsplus_bheader_record *bnode;
175 struct hfsplus_catalog_key *key;
176 struct hfsplus_vol_header *hfsplus;
178 unsigned int alloc_block_size;
179 unsigned int alloc_first_block;
180 unsigned int embed_first_block;
181 unsigned int off = 0;
182 unsigned int blocksize;
183 unsigned int cat_block;
184 unsigned int ext_block_start;
185 unsigned int ext_block_count;
186 unsigned int record_count;
187 unsigned int leaf_node_head;
188 unsigned int leaf_node_count;
189 unsigned int leaf_node_size;
190 unsigned int leaf_block;
195 sbd = blkid_probe_get_sb(pr, mag, struct hfs_mdb);
199 /* Check for a HFS+ volume embedded in a HFS volume */
200 if (memcmp(sbd->signature, "BD", 2) == 0) {
201 if ((memcmp(sbd->embed_sig, "H+", 2) != 0) &&
202 (memcmp(sbd->embed_sig, "HX", 2) != 0))
203 /* This must be an HFS volume, so fail */
206 alloc_block_size = be32_to_cpu(sbd->al_blk_size);
207 alloc_first_block = be16_to_cpu(sbd->al_bl_st);
208 embed_first_block = be16_to_cpu(sbd->embed_startblock);
209 off = (alloc_first_block * 512) +
210 (embed_first_block * alloc_block_size);
212 buf = blkid_probe_get_buffer(pr,
213 off + (mag->kboff * 1024),
214 sizeof(struct hfsplus_vol_header));
215 hfsplus = (struct hfsplus_vol_header *) buf;
218 hfsplus = blkid_probe_get_sb(pr, mag,
219 struct hfsplus_vol_header);
224 if ((memcmp(hfsplus->signature, "H+", 2) != 0) &&
225 (memcmp(hfsplus->signature, "HX", 2) != 0))
228 hfs_set_uuid(pr, hfsplus->finder_info.id, sizeof(hfsplus->finder_info.id));
230 blocksize = be32_to_cpu(hfsplus->blocksize);
231 if (blocksize < HFSPLUS_SECTOR_SIZE)
234 memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
235 cat_block = be32_to_cpu(extents[0].start_block);
237 buf = blkid_probe_get_buffer(pr,
238 off + ((blkid_loff_t) cat_block * blocksize), 0x2000);
242 bnode = (struct hfsplus_bheader_record *)
243 &buf[sizeof(struct hfsplus_bnode_descriptor)];
245 leaf_node_head = be32_to_cpu(bnode->leaf_head);
246 leaf_node_size = be16_to_cpu(bnode->node_size);
247 leaf_node_count = be32_to_cpu(bnode->leaf_count);
248 if (leaf_node_count == 0)
251 leaf_block = (leaf_node_head * leaf_node_size) / blocksize;
253 /* get physical location */
254 for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) {
255 ext_block_start = be32_to_cpu(extents[ext].start_block);
256 ext_block_count = be32_to_cpu(extents[ext].block_count);
257 if (ext_block_count == 0)
260 /* this is our extent */
261 if (leaf_block < ext_block_count)
264 leaf_block -= ext_block_count;
266 if (ext == HFSPLUS_EXTENT_COUNT)
269 leaf_off = (ext_block_start + leaf_block) * blocksize;
271 buf = blkid_probe_get_buffer(pr,
272 (blkid_loff_t) off + leaf_off,
277 descr = (struct hfsplus_bnode_descriptor *) buf;
278 record_count = be16_to_cpu(descr->num_recs);
279 if (record_count == 0)
282 if (descr->type != HFS_NODE_LEAF)
285 key = (struct hfsplus_catalog_key *)
286 &buf[sizeof(struct hfsplus_bnode_descriptor)];
288 if (be32_to_cpu(key->parent_id) != HFSPLUS_POR_CNID)
294 const struct blkid_idinfo hfs_idinfo =
297 .usage = BLKID_USAGE_FILESYSTEM,
298 .probefunc = probe_hfs,
299 .flags = BLKID_IDINFO_TOLERANT,
302 { .magic = "BD", .len = 2, .kboff = 1 },
307 const struct blkid_idinfo hfsplus_idinfo =
310 .usage = BLKID_USAGE_FILESYSTEM,
311 .probefunc = probe_hfsplus,
314 { .magic = "BD", .len = 2, .kboff = 1 },
315 { .magic = "H+", .len = 2, .kboff = 1 },
316 { .magic = "HX", .len = 2, .kboff = 1 },