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