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