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