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 },