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