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