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