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