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