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