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