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