libhfs.c revision 1.12 1 1.12 matt /* $NetBSD: libhfs.c,v 1.12 2012/07/28 00:43:23 matt Exp $ */
2 1.1 dillo
3 1.1 dillo /*-
4 1.1 dillo * Copyright (c) 2005, 2007 The NetBSD Foundation, Inc.
5 1.1 dillo * All rights reserved.
6 1.1 dillo *
7 1.1 dillo * This code is derived from software contributed to The NetBSD Foundation
8 1.4 dillo * by Yevgeny Binder, Dieter Baron, and Pelle Johansson.
9 1.1 dillo *
10 1.1 dillo * Redistribution and use in source and binary forms, with or without
11 1.1 dillo * modification, are permitted provided that the following conditions
12 1.1 dillo * are met:
13 1.1 dillo * 1. Redistributions of source code must retain the above copyright
14 1.1 dillo * notice, this list of conditions and the following disclaimer.
15 1.1 dillo * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 dillo * notice, this list of conditions and the following disclaimer in the
17 1.1 dillo * documentation and/or other materials provided with the distribution.
18 1.1 dillo *
19 1.1 dillo * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 dillo * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 dillo * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 dillo * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 dillo * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 dillo * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 dillo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 dillo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 dillo * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 dillo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 dillo * POSSIBILITY OF SUCH DAMAGE.
30 1.1 dillo */
31 1.1 dillo
32 1.1 dillo /*
33 1.2 dillo * All functions and variable types have the prefix "hfs_". All constants
34 1.2 dillo * have the prefix "HFS_".
35 1.1 dillo *
36 1.1 dillo * Naming convention for functions which read/write raw, linear data
37 1.1 dillo * into/from a structured form:
38 1.1 dillo *
39 1.2 dillo * hfs_read/write[d][a]_foo_bar
40 1.1 dillo * [d] - read/write from/to [d]isk instead of a memory buffer
41 1.1 dillo * [a] - [a]llocate output buffer instead of using an existing one
42 1.1 dillo * (not applicable for writing functions)
43 1.1 dillo *
44 1.1 dillo * Most functions do not have either of these options, so they will read from
45 1.1 dillo * or write to a memory buffer, which has been previously allocated by the
46 1.1 dillo * caller.
47 1.1 dillo */
48 1.1 dillo
49 1.5 lukem #include <sys/cdefs.h>
50 1.12 matt __KERNEL_RCSID(0, "$NetBSD: libhfs.c,v 1.12 2012/07/28 00:43:23 matt Exp $");
51 1.5 lukem
52 1.2 dillo #include "libhfs.h"
53 1.1 dillo
54 1.1 dillo /* global private file/folder keys */
55 1.2 dillo hfs_catalog_key_t hfs_gMetadataDirectoryKey; /* contains HFS+ inodes */
56 1.2 dillo hfs_catalog_key_t hfs_gJournalInfoBlockFileKey;
57 1.2 dillo hfs_catalog_key_t hfs_gJournalBufferFileKey;
58 1.2 dillo hfs_catalog_key_t* hfs_gPrivateObjectKeys[4] = {
59 1.2 dillo &hfs_gMetadataDirectoryKey,
60 1.2 dillo &hfs_gJournalInfoBlockFileKey,
61 1.2 dillo &hfs_gJournalBufferFileKey,
62 1.1 dillo NULL};
63 1.1 dillo
64 1.1 dillo
65 1.1 dillo extern uint16_t be16tohp(void** inout_ptr);
66 1.1 dillo extern uint32_t be32tohp(void** inout_ptr);
67 1.1 dillo extern uint64_t be64tohp(void** inout_ptr);
68 1.1 dillo
69 1.12 matt hfs_callbacks hfs_gcb; /* global callbacks */
70 1.12 matt
71 1.12 matt /*
72 1.12 matt * global case folding table
73 1.12 matt * (lazily initialized; see comments at bottom of hfs_open_volume())
74 1.12 matt */
75 1.12 matt unichar_t* hfs_gcft;
76 1.12 matt
77 1.12 matt
78 1.2 dillo int hfslib_create_casefolding_table(void);
79 1.1 dillo
80 1.1 dillo #ifdef DLO_DEBUG
81 1.1 dillo #include <stdio.h>
82 1.1 dillo void
83 1.2 dillo dlo_print_key(hfs_catalog_key_t *key)
84 1.1 dillo {
85 1.1 dillo int i;
86 1.1 dillo
87 1.1 dillo printf("%ld:[", (long)key->parent_cnid);
88 1.1 dillo for (i=0; i<key->name.length; i++) {
89 1.1 dillo if (key->name.unicode[i] < 256
90 1.1 dillo && isprint(key->name.unicode[i]))
91 1.1 dillo putchar(key->name.unicode[i]);
92 1.1 dillo else
93 1.1 dillo printf("<%04x>", key->name.unicode[i]);
94 1.1 dillo }
95 1.1 dillo printf("]");
96 1.1 dillo }
97 1.1 dillo #endif
98 1.1 dillo
99 1.1 dillo void
100 1.2 dillo hfslib_init(hfs_callbacks* in_callbacks)
101 1.1 dillo {
102 1.1 dillo unichar_t temp[256];
103 1.1 dillo
104 1.1 dillo if(in_callbacks!=NULL)
105 1.2 dillo memcpy(&hfs_gcb, in_callbacks, sizeof(hfs_callbacks));
106 1.1 dillo
107 1.2 dillo hfs_gcft = NULL;
108 1.1 dillo
109 1.1 dillo /*
110 1.1 dillo * Create keys for the HFS+ "private" files so we can reuse them whenever
111 1.1 dillo * we perform a user-visible operation, such as listing directory contents.
112 1.1 dillo */
113 1.1 dillo
114 1.1 dillo #define ATOU(str, len) /* quick & dirty ascii-to-unicode conversion */ \
115 1.1 dillo do{ int i; for(i=0; i<len; i++) temp[i]=str[i]; } \
116 1.1 dillo while( /*CONSTCOND*/ 0)
117 1.1 dillo
118 1.1 dillo ATOU("\0\0\0\0HFS+ Private Data", 21);
119 1.2 dillo hfslib_make_catalog_key(HFS_CNID_ROOT_FOLDER, 21, temp,
120 1.2 dillo &hfs_gMetadataDirectoryKey);
121 1.1 dillo
122 1.1 dillo ATOU(".journal_info_block", 19);
123 1.2 dillo hfslib_make_catalog_key(HFS_CNID_ROOT_FOLDER, 19, temp,
124 1.2 dillo &hfs_gJournalInfoBlockFileKey);
125 1.1 dillo
126 1.1 dillo ATOU(".journal", 8);
127 1.2 dillo hfslib_make_catalog_key(HFS_CNID_ROOT_FOLDER, 8, temp,
128 1.2 dillo &hfs_gJournalBufferFileKey);
129 1.1 dillo
130 1.1 dillo #undef ATOU
131 1.1 dillo }
132 1.1 dillo
133 1.1 dillo void
134 1.2 dillo hfslib_done(void)
135 1.1 dillo {
136 1.2 dillo hfs_callback_args cbargs;
137 1.1 dillo
138 1.2 dillo if(hfs_gcft!=NULL) {
139 1.2 dillo hfslib_init_cbargs(&cbargs);
140 1.2 dillo hfslib_free(hfs_gcft, &cbargs);
141 1.2 dillo hfs_gcft = NULL;
142 1.1 dillo }
143 1.1 dillo
144 1.1 dillo return;
145 1.1 dillo }
146 1.1 dillo
147 1.1 dillo void
148 1.2 dillo hfslib_init_cbargs(hfs_callback_args* ptr)
149 1.1 dillo {
150 1.2 dillo memset(ptr, 0, sizeof(hfs_callback_args));
151 1.1 dillo }
152 1.1 dillo
153 1.1 dillo #if 0
154 1.1 dillo #pragma mark -
155 1.1 dillo #pragma mark High-Level Routines
156 1.1 dillo #endif
157 1.1 dillo
158 1.1 dillo int
159 1.2 dillo hfslib_open_volume(
160 1.1 dillo const char* in_device,
161 1.1 dillo int in_readonly,
162 1.2 dillo hfs_volume* out_vol,
163 1.2 dillo hfs_callback_args* cbargs)
164 1.1 dillo {
165 1.2 dillo hfs_catalog_key_t rootkey;
166 1.2 dillo hfs_thread_record_t rootthread;
167 1.4 dillo hfs_hfs_master_directory_block_t mdb;
168 1.3 dillo uint16_t node_rec_sizes[1];
169 1.3 dillo void* node_recs[1];
170 1.1 dillo void* buffer;
171 1.1 dillo void* buffer2; /* used as temporary pointer for realloc() */
172 1.1 dillo int result;
173 1.6 pooka int isopen = 0;
174 1.1 dillo
175 1.1 dillo result = 1;
176 1.1 dillo buffer = NULL;
177 1.1 dillo
178 1.1 dillo if(in_device==NULL || out_vol==NULL)
179 1.1 dillo return 1;
180 1.1 dillo
181 1.1 dillo out_vol->readonly = in_readonly;
182 1.4 dillo out_vol->offset = 0;
183 1.4 dillo
184 1.4 dillo if(hfslib_openvoldevice(out_vol, in_device, cbargs) != 0)
185 1.2 dillo HFS_LIBERR("could not open device");
186 1.6 pooka isopen = 1;
187 1.1 dillo
188 1.1 dillo /*
189 1.1 dillo * Read the volume header.
190 1.1 dillo */
191 1.4 dillo buffer = hfslib_malloc(max(sizeof(hfs_volume_header_t),
192 1.4 dillo sizeof(hfs_hfs_master_directory_block_t)), cbargs);
193 1.1 dillo if(buffer==NULL)
194 1.2 dillo HFS_LIBERR("could not allocate volume header");
195 1.4 dillo if(hfslib_readd(out_vol, buffer, max(sizeof(hfs_volume_header_t),
196 1.4 dillo sizeof(hfs_hfs_master_directory_block_t)),
197 1.4 dillo HFS_VOLUME_HEAD_RESERVE_SIZE, cbargs)!=0)
198 1.2 dillo HFS_LIBERR("could not read volume header");
199 1.4 dillo
200 1.4 dillo if (be16toh(*((uint16_t *)buffer)) == HFS_SIG_HFS) {
201 1.4 dillo if (hfslib_read_master_directory_block(buffer, &mdb) == 0)
202 1.4 dillo HFS_LIBERR("could not parse master directory block");
203 1.4 dillo if (mdb.embedded_signature == HFS_SIG_HFSP)
204 1.4 dillo {
205 1.4 dillo /* XXX: is 512 always correct? */
206 1.4 dillo out_vol->offset =
207 1.4 dillo mdb.first_block * 512
208 1.4 dillo + mdb.embedded_extent.start_block
209 1.4 dillo * (uint64_t)mdb.block_size;
210 1.4 dillo
211 1.4 dillo if(hfslib_readd(out_vol, buffer,
212 1.4 dillo sizeof(hfs_volume_header_t),
213 1.4 dillo HFS_VOLUME_HEAD_RESERVE_SIZE, cbargs)!=0)
214 1.4 dillo HFS_LIBERR("could not read volume header");
215 1.4 dillo }
216 1.4 dillo else
217 1.4 dillo HFS_LIBERR("Plain HFS volumes not currently supported");
218 1.4 dillo }
219 1.4 dillo
220 1.2 dillo if(hfslib_read_volume_header(buffer, &(out_vol->vh))==0)
221 1.2 dillo HFS_LIBERR("could not parse volume header");
222 1.1 dillo
223 1.1 dillo /*
224 1.1 dillo * Check the volume signature to see if this is a legitimate HFS+ or HFSX
225 1.1 dillo * volume. If so, set the key comparison function pointers appropriately.
226 1.1 dillo */
227 1.1 dillo switch(out_vol->vh.signature)
228 1.1 dillo {
229 1.2 dillo case HFS_SIG_HFSP:
230 1.2 dillo out_vol->keycmp = hfslib_compare_catalog_keys_cf;
231 1.1 dillo break;
232 1.1 dillo
233 1.2 dillo case HFS_SIG_HFSX:
234 1.1 dillo out_vol->keycmp = NULL; /* will be set below */
235 1.1 dillo break;
236 1.1 dillo
237 1.1 dillo default:
238 1.9 pooka /* HFS_LIBERR("unrecognized volume format"); */
239 1.9 pooka goto error;
240 1.9 pooka break;
241 1.1 dillo }
242 1.1 dillo
243 1.1 dillo
244 1.1 dillo /*
245 1.1 dillo * Read the catalog header.
246 1.1 dillo */
247 1.3 dillo buffer2 = hfslib_realloc(buffer, 512, cbargs);
248 1.1 dillo if(buffer2==NULL)
249 1.2 dillo HFS_LIBERR("could not allocate catalog header node");
250 1.1 dillo buffer = buffer2;
251 1.1 dillo
252 1.3 dillo /*
253 1.3 dillo We are only interested in the node header, so read the first
254 1.3 dillo 512 bytes and construct the node descriptor by hand.
255 1.3 dillo */
256 1.3 dillo if(hfslib_readd(out_vol, buffer, 512,
257 1.3 dillo out_vol->vh.catalog_file.extents[0].start_block
258 1.3 dillo *(uint64_t)out_vol->vh.block_size,
259 1.1 dillo cbargs) != 0)
260 1.2 dillo HFS_LIBERR("could not read catalog header node");
261 1.3 dillo node_recs[0] = (char *)buffer+14;
262 1.3 dillo node_rec_sizes[0] = 120;
263 1.3 dillo if(hfslib_read_header_node(node_recs, node_rec_sizes, 1,
264 1.1 dillo &out_vol->chr, NULL, NULL)==0)
265 1.2 dillo HFS_LIBERR("could not parse catalog header node");
266 1.1 dillo
267 1.1 dillo /* If this is an HFSX volume, the catalog header specifies the type of
268 1.1 dillo * key comparison method (case-folding or binary compare) we should use. */
269 1.1 dillo if(out_vol->keycmp == NULL)
270 1.1 dillo {
271 1.2 dillo if(out_vol->chr.keycomp_type == HFS_KEY_CASEFOLD)
272 1.2 dillo out_vol->keycmp = hfslib_compare_catalog_keys_cf;
273 1.2 dillo else if(out_vol->chr.keycomp_type == HFS_KEY_BINARY)
274 1.2 dillo out_vol->keycmp = hfslib_compare_catalog_keys_bc;
275 1.1 dillo else
276 1.2 dillo HFS_LIBERR("undefined key compare method");
277 1.1 dillo }
278 1.3 dillo
279 1.3 dillo out_vol->catkeysizefieldsize
280 1.3 dillo = (out_vol->chr.attributes & HFS_BIG_KEYS_MASK) ?
281 1.3 dillo sizeof(uint16_t) : sizeof(uint8_t);
282 1.3 dillo
283 1.1 dillo /*
284 1.1 dillo * Read the extent overflow header.
285 1.1 dillo */
286 1.3 dillo /*
287 1.3 dillo We are only interested in the node header, so read the first
288 1.3 dillo 512 bytes and construct the node descriptor by hand.
289 1.3 dillo buffer is already 512 bytes long.
290 1.3 dillo */
291 1.3 dillo if(hfslib_readd(out_vol, buffer, 512,
292 1.3 dillo out_vol->vh.extents_file.extents[0].start_block
293 1.3 dillo *(uint64_t)out_vol->vh.block_size,
294 1.1 dillo cbargs) != 0)
295 1.2 dillo HFS_LIBERR("could not read extent header node");
296 1.1 dillo
297 1.3 dillo node_recs[0] = (char *)buffer+14;
298 1.3 dillo node_rec_sizes[0] = 120;
299 1.3 dillo if(hfslib_read_header_node(node_recs, node_rec_sizes, 1,
300 1.1 dillo &out_vol->ehr, NULL, NULL)==0)
301 1.2 dillo HFS_LIBERR("could not parse extent header node");
302 1.3 dillo out_vol->extkeysizefieldsize
303 1.3 dillo = (out_vol->ehr.attributes & HFS_BIG_KEYS_MASK) ?
304 1.3 dillo sizeof(uint16_t):sizeof(uint8_t);
305 1.1 dillo /*
306 1.1 dillo * Read the journal info block and journal header (if volume journaled).
307 1.1 dillo */
308 1.2 dillo if(out_vol->vh.attributes & (1<<HFS_VOL_JOURNALED))
309 1.1 dillo {
310 1.1 dillo /* journal info block */
311 1.2 dillo buffer2 = hfslib_realloc(buffer, sizeof(hfs_journal_info_t), cbargs);
312 1.1 dillo if(buffer2==NULL)
313 1.2 dillo HFS_LIBERR("could not allocate journal info block");
314 1.1 dillo buffer = buffer2;
315 1.1 dillo
316 1.2 dillo if(hfslib_readd(out_vol, buffer, sizeof(hfs_journal_info_t),
317 1.1 dillo out_vol->vh.journal_info_block * out_vol->vh.block_size,
318 1.1 dillo cbargs) != 0)
319 1.2 dillo HFS_LIBERR("could not read journal info block");
320 1.1 dillo
321 1.2 dillo if(hfslib_read_journal_info(buffer, &out_vol->jib)==0)
322 1.2 dillo HFS_LIBERR("could not parse journal info block");
323 1.1 dillo
324 1.1 dillo /* journal header */
325 1.2 dillo buffer2 = hfslib_realloc(buffer, sizeof(hfs_journal_header_t),cbargs);
326 1.1 dillo if(buffer2==NULL)
327 1.2 dillo HFS_LIBERR("could not allocate journal header");
328 1.1 dillo buffer = buffer2;
329 1.1 dillo
330 1.2 dillo if(hfslib_readd(out_vol, buffer, sizeof(hfs_journal_header_t),
331 1.1 dillo out_vol->jib.offset, cbargs) != 0)
332 1.2 dillo HFS_LIBERR("could not read journal header");
333 1.1 dillo
334 1.2 dillo if(hfslib_read_journal_header(buffer, &out_vol->jh)==0)
335 1.2 dillo HFS_LIBERR("could not parse journal header");
336 1.1 dillo
337 1.1 dillo out_vol->journaled = 1;
338 1.1 dillo }
339 1.1 dillo else
340 1.1 dillo {
341 1.1 dillo out_vol->journaled = 0;
342 1.1 dillo }
343 1.1 dillo
344 1.1 dillo /*
345 1.1 dillo * If this volume uses case-folding comparison and the folding table hasn't
346 1.2 dillo * been created yet, do that here. (We don't do this in hfslib_init()
347 1.1 dillo * because the table is large and we might never even need to use it.)
348 1.1 dillo */
349 1.2 dillo if(out_vol->keycmp==hfslib_compare_catalog_keys_cf && hfs_gcft==NULL)
350 1.2 dillo result = hfslib_create_casefolding_table();
351 1.1 dillo else
352 1.1 dillo result = 0;
353 1.1 dillo
354 1.1 dillo /*
355 1.1 dillo * Find and store the volume name.
356 1.1 dillo */
357 1.2 dillo if(hfslib_make_catalog_key(HFS_CNID_ROOT_FOLDER, 0, NULL, &rootkey)==0)
358 1.2 dillo HFS_LIBERR("could not make root search key");
359 1.1 dillo
360 1.2 dillo if(hfslib_find_catalog_record_with_key(out_vol, &rootkey,
361 1.2 dillo (hfs_catalog_keyed_record_t*)&rootthread, cbargs)!=0)
362 1.2 dillo HFS_LIBERR("could not find root parent");
363 1.1 dillo
364 1.2 dillo memcpy(&out_vol->name, &rootthread.name, sizeof(hfs_unistr255_t));
365 1.1 dillo
366 1.1 dillo
367 1.1 dillo /* FALLTHROUGH */
368 1.1 dillo error:
369 1.7 pooka if (result != 0 && isopen)
370 1.6 pooka hfslib_close_volume(out_vol, cbargs);
371 1.1 dillo if(buffer!=NULL)
372 1.2 dillo hfslib_free(buffer, cbargs);
373 1.1 dillo
374 1.1 dillo return result;
375 1.1 dillo }
376 1.1 dillo
377 1.1 dillo void
378 1.2 dillo hfslib_close_volume(hfs_volume* in_vol, hfs_callback_args* cbargs)
379 1.1 dillo {
380 1.1 dillo if(in_vol==NULL)
381 1.1 dillo return;
382 1.1 dillo
383 1.2 dillo hfslib_closevoldevice(in_vol, cbargs);
384 1.1 dillo }
385 1.1 dillo
386 1.1 dillo int
387 1.2 dillo hfslib_path_to_cnid(hfs_volume* in_vol,
388 1.2 dillo hfs_cnid_t in_cnid,
389 1.1 dillo char** out_unicode,
390 1.1 dillo uint16_t* out_length,
391 1.2 dillo hfs_callback_args* cbargs)
392 1.1 dillo {
393 1.2 dillo hfs_thread_record_t parent_thread;
394 1.2 dillo hfs_cnid_t parent_cnid, child_cnid;
395 1.1 dillo char* newpath;
396 1.1 dillo char* path;
397 1.1 dillo int path_offset = 0;
398 1.1 dillo int result;
399 1.1 dillo uint16_t* ptr; /* dummy var */
400 1.1 dillo uint16_t uchar; /* dummy var */
401 1.1 dillo uint16_t total_path_length;
402 1.1 dillo
403 1.1 dillo if(in_vol==NULL || in_cnid==0 || out_unicode==NULL || out_length==NULL)
404 1.1 dillo return 1;
405 1.1 dillo
406 1.1 dillo result = 1;
407 1.1 dillo *out_unicode = NULL;
408 1.1 dillo *out_length = 0;
409 1.1 dillo path = NULL;
410 1.1 dillo total_path_length = 0;
411 1.1 dillo
412 1.2 dillo path = hfslib_malloc(514, cbargs); /* 256 unichars plus a forward slash */
413 1.1 dillo if(path==NULL)
414 1.1 dillo return 1;
415 1.1 dillo
416 1.1 dillo child_cnid = in_cnid;
417 1.1 dillo parent_cnid = child_cnid; /* skips loop in case in_cnid is root id */
418 1.2 dillo while(parent_cnid != HFS_CNID_ROOT_FOLDER
419 1.2 dillo && parent_cnid != HFS_CNID_ROOT_PARENT)
420 1.1 dillo {
421 1.1 dillo if(child_cnid!=in_cnid)
422 1.1 dillo {
423 1.2 dillo newpath = hfslib_realloc(path, 514 + total_path_length*2, cbargs);
424 1.1 dillo
425 1.1 dillo if(newpath==NULL)
426 1.1 dillo goto exit;
427 1.1 dillo path = newpath;
428 1.1 dillo
429 1.1 dillo memmove(path + 514, path + path_offset, total_path_length*2);
430 1.1 dillo }
431 1.1 dillo
432 1.2 dillo parent_cnid = hfslib_find_parent_thread(in_vol, child_cnid,
433 1.1 dillo &parent_thread, cbargs);
434 1.1 dillo if(parent_cnid==0)
435 1.1 dillo goto exit;
436 1.1 dillo
437 1.1 dillo path_offset = 512 - parent_thread.name.length*2;
438 1.1 dillo
439 1.1 dillo memcpy(path + path_offset, parent_thread.name.unicode,
440 1.1 dillo parent_thread.name.length*2);
441 1.1 dillo
442 1.1 dillo /* Add a forward slash. The unicode string was specified in big endian
443 1.1 dillo * format, so convert to core format if necessary. */
444 1.1 dillo path[512]=0x00;
445 1.1 dillo path[513]=0x2F;
446 1.1 dillo
447 1.1 dillo ptr = (uint16_t*)path + 256;
448 1.1 dillo uchar = be16tohp((void*)&ptr);
449 1.1 dillo *(ptr-1) = uchar;
450 1.1 dillo
451 1.1 dillo total_path_length += parent_thread.name.length + 1;
452 1.1 dillo
453 1.1 dillo child_cnid = parent_cnid;
454 1.1 dillo }
455 1.1 dillo
456 1.1 dillo /*
457 1.1 dillo * At this point, 'path' holds a sequence of unicode characters which
458 1.1 dillo * represent the absolute path to the given cnid. This string is missing
459 1.1 dillo * a terminating null char and an initial forward slash that represents
460 1.1 dillo * the root of the filesystem. It most likely also has extra space in
461 1.1 dillo * the beginning, due to the fact that we reserve 512 bytes for each path
462 1.1 dillo * component and won't usually use all that space. So, we allocate the
463 1.1 dillo * final string based on the actual length of the absolute path, plus four
464 1.1 dillo * additional bytes (two unichars) for the forward slash and the null char.
465 1.1 dillo */
466 1.1 dillo
467 1.2 dillo *out_unicode = hfslib_malloc((total_path_length+2)*2, cbargs);
468 1.1 dillo if(*out_unicode == NULL)
469 1.1 dillo goto exit;
470 1.1 dillo
471 1.1 dillo /* copy only the bytes that are actually used */
472 1.10 christos memcpy(*out_unicode + 2, path + path_offset, total_path_length*2);
473 1.1 dillo
474 1.1 dillo /* insert forward slash at start */
475 1.10 christos uchar = be16toh(0x2F);
476 1.10 christos memcpy(*out_unicode, &uchar, sizeof(uchar));
477 1.1 dillo
478 1.1 dillo /* insert null char at end */
479 1.1 dillo (*out_unicode)[total_path_length*2+2] = 0x00;
480 1.1 dillo (*out_unicode)[total_path_length*2+3] = 0x00;
481 1.1 dillo
482 1.1 dillo *out_length = total_path_length + 1 /* extra for forward slash */ ;
483 1.1 dillo
484 1.1 dillo result = 0;
485 1.1 dillo
486 1.1 dillo exit:
487 1.1 dillo if(path!=NULL)
488 1.2 dillo hfslib_free(path, cbargs);
489 1.1 dillo
490 1.1 dillo return result;
491 1.1 dillo }
492 1.1 dillo
493 1.2 dillo hfs_cnid_t
494 1.2 dillo hfslib_find_parent_thread(
495 1.2 dillo hfs_volume* in_vol,
496 1.2 dillo hfs_cnid_t in_child,
497 1.2 dillo hfs_thread_record_t* out_thread,
498 1.2 dillo hfs_callback_args* cbargs)
499 1.1 dillo {
500 1.2 dillo hfs_catalog_key_t childkey;
501 1.1 dillo
502 1.1 dillo if(in_vol==NULL || in_child==0 || out_thread==NULL)
503 1.1 dillo return 0;
504 1.1 dillo
505 1.2 dillo if(hfslib_make_catalog_key(in_child, 0, NULL, &childkey)==0)
506 1.1 dillo return 0;
507 1.1 dillo
508 1.2 dillo if(hfslib_find_catalog_record_with_key(in_vol, &childkey,
509 1.2 dillo (hfs_catalog_keyed_record_t*)out_thread, cbargs)!=0)
510 1.1 dillo return 0;
511 1.1 dillo
512 1.1 dillo return out_thread->parent_cnid;
513 1.1 dillo }
514 1.1 dillo
515 1.1 dillo /*
516 1.2 dillo * hfslib_find_catalog_record_with_cnid()
517 1.1 dillo *
518 1.2 dillo * Looks up a catalog record by calling hfslib_find_parent_thread() and
519 1.2 dillo * hfslib_find_catalog_record_with_key(). out_key may be NULL; if not, the key
520 1.1 dillo * corresponding to this cnid is stuffed in it. Returns 0 on success.
521 1.1 dillo */
522 1.1 dillo int
523 1.2 dillo hfslib_find_catalog_record_with_cnid(
524 1.2 dillo hfs_volume* in_vol,
525 1.2 dillo hfs_cnid_t in_cnid,
526 1.2 dillo hfs_catalog_keyed_record_t* out_rec,
527 1.2 dillo hfs_catalog_key_t* out_key,
528 1.2 dillo hfs_callback_args* cbargs)
529 1.2 dillo {
530 1.2 dillo hfs_cnid_t parentcnid;
531 1.2 dillo hfs_thread_record_t parentthread;
532 1.2 dillo hfs_catalog_key_t key;
533 1.1 dillo
534 1.1 dillo if(in_vol==NULL || in_cnid==0 || out_rec==NULL)
535 1.1 dillo return 0;
536 1.1 dillo
537 1.1 dillo parentcnid =
538 1.2 dillo hfslib_find_parent_thread(in_vol, in_cnid, &parentthread, cbargs);
539 1.1 dillo if(parentcnid == 0)
540 1.2 dillo HFS_LIBERR("could not find parent thread for cnid %i", in_cnid);
541 1.1 dillo
542 1.2 dillo if(hfslib_make_catalog_key(parentthread.parent_cnid,
543 1.1 dillo parentthread.name.length, parentthread.name.unicode, &key) == 0)
544 1.2 dillo HFS_LIBERR("could not make catalog search key");
545 1.1 dillo
546 1.1 dillo if(out_key!=NULL)
547 1.1 dillo memcpy(out_key, &key, sizeof(key));
548 1.1 dillo
549 1.2 dillo return hfslib_find_catalog_record_with_key(in_vol, &key, out_rec, cbargs);
550 1.1 dillo
551 1.1 dillo error:
552 1.1 dillo return 1;
553 1.1 dillo }
554 1.1 dillo
555 1.1 dillo /* Returns 0 on success, 1 on error, and -1 if record was not found. */
556 1.1 dillo int
557 1.2 dillo hfslib_find_catalog_record_with_key(
558 1.2 dillo hfs_volume* in_vol,
559 1.2 dillo hfs_catalog_key_t* in_key,
560 1.2 dillo hfs_catalog_keyed_record_t* out_rec,
561 1.2 dillo hfs_callback_args* cbargs)
562 1.2 dillo {
563 1.2 dillo hfs_node_descriptor_t nd;
564 1.2 dillo hfs_extent_descriptor_t* extents;
565 1.2 dillo hfs_catalog_keyed_record_t lastrec;
566 1.2 dillo hfs_catalog_key_t* curkey;
567 1.1 dillo void** recs;
568 1.1 dillo void* buffer;
569 1.1 dillo uint64_t bytesread;
570 1.1 dillo uint32_t curnode;
571 1.1 dillo uint16_t* recsizes;
572 1.1 dillo uint16_t numextents;
573 1.1 dillo uint16_t recnum;
574 1.1 dillo int16_t leaftype;
575 1.1 dillo int keycompare;
576 1.1 dillo int result;
577 1.1 dillo
578 1.1 dillo if(in_key==NULL || out_rec==NULL || in_vol==NULL)
579 1.1 dillo return 1;
580 1.1 dillo
581 1.1 dillo result = 1;
582 1.1 dillo buffer = NULL;
583 1.1 dillo curkey = NULL;
584 1.1 dillo extents = NULL;
585 1.1 dillo recs = NULL;
586 1.1 dillo recsizes = NULL;
587 1.1 dillo
588 1.1 dillo /* The key takes up over half a kb of ram, which is a lot for the BSD
589 1.1 dillo * kernel stack. So allocate it in the heap instead to play it safe. */
590 1.2 dillo curkey = hfslib_malloc(sizeof(hfs_catalog_key_t), cbargs);
591 1.1 dillo if(curkey==NULL)
592 1.2 dillo HFS_LIBERR("could not allocate catalog search key");
593 1.1 dillo
594 1.2 dillo buffer = hfslib_malloc(in_vol->chr.node_size, cbargs);
595 1.1 dillo if(buffer==NULL)
596 1.2 dillo HFS_LIBERR("could not allocate node buffer");
597 1.1 dillo
598 1.2 dillo numextents = hfslib_get_file_extents(in_vol, HFS_CNID_CATALOG,
599 1.2 dillo HFS_DATAFORK, &extents, cbargs);
600 1.1 dillo if(numextents==0)
601 1.2 dillo HFS_LIBERR("could not locate fork extents");
602 1.1 dillo
603 1.1 dillo nd.num_recs = 0;
604 1.1 dillo curnode = in_vol->chr.root_node;
605 1.1 dillo
606 1.1 dillo #ifdef DLO_DEBUG
607 1.1 dillo printf("-> key ");
608 1.1 dillo dlo_print_key(in_key);
609 1.1 dillo printf("\n");
610 1.1 dillo #endif
611 1.1 dillo
612 1.1 dillo do
613 1.1 dillo {
614 1.1 dillo #ifdef DLO_DEBUG
615 1.1 dillo printf("--> node %d\n", curnode);
616 1.1 dillo #endif
617 1.1 dillo
618 1.2 dillo if(hfslib_readd_with_extents(in_vol, buffer,
619 1.1 dillo &bytesread,in_vol->chr.node_size, curnode * in_vol->chr.node_size,
620 1.1 dillo extents, numextents, cbargs)!=0)
621 1.2 dillo HFS_LIBERR("could not read catalog node #%i", curnode);
622 1.1 dillo
623 1.2 dillo if(hfslib_reada_node(buffer, &nd, &recs, &recsizes, HFS_CATALOG_FILE,
624 1.1 dillo in_vol, cbargs)==0)
625 1.2 dillo HFS_LIBERR("could not parse catalog node #%i", curnode);
626 1.1 dillo
627 1.1 dillo for(recnum=0; recnum<nd.num_recs; recnum++)
628 1.1 dillo {
629 1.1 dillo leaftype = nd.kind;
630 1.2 dillo if(hfslib_read_catalog_keyed_record(recs[recnum], out_rec,
631 1.1 dillo &leaftype, curkey, in_vol)==0)
632 1.2 dillo HFS_LIBERR("could not read catalog record #%i",recnum);
633 1.1 dillo
634 1.1 dillo #ifdef DLO_DEBUG
635 1.1 dillo printf("---> record %d: ", recnum);
636 1.1 dillo dlo_print_key(curkey);
637 1.1 dillo fflush(stdout);
638 1.1 dillo #endif
639 1.1 dillo keycompare = in_vol->keycmp(in_key, curkey);
640 1.1 dillo #ifdef DLO_DEBUG
641 1.1 dillo printf(" %c\n",
642 1.1 dillo keycompare < 0 ? '<'
643 1.1 dillo : keycompare == 0 ? '=' : '>');
644 1.1 dillo #endif
645 1.1 dillo
646 1.1 dillo if(keycompare < 0)
647 1.1 dillo {
648 1.1 dillo /* Check if key is less than *every* record, which should never
649 1.1 dillo * happen if the volume is consistent and the key legit. */
650 1.1 dillo if(recnum==0)
651 1.2 dillo HFS_LIBERR("all records greater than key");
652 1.1 dillo
653 1.1 dillo /* Otherwise, we've found the first record that exceeds our key,
654 1.1 dillo * so retrieve the previous record, which is still less... */
655 1.1 dillo memcpy(out_rec, &lastrec,
656 1.2 dillo sizeof(hfs_catalog_keyed_record_t));
657 1.1 dillo
658 1.1 dillo /* ...unless this is a leaf node, which means we've gone from
659 1.1 dillo * a key which is smaller than the search key, in the previous
660 1.1 dillo * loop, to a key which is larger, in this loop, and that
661 1.1 dillo * implies that our search key does not exist on the volume. */
662 1.2 dillo if(nd.kind==HFS_LEAFNODE)
663 1.1 dillo result = -1;
664 1.1 dillo
665 1.1 dillo break;
666 1.1 dillo }
667 1.1 dillo else if(keycompare == 0)
668 1.1 dillo {
669 1.1 dillo /* If leaf node, found an exact match. */
670 1.1 dillo result = 0;
671 1.1 dillo break;
672 1.1 dillo }
673 1.1 dillo else if(recnum==nd.num_recs-1 && keycompare > 0)
674 1.1 dillo {
675 1.1 dillo /* If leaf node, we've reached the last record with no match,
676 1.1 dillo * which means this key is not present on the volume. */
677 1.1 dillo result = -1;
678 1.1 dillo break;
679 1.1 dillo }
680 1.1 dillo
681 1.2 dillo memcpy(&lastrec, out_rec, sizeof(hfs_catalog_keyed_record_t));
682 1.1 dillo }
683 1.1 dillo
684 1.2 dillo if(nd.kind==HFS_INDEXNODE)
685 1.1 dillo curnode = out_rec->child;
686 1.2 dillo else if(nd.kind==HFS_LEAFNODE)
687 1.1 dillo break;
688 1.1 dillo
689 1.2 dillo hfslib_free_recs(&recs, &recsizes, &nd.num_recs, cbargs);
690 1.1 dillo }
691 1.2 dillo while(nd.kind!=HFS_LEAFNODE);
692 1.1 dillo
693 1.1 dillo /* FALLTHROUGH */
694 1.1 dillo error:
695 1.1 dillo if(extents!=NULL)
696 1.2 dillo hfslib_free(extents, cbargs);
697 1.2 dillo hfslib_free_recs(&recs, &recsizes, &nd.num_recs, cbargs);
698 1.1 dillo if(curkey!=NULL)
699 1.2 dillo hfslib_free(curkey, cbargs);
700 1.1 dillo if(buffer!=NULL)
701 1.2 dillo hfslib_free(buffer, cbargs);
702 1.1 dillo
703 1.1 dillo return result;
704 1.1 dillo }
705 1.1 dillo
706 1.1 dillo /* returns 0 on success */
707 1.1 dillo /* XXX Need to look this over and make sure it gracefully handles cases where
708 1.1 dillo * XXX the key is not found. */
709 1.1 dillo int
710 1.2 dillo hfslib_find_extent_record_with_key(hfs_volume* in_vol,
711 1.2 dillo hfs_extent_key_t* in_key,
712 1.2 dillo hfs_extent_record_t* out_rec,
713 1.2 dillo hfs_callback_args* cbargs)
714 1.2 dillo {
715 1.2 dillo hfs_node_descriptor_t nd;
716 1.2 dillo hfs_extent_descriptor_t* extents;
717 1.2 dillo hfs_extent_record_t lastrec;
718 1.2 dillo hfs_extent_key_t curkey;
719 1.1 dillo void** recs;
720 1.1 dillo void* buffer;
721 1.1 dillo uint64_t bytesread;
722 1.1 dillo uint32_t curnode;
723 1.1 dillo uint16_t* recsizes;
724 1.1 dillo uint16_t numextents;
725 1.1 dillo uint16_t recnum;
726 1.1 dillo int keycompare;
727 1.1 dillo int result;
728 1.1 dillo
729 1.1 dillo if(in_vol==NULL || in_key==NULL || out_rec==NULL)
730 1.1 dillo return 1;
731 1.1 dillo
732 1.1 dillo result = 1;
733 1.1 dillo buffer = NULL;
734 1.1 dillo extents = NULL;
735 1.1 dillo recs = NULL;
736 1.1 dillo recsizes = NULL;
737 1.1 dillo
738 1.2 dillo buffer = hfslib_malloc(in_vol->ehr.node_size, cbargs);
739 1.1 dillo if(buffer==NULL)
740 1.2 dillo HFS_LIBERR("could not allocate node buffer");
741 1.1 dillo
742 1.2 dillo numextents = hfslib_get_file_extents(in_vol, HFS_CNID_EXTENTS,
743 1.2 dillo HFS_DATAFORK, &extents, cbargs);
744 1.1 dillo if(numextents==0)
745 1.2 dillo HFS_LIBERR("could not locate fork extents");
746 1.1 dillo
747 1.1 dillo nd.num_recs = 0;
748 1.1 dillo curnode = in_vol->ehr.root_node;
749 1.1 dillo
750 1.1 dillo do
751 1.1 dillo {
752 1.2 dillo hfslib_free_recs(&recs, &recsizes, &nd.num_recs, cbargs);
753 1.1 dillo recnum = 0;
754 1.1 dillo
755 1.2 dillo if(hfslib_readd_with_extents(in_vol, buffer, &bytesread,
756 1.1 dillo in_vol->ehr.node_size, curnode * in_vol->ehr.node_size, extents,
757 1.1 dillo numextents, cbargs)!=0)
758 1.2 dillo HFS_LIBERR("could not read extents overflow node #%i", curnode);
759 1.1 dillo
760 1.2 dillo if(hfslib_reada_node(buffer, &nd, &recs, &recsizes, HFS_EXTENTS_FILE,
761 1.1 dillo in_vol, cbargs)==0)
762 1.2 dillo HFS_LIBERR("could not parse extents overflow node #%i",curnode);
763 1.1 dillo
764 1.1 dillo for(recnum=0; recnum<nd.num_recs; recnum++)
765 1.1 dillo {
766 1.2 dillo memcpy(&lastrec, out_rec, sizeof(hfs_extent_record_t));
767 1.1 dillo
768 1.2 dillo if(hfslib_read_extent_record(recs[recnum], out_rec, nd.kind,
769 1.1 dillo &curkey, in_vol)==0)
770 1.2 dillo HFS_LIBERR("could not read extents record #%i",recnum);
771 1.1 dillo
772 1.2 dillo keycompare = hfslib_compare_extent_keys(in_key, &curkey);
773 1.1 dillo if(keycompare < 0)
774 1.1 dillo {
775 1.1 dillo /* this should never happen for any legitimate key */
776 1.1 dillo if(recnum==0)
777 1.1 dillo return 1;
778 1.1 dillo
779 1.2 dillo memcpy(out_rec, &lastrec, sizeof(hfs_extent_record_t));
780 1.1 dillo
781 1.1 dillo break;
782 1.1 dillo }
783 1.1 dillo else if(keycompare == 0 ||
784 1.1 dillo (recnum==nd.num_recs-1 && keycompare > 0))
785 1.1 dillo break;
786 1.1 dillo }
787 1.1 dillo
788 1.2 dillo if(nd.kind==HFS_INDEXNODE)
789 1.1 dillo curnode = *((uint32_t *)out_rec); /* out_rec is a node ptr in this case */
790 1.2 dillo else if(nd.kind==HFS_LEAFNODE)
791 1.1 dillo break;
792 1.1 dillo else
793 1.2 dillo HFS_LIBERR("unknwon node type for extents overflow node #%i",curnode);
794 1.1 dillo }
795 1.2 dillo while(nd.kind!=HFS_LEAFNODE);
796 1.1 dillo
797 1.1 dillo result = 0;
798 1.1 dillo
799 1.1 dillo /* FALLTHROUGH */
800 1.1 dillo
801 1.1 dillo error:
802 1.1 dillo if(buffer!=NULL)
803 1.2 dillo hfslib_free(buffer, cbargs);
804 1.1 dillo if(extents!=NULL)
805 1.2 dillo hfslib_free(extents, cbargs);
806 1.2 dillo hfslib_free_recs(&recs, &recsizes, &nd.num_recs, cbargs);
807 1.1 dillo
808 1.1 dillo return result;
809 1.1 dillo }
810 1.1 dillo
811 1.1 dillo /* out_extents may be NULL. */
812 1.1 dillo uint16_t
813 1.2 dillo hfslib_get_file_extents(hfs_volume* in_vol,
814 1.2 dillo hfs_cnid_t in_cnid,
815 1.1 dillo uint8_t in_forktype,
816 1.2 dillo hfs_extent_descriptor_t** out_extents,
817 1.2 dillo hfs_callback_args* cbargs)
818 1.1 dillo {
819 1.2 dillo hfs_extent_descriptor_t* dummy;
820 1.2 dillo hfs_extent_key_t extentkey;
821 1.2 dillo hfs_file_record_t file;
822 1.2 dillo hfs_catalog_key_t filekey;
823 1.2 dillo hfs_thread_record_t fileparent;
824 1.8 apb hfs_fork_t fork = {.logical_size = 0};
825 1.2 dillo hfs_extent_record_t nextextentrec;
826 1.1 dillo uint32_t numblocks;
827 1.1 dillo uint16_t numextents, n;
828 1.1 dillo
829 1.1 dillo if(in_vol==NULL || in_cnid==0)
830 1.1 dillo return 0;
831 1.1 dillo
832 1.1 dillo if(out_extents!=NULL)
833 1.1 dillo {
834 1.2 dillo *out_extents = hfslib_malloc(sizeof(hfs_extent_descriptor_t), cbargs);
835 1.1 dillo if(*out_extents==NULL)
836 1.1 dillo return 0;
837 1.1 dillo }
838 1.1 dillo
839 1.1 dillo switch(in_cnid)
840 1.1 dillo {
841 1.2 dillo case HFS_CNID_CATALOG:
842 1.1 dillo fork = in_vol->vh.catalog_file;
843 1.1 dillo break;
844 1.1 dillo
845 1.2 dillo case HFS_CNID_EXTENTS:
846 1.1 dillo fork = in_vol->vh.extents_file;
847 1.1 dillo break;
848 1.1 dillo
849 1.2 dillo case HFS_CNID_ALLOCATION:
850 1.1 dillo fork = in_vol->vh.allocation_file;
851 1.1 dillo break;
852 1.1 dillo
853 1.2 dillo case HFS_CNID_ATTRIBUTES:
854 1.1 dillo fork = in_vol->vh.attributes_file;
855 1.1 dillo break;
856 1.1 dillo
857 1.2 dillo case HFS_CNID_STARTUP:
858 1.1 dillo fork = in_vol->vh.startup_file;
859 1.1 dillo break;
860 1.1 dillo
861 1.1 dillo default:
862 1.2 dillo if(hfslib_find_parent_thread(in_vol, in_cnid, &fileparent,
863 1.1 dillo cbargs)==0)
864 1.1 dillo goto error;
865 1.1 dillo
866 1.2 dillo if(hfslib_make_catalog_key(fileparent.parent_cnid,
867 1.1 dillo fileparent.name.length, fileparent.name.unicode, &filekey)==0)
868 1.1 dillo goto error;
869 1.1 dillo
870 1.2 dillo if(hfslib_find_catalog_record_with_key(in_vol, &filekey,
871 1.2 dillo (hfs_catalog_keyed_record_t*)&file, cbargs)!=0)
872 1.1 dillo goto error;
873 1.1 dillo
874 1.1 dillo /* only files have extents, not folders or threads */
875 1.2 dillo if(file.rec_type!=HFS_REC_FILE)
876 1.1 dillo goto error;
877 1.1 dillo
878 1.2 dillo if(in_forktype==HFS_DATAFORK)
879 1.1 dillo fork = file.data_fork;
880 1.2 dillo else if(in_forktype==HFS_RSRCFORK)
881 1.1 dillo fork = file.rsrc_fork;
882 1.1 dillo }
883 1.1 dillo
884 1.1 dillo numextents = 0;
885 1.1 dillo numblocks = 0;
886 1.2 dillo memcpy(&nextextentrec, &fork.extents, sizeof(hfs_extent_record_t));
887 1.1 dillo
888 1.1 dillo while(1)
889 1.1 dillo {
890 1.1 dillo for(n=0; n<8; n++)
891 1.1 dillo {
892 1.1 dillo if(nextextentrec[n].block_count==0)
893 1.1 dillo break;
894 1.1 dillo
895 1.1 dillo numblocks += nextextentrec[n].block_count;
896 1.1 dillo }
897 1.1 dillo
898 1.1 dillo if(out_extents!=NULL)
899 1.1 dillo {
900 1.2 dillo dummy = hfslib_realloc(*out_extents,
901 1.2 dillo (numextents+n) * sizeof(hfs_extent_descriptor_t),
902 1.1 dillo cbargs);
903 1.1 dillo if(dummy==NULL)
904 1.1 dillo goto error;
905 1.1 dillo *out_extents = dummy;
906 1.1 dillo
907 1.1 dillo memcpy(*out_extents + numextents,
908 1.2 dillo &nextextentrec, n*sizeof(hfs_extent_descriptor_t));
909 1.1 dillo }
910 1.1 dillo numextents += n;
911 1.1 dillo
912 1.1 dillo if(numblocks >= fork.total_blocks)
913 1.1 dillo break;
914 1.1 dillo
915 1.2 dillo if(hfslib_make_extent_key(in_cnid, in_forktype, numblocks,
916 1.1 dillo &extentkey)==0)
917 1.1 dillo goto error;
918 1.1 dillo
919 1.2 dillo if(hfslib_find_extent_record_with_key(in_vol, &extentkey,
920 1.1 dillo &nextextentrec, cbargs)!=0)
921 1.1 dillo goto error;
922 1.1 dillo }
923 1.1 dillo
924 1.1 dillo goto exit;
925 1.1 dillo
926 1.1 dillo error:
927 1.1 dillo if(out_extents!=NULL && *out_extents!=NULL)
928 1.1 dillo {
929 1.2 dillo hfslib_free(*out_extents, cbargs);
930 1.1 dillo *out_extents = NULL;
931 1.1 dillo }
932 1.1 dillo return 0;
933 1.1 dillo
934 1.1 dillo exit:
935 1.1 dillo return numextents;
936 1.1 dillo }
937 1.1 dillo
938 1.1 dillo /*
939 1.2 dillo * hfslib_get_directory_contents()
940 1.1 dillo *
941 1.1 dillo * Finds the immediate children of a given directory CNID and places their
942 1.1 dillo * CNIDs in an array allocated here. The first child is found by doing a
943 1.1 dillo * catalog search that only compares parent CNIDs (ignoring file/folder names)
944 1.1 dillo * and skips over thread records. Then the remaining children are listed in
945 1.1 dillo * ascending order by name, according to the HFS+ spec, so just read off each
946 1.1 dillo * successive leaf node until a different parent CNID is found.
947 1.1 dillo *
948 1.1 dillo * If out_childnames is not NULL, it will be allocated and set to an array of
949 1.2 dillo * hfs_unistr255_t's which correspond to the name of the child with that same
950 1.1 dillo * index.
951 1.1 dillo *
952 1.1 dillo * out_children may be NULL.
953 1.1 dillo *
954 1.1 dillo * Returns 0 on success.
955 1.1 dillo */
956 1.1 dillo int
957 1.2 dillo hfslib_get_directory_contents(
958 1.2 dillo hfs_volume* in_vol,
959 1.2 dillo hfs_cnid_t in_dir,
960 1.2 dillo hfs_catalog_keyed_record_t** out_children,
961 1.2 dillo hfs_unistr255_t** out_childnames,
962 1.1 dillo uint32_t* out_numchildren,
963 1.2 dillo hfs_callback_args* cbargs)
964 1.1 dillo {
965 1.2 dillo hfs_node_descriptor_t nd;
966 1.2 dillo hfs_extent_descriptor_t* extents;
967 1.2 dillo hfs_catalog_keyed_record_t currec;
968 1.2 dillo hfs_catalog_key_t curkey;
969 1.1 dillo void** recs;
970 1.1 dillo void* buffer;
971 1.1 dillo void* ptr; /* temporary pointer for realloc() */
972 1.1 dillo uint64_t bytesread;
973 1.1 dillo uint32_t curnode;
974 1.1 dillo uint32_t lastnode;
975 1.1 dillo uint16_t* recsizes;
976 1.1 dillo uint16_t numextents;
977 1.1 dillo uint16_t recnum;
978 1.1 dillo int16_t leaftype;
979 1.1 dillo int keycompare;
980 1.1 dillo int result;
981 1.1 dillo
982 1.1 dillo if(in_vol==NULL || in_dir==0 || out_numchildren==NULL)
983 1.1 dillo return 1;
984 1.1 dillo
985 1.1 dillo result = 1;
986 1.1 dillo buffer = NULL;
987 1.1 dillo extents = NULL;
988 1.1 dillo lastnode = 0;
989 1.1 dillo recs = NULL;
990 1.1 dillo recsizes = NULL;
991 1.1 dillo *out_numchildren = 0;
992 1.1 dillo if(out_children!=NULL)
993 1.1 dillo *out_children = NULL;
994 1.1 dillo if(out_childnames!=NULL)
995 1.1 dillo *out_childnames = NULL;
996 1.1 dillo
997 1.2 dillo buffer = hfslib_malloc(in_vol->chr.node_size, cbargs);
998 1.1 dillo if(buffer==NULL)
999 1.2 dillo HFS_LIBERR("could not allocate node buffer");
1000 1.1 dillo
1001 1.2 dillo numextents = hfslib_get_file_extents(in_vol, HFS_CNID_CATALOG,
1002 1.2 dillo HFS_DATAFORK, &extents, cbargs);
1003 1.1 dillo if(numextents==0)
1004 1.2 dillo HFS_LIBERR("could not locate fork extents");
1005 1.1 dillo
1006 1.1 dillo nd.num_recs = 0;
1007 1.1 dillo curnode = in_vol->chr.root_node;
1008 1.1 dillo
1009 1.1 dillo while(1)
1010 1.1 dillo {
1011 1.2 dillo hfslib_free_recs(&recs, &recsizes, &nd.num_recs, cbargs);
1012 1.1 dillo recnum = 0;
1013 1.1 dillo
1014 1.2 dillo if(hfslib_readd_with_extents(in_vol, buffer, &bytesread,
1015 1.1 dillo in_vol->chr.node_size, curnode * in_vol->chr.node_size, extents,
1016 1.1 dillo numextents, cbargs)!=0)
1017 1.2 dillo HFS_LIBERR("could not read catalog node #%i", curnode);
1018 1.1 dillo
1019 1.2 dillo if(hfslib_reada_node(buffer, &nd, &recs, &recsizes, HFS_CATALOG_FILE,
1020 1.1 dillo in_vol, cbargs)==0)
1021 1.2 dillo HFS_LIBERR("could not parse catalog node #%i", curnode);
1022 1.1 dillo
1023 1.1 dillo for(recnum=0; recnum<nd.num_recs; recnum++)
1024 1.1 dillo {
1025 1.1 dillo leaftype = nd.kind; /* needed b/c leaftype might be modified now */
1026 1.2 dillo if(hfslib_read_catalog_keyed_record(recs[recnum], &currec,
1027 1.1 dillo &leaftype, &curkey, in_vol)==0)
1028 1.2 dillo HFS_LIBERR("could not read cat record %i:%i", curnode, recnum);
1029 1.1 dillo
1030 1.2 dillo if(nd.kind==HFS_INDEXNODE)
1031 1.1 dillo {
1032 1.1 dillo keycompare = in_dir - curkey.parent_cnid;
1033 1.1 dillo if(keycompare < 0)
1034 1.1 dillo {
1035 1.1 dillo /* Check if key is less than *every* record, which should
1036 1.1 dillo * never happen if the volume and key are good. */
1037 1.1 dillo if(recnum==0)
1038 1.2 dillo HFS_LIBERR("all records greater than key");
1039 1.1 dillo
1040 1.1 dillo /* Otherwise, we've found the first record that exceeds our
1041 1.1 dillo * key, so retrieve the previous, lesser record. */
1042 1.1 dillo curnode = lastnode;
1043 1.1 dillo break;
1044 1.1 dillo }
1045 1.1 dillo else if(keycompare == 0)
1046 1.1 dillo {
1047 1.1 dillo /*
1048 1.1 dillo * Normally, if we were doing a typical catalog lookup with
1049 1.1 dillo * both a parent cnid AND a name, keycompare==0 would be an
1050 1.1 dillo * exact match. However, since we are ignoring object names
1051 1.1 dillo * in this case and only comparing parent cnids, a direct
1052 1.1 dillo * match on only a parent cnid could mean that we've found
1053 1.1 dillo * an object with that parent cnid BUT which is NOT the
1054 1.1 dillo * first object (according to the HFS+ spec) with that
1055 1.1 dillo * parent cnid. Thus, when we find a parent cnid match, we
1056 1.1 dillo * still go back to the previously found leaf node and start
1057 1.1 dillo * checking it for a possible prior instance of an object
1058 1.1 dillo * with our desired parent cnid.
1059 1.1 dillo */
1060 1.1 dillo curnode = lastnode;
1061 1.1 dillo break;
1062 1.1 dillo }
1063 1.1 dillo else if (recnum==nd.num_recs-1 && keycompare > 0)
1064 1.1 dillo {
1065 1.1 dillo /* Descend to child node if we found an exact match, or if
1066 1.1 dillo * this is the last pointer record. */
1067 1.1 dillo curnode = currec.child;
1068 1.1 dillo break;
1069 1.1 dillo }
1070 1.1 dillo
1071 1.1 dillo lastnode = currec.child;
1072 1.1 dillo }
1073 1.1 dillo else
1074 1.1 dillo {
1075 1.1 dillo /*
1076 1.1 dillo * We have now descended down the hierarchy of index nodes into
1077 1.1 dillo * the leaf node that contains the first catalog record with a
1078 1.1 dillo * matching parent CNID. Since all leaf nodes are chained
1079 1.1 dillo * through their flink/blink, we can simply walk forward through
1080 1.1 dillo * this chain, copying every matching non-thread record, until
1081 1.1 dillo * we hit a record with a different parent CNID. At that point,
1082 1.1 dillo * we've retrieved all of our directory's items, if any.
1083 1.1 dillo */
1084 1.1 dillo curnode = nd.flink;
1085 1.1 dillo
1086 1.1 dillo if(curkey.parent_cnid<in_dir)
1087 1.1 dillo continue;
1088 1.1 dillo else if(curkey.parent_cnid==in_dir)
1089 1.1 dillo {
1090 1.1 dillo /* Hide files/folders which are supposed to be invisible
1091 1.1 dillo * to users, according to the hfs+ spec. */
1092 1.2 dillo if(hfslib_is_private_file(&curkey))
1093 1.1 dillo continue;
1094 1.1 dillo
1095 1.1 dillo /* leaftype has now been set to the catalog record type */
1096 1.2 dillo if(leaftype==HFS_REC_FLDR || leaftype==HFS_REC_FILE)
1097 1.1 dillo {
1098 1.1 dillo (*out_numchildren)++;
1099 1.1 dillo
1100 1.1 dillo if(out_children!=NULL)
1101 1.1 dillo {
1102 1.2 dillo ptr = hfslib_realloc(*out_children,
1103 1.1 dillo *out_numchildren *
1104 1.2 dillo sizeof(hfs_catalog_keyed_record_t), cbargs);
1105 1.1 dillo if(ptr==NULL)
1106 1.2 dillo HFS_LIBERR("could not allocate child record");
1107 1.1 dillo *out_children = ptr;
1108 1.1 dillo
1109 1.1 dillo memcpy(&((*out_children)[*out_numchildren-1]),
1110 1.2 dillo &currec, sizeof(hfs_catalog_keyed_record_t));
1111 1.1 dillo }
1112 1.1 dillo
1113 1.1 dillo if(out_childnames!=NULL)
1114 1.1 dillo {
1115 1.2 dillo ptr = hfslib_realloc(*out_childnames,
1116 1.2 dillo *out_numchildren * sizeof(hfs_unistr255_t),
1117 1.1 dillo cbargs);
1118 1.1 dillo if(ptr==NULL)
1119 1.2 dillo HFS_LIBERR("could not allocate child name");
1120 1.1 dillo *out_childnames = ptr;
1121 1.1 dillo
1122 1.1 dillo memcpy(&((*out_childnames)[*out_numchildren-1]),
1123 1.2 dillo &curkey.name, sizeof(hfs_unistr255_t));
1124 1.1 dillo }
1125 1.1 dillo }
1126 1.1 dillo } else {
1127 1.1 dillo result = 0;
1128 1.1 dillo /* We have just now passed the last item in the desired
1129 1.1 dillo * folder (or the folder was empty), so exit. */
1130 1.1 dillo goto exit;
1131 1.1 dillo }
1132 1.1 dillo }
1133 1.1 dillo }
1134 1.1 dillo }
1135 1.1 dillo
1136 1.1 dillo result = 0;
1137 1.1 dillo
1138 1.1 dillo goto exit;
1139 1.1 dillo
1140 1.1 dillo error:
1141 1.1 dillo if(out_children!=NULL && *out_children!=NULL)
1142 1.2 dillo hfslib_free(*out_children, cbargs);
1143 1.1 dillo if(out_childnames!=NULL && *out_childnames!=NULL)
1144 1.2 dillo hfslib_free(*out_childnames, cbargs);
1145 1.1 dillo
1146 1.1 dillo /* FALLTHROUGH */
1147 1.1 dillo
1148 1.1 dillo exit:
1149 1.1 dillo if(extents!=NULL)
1150 1.2 dillo hfslib_free(extents, cbargs);
1151 1.2 dillo hfslib_free_recs(&recs, &recsizes, &nd.num_recs, cbargs);
1152 1.1 dillo if(buffer!=NULL)
1153 1.2 dillo hfslib_free(buffer, cbargs);
1154 1.1 dillo
1155 1.1 dillo return result;
1156 1.1 dillo }
1157 1.1 dillo
1158 1.1 dillo int
1159 1.2 dillo hfslib_is_journal_clean(hfs_volume* in_vol)
1160 1.1 dillo {
1161 1.1 dillo if(in_vol==NULL)
1162 1.1 dillo return 0;
1163 1.1 dillo
1164 1.1 dillo /* return true if no journal */
1165 1.2 dillo if(!(in_vol->vh.attributes & (1<<HFS_VOL_JOURNALED)))
1166 1.1 dillo return 1;
1167 1.1 dillo
1168 1.1 dillo return (in_vol->jh.start == in_vol->jh.end);
1169 1.1 dillo }
1170 1.1 dillo
1171 1.1 dillo /*
1172 1.2 dillo * hfslib_is_private_file()
1173 1.1 dillo *
1174 1.1 dillo * Given a file/folder's key and parent CNID, determines if it should be hidden
1175 1.1 dillo * from the user (e.g., the journal header file or the HFS+ Private Data folder)
1176 1.1 dillo */
1177 1.1 dillo int
1178 1.2 dillo hfslib_is_private_file(hfs_catalog_key_t *filekey)
1179 1.1 dillo {
1180 1.2 dillo hfs_catalog_key_t* curkey = NULL;
1181 1.1 dillo int i = 0;
1182 1.1 dillo
1183 1.1 dillo /*
1184 1.1 dillo * According to the HFS+ spec to date, all special objects are located in
1185 1.1 dillo * the root directory of the volume, so don't bother going further if the
1186 1.1 dillo * requested object is not.
1187 1.1 dillo */
1188 1.2 dillo if(filekey->parent_cnid != HFS_CNID_ROOT_FOLDER)
1189 1.1 dillo return 0;
1190 1.1 dillo
1191 1.2 dillo while((curkey = hfs_gPrivateObjectKeys[i]) != NULL)
1192 1.1 dillo {
1193 1.1 dillo /* XXX Always use binary compare here, or use volume's specific key
1194 1.1 dillo * XXX comparison routine? */
1195 1.1 dillo if(filekey->name.length == curkey->name.length
1196 1.1 dillo && memcmp(filekey->name.unicode, curkey->name.unicode,
1197 1.1 dillo 2 * curkey->name.length)==0)
1198 1.1 dillo return 1;
1199 1.1 dillo
1200 1.1 dillo i++;
1201 1.1 dillo }
1202 1.1 dillo
1203 1.1 dillo return 0;
1204 1.1 dillo }
1205 1.1 dillo
1206 1.1 dillo
1207 1.1 dillo /* bool
1208 1.2 dillo hfslib_is_journal_valid(hfs_volume* in_vol)
1209 1.1 dillo {
1210 1.1 dillo - check magic numbers
1211 1.1 dillo - check Other Things
1212 1.1 dillo }*/
1213 1.1 dillo
1214 1.1 dillo #if 0
1215 1.1 dillo #pragma mark -
1216 1.1 dillo #pragma mark Major Structures
1217 1.1 dillo #endif
1218 1.1 dillo
1219 1.1 dillo /*
1220 1.2 dillo * hfslib_read_volume_header()
1221 1.1 dillo *
1222 1.1 dillo * Reads in_bytes, formats the data appropriately, and places the result
1223 1.1 dillo * in out_header, which is assumed to be previously allocated. Returns number
1224 1.1 dillo * of bytes read, 0 if failed.
1225 1.1 dillo */
1226 1.1 dillo
1227 1.1 dillo size_t
1228 1.2 dillo hfslib_read_volume_header(void* in_bytes, hfs_volume_header_t* out_header)
1229 1.1 dillo {
1230 1.1 dillo void* ptr;
1231 1.1 dillo size_t last_bytes_read;
1232 1.1 dillo int i;
1233 1.1 dillo
1234 1.1 dillo if(in_bytes==NULL || out_header==NULL)
1235 1.1 dillo return 0;
1236 1.1 dillo
1237 1.1 dillo ptr = in_bytes;
1238 1.1 dillo
1239 1.1 dillo out_header->signature = be16tohp(&ptr);
1240 1.1 dillo out_header->version = be16tohp(&ptr);
1241 1.1 dillo out_header->attributes = be32tohp(&ptr);
1242 1.1 dillo out_header->last_mounting_version = be32tohp(&ptr);
1243 1.1 dillo out_header->journal_info_block = be32tohp(&ptr);
1244 1.1 dillo
1245 1.1 dillo out_header->date_created = be32tohp(&ptr);
1246 1.1 dillo out_header->date_modified = be32tohp(&ptr);
1247 1.1 dillo out_header->date_backedup = be32tohp(&ptr);
1248 1.1 dillo out_header->date_checked = be32tohp(&ptr);
1249 1.1 dillo
1250 1.1 dillo out_header->file_count = be32tohp(&ptr);
1251 1.1 dillo out_header->folder_count = be32tohp(&ptr);
1252 1.1 dillo
1253 1.1 dillo out_header->block_size = be32tohp(&ptr);
1254 1.1 dillo out_header->total_blocks = be32tohp(&ptr);
1255 1.1 dillo out_header->free_blocks = be32tohp(&ptr);
1256 1.1 dillo out_header->next_alloc_block = be32tohp(&ptr);
1257 1.1 dillo out_header->rsrc_clump_size = be32tohp(&ptr);
1258 1.1 dillo out_header->data_clump_size = be32tohp(&ptr);
1259 1.1 dillo out_header->next_cnid = be32tohp(&ptr);
1260 1.1 dillo
1261 1.1 dillo out_header->write_count = be32tohp(&ptr);
1262 1.1 dillo out_header->encodings = be64tohp(&ptr);
1263 1.1 dillo
1264 1.1 dillo for(i=0;i<8;i++)
1265 1.1 dillo out_header->finder_info[i] = be32tohp(&ptr);
1266 1.1 dillo
1267 1.2 dillo if((last_bytes_read = hfslib_read_fork_descriptor(ptr,
1268 1.1 dillo &out_header->allocation_file))==0)
1269 1.1 dillo return 0;
1270 1.1 dillo ptr = (uint8_t*)ptr + last_bytes_read;
1271 1.1 dillo
1272 1.2 dillo if((last_bytes_read = hfslib_read_fork_descriptor(ptr,
1273 1.1 dillo &out_header->extents_file))==0)
1274 1.1 dillo return 0;
1275 1.1 dillo ptr = (uint8_t*)ptr + last_bytes_read;
1276 1.1 dillo
1277 1.2 dillo if((last_bytes_read = hfslib_read_fork_descriptor(ptr,
1278 1.1 dillo &out_header->catalog_file))==0)
1279 1.1 dillo return 0;
1280 1.1 dillo ptr = (uint8_t*)ptr + last_bytes_read;
1281 1.1 dillo
1282 1.2 dillo if((last_bytes_read = hfslib_read_fork_descriptor(ptr,
1283 1.1 dillo &out_header->attributes_file))==0)
1284 1.1 dillo return 0;
1285 1.1 dillo ptr = (uint8_t*)ptr + last_bytes_read;
1286 1.1 dillo
1287 1.2 dillo if((last_bytes_read = hfslib_read_fork_descriptor(ptr,
1288 1.1 dillo &out_header->startup_file))==0)
1289 1.1 dillo return 0;
1290 1.1 dillo ptr = (uint8_t*)ptr + last_bytes_read;
1291 1.1 dillo
1292 1.1 dillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
1293 1.1 dillo }
1294 1.1 dillo
1295 1.1 dillo /*
1296 1.4 dillo * hfsplib_read_master_directory_block()
1297 1.4 dillo *
1298 1.4 dillo * Reads in_bytes, formats the data appropriately, and places the result
1299 1.4 dillo * in out_header, which is assumed to be previously allocated. Returns numb
1300 1.4 dillo er
1301 1.4 dillo * of bytes read, 0 if failed.
1302 1.4 dillo */
1303 1.4 dillo
1304 1.4 dillo size_t
1305 1.4 dillo hfslib_read_master_directory_block(void* in_bytes,
1306 1.4 dillo hfs_hfs_master_directory_block_t* out_mdr)
1307 1.4 dillo {
1308 1.4 dillo void* ptr;
1309 1.4 dillo int i;
1310 1.4 dillo
1311 1.4 dillo if(in_bytes==NULL || out_mdr==NULL)
1312 1.4 dillo return 0;
1313 1.4 dillo
1314 1.4 dillo ptr = in_bytes;
1315 1.4 dillo
1316 1.4 dillo out_mdr->signature = be16tohp(&ptr);
1317 1.4 dillo
1318 1.4 dillo out_mdr->date_created = be32tohp(&ptr);
1319 1.4 dillo out_mdr->date_modified = be32tohp(&ptr);
1320 1.4 dillo
1321 1.4 dillo out_mdr->attributes = be16tohp(&ptr);
1322 1.4 dillo out_mdr->root_file_count = be16tohp(&ptr);
1323 1.4 dillo out_mdr->volume_bitmap = be16tohp(&ptr);
1324 1.4 dillo
1325 1.4 dillo out_mdr->next_alloc_block = be16tohp(&ptr);
1326 1.4 dillo out_mdr->total_blocks = be16tohp(&ptr);
1327 1.4 dillo out_mdr->block_size = be32tohp(&ptr);
1328 1.4 dillo
1329 1.4 dillo out_mdr->clump_size = be32tohp(&ptr);
1330 1.4 dillo out_mdr->first_block = be16tohp(&ptr);
1331 1.4 dillo out_mdr->next_cnid = be32tohp(&ptr);
1332 1.4 dillo out_mdr->free_blocks = be16tohp(&ptr);
1333 1.4 dillo
1334 1.4 dillo memcpy(out_mdr->volume_name, ptr, 28);
1335 1.4 dillo ptr = (char *)ptr + 28;
1336 1.4 dillo
1337 1.4 dillo out_mdr->date_backedup = be32tohp(&ptr);
1338 1.4 dillo out_mdr->backup_seqnum = be16tohp(&ptr);
1339 1.4 dillo
1340 1.4 dillo out_mdr->write_count = be32tohp(&ptr);
1341 1.4 dillo
1342 1.4 dillo out_mdr->extents_clump_size = be32tohp(&ptr);
1343 1.4 dillo out_mdr->catalog_clump_size = be32tohp(&ptr);
1344 1.4 dillo
1345 1.4 dillo out_mdr->root_folder_count = be16tohp(&ptr);
1346 1.4 dillo out_mdr->file_count = be32tohp(&ptr);
1347 1.4 dillo out_mdr->folder_count = be32tohp(&ptr);
1348 1.4 dillo
1349 1.4 dillo for(i=0;i<8;i++)
1350 1.4 dillo out_mdr->finder_info[i] = be32tohp(&ptr);
1351 1.4 dillo
1352 1.4 dillo out_mdr->embedded_signature = be16tohp(&ptr);
1353 1.4 dillo out_mdr->embedded_extent.start_block = be16tohp(&ptr);
1354 1.4 dillo out_mdr->embedded_extent.block_count = be16tohp(&ptr);
1355 1.4 dillo
1356 1.4 dillo out_mdr->extents_size = be32tohp(&ptr);
1357 1.4 dillo for (i = 0; i < 3; i++)
1358 1.4 dillo {
1359 1.4 dillo out_mdr->extents_extents[i].start_block = be16tohp(&ptr);
1360 1.4 dillo out_mdr->extents_extents[i].block_count = be16tohp(&ptr);
1361 1.4 dillo }
1362 1.4 dillo
1363 1.4 dillo out_mdr->catalog_size = be32tohp(&ptr);
1364 1.4 dillo for (i = 0; i < 3; i++)
1365 1.4 dillo {
1366 1.4 dillo out_mdr->catalog_extents[i].start_block = be16tohp(&ptr);
1367 1.4 dillo out_mdr->catalog_extents[i].block_count = be16tohp(&ptr);
1368 1.4 dillo }
1369 1.4 dillo
1370 1.4 dillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
1371 1.4 dillo }
1372 1.4 dillo
1373 1.4 dillo /*
1374 1.2 dillo * hfslib_reada_node()
1375 1.1 dillo *
1376 1.1 dillo * Given the pointer to and size of a buffer containing the entire, raw
1377 1.1 dillo * contents of any b-tree node from the disk, this function will:
1378 1.1 dillo *
1379 1.1 dillo * 1. determine the type of node and read its contents
1380 1.1 dillo * 2. allocate memory for each record and fill it appropriately
1381 1.1 dillo * 3. set out_record_ptrs_array to point to an array (which it allocates)
1382 1.1 dillo * which has out_node_descriptor->num_recs many pointers to the
1383 1.1 dillo * records themselves
1384 1.1 dillo * 4. allocate out_record_ptr_sizes_array and fill it with the sizes of
1385 1.1 dillo * each record
1386 1.1 dillo * 5. return the number of bytes read (i.e., the size of the node)
1387 1.1 dillo * or 0 on failure
1388 1.1 dillo *
1389 1.1 dillo * out_node_descriptor must be allocated by the caller and may not be NULL.
1390 1.1 dillo *
1391 1.1 dillo * out_record_ptrs_array and out_record_ptr_sizes_array must both be specified,
1392 1.1 dillo * or both be NULL if the caller is not interested in reading the records.
1393 1.1 dillo *
1394 1.1 dillo * out_record_ptr_sizes_array may be NULL if the caller is not interested in
1395 1.1 dillo * reading the records, but must not be NULL if out_record_ptrs_array is not.
1396 1.1 dillo *
1397 1.2 dillo * in_parent_file is HFS_CATALOG_FILE, HFS_EXTENTS_FILE, or
1398 1.2 dillo * HFS_ATTRIBUTES_FILE, depending on the special file in which this node
1399 1.1 dillo * resides.
1400 1.1 dillo *
1401 1.1 dillo * inout_volume must have its catnodesize or extnodesize field (depending on
1402 1.1 dillo * the parent file) set to the correct value if this is an index, leaf, or map
1403 1.1 dillo * node. If this is a header node, the field will be set to its correct value.
1404 1.1 dillo */
1405 1.1 dillo size_t
1406 1.2 dillo hfslib_reada_node(void* in_bytes,
1407 1.2 dillo hfs_node_descriptor_t* out_node_descriptor,
1408 1.1 dillo void** out_record_ptrs_array[],
1409 1.1 dillo uint16_t* out_record_ptr_sizes_array[],
1410 1.2 dillo hfs_btree_file_type in_parent_file,
1411 1.2 dillo hfs_volume* inout_volume,
1412 1.2 dillo hfs_callback_args* cbargs)
1413 1.1 dillo {
1414 1.1 dillo void* ptr;
1415 1.1 dillo uint16_t* rec_offsets;
1416 1.1 dillo size_t last_bytes_read;
1417 1.1 dillo uint16_t nodesize;
1418 1.1 dillo uint16_t numrecords;
1419 1.1 dillo uint16_t free_space_offset; /* offset to free space in node */
1420 1.1 dillo int keysizefieldsize;
1421 1.1 dillo int i;
1422 1.1 dillo
1423 1.1 dillo numrecords = 0;
1424 1.1 dillo rec_offsets = NULL;
1425 1.1 dillo if(out_record_ptrs_array!=NULL)
1426 1.1 dillo *out_record_ptrs_array = NULL;
1427 1.1 dillo if(out_record_ptr_sizes_array!=NULL)
1428 1.1 dillo *out_record_ptr_sizes_array = NULL;
1429 1.1 dillo
1430 1.1 dillo if(in_bytes==NULL || inout_volume==NULL || out_node_descriptor==NULL
1431 1.1 dillo || (out_record_ptrs_array==NULL && out_record_ptr_sizes_array!=NULL)
1432 1.1 dillo || (out_record_ptrs_array!=NULL && out_record_ptr_sizes_array==NULL) )
1433 1.1 dillo goto error;
1434 1.1 dillo
1435 1.1 dillo ptr = in_bytes;
1436 1.1 dillo
1437 1.1 dillo out_node_descriptor->flink = be32tohp(&ptr);
1438 1.1 dillo out_node_descriptor->blink = be32tohp(&ptr);
1439 1.1 dillo out_node_descriptor->kind = *(((int8_t*)ptr));
1440 1.1 dillo ptr = (uint8_t*)ptr + 1;
1441 1.1 dillo out_node_descriptor->height = *(((uint8_t*)ptr));
1442 1.1 dillo ptr = (uint8_t*)ptr + 1;
1443 1.1 dillo out_node_descriptor->num_recs = be16tohp(&ptr);
1444 1.1 dillo out_node_descriptor->reserved = be16tohp(&ptr);
1445 1.1 dillo
1446 1.1 dillo numrecords = out_node_descriptor->num_recs;
1447 1.1 dillo
1448 1.1 dillo /*
1449 1.1 dillo * To go any further, we will need to know the size of this node, as well
1450 1.1 dillo * as the width of keyed records' key_len parameters for this btree. If
1451 1.1 dillo * this is an index, leaf, or map node, inout_volume already has the node
1452 1.1 dillo * size set in its catnodesize or extnodesize field and the key length set
1453 1.1 dillo * in the catkeysizefieldsize or extkeysizefieldsize for catalog files and
1454 1.1 dillo * extent files, respectively. However, if this is a header node, this
1455 1.1 dillo * information has not yet been determined, so this is the place to do it.
1456 1.1 dillo */
1457 1.2 dillo if(out_node_descriptor->kind == HFS_HEADERNODE)
1458 1.1 dillo {
1459 1.2 dillo hfs_header_record_t hr;
1460 1.1 dillo void* header_rec_offset[1];
1461 1.1 dillo uint16_t header_rec_size[1];
1462 1.1 dillo
1463 1.1 dillo /* sanity check to ensure this is a good header node */
1464 1.1 dillo if(numrecords!=3)
1465 1.2 dillo HFS_LIBERR("header node does not have exactly 3 records");
1466 1.1 dillo
1467 1.1 dillo header_rec_offset[0] = ptr;
1468 1.2 dillo header_rec_size[0] = sizeof(hfs_header_record_t);
1469 1.1 dillo
1470 1.2 dillo last_bytes_read = hfslib_read_header_node(header_rec_offset,
1471 1.1 dillo header_rec_size, 1, &hr, NULL, NULL);
1472 1.1 dillo if(last_bytes_read==0)
1473 1.2 dillo HFS_LIBERR("could not read header node");
1474 1.1 dillo
1475 1.1 dillo switch(in_parent_file)
1476 1.1 dillo {
1477 1.2 dillo case HFS_CATALOG_FILE:
1478 1.1 dillo inout_volume->chr.node_size = hr.node_size;
1479 1.1 dillo inout_volume->catkeysizefieldsize =
1480 1.2 dillo (hr.attributes & HFS_BIG_KEYS_MASK) ?
1481 1.1 dillo sizeof(uint16_t):sizeof(uint8_t);
1482 1.1 dillo break;
1483 1.1 dillo
1484 1.2 dillo case HFS_EXTENTS_FILE:
1485 1.1 dillo inout_volume->ehr.node_size = hr.node_size;
1486 1.1 dillo inout_volume->extkeysizefieldsize =
1487 1.2 dillo (hr.attributes & HFS_BIG_KEYS_MASK) ?
1488 1.1 dillo sizeof(uint16_t):sizeof(uint8_t);
1489 1.1 dillo break;
1490 1.1 dillo
1491 1.2 dillo case HFS_ATTRIBUTES_FILE:
1492 1.1 dillo default:
1493 1.2 dillo HFS_LIBERR("invalid parent file type specified");
1494 1.1 dillo /* NOTREACHED */
1495 1.1 dillo }
1496 1.1 dillo }
1497 1.1 dillo
1498 1.1 dillo switch(in_parent_file)
1499 1.1 dillo {
1500 1.2 dillo case HFS_CATALOG_FILE:
1501 1.1 dillo nodesize = inout_volume->chr.node_size;
1502 1.1 dillo keysizefieldsize = inout_volume->catkeysizefieldsize;
1503 1.1 dillo break;
1504 1.1 dillo
1505 1.2 dillo case HFS_EXTENTS_FILE:
1506 1.1 dillo nodesize = inout_volume->ehr.node_size;
1507 1.1 dillo keysizefieldsize = inout_volume->extkeysizefieldsize;
1508 1.1 dillo break;
1509 1.1 dillo
1510 1.2 dillo case HFS_ATTRIBUTES_FILE:
1511 1.1 dillo default:
1512 1.2 dillo HFS_LIBERR("invalid parent file type specified");
1513 1.1 dillo /* NOTREACHED */
1514 1.1 dillo }
1515 1.1 dillo
1516 1.1 dillo /*
1517 1.1 dillo * Don't care about records so just exit after getting the node descriptor.
1518 1.1 dillo * Note: This happens after the header node code, and not before it, in
1519 1.1 dillo * case the caller calls this function and ignores the record data just to
1520 1.1 dillo * get at the node descriptor, but then tries to call it again on a non-
1521 1.1 dillo * header node without first setting inout_volume->cat/extnodesize.
1522 1.1 dillo */
1523 1.1 dillo if(out_record_ptrs_array==NULL)
1524 1.1 dillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
1525 1.1 dillo
1526 1.2 dillo rec_offsets = hfslib_malloc(numrecords * sizeof(uint16_t), cbargs);
1527 1.1 dillo *out_record_ptr_sizes_array =
1528 1.2 dillo hfslib_malloc(numrecords * sizeof(uint16_t), cbargs);
1529 1.1 dillo if(rec_offsets==NULL || *out_record_ptr_sizes_array==NULL)
1530 1.2 dillo HFS_LIBERR("could not allocate node record offsets");
1531 1.1 dillo
1532 1.2 dillo *out_record_ptrs_array = hfslib_malloc(numrecords * sizeof(void*), cbargs);
1533 1.1 dillo if(*out_record_ptrs_array==NULL)
1534 1.2 dillo HFS_LIBERR("could not allocate node records");
1535 1.1 dillo
1536 1.2 dillo last_bytes_read = hfslib_reada_node_offsets((uint8_t*)in_bytes + nodesize -
1537 1.1 dillo numrecords * sizeof(uint16_t), rec_offsets);
1538 1.1 dillo if(last_bytes_read==0)
1539 1.2 dillo HFS_LIBERR("could not read node record offsets");
1540 1.1 dillo
1541 1.1 dillo /* The size of the last record (i.e. the first one listed in the offsets)
1542 1.1 dillo * must be determined using the offset to the node's free space. */
1543 1.1 dillo free_space_offset = be16toh(*(uint16_t*)((uint8_t*)in_bytes + nodesize -
1544 1.1 dillo (numrecords+1) * sizeof(uint16_t)));
1545 1.1 dillo
1546 1.1 dillo (*out_record_ptr_sizes_array)[numrecords-1] =
1547 1.1 dillo free_space_offset - rec_offsets[0];
1548 1.1 dillo for(i=1;i<numrecords;i++)
1549 1.1 dillo {
1550 1.1 dillo (*out_record_ptr_sizes_array)[numrecords-i-1] =
1551 1.1 dillo rec_offsets[i-1] - rec_offsets[i];
1552 1.1 dillo }
1553 1.1 dillo
1554 1.1 dillo for(i=0;i<numrecords;i++)
1555 1.1 dillo {
1556 1.1 dillo (*out_record_ptrs_array)[i] =
1557 1.2 dillo hfslib_malloc((*out_record_ptr_sizes_array)[i], cbargs);
1558 1.1 dillo
1559 1.1 dillo if((*out_record_ptrs_array)[i]==NULL)
1560 1.2 dillo HFS_LIBERR("could not allocate node record #%i",i);
1561 1.1 dillo
1562 1.1 dillo /*
1563 1.1 dillo * If this is a keyed node (i.e., a leaf or index node), there are two
1564 1.1 dillo * boundary rules that each record must obey:
1565 1.1 dillo *
1566 1.1 dillo * 1. A pad byte must be placed between the key and data if the
1567 1.1 dillo * size of the key plus the size of the key_len field is odd.
1568 1.1 dillo *
1569 1.1 dillo * 2. A pad byte must be placed after the data if the data size
1570 1.1 dillo * is odd.
1571 1.1 dillo *
1572 1.1 dillo * So in the first case we increment the starting point of the data
1573 1.1 dillo * and correspondingly decrement the record size. In the second case
1574 1.1 dillo * we decrement the record size.
1575 1.1 dillo */
1576 1.2 dillo if(out_node_descriptor->kind == HFS_LEAFNODE ||
1577 1.2 dillo out_node_descriptor->kind == HFS_INDEXNODE)
1578 1.1 dillo {
1579 1.2 dillo hfs_catalog_key_t reckey;
1580 1.1 dillo uint16_t rectype;
1581 1.1 dillo
1582 1.1 dillo rectype = out_node_descriptor->kind;
1583 1.2 dillo last_bytes_read = hfslib_read_catalog_keyed_record(ptr, NULL,
1584 1.1 dillo &rectype, &reckey, inout_volume);
1585 1.1 dillo if(last_bytes_read==0)
1586 1.2 dillo HFS_LIBERR("could not read node record");
1587 1.1 dillo
1588 1.1 dillo if((reckey.key_len + keysizefieldsize) % 2 == 1)
1589 1.1 dillo {
1590 1.1 dillo ptr = (uint8_t*)ptr + 1;
1591 1.1 dillo (*out_record_ptr_sizes_array)[i]--;
1592 1.1 dillo }
1593 1.1 dillo
1594 1.1 dillo if((*out_record_ptr_sizes_array)[i] % 2 == 1)
1595 1.1 dillo (*out_record_ptr_sizes_array)[i]--;
1596 1.1 dillo }
1597 1.1 dillo
1598 1.1 dillo memcpy((*out_record_ptrs_array)[i], ptr,
1599 1.1 dillo (*out_record_ptr_sizes_array)[i]);
1600 1.1 dillo ptr = (uint8_t*)ptr + (*out_record_ptr_sizes_array)[i];
1601 1.1 dillo }
1602 1.1 dillo
1603 1.1 dillo goto exit;
1604 1.1 dillo
1605 1.1 dillo error:
1606 1.2 dillo hfslib_free_recs(out_record_ptrs_array, out_record_ptr_sizes_array,
1607 1.1 dillo &numrecords, cbargs);
1608 1.1 dillo
1609 1.1 dillo ptr = in_bytes;
1610 1.1 dillo
1611 1.2 dillo /* warn("error occurred in hfslib_reada_node()"); */
1612 1.1 dillo
1613 1.1 dillo /* FALLTHROUGH */
1614 1.1 dillo
1615 1.1 dillo exit:
1616 1.1 dillo if(rec_offsets!=NULL)
1617 1.2 dillo hfslib_free(rec_offsets, cbargs);
1618 1.1 dillo
1619 1.1 dillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
1620 1.1 dillo }
1621 1.1 dillo
1622 1.1 dillo /*
1623 1.2 dillo * hfslib_reada_node_offsets()
1624 1.1 dillo *
1625 1.1 dillo * Sets out_offset_array to contain the offsets to each record in the node,
1626 1.1 dillo * in reverse order. Does not read the free space offset.
1627 1.1 dillo */
1628 1.1 dillo size_t
1629 1.2 dillo hfslib_reada_node_offsets(void* in_bytes, uint16_t* out_offset_array)
1630 1.1 dillo {
1631 1.1 dillo void* ptr;
1632 1.1 dillo
1633 1.1 dillo if(in_bytes==NULL || out_offset_array==NULL)
1634 1.1 dillo return 0;
1635 1.1 dillo
1636 1.1 dillo ptr = in_bytes;
1637 1.1 dillo
1638 1.1 dillo /*
1639 1.1 dillo * The offset for record 0 (which is the very last offset in the node) is
1640 1.1 dillo * always equal to 14, the size of the node descriptor. So, once we hit
1641 1.1 dillo * offset=14, we know this is the last offset. In this way, we don't need
1642 1.1 dillo * to know the number of records beforehand.
1643 1.1 dillo */
1644 1.1 dillo out_offset_array--;
1645 1.1 dillo do
1646 1.1 dillo {
1647 1.1 dillo out_offset_array++;
1648 1.1 dillo *out_offset_array = be16tohp(&ptr);
1649 1.1 dillo }
1650 1.1 dillo while(*out_offset_array != (uint16_t)14);
1651 1.1 dillo
1652 1.1 dillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
1653 1.1 dillo }
1654 1.1 dillo
1655 1.2 dillo /* hfslib_read_header_node()
1656 1.1 dillo *
1657 1.1 dillo * out_header_record and/or out_map_record may be NULL if the caller doesn't
1658 1.1 dillo * care about their contents.
1659 1.1 dillo */
1660 1.1 dillo size_t
1661 1.2 dillo hfslib_read_header_node(void** in_recs,
1662 1.1 dillo uint16_t* in_rec_sizes,
1663 1.1 dillo uint16_t in_num_recs,
1664 1.2 dillo hfs_header_record_t* out_hr,
1665 1.1 dillo void* out_userdata,
1666 1.1 dillo void* out_map)
1667 1.1 dillo {
1668 1.1 dillo void* ptr;
1669 1.1 dillo int i;
1670 1.11 joerg
1671 1.11 joerg KASSERT(out_hr != NULL);
1672 1.11 joerg
1673 1.1 dillo if(in_recs==NULL || in_rec_sizes==NULL)
1674 1.1 dillo return 0;
1675 1.1 dillo
1676 1.11 joerg ptr = in_recs[0];
1677 1.11 joerg out_hr->tree_depth = be16tohp(&ptr);
1678 1.11 joerg out_hr->root_node = be32tohp(&ptr);
1679 1.11 joerg out_hr->leaf_recs = be32tohp(&ptr);
1680 1.11 joerg out_hr->first_leaf = be32tohp(&ptr);
1681 1.11 joerg out_hr->last_leaf = be32tohp(&ptr);
1682 1.11 joerg out_hr->node_size = be16tohp(&ptr);
1683 1.11 joerg out_hr->max_key_len = be16tohp(&ptr);
1684 1.11 joerg out_hr->total_nodes = be32tohp(&ptr);
1685 1.11 joerg out_hr->free_nodes = be32tohp(&ptr);
1686 1.11 joerg out_hr->reserved = be16tohp(&ptr);
1687 1.11 joerg out_hr->clump_size = be32tohp(&ptr);
1688 1.11 joerg out_hr->btree_type = *(((uint8_t*)ptr));
1689 1.11 joerg ptr = (uint8_t*)ptr + 1;
1690 1.11 joerg out_hr->keycomp_type = *(((uint8_t*)ptr));
1691 1.11 joerg ptr = (uint8_t*)ptr + 1;
1692 1.11 joerg out_hr->attributes = be32tohp(&ptr);
1693 1.11 joerg for(i=0;i<16;i++)
1694 1.11 joerg out_hr->reserved2[i] = be32tohp(&ptr);
1695 1.11 joerg
1696 1.1 dillo if(out_userdata!=NULL)
1697 1.1 dillo {
1698 1.1 dillo memcpy(out_userdata, in_recs[1], in_rec_sizes[1]);
1699 1.1 dillo }
1700 1.1 dillo ptr = (uint8_t*)ptr + in_rec_sizes[1]; /* size of user data record */
1701 1.1 dillo
1702 1.1 dillo if(out_map!=NULL)
1703 1.1 dillo {
1704 1.1 dillo memcpy(out_map, in_recs[2], in_rec_sizes[2]);
1705 1.1 dillo }
1706 1.1 dillo ptr = (uint8_t*)ptr + in_rec_sizes[2]; /* size of map record */
1707 1.1 dillo
1708 1.1 dillo return ((uint8_t*)ptr - (uint8_t*)in_recs[0]);
1709 1.1 dillo }
1710 1.1 dillo
1711 1.1 dillo /*
1712 1.2 dillo * hfslib_read_catalog_keyed_record()
1713 1.1 dillo *
1714 1.2 dillo * out_recdata can be NULL. inout_rectype must be set to either HFS_LEAFNODE
1715 1.2 dillo * or HFS_INDEXNODE upon calling this function, and will be set by the
1716 1.2 dillo * function to one of HFS_REC_FLDR, HFS_REC_FILE, HFS_REC_FLDR_THREAD, or
1717 1.2 dillo * HFS_REC_FLDR_THREAD upon return if the node is a leaf node. If it is an
1718 1.1 dillo * index node, inout_rectype will not be changed.
1719 1.1 dillo */
1720 1.1 dillo size_t
1721 1.2 dillo hfslib_read_catalog_keyed_record(
1722 1.1 dillo void* in_bytes,
1723 1.2 dillo hfs_catalog_keyed_record_t* out_recdata,
1724 1.1 dillo int16_t* inout_rectype,
1725 1.2 dillo hfs_catalog_key_t* out_key,
1726 1.2 dillo hfs_volume* in_volume)
1727 1.1 dillo {
1728 1.1 dillo void* ptr;
1729 1.1 dillo size_t last_bytes_read;
1730 1.1 dillo
1731 1.1 dillo if(in_bytes==NULL || out_key==NULL || inout_rectype==NULL)
1732 1.1 dillo return 0;
1733 1.1 dillo
1734 1.1 dillo ptr = in_bytes;
1735 1.1 dillo
1736 1.1 dillo /* For HFS+, the key length is always a 2-byte number. This is indicated
1737 1.2 dillo * by the HFS_BIG_KEYS_MASK bit in the attributes field of the catalog
1738 1.1 dillo * header record. However, we just assume this bit is set, since all HFS+
1739 1.1 dillo * volumes should have it set anyway. */
1740 1.1 dillo if(in_volume->catkeysizefieldsize == sizeof(uint16_t))
1741 1.1 dillo out_key->key_len = be16tohp(&ptr);
1742 1.1 dillo else if (in_volume->catkeysizefieldsize == sizeof(uint8_t)) {
1743 1.1 dillo out_key->key_len = *(((uint8_t*)ptr));
1744 1.1 dillo ptr = (uint8_t*)ptr + 1;
1745 1.1 dillo }
1746 1.1 dillo
1747 1.1 dillo out_key->parent_cnid = be32tohp(&ptr);
1748 1.1 dillo
1749 1.2 dillo last_bytes_read = hfslib_read_unistr255(ptr, &out_key->name);
1750 1.1 dillo if(last_bytes_read==0)
1751 1.1 dillo return 0;
1752 1.1 dillo ptr = (uint8_t*)ptr + last_bytes_read;
1753 1.1 dillo
1754 1.1 dillo /* don't waste time if the user just wanted the key and/or record type */
1755 1.1 dillo if(out_recdata==NULL)
1756 1.1 dillo {
1757 1.2 dillo if(*inout_rectype == HFS_LEAFNODE)
1758 1.1 dillo *inout_rectype = be16tohp(&ptr);
1759 1.2 dillo else if(*inout_rectype != HFS_INDEXNODE)
1760 1.1 dillo return 0; /* should not happen if we were given valid arguments */
1761 1.1 dillo
1762 1.1 dillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
1763 1.1 dillo }
1764 1.1 dillo
1765 1.2 dillo if(*inout_rectype == HFS_INDEXNODE)
1766 1.1 dillo {
1767 1.1 dillo out_recdata->child = be32tohp(&ptr);
1768 1.1 dillo }
1769 1.1 dillo else
1770 1.1 dillo {
1771 1.1 dillo /* first need to determine what kind of record this is */
1772 1.1 dillo *inout_rectype = be16tohp(&ptr);
1773 1.1 dillo out_recdata->type = *inout_rectype;
1774 1.1 dillo
1775 1.1 dillo switch(out_recdata->type)
1776 1.1 dillo {
1777 1.2 dillo case HFS_REC_FLDR:
1778 1.1 dillo {
1779 1.1 dillo out_recdata->folder.flags = be16tohp(&ptr);
1780 1.1 dillo out_recdata->folder.valence = be32tohp(&ptr);
1781 1.1 dillo out_recdata->folder.cnid = be32tohp(&ptr);
1782 1.1 dillo out_recdata->folder.date_created = be32tohp(&ptr);
1783 1.1 dillo out_recdata->folder.date_content_mod = be32tohp(&ptr);
1784 1.1 dillo out_recdata->folder.date_attrib_mod = be32tohp(&ptr);
1785 1.1 dillo out_recdata->folder.date_accessed = be32tohp(&ptr);
1786 1.1 dillo out_recdata->folder.date_backedup = be32tohp(&ptr);
1787 1.1 dillo
1788 1.2 dillo last_bytes_read = hfslib_read_bsd_data(ptr,
1789 1.1 dillo &out_recdata->folder.bsd);
1790 1.1 dillo if(last_bytes_read==0)
1791 1.1 dillo return 0;
1792 1.1 dillo ptr = (uint8_t*)ptr + last_bytes_read;
1793 1.1 dillo
1794 1.2 dillo last_bytes_read = hfslib_read_folder_userinfo(ptr,
1795 1.1 dillo &out_recdata->folder.user_info);
1796 1.1 dillo if(last_bytes_read==0)
1797 1.1 dillo return 0;
1798 1.1 dillo ptr = (uint8_t*)ptr + last_bytes_read;
1799 1.1 dillo
1800 1.2 dillo last_bytes_read = hfslib_read_folder_finderinfo(ptr,
1801 1.1 dillo &out_recdata->folder.finder_info);
1802 1.1 dillo if(last_bytes_read==0)
1803 1.1 dillo return 0;
1804 1.1 dillo ptr = (uint8_t*)ptr + last_bytes_read;
1805 1.1 dillo
1806 1.1 dillo out_recdata->folder.text_encoding = be32tohp(&ptr);
1807 1.1 dillo out_recdata->folder.reserved = be32tohp(&ptr);
1808 1.1 dillo }
1809 1.1 dillo break;
1810 1.1 dillo
1811 1.2 dillo case HFS_REC_FILE:
1812 1.1 dillo {
1813 1.1 dillo out_recdata->file.flags = be16tohp(&ptr);
1814 1.1 dillo out_recdata->file.reserved = be32tohp(&ptr);
1815 1.1 dillo out_recdata->file.cnid = be32tohp(&ptr);
1816 1.1 dillo out_recdata->file.date_created = be32tohp(&ptr);
1817 1.1 dillo out_recdata->file.date_content_mod = be32tohp(&ptr);
1818 1.1 dillo out_recdata->file.date_attrib_mod = be32tohp(&ptr);
1819 1.1 dillo out_recdata->file.date_accessed = be32tohp(&ptr);
1820 1.1 dillo out_recdata->file.date_backedup = be32tohp(&ptr);
1821 1.1 dillo
1822 1.2 dillo last_bytes_read = hfslib_read_bsd_data(ptr,
1823 1.1 dillo &out_recdata->file.bsd);
1824 1.1 dillo if(last_bytes_read==0)
1825 1.1 dillo return 0;
1826 1.1 dillo ptr = (uint8_t*)ptr + last_bytes_read;
1827 1.1 dillo
1828 1.2 dillo last_bytes_read = hfslib_read_file_userinfo(ptr,
1829 1.1 dillo &out_recdata->file.user_info);
1830 1.1 dillo if(last_bytes_read==0)
1831 1.1 dillo return 0;
1832 1.1 dillo ptr = (uint8_t*)ptr + last_bytes_read;
1833 1.1 dillo
1834 1.2 dillo last_bytes_read = hfslib_read_file_finderinfo(ptr,
1835 1.1 dillo &out_recdata->file.finder_info);
1836 1.1 dillo if(last_bytes_read==0)
1837 1.1 dillo return 0;
1838 1.1 dillo ptr = (uint8_t*)ptr + last_bytes_read;
1839 1.1 dillo
1840 1.1 dillo out_recdata->file.text_encoding = be32tohp(&ptr);
1841 1.1 dillo out_recdata->file.reserved2 = be32tohp(&ptr);
1842 1.1 dillo
1843 1.2 dillo last_bytes_read = hfslib_read_fork_descriptor(ptr,
1844 1.1 dillo &out_recdata->file.data_fork);
1845 1.1 dillo if(last_bytes_read==0)
1846 1.1 dillo return 0;
1847 1.1 dillo ptr = (uint8_t*)ptr + last_bytes_read;
1848 1.1 dillo
1849 1.2 dillo last_bytes_read = hfslib_read_fork_descriptor(ptr,
1850 1.1 dillo &out_recdata->file.rsrc_fork);
1851 1.1 dillo if(last_bytes_read==0)
1852 1.1 dillo return 0;
1853 1.1 dillo ptr = (uint8_t*)ptr + last_bytes_read;
1854 1.1 dillo }
1855 1.1 dillo break;
1856 1.1 dillo
1857 1.2 dillo case HFS_REC_FLDR_THREAD:
1858 1.2 dillo case HFS_REC_FILE_THREAD:
1859 1.1 dillo {
1860 1.1 dillo out_recdata->thread.reserved = be16tohp(&ptr);
1861 1.1 dillo out_recdata->thread.parent_cnid = be32tohp(&ptr);
1862 1.1 dillo
1863 1.2 dillo last_bytes_read = hfslib_read_unistr255(ptr,
1864 1.1 dillo &out_recdata->thread.name);
1865 1.1 dillo if(last_bytes_read==0)
1866 1.1 dillo return 0;
1867 1.1 dillo ptr = (uint8_t*)ptr + last_bytes_read;
1868 1.1 dillo }
1869 1.1 dillo break;
1870 1.1 dillo
1871 1.1 dillo default:
1872 1.1 dillo return 1;
1873 1.1 dillo /* NOTREACHED */
1874 1.1 dillo }
1875 1.1 dillo }
1876 1.1 dillo
1877 1.1 dillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
1878 1.1 dillo }
1879 1.1 dillo
1880 1.1 dillo /* out_rec may be NULL */
1881 1.1 dillo size_t
1882 1.2 dillo hfslib_read_extent_record(
1883 1.1 dillo void* in_bytes,
1884 1.2 dillo hfs_extent_record_t* out_rec,
1885 1.2 dillo hfs_node_kind in_nodekind,
1886 1.2 dillo hfs_extent_key_t* out_key,
1887 1.2 dillo hfs_volume* in_volume)
1888 1.1 dillo {
1889 1.1 dillo void* ptr;
1890 1.1 dillo size_t last_bytes_read;
1891 1.1 dillo
1892 1.1 dillo if(in_bytes==NULL || out_key==NULL
1893 1.2 dillo || (in_nodekind!=HFS_LEAFNODE && in_nodekind!=HFS_INDEXNODE))
1894 1.1 dillo return 0;
1895 1.1 dillo
1896 1.1 dillo ptr = in_bytes;
1897 1.1 dillo
1898 1.1 dillo /* For HFS+, the key length is always a 2-byte number. This is indicated
1899 1.2 dillo * by the HFS_BIG_KEYS_MASK bit in the attributes field of the extent
1900 1.1 dillo * overflow header record. However, we just assume this bit is set, since
1901 1.1 dillo * all HFS+ volumes should have it set anyway. */
1902 1.1 dillo if(in_volume->extkeysizefieldsize == sizeof(uint16_t))
1903 1.1 dillo out_key->key_length = be16tohp(&ptr);
1904 1.1 dillo else if (in_volume->extkeysizefieldsize == sizeof(uint8_t)) {
1905 1.1 dillo out_key->key_length = *(((uint8_t*)ptr));
1906 1.1 dillo ptr = (uint8_t*)ptr + 1;
1907 1.1 dillo }
1908 1.1 dillo
1909 1.1 dillo out_key->fork_type = *(((uint8_t*)ptr));
1910 1.1 dillo ptr = (uint8_t*)ptr + 1;
1911 1.1 dillo out_key->padding = *(((uint8_t*)ptr));
1912 1.1 dillo ptr = (uint8_t*)ptr + 1;
1913 1.1 dillo out_key->file_cnid = be32tohp(&ptr);
1914 1.1 dillo out_key->start_block = be32tohp(&ptr);
1915 1.1 dillo
1916 1.1 dillo /* don't waste time if the user just wanted the key */
1917 1.1 dillo if(out_rec==NULL)
1918 1.1 dillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
1919 1.1 dillo
1920 1.2 dillo if(in_nodekind==HFS_LEAFNODE)
1921 1.1 dillo {
1922 1.2 dillo last_bytes_read = hfslib_read_extent_descriptors(ptr, out_rec);
1923 1.1 dillo if(last_bytes_read==0)
1924 1.1 dillo return 0;
1925 1.1 dillo ptr = (uint8_t*)ptr + last_bytes_read;
1926 1.1 dillo }
1927 1.1 dillo else
1928 1.1 dillo {
1929 1.1 dillo /* XXX: this is completely bogus */
1930 1.1 dillo /* (uint32_t*)*out_rec = be32tohp(&ptr); */
1931 1.1 dillo uint32_t *ptr_32 = (uint32_t *)out_rec;
1932 1.1 dillo *ptr_32 = be32tohp(&ptr);
1933 1.1 dillo /* (*out_rec)[0].start_block = be32tohp(&ptr); */
1934 1.1 dillo }
1935 1.1 dillo
1936 1.1 dillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
1937 1.1 dillo }
1938 1.1 dillo
1939 1.1 dillo void
1940 1.2 dillo hfslib_free_recs(
1941 1.1 dillo void*** inout_node_recs,
1942 1.1 dillo uint16_t** inout_rec_sizes,
1943 1.1 dillo uint16_t* inout_num_recs,
1944 1.2 dillo hfs_callback_args* cbargs)
1945 1.1 dillo {
1946 1.1 dillo uint16_t i;
1947 1.1 dillo
1948 1.1 dillo if(inout_num_recs==NULL || *inout_num_recs==0)
1949 1.1 dillo return;
1950 1.1 dillo
1951 1.1 dillo if(inout_node_recs!=NULL && *inout_node_recs!=NULL)
1952 1.1 dillo {
1953 1.1 dillo for(i=0;i<*inout_num_recs;i++)
1954 1.1 dillo {
1955 1.1 dillo if((*inout_node_recs)[i]!=NULL)
1956 1.1 dillo {
1957 1.2 dillo hfslib_free((*inout_node_recs)[i], cbargs);
1958 1.1 dillo (*inout_node_recs)[i] = NULL;
1959 1.1 dillo }
1960 1.1 dillo }
1961 1.1 dillo
1962 1.2 dillo hfslib_free(*inout_node_recs, cbargs);
1963 1.1 dillo *inout_node_recs = NULL;
1964 1.1 dillo }
1965 1.1 dillo
1966 1.1 dillo if(inout_rec_sizes!=NULL && *inout_rec_sizes!=NULL)
1967 1.1 dillo {
1968 1.2 dillo hfslib_free(*inout_rec_sizes, cbargs);
1969 1.1 dillo *inout_rec_sizes = NULL;
1970 1.1 dillo }
1971 1.1 dillo
1972 1.1 dillo *inout_num_recs = 0;
1973 1.1 dillo }
1974 1.1 dillo
1975 1.1 dillo #if 0
1976 1.1 dillo #pragma mark -
1977 1.1 dillo #pragma mark Individual Fields
1978 1.1 dillo #endif
1979 1.1 dillo
1980 1.1 dillo size_t
1981 1.2 dillo hfslib_read_fork_descriptor(void* in_bytes, hfs_fork_t* out_forkdata)
1982 1.1 dillo {
1983 1.1 dillo void* ptr;
1984 1.1 dillo size_t last_bytes_read;
1985 1.1 dillo
1986 1.1 dillo if(in_bytes==NULL || out_forkdata==NULL)
1987 1.1 dillo return 0;
1988 1.1 dillo
1989 1.1 dillo ptr = in_bytes;
1990 1.1 dillo
1991 1.1 dillo out_forkdata->logical_size = be64tohp(&ptr);
1992 1.1 dillo out_forkdata->clump_size = be32tohp(&ptr);
1993 1.1 dillo out_forkdata->total_blocks = be32tohp(&ptr);
1994 1.1 dillo
1995 1.2 dillo if((last_bytes_read = hfslib_read_extent_descriptors(ptr,
1996 1.1 dillo &out_forkdata->extents))==0)
1997 1.1 dillo return 0;
1998 1.1 dillo ptr = (uint8_t*)ptr + last_bytes_read;
1999 1.1 dillo
2000 1.1 dillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
2001 1.1 dillo }
2002 1.1 dillo
2003 1.1 dillo size_t
2004 1.2 dillo hfslib_read_extent_descriptors(
2005 1.1 dillo void* in_bytes,
2006 1.2 dillo hfs_extent_record_t* out_extentrecord)
2007 1.1 dillo {
2008 1.1 dillo void* ptr;
2009 1.1 dillo int i;
2010 1.1 dillo
2011 1.1 dillo if(in_bytes==NULL || out_extentrecord==NULL)
2012 1.1 dillo return 0;
2013 1.1 dillo
2014 1.1 dillo ptr = in_bytes;
2015 1.1 dillo
2016 1.1 dillo for(i=0;i<8;i++)
2017 1.1 dillo {
2018 1.2 dillo (((hfs_extent_descriptor_t*)*out_extentrecord)[i]).start_block =
2019 1.1 dillo be32tohp(&ptr);
2020 1.2 dillo (((hfs_extent_descriptor_t*)*out_extentrecord)[i]).block_count =
2021 1.1 dillo be32tohp(&ptr);
2022 1.1 dillo }
2023 1.1 dillo
2024 1.1 dillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
2025 1.1 dillo }
2026 1.1 dillo
2027 1.1 dillo size_t
2028 1.2 dillo hfslib_read_unistr255(void* in_bytes, hfs_unistr255_t* out_string)
2029 1.1 dillo {
2030 1.1 dillo void* ptr;
2031 1.1 dillo uint16_t i, length;
2032 1.1 dillo
2033 1.1 dillo if(in_bytes==NULL || out_string==NULL)
2034 1.1 dillo return 0;
2035 1.1 dillo
2036 1.1 dillo ptr = in_bytes;
2037 1.1 dillo
2038 1.1 dillo length = be16tohp(&ptr);
2039 1.1 dillo if(length>255)
2040 1.1 dillo length = 255; /* hfs+ folder/file names have a limit of 255 chars */
2041 1.1 dillo out_string->length = length;
2042 1.1 dillo
2043 1.1 dillo for(i=0; i<length; i++)
2044 1.1 dillo {
2045 1.1 dillo out_string->unicode[i] = be16tohp(&ptr);
2046 1.1 dillo }
2047 1.1 dillo
2048 1.1 dillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
2049 1.1 dillo }
2050 1.1 dillo
2051 1.1 dillo size_t
2052 1.2 dillo hfslib_read_bsd_data(void* in_bytes, hfs_bsd_data_t* out_perms)
2053 1.1 dillo {
2054 1.1 dillo void* ptr;
2055 1.1 dillo
2056 1.1 dillo if(in_bytes==NULL || out_perms==NULL)
2057 1.1 dillo return 0;
2058 1.1 dillo
2059 1.1 dillo ptr = in_bytes;
2060 1.1 dillo
2061 1.1 dillo out_perms->owner_id = be32tohp(&ptr);
2062 1.1 dillo out_perms->group_id = be32tohp(&ptr);
2063 1.1 dillo out_perms->admin_flags = *(((uint8_t*)ptr));
2064 1.1 dillo ptr = (uint8_t*)ptr + 1;
2065 1.1 dillo out_perms->owner_flags = *(((uint8_t*)ptr));
2066 1.1 dillo ptr = (uint8_t*)ptr + 1;
2067 1.1 dillo out_perms->file_mode = be16tohp(&ptr);
2068 1.1 dillo out_perms->special.inode_num = be32tohp(&ptr); /* this field is a union */
2069 1.1 dillo
2070 1.1 dillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
2071 1.1 dillo }
2072 1.1 dillo
2073 1.1 dillo size_t
2074 1.2 dillo hfslib_read_file_userinfo(void* in_bytes, hfs_macos_file_info_t* out_info)
2075 1.1 dillo {
2076 1.1 dillo void* ptr;
2077 1.1 dillo
2078 1.1 dillo if(in_bytes==NULL || out_info==NULL)
2079 1.1 dillo return 0;
2080 1.1 dillo
2081 1.1 dillo ptr = in_bytes;
2082 1.1 dillo
2083 1.1 dillo out_info->file_type = be32tohp(&ptr);
2084 1.1 dillo out_info->file_creator = be32tohp(&ptr);
2085 1.1 dillo out_info->finder_flags = be16tohp(&ptr);
2086 1.1 dillo out_info->location.v = be16tohp(&ptr);
2087 1.1 dillo out_info->location.h = be16tohp(&ptr);
2088 1.1 dillo out_info->reserved = be16tohp(&ptr);
2089 1.1 dillo
2090 1.1 dillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
2091 1.1 dillo }
2092 1.1 dillo
2093 1.1 dillo size_t
2094 1.2 dillo hfslib_read_file_finderinfo(
2095 1.1 dillo void* in_bytes,
2096 1.2 dillo hfs_macos_extended_file_info_t* out_info)
2097 1.1 dillo {
2098 1.1 dillo void* ptr;
2099 1.1 dillo
2100 1.1 dillo if(in_bytes==NULL || out_info==NULL)
2101 1.1 dillo return 0;
2102 1.1 dillo
2103 1.1 dillo ptr = in_bytes;
2104 1.1 dillo
2105 1.1 dillo #if 0
2106 1.1 dillo #pragma warn Fill in with real code!
2107 1.1 dillo #endif
2108 1.1 dillo /* FIXME: Fill in with real code! */
2109 1.1 dillo memset(out_info, 0, sizeof(*out_info));
2110 1.2 dillo ptr = (uint8_t*)ptr + sizeof(hfs_macos_extended_file_info_t);
2111 1.1 dillo
2112 1.1 dillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
2113 1.1 dillo }
2114 1.1 dillo
2115 1.1 dillo size_t
2116 1.2 dillo hfslib_read_folder_userinfo(void* in_bytes, hfs_macos_folder_info_t* out_info)
2117 1.1 dillo {
2118 1.1 dillo void* ptr;
2119 1.1 dillo
2120 1.1 dillo if(in_bytes==NULL || out_info==NULL)
2121 1.1 dillo return 0;
2122 1.1 dillo
2123 1.1 dillo ptr = in_bytes;
2124 1.1 dillo
2125 1.1 dillo #if 0
2126 1.1 dillo #pragma warn Fill in with real code!
2127 1.1 dillo #endif
2128 1.1 dillo /* FIXME: Fill in with real code! */
2129 1.1 dillo memset(out_info, 0, sizeof(*out_info));
2130 1.2 dillo ptr = (uint8_t*)ptr + sizeof(hfs_macos_folder_info_t);
2131 1.1 dillo
2132 1.1 dillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
2133 1.1 dillo }
2134 1.1 dillo
2135 1.1 dillo size_t
2136 1.2 dillo hfslib_read_folder_finderinfo(
2137 1.1 dillo void* in_bytes,
2138 1.2 dillo hfs_macos_extended_folder_info_t* out_info)
2139 1.1 dillo {
2140 1.1 dillo void* ptr;
2141 1.1 dillo
2142 1.1 dillo if(in_bytes==NULL || out_info==NULL)
2143 1.1 dillo return 0;
2144 1.1 dillo
2145 1.1 dillo ptr = in_bytes;
2146 1.1 dillo
2147 1.1 dillo #if 0
2148 1.1 dillo #pragma warn Fill in with real code!
2149 1.1 dillo #endif
2150 1.1 dillo /* FIXME: Fill in with real code! */
2151 1.1 dillo memset(out_info, 0, sizeof(*out_info));
2152 1.2 dillo ptr = (uint8_t*)ptr + sizeof(hfs_macos_extended_folder_info_t);
2153 1.1 dillo
2154 1.1 dillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
2155 1.1 dillo }
2156 1.1 dillo
2157 1.1 dillo size_t
2158 1.2 dillo hfslib_read_journal_info(void* in_bytes, hfs_journal_info_t* out_info)
2159 1.1 dillo {
2160 1.1 dillo void* ptr;
2161 1.1 dillo int i;
2162 1.1 dillo
2163 1.1 dillo if(in_bytes==NULL || out_info==NULL)
2164 1.1 dillo return 0;
2165 1.1 dillo
2166 1.1 dillo ptr = in_bytes;
2167 1.1 dillo
2168 1.1 dillo out_info->flags = be32tohp(&ptr);
2169 1.1 dillo for(i=0; i<8; i++)
2170 1.1 dillo {
2171 1.1 dillo out_info->device_signature[i] = be32tohp(&ptr);
2172 1.1 dillo }
2173 1.1 dillo out_info->offset = be64tohp(&ptr);
2174 1.1 dillo out_info->size = be64tohp(&ptr);
2175 1.1 dillo for(i=0; i<32; i++)
2176 1.1 dillo {
2177 1.1 dillo out_info->reserved[i] = be64tohp(&ptr);
2178 1.1 dillo }
2179 1.1 dillo
2180 1.1 dillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
2181 1.1 dillo }
2182 1.1 dillo
2183 1.1 dillo size_t
2184 1.2 dillo hfslib_read_journal_header(void* in_bytes, hfs_journal_header_t* out_header)
2185 1.1 dillo {
2186 1.1 dillo void* ptr;
2187 1.1 dillo
2188 1.1 dillo if(in_bytes==NULL || out_header==NULL)
2189 1.1 dillo return 0;
2190 1.1 dillo
2191 1.1 dillo ptr = in_bytes;
2192 1.1 dillo
2193 1.1 dillo out_header->magic = be32tohp(&ptr);
2194 1.1 dillo out_header->endian = be32tohp(&ptr);
2195 1.1 dillo out_header->start = be64tohp(&ptr);
2196 1.1 dillo out_header->end = be64tohp(&ptr);
2197 1.1 dillo out_header->size = be64tohp(&ptr);
2198 1.1 dillo out_header->blocklist_header_size = be32tohp(&ptr);
2199 1.1 dillo out_header->checksum = be32tohp(&ptr);
2200 1.1 dillo out_header->journal_header_size = be32tohp(&ptr);
2201 1.1 dillo
2202 1.1 dillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
2203 1.1 dillo }
2204 1.1 dillo
2205 1.1 dillo #if 0
2206 1.1 dillo #pragma mark -
2207 1.1 dillo #pragma mark Disk Access
2208 1.1 dillo #endif
2209 1.1 dillo
2210 1.1 dillo /*
2211 1.2 dillo * hfslib_readd_with_extents()
2212 1.1 dillo *
2213 1.1 dillo * This function reads the contents of a file from the volume, given an array
2214 1.1 dillo * of extent descriptors which specify where every extent of the file is
2215 1.1 dillo * located (in addition to the usual pread() arguments). out_bytes is presumed
2216 1.1 dillo * to exist and be large enough to hold in_length number of bytes. Returns 0
2217 1.1 dillo * on success.
2218 1.1 dillo */
2219 1.1 dillo int
2220 1.2 dillo hfslib_readd_with_extents(
2221 1.2 dillo hfs_volume* in_vol,
2222 1.1 dillo void* out_bytes,
2223 1.1 dillo uint64_t* out_bytesread,
2224 1.1 dillo uint64_t in_length,
2225 1.1 dillo uint64_t in_offset,
2226 1.2 dillo hfs_extent_descriptor_t in_extents[],
2227 1.1 dillo uint16_t in_numextents,
2228 1.2 dillo hfs_callback_args* cbargs)
2229 1.1 dillo {
2230 1.1 dillo uint64_t ext_length, last_offset;
2231 1.1 dillo uint16_t i;
2232 1.1 dillo int error;
2233 1.1 dillo
2234 1.1 dillo if(in_vol==NULL || out_bytes==NULL || in_extents==NULL || in_numextents==0
2235 1.1 dillo || out_bytesread==NULL)
2236 1.1 dillo return -1;
2237 1.1 dillo
2238 1.1 dillo *out_bytesread = 0;
2239 1.1 dillo last_offset = 0;
2240 1.1 dillo
2241 1.1 dillo for(i=0; i<in_numextents; i++)
2242 1.1 dillo {
2243 1.1 dillo if(in_extents[i].block_count==0)
2244 1.1 dillo continue;
2245 1.1 dillo
2246 1.1 dillo ext_length = in_extents[i].block_count * in_vol->vh.block_size;
2247 1.1 dillo
2248 1.1 dillo if(in_offset < last_offset+ext_length
2249 1.1 dillo && in_offset+in_length >= last_offset)
2250 1.1 dillo {
2251 1.1 dillo uint64_t isect_start, isect_end;
2252 1.1 dillo
2253 1.1 dillo isect_start = max(in_offset, last_offset);
2254 1.1 dillo isect_end = min(in_offset+in_length, last_offset+ext_length);
2255 1.2 dillo error = hfslib_readd(in_vol, out_bytes, isect_end-isect_start,
2256 1.1 dillo isect_start - last_offset + (uint64_t)in_extents[i].start_block
2257 1.1 dillo * in_vol->vh.block_size, cbargs);
2258 1.1 dillo
2259 1.1 dillo if(error!=0)
2260 1.1 dillo return error;
2261 1.1 dillo
2262 1.1 dillo *out_bytesread += isect_end-isect_start;
2263 1.1 dillo out_bytes = (uint8_t*)out_bytes + isect_end-isect_start;
2264 1.1 dillo }
2265 1.1 dillo
2266 1.1 dillo last_offset += ext_length;
2267 1.1 dillo }
2268 1.1 dillo
2269 1.1 dillo
2270 1.1 dillo return 0;
2271 1.1 dillo }
2272 1.1 dillo
2273 1.1 dillo #if 0
2274 1.1 dillo #pragma mark -
2275 1.1 dillo #pragma mark Callback Wrappers
2276 1.1 dillo #endif
2277 1.1 dillo
2278 1.1 dillo void
2279 1.2 dillo hfslib_error(const char* in_format, const char* in_file, int in_line, ...)
2280 1.1 dillo {
2281 1.1 dillo va_list ap;
2282 1.1 dillo
2283 1.1 dillo if(in_format==NULL)
2284 1.1 dillo return;
2285 1.1 dillo
2286 1.2 dillo if(hfs_gcb.error!=NULL)
2287 1.1 dillo {
2288 1.1 dillo va_start(ap, in_line);
2289 1.1 dillo
2290 1.2 dillo hfs_gcb.error(in_format, in_file, in_line, ap);
2291 1.1 dillo
2292 1.1 dillo va_end(ap);
2293 1.1 dillo }
2294 1.1 dillo }
2295 1.1 dillo
2296 1.1 dillo void*
2297 1.2 dillo hfslib_malloc(size_t size, hfs_callback_args* cbargs)
2298 1.1 dillo {
2299 1.2 dillo if(hfs_gcb.allocmem!=NULL)
2300 1.2 dillo return hfs_gcb.allocmem(size, cbargs);
2301 1.1 dillo
2302 1.1 dillo return NULL;
2303 1.1 dillo }
2304 1.1 dillo
2305 1.1 dillo void*
2306 1.2 dillo hfslib_realloc(void* ptr, size_t size, hfs_callback_args* cbargs)
2307 1.1 dillo {
2308 1.2 dillo if(hfs_gcb.reallocmem!=NULL)
2309 1.2 dillo return hfs_gcb.reallocmem(ptr, size, cbargs);
2310 1.1 dillo
2311 1.1 dillo return NULL;
2312 1.1 dillo }
2313 1.1 dillo
2314 1.1 dillo void
2315 1.2 dillo hfslib_free(void* ptr, hfs_callback_args* cbargs)
2316 1.1 dillo {
2317 1.2 dillo if(hfs_gcb.freemem!=NULL && ptr!=NULL)
2318 1.2 dillo hfs_gcb.freemem(ptr, cbargs);
2319 1.1 dillo }
2320 1.1 dillo
2321 1.1 dillo int
2322 1.2 dillo hfslib_openvoldevice(
2323 1.2 dillo hfs_volume* in_vol,
2324 1.1 dillo const char* in_device,
2325 1.2 dillo hfs_callback_args* cbargs)
2326 1.1 dillo {
2327 1.2 dillo if(hfs_gcb.openvol!=NULL && in_device!=NULL)
2328 1.4 dillo return hfs_gcb.openvol(in_vol, in_device, cbargs);
2329 1.1 dillo
2330 1.1 dillo return 1;
2331 1.1 dillo }
2332 1.1 dillo
2333 1.1 dillo void
2334 1.2 dillo hfslib_closevoldevice(hfs_volume* in_vol, hfs_callback_args* cbargs)
2335 1.1 dillo {
2336 1.2 dillo if(hfs_gcb.closevol!=NULL)
2337 1.2 dillo hfs_gcb.closevol(in_vol, cbargs);
2338 1.1 dillo }
2339 1.1 dillo
2340 1.1 dillo int
2341 1.2 dillo hfslib_readd(
2342 1.2 dillo hfs_volume* in_vol,
2343 1.1 dillo void* out_bytes,
2344 1.1 dillo uint64_t in_length,
2345 1.1 dillo uint64_t in_offset,
2346 1.2 dillo hfs_callback_args* cbargs)
2347 1.1 dillo {
2348 1.1 dillo if(in_vol==NULL || out_bytes==NULL)
2349 1.1 dillo return -1;
2350 1.1 dillo
2351 1.2 dillo if(hfs_gcb.read!=NULL)
2352 1.2 dillo return hfs_gcb.read(in_vol, out_bytes, in_length, in_offset, cbargs);
2353 1.1 dillo
2354 1.1 dillo return -1;
2355 1.1 dillo }
2356 1.1 dillo
2357 1.1 dillo #if 0
2358 1.1 dillo #pragma mark -
2359 1.1 dillo #pragma mark Other
2360 1.1 dillo #endif
2361 1.1 dillo
2362 1.1 dillo /* returns key length */
2363 1.1 dillo uint16_t
2364 1.2 dillo hfslib_make_catalog_key(
2365 1.2 dillo hfs_cnid_t in_parent_cnid,
2366 1.1 dillo uint16_t in_name_len,
2367 1.1 dillo unichar_t* in_unicode,
2368 1.2 dillo hfs_catalog_key_t* out_key)
2369 1.1 dillo {
2370 1.1 dillo if(in_parent_cnid==0 || (in_name_len>0 && in_unicode==NULL) || out_key==0)
2371 1.1 dillo return 0;
2372 1.1 dillo
2373 1.1 dillo if(in_name_len>255)
2374 1.1 dillo in_name_len = 255;
2375 1.1 dillo
2376 1.1 dillo out_key->key_len = 6 + 2 * in_name_len;
2377 1.1 dillo out_key->parent_cnid = in_parent_cnid;
2378 1.1 dillo out_key->name.length = in_name_len;
2379 1.1 dillo if(in_name_len>0)
2380 1.1 dillo memcpy(&out_key->name.unicode, in_unicode, in_name_len*2);
2381 1.1 dillo
2382 1.1 dillo return out_key->key_len;
2383 1.1 dillo }
2384 1.1 dillo
2385 1.1 dillo /* returns key length */
2386 1.1 dillo uint16_t
2387 1.2 dillo hfslib_make_extent_key(
2388 1.2 dillo hfs_cnid_t in_cnid,
2389 1.1 dillo uint8_t in_forktype,
2390 1.1 dillo uint32_t in_startblock,
2391 1.2 dillo hfs_extent_key_t* out_key)
2392 1.1 dillo {
2393 1.1 dillo if(in_cnid==0 || out_key==0)
2394 1.1 dillo return 0;
2395 1.1 dillo
2396 1.2 dillo out_key->key_length = HFS_MAX_EXT_KEY_LEN;
2397 1.1 dillo out_key->fork_type = in_forktype;
2398 1.1 dillo out_key->padding = 0;
2399 1.1 dillo out_key->file_cnid = in_cnid;
2400 1.1 dillo out_key->start_block = in_startblock;
2401 1.1 dillo
2402 1.1 dillo return out_key->key_length;
2403 1.1 dillo }
2404 1.1 dillo
2405 1.1 dillo /* case-folding */
2406 1.1 dillo int
2407 1.2 dillo hfslib_compare_catalog_keys_cf (
2408 1.1 dillo const void *ap,
2409 1.1 dillo const void *bp)
2410 1.1 dillo {
2411 1.2 dillo const hfs_catalog_key_t *a, *b;
2412 1.1 dillo unichar_t ac, bc; /* current character from a, b */
2413 1.1 dillo unichar_t lc; /* lowercase version of current character */
2414 1.1 dillo uint8_t apos, bpos; /* current character indices */
2415 1.1 dillo
2416 1.2 dillo a = (const hfs_catalog_key_t*)ap;
2417 1.2 dillo b = (const hfs_catalog_key_t*)bp;
2418 1.1 dillo
2419 1.1 dillo if(a->parent_cnid != b->parent_cnid)
2420 1.1 dillo {
2421 1.1 dillo return (a->parent_cnid - b->parent_cnid);
2422 1.1 dillo }
2423 1.1 dillo else
2424 1.1 dillo {
2425 1.1 dillo /*
2426 1.1 dillo * The following code implements the pseudocode suggested by
2427 1.1 dillo * the HFS+ technote.
2428 1.1 dillo */
2429 1.1 dillo
2430 1.1 dillo /*
2431 1.1 dillo * XXX These need to be revised to be endian-independent!
2432 1.1 dillo */
2433 1.1 dillo #define hbyte(x) ((x) >> 8)
2434 1.1 dillo #define lbyte(x) ((x) & 0x00FF)
2435 1.1 dillo
2436 1.1 dillo apos = bpos = 0;
2437 1.1 dillo while(1)
2438 1.1 dillo {
2439 1.1 dillo /* get next valid character from a */
2440 1.1 dillo for (lc=0; lc == 0 && apos < a->name.length; apos++) {
2441 1.1 dillo ac = a->name.unicode[apos];
2442 1.2 dillo lc = hfs_gcft[hbyte(ac)];
2443 1.1 dillo if(lc==0)
2444 1.1 dillo lc = ac;
2445 1.1 dillo else
2446 1.2 dillo lc = hfs_gcft[lc + lbyte(ac)];
2447 1.1 dillo };
2448 1.1 dillo ac=lc;
2449 1.1 dillo
2450 1.1 dillo /* get next valid character from b */
2451 1.1 dillo for (lc=0; lc == 0 && bpos < b->name.length; bpos++) {
2452 1.1 dillo bc = b->name.unicode[bpos];
2453 1.2 dillo lc = hfs_gcft[hbyte(bc)];
2454 1.1 dillo if(lc==0)
2455 1.1 dillo lc = bc;
2456 1.1 dillo else
2457 1.2 dillo lc = hfs_gcft[lc + lbyte(bc)];
2458 1.1 dillo };
2459 1.1 dillo bc=lc;
2460 1.1 dillo
2461 1.1 dillo /* on end of string ac/bc are 0, otherwise > 0 */
2462 1.1 dillo if (ac != bc || (ac == 0 && bc == 0))
2463 1.1 dillo return ac - bc;
2464 1.1 dillo }
2465 1.1 dillo #undef hbyte
2466 1.1 dillo #undef lbyte
2467 1.1 dillo }
2468 1.1 dillo }
2469 1.1 dillo
2470 1.1 dillo /* binary compare (i.e., not case folding) */
2471 1.1 dillo int
2472 1.2 dillo hfslib_compare_catalog_keys_bc (
2473 1.1 dillo const void *a,
2474 1.1 dillo const void *b)
2475 1.1 dillo {
2476 1.2 dillo if(((const hfs_catalog_key_t*)a)->parent_cnid
2477 1.2 dillo == ((const hfs_catalog_key_t*)b)->parent_cnid)
2478 1.1 dillo {
2479 1.2 dillo if(((const hfs_catalog_key_t*)a)->name.length == 0 &&
2480 1.2 dillo ((const hfs_catalog_key_t*)b)->name.length == 0)
2481 1.1 dillo return 0;
2482 1.1 dillo
2483 1.2 dillo if(((const hfs_catalog_key_t*)a)->name.length == 0)
2484 1.1 dillo return -1;
2485 1.2 dillo if(((const hfs_catalog_key_t*)b)->name.length == 0)
2486 1.1 dillo return 1;
2487 1.1 dillo
2488 1.1 dillo /* FIXME: This does a byte-per-byte comparison, whereas the HFS spec
2489 1.1 dillo * mandates a uint16_t chunk comparison. */
2490 1.2 dillo return memcmp(((const hfs_catalog_key_t*)a)->name.unicode,
2491 1.2 dillo ((const hfs_catalog_key_t*)b)->name.unicode,
2492 1.2 dillo min(((const hfs_catalog_key_t*)a)->name.length,
2493 1.2 dillo ((const hfs_catalog_key_t*)b)->name.length));
2494 1.1 dillo }
2495 1.1 dillo else
2496 1.1 dillo {
2497 1.2 dillo return (((const hfs_catalog_key_t*)a)->parent_cnid -
2498 1.2 dillo ((const hfs_catalog_key_t*)b)->parent_cnid);
2499 1.1 dillo }
2500 1.1 dillo }
2501 1.1 dillo
2502 1.1 dillo int
2503 1.2 dillo hfslib_compare_extent_keys (
2504 1.1 dillo const void *a,
2505 1.1 dillo const void *b)
2506 1.1 dillo {
2507 1.1 dillo /*
2508 1.1 dillo * Comparison order, in descending importance:
2509 1.1 dillo *
2510 1.1 dillo * CNID -> fork type -> start block
2511 1.1 dillo */
2512 1.1 dillo
2513 1.2 dillo if(((const hfs_extent_key_t*)a)->file_cnid
2514 1.2 dillo == ((const hfs_extent_key_t*)b)->file_cnid)
2515 1.1 dillo {
2516 1.2 dillo if(((const hfs_extent_key_t*)a)->fork_type
2517 1.2 dillo == ((const hfs_extent_key_t*)b)->fork_type)
2518 1.1 dillo {
2519 1.2 dillo if(((const hfs_extent_key_t*)a)->start_block
2520 1.2 dillo == ((const hfs_extent_key_t*)b)->start_block)
2521 1.1 dillo {
2522 1.1 dillo return 0;
2523 1.1 dillo }
2524 1.1 dillo else
2525 1.1 dillo {
2526 1.2 dillo return (((const hfs_extent_key_t*)a)->start_block -
2527 1.2 dillo ((const hfs_extent_key_t*)b)->start_block);
2528 1.1 dillo }
2529 1.1 dillo }
2530 1.1 dillo else
2531 1.1 dillo {
2532 1.2 dillo return (((const hfs_extent_key_t*)a)->fork_type -
2533 1.2 dillo ((const hfs_extent_key_t*)b)->fork_type);
2534 1.1 dillo }
2535 1.1 dillo }
2536 1.1 dillo else
2537 1.1 dillo {
2538 1.2 dillo return (((const hfs_extent_key_t*)a)->file_cnid -
2539 1.2 dillo ((const hfs_extent_key_t*)b)->file_cnid);
2540 1.1 dillo }
2541 1.1 dillo }
2542 1.1 dillo
2543 1.1 dillo /* 1+10 tables of 16 rows and 16 columns, each 2 bytes wide = 5632 bytes */
2544 1.1 dillo int
2545 1.2 dillo hfslib_create_casefolding_table(void)
2546 1.1 dillo {
2547 1.2 dillo hfs_callback_args cbargs;
2548 1.1 dillo unichar_t* t; /* convenience */
2549 1.1 dillo uint16_t s; /* current subtable * 256 */
2550 1.1 dillo uint16_t i; /* current subtable index (0 to 255) */
2551 1.1 dillo
2552 1.2 dillo if(hfs_gcft!=NULL)
2553 1.1 dillo return 0; /* no sweat, table already exists */
2554 1.1 dillo
2555 1.2 dillo hfslib_init_cbargs(&cbargs);
2556 1.2 dillo hfs_gcft = hfslib_malloc(5632, &cbargs);
2557 1.2 dillo if(hfs_gcft==NULL)
2558 1.2 dillo HFS_LIBERR("could not allocate case folding table");
2559 1.1 dillo
2560 1.2 dillo t = hfs_gcft; /* easier to type :) */
2561 1.1 dillo
2562 1.1 dillo /*
2563 1.1 dillo * high byte indices
2564 1.1 dillo */
2565 1.1 dillo s = 0 * 256;
2566 1.1 dillo memset(t, 0x00, 512);
2567 1.1 dillo t[s+ 0] = 0x0100;
2568 1.1 dillo t[s+ 1] = 0x0200;
2569 1.1 dillo t[s+ 3] = 0x0300;
2570 1.1 dillo t[s+ 4] = 0x0400;
2571 1.1 dillo t[s+ 5] = 0x0500;
2572 1.1 dillo t[s+ 16] = 0x0600;
2573 1.1 dillo t[s+ 32] = 0x0700;
2574 1.1 dillo t[s+ 33] = 0x0800;
2575 1.1 dillo t[s+254] = 0x0900;
2576 1.1 dillo t[s+255] = 0x0a00;
2577 1.1 dillo
2578 1.1 dillo /*
2579 1.1 dillo * table 1 (high byte 0x00)
2580 1.1 dillo */
2581 1.1 dillo s = 1 * 256;
2582 1.1 dillo for(i=0; i<65; i++)
2583 1.1 dillo t[s+i] = i;
2584 1.1 dillo t[s+ 0] = 0xffff;
2585 1.1 dillo for(i=65; i<91; i++)
2586 1.1 dillo t[s+i] = i + 0x20;
2587 1.1 dillo for(i=91; i<256; i++)
2588 1.1 dillo t[s+i] = i;
2589 1.1 dillo t[s+198] = 0x00e6;
2590 1.1 dillo t[s+208] = 0x00f0;
2591 1.1 dillo t[s+216] = 0x00f8;
2592 1.1 dillo t[s+222] = 0x00fe;
2593 1.1 dillo
2594 1.1 dillo /*
2595 1.1 dillo * table 2 (high byte 0x01)
2596 1.1 dillo */
2597 1.1 dillo s = 2 * 256;
2598 1.1 dillo for(i=0; i<256; i++)
2599 1.1 dillo t[s+i] = i + 0x0100;
2600 1.1 dillo t[s+ 16] = 0x0111;
2601 1.1 dillo t[s+ 38] = 0x0127;
2602 1.1 dillo t[s+ 50] = 0x0133;
2603 1.1 dillo t[s+ 63] = 0x0140;
2604 1.1 dillo t[s+ 65] = 0x0142;
2605 1.1 dillo t[s+ 74] = 0x014b;
2606 1.1 dillo t[s+ 82] = 0x0153;
2607 1.1 dillo t[s+102] = 0x0167;
2608 1.1 dillo t[s+129] = 0x0253;
2609 1.1 dillo t[s+130] = 0x0183;
2610 1.1 dillo t[s+132] = 0x0185;
2611 1.1 dillo t[s+134] = 0x0254;
2612 1.1 dillo t[s+135] = 0x0188;
2613 1.1 dillo t[s+137] = 0x0256;
2614 1.1 dillo t[s+138] = 0x0257;
2615 1.1 dillo t[s+139] = 0x018c;
2616 1.1 dillo t[s+142] = 0x01dd;
2617 1.1 dillo t[s+143] = 0x0259;
2618 1.1 dillo t[s+144] = 0x025b;
2619 1.1 dillo t[s+145] = 0x0192;
2620 1.1 dillo t[s+147] = 0x0260;
2621 1.1 dillo t[s+148] = 0x0263;
2622 1.1 dillo t[s+150] = 0x0269;
2623 1.1 dillo t[s+151] = 0x0268;
2624 1.1 dillo t[s+152] = 0x0199;
2625 1.1 dillo t[s+156] = 0x026f;
2626 1.1 dillo t[s+157] = 0x0272;
2627 1.1 dillo t[s+159] = 0x0275;
2628 1.1 dillo t[s+162] = 0x01a3;
2629 1.1 dillo t[s+164] = 0x01a5;
2630 1.1 dillo t[s+167] = 0x01a8;
2631 1.1 dillo t[s+169] = 0x0283;
2632 1.1 dillo t[s+172] = 0x01ad;
2633 1.1 dillo t[s+174] = 0x0288;
2634 1.1 dillo t[s+177] = 0x028a;
2635 1.1 dillo t[s+178] = 0x028b;
2636 1.1 dillo t[s+179] = 0x01b4;
2637 1.1 dillo t[s+181] = 0x01b6;
2638 1.1 dillo t[s+183] = 0x0292;
2639 1.1 dillo t[s+184] = 0x01b9;
2640 1.1 dillo t[s+188] = 0x01bd;
2641 1.1 dillo t[s+196] = 0x01c6;
2642 1.1 dillo t[s+197] = 0x01c6;
2643 1.1 dillo t[s+199] = 0x01c9;
2644 1.1 dillo t[s+200] = 0x01c9;
2645 1.1 dillo t[s+202] = 0x01cc;
2646 1.1 dillo t[s+203] = 0x01cc;
2647 1.1 dillo t[s+228] = 0x01e5;
2648 1.1 dillo t[s+241] = 0x01f3;
2649 1.1 dillo t[s+242] = 0x01f3;
2650 1.1 dillo
2651 1.1 dillo /*
2652 1.1 dillo * table 3 (high byte 0x03)
2653 1.1 dillo */
2654 1.1 dillo s = 3 * 256;
2655 1.1 dillo for(i=0; i<145; i++)
2656 1.1 dillo t[s+i] = i + 0x0300;
2657 1.1 dillo for(i=145; i<170; i++)
2658 1.1 dillo t[s+i] = i + 0x0320;
2659 1.1 dillo t[s+162] = 0x03a2;
2660 1.1 dillo for(i=170; i<256; i++)
2661 1.1 dillo t[s+i] = i + 0x0300;
2662 1.1 dillo
2663 1.1 dillo for(i=226; i<239; i+=2)
2664 1.1 dillo t[s+i] = i + 0x0301;
2665 1.1 dillo
2666 1.1 dillo /*
2667 1.1 dillo * table 4 (high byte 0x04)
2668 1.1 dillo */
2669 1.1 dillo s = 4 * 256;
2670 1.1 dillo for(i=0; i<16; i++)
2671 1.1 dillo t[s+i] = i + 0x0400;
2672 1.1 dillo t[s+ 2] = 0x0452;
2673 1.1 dillo t[s+ 4] = 0x0454;
2674 1.1 dillo t[s+ 5] = 0x0455;
2675 1.1 dillo t[s+ 6] = 0x0456;
2676 1.1 dillo t[s+ 8] = 0x0458;
2677 1.1 dillo t[s+ 9] = 0x0459;
2678 1.1 dillo t[s+ 10] = 0x045a;
2679 1.1 dillo t[s+ 11] = 0x045b;
2680 1.1 dillo t[s+ 15] = 0x045f;
2681 1.1 dillo
2682 1.1 dillo for(i=16; i<48; i++)
2683 1.1 dillo t[s+i] = i + 0x0420;
2684 1.1 dillo t[s+ 25] = 0x0419;
2685 1.1 dillo for(i=48; i<256; i++)
2686 1.1 dillo t[s+i] = i + 0x0400;
2687 1.1 dillo t[s+195] = 0x04c4;
2688 1.1 dillo t[s+199] = 0x04c8;
2689 1.1 dillo t[s+203] = 0x04cc;
2690 1.1 dillo
2691 1.1 dillo for(i=96; i<129; i+=2)
2692 1.1 dillo t[s+i] = i + 0x0401;
2693 1.1 dillo t[s+118] = 0x0476;
2694 1.1 dillo for(i=144; i<191; i+=2)
2695 1.1 dillo t[s+i] = i + 0x0401;
2696 1.1 dillo
2697 1.1 dillo /*
2698 1.1 dillo * table 5 (high byte 0x05)
2699 1.1 dillo */
2700 1.1 dillo s = 5 * 256;
2701 1.1 dillo for(i=0; i<49; i++)
2702 1.1 dillo t[s+i] = i + 0x0500;
2703 1.1 dillo for(i=49; i<87; i++)
2704 1.1 dillo t[s+i] = i + 0x0530;
2705 1.1 dillo for(i=87; i<256; i++)
2706 1.1 dillo t[s+i] = i + 0x0500;
2707 1.1 dillo
2708 1.1 dillo /*
2709 1.1 dillo * table 6 (high byte 0x10)
2710 1.1 dillo */
2711 1.1 dillo s = 6 * 256;
2712 1.1 dillo for(i=0; i<160; i++)
2713 1.1 dillo t[s+i] = i + 0x1000;
2714 1.1 dillo for(i=160; i<198; i++)
2715 1.1 dillo t[s+i] = i + 0x1030;
2716 1.1 dillo for(i=198; i<256; i++)
2717 1.1 dillo t[s+i] = i + 0x1000;
2718 1.1 dillo
2719 1.1 dillo /*
2720 1.1 dillo * table 7 (high byte 0x20)
2721 1.1 dillo */
2722 1.1 dillo s = 7 * 256;
2723 1.1 dillo for(i=0; i<256; i++)
2724 1.1 dillo t[s+i] = i + 0x2000;
2725 1.1 dillo {
2726 1.1 dillo uint8_t zi[15] = { 12, 13, 14, 15,
2727 1.1 dillo 42, 43, 44, 45, 46,
2728 1.1 dillo 106, 107, 108, 109, 110, 111};
2729 1.1 dillo
2730 1.1 dillo for(i=0; i<15; i++)
2731 1.1 dillo t[s+zi[i]] = 0x0000;
2732 1.1 dillo }
2733 1.1 dillo
2734 1.1 dillo /*
2735 1.1 dillo * table 8 (high byte 0x21)
2736 1.1 dillo */
2737 1.1 dillo s = 8 * 256;
2738 1.1 dillo for(i=0; i<96; i++)
2739 1.1 dillo t[s+i] = i + 0x2100;
2740 1.1 dillo for(i=96; i<112; i++)
2741 1.1 dillo t[s+i] = i + 0x2110;
2742 1.1 dillo for(i=112; i<256; i++)
2743 1.1 dillo t[s+i] = i + 0x2100;
2744 1.1 dillo
2745 1.1 dillo /*
2746 1.1 dillo * table 9 (high byte 0xFE)
2747 1.1 dillo */
2748 1.1 dillo s = 9 * 256;
2749 1.1 dillo for(i=0; i<256; i++)
2750 1.1 dillo t[s+i] = i + 0xFE00;
2751 1.1 dillo t[s+255] = 0x0000;
2752 1.1 dillo
2753 1.1 dillo /*
2754 1.1 dillo * table 10 (high byte 0xFF)
2755 1.1 dillo */
2756 1.1 dillo s = 10 * 256;
2757 1.1 dillo for(i=0; i<33; i++)
2758 1.1 dillo t[s+i] = i + 0xFF00;
2759 1.1 dillo for(i=33; i<59; i++)
2760 1.1 dillo t[s+i] = i + 0xFF20;
2761 1.1 dillo for(i=59; i<256; i++)
2762 1.1 dillo t[s+i] = i + 0xFF00;
2763 1.1 dillo
2764 1.1 dillo return 0;
2765 1.1 dillo
2766 1.1 dillo error:
2767 1.1 dillo return 1;
2768 1.1 dillo }
2769 1.1 dillo
2770 1.1 dillo int
2771 1.2 dillo hfslib_get_hardlink(hfs_volume *vol, uint32_t inode_num,
2772 1.2 dillo hfs_catalog_keyed_record_t *rec,
2773 1.2 dillo hfs_callback_args *cbargs)
2774 1.1 dillo {
2775 1.2 dillo hfs_catalog_keyed_record_t metadata;
2776 1.2 dillo hfs_catalog_key_t key;
2777 1.1 dillo char name[16];
2778 1.1 dillo unichar_t name_uni[16];
2779 1.1 dillo int i, len;
2780 1.1 dillo
2781 1.1 dillo /* XXX: cache this */
2782 1.2 dillo if (hfslib_find_catalog_record_with_key(vol,
2783 1.2 dillo &hfs_gMetadataDirectoryKey,
2784 1.1 dillo &metadata, cbargs) != 0
2785 1.2 dillo || metadata.type != HFS_REC_FLDR)
2786 1.1 dillo return -1;
2787 1.1 dillo
2788 1.1 dillo len = snprintf(name, sizeof(name), "iNode%d", inode_num);
2789 1.1 dillo for (i=0; i<len; i++)
2790 1.1 dillo name_uni[i] = name[i];
2791 1.1 dillo
2792 1.2 dillo if (hfslib_make_catalog_key(metadata.folder.cnid, len, name_uni,
2793 1.1 dillo &key) == 0)
2794 1.1 dillo return -1;
2795 1.1 dillo
2796 1.2 dillo return hfslib_find_catalog_record_with_key(vol, &key, rec, cbargs);
2797 1.1 dillo }
2798