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