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