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