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