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