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