2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
26 * This file implements endian swapping routines for the HFS/HFS Plus
30 #include <architecture/byte_order.h>
32 #include "hfs_endian.h"
34 #include "hfscommon/headers/BTreesPrivate.h"
39 * Internal swapping routines
41 * These routines handle swapping the records of leaf and index nodes. The
42 * layout of the keys and records varies depending on the kind of B-tree
43 * (determined by fileID).
45 * The direction parameter must be kSwapBTNodeBigToHost or kSwapBTNodeHostToBig.
46 * The kSwapBTNodeHeaderRecordOnly "direction" is not valid for these routines.
48 static int hfs_swap_HFSPlusBTInternalNode (BlockDescriptor
*src
, HFSCatalogNodeID fileID
, enum HFSBTSwapDirection direction
);
49 static int hfs_swap_HFSBTInternalNode (BlockDescriptor
*src
, HFSCatalogNodeID fileID
, enum HFSBTSwapDirection direction
);
52 * hfs_swap_HFSPlusForkData
55 hfs_swap_HFSPlusForkData (
61 src
->logicalSize
= SWAP_BE64 (src
->logicalSize
);
63 src
->clumpSize
= SWAP_BE32 (src
->clumpSize
);
64 src
->totalBlocks
= SWAP_BE32 (src
->totalBlocks
);
66 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
67 src
->extents
[i
].startBlock
= SWAP_BE32 (src
->extents
[i
].startBlock
);
68 src
->extents
[i
].blockCount
= SWAP_BE32 (src
->extents
[i
].blockCount
);
75 * NOTE: This operation is not naturally symmetric.
76 * We have to determine which way we're swapping things.
82 enum HFSBTSwapDirection direction
85 BTNodeDescriptor
*srcDesc
= src
->buffer
;
86 UInt16
*srcOffs
= NULL
;
87 BTreeControlBlockPtr btcb
= (BTreeControlBlockPtr
)VTOF(vp
)->fcbBTCBPtr
;
92 if (direction
== kSwapBTNodeBigToHost
) {
93 printf ("BE -> Native Swap\n");
94 } else if (direction
== kSwapBTNodeHostToBig
) {
95 printf ("Native -> BE Swap\n");
96 } else if (direction
== kSwapBTNodeHeaderRecordOnly
) {
97 printf ("Not swapping descriptors\n");
99 panic ("hfs_swap_BTNode: This is impossible");
104 * If we are doing a swap from on-disk to in-memory, then swap the node
105 * descriptor and record offsets before we need to use them.
107 if (direction
== kSwapBTNodeBigToHost
) {
108 srcDesc
->fLink
= SWAP_BE32 (srcDesc
->fLink
);
109 srcDesc
->bLink
= SWAP_BE32 (srcDesc
->bLink
);
112 * When first opening a BTree, we have to read the header node before the
113 * control block is initialized. In this case, totalNodes will be zero,
114 * so skip the bounds checking.
116 if (btcb
->totalNodes
!= 0) {
117 if (srcDesc
->fLink
>= btcb
->totalNodes
) {
118 printf("hfs_swap_BTNode: invalid forward link (0x%08X)\n", srcDesc
->fLink
);
119 error
= fsBTInvalidHeaderErr
;
122 if (srcDesc
->bLink
>= btcb
->totalNodes
) {
123 printf("hfs_swap_BTNode: invalid backward link (0x%08X)\n", srcDesc
->bLink
);
124 error
= fsBTInvalidHeaderErr
;
130 * Check srcDesc->kind. Don't swap it because it's only one byte.
132 if (srcDesc
->kind
< kBTLeafNode
|| srcDesc
->kind
> kBTMapNode
) {
133 printf("hfs_swap_BTNode: invalid node kind (%d)\n", srcDesc
->kind
);
134 error
= fsBTInvalidHeaderErr
;
139 * Check srcDesc->height. Don't swap it because it's only one byte.
141 if (srcDesc
->height
> btcb
->treeDepth
) {
142 printf("hfs_swap_BTNode: invalid node height (%d)\n", srcDesc
->height
);
143 error
= fsBTInvalidHeaderErr
;
147 /* Don't swap srcDesc->reserved */
149 srcDesc
->numRecords
= SWAP_BE16 (srcDesc
->numRecords
);
152 * Swap the node offsets (including the free space one!).
154 srcOffs
= (UInt16
*)((char *)src
->buffer
+ (src
->blockSize
- ((srcDesc
->numRecords
+ 1) * sizeof (UInt16
))));
157 * Sanity check that the record offsets are within the node itself.
159 if ((char *)srcOffs
> ((char *)src
->buffer
+ src
->blockSize
) ||
160 (char *)srcOffs
< ((char *)src
->buffer
+ sizeof(BTNodeDescriptor
))) {
161 printf("hfs_swap_BTNode: invalid record count (0x%04X)\n", srcDesc
->numRecords
);
162 error
= fsBTInvalidHeaderErr
;
167 * Swap and sanity check each of the record offsets.
169 for (i
= 0; i
<= srcDesc
->numRecords
; i
++) {
170 srcOffs
[i
] = SWAP_BE16 (srcOffs
[i
]);
173 * Sanity check: must be even, and within the node itself.
175 * We may be called to swap an unused node, which contains all zeroes.
176 * This is why we allow the record offset to be zero.
178 if ((srcOffs
[i
] & 1) || (srcOffs
[i
] < sizeof(BTNodeDescriptor
) && srcOffs
[i
] != 0) || (srcOffs
[i
] >= src
->blockSize
)) {
179 printf("hfs_swap_BTNode: record #%d invalid offset (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
180 error
= fsBTInvalidHeaderErr
;
185 * Make sure the offsets are strictly increasing. Note that we're looping over
186 * them backwards, hence the order in the comparison.
188 if ((i
!= 0) && (srcOffs
[i
] >= srcOffs
[i
-1])) {
189 printf("hfs_swap_BTNode: offsets %d and %d out of order (0x%04X, 0x%04X)\n",
190 srcDesc
->numRecords
-i
-1, srcDesc
->numRecords
-i
, srcOffs
[i
], srcOffs
[i
-1]);
191 error
= fsBTInvalidHeaderErr
;
198 * Swap the records (ordered by frequency of access)
200 if ((srcDesc
->kind
== kBTIndexNode
) ||
201 (srcDesc
-> kind
== kBTLeafNode
)) {
203 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
204 error
= hfs_swap_HFSPlusBTInternalNode (src
, VTOC(vp
)->c_fileid
, direction
);
206 error
= hfs_swap_HFSBTInternalNode (src
, VTOC(vp
)->c_fileid
, direction
);
209 if (error
) goto fail
;
211 } else if (srcDesc
-> kind
== kBTMapNode
) {
212 /* Don't swap the bitmaps, they'll be done in the bitmap routines */
214 } else if (srcDesc
-> kind
== kBTHeaderNode
) {
215 /* The header's offset is hard-wired because we cannot trust the offset pointers. */
216 BTHeaderRec
*srcHead
= (BTHeaderRec
*)((char *)src
->buffer
+ sizeof(BTNodeDescriptor
));
218 srcHead
->treeDepth
= SWAP_BE16 (srcHead
->treeDepth
);
220 srcHead
->rootNode
= SWAP_BE32 (srcHead
->rootNode
);
221 srcHead
->leafRecords
= SWAP_BE32 (srcHead
->leafRecords
);
222 srcHead
->firstLeafNode
= SWAP_BE32 (srcHead
->firstLeafNode
);
223 srcHead
->lastLeafNode
= SWAP_BE32 (srcHead
->lastLeafNode
);
225 srcHead
->nodeSize
= SWAP_BE16 (srcHead
->nodeSize
);
226 srcHead
->maxKeyLength
= SWAP_BE16 (srcHead
->maxKeyLength
);
228 srcHead
->totalNodes
= SWAP_BE32 (srcHead
->totalNodes
);
229 srcHead
->freeNodes
= SWAP_BE32 (srcHead
->freeNodes
);
231 srcHead
->clumpSize
= SWAP_BE32 (srcHead
->clumpSize
);
232 srcHead
->attributes
= SWAP_BE32 (srcHead
->attributes
);
234 /* Don't swap srcHead->reserved1 */
235 /* Don't swap srcHead->btreeType; it's only one byte */
236 /* Don't swap srcHead->reserved2 */
237 /* Don't swap srcHead->reserved3 */
238 /* Don't swap bitmap */
242 * If we are doing a swap from in-memory to on-disk, then swap the node
243 * descriptor and record offsets after we're done using them.
245 if (direction
== kSwapBTNodeHostToBig
) {
247 * Sanity check and swap the forkward and backward links.
249 if (srcDesc
->fLink
>= btcb
->totalNodes
) {
250 printf("hfs_UNswap_BTNode: invalid forward link (0x%08X)\n", srcDesc
->fLink
);
251 error
= fsBTInvalidHeaderErr
;
254 if (srcDesc
->bLink
>= btcb
->totalNodes
) {
255 printf("hfs_UNswap_BTNode: invalid backward link (0x%08X)\n", srcDesc
->bLink
);
256 error
= fsBTInvalidHeaderErr
;
259 srcDesc
->fLink
= SWAP_BE32 (srcDesc
->fLink
);
260 srcDesc
->bLink
= SWAP_BE32 (srcDesc
->bLink
);
263 * Check srcDesc->kind. Don't swap it because it's only one byte.
265 if (srcDesc
->kind
< kBTLeafNode
|| srcDesc
->kind
> kBTMapNode
) {
266 printf("hfs_UNswap_BTNode: invalid node kind (%d)\n", srcDesc
->kind
);
267 error
= fsBTInvalidHeaderErr
;
272 * Check srcDesc->height. Don't swap it because it's only one byte.
274 if (srcDesc
->height
> btcb
->treeDepth
) {
275 printf("hfs_UNswap_BTNode: invalid node height (%d)\n", srcDesc
->height
);
276 error
= fsBTInvalidHeaderErr
;
280 /* Don't swap srcDesc->reserved */
283 * Swap the node offsets (including the free space one!).
285 srcOffs
= (UInt16
*)((char *)src
->buffer
+ (src
->blockSize
- ((srcDesc
->numRecords
+ 1) * sizeof (UInt16
))));
288 * Sanity check that the record offsets are within the node itself.
290 if ((char *)srcOffs
> ((char *)src
->buffer
+ src
->blockSize
) ||
291 (char *)srcOffs
< ((char *)src
->buffer
+ sizeof(BTNodeDescriptor
))) {
292 printf("hfs_UNswap_BTNode: invalid record count (0x%04X)\n", srcDesc
->numRecords
);
293 error
= fsBTInvalidHeaderErr
;
298 * Swap and sanity check each of the record offsets.
300 for (i
= 0; i
<= srcDesc
->numRecords
; i
++) {
302 * Sanity check: must be even, and within the node itself.
304 * We may be called to swap an unused node, which contains all zeroes.
305 * This is why we allow the record offset to be zero.
307 if ((srcOffs
[i
] & 1) || (srcOffs
[i
] < sizeof(BTNodeDescriptor
) && srcOffs
[i
] != 0) || (srcOffs
[i
] >= src
->blockSize
)) {
308 printf("hfs_UNswap_BTNode: record #%d invalid offset (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
309 error
= fsBTInvalidHeaderErr
;
314 * Make sure the offsets are strictly increasing. Note that we're looping over
315 * them backwards, hence the order in the comparison.
317 if ((i
< srcDesc
->numRecords
) && (srcOffs
[i
+1] >= srcOffs
[i
])) {
318 printf("hfs_UNswap_BTNode: offsets %d and %d out of order (0x%04X, 0x%04X)\n",
319 srcDesc
->numRecords
-i
-2, srcDesc
->numRecords
-i
-1, srcOffs
[i
+1], srcOffs
[i
]);
320 error
= fsBTInvalidHeaderErr
;
324 srcOffs
[i
] = SWAP_BE16 (srcOffs
[i
]);
327 srcDesc
->numRecords
= SWAP_BE16 (srcDesc
->numRecords
);
333 * Log some useful information about where the corrupt node is.
335 printf("node=%lld fileID=%u volume=%s device=%s\n", src
->blockNum
, VTOC(vp
)->c_fileid
,
336 VTOVCB(vp
)->vcbVN
, vfs_statfs(vnode_mount(vp
))->f_mntfromname
);
337 VTOVCB(vp
)->vcbFlags
|= kHFS_DamagedVolume
;
344 hfs_swap_HFSPlusBTInternalNode (
345 BlockDescriptor
*src
,
346 HFSCatalogNodeID fileID
,
347 enum HFSBTSwapDirection direction
350 BTNodeDescriptor
*srcDesc
= src
->buffer
;
351 UInt16
*srcOffs
= (UInt16
*)((char *)src
->buffer
+ (src
->blockSize
- (srcDesc
->numRecords
* sizeof (UInt16
))));
352 char *nextRecord
; /* Points to start of record following current one */
356 if (fileID
== kHFSExtentsFileID
) {
357 HFSPlusExtentKey
*srcKey
;
358 HFSPlusExtentDescriptor
*srcRec
;
359 size_t recordSize
; /* Size of the data part of the record, or node number for index nodes */
361 if (srcDesc
->kind
== kBTIndexNode
)
362 recordSize
= sizeof(UInt32
);
364 recordSize
= sizeof(HFSPlusExtentDescriptor
);
366 for (i
= 0; i
< srcDesc
->numRecords
; i
++) {
367 /* Point to the start of the record we're currently checking. */
368 srcKey
= (HFSPlusExtentKey
*)((char *)src
->buffer
+ srcOffs
[i
]);
371 * Point to start of next (larger offset) record. We'll use this
372 * to be sure the current record doesn't overflow into the next
375 nextRecord
= (char *)src
->buffer
+ srcOffs
[i
-1];
378 * Make sure the key and data are within the buffer. Since both key
379 * and data are fixed size, this is relatively easy. Note that this
380 * relies on the keyLength being a constant; we verify the keyLength
383 if ((char *)srcKey
+ sizeof(HFSPlusExtentKey
) + recordSize
> nextRecord
) {
384 printf("hfs_swap_HFSPlusBTInternalNode: extents key #%d offset too big (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
385 return fsBTInvalidNodeErr
;
388 if (direction
== kSwapBTNodeBigToHost
)
389 srcKey
->keyLength
= SWAP_BE16 (srcKey
->keyLength
);
390 if (srcKey
->keyLength
!= sizeof(*srcKey
) - sizeof(srcKey
->keyLength
)) {
391 printf("hfs_swap_HFSPlusBTInternalNode: extents key #%d invalid length (%d)\n", srcDesc
->numRecords
-i
-1, srcKey
->keyLength
);
392 return fsBTInvalidNodeErr
;
394 srcRec
= (HFSPlusExtentDescriptor
*)((char *)srcKey
+ srcKey
->keyLength
+ sizeof(srcKey
->keyLength
));
395 if (direction
== kSwapBTNodeHostToBig
)
396 srcKey
->keyLength
= SWAP_BE16 (srcKey
->keyLength
);
398 /* Don't swap srcKey->forkType; it's only one byte */
399 /* Don't swap srcKey->pad */
401 srcKey
->fileID
= SWAP_BE32 (srcKey
->fileID
);
402 srcKey
->startBlock
= SWAP_BE32 (srcKey
->startBlock
);
404 if (srcDesc
->kind
== kBTIndexNode
) {
405 /* For index nodes, the record data is just a child node number. */
406 *((UInt32
*)srcRec
) = SWAP_BE32 (*((UInt32
*)srcRec
));
408 /* Swap the extent data */
409 for (j
= 0; j
< kHFSPlusExtentDensity
; j
++) {
410 srcRec
[j
].startBlock
= SWAP_BE32 (srcRec
[j
].startBlock
);
411 srcRec
[j
].blockCount
= SWAP_BE32 (srcRec
[j
].blockCount
);
416 } else if (fileID
== kHFSCatalogFileID
) {
417 HFSPlusCatalogKey
*srcKey
;
421 for (i
= 0; i
< srcDesc
->numRecords
; i
++) {
422 /* Point to the start of the record we're currently checking. */
423 srcKey
= (HFSPlusCatalogKey
*)((char *)src
->buffer
+ srcOffs
[i
]);
426 * Point to start of next (larger offset) record. We'll use this
427 * to be sure the current record doesn't overflow into the next
430 nextRecord
= (char *)src
->buffer
+ srcOffs
[i
-1];
433 * Make sure we can safely dereference the keyLength and parentID fields. */
434 if ((char *)srcKey
+ offsetof(HFSPlusCatalogKey
, nodeName
.unicode
[0]) > nextRecord
) {
435 printf("hfs_swap_HFSPlusBTInternalNode: catalog key #%d offset too big (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
436 return fsBTInvalidNodeErr
;
440 * Swap and sanity check the key length
442 if (direction
== kSwapBTNodeBigToHost
)
443 srcKey
->keyLength
= SWAP_BE16 (srcKey
->keyLength
);
444 keyLength
= srcKey
->keyLength
; /* Put it in a local (native order) because we use it several times */
445 if (direction
== kSwapBTNodeHostToBig
)
446 srcKey
->keyLength
= SWAP_BE16 (keyLength
);
448 /* Sanity check the key length */
449 if (keyLength
< kHFSPlusCatalogKeyMinimumLength
|| keyLength
> kHFSPlusCatalogKeyMaximumLength
) {
450 printf("hfs_swap_HFSPlusBTInternalNode: catalog key #%d invalid length (%d)\n", srcDesc
->numRecords
-i
-1, keyLength
);
451 return fsBTInvalidNodeErr
;
455 * Make sure that we can safely dereference the record's type field or
456 * an index node's child node number.
458 srcPtr
= (SInt16
*)((char *)srcKey
+ keyLength
+ sizeof(srcKey
->keyLength
));
459 if ((char *)srcPtr
+ sizeof(UInt32
) > nextRecord
) {
460 printf("hfs_swap_HFSPlusBTInternalNode: catalog key #%d too big\n", srcDesc
->numRecords
-i
-1);
461 return fsBTInvalidNodeErr
;
464 srcKey
->parentID
= SWAP_BE32 (srcKey
->parentID
);
467 * Swap and sanity check the key's node name
469 if (direction
== kSwapBTNodeBigToHost
)
470 srcKey
->nodeName
.length
= SWAP_BE16 (srcKey
->nodeName
.length
);
471 /* Make sure name length is consistent with key length */
472 if (keyLength
< sizeof(srcKey
->parentID
) + sizeof(srcKey
->nodeName
.length
) +
473 srcKey
->nodeName
.length
*sizeof(srcKey
->nodeName
.unicode
[0])) {
474 printf("hfs_swap_HFSPlusBTInternalNode: catalog record #%d keyLength=%d expected=%d\n",
475 srcDesc
->numRecords
-i
, keyLength
, sizeof(srcKey
->parentID
) + sizeof(srcKey
->nodeName
.length
) +
476 srcKey
->nodeName
.length
*sizeof(srcKey
->nodeName
.unicode
[0]));
477 return fsBTInvalidNodeErr
;
479 for (j
= 0; j
< srcKey
->nodeName
.length
; j
++) {
480 srcKey
->nodeName
.unicode
[j
] = SWAP_BE16 (srcKey
->nodeName
.unicode
[j
]);
482 if (direction
== kSwapBTNodeHostToBig
)
483 srcKey
->nodeName
.length
= SWAP_BE16 (srcKey
->nodeName
.length
);
486 * For index nodes, the record data is just the child's node number.
487 * Skip over swapping the various types of catalog record.
489 if (srcDesc
->kind
== kBTIndexNode
) {
490 *((UInt32
*)srcPtr
) = SWAP_BE32 (*((UInt32
*)srcPtr
));
494 /* Make sure the recordType is in native order before using it. */
495 if (direction
== kSwapBTNodeBigToHost
)
496 srcPtr
[0] = SWAP_BE16 (srcPtr
[0]);
498 if (srcPtr
[0] == kHFSPlusFolderRecord
) {
499 HFSPlusCatalogFolder
*srcRec
= (HFSPlusCatalogFolder
*)srcPtr
;
500 if ((char *)srcRec
+ sizeof(*srcRec
) > nextRecord
) {
501 printf("hfs_swap_HFSPlusBTInternalNode: catalog folder record #%d too big\n", srcDesc
->numRecords
-i
-1);
502 return fsBTInvalidNodeErr
;
505 srcRec
->flags
= SWAP_BE16 (srcRec
->flags
);
506 srcRec
->valence
= SWAP_BE32 (srcRec
->valence
);
507 srcRec
->folderID
= SWAP_BE32 (srcRec
->folderID
);
508 srcRec
->createDate
= SWAP_BE32 (srcRec
->createDate
);
509 srcRec
->contentModDate
= SWAP_BE32 (srcRec
->contentModDate
);
510 srcRec
->attributeModDate
= SWAP_BE32 (srcRec
->attributeModDate
);
511 srcRec
->accessDate
= SWAP_BE32 (srcRec
->accessDate
);
512 srcRec
->backupDate
= SWAP_BE32 (srcRec
->backupDate
);
514 srcRec
->bsdInfo
.ownerID
= SWAP_BE32 (srcRec
->bsdInfo
.ownerID
);
515 srcRec
->bsdInfo
.groupID
= SWAP_BE32 (srcRec
->bsdInfo
.groupID
);
517 /* Don't swap srcRec->bsdInfo.adminFlags; it's only one byte */
518 /* Don't swap srcRec->bsdInfo.ownerFlags; it's only one byte */
520 srcRec
->bsdInfo
.fileMode
= SWAP_BE16 (srcRec
->bsdInfo
.fileMode
);
521 srcRec
->bsdInfo
.special
.iNodeNum
= SWAP_BE32 (srcRec
->bsdInfo
.special
.iNodeNum
);
523 srcRec
->textEncoding
= SWAP_BE32 (srcRec
->textEncoding
);
525 /* Don't swap srcRec->userInfo */
526 /* Don't swap srcRec->finderInfo */
527 /* Don't swap srcRec->reserved */
529 } else if (srcPtr
[0] == kHFSPlusFileRecord
) {
530 HFSPlusCatalogFile
*srcRec
= (HFSPlusCatalogFile
*)srcPtr
;
531 if ((char *)srcRec
+ sizeof(*srcRec
) > nextRecord
) {
532 printf("hfs_swap_HFSPlusBTInternalNode: catalog file record #%d too big\n", srcDesc
->numRecords
-i
-1);
533 return fsBTInvalidNodeErr
;
536 srcRec
->flags
= SWAP_BE16 (srcRec
->flags
);
538 srcRec
->fileID
= SWAP_BE32 (srcRec
->fileID
);
540 srcRec
->createDate
= SWAP_BE32 (srcRec
->createDate
);
541 srcRec
->contentModDate
= SWAP_BE32 (srcRec
->contentModDate
);
542 srcRec
->attributeModDate
= SWAP_BE32 (srcRec
->attributeModDate
);
543 srcRec
->accessDate
= SWAP_BE32 (srcRec
->accessDate
);
544 srcRec
->backupDate
= SWAP_BE32 (srcRec
->backupDate
);
546 srcRec
->bsdInfo
.ownerID
= SWAP_BE32 (srcRec
->bsdInfo
.ownerID
);
547 srcRec
->bsdInfo
.groupID
= SWAP_BE32 (srcRec
->bsdInfo
.groupID
);
549 /* Don't swap srcRec->bsdInfo.adminFlags; it's only one byte */
550 /* Don't swap srcRec->bsdInfo.ownerFlags; it's only one byte */
552 srcRec
->bsdInfo
.fileMode
= SWAP_BE16 (srcRec
->bsdInfo
.fileMode
);
553 srcRec
->bsdInfo
.special
.iNodeNum
= SWAP_BE32 (srcRec
->bsdInfo
.special
.iNodeNum
);
555 srcRec
->textEncoding
= SWAP_BE32 (srcRec
->textEncoding
);
557 /* Don't swap srcRec->reserved1 */
558 /* Don't swap srcRec->userInfo */
559 /* Don't swap srcRec->finderInfo */
560 /* Don't swap srcRec->reserved2 */
562 hfs_swap_HFSPlusForkData (&srcRec
->dataFork
);
563 hfs_swap_HFSPlusForkData (&srcRec
->resourceFork
);
565 } else if ((srcPtr
[0] == kHFSPlusFolderThreadRecord
) ||
566 (srcPtr
[0] == kHFSPlusFileThreadRecord
)) {
569 * Make sure there is room for parentID and name length.
571 HFSPlusCatalogThread
*srcRec
= (HFSPlusCatalogThread
*)srcPtr
;
572 if ((char *) &srcRec
->nodeName
.unicode
[0] > nextRecord
) {
573 printf("hfs_swap_HFSPlusBTInternalNode: catalog thread record #%d too big\n", srcDesc
->numRecords
-i
-1);
574 return fsBTInvalidNodeErr
;
577 /* Don't swap srcRec->reserved */
579 srcRec
->parentID
= SWAP_BE32 (srcRec
->parentID
);
581 if (direction
== kSwapBTNodeBigToHost
)
582 srcRec
->nodeName
.length
= SWAP_BE16 (srcRec
->nodeName
.length
);
585 * Make sure there is room for the name in the buffer.
586 * Then swap the characters of the name itself.
588 if ((char *) &srcRec
->nodeName
.unicode
[srcRec
->nodeName
.length
] > nextRecord
) {
589 printf("hfs_swap_HFSPlusBTInternalNode: catalog thread record #%d name too big\n", srcDesc
->numRecords
-i
-1);
590 return fsBTInvalidNodeErr
;
592 for (j
= 0; j
< srcRec
->nodeName
.length
; j
++) {
593 srcRec
->nodeName
.unicode
[j
] = SWAP_BE16 (srcRec
->nodeName
.unicode
[j
]);
596 if (direction
== kSwapBTNodeHostToBig
)
597 srcRec
->nodeName
.length
= SWAP_BE16 (srcRec
->nodeName
.length
);
600 printf("hfs_swap_HFSPlusBTInternalNode: unrecognized catalog record type (0x%04X; record #%d)\n", srcPtr
[0], srcDesc
->numRecords
-i
-1);
601 return fsBTInvalidNodeErr
;
604 /* We can swap the record type now that we're done using it. */
605 if (direction
== kSwapBTNodeHostToBig
)
606 srcPtr
[0] = SWAP_BE16 (srcPtr
[0]);
609 } else if (fileID
== kHFSAttributesFileID
) {
610 HFSPlusAttrKey
*srcKey
;
611 HFSPlusAttrRecord
*srcRec
;
613 u_int32_t attrSize
= 0;
615 for (i
= 0; i
< srcDesc
->numRecords
; i
++) {
616 /* Point to the start of the record we're currently checking. */
617 srcKey
= (HFSPlusAttrKey
*)((char *)src
->buffer
+ srcOffs
[i
]);
620 * Point to start of next (larger offset) record. We'll use this
621 * to be sure the current record doesn't overflow into the next
624 nextRecord
= (char *)src
->buffer
+ srcOffs
[i
-1];
626 /* Make sure there is room in the buffer for a minimal key */
627 if ((char *) &srcKey
->attrName
[1] > nextRecord
) {
628 printf("hfs_swap_HFSPlusBTInternalNode: attr key #%d offset too big (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
629 return fsBTInvalidNodeErr
;
632 /* Swap the key length field */
633 if (direction
== kSwapBTNodeBigToHost
)
634 srcKey
->keyLength
= SWAP_BE16(srcKey
->keyLength
);
635 keyLength
= srcKey
->keyLength
; /* Keep a copy in native order */
636 if (direction
== kSwapBTNodeHostToBig
)
637 srcKey
->keyLength
= SWAP_BE16(srcKey
->keyLength
);
640 * Make sure that we can safely dereference the record's type field or
641 * an index node's child node number.
643 srcRec
= (HFSPlusAttrRecord
*)((char *)srcKey
+ keyLength
+ sizeof(srcKey
->keyLength
));
644 if ((char *)srcRec
+ sizeof(u_int32_t
) > nextRecord
) {
645 printf("hfs_swap_HFSPlusBTInternalNode: attr key #%d too big (%d)\n", srcDesc
->numRecords
-i
-1, keyLength
);
646 return fsBTInvalidNodeErr
;
649 srcKey
->fileID
= SWAP_BE32(srcKey
->fileID
);
650 srcKey
->startBlock
= SWAP_BE32(srcKey
->startBlock
);
653 * Swap and check the attribute name
655 if (direction
== kSwapBTNodeBigToHost
)
656 srcKey
->attrNameLen
= SWAP_BE16(srcKey
->attrNameLen
);
657 /* Sanity check the attribute name length */
658 if (srcKey
->attrNameLen
> kHFSMaxAttrNameLen
|| keyLength
< (kHFSPlusAttrKeyMinimumLength
+ sizeof(u_int16_t
)*srcKey
->attrNameLen
)) {
659 printf("hfs_swap_HFSPlusBTInternalNode: attr key #%d keyLength=%d attrNameLen=%d\n", srcDesc
->numRecords
-i
-1, keyLength
, srcKey
->attrNameLen
);
660 return fsBTInvalidNodeErr
;
662 for (j
= 0; j
< srcKey
->attrNameLen
; j
++)
663 srcKey
->attrName
[j
] = SWAP_BE16(srcKey
->attrName
[j
]);
664 if (direction
== kSwapBTNodeHostToBig
)
665 srcKey
->attrNameLen
= SWAP_BE16(srcKey
->attrNameLen
);
668 * For index nodes, the record data is just the child's node number.
669 * Skip over swapping the various types of attribute record.
671 if (srcDesc
->kind
== kBTIndexNode
) {
672 *((UInt32
*)srcRec
) = SWAP_BE32 (*((UInt32
*)srcRec
));
676 /* Swap the record data */
677 if (direction
== kSwapBTNodeBigToHost
)
678 srcRec
->recordType
= SWAP_BE32(srcRec
->recordType
);
679 switch (srcRec
->recordType
) {
680 case kHFSPlusAttrInlineData
:
681 /* Is there room for the inline data header? */
682 if ((char *) &srcRec
->attrData
.attrData
[0] > nextRecord
) {
683 printf("hfs_swap_HFSPlusBTInternalNode: attr inline #%d too big\n", srcDesc
->numRecords
-i
-1);
684 return fsBTInvalidNodeErr
;
687 /* We're not swapping the reserved fields */
689 /* Swap the attribute size */
690 if (direction
== kSwapBTNodeHostToBig
)
691 attrSize
= srcRec
->attrData
.attrSize
;
692 srcRec
->attrData
.attrSize
= SWAP_BE32(srcRec
->attrData
.attrSize
);
693 if (direction
== kSwapBTNodeBigToHost
)
694 attrSize
= srcRec
->attrData
.attrSize
;
696 /* Is there room for the inline attribute data? */
697 if ((char *) &srcRec
->attrData
.attrData
[attrSize
] > nextRecord
) {
698 printf("hfs_swap_HFSPlusBTInternalNode: attr inline #%d too big (attrSize=%u)\n", srcDesc
->numRecords
-i
-1, attrSize
);
699 return fsBTInvalidNodeErr
;
702 /* Not swapping the attribute data itself */
705 case kHFSPlusAttrForkData
:
706 /* Is there room for the fork data record? */
707 if ((char *)srcRec
+ sizeof(HFSPlusAttrForkData
) > nextRecord
) {
708 printf("hfs_swap_HFSPlusBTInternalNode: attr fork data #%d too big\n", srcDesc
->numRecords
-i
-1);
709 return fsBTInvalidNodeErr
;
712 /* We're not swapping the reserved field */
714 hfs_swap_HFSPlusForkData(&srcRec
->forkData
.theFork
);
717 case kHFSPlusAttrExtents
:
718 /* Is there room for an extent record? */
719 if ((char *)srcRec
+ sizeof(HFSPlusAttrExtents
) > nextRecord
) {
720 printf("hfs_swap_HFSPlusBTInternalNode: attr extents #%d too big\n", srcDesc
->numRecords
-i
-1);
721 return fsBTInvalidNodeErr
;
724 /* We're not swapping the reserved field */
726 for (j
= 0; j
< kHFSPlusExtentDensity
; j
++) {
727 srcRec
->overflowExtents
.extents
[j
].startBlock
=
728 SWAP_BE32(srcRec
->overflowExtents
.extents
[j
].startBlock
);
729 srcRec
->overflowExtents
.extents
[j
].blockCount
=
730 SWAP_BE32(srcRec
->overflowExtents
.extents
[j
].blockCount
);
734 if (direction
== kSwapBTNodeHostToBig
)
735 srcRec
->recordType
= SWAP_BE32(srcRec
->recordType
);
737 } else if (fileID
> kHFSFirstUserCatalogNodeID
) {
738 /* The only B-tree with a non-system CNID that we use is the hotfile B-tree */
742 for (i
= 0; i
< srcDesc
->numRecords
; i
++) {
743 /* Point to the start of the record we're currently checking. */
744 srcKey
= (HotFileKey
*)((char *)src
->buffer
+ srcOffs
[i
]);
747 * Point to start of next (larger offset) record. We'll use this
748 * to be sure the current record doesn't overflow into the next
751 nextRecord
= (char *)src
->buffer
+ srcOffs
[i
-1];
753 /* Make sure there is room for the key (HotFileKey) and data (UInt32) */
754 if ((char *)srcKey
+ sizeof(HotFileKey
) + sizeof(UInt32
) > nextRecord
) {
755 printf("hfs_swap_HFSPlusBTInternalNode: hotfile #%d offset too big (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
756 return fsBTInvalidNodeErr
;
759 /* Swap and sanity check the key length field */
760 if (direction
== kSwapBTNodeBigToHost
)
761 srcKey
->keyLength
= SWAP_BE16 (srcKey
->keyLength
);
762 if (srcKey
->keyLength
!= sizeof(*srcKey
) - sizeof(srcKey
->keyLength
)) {
763 printf("hfs_swap_HFSPlusBTInternalNode: hotfile #%d incorrect keyLength %d\n", srcDesc
->numRecords
-i
-1, srcKey
->keyLength
);
764 return fsBTInvalidNodeErr
;
766 srcRec
= (u_int32_t
*)((char *)srcKey
+ srcKey
->keyLength
+ sizeof(srcKey
->keyLength
));
767 if (direction
== kSwapBTNodeHostToBig
)
768 srcKey
->keyLength
= SWAP_BE16 (srcKey
->keyLength
);
770 /* Don't swap srcKey->forkType */
771 /* Don't swap srcKey->pad */
773 srcKey
->temperature
= SWAP_BE32 (srcKey
->temperature
);
774 srcKey
->fileID
= SWAP_BE32 (srcKey
->fileID
);
776 *((UInt32
*)srcRec
) = SWAP_BE32 (*((UInt32
*)srcRec
));
779 panic ("hfs_swap_HFSPlusBTInternalNode: fileID %u is not a system B-tree\n", fileID
);
787 hfs_swap_HFSBTInternalNode (
788 BlockDescriptor
*src
,
789 HFSCatalogNodeID fileID
,
790 enum HFSBTSwapDirection direction
793 BTNodeDescriptor
*srcDesc
= src
->buffer
;
794 UInt16
*srcOffs
= (UInt16
*)((char *)src
->buffer
+ (src
->blockSize
- (srcDesc
->numRecords
* sizeof (UInt16
))));
795 char *nextRecord
; /* Points to start of record following current one */
800 if (fileID
== kHFSExtentsFileID
) {
801 HFSExtentKey
*srcKey
;
802 HFSExtentDescriptor
*srcRec
;
803 size_t recordSize
; /* Size of the data part of the record, or node number for index nodes */
805 if (srcDesc
->kind
== kBTIndexNode
)
806 recordSize
= sizeof(UInt32
);
808 recordSize
= sizeof(HFSExtentDescriptor
);
810 for (i
= 0; i
< srcDesc
->numRecords
; i
++) {
811 /* Point to the start of the record we're currently checking. */
812 srcKey
= (HFSExtentKey
*)((char *)src
->buffer
+ srcOffs
[i
]);
815 * Point to start of next (larger offset) record. We'll use this
816 * to be sure the current record doesn't overflow into the next
819 nextRecord
= (char *)src
->buffer
+ srcOffs
[i
-1];
822 * Make sure the key and data are within the buffer. Since both key
823 * and data are fixed size, this is relatively easy. Note that this
824 * relies on the keyLength being a constant; we verify the keyLength
827 if ((char *)srcKey
+ sizeof(HFSExtentKey
) + recordSize
> nextRecord
) {
828 printf("hfs_swap_HFSBTInternalNode: extents key #%d offset too big (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
829 return fsBTInvalidNodeErr
;
832 /* Don't swap srcKey->keyLength (it's only one byte), but do sanity check it */
833 if (srcKey
->keyLength
!= sizeof(*srcKey
) - sizeof(srcKey
->keyLength
)) {
834 printf("hfs_swap_HFSBTInternalNode: extents key #%d invalid length (%d)\n", srcDesc
->numRecords
-i
-1, srcKey
->keyLength
);
835 return fsBTInvalidNodeErr
;
838 /* Don't swap srcKey->forkType; it's only one byte */
840 srcKey
->fileID
= SWAP_BE32 (srcKey
->fileID
);
841 srcKey
->startBlock
= SWAP_BE16 (srcKey
->startBlock
);
843 /* Point to record data (round up to even byte boundary) */
844 srcRec
= (HFSExtentDescriptor
*)((char *)srcKey
+ ((srcKey
->keyLength
+ 2) & ~1));
846 if (srcDesc
->kind
== kBTIndexNode
) {
847 /* For index nodes, the record data is just a child node number. */
848 *((UInt32
*)srcRec
) = SWAP_BE32 (*((UInt32
*)srcRec
));
850 /* Swap the extent data */
851 for (j
= 0; j
< kHFSExtentDensity
; j
++) {
852 srcRec
[j
].startBlock
= SWAP_BE16 (srcRec
[j
].startBlock
);
853 srcRec
[j
].blockCount
= SWAP_BE16 (srcRec
[j
].blockCount
);
858 } else if (fileID
== kHFSCatalogFileID
) {
859 HFSCatalogKey
*srcKey
;
861 unsigned expectedKeyLength
;
863 for (i
= 0; i
< srcDesc
->numRecords
; i
++) {
864 /* Point to the start of the record we're currently checking. */
865 srcKey
= (HFSCatalogKey
*)((char *)src
->buffer
+ srcOffs
[i
]);
868 * Point to start of next (larger offset) record. We'll use this
869 * to be sure the current record doesn't overflow into the next
872 nextRecord
= (char *)src
->buffer
+ srcOffs
[i
-1];
875 * Make sure we can safely dereference the keyLength and parentID fields.
876 * The value 8 below is 1 bytes for keyLength + 1 byte reserved + 4 bytes
877 * for parentID + 1 byte for nodeName's length + 1 byte to round up the
878 * record start to an even offset, which forms a minimal key.
880 if ((char *)srcKey
+ 8 > nextRecord
) {
881 printf("hfs_swap_HFSBTInternalNode: catalog key #%d offset too big (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
882 return fsBTInvalidNodeErr
;
885 /* Don't swap srcKey->keyLength (it's only one byte), but do sanity check it */
886 if (srcKey
->keyLength
< kHFSCatalogKeyMinimumLength
|| srcKey
->keyLength
> kHFSCatalogKeyMaximumLength
) {
887 printf("hfs_swap_HFSBTInternalNode: catalog key #%d invalid length (%d)\n", srcDesc
->numRecords
-i
-1, srcKey
->keyLength
);
888 return fsBTInvalidNodeErr
;
891 /* Don't swap srcKey->reserved */
893 srcKey
->parentID
= SWAP_BE32 (srcKey
->parentID
);
895 /* Don't swap srcKey->nodeName */
897 /* Make sure the keyLength is big enough for the key's content */
898 if (srcDesc
->kind
== kBTIndexNode
)
899 expectedKeyLength
= sizeof(*srcKey
) - sizeof(srcKey
->keyLength
);
901 expectedKeyLength
= srcKey
->nodeName
[0] + kHFSCatalogKeyMinimumLength
;
902 if (srcKey
->keyLength
< expectedKeyLength
) {
903 printf("hfs_swap_HFSBTInternalNode: catalog record #%d keyLength=%u expected=%u\n",
904 srcDesc
->numRecords
-i
, srcKey
->keyLength
, expectedKeyLength
);
905 return fsBTInvalidNodeErr
;
908 /* Point to record data (round up to even byte boundary) */
909 srcPtr
= (SInt16
*)((char *)srcKey
+ ((srcKey
->keyLength
+ 2) & ~1));
912 * Make sure that we can safely dereference the record's type field or
913 * and index node's child node number.
915 if ((char *)srcPtr
+ sizeof(UInt32
) > nextRecord
) {
916 printf("hfs_swap_HFSBTInternalNode: catalog key #%d too big\n", srcDesc
->numRecords
-i
-1);
917 return fsBTInvalidNodeErr
;
921 * For index nodes, the record data is just the child's node number.
922 * Skip over swapping the various types of catalog record.
924 if (srcDesc
->kind
== kBTIndexNode
) {
925 *((UInt32
*)srcPtr
) = SWAP_BE32 (*((UInt32
*)srcPtr
));
929 /* Make sure the recordType is in native order before using it. */
930 if (direction
== kSwapBTNodeBigToHost
)
931 srcPtr
[0] = SWAP_BE16 (srcPtr
[0]);
933 if (srcPtr
[0] == kHFSFolderRecord
) {
934 HFSCatalogFolder
*srcRec
= (HFSCatalogFolder
*)srcPtr
;
935 if ((char *)srcRec
+ sizeof(*srcRec
) > nextRecord
) {
936 printf("hfs_swap_HFSBTInternalNode: catalog folder record #%d too big\n", srcDesc
->numRecords
-i
-1);
937 return fsBTInvalidNodeErr
;
940 srcRec
->flags
= SWAP_BE16 (srcRec
->flags
);
941 srcRec
->valence
= SWAP_BE16 (srcRec
->valence
);
943 srcRec
->folderID
= SWAP_BE32 (srcRec
->folderID
);
944 srcRec
->createDate
= SWAP_BE32 (srcRec
->createDate
);
945 srcRec
->modifyDate
= SWAP_BE32 (srcRec
->modifyDate
);
946 srcRec
->backupDate
= SWAP_BE32 (srcRec
->backupDate
);
948 /* Don't swap srcRec->userInfo */
949 /* Don't swap srcRec->finderInfo */
950 /* Don't swap resserved array */
952 } else if (srcPtr
[0] == kHFSFileRecord
) {
953 HFSCatalogFile
*srcRec
= (HFSCatalogFile
*)srcPtr
;
954 if ((char *)srcRec
+ sizeof(*srcRec
) > nextRecord
) {
955 printf("hfs_swap_HFSBTInternalNode: catalog file record #%d too big\n", srcDesc
->numRecords
-i
-1);
956 return fsBTInvalidNodeErr
;
959 srcRec
->flags
= srcRec
->flags
;
960 srcRec
->fileType
= srcRec
->fileType
;
962 /* Don't swap srcRec->userInfo */
964 srcRec
->fileID
= SWAP_BE32 (srcRec
->fileID
);
966 srcRec
->dataStartBlock
= SWAP_BE16 (srcRec
->dataStartBlock
);
967 srcRec
->dataLogicalSize
= SWAP_BE32 (srcRec
->dataLogicalSize
);
968 srcRec
->dataPhysicalSize
= SWAP_BE32 (srcRec
->dataPhysicalSize
);
970 srcRec
->rsrcStartBlock
= SWAP_BE16 (srcRec
->rsrcStartBlock
);
971 srcRec
->rsrcLogicalSize
= SWAP_BE32 (srcRec
->rsrcLogicalSize
);
972 srcRec
->rsrcPhysicalSize
= SWAP_BE32 (srcRec
->rsrcPhysicalSize
);
974 srcRec
->createDate
= SWAP_BE32 (srcRec
->createDate
);
975 srcRec
->modifyDate
= SWAP_BE32 (srcRec
->modifyDate
);
976 srcRec
->backupDate
= SWAP_BE32 (srcRec
->backupDate
);
978 /* Don't swap srcRec->finderInfo */
980 srcRec
->clumpSize
= SWAP_BE16 (srcRec
->clumpSize
);
982 /* Swap the two sets of extents as an array of six (three each) UInt16 */
983 for (j
= 0; j
< kHFSExtentDensity
* 2; j
++) {
984 srcRec
->dataExtents
[j
].startBlock
= SWAP_BE16 (srcRec
->dataExtents
[j
].startBlock
);
985 srcRec
->dataExtents
[j
].blockCount
= SWAP_BE16 (srcRec
->dataExtents
[j
].blockCount
);
988 /* Don't swap srcRec->reserved */
990 } else if ((srcPtr
[0] == kHFSFolderThreadRecord
) ||
991 (srcPtr
[0] == kHFSFileThreadRecord
)) {
992 HFSCatalogThread
*srcRec
= (HFSCatalogThread
*)srcPtr
;
994 /* Make sure there is room for parentID and name length */
995 if ((char *) &srcRec
->nodeName
[1] > nextRecord
) {
996 printf("hfs_swap_HFSBTInternalNode: catalog thread record #%d too big\n", srcDesc
->numRecords
-i
-1);
997 return fsBTInvalidNodeErr
;
1000 /* Don't swap srcRec->reserved array */
1002 srcRec
->parentID
= SWAP_BE32 (srcRec
->parentID
);
1004 /* Don't swap srcRec->nodeName */
1006 /* Make sure there is room for the name in the buffer */
1007 if ((char *) &srcRec
->nodeName
[srcRec
->nodeName
[0]] > nextRecord
) {
1008 printf("hfs_swap_HFSBTInternalNode: catalog thread record #%d name too big\n", srcDesc
->numRecords
-i
-1);
1009 return fsBTInvalidNodeErr
;
1012 printf("hfs_swap_HFSBTInternalNode: unrecognized catalog record type (0x%04X; record #%d)\n", srcPtr
[0], srcDesc
->numRecords
-i
-1);
1013 return fsBTInvalidNodeErr
;
1016 /* We can swap the record type now that we're done using it */
1017 if (direction
== kSwapBTNodeHostToBig
)
1018 srcPtr
[0] = SWAP_BE16 (srcPtr
[0]);
1022 panic ("hfs_swap_HFSBTInternalNode: fileID %u is not a system B-tree\n", fileID
);