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