]> git.saurik.com Git - apple/hfs.git/blob - fsck_hfs/dfalib/hfs_endian.c
hfs-226.1.1.tar.gz
[apple/hfs.git] / fsck_hfs / dfalib / hfs_endian.c
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 */
55 static int hfs_swap_HFSPlusBTInternalNode (BlockDescriptor *src, SFCB *fcb, enum HFSBTSwapDirection direction);
56 static int hfs_swap_HFSBTInternalNode (BlockDescriptor *src, SFCB *fcb, enum HFSBTSwapDirection direction);
57
58 /*
59 * hfs_swap_HFSPlusForkData
60 */
61 static void
62 hfs_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 */
84 void
85 hfs_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 */
143 void
144 hfs_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 */
188 int
189 hfs_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 plog ("BE -> Native Swap\n");
206 } else if (direction == kSwapBTNodeHostToBig) {
207 plog ("Native -> BE Swap\n");
208 } else if (direction == kSwapBTNodeHeaderRecordOnly) {
209 plog ("Not swapping descriptors\n");
210 } else {
211 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: record #%d invalid offset (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
276 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
277 error = E_BadNode;
278 goto fail;
279 }
280
281 /*
282 * Make sure the offsets are strictly increasing. Note that we're looping over
283 * them backwards, hence the order in the comparison.
284 */
285 if ((i != 0) && (srcOffs[i] >= srcOffs[i-1])) {
286 if (debug) plog("hfs_swap_BTNode: offsets %d and %d out of order (0x%04X, 0x%04X)\n",
287 srcDesc->numRecords-i-1, srcDesc->numRecords-i, srcOffs[i], srcOffs[i-1]);
288 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
289 error = E_BadNode;
290 goto fail;
291 }
292 }
293 }
294
295 /*
296 * Swap the records (ordered by frequency of access)
297 */
298 if ((srcDesc->kind == kBTIndexNode) ||
299 (srcDesc-> kind == kBTLeafNode)) {
300
301 if (fcb->fcbVolume->vcbSignature == kHFSPlusSigWord) {
302 error = hfs_swap_HFSPlusBTInternalNode (src, fcb, direction);
303 } else {
304 error = hfs_swap_HFSBTInternalNode (src, fcb, direction);
305 }
306
307 if (error) goto fail;
308
309 } else if (srcDesc-> kind == kBTMapNode) {
310 /* Don't swap the bitmaps, they'll be done in the bitmap routines */
311
312 } else if (srcDesc-> kind == kBTHeaderNode) {
313 /* The header's offset is hard-wired because we cannot trust the offset pointers. */
314 BTHeaderRec *srcHead = (BTHeaderRec *)((char *)src->buffer + sizeof(BTNodeDescriptor));
315
316 srcHead->treeDepth = SWAP_BE16 (srcHead->treeDepth);
317
318 srcHead->rootNode = SWAP_BE32 (srcHead->rootNode);
319 srcHead->leafRecords = SWAP_BE32 (srcHead->leafRecords);
320 srcHead->firstLeafNode = SWAP_BE32 (srcHead->firstLeafNode);
321 srcHead->lastLeafNode = SWAP_BE32 (srcHead->lastLeafNode);
322
323 srcHead->nodeSize = SWAP_BE16 (srcHead->nodeSize);
324 srcHead->maxKeyLength = SWAP_BE16 (srcHead->maxKeyLength);
325
326 srcHead->totalNodes = SWAP_BE32 (srcHead->totalNodes);
327 srcHead->freeNodes = SWAP_BE32 (srcHead->freeNodes);
328
329 srcHead->clumpSize = SWAP_BE32 (srcHead->clumpSize);
330 srcHead->attributes = SWAP_BE32 (srcHead->attributes);
331
332 /* Don't swap srcHead->reserved1 */
333 /* Don't swap srcHead->btreeType; it's only one byte */
334 /* Don't swap srcHead->reserved2 */
335 /* Don't swap srcHead->reserved3 */
336 /* Don't swap bitmap */
337 }
338 /* Else: other node kinds will be caught by upper layers */
339
340 /*
341 * If we are doing a swap from in-memory to on-disk, then swap the node
342 * descriptor and record offsets after we're done using them.
343 */
344 if (direction == kSwapBTNodeHostToBig) {
345 /*
346 * Swap the forward and backward links.
347 */
348 if (srcDesc->fLink >= btcb->totalNodes) {
349 if (debug) plog("hfs_UNswap_BTNode: invalid forward link (0x%08X)\n", srcDesc->fLink);
350 }
351 if (srcDesc->bLink >= btcb->totalNodes) {
352 if (debug) plog("hfs_UNswap_BTNode: invalid backward link (0x%08X)\n", srcDesc->bLink);
353 }
354 srcDesc->fLink = SWAP_BE32 (srcDesc->fLink);
355 srcDesc->bLink = SWAP_BE32 (srcDesc->bLink);
356
357 /*
358 * Don't swap srcDesc->kind or srcDesc->height because they are only one byte.
359 * We don't check them here because the upper layers will check (and possibly
360 * repair) them more effectively.
361 */
362 if (srcDesc->kind < kBTLeafNode || srcDesc->kind > kBTMapNode) {
363 if (debug) plog("hfs_UNswap_BTNode: invalid node kind (%d)\n", srcDesc->kind);
364 }
365 if (srcDesc->height > btcb->treeDepth) {
366 if (debug) plog("hfs_UNswap_BTNode: invalid node height (%d)\n", srcDesc->height);
367 }
368
369 /* Don't swap srcDesc->reserved */
370
371 /*
372 * Swap the node offsets (including the free space one!).
373 */
374 srcOffs = (UInt16 *)((char *)src->buffer + (src->blockSize - ((srcDesc->numRecords + 1) * sizeof (UInt16))));
375
376 /*
377 * Sanity check that the record offsets are within the node itself.
378 */
379 if ((char *)srcOffs > ((char *)src->buffer + src->blockSize) ||
380 (char *)srcOffs < ((char *)src->buffer + sizeof(BTNodeDescriptor))) {
381 if (debug) plog("hfs_UNswap_BTNode: invalid record count (0x%04X)\n", srcDesc->numRecords);
382 WriteError(fcb->fcbVolume->vcbGPtr, E_NRecs, fcb->fcbFileID, src->blockNum);
383 error = E_NRecs;
384 goto fail;
385 }
386
387 /*
388 * Swap and sanity check each of the record offsets.
389 */
390 for (i = 0; i <= srcDesc->numRecords; i++) {
391 /*
392 * Sanity check: must be even, and within the node itself.
393 *
394 * We may be called to swap an unused node, which contains all zeroes.
395 * This is why we allow the record offset to be zero.
396 */
397 if ((srcOffs[i] & 1) || (srcOffs[i] < sizeof(BTNodeDescriptor) && srcOffs[i] != 0) || (srcOffs[i] >= src->blockSize)) {
398 if (debug) plog("hfs_UNswap_BTNode: record #%d invalid offset (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
399 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
400 error = E_BadNode;
401 goto fail;
402 }
403
404 /*
405 * Make sure the offsets are strictly increasing. Note that we're looping over
406 * them backwards, hence the order in the comparison.
407 */
408 if ((i < srcDesc->numRecords) && (srcOffs[i+1] >= srcOffs[i])) {
409 if (debug) plog("hfs_UNswap_BTNode: offsets %d and %d out of order (0x%04X, 0x%04X)\n",
410 srcDesc->numRecords-i-2, srcDesc->numRecords-i-1, srcOffs[i+1], srcOffs[i]);
411 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
412 error = E_BadNode;
413 goto fail;
414 }
415
416 srcOffs[i] = SWAP_BE16 (srcOffs[i]);
417 }
418
419 srcDesc->numRecords = SWAP_BE16 (srcDesc->numRecords);
420 }
421
422 fail:
423 if (error && (cur_debug_level & d_dump_node))
424 {
425 plog("Node %u:\n", src->blockNum);
426 HexDump(src->buffer, src->blockSize, TRUE);
427 }
428 return (error);
429 }
430
431 static int
432 hfs_swap_HFSPlusBTInternalNode (
433 BlockDescriptor *src,
434 SFCB *fcb,
435 enum HFSBTSwapDirection direction
436 )
437 {
438 HFSCatalogNodeID fileID =fcb->fcbFileID;
439 BTNodeDescriptor *srcDesc = src->buffer;
440 UInt16 *srcOffs = (UInt16 *)((char *)src->buffer + (src->blockSize - (srcDesc->numRecords * sizeof (UInt16))));
441 char *nextRecord; /* Points to start of record following current one */
442 int32_t i;
443 UInt32 j;
444
445 if (fileID == kHFSExtentsFileID) {
446 HFSPlusExtentKey *srcKey;
447 HFSPlusExtentDescriptor *srcRec;
448 size_t recordSize; /* Size of the data part of the record, or node number for index nodes */
449
450 if (srcDesc->kind == kBTIndexNode)
451 recordSize = sizeof(UInt32);
452 else
453 recordSize = sizeof(HFSPlusExtentDescriptor);
454
455 for (i = 0; i < srcDesc->numRecords; i++) {
456 /* Point to the start of the record we're currently checking. */
457 srcKey = (HFSPlusExtentKey *)((char *)src->buffer + srcOffs[i]);
458
459 /*
460 * Point to start of next (larger offset) record. We'll use this
461 * to be sure the current record doesn't overflow into the next
462 * record.
463 */
464 nextRecord = (char *)src->buffer + srcOffs[i-1];
465
466 /*
467 * Make sure the key and data are within the buffer. Since both key
468 * and data are fixed size, this is relatively easy. Note that this
469 * relies on the keyLength being a constant; we verify the keyLength
470 * below.
471 */
472 if ((char *)srcKey + sizeof(HFSPlusExtentKey) + recordSize > nextRecord) {
473 if (debug) plog("hfs_swap_HFSPlusBTInternalNode: extents key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
474 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
475 return E_BadNode;
476 }
477
478 if (direction == kSwapBTNodeBigToHost)
479 srcKey->keyLength = SWAP_BE16 (srcKey->keyLength);
480 if (srcKey->keyLength != sizeof(*srcKey) - sizeof(srcKey->keyLength)) {
481 if (debug) plog("hfs_swap_HFSPlusBTInternalNode: extents key #%d invalid length (%d)\n", srcDesc->numRecords-i-1, srcKey->keyLength);
482 WriteError(fcb->fcbVolume->vcbGPtr, E_KeyLen, fcb->fcbFileID, src->blockNum);
483 return E_KeyLen;
484 }
485 srcRec = (HFSPlusExtentDescriptor *)((char *)srcKey + srcKey->keyLength + sizeof(srcKey->keyLength));
486 if (direction == kSwapBTNodeHostToBig)
487 srcKey->keyLength = SWAP_BE16 (srcKey->keyLength);
488
489 /* Don't swap srcKey->forkType; it's only one byte */
490 /* Don't swap srcKey->pad */
491
492 srcKey->fileID = SWAP_BE32 (srcKey->fileID);
493 srcKey->startBlock = SWAP_BE32 (srcKey->startBlock);
494
495 if (srcDesc->kind == kBTIndexNode) {
496 /* For index nodes, the record data is just a child node number. */
497 *((UInt32 *)srcRec) = SWAP_BE32 (*((UInt32 *)srcRec));
498 } else {
499 /* Swap the extent data */
500 for (j = 0; j < kHFSPlusExtentDensity; j++) {
501 srcRec[j].startBlock = SWAP_BE32 (srcRec[j].startBlock);
502 srcRec[j].blockCount = SWAP_BE32 (srcRec[j].blockCount);
503 }
504 }
505 }
506
507 } else if (fileID == kHFSCatalogFileID || fileID == kHFSRepairCatalogFileID) {
508 HFSPlusCatalogKey *srcKey;
509 SInt16 *srcPtr;
510 u_int16_t keyLength;
511
512 for (i = 0; i < srcDesc->numRecords; i++) {
513 /* Point to the start of the record we're currently checking. */
514 srcKey = (HFSPlusCatalogKey *)((char *)src->buffer + srcOffs[i]);
515
516 /*
517 * Point to start of next (larger offset) record. We'll use this
518 * to be sure the current record doesn't overflow into the next
519 * record.
520 */
521 nextRecord = (char *)src->buffer + srcOffs[i-1];
522
523 /*
524 * Make sure we can safely dereference the keyLength and parentID fields. */
525 if ((char *)srcKey + offsetof(HFSPlusCatalogKey, nodeName.unicode[0]) > nextRecord) {
526 if (debug) plog("hfs_swap_HFSPlusBTInternalNode: catalog key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
527 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
528 return E_BadNode;
529 }
530
531 /*
532 * Swap and sanity check the key length
533 */
534 if (direction == kSwapBTNodeBigToHost)
535 srcKey->keyLength = SWAP_BE16 (srcKey->keyLength);
536 keyLength = srcKey->keyLength; /* Put it in a local (native order) because we use it several times */
537 if (direction == kSwapBTNodeHostToBig)
538 srcKey->keyLength = SWAP_BE16 (keyLength);
539
540 /* Sanity check the key length */
541 if (keyLength < kHFSPlusCatalogKeyMinimumLength || keyLength > kHFSPlusCatalogKeyMaximumLength) {
542 if (debug) plog("hfs_swap_HFSPlusBTInternalNode: catalog key #%d invalid length (%d)\n", srcDesc->numRecords-i-1, keyLength);
543 WriteError(fcb->fcbVolume->vcbGPtr, E_KeyLen, fcb->fcbFileID, src->blockNum);
544 return E_KeyLen;
545 }
546
547 /*
548 * Make sure that we can safely dereference the record's type field or
549 * an index node's child node number.
550 */
551 srcPtr = (SInt16 *)((char *)srcKey + keyLength + sizeof(srcKey->keyLength));
552 if ((char *)srcPtr + sizeof(UInt32) > nextRecord) {
553 if (debug) plog("hfs_swap_HFSPlusBTInternalNode: catalog key #%d too big\n", srcDesc->numRecords-i-1);
554 WriteError(fcb->fcbVolume->vcbGPtr, E_KeyLen, fcb->fcbFileID, src->blockNum);
555 return E_KeyLen;
556 }
557
558 srcKey->parentID = SWAP_BE32 (srcKey->parentID);
559
560 /*
561 * Swap and sanity check the key's node name
562 */
563 if (direction == kSwapBTNodeBigToHost)
564 srcKey->nodeName.length = SWAP_BE16 (srcKey->nodeName.length);
565 /* Make sure name length is consistent with key length */
566 if (keyLength < sizeof(srcKey->parentID) + sizeof(srcKey->nodeName.length) +
567 srcKey->nodeName.length*sizeof(srcKey->nodeName.unicode[0])) {
568 if (debug){
569 uintptr_t keyOffset = (uintptr_t)srcKey - (uintptr_t)src->buffer;
570 uintptr_t recordSize = (uintptr_t)nextRecord - (uintptr_t)srcKey;
571 unsigned recordIndex = srcDesc->numRecords - i;
572
573 plog("hfs_swap_HFSPlusBTInternalNode: catalog record #%d (0-based, offset 0x%lX) keyLength=%d expected=%lu\n",
574 recordIndex, keyOffset, keyLength, sizeof(srcKey->parentID) + sizeof(srcKey->nodeName.length) +
575 srcKey->nodeName.length*sizeof(srcKey->nodeName.unicode[0]));
576 if (cur_debug_level & d_dump_record) {
577 plog("Record %u (offset 0x%04X):\n", recordIndex, keyOffset);
578 HexDump(srcKey, recordSize, FALSE);
579 }
580 }
581 WriteError(fcb->fcbVolume->vcbGPtr, E_KeyLen, fcb->fcbFileID, src->blockNum);
582 return E_KeyLen;
583 }
584 for (j = 0; j < srcKey->nodeName.length; j++) {
585 srcKey->nodeName.unicode[j] = SWAP_BE16 (srcKey->nodeName.unicode[j]);
586 }
587 if (direction == kSwapBTNodeHostToBig)
588 srcKey->nodeName.length = SWAP_BE16 (srcKey->nodeName.length);
589
590 /*
591 * For index nodes, the record data is just the child's node number.
592 * Skip over swapping the various types of catalog record.
593 */
594 if (srcDesc->kind == kBTIndexNode) {
595 *((UInt32 *)srcPtr) = SWAP_BE32 (*((UInt32 *)srcPtr));
596 continue;
597 }
598
599 /* Make sure the recordType is in native order before using it. */
600 if (direction == kSwapBTNodeBigToHost)
601 srcPtr[0] = SWAP_BE16 (srcPtr[0]);
602
603 if (srcPtr[0] == kHFSPlusFolderRecord) {
604 HFSPlusCatalogFolder *srcRec = (HFSPlusCatalogFolder *)srcPtr;
605 if ((char *)srcRec + sizeof(*srcRec) > nextRecord) {
606 if (debug) plog("hfs_swap_HFSPlusBTInternalNode: catalog folder record #%d too big\n", srcDesc->numRecords-i-1);
607 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
608 return E_BadNode;
609 }
610
611 srcRec->flags = SWAP_BE16 (srcRec->flags);
612 srcRec->valence = SWAP_BE32 (srcRec->valence);
613 srcRec->folderID = SWAP_BE32 (srcRec->folderID);
614 srcRec->createDate = SWAP_BE32 (srcRec->createDate);
615 srcRec->contentModDate = SWAP_BE32 (srcRec->contentModDate);
616 srcRec->attributeModDate = SWAP_BE32 (srcRec->attributeModDate);
617 srcRec->accessDate = SWAP_BE32 (srcRec->accessDate);
618 srcRec->backupDate = SWAP_BE32 (srcRec->backupDate);
619
620 srcRec->bsdInfo.ownerID = SWAP_BE32 (srcRec->bsdInfo.ownerID);
621 srcRec->bsdInfo.groupID = SWAP_BE32 (srcRec->bsdInfo.groupID);
622
623 /* Don't swap srcRec->bsdInfo.adminFlags; it's only one byte */
624 /* Don't swap srcRec->bsdInfo.ownerFlags; it's only one byte */
625
626 srcRec->bsdInfo.fileMode = SWAP_BE16 (srcRec->bsdInfo.fileMode);
627 srcRec->bsdInfo.special.iNodeNum = SWAP_BE32 (srcRec->bsdInfo.special.iNodeNum);
628
629 srcRec->textEncoding = SWAP_BE32 (srcRec->textEncoding);
630
631 /* The only field we use in srcRec->userInfo is frFlags (used in VLockedChk). */
632 srcRec->userInfo.frFlags = SWAP_BE16 (srcRec->userInfo.frFlags);
633
634 /* Don't swap srcRec->finderInfo */
635 srcRec->folderCount = SWAP_BE32 (srcRec->folderCount);
636
637 } else if (srcPtr[0] == kHFSPlusFileRecord) {
638 HFSPlusCatalogFile *srcRec = (HFSPlusCatalogFile *)srcPtr;
639 if ((char *)srcRec + sizeof(*srcRec) > nextRecord) {
640 if (debug) plog("hfs_swap_HFSPlusBTInternalNode: catalog file record #%d too big\n", srcDesc->numRecords-i-1);
641 return fsBTInvalidNodeErr;
642 }
643
644 srcRec->flags = SWAP_BE16 (srcRec->flags);
645
646 srcRec->fileID = SWAP_BE32 (srcRec->fileID);
647
648 srcRec->createDate = SWAP_BE32 (srcRec->createDate);
649 srcRec->contentModDate = SWAP_BE32 (srcRec->contentModDate);
650 srcRec->attributeModDate = SWAP_BE32 (srcRec->attributeModDate);
651 srcRec->accessDate = SWAP_BE32 (srcRec->accessDate);
652 srcRec->backupDate = SWAP_BE32 (srcRec->backupDate);
653
654 srcRec->bsdInfo.ownerID = SWAP_BE32 (srcRec->bsdInfo.ownerID);
655 srcRec->bsdInfo.groupID = SWAP_BE32 (srcRec->bsdInfo.groupID);
656
657 /* Don't swap srcRec->bsdInfo.adminFlags; it's only one byte */
658 /* Don't swap srcRec->bsdInfo.ownerFlags; it's only one byte */
659
660 srcRec->bsdInfo.fileMode = SWAP_BE16 (srcRec->bsdInfo.fileMode);
661 srcRec->bsdInfo.special.iNodeNum = SWAP_BE32 (srcRec->bsdInfo.special.iNodeNum);
662
663 srcRec->textEncoding = SWAP_BE32 (srcRec->textEncoding);
664
665 srcRec->hl_firstLinkID = SWAP_BE32 (srcRec->hl_firstLinkID);
666
667 srcRec->userInfo.fdType = SWAP_BE32 (srcRec->userInfo.fdType);
668 srcRec->userInfo.fdCreator = SWAP_BE32 (srcRec->userInfo.fdCreator);
669 srcRec->userInfo.fdFlags = SWAP_BE16 (srcRec->userInfo.fdFlags);
670 srcRec->userInfo.fdLocation.v = SWAP_BE16 (srcRec->userInfo.fdLocation.v);
671 srcRec->userInfo.fdLocation.h = SWAP_BE16 (srcRec->userInfo.fdLocation.h);
672 srcRec->userInfo.opaque = SWAP_BE16 (srcRec->userInfo.opaque);
673
674 /* Don't swap srcRec->finderInfo */
675 /* Don't swap srcRec->reserved2 */
676
677 hfs_swap_HFSPlusForkData (&srcRec->dataFork);
678 hfs_swap_HFSPlusForkData (&srcRec->resourceFork);
679
680 } else if ((srcPtr[0] == kHFSPlusFolderThreadRecord) ||
681 (srcPtr[0] == kHFSPlusFileThreadRecord)) {
682
683 /*
684 * Make sure there is room for parentID and name length.
685 */
686 HFSPlusCatalogThread *srcRec = (HFSPlusCatalogThread *)srcPtr;
687 if ((char *) &srcRec->nodeName.unicode[0] > nextRecord) {
688 if (debug) plog("hfs_swap_HFSPlusBTInternalNode: catalog thread record #%d too big\n", srcDesc->numRecords-i-1);
689 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
690 return E_BadNode;
691 }
692
693 /* Don't swap srcRec->reserved */
694
695 srcRec->parentID = SWAP_BE32 (srcRec->parentID);
696
697 if (direction == kSwapBTNodeBigToHost)
698 srcRec->nodeName.length = SWAP_BE16 (srcRec->nodeName.length);
699
700 /*
701 * Make sure there is room for the name in the buffer.
702 * Then swap the characters of the name itself.
703 */
704 if ((char *) &srcRec->nodeName.unicode[srcRec->nodeName.length] > nextRecord) {
705 if (debug) plog("hfs_swap_HFSPlusBTInternalNode: catalog thread record #%d name too big\n", srcDesc->numRecords-i-1);
706 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
707 return E_BadNode;
708 }
709 for (j = 0; j < srcRec->nodeName.length; j++) {
710 srcRec->nodeName.unicode[j] = SWAP_BE16 (srcRec->nodeName.unicode[j]);
711 }
712
713 if (direction == kSwapBTNodeHostToBig)
714 srcRec->nodeName.length = SWAP_BE16 (srcRec->nodeName.length);
715
716 } else {
717 if (debug) plog("hfs_swap_HFSPlusBTInternalNode: unrecognized catalog record type (0x%04X; record #%d)\n", srcPtr[0], srcDesc->numRecords-i-1);
718 }
719
720 /* We can swap the record type now that we're done using it. */
721 if (direction == kSwapBTNodeHostToBig)
722 srcPtr[0] = SWAP_BE16 (srcPtr[0]);
723 }
724
725 } else if (fileID == kHFSAttributesFileID) {
726 HFSPlusAttrKey *srcKey;
727 HFSPlusAttrRecord *srcRec;
728 u_int16_t keyLength;
729 u_int32_t attrSize = 0;
730
731 for (i = 0; i < srcDesc->numRecords; i++) {
732 /* Point to the start of the record we're currently checking. */
733 srcKey = (HFSPlusAttrKey *)((char *)src->buffer + srcOffs[i]);
734
735 /*
736 * Point to start of next (larger offset) record. We'll use this
737 * to be sure the current record doesn't overflow into the next
738 * record.
739 */
740 nextRecord = (char *)src->buffer + srcOffs[i-1];
741
742 /* Make sure there is room in the buffer for a minimal key */
743 if ((char *) &srcKey->attrName[1] > nextRecord) {
744 if (debug) plog("hfs_swap_HFSPlusBTInternalNode: attr key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
745 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
746 return E_BadNode;
747 }
748
749 /* Swap the key length field */
750 if (direction == kSwapBTNodeBigToHost)
751 srcKey->keyLength = SWAP_BE16(srcKey->keyLength);
752 keyLength = srcKey->keyLength; /* Keep a copy in native order */
753 if (direction == kSwapBTNodeHostToBig)
754 srcKey->keyLength = SWAP_BE16(srcKey->keyLength);
755
756 /*
757 * Make sure that we can safely dereference the record's type field or
758 * an index node's child node number.
759 */
760 srcRec = (HFSPlusAttrRecord *)((char *)srcKey + keyLength + sizeof(srcKey->keyLength));
761 if ((char *)srcRec + sizeof(u_int32_t) > nextRecord) {
762 if (debug) plog("hfs_swap_HFSPlusBTInternalNode: attr key #%d too big (%d)\n", srcDesc->numRecords-i-1, keyLength);
763 WriteError(fcb->fcbVolume->vcbGPtr, E_KeyLen, fcb->fcbFileID, src->blockNum);
764 return E_KeyLen;
765 }
766
767 srcKey->fileID = SWAP_BE32(srcKey->fileID);
768 srcKey->startBlock = SWAP_BE32(srcKey->startBlock);
769
770 /*
771 * Swap and check the attribute name
772 */
773 if (direction == kSwapBTNodeBigToHost)
774 srcKey->attrNameLen = SWAP_BE16(srcKey->attrNameLen);
775 /* Sanity check the attribute name length */
776 if (srcKey->attrNameLen > kHFSMaxAttrNameLen || keyLength < (kHFSPlusAttrKeyMinimumLength + sizeof(u_int16_t)*srcKey->attrNameLen)) {
777 if (debug) plog("hfs_swap_HFSPlusBTInternalNode: attr key #%d keyLength=%d attrNameLen=%d\n", srcDesc->numRecords-i-1, keyLength, srcKey->attrNameLen);
778 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
779 return E_BadNode;
780 }
781 for (j = 0; j < srcKey->attrNameLen; j++)
782 srcKey->attrName[j] = SWAP_BE16(srcKey->attrName[j]);
783 if (direction == kSwapBTNodeHostToBig)
784 srcKey->attrNameLen = SWAP_BE16(srcKey->attrNameLen);
785
786 /*
787 * For index nodes, the record data is just the child's node number.
788 * Skip over swapping the various types of attribute record.
789 */
790 if (srcDesc->kind == kBTIndexNode) {
791 *((UInt32 *)srcRec) = SWAP_BE32 (*((UInt32 *)srcRec));
792 continue;
793 }
794
795 /* Swap the record data */
796 if (direction == kSwapBTNodeBigToHost)
797 srcRec->recordType = SWAP_BE32(srcRec->recordType);
798 switch (srcRec->recordType) {
799 case kHFSPlusAttrInlineData:
800 /* Is there room for the inline data header? */
801 if ((char *) &srcRec->attrData.attrData[0] > nextRecord) {
802 if (debug) plog("hfs_swap_HFSPlusBTInternalNode: attr inline #%d too big\n", srcDesc->numRecords-i-1);
803 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
804 return E_BadNode;
805 }
806
807 /* We're not swapping the reserved fields */
808
809 /* Swap the attribute size */
810 if (direction == kSwapBTNodeHostToBig)
811 attrSize = srcRec->attrData.attrSize;
812 srcRec->attrData.attrSize = SWAP_BE32(srcRec->attrData.attrSize);
813 if (direction == kSwapBTNodeBigToHost)
814 attrSize = srcRec->attrData.attrSize;
815
816 /* Is there room for the inline attribute data? */
817 if ((char *) &srcRec->attrData.attrData[attrSize] > nextRecord) {
818 if (debug) plog("hfs_swap_HFSPlusBTInternalNode: attr inline #%d too big (attrSize=%u)\n", srcDesc->numRecords-i-1, attrSize);
819 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
820 return E_BadNode;
821 }
822
823 /* Not swapping the attribute data itself */
824 break;
825
826 case kHFSPlusAttrForkData:
827 /* Is there room for the fork data record? */
828 if ((char *)srcRec + sizeof(HFSPlusAttrForkData) > nextRecord) {
829 if (debug) plog("hfs_swap_HFSPlusBTInternalNode: attr fork data #%d too big\n", srcDesc->numRecords-i-1);
830 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
831 return E_BadNode;
832 }
833
834 /* We're not swapping the reserved field */
835
836 hfs_swap_HFSPlusForkData(&srcRec->forkData.theFork);
837 break;
838
839 case kHFSPlusAttrExtents:
840 /* Is there room for an extent record? */
841 if ((char *)srcRec + sizeof(HFSPlusAttrExtents) > nextRecord) {
842 if (debug) plog("hfs_swap_HFSPlusBTInternalNode: attr extents #%d too big\n", srcDesc->numRecords-i-1);
843 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
844 return E_BadNode;
845 }
846
847 /* We're not swapping the reserved field */
848
849 for (j = 0; j < kHFSPlusExtentDensity; j++) {
850 srcRec->overflowExtents.extents[j].startBlock =
851 SWAP_BE32(srcRec->overflowExtents.extents[j].startBlock);
852 srcRec->overflowExtents.extents[j].blockCount =
853 SWAP_BE32(srcRec->overflowExtents.extents[j].blockCount);
854 }
855 break;
856 default:
857 if (debug) plog ("hfs_swap_BTNode: unrecognized attribute record type (%d)\n", srcRec->recordType);
858 }
859 if (direction == kSwapBTNodeHostToBig)
860 srcRec->recordType = SWAP_BE32(srcRec->recordType);
861 }
862 } else {
863 plog("hfs_swap_HFSPlusBTInternalNode: fileID %u is not a system B-tree\n", fileID);
864 exit(99);
865 }
866
867 return (0);
868 }
869
870 static int
871 hfs_swap_HFSBTInternalNode (
872 BlockDescriptor *src,
873 SFCB *fcb,
874 enum HFSBTSwapDirection direction
875 )
876 {
877 HFSCatalogNodeID fileID =fcb->fcbFileID;
878 BTNodeDescriptor *srcDesc = src->buffer;
879 UInt16 *srcOffs = (UInt16 *)((char *)src->buffer + (src->blockSize - (srcDesc->numRecords * sizeof (UInt16))));
880 char *nextRecord; /* Points to start of record following current one */
881
882 int32_t i;
883 UInt32 j;
884
885 if (fileID == kHFSExtentsFileID) {
886 HFSExtentKey *srcKey;
887 HFSExtentDescriptor *srcRec;
888 size_t recordSize; /* Size of the data part of the record, or node number for index nodes */
889
890 if (srcDesc->kind == kBTIndexNode)
891 recordSize = sizeof(UInt32);
892 else
893 recordSize = sizeof(HFSExtentDescriptor);
894
895 for (i = 0; i < srcDesc->numRecords; i++) {
896 /* Point to the start of the record we're currently checking. */
897 srcKey = (HFSExtentKey *)((char *)src->buffer + srcOffs[i]);
898
899 /*
900 * Point to start of next (larger offset) record. We'll use this
901 * to be sure the current record doesn't overflow into the next
902 * record.
903 */
904 nextRecord = (char *)src->buffer + srcOffs[i-1];
905
906 /*
907 * Make sure the key and data are within the buffer. Since both key
908 * and data are fixed size, this is relatively easy. Note that this
909 * relies on the keyLength being a constant; we verify the keyLength
910 * below.
911 */
912 if ((char *)srcKey + sizeof(HFSExtentKey) + recordSize > nextRecord) {
913 if (debug) plog("hfs_swap_HFSBTInternalNode: extents key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
914 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
915 return E_BadNode;
916 }
917
918 /* Don't swap srcKey->keyLength (it's only one byte), but do sanity check it */
919 if (srcKey->keyLength != sizeof(*srcKey) - sizeof(srcKey->keyLength)) {
920 if (debug) plog("hfs_swap_HFSBTInternalNode: extents key #%d invalid length (%d)\n", srcDesc->numRecords-i-1, srcKey->keyLength);
921 }
922
923 /* Don't swap srcKey->forkType; it's only one byte */
924
925 srcKey->fileID = SWAP_BE32 (srcKey->fileID);
926 srcKey->startBlock = SWAP_BE16 (srcKey->startBlock);
927
928 /* Point to record data (round up to even byte boundary) */
929 srcRec = (HFSExtentDescriptor *)((char *)srcKey + ((srcKey->keyLength + 2) & ~1));
930
931 if (srcDesc->kind == kBTIndexNode) {
932 /* For index nodes, the record data is just a child node number. */
933 *((UInt32 *)srcRec) = SWAP_BE32 (*((UInt32 *)srcRec));
934 } else {
935 /* Swap the extent data */
936 for (j = 0; j < kHFSExtentDensity; j++) {
937 srcRec[j].startBlock = SWAP_BE16 (srcRec[j].startBlock);
938 srcRec[j].blockCount = SWAP_BE16 (srcRec[j].blockCount);
939 }
940 }
941 }
942
943 } else if (fileID == kHFSCatalogFileID || fileID == kHFSRepairCatalogFileID) {
944 HFSCatalogKey *srcKey;
945 SInt16 *srcPtr;
946 size_t expectedKeyLength;
947
948 for (i = 0; i < srcDesc->numRecords; i++) {
949 /* Point to the start of the record we're currently checking. */
950 srcKey = (HFSCatalogKey *)((char *)src->buffer + srcOffs[i]);
951
952 /*
953 * Point to start of next (larger offset) record. We'll use this
954 * to be sure the current record doesn't overflow into the next
955 * record.
956 */
957 nextRecord = (char *)src->buffer + srcOffs[i-1];
958
959 /*
960 * Make sure we can safely dereference the keyLength and parentID fields.
961 * The value 8 below is 1 bytes for keyLength + 1 byte reserved + 4 bytes
962 * for parentID + 1 byte for nodeName's length + 1 byte to round up the
963 * record start to an even offset, which forms a minimal key.
964 */
965 if ((char *)srcKey + 8 > nextRecord) {
966 if (debug) plog("hfs_swap_HFSBTInternalNode: catalog key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
967 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
968 return E_BadNode;
969 }
970
971 /* Don't swap srcKey->keyLength (it's only one byte), but do sanity check it */
972 if (srcKey->keyLength < kHFSCatalogKeyMinimumLength || srcKey->keyLength > kHFSCatalogKeyMaximumLength) {
973 if (debug) plog("hfs_swap_HFSBTInternalNode: catalog key #%d invalid length (%d)\n", srcDesc->numRecords-i-1, srcKey->keyLength);
974 }
975
976 /* Don't swap srcKey->reserved */
977
978 srcKey->parentID = SWAP_BE32 (srcKey->parentID);
979
980 /* Don't swap srcKey->nodeName */
981
982 /* Make sure the keyLength is big enough for the key's content */
983 if (srcDesc->kind == kBTIndexNode)
984 expectedKeyLength = sizeof(*srcKey) - sizeof(srcKey->keyLength);
985 else
986 expectedKeyLength = srcKey->nodeName[0] + kHFSCatalogKeyMinimumLength;
987 if (srcKey->keyLength < expectedKeyLength) {
988 if (debug) plog("hfs_swap_HFSBTInternalNode: catalog record #%d keyLength=%u expected=%u\n",
989 srcDesc->numRecords-i, srcKey->keyLength, expectedKeyLength);
990 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
991 return E_BadNode;
992 }
993
994 /* Point to record data (round up to even byte boundary) */
995 srcPtr = (SInt16 *)((char *)srcKey + ((srcKey->keyLength + 2) & ~1));
996
997 /*
998 * Make sure that we can safely dereference the record's type field or
999 * and index node's child node number.
1000 */
1001 if ((char *)srcPtr + sizeof(UInt32) > nextRecord) {
1002 if (debug) plog("hfs_swap_HFSBTInternalNode: catalog key #%d too big\n", srcDesc->numRecords-i-1);
1003 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
1004 return E_BadNode;
1005 }
1006
1007 /*
1008 * For index nodes, the record data is just the child's node number.
1009 * Skip over swapping the various types of catalog record.
1010 */
1011 if (srcDesc->kind == kBTIndexNode) {
1012 *((UInt32 *)srcPtr) = SWAP_BE32 (*((UInt32 *)srcPtr));
1013 continue;
1014 }
1015
1016 /* Make sure the recordType is in native order before using it. */
1017 if (direction == kSwapBTNodeBigToHost)
1018 srcPtr[0] = SWAP_BE16 (srcPtr[0]);
1019
1020 if (srcPtr[0] == kHFSFolderRecord) {
1021 HFSCatalogFolder *srcRec = (HFSCatalogFolder *)srcPtr;
1022 if ((char *)srcRec + sizeof(*srcRec) > nextRecord) {
1023 if (debug) plog("hfs_swap_HFSBTInternalNode: catalog folder record #%d too big\n", srcDesc->numRecords-i-1);
1024 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
1025 return E_BadNode;
1026 }
1027
1028 srcRec->flags = SWAP_BE16 (srcRec->flags);
1029 srcRec->valence = SWAP_BE16 (srcRec->valence);
1030
1031 srcRec->folderID = SWAP_BE32 (srcRec->folderID);
1032 srcRec->createDate = SWAP_BE32 (srcRec->createDate);
1033 srcRec->modifyDate = SWAP_BE32 (srcRec->modifyDate);
1034 srcRec->backupDate = SWAP_BE32 (srcRec->backupDate);
1035
1036 /* The only field we use in srcRec->userInfo is frFlags (used in VLockedChk). */
1037 srcRec->userInfo.frFlags = SWAP_BE16 (srcRec->userInfo.frFlags);
1038
1039 /* Don't swap srcRec->finderInfo */
1040 /* Don't swap resserved array */
1041
1042 } else if (srcPtr[0] == kHFSFileRecord) {
1043 HFSCatalogFile *srcRec = (HFSCatalogFile *)srcPtr;
1044 if ((char *)srcRec + sizeof(*srcRec) > nextRecord) {
1045 if (debug) plog("hfs_swap_HFSBTInternalNode: catalog file record #%d too big\n", srcDesc->numRecords-i-1);
1046 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
1047 return E_BadNode;
1048 }
1049
1050 srcRec->flags = srcRec->flags;
1051 srcRec->fileType = srcRec->fileType;
1052
1053 /* Don't swap srcRec->userInfo */
1054
1055 srcRec->fileID = SWAP_BE32 (srcRec->fileID);
1056
1057 srcRec->dataStartBlock = SWAP_BE16 (srcRec->dataStartBlock);
1058 srcRec->dataLogicalSize = SWAP_BE32 (srcRec->dataLogicalSize);
1059 srcRec->dataPhysicalSize = SWAP_BE32 (srcRec->dataPhysicalSize);
1060
1061 srcRec->rsrcStartBlock = SWAP_BE16 (srcRec->rsrcStartBlock);
1062 srcRec->rsrcLogicalSize = SWAP_BE32 (srcRec->rsrcLogicalSize);
1063 srcRec->rsrcPhysicalSize = SWAP_BE32 (srcRec->rsrcPhysicalSize);
1064
1065 srcRec->createDate = SWAP_BE32 (srcRec->createDate);
1066 srcRec->modifyDate = SWAP_BE32 (srcRec->modifyDate);
1067 srcRec->backupDate = SWAP_BE32 (srcRec->backupDate);
1068
1069 /* Don't swap srcRec->finderInfo */
1070
1071 srcRec->clumpSize = SWAP_BE16 (srcRec->clumpSize);
1072
1073 /* Swap the two sets of extents as an array of six (three each) UInt16 */
1074 for (j = 0; j < kHFSExtentDensity * 2; j++) {
1075 srcRec->dataExtents[j].startBlock = SWAP_BE16 (srcRec->dataExtents[j].startBlock);
1076 srcRec->dataExtents[j].blockCount = SWAP_BE16 (srcRec->dataExtents[j].blockCount);
1077 }
1078
1079 /* Don't swap srcRec->reserved */
1080
1081 } else if ((srcPtr[0] == kHFSFolderThreadRecord) ||
1082 (srcPtr[0] == kHFSFileThreadRecord)) {
1083 HFSCatalogThread *srcRec = (HFSCatalogThread *)srcPtr;
1084
1085 /* Make sure there is room for parentID and name length */
1086 if ((char *) &srcRec->nodeName[1] > nextRecord) {
1087 if (debug) plog("hfs_swap_HFSBTInternalNode: catalog thread record #%d too big\n", srcDesc->numRecords-i-1);
1088 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
1089 return E_BadNode;
1090 }
1091
1092 /* Don't swap srcRec->reserved array */
1093
1094 srcRec->parentID = SWAP_BE32 (srcRec->parentID);
1095
1096 /* Don't swap srcRec->nodeName */
1097
1098 /* Make sure there is room for the name in the buffer */
1099 if ((char *) &srcRec->nodeName[srcRec->nodeName[0]] > nextRecord) {
1100 if (debug) plog("hfs_swap_HFSBTInternalNode: catalog thread record #%d name too big\n", srcDesc->numRecords-i-1);
1101 WriteError(fcb->fcbVolume->vcbGPtr, E_BadNode, fcb->fcbFileID, src->blockNum);
1102 return E_BadNode;
1103 }
1104 } else {
1105 if (debug) plog("hfs_swap_HFSBTInternalNode: unrecognized catalog record type (0x%04X; record #%d)\n", srcPtr[0], srcDesc->numRecords-i-1);
1106 }
1107
1108 /* We can swap the record type now that we're done using it */
1109 if (direction == kSwapBTNodeHostToBig)
1110 srcPtr[0] = SWAP_BE16 (srcPtr[0]);
1111 }
1112
1113 } else {
1114 plog("hfs_swap_HFSBTInternalNode: fileID %u is not a system B-tree\n", fileID);
1115 exit(99);
1116 }
1117
1118 return (0);
1119 }