2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * This file implements endian swapping routines for the HFS/HFS Plus
36 #include "hfs_endian.h"
38 #include "hfscommon/headers/BTreesPrivate.h"
43 * Internal swapping routines
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).
49 * The direction parameter must be kSwapBTNodeBigToHost or kSwapBTNodeHostToBig.
50 * The kSwapBTNodeHeaderRecordOnly "direction" is not valid for these routines.
52 static int hfs_swap_HFSPlusBTInternalNode (BlockDescriptor
*src
, HFSCatalogNodeID fileID
, enum HFSBTSwapDirection direction
);
53 static int hfs_swap_HFSBTInternalNode (BlockDescriptor
*src
, HFSCatalogNodeID fileID
, enum HFSBTSwapDirection direction
);
56 * hfs_swap_HFSPlusForkData
59 hfs_swap_HFSPlusForkData (
65 src
->logicalSize
= SWAP_BE64 (src
->logicalSize
);
67 src
->clumpSize
= SWAP_BE32 (src
->clumpSize
);
68 src
->totalBlocks
= SWAP_BE32 (src
->totalBlocks
);
70 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
71 src
->extents
[i
].startBlock
= SWAP_BE32 (src
->extents
[i
].startBlock
);
72 src
->extents
[i
].blockCount
= SWAP_BE32 (src
->extents
[i
].blockCount
);
79 * NOTE: This operation is not naturally symmetric.
80 * We have to determine which way we're swapping things.
86 enum HFSBTSwapDirection direction
,
87 u_int8_t allow_empty_node
90 BTNodeDescriptor
*srcDesc
= src
->buffer
;
91 u_int16_t
*srcOffs
= NULL
;
92 BTreeControlBlockPtr btcb
= (BTreeControlBlockPtr
)VTOF(vp
)->fcbBTCBPtr
;
93 u_int16_t i
; /* index to match srcDesc->numRecords */
97 if (direction
== kSwapBTNodeBigToHost
) {
98 printf ("hfs: BE -> Native Swap\n");
99 } else if (direction
== kSwapBTNodeHostToBig
) {
100 printf ("hfs: Native -> BE Swap\n");
101 } else if (direction
== kSwapBTNodeHeaderRecordOnly
) {
102 printf ("hfs: Not swapping descriptors\n");
104 panic ("hfs_swap_BTNode: This is impossible");
109 * If we are doing a swap from on-disk to in-memory, then swap the node
110 * descriptor and record offsets before we need to use them.
112 if (direction
== kSwapBTNodeBigToHost
) {
113 srcDesc
->fLink
= SWAP_BE32 (srcDesc
->fLink
);
114 srcDesc
->bLink
= SWAP_BE32 (srcDesc
->bLink
);
117 * When first opening a BTree, we have to read the header node before the
118 * control block is initialized. In this case, totalNodes will be zero,
119 * so skip the bounds checking. Also, we should ignore the header node when
120 * checking for invalid forwards and backwards links, since the header node's
121 * links can point back to itself legitimately.
123 if (btcb
->totalNodes
!= 0) {
124 if (srcDesc
->fLink
>= btcb
->totalNodes
) {
125 printf("hfs_swap_BTNode: invalid forward link (0x%08x >= 0x%08x)\n", srcDesc
->fLink
, btcb
->totalNodes
);
126 error
= fsBTInvalidHeaderErr
;
129 if (srcDesc
->bLink
>= btcb
->totalNodes
) {
130 printf("hfs_swap_BTNode: invalid backward link (0x%08x >= 0x%08x)\n", srcDesc
->bLink
, btcb
->totalNodes
);
131 error
= fsBTInvalidHeaderErr
;
135 if ((src
->blockNum
!= 0) && (srcDesc
->fLink
== (u_int32_t
) src
->blockNum
)) {
136 printf("hfs_swap_BTNode: invalid forward link (0x%08x == 0x%08x)\n",
137 srcDesc
->fLink
, (u_int32_t
) src
->blockNum
);
138 error
= fsBTInvalidHeaderErr
;
141 if ((src
->blockNum
!= 0) && (srcDesc
->bLink
== (u_int32_t
) src
->blockNum
)) {
142 printf("hfs_swap_BTNode: invalid backward link (0x%08x == 0x%08x)\n",
143 srcDesc
->bLink
, (u_int32_t
) src
->blockNum
);
144 error
= fsBTInvalidHeaderErr
;
152 * Check srcDesc->kind. Don't swap it because it's only one byte.
154 if (srcDesc
->kind
< kBTLeafNode
|| srcDesc
->kind
> kBTMapNode
) {
155 printf("hfs_swap_BTNode: invalid node kind (%d)\n", srcDesc
->kind
);
156 error
= fsBTInvalidHeaderErr
;
161 * Check srcDesc->height. Don't swap it because it's only one byte.
163 if (srcDesc
->height
> btcb
->treeDepth
) {
164 printf("hfs_swap_BTNode: invalid node height (%d)\n", srcDesc
->height
);
165 error
= fsBTInvalidHeaderErr
;
169 /* Don't swap srcDesc->reserved */
171 srcDesc
->numRecords
= SWAP_BE16 (srcDesc
->numRecords
);
174 * Swap the node offsets (including the free space one!).
176 srcOffs
= (u_int16_t
*)((char *)src
->buffer
+ (src
->blockSize
- ((srcDesc
->numRecords
+ 1) * sizeof (u_int16_t
))));
179 * Sanity check that the record offsets are within the node itself.
181 if ((char *)srcOffs
> ((char *)src
->buffer
+ src
->blockSize
) ||
182 (char *)srcOffs
< ((char *)src
->buffer
+ sizeof(BTNodeDescriptor
))) {
183 printf("hfs_swap_BTNode: invalid record count (0x%04X)\n", srcDesc
->numRecords
);
184 error
= fsBTInvalidHeaderErr
;
189 * Swap and sanity check each of the record offsets.
191 for (i
= 0; i
<= srcDesc
->numRecords
; i
++) {
192 srcOffs
[i
] = SWAP_BE16 (srcOffs
[i
]);
195 * Sanity check: must be even, and within the node itself.
197 * We may be called to swap an unused node, which contains all zeroes.
198 * Unused nodes are expected only when allow_empty_node is true.
199 * If it is false and record offset is zero, return error.
201 if ((srcOffs
[i
] & 1) || (
202 (allow_empty_node
== false) && (srcOffs
[i
] == 0)) ||
203 (srcOffs
[i
] < sizeof(BTNodeDescriptor
) && srcOffs
[i
] != 0) ||
204 (srcOffs
[i
] >= src
->blockSize
)) {
205 printf("hfs_swap_BTNode: record #%d invalid offset (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
206 error
= fsBTInvalidHeaderErr
;
211 * Make sure the offsets are strictly increasing. Note that we're looping over
212 * them backwards, hence the order in the comparison.
214 if ((i
!= 0) && (srcOffs
[i
] >= srcOffs
[i
-1])) {
215 printf("hfs_swap_BTNode: offsets %d and %d out of order (0x%04X, 0x%04X)\n",
216 srcDesc
->numRecords
-i
-1, srcDesc
->numRecords
-i
, srcOffs
[i
], srcOffs
[i
-1]);
217 error
= fsBTInvalidHeaderErr
;
224 * Swap the records (ordered by frequency of access)
226 if ((srcDesc
->kind
== kBTIndexNode
) ||
227 (srcDesc
-> kind
== kBTLeafNode
)) {
229 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
230 error
= hfs_swap_HFSPlusBTInternalNode (src
, VTOC(vp
)->c_fileid
, direction
);
232 error
= hfs_swap_HFSBTInternalNode (src
, VTOC(vp
)->c_fileid
, direction
);
235 if (error
) goto fail
;
237 } else if (srcDesc
-> kind
== kBTMapNode
) {
238 /* Don't swap the bitmaps, they'll be done in the bitmap routines */
240 } else if (srcDesc
-> kind
== kBTHeaderNode
) {
241 /* The header's offset is hard-wired because we cannot trust the offset pointers. */
242 BTHeaderRec
*srcHead
= (BTHeaderRec
*)((char *)src
->buffer
+ sizeof(BTNodeDescriptor
));
244 srcHead
->treeDepth
= SWAP_BE16 (srcHead
->treeDepth
);
246 srcHead
->rootNode
= SWAP_BE32 (srcHead
->rootNode
);
247 srcHead
->leafRecords
= SWAP_BE32 (srcHead
->leafRecords
);
248 srcHead
->firstLeafNode
= SWAP_BE32 (srcHead
->firstLeafNode
);
249 srcHead
->lastLeafNode
= SWAP_BE32 (srcHead
->lastLeafNode
);
251 srcHead
->nodeSize
= SWAP_BE16 (srcHead
->nodeSize
);
252 srcHead
->maxKeyLength
= SWAP_BE16 (srcHead
->maxKeyLength
);
254 srcHead
->totalNodes
= SWAP_BE32 (srcHead
->totalNodes
);
255 srcHead
->freeNodes
= SWAP_BE32 (srcHead
->freeNodes
);
257 srcHead
->clumpSize
= SWAP_BE32 (srcHead
->clumpSize
);
258 srcHead
->attributes
= SWAP_BE32 (srcHead
->attributes
);
260 /* Don't swap srcHead->reserved1 */
261 /* Don't swap srcHead->btreeType; it's only one byte */
262 /* Don't swap srcHead->reserved2 */
263 /* Don't swap srcHead->reserved3 */
264 /* Don't swap bitmap */
268 * If we are doing a swap from in-memory to on-disk, then swap the node
269 * descriptor and record offsets after we're done using them.
271 if (direction
== kSwapBTNodeHostToBig
) {
273 * Sanity check and swap the forward and backward links.
274 * Ignore the header node since its forward and backwards links can legitimately
277 if (srcDesc
->fLink
>= btcb
->totalNodes
) {
278 panic("hfs_UNswap_BTNode: invalid forward link (0x%08X)\n", srcDesc
->fLink
);
279 error
= fsBTInvalidHeaderErr
;
282 if ((src
->blockNum
!= 0) && (srcDesc
->fLink
== (u_int32_t
) src
->blockNum
)) {
283 panic ("hfs_UNswap_BTNode: invalid forward link (0x%08x == 0x%08x)\n",
284 srcDesc
->fLink
, (u_int32_t
) src
->blockNum
);
285 error
= fsBTInvalidHeaderErr
;
289 if (srcDesc
->bLink
>= btcb
->totalNodes
) {
290 panic("hfs_UNswap_BTNode: invalid backward link (0x%08X)\n", srcDesc
->bLink
);
291 error
= fsBTInvalidHeaderErr
;
294 if ((src
->blockNum
!= 0) && (srcDesc
->bLink
== (u_int32_t
) src
->blockNum
)) {
295 panic ("hfs_UNswap_BTNode: invalid backward link (0x%08x == 0x%08x)\n",
296 srcDesc
->bLink
, (u_int32_t
) src
->blockNum
);
297 error
= fsBTInvalidHeaderErr
;
302 srcDesc
->fLink
= SWAP_BE32 (srcDesc
->fLink
);
303 srcDesc
->bLink
= SWAP_BE32 (srcDesc
->bLink
);
306 * Check srcDesc->kind. Don't swap it because it's only one byte.
308 if (srcDesc
->kind
< kBTLeafNode
|| srcDesc
->kind
> kBTMapNode
) {
309 panic("hfs_UNswap_BTNode: invalid node kind (%d)\n", srcDesc
->kind
);
310 error
= fsBTInvalidHeaderErr
;
315 * Check srcDesc->height. Don't swap it because it's only one byte.
317 if (srcDesc
->height
> btcb
->treeDepth
) {
318 panic("hfs_UNswap_BTNode: invalid node height (%d)\n", srcDesc
->height
);
319 error
= fsBTInvalidHeaderErr
;
323 /* Don't swap srcDesc->reserved */
326 * Swap the node offsets (including the free space one!).
328 srcOffs
= (u_int16_t
*)((char *)src
->buffer
+ (src
->blockSize
- ((srcDesc
->numRecords
+ 1) * sizeof (u_int16_t
))));
331 * Sanity check that the record offsets are within the node itself.
333 if ((char *)srcOffs
> ((char *)src
->buffer
+ src
->blockSize
) ||
334 (char *)srcOffs
< ((char *)src
->buffer
+ sizeof(BTNodeDescriptor
))) {
335 panic("hfs_UNswap_BTNode: invalid record count (0x%04X)\n", srcDesc
->numRecords
);
336 error
= fsBTInvalidHeaderErr
;
341 * Swap and sanity check each of the record offsets.
343 for (i
= 0; i
<= srcDesc
->numRecords
; i
++) {
345 * Sanity check: must be even, and within the node itself.
347 * We may be called to swap an unused node, which contains all zeroes.
348 * This can happen when the last record from a node gets deleted.
349 * This is why we allow the record offset to be zero.
350 * Unused nodes are expected only when allow_empty_node is true
351 * (the caller should set it to true for kSwapBTNodeBigToHost).
353 if ((srcOffs
[i
] & 1) ||
354 ((allow_empty_node
== false) && (srcOffs
[i
] == 0)) ||
355 (srcOffs
[i
] < sizeof(BTNodeDescriptor
) && srcOffs
[i
] != 0) ||
356 (srcOffs
[i
] >= src
->blockSize
)) {
357 panic("hfs_UNswap_BTNode: record #%d invalid offset (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
358 error
= fsBTInvalidHeaderErr
;
363 * Make sure the offsets are strictly increasing. Note that we're looping over
364 * them backwards, hence the order in the comparison.
366 if ((i
< srcDesc
->numRecords
) && (srcOffs
[i
+1] >= srcOffs
[i
])) {
367 panic("hfs_UNswap_BTNode: offsets %d and %d out of order (0x%04X, 0x%04X)\n",
368 srcDesc
->numRecords
-i
-2, srcDesc
->numRecords
-i
-1, srcOffs
[i
+1], srcOffs
[i
]);
369 error
= fsBTInvalidHeaderErr
;
373 srcOffs
[i
] = SWAP_BE16 (srcOffs
[i
]);
376 srcDesc
->numRecords
= SWAP_BE16 (srcDesc
->numRecords
);
382 * Log some useful information about where the corrupt node is.
384 printf("hfs: node=%lld fileID=%u volume=%s device=%s\n", src
->blockNum
, VTOC(vp
)->c_fileid
,
385 VTOVCB(vp
)->vcbVN
, vfs_statfs(vnode_mount(vp
))->f_mntfromname
);
386 hfs_mark_volume_inconsistent(VTOVCB(vp
));
393 hfs_swap_HFSPlusBTInternalNode (
394 BlockDescriptor
*src
,
395 HFSCatalogNodeID fileID
,
396 enum HFSBTSwapDirection direction
399 BTNodeDescriptor
*srcDesc
= src
->buffer
;
400 u_int16_t
*srcOffs
= (u_int16_t
*)((char *)src
->buffer
+ (src
->blockSize
- (srcDesc
->numRecords
* sizeof (u_int16_t
))));
401 char *nextRecord
; /* Points to start of record following current one */
404 * i is an int32 because it needs to be negative to index the offset to free space.
405 * srcDesc->numRecords is a u_int16_t and is unlikely to become 32-bit so this should be ok.
411 if (fileID
== kHFSExtentsFileID
) {
412 HFSPlusExtentKey
*srcKey
;
413 HFSPlusExtentDescriptor
*srcRec
;
414 size_t recordSize
; /* Size of the data part of the record, or node number for index nodes */
416 if (srcDesc
->kind
== kBTIndexNode
)
417 recordSize
= sizeof(u_int32_t
);
419 recordSize
= sizeof(HFSPlusExtentDescriptor
);
421 for (i
= 0; i
< srcDesc
->numRecords
; i
++) {
422 /* Point to the start of the record we're currently checking. */
423 srcKey
= (HFSPlusExtentKey
*)((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 the key and data are within the buffer. Since both key
434 * and data are fixed size, this is relatively easy. Note that this
435 * relies on the keyLength being a constant; we verify the keyLength
438 if ((char *)srcKey
+ sizeof(HFSPlusExtentKey
) + recordSize
> nextRecord
) {
439 if (direction
== kSwapBTNodeHostToBig
) {
440 panic("hfs_swap_HFSPlusBTInternalNode: extents key #%d offset too big (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
442 printf("hfs_swap_HFSPlusBTInternalNode: extents key #%d offset too big (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
444 return fsBTInvalidNodeErr
;
447 if (direction
== kSwapBTNodeBigToHost
)
448 srcKey
->keyLength
= SWAP_BE16 (srcKey
->keyLength
);
449 if (srcKey
->keyLength
!= sizeof(*srcKey
) - sizeof(srcKey
->keyLength
)) {
450 if (direction
== kSwapBTNodeHostToBig
) {
451 panic("hfs_swap_HFSPlusBTInternalNode: extents key #%d invalid length (%d)\n", srcDesc
->numRecords
-i
-1, srcKey
->keyLength
);
453 printf("hfs_swap_HFSPlusBTInternalNode: extents key #%d invalid length (%d)\n", srcDesc
->numRecords
-i
-1, srcKey
->keyLength
);
455 return fsBTInvalidNodeErr
;
457 srcRec
= (HFSPlusExtentDescriptor
*)((char *)srcKey
+ srcKey
->keyLength
+ sizeof(srcKey
->keyLength
));
458 if (direction
== kSwapBTNodeHostToBig
)
459 srcKey
->keyLength
= SWAP_BE16 (srcKey
->keyLength
);
461 /* Don't swap srcKey->forkType; it's only one byte */
462 /* Don't swap srcKey->pad */
464 srcKey
->fileID
= SWAP_BE32 (srcKey
->fileID
);
465 srcKey
->startBlock
= SWAP_BE32 (srcKey
->startBlock
);
467 if (srcDesc
->kind
== kBTIndexNode
) {
468 /* For index nodes, the record data is just a child node number. */
469 *((u_int32_t
*)srcRec
) = SWAP_BE32 (*((u_int32_t
*)srcRec
));
471 /* Swap the extent data */
472 for (j
= 0; j
< kHFSPlusExtentDensity
; j
++) {
473 srcRec
[j
].startBlock
= SWAP_BE32 (srcRec
[j
].startBlock
);
474 srcRec
[j
].blockCount
= SWAP_BE32 (srcRec
[j
].blockCount
);
479 } else if (fileID
== kHFSCatalogFileID
) {
480 HFSPlusCatalogKey
*srcKey
;
484 for (i
= 0; i
< srcDesc
->numRecords
; i
++) {
485 /* Point to the start of the record we're currently checking. */
486 srcKey
= (HFSPlusCatalogKey
*)((char *)src
->buffer
+ srcOffs
[i
]);
489 * Point to start of next (larger offset) record. We'll use this
490 * to be sure the current record doesn't overflow into the next
493 nextRecord
= (char *)src
->buffer
+ (uintptr_t)(srcOffs
[i
-1]);
496 * Make sure we can safely dereference the keyLength and parentID fields.
498 if ((char *)srcKey
+ offsetof(HFSPlusCatalogKey
, nodeName
.unicode
[0]) > nextRecord
) {
499 if (direction
== kSwapBTNodeHostToBig
) {
500 panic("hfs_swap_HFSPlusBTInternalNode: catalog key #%d offset too big (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
502 printf("hfs_swap_HFSPlusBTInternalNode: catalog key #%d offset too big (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
504 return fsBTInvalidNodeErr
;
508 * Swap and sanity check the key length
510 if (direction
== kSwapBTNodeBigToHost
)
511 srcKey
->keyLength
= SWAP_BE16 (srcKey
->keyLength
);
512 keyLength
= srcKey
->keyLength
; /* Put it in a local (native order) because we use it several times */
513 if (direction
== kSwapBTNodeHostToBig
)
514 srcKey
->keyLength
= SWAP_BE16 (keyLength
);
516 /* Sanity check the key length */
517 if (keyLength
< kHFSPlusCatalogKeyMinimumLength
|| keyLength
> kHFSPlusCatalogKeyMaximumLength
) {
518 if (direction
== kSwapBTNodeHostToBig
) {
519 panic("hfs_swap_HFSPlusBTInternalNode: catalog key #%d invalid length (%d)\n", srcDesc
->numRecords
-i
-1, keyLength
);
521 printf("hfs_swap_HFSPlusBTInternalNode: catalog key #%d invalid length (%d)\n", srcDesc
->numRecords
-i
-1, keyLength
);
523 return fsBTInvalidNodeErr
;
527 * Make sure that we can safely dereference the record's type field or
528 * an index node's child node number.
530 srcPtr
= (int16_t *)((char *)srcKey
+ keyLength
+ sizeof(srcKey
->keyLength
));
531 if ((char *)srcPtr
+ sizeof(u_int32_t
) > nextRecord
) {
532 if (direction
== kSwapBTNodeHostToBig
) {
533 panic("hfs_swap_HFSPlusBTInternalNode: catalog key #%d too big\n", srcDesc
->numRecords
-i
-1);
535 printf("hfs_swap_HFSPlusBTInternalNode: catalog key #%d too big\n", srcDesc
->numRecords
-i
-1);
537 return fsBTInvalidNodeErr
;
540 srcKey
->parentID
= SWAP_BE32 (srcKey
->parentID
);
543 * Swap and sanity check the key's node name
545 if (direction
== kSwapBTNodeBigToHost
)
546 srcKey
->nodeName
.length
= SWAP_BE16 (srcKey
->nodeName
.length
);
547 /* Make sure name length is consistent with key length */
548 if (keyLength
< sizeof(srcKey
->parentID
) + sizeof(srcKey
->nodeName
.length
) +
549 srcKey
->nodeName
.length
*sizeof(srcKey
->nodeName
.unicode
[0])) {
550 if (direction
== kSwapBTNodeHostToBig
) {
551 panic("hfs_swap_HFSPlusBTInternalNode: catalog record #%d keyLength=%d expected=%lu\n",
552 srcDesc
->numRecords
-i
, keyLength
, sizeof(srcKey
->parentID
) + sizeof(srcKey
->nodeName
.length
) +
553 srcKey
->nodeName
.length
*sizeof(srcKey
->nodeName
.unicode
[0]));
555 printf("hfs_swap_HFSPlusBTInternalNode: catalog record #%d keyLength=%d expected=%lu\n",
556 srcDesc
->numRecords
-i
, keyLength
, sizeof(srcKey
->parentID
) + sizeof(srcKey
->nodeName
.length
) +
557 srcKey
->nodeName
.length
*sizeof(srcKey
->nodeName
.unicode
[0]));
559 return fsBTInvalidNodeErr
;
561 for (j
= 0; j
< srcKey
->nodeName
.length
; j
++) {
562 srcKey
->nodeName
.unicode
[j
] = SWAP_BE16 (srcKey
->nodeName
.unicode
[j
]);
564 if (direction
== kSwapBTNodeHostToBig
)
565 srcKey
->nodeName
.length
= SWAP_BE16 (srcKey
->nodeName
.length
);
568 * For index nodes, the record data is just the child's node number.
569 * Skip over swapping the various types of catalog record.
571 if (srcDesc
->kind
== kBTIndexNode
) {
572 *((u_int32_t
*)srcPtr
) = SWAP_BE32 (*((u_int32_t
*)srcPtr
));
576 /* Make sure the recordType is in native order before using it. */
577 if (direction
== kSwapBTNodeBigToHost
)
578 srcPtr
[0] = SWAP_BE16 (srcPtr
[0]);
580 if (srcPtr
[0] == kHFSPlusFolderRecord
) {
581 HFSPlusCatalogFolder
*srcRec
= (HFSPlusCatalogFolder
*)srcPtr
;
582 if ((char *)srcRec
+ sizeof(*srcRec
) > nextRecord
) {
583 if (direction
== kSwapBTNodeHostToBig
) {
584 panic("hfs_swap_HFSPlusBTInternalNode: catalog folder record #%d too big\n", srcDesc
->numRecords
-i
-1);
586 printf("hfs_swap_HFSPlusBTInternalNode: catalog folder record #%d too big\n", srcDesc
->numRecords
-i
-1);
588 return fsBTInvalidNodeErr
;
591 srcRec
->flags
= SWAP_BE16 (srcRec
->flags
);
592 srcRec
->valence
= SWAP_BE32 (srcRec
->valence
);
593 srcRec
->folderID
= SWAP_BE32 (srcRec
->folderID
);
594 srcRec
->createDate
= SWAP_BE32 (srcRec
->createDate
);
595 srcRec
->contentModDate
= SWAP_BE32 (srcRec
->contentModDate
);
596 srcRec
->attributeModDate
= SWAP_BE32 (srcRec
->attributeModDate
);
597 srcRec
->accessDate
= SWAP_BE32 (srcRec
->accessDate
);
598 srcRec
->backupDate
= SWAP_BE32 (srcRec
->backupDate
);
600 srcRec
->bsdInfo
.ownerID
= SWAP_BE32 (srcRec
->bsdInfo
.ownerID
);
601 srcRec
->bsdInfo
.groupID
= SWAP_BE32 (srcRec
->bsdInfo
.groupID
);
603 /* Don't swap srcRec->bsdInfo.adminFlags; it's only one byte */
604 /* Don't swap srcRec->bsdInfo.ownerFlags; it's only one byte */
606 srcRec
->bsdInfo
.fileMode
= SWAP_BE16 (srcRec
->bsdInfo
.fileMode
);
607 srcRec
->bsdInfo
.special
.iNodeNum
= SWAP_BE32 (srcRec
->bsdInfo
.special
.iNodeNum
);
609 srcRec
->textEncoding
= SWAP_BE32 (srcRec
->textEncoding
);
611 /* Don't swap srcRec->userInfo */
612 /* Don't swap srcRec->finderInfo */
613 srcRec
->folderCount
= SWAP_BE32 (srcRec
->folderCount
);
615 } else if (srcPtr
[0] == kHFSPlusFileRecord
) {
616 HFSPlusCatalogFile
*srcRec
= (HFSPlusCatalogFile
*)srcPtr
;
617 if ((char *)srcRec
+ sizeof(*srcRec
) > nextRecord
) {
618 if (direction
== kSwapBTNodeHostToBig
) {
619 panic("hfs_swap_HFSPlusBTInternalNode: catalog file record #%d too big\n", srcDesc
->numRecords
-i
-1);
621 printf("hfs_swap_HFSPlusBTInternalNode: catalog file record #%d too big\n", srcDesc
->numRecords
-i
-1);
623 return fsBTInvalidNodeErr
;
626 srcRec
->flags
= SWAP_BE16 (srcRec
->flags
);
628 srcRec
->fileID
= SWAP_BE32 (srcRec
->fileID
);
630 srcRec
->createDate
= SWAP_BE32 (srcRec
->createDate
);
631 srcRec
->contentModDate
= SWAP_BE32 (srcRec
->contentModDate
);
632 srcRec
->attributeModDate
= SWAP_BE32 (srcRec
->attributeModDate
);
633 srcRec
->accessDate
= SWAP_BE32 (srcRec
->accessDate
);
634 srcRec
->backupDate
= SWAP_BE32 (srcRec
->backupDate
);
636 srcRec
->bsdInfo
.ownerID
= SWAP_BE32 (srcRec
->bsdInfo
.ownerID
);
637 srcRec
->bsdInfo
.groupID
= SWAP_BE32 (srcRec
->bsdInfo
.groupID
);
639 /* Don't swap srcRec->bsdInfo.adminFlags; it's only one byte */
640 /* Don't swap srcRec->bsdInfo.ownerFlags; it's only one byte */
642 srcRec
->bsdInfo
.fileMode
= SWAP_BE16 (srcRec
->bsdInfo
.fileMode
);
643 srcRec
->bsdInfo
.special
.iNodeNum
= SWAP_BE32 (srcRec
->bsdInfo
.special
.iNodeNum
);
645 srcRec
->textEncoding
= SWAP_BE32 (srcRec
->textEncoding
);
647 /* If kHFSHasLinkChainBit is set, reserved1 is hl_FirstLinkID.
648 * In all other context, it is expected to be zero.
650 srcRec
->reserved1
= SWAP_BE32 (srcRec
->reserved1
);
652 /* Don't swap srcRec->userInfo */
653 /* Don't swap srcRec->finderInfo */
654 /* Don't swap srcRec->reserved2 */
656 hfs_swap_HFSPlusForkData (&srcRec
->dataFork
);
657 hfs_swap_HFSPlusForkData (&srcRec
->resourceFork
);
659 } else if ((srcPtr
[0] == kHFSPlusFolderThreadRecord
) ||
660 (srcPtr
[0] == kHFSPlusFileThreadRecord
)) {
663 * Make sure there is room for parentID and name length.
665 HFSPlusCatalogThread
*srcRec
= (HFSPlusCatalogThread
*)srcPtr
;
666 if ((char *) &srcRec
->nodeName
.unicode
[0] > nextRecord
) {
667 if (direction
== kSwapBTNodeHostToBig
) {
668 panic("hfs_swap_HFSPlusBTInternalNode: catalog thread record #%d too big\n", srcDesc
->numRecords
-i
-1);
670 printf("hfs_swap_HFSPlusBTInternalNode: catalog thread record #%d too big\n", srcDesc
->numRecords
-i
-1);
672 return fsBTInvalidNodeErr
;
675 /* Don't swap srcRec->reserved */
677 srcRec
->parentID
= SWAP_BE32 (srcRec
->parentID
);
679 if (direction
== kSwapBTNodeBigToHost
)
680 srcRec
->nodeName
.length
= SWAP_BE16 (srcRec
->nodeName
.length
);
683 * Make sure there is room for the name in the buffer.
684 * Then swap the characters of the name itself.
686 if ((char *) &srcRec
->nodeName
.unicode
[srcRec
->nodeName
.length
] > nextRecord
) {
687 if (direction
== kSwapBTNodeHostToBig
) {
688 panic("hfs_swap_HFSPlusBTInternalNode: catalog thread record #%d name too big\n", srcDesc
->numRecords
-i
-1);
690 printf("hfs_swap_HFSPlusBTInternalNode: catalog thread record #%d name too big\n", srcDesc
->numRecords
-i
-1);
692 return fsBTInvalidNodeErr
;
694 for (j
= 0; j
< srcRec
->nodeName
.length
; j
++) {
695 srcRec
->nodeName
.unicode
[j
] = SWAP_BE16 (srcRec
->nodeName
.unicode
[j
]);
698 if (direction
== kSwapBTNodeHostToBig
)
699 srcRec
->nodeName
.length
= SWAP_BE16 (srcRec
->nodeName
.length
);
702 if (direction
== kSwapBTNodeHostToBig
) {
703 panic("hfs_swap_HFSPlusBTInternalNode: unrecognized catalog record type (0x%04X; record #%d)\n", srcPtr
[0], srcDesc
->numRecords
-i
-1);
705 printf("hfs_swap_HFSPlusBTInternalNode: unrecognized catalog record type (0x%04X; record #%d)\n", srcPtr
[0], srcDesc
->numRecords
-i
-1);
707 return fsBTInvalidNodeErr
;
710 /* We can swap the record type now that we're done using it. */
711 if (direction
== kSwapBTNodeHostToBig
)
712 srcPtr
[0] = SWAP_BE16 (srcPtr
[0]);
715 } else if (fileID
== kHFSAttributesFileID
) {
716 HFSPlusAttrKey
*srcKey
;
717 HFSPlusAttrRecord
*srcRec
;
719 u_int32_t attrSize
= 0;
721 for (i
= 0; i
< srcDesc
->numRecords
; i
++) {
722 /* Point to the start of the record we're currently checking. */
723 srcKey
= (HFSPlusAttrKey
*)((char *)src
->buffer
+ srcOffs
[i
]);
726 * Point to start of next (larger offset) record. We'll use this
727 * to be sure the current record doesn't overflow into the next
730 nextRecord
= (char *)src
->buffer
+ srcOffs
[i
-1];
732 /* Make sure there is room in the buffer for a minimal key */
733 if ((char *) &srcKey
->attrName
[1] > nextRecord
) {
734 if (direction
== kSwapBTNodeHostToBig
) {
735 panic("hfs_swap_HFSPlusBTInternalNode: attr key #%d offset too big (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
737 printf("hfs_swap_HFSPlusBTInternalNode: attr key #%d offset too big (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
739 return fsBTInvalidNodeErr
;
742 /* Swap the key length field */
743 if (direction
== kSwapBTNodeBigToHost
)
744 srcKey
->keyLength
= SWAP_BE16(srcKey
->keyLength
);
745 keyLength
= srcKey
->keyLength
; /* Keep a copy in native order */
746 if (direction
== kSwapBTNodeHostToBig
)
747 srcKey
->keyLength
= SWAP_BE16(srcKey
->keyLength
);
750 * Make sure that we can safely dereference the record's type field or
751 * an index node's child node number.
753 srcRec
= (HFSPlusAttrRecord
*)((char *)srcKey
+ keyLength
+ sizeof(srcKey
->keyLength
));
754 if ((char *)srcRec
+ sizeof(u_int32_t
) > nextRecord
) {
755 if (direction
== kSwapBTNodeHostToBig
) {
756 panic("hfs_swap_HFSPlusBTInternalNode: attr key #%d too big (%d)\n", srcDesc
->numRecords
-i
-1, keyLength
);
758 printf("hfs_swap_HFSPlusBTInternalNode: attr key #%d too big (%d)\n", srcDesc
->numRecords
-i
-1, keyLength
);
760 return fsBTInvalidNodeErr
;
763 srcKey
->fileID
= SWAP_BE32(srcKey
->fileID
);
764 srcKey
->startBlock
= SWAP_BE32(srcKey
->startBlock
);
767 * Swap and check the attribute name
769 if (direction
== kSwapBTNodeBigToHost
)
770 srcKey
->attrNameLen
= SWAP_BE16(srcKey
->attrNameLen
);
771 /* Sanity check the attribute name length */
772 if (srcKey
->attrNameLen
> kHFSMaxAttrNameLen
|| keyLength
< (kHFSPlusAttrKeyMinimumLength
+ sizeof(u_int16_t
)*srcKey
->attrNameLen
)) {
773 if (direction
== kSwapBTNodeHostToBig
) {
774 panic("hfs_swap_HFSPlusBTInternalNode: attr key #%d keyLength=%d attrNameLen=%d\n", srcDesc
->numRecords
-i
-1, keyLength
, srcKey
->attrNameLen
);
776 printf("hfs_swap_HFSPlusBTInternalNode: attr key #%d keyLength=%d attrNameLen=%d\n", srcDesc
->numRecords
-i
-1, keyLength
, srcKey
->attrNameLen
);
778 return fsBTInvalidNodeErr
;
780 for (j
= 0; j
< srcKey
->attrNameLen
; j
++)
781 srcKey
->attrName
[j
] = SWAP_BE16(srcKey
->attrName
[j
]);
782 if (direction
== kSwapBTNodeHostToBig
)
783 srcKey
->attrNameLen
= SWAP_BE16(srcKey
->attrNameLen
);
786 * For index nodes, the record data is just the child's node number.
787 * Skip over swapping the various types of attribute record.
789 if (srcDesc
->kind
== kBTIndexNode
) {
790 *((u_int32_t
*)srcRec
) = SWAP_BE32 (*((u_int32_t
*)srcRec
));
794 /* Swap the record data */
795 if (direction
== kSwapBTNodeBigToHost
)
796 srcRec
->recordType
= SWAP_BE32(srcRec
->recordType
);
797 switch (srcRec
->recordType
) {
798 case kHFSPlusAttrInlineData
:
799 /* Is there room for the inline data header? */
800 if ((char *) &srcRec
->attrData
.attrData
[0] > nextRecord
) {
801 if (direction
== kSwapBTNodeHostToBig
) {
802 panic("hfs_swap_HFSPlusBTInternalNode: attr inline #%d too big\n", srcDesc
->numRecords
-i
-1);
804 printf("hfs_swap_HFSPlusBTInternalNode: attr inline #%d too big\n", srcDesc
->numRecords
-i
-1);
806 return fsBTInvalidNodeErr
;
809 /* We're not swapping the reserved fields */
811 /* Swap the attribute size */
812 if (direction
== kSwapBTNodeHostToBig
)
813 attrSize
= srcRec
->attrData
.attrSize
;
814 srcRec
->attrData
.attrSize
= SWAP_BE32(srcRec
->attrData
.attrSize
);
815 if (direction
== kSwapBTNodeBigToHost
)
816 attrSize
= srcRec
->attrData
.attrSize
;
818 /* Is there room for the inline attribute data? */
819 if ((char *) &srcRec
->attrData
.attrData
[attrSize
] > nextRecord
) {
820 if (direction
== kSwapBTNodeHostToBig
) {
821 panic("hfs_swap_HFSPlusBTInternalNode: attr inline #%d too big (attrSize=%u)\n", srcDesc
->numRecords
-i
-1, attrSize
);
823 printf("hfs_swap_HFSPlusBTInternalNode: attr inline #%d too big (attrSize=%u)\n", srcDesc
->numRecords
-i
-1, attrSize
);
825 return fsBTInvalidNodeErr
;
828 /* Not swapping the attribute data itself */
831 case kHFSPlusAttrForkData
:
832 /* Is there room for the fork data record? */
833 if ((char *)srcRec
+ sizeof(HFSPlusAttrForkData
) > nextRecord
) {
834 if (direction
== kSwapBTNodeHostToBig
) {
835 panic("hfs_swap_HFSPlusBTInternalNode: attr fork data #%d too big\n", srcDesc
->numRecords
-i
-1);
837 printf("hfs_swap_HFSPlusBTInternalNode: attr fork data #%d too big\n", srcDesc
->numRecords
-i
-1);
839 return fsBTInvalidNodeErr
;
842 /* We're not swapping the reserved field */
844 hfs_swap_HFSPlusForkData(&srcRec
->forkData
.theFork
);
847 case kHFSPlusAttrExtents
:
848 /* Is there room for an extent record? */
849 if ((char *)srcRec
+ sizeof(HFSPlusAttrExtents
) > nextRecord
) {
850 if (direction
== kSwapBTNodeHostToBig
) {
851 panic("hfs_swap_HFSPlusBTInternalNode: attr extents #%d too big\n", srcDesc
->numRecords
-i
-1);
853 printf("hfs_swap_HFSPlusBTInternalNode: attr extents #%d too big\n", srcDesc
->numRecords
-i
-1);
855 return fsBTInvalidNodeErr
;
858 /* We're not swapping the reserved field */
860 for (j
= 0; j
< kHFSPlusExtentDensity
; j
++) {
861 srcRec
->overflowExtents
.extents
[j
].startBlock
=
862 SWAP_BE32(srcRec
->overflowExtents
.extents
[j
].startBlock
);
863 srcRec
->overflowExtents
.extents
[j
].blockCount
=
864 SWAP_BE32(srcRec
->overflowExtents
.extents
[j
].blockCount
);
868 if (direction
== kSwapBTNodeHostToBig
)
869 srcRec
->recordType
= SWAP_BE32(srcRec
->recordType
);
871 } else if (fileID
> kHFSFirstUserCatalogNodeID
) {
872 /* The only B-tree with a non-system CNID that we use is the hotfile B-tree */
876 for (i
= 0; i
< srcDesc
->numRecords
; i
++) {
877 /* Point to the start of the record we're currently checking. */
878 srcKey
= (HotFileKey
*)((char *)src
->buffer
+ srcOffs
[i
]);
881 * Point to start of next (larger offset) record. We'll use this
882 * to be sure the current record doesn't overflow into the next
885 nextRecord
= (char *)src
->buffer
+ srcOffs
[i
-1];
887 /* Make sure there is room for the key (HotFileKey) and data (u_int32_t) */
888 if ((char *)srcKey
+ sizeof(HotFileKey
) + sizeof(u_int32_t
) > nextRecord
) {
889 if (direction
== kSwapBTNodeHostToBig
) {
890 panic("hfs_swap_HFSPlusBTInternalNode: hotfile #%d offset too big (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
892 printf("hfs_swap_HFSPlusBTInternalNode: hotfile #%d offset too big (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
894 return fsBTInvalidNodeErr
;
897 /* Swap and sanity check the key length field */
898 if (direction
== kSwapBTNodeBigToHost
)
899 srcKey
->keyLength
= SWAP_BE16 (srcKey
->keyLength
);
900 if (srcKey
->keyLength
!= sizeof(*srcKey
) - sizeof(srcKey
->keyLength
)) {
901 if (direction
== kSwapBTNodeHostToBig
) {
902 panic("hfs_swap_HFSPlusBTInternalNode: hotfile #%d incorrect keyLength %d\n", srcDesc
->numRecords
-i
-1, srcKey
->keyLength
);
904 printf("hfs_swap_HFSPlusBTInternalNode: hotfile #%d incorrect keyLength %d\n", srcDesc
->numRecords
-i
-1, srcKey
->keyLength
);
906 return fsBTInvalidNodeErr
;
908 srcRec
= (u_int32_t
*)((char *)srcKey
+ srcKey
->keyLength
+ sizeof(srcKey
->keyLength
));
909 if (direction
== kSwapBTNodeHostToBig
)
910 srcKey
->keyLength
= SWAP_BE16 (srcKey
->keyLength
);
912 /* Don't swap srcKey->forkType */
913 /* Don't swap srcKey->pad */
915 srcKey
->temperature
= SWAP_BE32 (srcKey
->temperature
);
916 srcKey
->fileID
= SWAP_BE32 (srcKey
->fileID
);
918 *((u_int32_t
*)srcRec
) = SWAP_BE32 (*((u_int32_t
*)srcRec
));
921 panic ("hfs_swap_HFSPlusBTInternalNode: fileID %u is not a system B-tree\n", fileID
);
929 hfs_swap_HFSBTInternalNode (
930 BlockDescriptor
*src
,
931 HFSCatalogNodeID fileID
,
932 enum HFSBTSwapDirection direction
935 BTNodeDescriptor
*srcDesc
= src
->buffer
;
936 u_int16_t
*srcOffs
= (u_int16_t
*)((char *)src
->buffer
+ (src
->blockSize
- (srcDesc
->numRecords
* sizeof (u_int16_t
))));
937 char *nextRecord
; /* Points to start of record following current one */
940 * i is an int32 because it needs to be negative to index the offset to free space.
941 * srcDesc->numRecords is a u_int16_t and is unlikely to become 32-bit so this should be ok.
946 if (fileID
== kHFSExtentsFileID
) {
947 HFSExtentKey
*srcKey
;
948 HFSExtentDescriptor
*srcRec
;
949 size_t recordSize
; /* Size of the data part of the record, or node number for index nodes */
951 if (srcDesc
->kind
== kBTIndexNode
)
952 recordSize
= sizeof(u_int32_t
);
954 recordSize
= sizeof(HFSExtentDescriptor
);
956 for (i
= 0; i
< srcDesc
->numRecords
; i
++) {
957 /* Point to the start of the record we're currently checking. */
958 srcKey
= (HFSExtentKey
*)((char *)src
->buffer
+ srcOffs
[i
]);
961 * Point to start of next (larger offset) record. We'll use this
962 * to be sure the current record doesn't overflow into the next
965 nextRecord
= (char *)src
->buffer
+ srcOffs
[i
-1];
968 * Make sure the key and data are within the buffer. Since both key
969 * and data are fixed size, this is relatively easy. Note that this
970 * relies on the keyLength being a constant; we verify the keyLength
973 if ((char *)srcKey
+ sizeof(HFSExtentKey
) + recordSize
> nextRecord
) {
974 if (direction
== kSwapBTNodeHostToBig
) {
975 panic("hfs_swap_HFSBTInternalNode: extents key #%d offset too big (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
977 printf("hfs_swap_HFSBTInternalNode: extents key #%d offset too big (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
979 return fsBTInvalidNodeErr
;
982 /* Don't swap srcKey->keyLength (it's only one byte), but do sanity check it */
983 if (srcKey
->keyLength
!= sizeof(*srcKey
) - sizeof(srcKey
->keyLength
)) {
984 if (direction
== kSwapBTNodeHostToBig
) {
985 panic("hfs_swap_HFSBTInternalNode: extents key #%d invalid length (%d)\n", srcDesc
->numRecords
-i
-1, srcKey
->keyLength
);
987 printf("hfs_swap_HFSBTInternalNode: extents key #%d invalid length (%d)\n", srcDesc
->numRecords
-i
-1, srcKey
->keyLength
);
989 return fsBTInvalidNodeErr
;
992 /* Don't swap srcKey->forkType; it's only one byte */
994 srcKey
->fileID
= SWAP_BE32 (srcKey
->fileID
);
995 srcKey
->startBlock
= SWAP_BE16 (srcKey
->startBlock
);
997 /* Point to record data (round up to even byte boundary) */
998 srcRec
= (HFSExtentDescriptor
*)((char *)srcKey
+ ((srcKey
->keyLength
+ 2) & ~1));
1000 if (srcDesc
->kind
== kBTIndexNode
) {
1001 /* For index nodes, the record data is just a child node number. */
1002 *((u_int32_t
*)srcRec
) = SWAP_BE32 (*((u_int32_t
*)srcRec
));
1004 /* Swap the extent data */
1005 for (j
= 0; j
< kHFSExtentDensity
; j
++) {
1006 srcRec
[j
].startBlock
= SWAP_BE16 (srcRec
[j
].startBlock
);
1007 srcRec
[j
].blockCount
= SWAP_BE16 (srcRec
[j
].blockCount
);
1012 } else if (fileID
== kHFSCatalogFileID
) {
1013 HFSCatalogKey
*srcKey
;
1015 unsigned expectedKeyLength
;
1017 for (i
= 0; i
< srcDesc
->numRecords
; i
++) {
1018 /* Point to the start of the record we're currently checking. */
1019 srcKey
= (HFSCatalogKey
*)((char *)src
->buffer
+ srcOffs
[i
]);
1022 * Point to start of next (larger offset) record. We'll use this
1023 * to be sure the current record doesn't overflow into the next
1026 nextRecord
= (char *)src
->buffer
+ srcOffs
[i
-1];
1029 * Make sure we can safely dereference the keyLength and parentID fields.
1030 * The value 8 below is 1 bytes for keyLength + 1 byte reserved + 4 bytes
1031 * for parentID + 1 byte for nodeName's length + 1 byte to round up the
1032 * record start to an even offset, which forms a minimal key.
1034 if ((char *)srcKey
+ 8 > nextRecord
) {
1035 if (direction
== kSwapBTNodeHostToBig
) {
1036 panic("hfs_swap_HFSBTInternalNode: catalog key #%d offset too big (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
1038 printf("hfs_swap_HFSBTInternalNode: catalog key #%d offset too big (0x%04X)\n", srcDesc
->numRecords
-i
-1, srcOffs
[i
]);
1040 return fsBTInvalidNodeErr
;
1043 /* Don't swap srcKey->keyLength (it's only one byte), but do sanity check it */
1044 if (srcKey
->keyLength
< kHFSCatalogKeyMinimumLength
|| srcKey
->keyLength
> kHFSCatalogKeyMaximumLength
) {
1045 if (direction
== kSwapBTNodeHostToBig
) {
1046 panic("hfs_swap_HFSBTInternalNode: catalog key #%d invalid length (%d)\n", srcDesc
->numRecords
-i
-1, srcKey
->keyLength
);
1048 printf("hfs_swap_HFSBTInternalNode: catalog key #%d invalid length (%d)\n", srcDesc
->numRecords
-i
-1, srcKey
->keyLength
);
1050 return fsBTInvalidNodeErr
;
1053 /* Don't swap srcKey->reserved */
1055 srcKey
->parentID
= SWAP_BE32 (srcKey
->parentID
);
1057 /* Don't swap srcKey->nodeName */
1059 /* Make sure the keyLength is big enough for the key's content */
1060 if (srcDesc
->kind
== kBTIndexNode
)
1061 expectedKeyLength
= sizeof(*srcKey
) - sizeof(srcKey
->keyLength
);
1063 expectedKeyLength
= srcKey
->nodeName
[0] + kHFSCatalogKeyMinimumLength
;
1064 if (srcKey
->keyLength
< expectedKeyLength
) {
1065 if (direction
== kSwapBTNodeHostToBig
) {
1066 panic("hfs_swap_HFSBTInternalNode: catalog record #%d keyLength=%u expected=%u\n",
1067 srcDesc
->numRecords
-i
, srcKey
->keyLength
, expectedKeyLength
);
1069 printf("hfs_swap_HFSBTInternalNode: catalog record #%d keyLength=%u expected=%u\n",
1070 srcDesc
->numRecords
-i
, srcKey
->keyLength
, expectedKeyLength
);
1072 return fsBTInvalidNodeErr
;
1075 /* Point to record data (round up to even byte boundary) */
1076 srcPtr
= (int16_t *)((char *)srcKey
+ ((srcKey
->keyLength
+ 2) & ~1));
1079 * Make sure that we can safely dereference the record's type field or
1080 * and index node's child node number.
1082 if ((char *)srcPtr
+ sizeof(u_int32_t
) > nextRecord
) {
1083 if (direction
== kSwapBTNodeHostToBig
) {
1084 panic("hfs_swap_HFSBTInternalNode: catalog key #%d too big\n", srcDesc
->numRecords
-i
-1);
1086 printf("hfs_swap_HFSBTInternalNode: catalog key #%d too big\n", srcDesc
->numRecords
-i
-1);
1088 return fsBTInvalidNodeErr
;
1092 * For index nodes, the record data is just the child's node number.
1093 * Skip over swapping the various types of catalog record.
1095 if (srcDesc
->kind
== kBTIndexNode
) {
1096 *((u_int32_t
*)srcPtr
) = SWAP_BE32 (*((u_int32_t
*)srcPtr
));
1100 /* Make sure the recordType is in native order before using it. */
1101 if (direction
== kSwapBTNodeBigToHost
)
1102 srcPtr
[0] = SWAP_BE16 (srcPtr
[0]);
1104 if (srcPtr
[0] == kHFSFolderRecord
) {
1105 HFSCatalogFolder
*srcRec
= (HFSCatalogFolder
*)srcPtr
;
1106 if ((char *)srcRec
+ sizeof(*srcRec
) > nextRecord
) {
1107 if (direction
== kSwapBTNodeHostToBig
) {
1108 panic("hfs_swap_HFSBTInternalNode: catalog folder record #%d too big\n", srcDesc
->numRecords
-i
-1);
1110 printf("hfs_swap_HFSBTInternalNode: catalog folder record #%d too big\n", srcDesc
->numRecords
-i
-1);
1112 return fsBTInvalidNodeErr
;
1115 srcRec
->flags
= SWAP_BE16 (srcRec
->flags
);
1116 srcRec
->valence
= SWAP_BE16 (srcRec
->valence
);
1118 srcRec
->folderID
= SWAP_BE32 (srcRec
->folderID
);
1119 srcRec
->createDate
= SWAP_BE32 (srcRec
->createDate
);
1120 srcRec
->modifyDate
= SWAP_BE32 (srcRec
->modifyDate
);
1121 srcRec
->backupDate
= SWAP_BE32 (srcRec
->backupDate
);
1123 /* Don't swap srcRec->userInfo */
1124 /* Don't swap srcRec->finderInfo */
1125 /* Don't swap resserved array */
1127 } else if (srcPtr
[0] == kHFSFileRecord
) {
1128 HFSCatalogFile
*srcRec
= (HFSCatalogFile
*)srcPtr
;
1129 if ((char *)srcRec
+ sizeof(*srcRec
) > nextRecord
) {
1130 if (direction
== kSwapBTNodeHostToBig
) {
1131 panic("hfs_swap_HFSBTInternalNode: catalog file record #%d too big\n", srcDesc
->numRecords
-i
-1);
1133 printf("hfs_swap_HFSBTInternalNode: catalog file record #%d too big\n", srcDesc
->numRecords
-i
-1);
1135 return fsBTInvalidNodeErr
;
1138 srcRec
->flags
= srcRec
->flags
;
1139 srcRec
->fileType
= srcRec
->fileType
;
1141 /* Don't swap srcRec->userInfo */
1143 srcRec
->fileID
= SWAP_BE32 (srcRec
->fileID
);
1145 srcRec
->dataStartBlock
= SWAP_BE16 (srcRec
->dataStartBlock
);
1146 srcRec
->dataLogicalSize
= SWAP_BE32 (srcRec
->dataLogicalSize
);
1147 srcRec
->dataPhysicalSize
= SWAP_BE32 (srcRec
->dataPhysicalSize
);
1149 srcRec
->rsrcStartBlock
= SWAP_BE16 (srcRec
->rsrcStartBlock
);
1150 srcRec
->rsrcLogicalSize
= SWAP_BE32 (srcRec
->rsrcLogicalSize
);
1151 srcRec
->rsrcPhysicalSize
= SWAP_BE32 (srcRec
->rsrcPhysicalSize
);
1153 srcRec
->createDate
= SWAP_BE32 (srcRec
->createDate
);
1154 srcRec
->modifyDate
= SWAP_BE32 (srcRec
->modifyDate
);
1155 srcRec
->backupDate
= SWAP_BE32 (srcRec
->backupDate
);
1157 /* Don't swap srcRec->finderInfo */
1159 srcRec
->clumpSize
= SWAP_BE16 (srcRec
->clumpSize
);
1161 /* Swap the two sets of extents as an array of six (three each) u_int16_t */
1162 for (j
= 0; j
< kHFSExtentDensity
* 2; j
++) {
1163 srcRec
->dataExtents
[j
].startBlock
= SWAP_BE16 (srcRec
->dataExtents
[j
].startBlock
);
1164 srcRec
->dataExtents
[j
].blockCount
= SWAP_BE16 (srcRec
->dataExtents
[j
].blockCount
);
1167 /* Don't swap srcRec->reserved */
1169 } else if ((srcPtr
[0] == kHFSFolderThreadRecord
) ||
1170 (srcPtr
[0] == kHFSFileThreadRecord
)) {
1171 HFSCatalogThread
*srcRec
= (HFSCatalogThread
*)srcPtr
;
1173 /* Make sure there is room for parentID and name length */
1174 if ((char *) &srcRec
->nodeName
[1] > nextRecord
) {
1175 if (direction
== kSwapBTNodeHostToBig
) {
1176 panic("hfs_swap_HFSBTInternalNode: catalog thread record #%d too big\n", srcDesc
->numRecords
-i
-1);
1178 printf("hfs_swap_HFSBTInternalNode: catalog thread record #%d too big\n", srcDesc
->numRecords
-i
-1);
1180 return fsBTInvalidNodeErr
;
1183 /* Don't swap srcRec->reserved array */
1185 srcRec
->parentID
= SWAP_BE32 (srcRec
->parentID
);
1187 /* Don't swap srcRec->nodeName */
1189 /* Make sure there is room for the name in the buffer */
1190 if ((char *) &srcRec
->nodeName
[srcRec
->nodeName
[0]] > nextRecord
) {
1191 if (direction
== kSwapBTNodeHostToBig
) {
1192 panic("hfs_swap_HFSBTInternalNode: catalog thread record #%d name too big\n", srcDesc
->numRecords
-i
-1);
1194 printf("hfs_swap_HFSBTInternalNode: catalog thread record #%d name too big\n", srcDesc
->numRecords
-i
-1);
1196 return fsBTInvalidNodeErr
;
1199 if (direction
== kSwapBTNodeHostToBig
) {
1200 panic("hfs_swap_HFSBTInternalNode: unrecognized catalog record type (0x%04X; record #%d)\n", srcPtr
[0], srcDesc
->numRecords
-i
-1);
1202 printf("hfs_swap_HFSBTInternalNode: unrecognized catalog record type (0x%04X; record #%d)\n", srcPtr
[0], srcDesc
->numRecords
-i
-1);
1204 return fsBTInvalidNodeErr
;
1207 /* We can swap the record type now that we're done using it */
1208 if (direction
== kSwapBTNodeHostToBig
)
1209 srcPtr
[0] = SWAP_BE16 (srcPtr
[0]);
1213 panic ("hfs_swap_HFSBTInternalNode: fileID %u is not a system B-tree\n", fileID
);