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