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"
21 struct hfs_finder_info
{
29 } __attribute__((packed
));
50 uint32_t xt_clump_size
;
51 uint32_t ct_clump_size
;
52 uint16_t num_root_dirs
;
55 struct hfs_finder_info finder_info
;
57 uint16_t embed_startblock
;
58 uint16_t embed_blockcount
;
59 } __attribute__((packed
));
62 #define HFS_NODE_LEAF 0xff
63 #define HFSPLUS_POR_CNID 1
65 struct hfsplus_bnode_descriptor
{
72 } __attribute__((packed
));
74 struct hfsplus_bheader_record
{
81 } __attribute__((packed
));
83 struct hfsplus_catalog_key
{
87 uint8_t unicode
[255 * 2];
88 } __attribute__((packed
));
90 struct hfsplus_extent
{
93 } __attribute__((packed
));
95 #define HFSPLUS_EXTENT_COUNT 8
99 uint32_t total_blocks
;
100 struct hfsplus_extent extents
[HFSPLUS_EXTENT_COUNT
];
101 } __attribute__((packed
));
103 struct hfsplus_vol_header
{
104 uint8_t signature
[2];
107 uint32_t last_mount_vers
;
109 uint32_t create_date
;
110 uint32_t modify_date
;
111 uint32_t backup_date
;
112 uint32_t checked_date
;
114 uint32_t folder_count
;
116 uint32_t total_blocks
;
117 uint32_t free_blocks
;
119 uint32_t rsrc_clump_sz
;
120 uint32_t data_clump_sz
;
122 uint32_t write_count
;
123 uint64_t encodings_bmp
;
124 struct hfs_finder_info finder_info
;
125 struct hfsplus_fork alloc_file
;
126 struct hfsplus_fork ext_file
;
127 struct hfsplus_fork cat_file
;
128 struct hfsplus_fork attr_file
;
129 struct hfsplus_fork start_file
;
130 } __attribute__((packed
));
132 #define HFSPLUS_SECTOR_SIZE 512
134 static int hfs_set_uuid(blkid_probe pr
, unsigned char const *hfs_info
, size_t len
)
137 static unsigned char const hash_init
[MD5LENGTH
] = {
138 0xb3, 0xe2, 0x0f, 0x39, 0xf2, 0x92, 0x11, 0xd6,
139 0x97, 0xa4, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac
141 unsigned char uuid
[MD5LENGTH
];
142 struct MD5Context md5c
;
144 if (memcmp(hfs_info
, "\0\0\0\0\0\0\0\0", len
) == 0)
147 MD5Update(&md5c
, hash_init
, MD5LENGTH
);
148 MD5Update(&md5c
, hfs_info
, len
);
149 MD5Final(uuid
, &md5c
);
150 uuid
[6] = 0x30 | (uuid
[6] & 0x0f);
151 uuid
[8] = 0x80 | (uuid
[8] & 0x3f);
152 return blkid_probe_set_uuid(pr
, uuid
);
158 static int probe_hfs(blkid_probe pr
, const struct blkid_idmag
*mag
)
162 hfs
= blkid_probe_get_sb(pr
, mag
, struct hfs_mdb
);
164 return errno
? -errno
: 1;
166 if ((memcmp(hfs
->embed_sig
, "H+", 2) == 0) ||
167 (memcmp(hfs
->embed_sig
, "HX", 2) == 0))
168 return 1; /* Not hfs, but an embedded HFS+ */
170 hfs_set_uuid(pr
, hfs
->finder_info
.id
, sizeof(hfs
->finder_info
.id
));
172 blkid_probe_set_label(pr
, hfs
->label
, hfs
->label_len
);
176 static int probe_hfsplus(blkid_probe pr
, const struct blkid_idmag
*mag
)
178 struct hfsplus_extent extents
[HFSPLUS_EXTENT_COUNT
];
179 struct hfsplus_bnode_descriptor
*descr
;
180 struct hfsplus_bheader_record
*bnode
;
181 struct hfsplus_catalog_key
*key
;
182 struct hfsplus_vol_header
*hfsplus
;
184 unsigned int alloc_block_size
;
185 unsigned int alloc_first_block
;
186 unsigned int embed_first_block
;
187 unsigned int off
= 0;
188 unsigned int blocksize
;
189 unsigned int cat_block
;
190 unsigned int ext_block_start
;
191 unsigned int ext_block_count
;
192 unsigned int record_count
;
193 unsigned int leaf_node_head
;
194 unsigned int leaf_node_count
;
195 unsigned int leaf_node_size
;
196 unsigned int leaf_block
;
201 sbd
= blkid_probe_get_sb(pr
, mag
, struct hfs_mdb
);
203 return errno
? -errno
: 1;
205 /* Check for a HFS+ volume embedded in a HFS volume */
206 if (memcmp(sbd
->signature
, "BD", 2) == 0) {
207 if ((memcmp(sbd
->embed_sig
, "H+", 2) != 0) &&
208 (memcmp(sbd
->embed_sig
, "HX", 2) != 0))
209 /* This must be an HFS volume, so fail */
212 alloc_block_size
= be32_to_cpu(sbd
->al_blk_size
);
213 alloc_first_block
= be16_to_cpu(sbd
->al_bl_st
);
214 embed_first_block
= be16_to_cpu(sbd
->embed_startblock
);
215 off
= (alloc_first_block
* 512) +
216 (embed_first_block
* alloc_block_size
);
218 buf
= blkid_probe_get_buffer(pr
,
219 off
+ (mag
->kboff
* 1024),
220 sizeof(struct hfsplus_vol_header
));
221 hfsplus
= (struct hfsplus_vol_header
*) buf
;
224 hfsplus
= blkid_probe_get_sb(pr
, mag
,
225 struct hfsplus_vol_header
);
228 return errno
? -errno
: 1;
230 if ((memcmp(hfsplus
->signature
, "H+", 2) != 0) &&
231 (memcmp(hfsplus
->signature
, "HX", 2) != 0))
234 hfs_set_uuid(pr
, hfsplus
->finder_info
.id
, sizeof(hfsplus
->finder_info
.id
));
236 blocksize
= be32_to_cpu(hfsplus
->blocksize
);
237 if (blocksize
< HFSPLUS_SECTOR_SIZE
)
240 memcpy(extents
, hfsplus
->cat_file
.extents
, sizeof(extents
));
241 cat_block
= be32_to_cpu(extents
[0].start_block
);
243 buf
= blkid_probe_get_buffer(pr
,
244 off
+ ((blkid_loff_t
) cat_block
* blocksize
), 0x2000);
246 return errno
? -errno
: 0;
248 bnode
= (struct hfsplus_bheader_record
*)
249 &buf
[sizeof(struct hfsplus_bnode_descriptor
)];
251 leaf_node_head
= be32_to_cpu(bnode
->leaf_head
);
252 leaf_node_size
= be16_to_cpu(bnode
->node_size
);
253 leaf_node_count
= be32_to_cpu(bnode
->leaf_count
);
254 if (leaf_node_count
== 0)
257 leaf_block
= (leaf_node_head
* leaf_node_size
) / blocksize
;
259 /* get physical location */
260 for (ext
= 0; ext
< HFSPLUS_EXTENT_COUNT
; ext
++) {
261 ext_block_start
= be32_to_cpu(extents
[ext
].start_block
);
262 ext_block_count
= be32_to_cpu(extents
[ext
].block_count
);
263 if (ext_block_count
== 0)
266 /* this is our extent */
267 if (leaf_block
< ext_block_count
)
270 leaf_block
-= ext_block_count
;
272 if (ext
== HFSPLUS_EXTENT_COUNT
)
275 leaf_off
= ((uint64_t) ext_block_start
+ leaf_block
) * blocksize
;
277 buf
= blkid_probe_get_buffer(pr
,
278 (blkid_loff_t
) off
+ leaf_off
,
281 return errno
? -errno
: 0;
283 descr
= (struct hfsplus_bnode_descriptor
*) buf
;
284 record_count
= be16_to_cpu(descr
->num_recs
);
285 if (record_count
== 0)
288 if (descr
->type
!= HFS_NODE_LEAF
)
291 key
= (struct hfsplus_catalog_key
*)
292 &buf
[sizeof(struct hfsplus_bnode_descriptor
)];
294 if (be32_to_cpu(key
->parent_id
) != HFSPLUS_POR_CNID
)
297 blkid_probe_set_utf8label(pr
, key
->unicode
,
298 be16_to_cpu(key
->unicode_len
) * 2,
304 const struct blkid_idinfo hfs_idinfo
=
307 .usage
= BLKID_USAGE_FILESYSTEM
,
308 .probefunc
= probe_hfs
,
309 .flags
= BLKID_IDINFO_TOLERANT
,
312 { .magic
= "BD", .len
= 2, .kboff
= 1 },
317 const struct blkid_idinfo hfsplus_idinfo
=
320 .usage
= BLKID_USAGE_FILESYSTEM
,
321 .probefunc
= probe_hfsplus
,
324 { .magic
= "BD", .len
= 2, .kboff
= 1 },
325 { .magic
= "H+", .len
= 2, .kboff
= 1 },
326 { .magic
= "HX", .len
= 2, .kboff
= 1 },