1/* 2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29/* 30 * hfs_endian.c 31 * 32 * This file implements endian swapping routines for the HFS/HFS Plus 33 * volume format. 34 */ 35 36#include "hfs_endian.h" 37#include "hfs_dbg.h" 38#include "hfscommon/headers/BTreesPrivate.h" 39 40#undef ENDIAN_DEBUG 41 42/* 43 * Internal swapping routines 44 * 45 * These routines handle swapping the records of leaf and index nodes. The 46 * layout of the keys and records varies depending on the kind of B-tree 47 * (determined by fileID). 48 * 49 * The direction parameter must be kSwapBTNodeBigToHost or kSwapBTNodeHostToBig. 50 * The kSwapBTNodeHeaderRecordOnly "direction" is not valid for these routines. 51 */ 52int hfs_swap_HFSPlusBTInternalNode (BlockDescriptor *src, HFSCatalogNodeID fileID, enum HFSBTSwapDirection direction); 53int hfs_swap_HFSBTInternalNode (BlockDescriptor *src, HFSCatalogNodeID fileID, enum HFSBTSwapDirection direction); 54void hfs_swap_HFSPlusForkData (HFSPlusForkData *src); 55 56/* 57 * hfs_swap_HFSPlusForkData 58 */ 59void 60hfs_swap_HFSPlusForkData ( 61 HFSPlusForkData *src 62) 63{ 64 int i; 65 66 src->logicalSize = SWAP_BE64 (src->logicalSize); 67 68 src->clumpSize = SWAP_BE32 (src->clumpSize); 69 src->totalBlocks = SWAP_BE32 (src->totalBlocks); 70 71 for (i = 0; i < kHFSPlusExtentDensity; i++) { 72 src->extents[i].startBlock = SWAP_BE32 (src->extents[i].startBlock); 73 src->extents[i].blockCount = SWAP_BE32 (src->extents[i].blockCount); 74 } 75} 76 77/* 78 * hfs_swap_BTNode 79 * 80 * NOTE: This operation is not naturally symmetric. 81 * We have to determine which way we're swapping things. 82 */ 83int 84hfs_swap_BTNode ( 85 BlockDescriptor *src, 86 vnode_t vp, 87 enum HFSBTSwapDirection direction, 88 u_int8_t allow_empty_node 89) 90{ 91 BTNodeDescriptor *srcDesc = src->buffer; 92 u_int16_t *srcOffs = NULL; 93 BTreeControlBlockPtr btcb = (BTreeControlBlockPtr)VTOF(vp)->fcbBTCBPtr; 94 u_int16_t i; /* index to match srcDesc->numRecords */ 95 int error = 0; 96 97#ifdef ENDIAN_DEBUG 98 if (direction == kSwapBTNodeBigToHost) { 99 printf ("hfs: BE -> Native Swap\n"); 100 } else if (direction == kSwapBTNodeHostToBig) { 101 printf ("hfs: Native -> BE Swap\n"); 102 } else if (direction == kSwapBTNodeHeaderRecordOnly) { 103 printf ("hfs: Not swapping descriptors\n"); 104 } else { 105 panic ("hfs_swap_BTNode: This is impossible"); 106 } 107#endif 108 109 /* 110 * If we are doing a swap from on-disk to in-memory, then swap the node 111 * descriptor and record offsets before we need to use them. 112 */ 113 if (direction == kSwapBTNodeBigToHost) { 114 srcDesc->fLink = SWAP_BE32 (srcDesc->fLink); 115 srcDesc->bLink = SWAP_BE32 (srcDesc->bLink); 116 117 /* 118 * When first opening a BTree, we have to read the header node before the 119 * control block is initialized. In this case, totalNodes will be zero, 120 * so skip the bounds checking. Also, we should ignore the header node when 121 * checking for invalid forwards and backwards links, since the header node's 122 * links can point back to itself legitimately. 123 */ 124 if (btcb->totalNodes != 0) { 125 if (srcDesc->fLink >= btcb->totalNodes) { 126 printf("hfs_swap_BTNode: invalid forward link (0x%08x >= 0x%08x)\n", srcDesc->fLink, btcb->totalNodes); 127 error = fsBTInvalidHeaderErr; 128 goto fail; 129 } 130 if (srcDesc->bLink >= btcb->totalNodes) { 131 printf("hfs_swap_BTNode: invalid backward link (0x%08x >= 0x%08x)\n", srcDesc->bLink, btcb->totalNodes); 132 error = fsBTInvalidHeaderErr; 133 goto fail; 134 } 135 136 if ((src->blockNum != 0) && (srcDesc->fLink == (u_int32_t) src->blockNum)) { 137 printf("hfs_swap_BTNode: invalid forward link (0x%08x == 0x%08x)\n", 138 srcDesc->fLink, (u_int32_t) src->blockNum); 139 error = fsBTInvalidHeaderErr; 140 goto fail; 141 } 142 if ((src->blockNum != 0) && (srcDesc->bLink == (u_int32_t) src->blockNum)) { 143 printf("hfs_swap_BTNode: invalid backward link (0x%08x == 0x%08x)\n", 144 srcDesc->bLink, (u_int32_t) src->blockNum); 145 error = fsBTInvalidHeaderErr; 146 goto fail; 147 } 148 149 150 } 151 152 /* 153 * Check srcDesc->kind. Don't swap it because it's only one byte. 154 */ 155 if (srcDesc->kind < kBTLeafNode || srcDesc->kind > kBTMapNode) { 156 printf("hfs_swap_BTNode: invalid node kind (%d)\n", srcDesc->kind); 157 error = fsBTInvalidHeaderErr; 158 goto fail; 159 } 160 161 /* 162 * Check srcDesc->height. Don't swap it because it's only one byte. 163 */ 164 if (srcDesc->height > kMaxTreeDepth) { 165 printf("hfs_swap_BTNode: invalid node height (%d)\n", srcDesc->height); 166 error = fsBTInvalidHeaderErr; 167 goto fail; 168 } 169 170 /* Don't swap srcDesc->reserved */ 171 172 srcDesc->numRecords = SWAP_BE16 (srcDesc->numRecords); 173 174 /* 175 * Swap the node offsets (including the free space one!). 176 */ 177 srcOffs = (u_int16_t *)((char *)src->buffer + (src->blockSize - ((srcDesc->numRecords + 1) * sizeof (u_int16_t)))); 178 179 /* 180 * Sanity check that the record offsets are within the node itself. 181 */ 182 if ((char *)srcOffs > ((char *)src->buffer + src->blockSize) || 183 (char *)srcOffs < ((char *)src->buffer + sizeof(BTNodeDescriptor))) { 184 printf("hfs_swap_BTNode: invalid record count (0x%04X)\n", srcDesc->numRecords); 185 error = fsBTInvalidHeaderErr; 186 goto fail; 187 } 188 189 /* 190 * Swap and sanity check each of the record offsets. 191 */ 192 for (i = 0; i <= srcDesc->numRecords; i++) { 193 srcOffs[i] = SWAP_BE16 (srcOffs[i]); 194 195 /* 196 * Sanity check: must be even, and within the node itself. 197 * 198 * We may be called to swap an unused node, which contains all zeroes. 199 * Unused nodes are expected only when allow_empty_node is true. 200 * If it is false and record offset is zero, return error. 201 */ 202 if ((srcOffs[i] & 1) || ( 203 (allow_empty_node == false) && (srcOffs[i] == 0)) || 204 (srcOffs[i] < sizeof(BTNodeDescriptor) && srcOffs[i] != 0) || 205 (srcOffs[i] >= src->blockSize)) { 206 printf("hfs_swap_BTNode: record #%d invalid offset (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]); 207 error = fsBTInvalidHeaderErr; 208 goto fail; 209 } 210 211 /* 212 * Make sure the offsets are strictly increasing. Note that we're looping over 213 * them backwards, hence the order in the comparison. 214 */ 215 if ((i != 0) && (srcOffs[i] >= srcOffs[i-1])) { 216 printf("hfs_swap_BTNode: offsets %d and %d out of order (0x%04X, 0x%04X)\n", 217 srcDesc->numRecords-i-1, srcDesc->numRecords-i, srcOffs[i], srcOffs[i-1]); 218 error = fsBTInvalidHeaderErr; 219 goto fail; 220 } 221 } 222 } 223 224 /* 225 * Swap the records (ordered by frequency of access) 226 */ 227 if ((srcDesc->kind == kBTIndexNode) || 228 (srcDesc-> kind == kBTLeafNode)) { 229 230 if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) { 231 error = hfs_swap_HFSPlusBTInternalNode (src, VTOC(vp)->c_fileid, direction); 232 } else { 233 error = hfs_swap_HFSBTInternalNode (src, VTOC(vp)->c_fileid, direction); 234 } 235 236 if (error) goto fail; 237 238 } else if (srcDesc-> kind == kBTMapNode) { 239 /* Don't swap the bitmaps, they'll be done in the bitmap routines */ 240 241 } else if (srcDesc-> kind == kBTHeaderNode) { 242 /* The header's offset is hard-wired because we cannot trust the offset pointers. */ 243 BTHeaderRec *srcHead = (BTHeaderRec *)((char *)src->buffer + sizeof(BTNodeDescriptor)); 244 245 srcHead->treeDepth = SWAP_BE16 (srcHead->treeDepth); 246 247 srcHead->rootNode = SWAP_BE32 (srcHead->rootNode); 248 srcHead->leafRecords = SWAP_BE32 (srcHead->leafRecords); 249 srcHead->firstLeafNode = SWAP_BE32 (srcHead->firstLeafNode); 250 srcHead->lastLeafNode = SWAP_BE32 (srcHead->lastLeafNode); 251 252 srcHead->nodeSize = SWAP_BE16 (srcHead->nodeSize); 253 srcHead->maxKeyLength = SWAP_BE16 (srcHead->maxKeyLength); 254 255 srcHead->totalNodes = SWAP_BE32 (srcHead->totalNodes); 256 srcHead->freeNodes = SWAP_BE32 (srcHead->freeNodes); 257 258 srcHead->clumpSize = SWAP_BE32 (srcHead->clumpSize); 259 srcHead->attributes = SWAP_BE32 (srcHead->attributes); 260 261 /* Don't swap srcHead->reserved1 */ 262 /* Don't swap srcHead->btreeType; it's only one byte */ 263 /* Don't swap srcHead->reserved2 */ 264 /* Don't swap srcHead->reserved3 */ 265 /* Don't swap bitmap */ 266 } 267 268 /* 269 * If we are doing a swap from in-memory to on-disk, then swap the node 270 * descriptor and record offsets after we're done using them. 271 */ 272 if (direction == kSwapBTNodeHostToBig) { 273 /* 274 * Sanity check and swap the forward and backward links. 275 * Ignore the header node since its forward and backwards links can legitimately 276 * point to itself. 277 */ 278 if (srcDesc->fLink >= btcb->totalNodes) { 279 panic("hfs_UNswap_BTNode: invalid forward link (0x%08X)\n", srcDesc->fLink); 280 error = fsBTInvalidHeaderErr; 281 goto fail; 282 } 283 if ((src->blockNum != 0) && (srcDesc->fLink == (u_int32_t) src->blockNum)) { 284 panic ("hfs_UNswap_BTNode: invalid forward link (0x%08x == 0x%08x)\n", 285 srcDesc->fLink, (u_int32_t) src->blockNum); 286 error = fsBTInvalidHeaderErr; 287 goto fail; 288 } 289 290 if (srcDesc->bLink >= btcb->totalNodes) { 291 panic("hfs_UNswap_BTNode: invalid backward link (0x%08X)\n", srcDesc->bLink); 292 error = fsBTInvalidHeaderErr; 293 goto fail; 294 } 295 if ((src->blockNum != 0) && (srcDesc->bLink == (u_int32_t) src->blockNum)) { 296 panic ("hfs_UNswap_BTNode: invalid backward link (0x%08x == 0x%08x)\n", 297 srcDesc->bLink, (u_int32_t) src->blockNum); 298 error = fsBTInvalidHeaderErr; 299 goto fail; 300 } 301 302 303 srcDesc->fLink = SWAP_BE32 (srcDesc->fLink); 304 srcDesc->bLink = SWAP_BE32 (srcDesc->bLink); 305 306 /* 307 * Check srcDesc->kind. Don't swap it because it's only one byte. 308 */ 309 if (srcDesc->kind < kBTLeafNode || srcDesc->kind > kBTMapNode) { 310 panic("hfs_UNswap_BTNode: invalid node kind (%d)\n", srcDesc->kind); 311 error = fsBTInvalidHeaderErr; 312 goto fail; 313 } 314 315 /* 316 * Check srcDesc->height. Don't swap it because it's only one byte. 317 */ 318 if (srcDesc->height > kMaxTreeDepth) { 319 panic("hfs_UNswap_BTNode: invalid node height (%d)\n", srcDesc->height); 320 error = fsBTInvalidHeaderErr; 321 goto fail; 322 } 323 324 /* Don't swap srcDesc->reserved */ 325 326 /* 327 * Swap the node offsets (including the free space one!). 328 */ 329 srcOffs = (u_int16_t *)((char *)src->buffer + (src->blockSize - ((srcDesc->numRecords + 1) * sizeof (u_int16_t)))); 330 331 /* 332 * Sanity check that the record offsets are within the node itself. 333 */ 334 if ((char *)srcOffs > ((char *)src->buffer + src->blockSize) || 335 (char *)srcOffs < ((char *)src->buffer + sizeof(BTNodeDescriptor))) { 336 panic("hfs_UNswap_BTNode: invalid record count (0x%04X)\n", srcDesc->numRecords); 337 error = fsBTInvalidHeaderErr; 338 goto fail; 339 } 340 341 /* 342 * Swap and sanity check each of the record offsets. 343 */ 344 for (i = 0; i <= srcDesc->numRecords; i++) { 345 /* 346 * Sanity check: must be even, and within the node itself. 347 * 348 * We may be called to swap an unused node, which contains all zeroes. 349 * This can happen when the last record from a node gets deleted. 350 * This is why we allow the record offset to be zero. 351 * Unused nodes are expected only when allow_empty_node is true 352 * (the caller should set it to true for kSwapBTNodeBigToHost). 353 */ 354 if ((srcOffs[i] & 1) || 355 ((allow_empty_node == false) && (srcOffs[i] == 0)) || 356 (srcOffs[i] < sizeof(BTNodeDescriptor) && srcOffs[i] != 0) || 357 (srcOffs[i] >= src->blockSize)) { 358 panic("hfs_UNswap_BTNode: record #%d invalid offset (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]); 359 error = fsBTInvalidHeaderErr; 360 goto fail; 361 } 362 363 /* 364 * Make sure the offsets are strictly increasing. Note that we're looping over 365 * them backwards, hence the order in the comparison. 366 */ 367 if ((i < srcDesc->numRecords) && (srcOffs[i+1] >= srcOffs[i])) { 368 panic("hfs_UNswap_BTNode: offsets %d and %d out of order (0x%04X, 0x%04X)\n", 369 srcDesc->numRecords-i-2, srcDesc->numRecords-i-1, srcOffs[i+1], srcOffs[i]); 370 error = fsBTInvalidHeaderErr; 371 goto fail; 372 } 373 374 srcOffs[i] = SWAP_BE16 (srcOffs[i]); 375 } 376 377 srcDesc->numRecords = SWAP_BE16 (srcDesc->numRecords); 378 } 379 380fail: 381 if (error) { 382 /* 383 * Log some useful information about where the corrupt node is. 384 */ 385 printf("hfs: node=%lld fileID=%u volume=%s device=%s\n", src->blockNum, VTOC(vp)->c_fileid, 386 VTOVCB(vp)->vcbVN, vfs_statfs(vnode_mount(vp))->f_mntfromname); 387 hfs_mark_volume_inconsistent(VTOVCB(vp)); 388 } 389 390 return (error); 391} 392 393int 394hfs_swap_HFSPlusBTInternalNode ( 395 BlockDescriptor *src, 396 HFSCatalogNodeID fileID, 397 enum HFSBTSwapDirection direction 398) 399{ 400 BTNodeDescriptor *srcDesc = src->buffer; 401 u_int16_t *srcOffs = (u_int16_t *)((char *)src->buffer + (src->blockSize - (srcDesc->numRecords * sizeof (u_int16_t)))); 402 char *nextRecord; /* Points to start of record following current one */ 403 404 /* 405 * i is an int32 because it needs to be negative to index the offset to free space. 406 * srcDesc->numRecords is a u_int16_t and is unlikely to become 32-bit so this should be ok. 407 */ 408 409 int32_t i; 410 u_int32_t j; 411 412 if (fileID == kHFSExtentsFileID) { 413 HFSPlusExtentKey *srcKey; 414 HFSPlusExtentDescriptor *srcRec; 415 size_t recordSize; /* Size of the data part of the record, or node number for index nodes */ 416 417 if (srcDesc->kind == kBTIndexNode) 418 recordSize = sizeof(u_int32_t); 419 else 420 recordSize = sizeof(HFSPlusExtentDescriptor); 421 422 for (i = 0; i < srcDesc->numRecords; i++) { 423 /* Point to the start of the record we're currently checking. */ 424 srcKey = (HFSPlusExtentKey *)((char *)src->buffer + srcOffs[i]); 425 426 /* 427 * Point to start of next (larger offset) record. We'll use this 428 * to be sure the current record doesn't overflow into the next 429 * record. 430 */ 431 nextRecord = (char *)src->buffer + srcOffs[i-1]; 432 433 /* 434 * Make sure the key and data are within the buffer. Since both key 435 * and data are fixed size, this is relatively easy. Note that this 436 * relies on the keyLength being a constant; we verify the keyLength 437 * below. 438 */ 439 if ((char *)srcKey + sizeof(HFSPlusExtentKey) + recordSize > nextRecord) { 440 if (direction == kSwapBTNodeHostToBig) { 441 panic("hfs_swap_HFSPlusBTInternalNode: extents key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]); 442 } else { 443 printf("hfs_swap_HFSPlusBTInternalNode: extents key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]); 444 } 445 return fsBTInvalidNodeErr; 446 } 447 448 if (direction == kSwapBTNodeBigToHost) 449 srcKey->keyLength = SWAP_BE16 (srcKey->keyLength); 450 if (srcKey->keyLength != sizeof(*srcKey) - sizeof(srcKey->keyLength)) { 451 if (direction == kSwapBTNodeHostToBig) { 452 panic("hfs_swap_HFSPlusBTInternalNode: extents key #%d invalid length (%d)\n", srcDesc->numRecords-i-1, srcKey->keyLength); 453 } else { 454 printf("hfs_swap_HFSPlusBTInternalNode: extents key #%d invalid length (%d)\n", srcDesc->numRecords-i-1, srcKey->keyLength); 455 } 456 return fsBTInvalidNodeErr; 457 } 458 srcRec = (HFSPlusExtentDescriptor *)((char *)srcKey + srcKey->keyLength + sizeof(srcKey->keyLength)); 459 if (direction == kSwapBTNodeHostToBig) 460 srcKey->keyLength = SWAP_BE16 (srcKey->keyLength); 461 462 /* Don't swap srcKey->forkType; it's only one byte */ 463 /* Don't swap srcKey->pad */ 464 465 srcKey->fileID = SWAP_BE32 (srcKey->fileID); 466 srcKey->startBlock = SWAP_BE32 (srcKey->startBlock); 467 468 if (srcDesc->kind == kBTIndexNode) { 469 /* For index nodes, the record data is just a child node number. */ 470 *((u_int32_t *)srcRec) = SWAP_BE32 (*((u_int32_t *)srcRec)); 471 } else { 472 /* Swap the extent data */ 473 for (j = 0; j < kHFSPlusExtentDensity; j++) { 474 srcRec[j].startBlock = SWAP_BE32 (srcRec[j].startBlock); 475 srcRec[j].blockCount = SWAP_BE32 (srcRec[j].blockCount); 476 } 477 } 478 } 479 480 } else if (fileID == kHFSCatalogFileID) { 481 HFSPlusCatalogKey *srcKey; 482 int16_t *srcPtr; 483 u_int16_t keyLength; 484 485 for (i = 0; i < srcDesc->numRecords; i++) { 486 /* Point to the start of the record we're currently checking. */ 487 srcKey = (HFSPlusCatalogKey *)((char *)src->buffer + srcOffs[i]); 488 489 /* 490 * Point to start of next (larger offset) record. We'll use this 491 * to be sure the current record doesn't overflow into the next 492 * record. 493 */ 494 nextRecord = (char *)src->buffer + (uintptr_t)(srcOffs[i-1]); 495 496 /* 497 * Make sure we can safely dereference the keyLength and parentID fields. 498 */ 499 if ((char *)srcKey + offsetof(HFSPlusCatalogKey, nodeName.unicode[0]) > nextRecord) { 500 if (direction == kSwapBTNodeHostToBig) { 501 panic("hfs_swap_HFSPlusBTInternalNode: catalog key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]); 502 } else { 503 printf("hfs_swap_HFSPlusBTInternalNode: catalog key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]); 504 } 505 return fsBTInvalidNodeErr; 506 } 507 508 /* 509 * Swap and sanity check the key length 510 */ 511 if (direction == kSwapBTNodeBigToHost) 512 srcKey->keyLength = SWAP_BE16 (srcKey->keyLength); 513 keyLength = srcKey->keyLength; /* Put it in a local (native order) because we use it several times */ 514 if (direction == kSwapBTNodeHostToBig) 515 srcKey->keyLength = SWAP_BE16 (keyLength); 516 517 /* Sanity check the key length */ 518 if (keyLength < kHFSPlusCatalogKeyMinimumLength || keyLength > kHFSPlusCatalogKeyMaximumLength) { 519 if (direction == kSwapBTNodeHostToBig) { 520 panic("hfs_swap_HFSPlusBTInternalNode: catalog key #%d invalid length (%d)\n", srcDesc->numRecords-i-1, keyLength); 521 } else { 522 printf("hfs_swap_HFSPlusBTInternalNode: catalog key #%d invalid length (%d)\n", srcDesc->numRecords-i-1, keyLength); 523 } 524 return fsBTInvalidNodeErr; 525 } 526 527 /* 528 * Make sure that we can safely dereference the record's type field or 529 * an index node's child node number. 530 */ 531 srcPtr = (int16_t *)((char *)srcKey + keyLength + sizeof(srcKey->keyLength)); 532 if ((char *)srcPtr + sizeof(u_int32_t) > nextRecord) { 533 if (direction == kSwapBTNodeHostToBig) { 534 panic("hfs_swap_HFSPlusBTInternalNode: catalog key #%d too big\n", srcDesc->numRecords-i-1); 535 } else { 536 printf("hfs_swap_HFSPlusBTInternalNode: catalog key #%d too big\n", srcDesc->numRecords-i-1); 537 } 538 return fsBTInvalidNodeErr; 539 } 540 541 srcKey->parentID = SWAP_BE32 (srcKey->parentID); 542 543 /* 544 * Swap and sanity check the key's node name 545 */ 546 if (direction == kSwapBTNodeBigToHost) 547 srcKey->nodeName.length = SWAP_BE16 (srcKey->nodeName.length); 548 /* Make sure name length is consistent with key length */ 549 if (keyLength < sizeof(srcKey->parentID) + sizeof(srcKey->nodeName.length) + 550 srcKey->nodeName.length*sizeof(srcKey->nodeName.unicode[0])) { 551 if (direction == kSwapBTNodeHostToBig) { 552 panic("hfs_swap_HFSPlusBTInternalNode: catalog record #%d keyLength=%d expected=%lu\n", 553 srcDesc->numRecords-i, keyLength, sizeof(srcKey->parentID) + sizeof(srcKey->nodeName.length) + 554 srcKey->nodeName.length*sizeof(srcKey->nodeName.unicode[0])); 555 } else { 556 printf("hfs_swap_HFSPlusBTInternalNode: catalog record #%d keyLength=%d expected=%lu\n", 557 srcDesc->numRecords-i, keyLength, sizeof(srcKey->parentID) + sizeof(srcKey->nodeName.length) + 558 srcKey->nodeName.length*sizeof(srcKey->nodeName.unicode[0])); 559 } 560 return fsBTInvalidNodeErr; 561 } 562 for (j = 0; j < srcKey->nodeName.length; j++) { 563 srcKey->nodeName.unicode[j] = SWAP_BE16 (srcKey->nodeName.unicode[j]); 564 } 565 if (direction == kSwapBTNodeHostToBig) 566 srcKey->nodeName.length = SWAP_BE16 (srcKey->nodeName.length); 567 568 /* 569 * For index nodes, the record data is just the child's node number. 570 * Skip over swapping the various types of catalog record. 571 */ 572 if (srcDesc->kind == kBTIndexNode) { 573 *((u_int32_t *)srcPtr) = SWAP_BE32 (*((u_int32_t *)srcPtr)); 574 continue; 575 } 576 577 /* Make sure the recordType is in native order before using it. */ 578 if (direction == kSwapBTNodeBigToHost) 579 srcPtr[0] = SWAP_BE16 (srcPtr[0]); 580 581 if (srcPtr[0] == kHFSPlusFolderRecord) { 582 HFSPlusCatalogFolder *srcRec = (HFSPlusCatalogFolder *)srcPtr; 583 if ((char *)srcRec + sizeof(*srcRec) > nextRecord) { 584 if (direction == kSwapBTNodeHostToBig) { 585 panic("hfs_swap_HFSPlusBTInternalNode: catalog folder record #%d too big\n", srcDesc->numRecords-i-1); 586 } else { 587 printf("hfs_swap_HFSPlusBTInternalNode: catalog folder record #%d too big\n", srcDesc->numRecords-i-1); 588 } 589 return fsBTInvalidNodeErr; 590 } 591 592 srcRec->flags = SWAP_BE16 (srcRec->flags); 593 srcRec->valence = SWAP_BE32 (srcRec->valence); 594 srcRec->folderID = SWAP_BE32 (srcRec->folderID); 595 srcRec->createDate = SWAP_BE32 (srcRec->createDate); 596 srcRec->contentModDate = SWAP_BE32 (srcRec->contentModDate); 597 srcRec->attributeModDate = SWAP_BE32 (srcRec->attributeModDate); 598 srcRec->accessDate = SWAP_BE32 (srcRec->accessDate); 599 srcRec->backupDate = SWAP_BE32 (srcRec->backupDate); 600 601 srcRec->bsdInfo.ownerID = SWAP_BE32 (srcRec->bsdInfo.ownerID); 602 srcRec->bsdInfo.groupID = SWAP_BE32 (srcRec->bsdInfo.groupID); 603 604 /* Don't swap srcRec->bsdInfo.adminFlags; it's only one byte */ 605 /* Don't swap srcRec->bsdInfo.ownerFlags; it's only one byte */ 606 607 srcRec->bsdInfo.fileMode = SWAP_BE16 (srcRec->bsdInfo.fileMode); 608 srcRec->bsdInfo.special.iNodeNum = SWAP_BE32 (srcRec->bsdInfo.special.iNodeNum); 609 610 srcRec->textEncoding = SWAP_BE32 (srcRec->textEncoding); 611 612 /* Don't swap srcRec->userInfo */ 613 /* Don't swap srcRec->finderInfo */ 614 srcRec->folderCount = SWAP_BE32 (srcRec->folderCount); 615 616 } else if (srcPtr[0] == kHFSPlusFileRecord) { 617 HFSPlusCatalogFile *srcRec = (HFSPlusCatalogFile *)srcPtr; 618 if ((char *)srcRec + sizeof(*srcRec) > nextRecord) { 619 if (direction == kSwapBTNodeHostToBig) { 620 panic("hfs_swap_HFSPlusBTInternalNode: catalog file record #%d too big\n", srcDesc->numRecords-i-1); 621 } else { 622 printf("hfs_swap_HFSPlusBTInternalNode: catalog file record #%d too big\n", srcDesc->numRecords-i-1); 623 } 624 return fsBTInvalidNodeErr; 625 } 626 627 srcRec->flags = SWAP_BE16 (srcRec->flags); 628 629 srcRec->fileID = SWAP_BE32 (srcRec->fileID); 630 631 srcRec->createDate = SWAP_BE32 (srcRec->createDate); 632 srcRec->contentModDate = SWAP_BE32 (srcRec->contentModDate); 633 srcRec->attributeModDate = SWAP_BE32 (srcRec->attributeModDate); 634 srcRec->accessDate = SWAP_BE32 (srcRec->accessDate); 635 srcRec->backupDate = SWAP_BE32 (srcRec->backupDate); 636 637 srcRec->bsdInfo.ownerID = SWAP_BE32 (srcRec->bsdInfo.ownerID); 638 srcRec->bsdInfo.groupID = SWAP_BE32 (srcRec->bsdInfo.groupID); 639 640 /* Don't swap srcRec->bsdInfo.adminFlags; it's only one byte */ 641 /* Don't swap srcRec->bsdInfo.ownerFlags; it's only one byte */ 642 643 srcRec->bsdInfo.fileMode = SWAP_BE16 (srcRec->bsdInfo.fileMode); 644 srcRec->bsdInfo.special.iNodeNum = SWAP_BE32 (srcRec->bsdInfo.special.iNodeNum); 645 646 srcRec->textEncoding = SWAP_BE32 (srcRec->textEncoding); 647 648 /* If kHFSHasLinkChainBit is set, reserved1 is hl_FirstLinkID. 649 * In all other context, it is expected to be zero. 650 */ 651 srcRec->reserved1 = SWAP_BE32 (srcRec->reserved1); 652 653 /* Don't swap srcRec->userInfo */ 654 /* Don't swap srcRec->finderInfo */ 655 /* Don't swap srcRec->reserved2 */ 656 657 hfs_swap_HFSPlusForkData (&srcRec->dataFork); 658 hfs_swap_HFSPlusForkData (&srcRec->resourceFork); 659 660 } else if ((srcPtr[0] == kHFSPlusFolderThreadRecord) || 661 (srcPtr[0] == kHFSPlusFileThreadRecord)) { 662 663 /* 664 * Make sure there is room for parentID and name length. 665 */ 666 HFSPlusCatalogThread *srcRec = (HFSPlusCatalogThread *)srcPtr; 667 if ((char *) &srcRec->nodeName.unicode[0] > nextRecord) { 668 if (direction == kSwapBTNodeHostToBig) { 669 panic("hfs_swap_HFSPlusBTInternalNode: catalog thread record #%d too big\n", srcDesc->numRecords-i-1); 670 } else { 671 printf("hfs_swap_HFSPlusBTInternalNode: catalog thread record #%d too big\n", srcDesc->numRecords-i-1); 672 } 673 return fsBTInvalidNodeErr; 674 } 675 676 /* Don't swap srcRec->reserved */ 677 678 srcRec->parentID = SWAP_BE32 (srcRec->parentID); 679 680 if (direction == kSwapBTNodeBigToHost) 681 srcRec->nodeName.length = SWAP_BE16 (srcRec->nodeName.length); 682 683 /* 684 * Make sure there is room for the name in the buffer. 685 * Then swap the characters of the name itself. 686 */ 687 if ((char *) &srcRec->nodeName.unicode[srcRec->nodeName.length] > nextRecord) { 688 if (direction == kSwapBTNodeHostToBig) { 689 panic("hfs_swap_HFSPlusBTInternalNode: catalog thread record #%d name too big\n", srcDesc->numRecords-i-1); 690 } else { 691 printf("hfs_swap_HFSPlusBTInternalNode: catalog thread record #%d name too big\n", srcDesc->numRecords-i-1); 692 } 693 return fsBTInvalidNodeErr; 694 } 695 for (j = 0; j < srcRec->nodeName.length; j++) { 696 srcRec->nodeName.unicode[j] = SWAP_BE16 (srcRec->nodeName.unicode[j]); 697 } 698 699 if (direction == kSwapBTNodeHostToBig) 700 srcRec->nodeName.length = SWAP_BE16 (srcRec->nodeName.length); 701 702 } else { 703 if (direction == kSwapBTNodeHostToBig) { 704 panic("hfs_swap_HFSPlusBTInternalNode: unrecognized catalog record type (0x%04X; record #%d)\n", srcPtr[0], srcDesc->numRecords-i-1); 705 } else { 706 printf("hfs_swap_HFSPlusBTInternalNode: unrecognized catalog record type (0x%04X; record #%d)\n", srcPtr[0], srcDesc->numRecords-i-1); 707 } 708 return fsBTInvalidNodeErr; 709 } 710 711 /* We can swap the record type now that we're done using it. */ 712 if (direction == kSwapBTNodeHostToBig) 713 srcPtr[0] = SWAP_BE16 (srcPtr[0]); 714 } 715 716 } else if (fileID == kHFSAttributesFileID) { 717 HFSPlusAttrKey *srcKey; 718 HFSPlusAttrRecord *srcRec; 719 u_int16_t keyLength; 720 u_int32_t attrSize = 0; 721 722 for (i = 0; i < srcDesc->numRecords; i++) { 723 /* Point to the start of the record we're currently checking. */ 724 srcKey = (HFSPlusAttrKey *)((char *)src->buffer + srcOffs[i]); 725 726 /* 727 * Point to start of next (larger offset) record. We'll use this 728 * to be sure the current record doesn't overflow into the next 729 * record. 730 */ 731 nextRecord = (char *)src->buffer + srcOffs[i-1]; 732 733 /* Make sure there is room in the buffer for a minimal key */ 734 if ((char *) &srcKey->attrName[1] > nextRecord) { 735 if (direction == kSwapBTNodeHostToBig) { 736 panic("hfs_swap_HFSPlusBTInternalNode: attr key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]); 737 } else { 738 printf("hfs_swap_HFSPlusBTInternalNode: attr key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]); 739 } 740 return fsBTInvalidNodeErr; 741 } 742 743 /* Swap the key length field */ 744 if (direction == kSwapBTNodeBigToHost) 745 srcKey->keyLength = SWAP_BE16(srcKey->keyLength); 746 keyLength = srcKey->keyLength; /* Keep a copy in native order */ 747 if (direction == kSwapBTNodeHostToBig) 748 srcKey->keyLength = SWAP_BE16(srcKey->keyLength); 749 750 /* 751 * Make sure that we can safely dereference the record's type field or 752 * an index node's child node number. 753 */ 754 srcRec = (HFSPlusAttrRecord *)((char *)srcKey + keyLength + sizeof(srcKey->keyLength)); 755 if ((char *)srcRec + sizeof(u_int32_t) > nextRecord) { 756 if (direction == kSwapBTNodeHostToBig) { 757 panic("hfs_swap_HFSPlusBTInternalNode: attr key #%d too big (%d)\n", srcDesc->numRecords-i-1, keyLength); 758 } else { 759 printf("hfs_swap_HFSPlusBTInternalNode: attr key #%d too big (%d)\n", srcDesc->numRecords-i-1, keyLength); 760 } 761 return fsBTInvalidNodeErr; 762 } 763 764 srcKey->fileID = SWAP_BE32(srcKey->fileID); 765 srcKey->startBlock = SWAP_BE32(srcKey->startBlock); 766 767 /* 768 * Swap and check the attribute name 769 */ 770 if (direction == kSwapBTNodeBigToHost) 771 srcKey->attrNameLen = SWAP_BE16(srcKey->attrNameLen); 772 /* Sanity check the attribute name length */ 773 if (srcKey->attrNameLen > kHFSMaxAttrNameLen || keyLength < (kHFSPlusAttrKeyMinimumLength + sizeof(u_int16_t)*srcKey->attrNameLen)) { 774 if (direction == kSwapBTNodeHostToBig) { 775 panic("hfs_swap_HFSPlusBTInternalNode: attr key #%d keyLength=%d attrNameLen=%d\n", srcDesc->numRecords-i-1, keyLength, srcKey->attrNameLen); 776 } else { 777 printf("hfs_swap_HFSPlusBTInternalNode: attr key #%d keyLength=%d attrNameLen=%d\n", srcDesc->numRecords-i-1, keyLength, srcKey->attrNameLen); 778 } 779 return fsBTInvalidNodeErr; 780 } 781 for (j = 0; j < srcKey->attrNameLen; j++) 782 srcKey->attrName[j] = SWAP_BE16(srcKey->attrName[j]); 783 if (direction == kSwapBTNodeHostToBig) 784 srcKey->attrNameLen = SWAP_BE16(srcKey->attrNameLen); 785 786 /* 787 * For index nodes, the record data is just the child's node number. 788 * Skip over swapping the various types of attribute record. 789 */ 790 if (srcDesc->kind == kBTIndexNode) { 791 *((u_int32_t *)srcRec) = SWAP_BE32 (*((u_int32_t *)srcRec)); 792 continue; 793 } 794 795 /* Swap the record data */ 796 if (direction == kSwapBTNodeBigToHost) 797 srcRec->recordType = SWAP_BE32(srcRec->recordType); 798 switch (srcRec->recordType) { 799 case kHFSPlusAttrInlineData: 800 /* Is there room for the inline data header? */ 801 if ((char *) &srcRec->attrData.attrData[0] > nextRecord) { 802 if (direction == kSwapBTNodeHostToBig) { 803 panic("hfs_swap_HFSPlusBTInternalNode: attr inline #%d too big\n", srcDesc->numRecords-i-1); 804 } else { 805 printf("hfs_swap_HFSPlusBTInternalNode: attr inline #%d too big\n", srcDesc->numRecords-i-1); 806 } 807 return fsBTInvalidNodeErr; 808 } 809 810 /* We're not swapping the reserved fields */ 811 812 /* Swap the attribute size */ 813 if (direction == kSwapBTNodeHostToBig) 814 attrSize = srcRec->attrData.attrSize; 815 srcRec->attrData.attrSize = SWAP_BE32(srcRec->attrData.attrSize); 816 if (direction == kSwapBTNodeBigToHost) 817 attrSize = srcRec->attrData.attrSize; 818 819 /* Is there room for the inline attribute data? */ 820 if ((char *) &srcRec->attrData.attrData[attrSize] > nextRecord) { 821 if (direction == kSwapBTNodeHostToBig) { 822 panic("hfs_swap_HFSPlusBTInternalNode: attr inline #%d too big (attrSize=%u)\n", srcDesc->numRecords-i-1, attrSize); 823 } else { 824 printf("hfs_swap_HFSPlusBTInternalNode: attr inline #%d too big (attrSize=%u)\n", srcDesc->numRecords-i-1, attrSize); 825 } 826 return fsBTInvalidNodeErr; 827 } 828 829 /* Not swapping the attribute data itself */ 830 break; 831 832 case kHFSPlusAttrForkData: 833 /* Is there room for the fork data record? */ 834 if ((char *)srcRec + sizeof(HFSPlusAttrForkData) > nextRecord) { 835 if (direction == kSwapBTNodeHostToBig) { 836 panic("hfs_swap_HFSPlusBTInternalNode: attr fork data #%d too big\n", srcDesc->numRecords-i-1); 837 } else { 838 printf("hfs_swap_HFSPlusBTInternalNode: attr fork data #%d too big\n", srcDesc->numRecords-i-1); 839 } 840 return fsBTInvalidNodeErr; 841 } 842 843 /* We're not swapping the reserved field */ 844 845 hfs_swap_HFSPlusForkData(&srcRec->forkData.theFork); 846 break; 847 848 case kHFSPlusAttrExtents: 849 /* Is there room for an extent record? */ 850 if ((char *)srcRec + sizeof(HFSPlusAttrExtents) > nextRecord) { 851 if (direction == kSwapBTNodeHostToBig) { 852 panic("hfs_swap_HFSPlusBTInternalNode: attr extents #%d too big\n", srcDesc->numRecords-i-1); 853 } else { 854 printf("hfs_swap_HFSPlusBTInternalNode: attr extents #%d too big\n", srcDesc->numRecords-i-1); 855 } 856 return fsBTInvalidNodeErr; 857 } 858 859 /* We're not swapping the reserved field */ 860 861 for (j = 0; j < kHFSPlusExtentDensity; j++) { 862 srcRec->overflowExtents.extents[j].startBlock = 863 SWAP_BE32(srcRec->overflowExtents.extents[j].startBlock); 864 srcRec->overflowExtents.extents[j].blockCount = 865 SWAP_BE32(srcRec->overflowExtents.extents[j].blockCount); 866 } 867 break; 868 } 869 if (direction == kSwapBTNodeHostToBig) 870 srcRec->recordType = SWAP_BE32(srcRec->recordType); 871 } 872 } else if (fileID > kHFSFirstUserCatalogNodeID) { 873 /* The only B-tree with a non-system CNID that we use is the hotfile B-tree */ 874 HotFileKey *srcKey; 875 u_int32_t *srcRec; 876 877 for (i = 0; i < srcDesc->numRecords; i++) { 878 /* Point to the start of the record we're currently checking. */ 879 srcKey = (HotFileKey *)((char *)src->buffer + srcOffs[i]); 880 881 /* 882 * Point to start of next (larger offset) record. We'll use this 883 * to be sure the current record doesn't overflow into the next 884 * record. 885 */ 886 nextRecord = (char *)src->buffer + srcOffs[i-1]; 887 888 /* Make sure there is room for the key (HotFileKey) and data (u_int32_t) */ 889 if ((char *)srcKey + sizeof(HotFileKey) + sizeof(u_int32_t) > nextRecord) { 890 if (direction == kSwapBTNodeHostToBig) { 891 panic("hfs_swap_HFSPlusBTInternalNode: hotfile #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]); 892 } else { 893 printf("hfs_swap_HFSPlusBTInternalNode: hotfile #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]); 894 } 895 return fsBTInvalidNodeErr; 896 } 897 898 /* Swap and sanity check the key length field */ 899 if (direction == kSwapBTNodeBigToHost) 900 srcKey->keyLength = SWAP_BE16 (srcKey->keyLength); 901 if (srcKey->keyLength != sizeof(*srcKey) - sizeof(srcKey->keyLength)) { 902 if (direction == kSwapBTNodeHostToBig) { 903 panic("hfs_swap_HFSPlusBTInternalNode: hotfile #%d incorrect keyLength %d\n", srcDesc->numRecords-i-1, srcKey->keyLength); 904 } else { 905 printf("hfs_swap_HFSPlusBTInternalNode: hotfile #%d incorrect keyLength %d\n", srcDesc->numRecords-i-1, srcKey->keyLength); 906 } 907 return fsBTInvalidNodeErr; 908 } 909 srcRec = (u_int32_t *)((char *)srcKey + srcKey->keyLength + sizeof(srcKey->keyLength)); 910 if (direction == kSwapBTNodeHostToBig) 911 srcKey->keyLength = SWAP_BE16 (srcKey->keyLength); 912 913 /* Don't swap srcKey->forkType */ 914 /* Don't swap srcKey->pad */ 915 916 srcKey->temperature = SWAP_BE32 (srcKey->temperature); 917 srcKey->fileID = SWAP_BE32 (srcKey->fileID); 918 919 *((u_int32_t *)srcRec) = SWAP_BE32 (*((u_int32_t *)srcRec)); 920 } 921 } else { 922 panic ("hfs_swap_HFSPlusBTInternalNode: fileID %u is not a system B-tree\n", fileID); 923 } 924 925 926 return (0); 927} 928 929int 930hfs_swap_HFSBTInternalNode ( 931 BlockDescriptor *src, 932 HFSCatalogNodeID fileID, 933 enum HFSBTSwapDirection direction 934) 935{ 936 BTNodeDescriptor *srcDesc = src->buffer; 937 u_int16_t *srcOffs = (u_int16_t *)((char *)src->buffer + (src->blockSize - (srcDesc->numRecords * sizeof (u_int16_t)))); 938 char *nextRecord; /* Points to start of record following current one */ 939 940 /* 941 * i is an int32 because it needs to be negative to index the offset to free space. 942 * srcDesc->numRecords is a u_int16_t and is unlikely to become 32-bit so this should be ok. 943 */ 944 int32_t i; 945 u_int32_t j; 946 947 if (fileID == kHFSExtentsFileID) { 948 HFSExtentKey *srcKey; 949 HFSExtentDescriptor *srcRec; 950 size_t recordSize; /* Size of the data part of the record, or node number for index nodes */ 951 952 if (srcDesc->kind == kBTIndexNode) 953 recordSize = sizeof(u_int32_t); 954 else 955 recordSize = sizeof(HFSExtentDescriptor); 956 957 for (i = 0; i < srcDesc->numRecords; i++) { 958 /* Point to the start of the record we're currently checking. */ 959 srcKey = (HFSExtentKey *)((char *)src->buffer + srcOffs[i]); 960 961 /* 962 * Point to start of next (larger offset) record. We'll use this 963 * to be sure the current record doesn't overflow into the next 964 * record. 965 */ 966 nextRecord = (char *)src->buffer + srcOffs[i-1]; 967 968 /* 969 * Make sure the key and data are within the buffer. Since both key 970 * and data are fixed size, this is relatively easy. Note that this 971 * relies on the keyLength being a constant; we verify the keyLength 972 * below. 973 */ 974 if ((char *)srcKey + sizeof(HFSExtentKey) + recordSize > nextRecord) { 975 if (direction == kSwapBTNodeHostToBig) { 976 panic("hfs_swap_HFSBTInternalNode: extents key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]); 977 } else { 978 printf("hfs_swap_HFSBTInternalNode: extents key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]); 979 } 980 return fsBTInvalidNodeErr; 981 } 982 983 /* Don't swap srcKey->keyLength (it's only one byte), but do sanity check it */ 984 if (srcKey->keyLength != sizeof(*srcKey) - sizeof(srcKey->keyLength)) { 985 if (direction == kSwapBTNodeHostToBig) { 986 panic("hfs_swap_HFSBTInternalNode: extents key #%d invalid length (%d)\n", srcDesc->numRecords-i-1, srcKey->keyLength); 987 } else { 988 printf("hfs_swap_HFSBTInternalNode: extents key #%d invalid length (%d)\n", srcDesc->numRecords-i-1, srcKey->keyLength); 989 } 990 return fsBTInvalidNodeErr; 991 } 992 993 /* Don't swap srcKey->forkType; it's only one byte */ 994 995 srcKey->fileID = SWAP_BE32 (srcKey->fileID); 996 srcKey->startBlock = SWAP_BE16 (srcKey->startBlock); 997 998 /* Point to record data (round up to even byte boundary) */ 999 srcRec = (HFSExtentDescriptor *)((char *)srcKey + ((srcKey->keyLength + 2) & ~1)); 1000 1001 if (srcDesc->kind == kBTIndexNode) { 1002 /* For index nodes, the record data is just a child node number. */ 1003 *((u_int32_t *)srcRec) = SWAP_BE32 (*((u_int32_t *)srcRec)); 1004 } else { 1005 /* Swap the extent data */ 1006 for (j = 0; j < kHFSExtentDensity; j++) { 1007 srcRec[j].startBlock = SWAP_BE16 (srcRec[j].startBlock); 1008 srcRec[j].blockCount = SWAP_BE16 (srcRec[j].blockCount); 1009 } 1010 } 1011 } 1012 1013 } else if (fileID == kHFSCatalogFileID) { 1014 HFSCatalogKey *srcKey; 1015 int16_t *srcPtr; 1016 unsigned expectedKeyLength; 1017 1018 for (i = 0; i < srcDesc->numRecords; i++) { 1019 /* Point to the start of the record we're currently checking. */ 1020 srcKey = (HFSCatalogKey *)((char *)src->buffer + srcOffs[i]); 1021 1022 /* 1023 * Point to start of next (larger offset) record. We'll use this 1024 * to be sure the current record doesn't overflow into the next 1025 * record. 1026 */ 1027 nextRecord = (char *)src->buffer + srcOffs[i-1]; 1028 1029 /* 1030 * Make sure we can safely dereference the keyLength and parentID fields. 1031 * The value 8 below is 1 bytes for keyLength + 1 byte reserved + 4 bytes 1032 * for parentID + 1 byte for nodeName's length + 1 byte to round up the 1033 * record start to an even offset, which forms a minimal key. 1034 */ 1035 if ((char *)srcKey + 8 > nextRecord) { 1036 if (direction == kSwapBTNodeHostToBig) { 1037 panic("hfs_swap_HFSBTInternalNode: catalog key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]); 1038 } else { 1039 printf("hfs_swap_HFSBTInternalNode: catalog key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]); 1040 } 1041 return fsBTInvalidNodeErr; 1042 } 1043 1044 /* Don't swap srcKey->keyLength (it's only one byte), but do sanity check it */ 1045 if (srcKey->keyLength < kHFSCatalogKeyMinimumLength || srcKey->keyLength > kHFSCatalogKeyMaximumLength) { 1046 if (direction == kSwapBTNodeHostToBig) { 1047 panic("hfs_swap_HFSBTInternalNode: catalog key #%d invalid length (%d)\n", srcDesc->numRecords-i-1, srcKey->keyLength); 1048 } else { 1049 printf("hfs_swap_HFSBTInternalNode: catalog key #%d invalid length (%d)\n", srcDesc->numRecords-i-1, srcKey->keyLength); 1050 } 1051 return fsBTInvalidNodeErr; 1052 } 1053 1054 /* Don't swap srcKey->reserved */ 1055 1056 srcKey->parentID = SWAP_BE32 (srcKey->parentID); 1057 1058 /* Don't swap srcKey->nodeName */ 1059 1060 /* Make sure the keyLength is big enough for the key's content */ 1061 if (srcDesc->kind == kBTIndexNode) 1062 expectedKeyLength = sizeof(*srcKey) - sizeof(srcKey->keyLength); 1063 else 1064 expectedKeyLength = srcKey->nodeName[0] + kHFSCatalogKeyMinimumLength; 1065 if (srcKey->keyLength < expectedKeyLength) { 1066 if (direction == kSwapBTNodeHostToBig) { 1067 panic("hfs_swap_HFSBTInternalNode: catalog record #%d keyLength=%u expected=%u\n", 1068 srcDesc->numRecords-i, srcKey->keyLength, expectedKeyLength); 1069 } else { 1070 printf("hfs_swap_HFSBTInternalNode: catalog record #%d keyLength=%u expected=%u\n", 1071 srcDesc->numRecords-i, srcKey->keyLength, expectedKeyLength); 1072 } 1073 return fsBTInvalidNodeErr; 1074 } 1075 1076 /* Point to record data (round up to even byte boundary) */ 1077 srcPtr = (int16_t *)((char *)srcKey + ((srcKey->keyLength + 2) & ~1)); 1078 1079 /* 1080 * Make sure that we can safely dereference the record's type field or 1081 * and index node's child node number. 1082 */ 1083 if ((char *)srcPtr + sizeof(u_int32_t) > nextRecord) { 1084 if (direction == kSwapBTNodeHostToBig) { 1085 panic("hfs_swap_HFSBTInternalNode: catalog key #%d too big\n", srcDesc->numRecords-i-1); 1086 } else { 1087 printf("hfs_swap_HFSBTInternalNode: catalog key #%d too big\n", srcDesc->numRecords-i-1); 1088 } 1089 return fsBTInvalidNodeErr; 1090 } 1091 1092 /* 1093 * For index nodes, the record data is just the child's node number. 1094 * Skip over swapping the various types of catalog record. 1095 */ 1096 if (srcDesc->kind == kBTIndexNode) { 1097 *((u_int32_t *)srcPtr) = SWAP_BE32 (*((u_int32_t *)srcPtr)); 1098 continue; 1099 } 1100 1101 /* Make sure the recordType is in native order before using it. */ 1102 if (direction == kSwapBTNodeBigToHost) 1103 srcPtr[0] = SWAP_BE16 (srcPtr[0]); 1104 1105 if (srcPtr[0] == kHFSFolderRecord) { 1106 HFSCatalogFolder *srcRec = (HFSCatalogFolder *)srcPtr; 1107 if ((char *)srcRec + sizeof(*srcRec) > nextRecord) { 1108 if (direction == kSwapBTNodeHostToBig) { 1109 panic("hfs_swap_HFSBTInternalNode: catalog folder record #%d too big\n", srcDesc->numRecords-i-1); 1110 } else { 1111 printf("hfs_swap_HFSBTInternalNode: catalog folder record #%d too big\n", srcDesc->numRecords-i-1); 1112 } 1113 return fsBTInvalidNodeErr; 1114 } 1115 1116 srcRec->flags = SWAP_BE16 (srcRec->flags); 1117 srcRec->valence = SWAP_BE16 (srcRec->valence); 1118 1119 srcRec->folderID = SWAP_BE32 (srcRec->folderID); 1120 srcRec->createDate = SWAP_BE32 (srcRec->createDate); 1121 srcRec->modifyDate = SWAP_BE32 (srcRec->modifyDate); 1122 srcRec->backupDate = SWAP_BE32 (srcRec->backupDate); 1123 1124 /* Don't swap srcRec->userInfo */ 1125 /* Don't swap srcRec->finderInfo */ 1126 /* Don't swap resserved array */ 1127 1128 } else if (srcPtr[0] == kHFSFileRecord) { 1129 HFSCatalogFile *srcRec = (HFSCatalogFile *)srcPtr; 1130 if ((char *)srcRec + sizeof(*srcRec) > nextRecord) { 1131 if (direction == kSwapBTNodeHostToBig) { 1132 panic("hfs_swap_HFSBTInternalNode: catalog file record #%d too big\n", srcDesc->numRecords-i-1); 1133 } else { 1134 printf("hfs_swap_HFSBTInternalNode: catalog file record #%d too big\n", srcDesc->numRecords-i-1); 1135 } 1136 return fsBTInvalidNodeErr; 1137 } 1138 1139 srcRec->flags = srcRec->flags; 1140 srcRec->fileType = srcRec->fileType; 1141 1142 /* Don't swap srcRec->userInfo */ 1143 1144 srcRec->fileID = SWAP_BE32 (srcRec->fileID); 1145 1146 srcRec->dataStartBlock = SWAP_BE16 (srcRec->dataStartBlock); 1147 srcRec->dataLogicalSize = SWAP_BE32 (srcRec->dataLogicalSize); 1148 srcRec->dataPhysicalSize = SWAP_BE32 (srcRec->dataPhysicalSize); 1149 1150 srcRec->rsrcStartBlock = SWAP_BE16 (srcRec->rsrcStartBlock); 1151 srcRec->rsrcLogicalSize = SWAP_BE32 (srcRec->rsrcLogicalSize); 1152 srcRec->rsrcPhysicalSize = SWAP_BE32 (srcRec->rsrcPhysicalSize); 1153 1154 srcRec->createDate = SWAP_BE32 (srcRec->createDate); 1155 srcRec->modifyDate = SWAP_BE32 (srcRec->modifyDate); 1156 srcRec->backupDate = SWAP_BE32 (srcRec->backupDate); 1157 1158 /* Don't swap srcRec->finderInfo */ 1159 1160 srcRec->clumpSize = SWAP_BE16 (srcRec->clumpSize); 1161 1162 /* Swap the two sets of extents as an array of six (three each) u_int16_t */ 1163 for (j = 0; j < kHFSExtentDensity * 2; j++) { 1164 srcRec->dataExtents[j].startBlock = SWAP_BE16 (srcRec->dataExtents[j].startBlock); 1165 srcRec->dataExtents[j].blockCount = SWAP_BE16 (srcRec->dataExtents[j].blockCount); 1166 } 1167 1168 /* Don't swap srcRec->reserved */ 1169 1170 } else if ((srcPtr[0] == kHFSFolderThreadRecord) || 1171 (srcPtr[0] == kHFSFileThreadRecord)) { 1172 HFSCatalogThread *srcRec = (HFSCatalogThread *)srcPtr; 1173 1174 /* Make sure there is room for parentID and name length */ 1175 if ((char *) &srcRec->nodeName[1] > nextRecord) { 1176 if (direction == kSwapBTNodeHostToBig) { 1177 panic("hfs_swap_HFSBTInternalNode: catalog thread record #%d too big\n", srcDesc->numRecords-i-1); 1178 } else { 1179 printf("hfs_swap_HFSBTInternalNode: catalog thread record #%d too big\n", srcDesc->numRecords-i-1); 1180 } 1181 return fsBTInvalidNodeErr; 1182 } 1183 1184 /* Don't swap srcRec->reserved array */ 1185 1186 srcRec->parentID = SWAP_BE32 (srcRec->parentID); 1187 1188 /* Don't swap srcRec->nodeName */ 1189 1190 /* Make sure there is room for the name in the buffer */ 1191 if ((char *) &srcRec->nodeName[srcRec->nodeName[0]] > nextRecord) { 1192 if (direction == kSwapBTNodeHostToBig) { 1193 panic("hfs_swap_HFSBTInternalNode: catalog thread record #%d name too big\n", srcDesc->numRecords-i-1); 1194 } else { 1195 printf("hfs_swap_HFSBTInternalNode: catalog thread record #%d name too big\n", srcDesc->numRecords-i-1); 1196 } 1197 return fsBTInvalidNodeErr; 1198 } 1199 } else { 1200 if (direction == kSwapBTNodeHostToBig) { 1201 panic("hfs_swap_HFSBTInternalNode: unrecognized catalog record type (0x%04X; record #%d)\n", srcPtr[0], srcDesc->numRecords-i-1); 1202 } else { 1203 printf("hfs_swap_HFSBTInternalNode: unrecognized catalog record type (0x%04X; record #%d)\n", srcPtr[0], srcDesc->numRecords-i-1); 1204 } 1205 return fsBTInvalidNodeErr; 1206 } 1207 1208 /* We can swap the record type now that we're done using it */ 1209 if (direction == kSwapBTNodeHostToBig) 1210 srcPtr[0] = SWAP_BE16 (srcPtr[0]); 1211 } 1212 1213 } else { 1214 panic ("hfs_swap_HFSBTInternalNode: fileID %u is not a system B-tree\n", fileID); 1215 } 1216 1217 return (0); 1218} 1219