source: MondoRescue/branches/3.3/mindi-busybox/util-linux/volume_id/hfs.c@ 3625

Last change on this file since 3625 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 8.3 KB
Line 
1/*
2 * volume_id - reads filesystem label and uuid
3 *
4 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library 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 GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_HFS) += hfs.o
22
23//config:
24//config:config FEATURE_VOLUMEID_HFS
25//config: bool "hfs filesystem"
26//config: default y
27//config: depends on VOLUMEID
28//config: help
29//config: TODO
30//config:
31
32#include "volume_id_internal.h"
33
34struct hfs_finder_info{
35 uint32_t boot_folder;
36 uint32_t start_app;
37 uint32_t open_folder;
38 uint32_t os9_folder;
39 uint32_t reserved;
40 uint32_t osx_folder;
41 uint8_t id[8];
42} PACKED;
43
44struct hfs_mdb {
45 uint8_t signature[2];
46 uint32_t cr_date;
47 uint32_t ls_Mod;
48 uint16_t atrb;
49 uint16_t nm_fls;
50 uint16_t vbm_st;
51 uint16_t alloc_ptr;
52 uint16_t nm_al_blks;
53 uint32_t al_blk_size;
54 uint32_t clp_size;
55 uint16_t al_bl_st;
56 uint32_t nxt_cnid;
57 uint16_t free_bks;
58 uint8_t label_len;
59 uint8_t label[27];
60 uint32_t vol_bkup;
61 uint16_t vol_seq_num;
62 uint32_t wr_cnt;
63 uint32_t xt_clump_size;
64 uint32_t ct_clump_size;
65 uint16_t num_root_dirs;
66 uint32_t file_count;
67 uint32_t dir_count;
68 struct hfs_finder_info finder_info;
69 uint8_t embed_sig[2];
70 uint16_t embed_startblock;
71 uint16_t embed_blockcount;
72} PACKED;
73
74struct hfsplus_bnode_descriptor {
75 uint32_t next;
76 uint32_t prev;
77 uint8_t type;
78 uint8_t height;
79 uint16_t num_recs;
80 uint16_t reserved;
81} PACKED;
82
83struct hfsplus_bheader_record {
84 uint16_t depth;
85 uint32_t root;
86 uint32_t leaf_count;
87 uint32_t leaf_head;
88 uint32_t leaf_tail;
89 uint16_t node_size;
90} PACKED;
91
92struct hfsplus_catalog_key {
93 uint16_t key_len;
94 uint32_t parent_id;
95 uint16_t unicode_len;
96 uint8_t unicode[255 * 2];
97} PACKED;
98
99struct hfsplus_extent {
100 uint32_t start_block;
101 uint32_t block_count;
102} PACKED;
103
104#define HFSPLUS_EXTENT_COUNT 8
105struct hfsplus_fork {
106 uint64_t total_size;
107 uint32_t clump_size;
108 uint32_t total_blocks;
109 struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
110} PACKED;
111
112struct hfsplus_vol_header {
113 uint8_t signature[2];
114 uint16_t version;
115 uint32_t attributes;
116 uint32_t last_mount_vers;
117 uint32_t reserved;
118 uint32_t create_date;
119 uint32_t modify_date;
120 uint32_t backup_date;
121 uint32_t checked_date;
122 uint32_t file_count;
123 uint32_t folder_count;
124 uint32_t blocksize;
125 uint32_t total_blocks;
126 uint32_t free_blocks;
127 uint32_t next_alloc;
128 uint32_t rsrc_clump_sz;
129 uint32_t data_clump_sz;
130 uint32_t next_cnid;
131 uint32_t write_count;
132 uint64_t encodings_bmp;
133 struct hfs_finder_info finder_info;
134 struct hfsplus_fork alloc_file;
135 struct hfsplus_fork ext_file;
136 struct hfsplus_fork cat_file;
137 struct hfsplus_fork attr_file;
138 struct hfsplus_fork start_file;
139} PACKED;
140
141#define HFS_SUPERBLOCK_OFFSET 0x400
142#define HFS_NODE_LEAF 0xff
143#define HFSPLUS_POR_CNID 1
144
145static void FAST_FUNC hfs_set_uuid(struct volume_id *id, const uint8_t *hfs_id)
146{
147#define hfs_id_len 8
148 md5_ctx_t md5c;
149 uint8_t uuid[16];
150 unsigned i;
151
152 for (i = 0; i < hfs_id_len; i++)
153 if (hfs_id[i] != 0)
154 goto do_md5;
155 return;
156 do_md5:
157 md5_begin(&md5c);
158 md5_hash(&md5c, "\263\342\17\71\362\222\21\326\227\244\0\60\145\103\354\254", 16);
159 md5_hash(&md5c, hfs_id, hfs_id_len);
160 md5_end(&md5c, uuid);
161 uuid[6] = 0x30 | (uuid[6] & 0x0f);
162 uuid[8] = 0x80 | (uuid[8] & 0x3f);
163 volume_id_set_uuid(id, uuid, UUID_DCE);
164}
165
166int FAST_FUNC volume_id_probe_hfs_hfsplus(struct volume_id *id /*,uint64_t off*/)
167{
168 uint64_t off = 0;
169 unsigned blocksize;
170 unsigned cat_block;
171 unsigned ext_block_start;
172 unsigned ext_block_count;
173 int ext;
174 unsigned leaf_node_head;
175 unsigned leaf_node_count;
176 unsigned leaf_node_size;
177 unsigned leaf_block;
178 uint64_t leaf_off;
179 unsigned alloc_block_size;
180 unsigned alloc_first_block;
181 unsigned embed_first_block;
182 unsigned record_count;
183 struct hfsplus_vol_header *hfsplus;
184 struct hfsplus_bnode_descriptor *descr;
185 struct hfsplus_bheader_record *bnode;
186 struct hfsplus_catalog_key *key;
187 unsigned label_len;
188 struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
189 struct hfs_mdb *hfs;
190 const uint8_t *buf;
191
192 dbg("probing at offset 0x%llx", (unsigned long long) off);
193
194 buf = volume_id_get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
195 if (buf == NULL)
196 return -1;
197
198 hfs = (struct hfs_mdb *) buf;
199 if (hfs->signature[0] != 'B' || hfs->signature[1] != 'D')
200 goto checkplus;
201
202 /* it may be just a hfs wrapper for hfs+ */
203 if (hfs->embed_sig[0] == 'H' && hfs->embed_sig[1] == '+') {
204 alloc_block_size = be32_to_cpu(hfs->al_blk_size);
205 dbg("alloc_block_size 0x%x", alloc_block_size);
206
207 alloc_first_block = be16_to_cpu(hfs->al_bl_st);
208 dbg("alloc_first_block 0x%x", alloc_first_block);
209
210 embed_first_block = be16_to_cpu(hfs->embed_startblock);
211 dbg("embed_first_block 0x%x", embed_first_block);
212
213 off += (alloc_first_block * 512) +
214 (embed_first_block * alloc_block_size);
215 dbg("hfs wrapped hfs+ found at offset 0x%llx", (unsigned long long) off);
216
217 buf = volume_id_get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
218 if (buf == NULL)
219 return -1;
220 goto checkplus;
221 }
222
223 if (hfs->label_len > 0 && hfs->label_len < 28) {
224// volume_id_set_label_raw(id, hfs->label, hfs->label_len);
225 volume_id_set_label_string(id, hfs->label, hfs->label_len) ;
226 }
227
228 hfs_set_uuid(id, hfs->finder_info.id);
229// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
230 IF_FEATURE_BLKID_TYPE(id->type = "hfs";)
231
232 return 0;
233
234 checkplus:
235 hfsplus = (struct hfsplus_vol_header *) buf;
236 if (hfs->signature[0] == 'H')
237 if (hfs->signature[1] == '+' || hfs->signature[1] == 'X')
238 goto hfsplus;
239 return -1;
240
241 hfsplus:
242 hfs_set_uuid(id, hfsplus->finder_info.id);
243
244 blocksize = be32_to_cpu(hfsplus->blocksize);
245 dbg("blocksize %u", blocksize);
246
247 memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
248 cat_block = be32_to_cpu(extents[0].start_block);
249 dbg("catalog start block 0x%x", cat_block);
250
251 buf = volume_id_get_buffer(id, off + (cat_block * blocksize), 0x2000);
252 if (buf == NULL)
253 goto found;
254
255 bnode = (struct hfsplus_bheader_record *)
256 &buf[sizeof(struct hfsplus_bnode_descriptor)];
257
258 leaf_node_head = be32_to_cpu(bnode->leaf_head);
259 dbg("catalog leaf node 0x%x", leaf_node_head);
260
261 leaf_node_size = be16_to_cpu(bnode->node_size);
262 dbg("leaf node size 0x%x", leaf_node_size);
263
264 leaf_node_count = be32_to_cpu(bnode->leaf_count);
265 dbg("leaf node count 0x%x", leaf_node_count);
266 if (leaf_node_count == 0)
267 goto found;
268
269 leaf_block = (leaf_node_head * leaf_node_size) / blocksize;
270
271 /* get physical location */
272 for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) {
273 ext_block_start = be32_to_cpu(extents[ext].start_block);
274 ext_block_count = be32_to_cpu(extents[ext].block_count);
275 dbg("extent start block 0x%x, count 0x%x", ext_block_start, ext_block_count);
276
277 if (ext_block_count == 0)
278 goto found;
279
280 /* this is our extent */
281 if (leaf_block < ext_block_count)
282 break;
283
284 leaf_block -= ext_block_count;
285 }
286 if (ext == HFSPLUS_EXTENT_COUNT)
287 goto found;
288 dbg("found block in extent %i", ext);
289
290 leaf_off = (ext_block_start + leaf_block) * blocksize;
291
292 buf = volume_id_get_buffer(id, off + leaf_off, leaf_node_size);
293 if (buf == NULL)
294 goto found;
295
296 descr = (struct hfsplus_bnode_descriptor *) buf;
297 dbg("descriptor type 0x%x", descr->type);
298
299 record_count = be16_to_cpu(descr->num_recs);
300 dbg("number of records %u", record_count);
301 if (record_count == 0)
302 goto found;
303
304 if (descr->type != HFS_NODE_LEAF)
305 goto found;
306
307 key = (struct hfsplus_catalog_key *)
308 &buf[sizeof(struct hfsplus_bnode_descriptor)];
309
310 dbg("parent id 0x%x", be32_to_cpu(key->parent_id));
311 if (key->parent_id != cpu_to_be32(HFSPLUS_POR_CNID))
312 goto found;
313
314 label_len = be16_to_cpu(key->unicode_len) * 2;
315 dbg("label unicode16 len %i", label_len);
316// volume_id_set_label_raw(id, key->unicode, label_len);
317 volume_id_set_label_unicode16(id, key->unicode, BE, label_len);
318
319 found:
320// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
321 IF_FEATURE_BLKID_TYPE(id->type = "hfsplus";)
322
323 return 0;
324}
Note: See TracBrowser for help on using the repository browser.