block: remove handling of name property
[project/fstools.git] / libblkid-tiny / hfs.c
1 /*
2 * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org>
3 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
4 *
5 * This file may be redistributed under the terms of the
6 * GNU Lesser General Public License.
7 */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <inttypes.h>
13
14 #include "superblocks.h"
15
16 #if 0
17 #include "md5.h"
18 #endif
19
20 /* HFS / HFS+ */
21 struct hfs_finder_info {
22 uint32_t boot_folder;
23 uint32_t start_app;
24 uint32_t open_folder;
25 uint32_t os9_folder;
26 uint32_t reserved;
27 uint32_t osx_folder;
28 uint8_t id[8];
29 } __attribute__((packed));
30
31 struct hfs_mdb {
32 uint8_t signature[2];
33 uint32_t cr_date;
34 uint32_t ls_Mod;
35 uint16_t atrb;
36 uint16_t nm_fls;
37 uint16_t vbm_st;
38 uint16_t alloc_ptr;
39 uint16_t nm_al_blks;
40 uint32_t al_blk_size;
41 uint32_t clp_size;
42 uint16_t al_bl_st;
43 uint32_t nxt_cnid;
44 uint16_t free_bks;
45 uint8_t label_len;
46 uint8_t label[27];
47 uint32_t vol_bkup;
48 uint16_t vol_seq_num;
49 uint32_t wr_cnt;
50 uint32_t xt_clump_size;
51 uint32_t ct_clump_size;
52 uint16_t num_root_dirs;
53 uint32_t file_count;
54 uint32_t dir_count;
55 struct hfs_finder_info finder_info;
56 uint8_t embed_sig[2];
57 uint16_t embed_startblock;
58 uint16_t embed_blockcount;
59 } __attribute__((packed));
60
61
62 #define HFS_NODE_LEAF 0xff
63 #define HFSPLUS_POR_CNID 1
64
65 struct hfsplus_bnode_descriptor {
66 uint32_t next;
67 uint32_t prev;
68 uint8_t type;
69 uint8_t height;
70 uint16_t num_recs;
71 uint16_t reserved;
72 } __attribute__((packed));
73
74 struct hfsplus_bheader_record {
75 uint16_t depth;
76 uint32_t root;
77 uint32_t leaf_count;
78 uint32_t leaf_head;
79 uint32_t leaf_tail;
80 uint16_t node_size;
81 } __attribute__((packed));
82
83 struct hfsplus_catalog_key {
84 uint16_t key_len;
85 uint32_t parent_id;
86 uint16_t unicode_len;
87 uint8_t unicode[255 * 2];
88 } __attribute__((packed));
89
90 struct hfsplus_extent {
91 uint32_t start_block;
92 uint32_t block_count;
93 } __attribute__((packed));
94
95 #define HFSPLUS_EXTENT_COUNT 8
96 struct hfsplus_fork {
97 uint64_t total_size;
98 uint32_t clump_size;
99 uint32_t total_blocks;
100 struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
101 } __attribute__((packed));
102
103 struct hfsplus_vol_header {
104 uint8_t signature[2];
105 uint16_t version;
106 uint32_t attributes;
107 uint32_t last_mount_vers;
108 uint32_t reserved;
109 uint32_t create_date;
110 uint32_t modify_date;
111 uint32_t backup_date;
112 uint32_t checked_date;
113 uint32_t file_count;
114 uint32_t folder_count;
115 uint32_t blocksize;
116 uint32_t total_blocks;
117 uint32_t free_blocks;
118 uint32_t next_alloc;
119 uint32_t rsrc_clump_sz;
120 uint32_t data_clump_sz;
121 uint32_t next_cnid;
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));
131
132 #define HFSPLUS_SECTOR_SIZE 512
133
134 static int hfs_set_uuid(blkid_probe pr, unsigned char const *hfs_info, size_t len)
135 {
136 #if 0
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
140 };
141 unsigned char uuid[MD5LENGTH];
142 struct MD5Context md5c;
143
144 if (memcmp(hfs_info, "\0\0\0\0\0\0\0\0", len) == 0)
145 return -1;
146 MD5Init(&md5c);
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);
153 #else
154 return -ENOSYS;
155 #endif
156 }
157
158 static int probe_hfs(blkid_probe pr, const struct blkid_idmag *mag)
159 {
160 struct hfs_mdb *hfs;
161
162 hfs = blkid_probe_get_sb(pr, mag, struct hfs_mdb);
163 if (!hfs)
164 return errno ? -errno : 1;
165
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+ */
169
170 hfs_set_uuid(pr, hfs->finder_info.id, sizeof(hfs->finder_info.id));
171
172 blkid_probe_set_label(pr, hfs->label, hfs->label_len);
173 return 0;
174 }
175
176 static int probe_hfsplus(blkid_probe pr, const struct blkid_idmag *mag)
177 {
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;
183 struct hfs_mdb *sbd;
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;
197 int ext;
198 uint64_t leaf_off;
199 unsigned char *buf;
200
201 sbd = blkid_probe_get_sb(pr, mag, struct hfs_mdb);
202 if (!sbd)
203 return errno ? -errno : 1;
204
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 */
210 return 1;
211
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);
217
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;
222
223 } else
224 hfsplus = blkid_probe_get_sb(pr, mag,
225 struct hfsplus_vol_header);
226
227 if (!hfsplus)
228 return errno ? -errno : 1;
229
230 if ((memcmp(hfsplus->signature, "H+", 2) != 0) &&
231 (memcmp(hfsplus->signature, "HX", 2) != 0))
232 return 1;
233
234 hfs_set_uuid(pr, hfsplus->finder_info.id, sizeof(hfsplus->finder_info.id));
235
236 blocksize = be32_to_cpu(hfsplus->blocksize);
237 if (blocksize < HFSPLUS_SECTOR_SIZE)
238 return 1;
239
240 memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
241 cat_block = be32_to_cpu(extents[0].start_block);
242
243 buf = blkid_probe_get_buffer(pr,
244 off + ((blkid_loff_t) cat_block * blocksize), 0x2000);
245 if (!buf)
246 return errno ? -errno : 0;
247
248 bnode = (struct hfsplus_bheader_record *)
249 &buf[sizeof(struct hfsplus_bnode_descriptor)];
250
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)
255 return 0;
256
257 leaf_block = (leaf_node_head * leaf_node_size) / blocksize;
258
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)
264 return 0;
265
266 /* this is our extent */
267 if (leaf_block < ext_block_count)
268 break;
269
270 leaf_block -= ext_block_count;
271 }
272 if (ext == HFSPLUS_EXTENT_COUNT)
273 return 0;
274
275 leaf_off = ((uint64_t) ext_block_start + leaf_block) * blocksize;
276
277 buf = blkid_probe_get_buffer(pr,
278 (blkid_loff_t) off + leaf_off,
279 leaf_node_size);
280 if (!buf)
281 return errno ? -errno : 0;
282
283 descr = (struct hfsplus_bnode_descriptor *) buf;
284 record_count = be16_to_cpu(descr->num_recs);
285 if (record_count == 0)
286 return 0;
287
288 if (descr->type != HFS_NODE_LEAF)
289 return 0;
290
291 key = (struct hfsplus_catalog_key *)
292 &buf[sizeof(struct hfsplus_bnode_descriptor)];
293
294 if (be32_to_cpu(key->parent_id) != HFSPLUS_POR_CNID)
295 return 0;
296
297 #if 0
298 blkid_probe_set_utf8label(pr, key->unicode,
299 be16_to_cpu(key->unicode_len) * 2,
300 BLKID_ENC_UTF16BE);
301 #endif
302
303 return 0;
304 }
305
306 const struct blkid_idinfo hfs_idinfo =
307 {
308 .name = "hfs",
309 .usage = BLKID_USAGE_FILESYSTEM,
310 .probefunc = probe_hfs,
311 .flags = BLKID_IDINFO_TOLERANT,
312 .magics =
313 {
314 { .magic = "BD", .len = 2, .kboff = 1 },
315 { NULL }
316 }
317 };
318
319 const struct blkid_idinfo hfsplus_idinfo =
320 {
321 .name = "hfsplus",
322 .usage = BLKID_USAGE_FILESYSTEM,
323 .probefunc = probe_hfsplus,
324 .magics =
325 {
326 { .magic = "BD", .len = 2, .kboff = 1 },
327 { .magic = "H+", .len = 2, .kboff = 1 },
328 { .magic = "HX", .len = 2, .kboff = 1 },
329 { NULL }
330 }
331 };