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