#include "hfs_endian.h"
#include "hfs_dbg.h"
#include "hfscommon/headers/BTreesPrivate.h"
#undef ENDIAN_DEBUG
int hfs_swap_HFSPlusBTInternalNode (BlockDescriptor *src, HFSCatalogNodeID fileID, enum HFSBTSwapDirection direction);
int hfs_swap_HFSBTInternalNode (BlockDescriptor *src, HFSCatalogNodeID fileID, enum HFSBTSwapDirection direction);
void hfs_swap_HFSPlusForkData (HFSPlusForkData *src);
void
hfs_swap_HFSPlusForkData (
HFSPlusForkData *src
)
{
int i;
src->logicalSize = SWAP_BE64 (src->logicalSize);
src->clumpSize = SWAP_BE32 (src->clumpSize);
src->totalBlocks = SWAP_BE32 (src->totalBlocks);
for (i = 0; i < kHFSPlusExtentDensity; i++) {
src->extents[i].startBlock = SWAP_BE32 (src->extents[i].startBlock);
src->extents[i].blockCount = SWAP_BE32 (src->extents[i].blockCount);
}
}
int
hfs_swap_BTNode (
BlockDescriptor *src,
vnode_t vp,
enum HFSBTSwapDirection direction,
u_int8_t allow_empty_node
)
{
BTNodeDescriptor *srcDesc = src->buffer;
u_int16_t *srcOffs = NULL;
BTreeControlBlockPtr btcb = (BTreeControlBlockPtr)VTOF(vp)->fcbBTCBPtr;
u_int16_t i;
int error = 0;
#ifdef ENDIAN_DEBUG
if (direction == kSwapBTNodeBigToHost) {
printf ("hfs: BE -> Native Swap\n");
} else if (direction == kSwapBTNodeHostToBig) {
printf ("hfs: Native -> BE Swap\n");
} else if (direction == kSwapBTNodeHeaderRecordOnly) {
printf ("hfs: Not swapping descriptors\n");
} else {
panic ("hfs_swap_BTNode: This is impossible");
}
#endif
if (direction == kSwapBTNodeBigToHost) {
srcDesc->fLink = SWAP_BE32 (srcDesc->fLink);
srcDesc->bLink = SWAP_BE32 (srcDesc->bLink);
if (btcb->totalNodes != 0) {
if (srcDesc->fLink >= btcb->totalNodes) {
printf("hfs_swap_BTNode: invalid forward link (0x%08x >= 0x%08x)\n", srcDesc->fLink, btcb->totalNodes);
error = fsBTInvalidHeaderErr;
goto fail;
}
if (srcDesc->bLink >= btcb->totalNodes) {
printf("hfs_swap_BTNode: invalid backward link (0x%08x >= 0x%08x)\n", srcDesc->bLink, btcb->totalNodes);
error = fsBTInvalidHeaderErr;
goto fail;
}
if ((src->blockNum != 0) && (srcDesc->fLink == (u_int32_t) src->blockNum)) {
printf("hfs_swap_BTNode: invalid forward link (0x%08x == 0x%08x)\n",
srcDesc->fLink, (u_int32_t) src->blockNum);
error = fsBTInvalidHeaderErr;
goto fail;
}
if ((src->blockNum != 0) && (srcDesc->bLink == (u_int32_t) src->blockNum)) {
printf("hfs_swap_BTNode: invalid backward link (0x%08x == 0x%08x)\n",
srcDesc->bLink, (u_int32_t) src->blockNum);
error = fsBTInvalidHeaderErr;
goto fail;
}
}
if (srcDesc->kind < kBTLeafNode || srcDesc->kind > kBTMapNode) {
printf("hfs_swap_BTNode: invalid node kind (%d)\n", srcDesc->kind);
error = fsBTInvalidHeaderErr;
goto fail;
}
if (srcDesc->height > kMaxTreeDepth) {
printf("hfs_swap_BTNode: invalid node height (%d)\n", srcDesc->height);
error = fsBTInvalidHeaderErr;
goto fail;
}
srcDesc->numRecords = SWAP_BE16 (srcDesc->numRecords);
srcOffs = (u_int16_t *)((char *)src->buffer + (src->blockSize - ((srcDesc->numRecords + 1) * sizeof (u_int16_t))));
if ((char *)srcOffs > ((char *)src->buffer + src->blockSize) ||
(char *)srcOffs < ((char *)src->buffer + sizeof(BTNodeDescriptor))) {
printf("hfs_swap_BTNode: invalid record count (0x%04X)\n", srcDesc->numRecords);
error = fsBTInvalidHeaderErr;
goto fail;
}
for (i = 0; i <= srcDesc->numRecords; i++) {
srcOffs[i] = SWAP_BE16 (srcOffs[i]);
if ((srcOffs[i] & 1) || (
(allow_empty_node == false) && (srcOffs[i] == 0)) ||
(srcOffs[i] < sizeof(BTNodeDescriptor) && srcOffs[i] != 0) ||
(srcOffs[i] >= src->blockSize)) {
printf("hfs_swap_BTNode: record #%d invalid offset (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
error = fsBTInvalidHeaderErr;
goto fail;
}
if ((i != 0) && (srcOffs[i] >= srcOffs[i-1])) {
printf("hfs_swap_BTNode: offsets %d and %d out of order (0x%04X, 0x%04X)\n",
srcDesc->numRecords-i-1, srcDesc->numRecords-i, srcOffs[i], srcOffs[i-1]);
error = fsBTInvalidHeaderErr;
goto fail;
}
}
}
if ((srcDesc->kind == kBTIndexNode) ||
(srcDesc-> kind == kBTLeafNode)) {
if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
error = hfs_swap_HFSPlusBTInternalNode (src, VTOC(vp)->c_fileid, direction);
} else {
error = hfs_swap_HFSBTInternalNode (src, VTOC(vp)->c_fileid, direction);
}
if (error) goto fail;
} else if (srcDesc-> kind == kBTMapNode) {
} else if (srcDesc-> kind == kBTHeaderNode) {
BTHeaderRec *srcHead = (BTHeaderRec *)((char *)src->buffer + sizeof(BTNodeDescriptor));
srcHead->treeDepth = SWAP_BE16 (srcHead->treeDepth);
srcHead->rootNode = SWAP_BE32 (srcHead->rootNode);
srcHead->leafRecords = SWAP_BE32 (srcHead->leafRecords);
srcHead->firstLeafNode = SWAP_BE32 (srcHead->firstLeafNode);
srcHead->lastLeafNode = SWAP_BE32 (srcHead->lastLeafNode);
srcHead->nodeSize = SWAP_BE16 (srcHead->nodeSize);
srcHead->maxKeyLength = SWAP_BE16 (srcHead->maxKeyLength);
srcHead->totalNodes = SWAP_BE32 (srcHead->totalNodes);
srcHead->freeNodes = SWAP_BE32 (srcHead->freeNodes);
srcHead->clumpSize = SWAP_BE32 (srcHead->clumpSize);
srcHead->attributes = SWAP_BE32 (srcHead->attributes);
}
if (direction == kSwapBTNodeHostToBig) {
if (srcDesc->fLink >= btcb->totalNodes) {
panic("hfs_UNswap_BTNode: invalid forward link (0x%08X)\n", srcDesc->fLink);
error = fsBTInvalidHeaderErr;
goto fail;
}
if ((src->blockNum != 0) && (srcDesc->fLink == (u_int32_t) src->blockNum)) {
panic ("hfs_UNswap_BTNode: invalid forward link (0x%08x == 0x%08x)\n",
srcDesc->fLink, (u_int32_t) src->blockNum);
error = fsBTInvalidHeaderErr;
goto fail;
}
if (srcDesc->bLink >= btcb->totalNodes) {
panic("hfs_UNswap_BTNode: invalid backward link (0x%08X)\n", srcDesc->bLink);
error = fsBTInvalidHeaderErr;
goto fail;
}
if ((src->blockNum != 0) && (srcDesc->bLink == (u_int32_t) src->blockNum)) {
panic ("hfs_UNswap_BTNode: invalid backward link (0x%08x == 0x%08x)\n",
srcDesc->bLink, (u_int32_t) src->blockNum);
error = fsBTInvalidHeaderErr;
goto fail;
}
srcDesc->fLink = SWAP_BE32 (srcDesc->fLink);
srcDesc->bLink = SWAP_BE32 (srcDesc->bLink);
if (srcDesc->kind < kBTLeafNode || srcDesc->kind > kBTMapNode) {
panic("hfs_UNswap_BTNode: invalid node kind (%d)\n", srcDesc->kind);
error = fsBTInvalidHeaderErr;
goto fail;
}
if (srcDesc->height > kMaxTreeDepth) {
panic("hfs_UNswap_BTNode: invalid node height (%d)\n", srcDesc->height);
error = fsBTInvalidHeaderErr;
goto fail;
}
srcOffs = (u_int16_t *)((char *)src->buffer + (src->blockSize - ((srcDesc->numRecords + 1) * sizeof (u_int16_t))));
if ((char *)srcOffs > ((char *)src->buffer + src->blockSize) ||
(char *)srcOffs < ((char *)src->buffer + sizeof(BTNodeDescriptor))) {
panic("hfs_UNswap_BTNode: invalid record count (0x%04X)\n", srcDesc->numRecords);
error = fsBTInvalidHeaderErr;
goto fail;
}
for (i = 0; i <= srcDesc->numRecords; i++) {
if ((srcOffs[i] & 1) ||
((allow_empty_node == false) && (srcOffs[i] == 0)) ||
(srcOffs[i] < sizeof(BTNodeDescriptor) && srcOffs[i] != 0) ||
(srcOffs[i] >= src->blockSize)) {
panic("hfs_UNswap_BTNode: record #%d invalid offset (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
error = fsBTInvalidHeaderErr;
goto fail;
}
if ((i < srcDesc->numRecords) && (srcOffs[i+1] >= srcOffs[i])) {
panic("hfs_UNswap_BTNode: offsets %d and %d out of order (0x%04X, 0x%04X)\n",
srcDesc->numRecords-i-2, srcDesc->numRecords-i-1, srcOffs[i+1], srcOffs[i]);
error = fsBTInvalidHeaderErr;
goto fail;
}
srcOffs[i] = SWAP_BE16 (srcOffs[i]);
}
srcDesc->numRecords = SWAP_BE16 (srcDesc->numRecords);
}
fail:
if (error) {
printf("hfs: node=%lld fileID=%u volume=%s device=%s\n", src->blockNum, VTOC(vp)->c_fileid,
VTOVCB(vp)->vcbVN, vfs_statfs(vnode_mount(vp))->f_mntfromname);
hfs_mark_volume_inconsistent(VTOVCB(vp));
}
return (error);
}
int
hfs_swap_HFSPlusBTInternalNode (
BlockDescriptor *src,
HFSCatalogNodeID fileID,
enum HFSBTSwapDirection direction
)
{
BTNodeDescriptor *srcDesc = src->buffer;
u_int16_t *srcOffs = (u_int16_t *)((char *)src->buffer + (src->blockSize - (srcDesc->numRecords * sizeof (u_int16_t))));
char *nextRecord;
int32_t i;
u_int32_t j;
if (fileID == kHFSExtentsFileID) {
HFSPlusExtentKey *srcKey;
HFSPlusExtentDescriptor *srcRec;
size_t recordSize;
if (srcDesc->kind == kBTIndexNode)
recordSize = sizeof(u_int32_t);
else
recordSize = sizeof(HFSPlusExtentDescriptor);
for (i = 0; i < srcDesc->numRecords; i++) {
srcKey = (HFSPlusExtentKey *)((char *)src->buffer + srcOffs[i]);
nextRecord = (char *)src->buffer + srcOffs[i-1];
if ((char *)srcKey + sizeof(HFSPlusExtentKey) + recordSize > nextRecord) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSPlusBTInternalNode: extents key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
} else {
printf("hfs_swap_HFSPlusBTInternalNode: extents key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
}
return fsBTInvalidNodeErr;
}
if (direction == kSwapBTNodeBigToHost)
srcKey->keyLength = SWAP_BE16 (srcKey->keyLength);
if (srcKey->keyLength != sizeof(*srcKey) - sizeof(srcKey->keyLength)) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSPlusBTInternalNode: extents key #%d invalid length (%d)\n", srcDesc->numRecords-i-1, srcKey->keyLength);
} else {
printf("hfs_swap_HFSPlusBTInternalNode: extents key #%d invalid length (%d)\n", srcDesc->numRecords-i-1, srcKey->keyLength);
}
return fsBTInvalidNodeErr;
}
srcRec = (HFSPlusExtentDescriptor *)((char *)srcKey + srcKey->keyLength + sizeof(srcKey->keyLength));
if (direction == kSwapBTNodeHostToBig)
srcKey->keyLength = SWAP_BE16 (srcKey->keyLength);
srcKey->fileID = SWAP_BE32 (srcKey->fileID);
srcKey->startBlock = SWAP_BE32 (srcKey->startBlock);
if (srcDesc->kind == kBTIndexNode) {
*((u_int32_t *)srcRec) = SWAP_BE32 (*((u_int32_t *)srcRec));
} else {
for (j = 0; j < kHFSPlusExtentDensity; j++) {
srcRec[j].startBlock = SWAP_BE32 (srcRec[j].startBlock);
srcRec[j].blockCount = SWAP_BE32 (srcRec[j].blockCount);
}
}
}
} else if (fileID == kHFSCatalogFileID) {
HFSPlusCatalogKey *srcKey;
int16_t *srcPtr;
u_int16_t keyLength;
for (i = 0; i < srcDesc->numRecords; i++) {
srcKey = (HFSPlusCatalogKey *)((char *)src->buffer + srcOffs[i]);
nextRecord = (char *)src->buffer + (uintptr_t)(srcOffs[i-1]);
if ((char *)srcKey + offsetof(HFSPlusCatalogKey, nodeName.unicode[0]) > nextRecord) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSPlusBTInternalNode: catalog key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
} else {
printf("hfs_swap_HFSPlusBTInternalNode: catalog key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
}
return fsBTInvalidNodeErr;
}
if (direction == kSwapBTNodeBigToHost)
srcKey->keyLength = SWAP_BE16 (srcKey->keyLength);
keyLength = srcKey->keyLength;
if (direction == kSwapBTNodeHostToBig)
srcKey->keyLength = SWAP_BE16 (keyLength);
if (keyLength < kHFSPlusCatalogKeyMinimumLength || keyLength > kHFSPlusCatalogKeyMaximumLength) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSPlusBTInternalNode: catalog key #%d invalid length (%d)\n", srcDesc->numRecords-i-1, keyLength);
} else {
printf("hfs_swap_HFSPlusBTInternalNode: catalog key #%d invalid length (%d)\n", srcDesc->numRecords-i-1, keyLength);
}
return fsBTInvalidNodeErr;
}
srcPtr = (int16_t *)((char *)srcKey + keyLength + sizeof(srcKey->keyLength));
if ((char *)srcPtr + sizeof(u_int32_t) > nextRecord) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSPlusBTInternalNode: catalog key #%d too big\n", srcDesc->numRecords-i-1);
} else {
printf("hfs_swap_HFSPlusBTInternalNode: catalog key #%d too big\n", srcDesc->numRecords-i-1);
}
return fsBTInvalidNodeErr;
}
srcKey->parentID = SWAP_BE32 (srcKey->parentID);
if (direction == kSwapBTNodeBigToHost)
srcKey->nodeName.length = SWAP_BE16 (srcKey->nodeName.length);
if (keyLength < sizeof(srcKey->parentID) + sizeof(srcKey->nodeName.length) +
srcKey->nodeName.length*sizeof(srcKey->nodeName.unicode[0])) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSPlusBTInternalNode: catalog record #%d keyLength=%d expected=%lu\n",
srcDesc->numRecords-i, keyLength, sizeof(srcKey->parentID) + sizeof(srcKey->nodeName.length) +
srcKey->nodeName.length*sizeof(srcKey->nodeName.unicode[0]));
} else {
printf("hfs_swap_HFSPlusBTInternalNode: catalog record #%d keyLength=%d expected=%lu\n",
srcDesc->numRecords-i, keyLength, sizeof(srcKey->parentID) + sizeof(srcKey->nodeName.length) +
srcKey->nodeName.length*sizeof(srcKey->nodeName.unicode[0]));
}
return fsBTInvalidNodeErr;
}
for (j = 0; j < srcKey->nodeName.length; j++) {
srcKey->nodeName.unicode[j] = SWAP_BE16 (srcKey->nodeName.unicode[j]);
}
if (direction == kSwapBTNodeHostToBig)
srcKey->nodeName.length = SWAP_BE16 (srcKey->nodeName.length);
if (srcDesc->kind == kBTIndexNode) {
*((u_int32_t *)srcPtr) = SWAP_BE32 (*((u_int32_t *)srcPtr));
continue;
}
if (direction == kSwapBTNodeBigToHost)
srcPtr[0] = SWAP_BE16 (srcPtr[0]);
if (srcPtr[0] == kHFSPlusFolderRecord) {
HFSPlusCatalogFolder *srcRec = (HFSPlusCatalogFolder *)srcPtr;
if ((char *)srcRec + sizeof(*srcRec) > nextRecord) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSPlusBTInternalNode: catalog folder record #%d too big\n", srcDesc->numRecords-i-1);
} else {
printf("hfs_swap_HFSPlusBTInternalNode: catalog folder record #%d too big\n", srcDesc->numRecords-i-1);
}
return fsBTInvalidNodeErr;
}
srcRec->flags = SWAP_BE16 (srcRec->flags);
srcRec->valence = SWAP_BE32 (srcRec->valence);
srcRec->folderID = SWAP_BE32 (srcRec->folderID);
srcRec->createDate = SWAP_BE32 (srcRec->createDate);
srcRec->contentModDate = SWAP_BE32 (srcRec->contentModDate);
srcRec->attributeModDate = SWAP_BE32 (srcRec->attributeModDate);
srcRec->accessDate = SWAP_BE32 (srcRec->accessDate);
srcRec->backupDate = SWAP_BE32 (srcRec->backupDate);
srcRec->bsdInfo.ownerID = SWAP_BE32 (srcRec->bsdInfo.ownerID);
srcRec->bsdInfo.groupID = SWAP_BE32 (srcRec->bsdInfo.groupID);
srcRec->bsdInfo.fileMode = SWAP_BE16 (srcRec->bsdInfo.fileMode);
srcRec->bsdInfo.special.iNodeNum = SWAP_BE32 (srcRec->bsdInfo.special.iNodeNum);
srcRec->textEncoding = SWAP_BE32 (srcRec->textEncoding);
srcRec->folderCount = SWAP_BE32 (srcRec->folderCount);
} else if (srcPtr[0] == kHFSPlusFileRecord) {
HFSPlusCatalogFile *srcRec = (HFSPlusCatalogFile *)srcPtr;
if ((char *)srcRec + sizeof(*srcRec) > nextRecord) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSPlusBTInternalNode: catalog file record #%d too big\n", srcDesc->numRecords-i-1);
} else {
printf("hfs_swap_HFSPlusBTInternalNode: catalog file record #%d too big\n", srcDesc->numRecords-i-1);
}
return fsBTInvalidNodeErr;
}
srcRec->flags = SWAP_BE16 (srcRec->flags);
srcRec->fileID = SWAP_BE32 (srcRec->fileID);
srcRec->createDate = SWAP_BE32 (srcRec->createDate);
srcRec->contentModDate = SWAP_BE32 (srcRec->contentModDate);
srcRec->attributeModDate = SWAP_BE32 (srcRec->attributeModDate);
srcRec->accessDate = SWAP_BE32 (srcRec->accessDate);
srcRec->backupDate = SWAP_BE32 (srcRec->backupDate);
srcRec->bsdInfo.ownerID = SWAP_BE32 (srcRec->bsdInfo.ownerID);
srcRec->bsdInfo.groupID = SWAP_BE32 (srcRec->bsdInfo.groupID);
srcRec->bsdInfo.fileMode = SWAP_BE16 (srcRec->bsdInfo.fileMode);
srcRec->bsdInfo.special.iNodeNum = SWAP_BE32 (srcRec->bsdInfo.special.iNodeNum);
srcRec->textEncoding = SWAP_BE32 (srcRec->textEncoding);
srcRec->reserved1 = SWAP_BE32 (srcRec->reserved1);
hfs_swap_HFSPlusForkData (&srcRec->dataFork);
hfs_swap_HFSPlusForkData (&srcRec->resourceFork);
} else if ((srcPtr[0] == kHFSPlusFolderThreadRecord) ||
(srcPtr[0] == kHFSPlusFileThreadRecord)) {
HFSPlusCatalogThread *srcRec = (HFSPlusCatalogThread *)srcPtr;
if ((char *) &srcRec->nodeName.unicode[0] > nextRecord) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSPlusBTInternalNode: catalog thread record #%d too big\n", srcDesc->numRecords-i-1);
} else {
printf("hfs_swap_HFSPlusBTInternalNode: catalog thread record #%d too big\n", srcDesc->numRecords-i-1);
}
return fsBTInvalidNodeErr;
}
srcRec->parentID = SWAP_BE32 (srcRec->parentID);
if (direction == kSwapBTNodeBigToHost)
srcRec->nodeName.length = SWAP_BE16 (srcRec->nodeName.length);
if ((char *) &srcRec->nodeName.unicode[srcRec->nodeName.length] > nextRecord) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSPlusBTInternalNode: catalog thread record #%d name too big\n", srcDesc->numRecords-i-1);
} else {
printf("hfs_swap_HFSPlusBTInternalNode: catalog thread record #%d name too big\n", srcDesc->numRecords-i-1);
}
return fsBTInvalidNodeErr;
}
for (j = 0; j < srcRec->nodeName.length; j++) {
srcRec->nodeName.unicode[j] = SWAP_BE16 (srcRec->nodeName.unicode[j]);
}
if (direction == kSwapBTNodeHostToBig)
srcRec->nodeName.length = SWAP_BE16 (srcRec->nodeName.length);
} else {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSPlusBTInternalNode: unrecognized catalog record type (0x%04X; record #%d)\n", srcPtr[0], srcDesc->numRecords-i-1);
} else {
printf("hfs_swap_HFSPlusBTInternalNode: unrecognized catalog record type (0x%04X; record #%d)\n", srcPtr[0], srcDesc->numRecords-i-1);
}
return fsBTInvalidNodeErr;
}
if (direction == kSwapBTNodeHostToBig)
srcPtr[0] = SWAP_BE16 (srcPtr[0]);
}
} else if (fileID == kHFSAttributesFileID) {
HFSPlusAttrKey *srcKey;
HFSPlusAttrRecord *srcRec;
u_int16_t keyLength;
u_int32_t attrSize = 0;
for (i = 0; i < srcDesc->numRecords; i++) {
srcKey = (HFSPlusAttrKey *)((char *)src->buffer + srcOffs[i]);
nextRecord = (char *)src->buffer + srcOffs[i-1];
if ((char *) &srcKey->attrName[1] > nextRecord) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSPlusBTInternalNode: attr key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
} else {
printf("hfs_swap_HFSPlusBTInternalNode: attr key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
}
return fsBTInvalidNodeErr;
}
if (direction == kSwapBTNodeBigToHost)
srcKey->keyLength = SWAP_BE16(srcKey->keyLength);
keyLength = srcKey->keyLength;
if (direction == kSwapBTNodeHostToBig)
srcKey->keyLength = SWAP_BE16(srcKey->keyLength);
srcRec = (HFSPlusAttrRecord *)((char *)srcKey + keyLength + sizeof(srcKey->keyLength));
if ((char *)srcRec + sizeof(u_int32_t) > nextRecord) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSPlusBTInternalNode: attr key #%d too big (%d)\n", srcDesc->numRecords-i-1, keyLength);
} else {
printf("hfs_swap_HFSPlusBTInternalNode: attr key #%d too big (%d)\n", srcDesc->numRecords-i-1, keyLength);
}
return fsBTInvalidNodeErr;
}
srcKey->fileID = SWAP_BE32(srcKey->fileID);
srcKey->startBlock = SWAP_BE32(srcKey->startBlock);
if (direction == kSwapBTNodeBigToHost)
srcKey->attrNameLen = SWAP_BE16(srcKey->attrNameLen);
if (srcKey->attrNameLen > kHFSMaxAttrNameLen || keyLength < (kHFSPlusAttrKeyMinimumLength + sizeof(u_int16_t)*srcKey->attrNameLen)) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSPlusBTInternalNode: attr key #%d keyLength=%d attrNameLen=%d\n", srcDesc->numRecords-i-1, keyLength, srcKey->attrNameLen);
} else {
printf("hfs_swap_HFSPlusBTInternalNode: attr key #%d keyLength=%d attrNameLen=%d\n", srcDesc->numRecords-i-1, keyLength, srcKey->attrNameLen);
}
return fsBTInvalidNodeErr;
}
for (j = 0; j < srcKey->attrNameLen; j++)
srcKey->attrName[j] = SWAP_BE16(srcKey->attrName[j]);
if (direction == kSwapBTNodeHostToBig)
srcKey->attrNameLen = SWAP_BE16(srcKey->attrNameLen);
if (srcDesc->kind == kBTIndexNode) {
*((u_int32_t *)srcRec) = SWAP_BE32 (*((u_int32_t *)srcRec));
continue;
}
if (direction == kSwapBTNodeBigToHost)
srcRec->recordType = SWAP_BE32(srcRec->recordType);
switch (srcRec->recordType) {
case kHFSPlusAttrInlineData:
if ((char *) &srcRec->attrData.attrData[0] > nextRecord) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSPlusBTInternalNode: attr inline #%d too big\n", srcDesc->numRecords-i-1);
} else {
printf("hfs_swap_HFSPlusBTInternalNode: attr inline #%d too big\n", srcDesc->numRecords-i-1);
}
return fsBTInvalidNodeErr;
}
if (direction == kSwapBTNodeHostToBig)
attrSize = srcRec->attrData.attrSize;
srcRec->attrData.attrSize = SWAP_BE32(srcRec->attrData.attrSize);
if (direction == kSwapBTNodeBigToHost)
attrSize = srcRec->attrData.attrSize;
if ((char *) &srcRec->attrData.attrData[attrSize] > nextRecord) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSPlusBTInternalNode: attr inline #%d too big (attrSize=%u)\n", srcDesc->numRecords-i-1, attrSize);
} else {
printf("hfs_swap_HFSPlusBTInternalNode: attr inline #%d too big (attrSize=%u)\n", srcDesc->numRecords-i-1, attrSize);
}
return fsBTInvalidNodeErr;
}
break;
case kHFSPlusAttrForkData:
if ((char *)srcRec + sizeof(HFSPlusAttrForkData) > nextRecord) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSPlusBTInternalNode: attr fork data #%d too big\n", srcDesc->numRecords-i-1);
} else {
printf("hfs_swap_HFSPlusBTInternalNode: attr fork data #%d too big\n", srcDesc->numRecords-i-1);
}
return fsBTInvalidNodeErr;
}
hfs_swap_HFSPlusForkData(&srcRec->forkData.theFork);
break;
case kHFSPlusAttrExtents:
if ((char *)srcRec + sizeof(HFSPlusAttrExtents) > nextRecord) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSPlusBTInternalNode: attr extents #%d too big\n", srcDesc->numRecords-i-1);
} else {
printf("hfs_swap_HFSPlusBTInternalNode: attr extents #%d too big\n", srcDesc->numRecords-i-1);
}
return fsBTInvalidNodeErr;
}
for (j = 0; j < kHFSPlusExtentDensity; j++) {
srcRec->overflowExtents.extents[j].startBlock =
SWAP_BE32(srcRec->overflowExtents.extents[j].startBlock);
srcRec->overflowExtents.extents[j].blockCount =
SWAP_BE32(srcRec->overflowExtents.extents[j].blockCount);
}
break;
}
if (direction == kSwapBTNodeHostToBig)
srcRec->recordType = SWAP_BE32(srcRec->recordType);
}
} else if (fileID > kHFSFirstUserCatalogNodeID) {
HotFileKey *srcKey;
u_int32_t *srcRec;
for (i = 0; i < srcDesc->numRecords; i++) {
srcKey = (HotFileKey *)((char *)src->buffer + srcOffs[i]);
nextRecord = (char *)src->buffer + srcOffs[i-1];
if ((char *)srcKey + sizeof(HotFileKey) + sizeof(u_int32_t) > nextRecord) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSPlusBTInternalNode: hotfile #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
} else {
printf("hfs_swap_HFSPlusBTInternalNode: hotfile #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
}
return fsBTInvalidNodeErr;
}
if (direction == kSwapBTNodeBigToHost)
srcKey->keyLength = SWAP_BE16 (srcKey->keyLength);
if (srcKey->keyLength != sizeof(*srcKey) - sizeof(srcKey->keyLength)) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSPlusBTInternalNode: hotfile #%d incorrect keyLength %d\n", srcDesc->numRecords-i-1, srcKey->keyLength);
} else {
printf("hfs_swap_HFSPlusBTInternalNode: hotfile #%d incorrect keyLength %d\n", srcDesc->numRecords-i-1, srcKey->keyLength);
}
return fsBTInvalidNodeErr;
}
srcRec = (u_int32_t *)((char *)srcKey + srcKey->keyLength + sizeof(srcKey->keyLength));
if (direction == kSwapBTNodeHostToBig)
srcKey->keyLength = SWAP_BE16 (srcKey->keyLength);
srcKey->temperature = SWAP_BE32 (srcKey->temperature);
srcKey->fileID = SWAP_BE32 (srcKey->fileID);
*((u_int32_t *)srcRec) = SWAP_BE32 (*((u_int32_t *)srcRec));
}
} else {
panic ("hfs_swap_HFSPlusBTInternalNode: fileID %u is not a system B-tree\n", fileID);
}
return (0);
}
int
hfs_swap_HFSBTInternalNode (
BlockDescriptor *src,
HFSCatalogNodeID fileID,
enum HFSBTSwapDirection direction
)
{
BTNodeDescriptor *srcDesc = src->buffer;
u_int16_t *srcOffs = (u_int16_t *)((char *)src->buffer + (src->blockSize - (srcDesc->numRecords * sizeof (u_int16_t))));
char *nextRecord;
int32_t i;
u_int32_t j;
if (fileID == kHFSExtentsFileID) {
HFSExtentKey *srcKey;
HFSExtentDescriptor *srcRec;
size_t recordSize;
if (srcDesc->kind == kBTIndexNode)
recordSize = sizeof(u_int32_t);
else
recordSize = sizeof(HFSExtentDescriptor);
for (i = 0; i < srcDesc->numRecords; i++) {
srcKey = (HFSExtentKey *)((char *)src->buffer + srcOffs[i]);
nextRecord = (char *)src->buffer + srcOffs[i-1];
if ((char *)srcKey + sizeof(HFSExtentKey) + recordSize > nextRecord) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSBTInternalNode: extents key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
} else {
printf("hfs_swap_HFSBTInternalNode: extents key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
}
return fsBTInvalidNodeErr;
}
if (srcKey->keyLength != sizeof(*srcKey) - sizeof(srcKey->keyLength)) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSBTInternalNode: extents key #%d invalid length (%d)\n", srcDesc->numRecords-i-1, srcKey->keyLength);
} else {
printf("hfs_swap_HFSBTInternalNode: extents key #%d invalid length (%d)\n", srcDesc->numRecords-i-1, srcKey->keyLength);
}
return fsBTInvalidNodeErr;
}
srcKey->fileID = SWAP_BE32 (srcKey->fileID);
srcKey->startBlock = SWAP_BE16 (srcKey->startBlock);
srcRec = (HFSExtentDescriptor *)((char *)srcKey + ((srcKey->keyLength + 2) & ~1));
if (srcDesc->kind == kBTIndexNode) {
*((u_int32_t *)srcRec) = SWAP_BE32 (*((u_int32_t *)srcRec));
} else {
for (j = 0; j < kHFSExtentDensity; j++) {
srcRec[j].startBlock = SWAP_BE16 (srcRec[j].startBlock);
srcRec[j].blockCount = SWAP_BE16 (srcRec[j].blockCount);
}
}
}
} else if (fileID == kHFSCatalogFileID) {
HFSCatalogKey *srcKey;
int16_t *srcPtr;
unsigned expectedKeyLength;
for (i = 0; i < srcDesc->numRecords; i++) {
srcKey = (HFSCatalogKey *)((char *)src->buffer + srcOffs[i]);
nextRecord = (char *)src->buffer + srcOffs[i-1];
if ((char *)srcKey + 8 > nextRecord) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSBTInternalNode: catalog key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
} else {
printf("hfs_swap_HFSBTInternalNode: catalog key #%d offset too big (0x%04X)\n", srcDesc->numRecords-i-1, srcOffs[i]);
}
return fsBTInvalidNodeErr;
}
if (srcKey->keyLength < kHFSCatalogKeyMinimumLength || srcKey->keyLength > kHFSCatalogKeyMaximumLength) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSBTInternalNode: catalog key #%d invalid length (%d)\n", srcDesc->numRecords-i-1, srcKey->keyLength);
} else {
printf("hfs_swap_HFSBTInternalNode: catalog key #%d invalid length (%d)\n", srcDesc->numRecords-i-1, srcKey->keyLength);
}
return fsBTInvalidNodeErr;
}
srcKey->parentID = SWAP_BE32 (srcKey->parentID);
if (srcDesc->kind == kBTIndexNode)
expectedKeyLength = sizeof(*srcKey) - sizeof(srcKey->keyLength);
else
expectedKeyLength = srcKey->nodeName[0] + kHFSCatalogKeyMinimumLength;
if (srcKey->keyLength < expectedKeyLength) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSBTInternalNode: catalog record #%d keyLength=%u expected=%u\n",
srcDesc->numRecords-i, srcKey->keyLength, expectedKeyLength);
} else {
printf("hfs_swap_HFSBTInternalNode: catalog record #%d keyLength=%u expected=%u\n",
srcDesc->numRecords-i, srcKey->keyLength, expectedKeyLength);
}
return fsBTInvalidNodeErr;
}
srcPtr = (int16_t *)((char *)srcKey + ((srcKey->keyLength + 2) & ~1));
if ((char *)srcPtr + sizeof(u_int32_t) > nextRecord) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSBTInternalNode: catalog key #%d too big\n", srcDesc->numRecords-i-1);
} else {
printf("hfs_swap_HFSBTInternalNode: catalog key #%d too big\n", srcDesc->numRecords-i-1);
}
return fsBTInvalidNodeErr;
}
if (srcDesc->kind == kBTIndexNode) {
*((u_int32_t *)srcPtr) = SWAP_BE32 (*((u_int32_t *)srcPtr));
continue;
}
if (direction == kSwapBTNodeBigToHost)
srcPtr[0] = SWAP_BE16 (srcPtr[0]);
if (srcPtr[0] == kHFSFolderRecord) {
HFSCatalogFolder *srcRec = (HFSCatalogFolder *)srcPtr;
if ((char *)srcRec + sizeof(*srcRec) > nextRecord) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSBTInternalNode: catalog folder record #%d too big\n", srcDesc->numRecords-i-1);
} else {
printf("hfs_swap_HFSBTInternalNode: catalog folder record #%d too big\n", srcDesc->numRecords-i-1);
}
return fsBTInvalidNodeErr;
}
srcRec->flags = SWAP_BE16 (srcRec->flags);
srcRec->valence = SWAP_BE16 (srcRec->valence);
srcRec->folderID = SWAP_BE32 (srcRec->folderID);
srcRec->createDate = SWAP_BE32 (srcRec->createDate);
srcRec->modifyDate = SWAP_BE32 (srcRec->modifyDate);
srcRec->backupDate = SWAP_BE32 (srcRec->backupDate);
} else if (srcPtr[0] == kHFSFileRecord) {
HFSCatalogFile *srcRec = (HFSCatalogFile *)srcPtr;
if ((char *)srcRec + sizeof(*srcRec) > nextRecord) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSBTInternalNode: catalog file record #%d too big\n", srcDesc->numRecords-i-1);
} else {
printf("hfs_swap_HFSBTInternalNode: catalog file record #%d too big\n", srcDesc->numRecords-i-1);
}
return fsBTInvalidNodeErr;
}
srcRec->flags = srcRec->flags;
srcRec->fileType = srcRec->fileType;
srcRec->fileID = SWAP_BE32 (srcRec->fileID);
srcRec->dataStartBlock = SWAP_BE16 (srcRec->dataStartBlock);
srcRec->dataLogicalSize = SWAP_BE32 (srcRec->dataLogicalSize);
srcRec->dataPhysicalSize = SWAP_BE32 (srcRec->dataPhysicalSize);
srcRec->rsrcStartBlock = SWAP_BE16 (srcRec->rsrcStartBlock);
srcRec->rsrcLogicalSize = SWAP_BE32 (srcRec->rsrcLogicalSize);
srcRec->rsrcPhysicalSize = SWAP_BE32 (srcRec->rsrcPhysicalSize);
srcRec->createDate = SWAP_BE32 (srcRec->createDate);
srcRec->modifyDate = SWAP_BE32 (srcRec->modifyDate);
srcRec->backupDate = SWAP_BE32 (srcRec->backupDate);
srcRec->clumpSize = SWAP_BE16 (srcRec->clumpSize);
for (j = 0; j < kHFSExtentDensity * 2; j++) {
srcRec->dataExtents[j].startBlock = SWAP_BE16 (srcRec->dataExtents[j].startBlock);
srcRec->dataExtents[j].blockCount = SWAP_BE16 (srcRec->dataExtents[j].blockCount);
}
} else if ((srcPtr[0] == kHFSFolderThreadRecord) ||
(srcPtr[0] == kHFSFileThreadRecord)) {
HFSCatalogThread *srcRec = (HFSCatalogThread *)srcPtr;
if ((char *) &srcRec->nodeName[1] > nextRecord) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSBTInternalNode: catalog thread record #%d too big\n", srcDesc->numRecords-i-1);
} else {
printf("hfs_swap_HFSBTInternalNode: catalog thread record #%d too big\n", srcDesc->numRecords-i-1);
}
return fsBTInvalidNodeErr;
}
srcRec->parentID = SWAP_BE32 (srcRec->parentID);
if ((char *) &srcRec->nodeName[srcRec->nodeName[0]] > nextRecord) {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSBTInternalNode: catalog thread record #%d name too big\n", srcDesc->numRecords-i-1);
} else {
printf("hfs_swap_HFSBTInternalNode: catalog thread record #%d name too big\n", srcDesc->numRecords-i-1);
}
return fsBTInvalidNodeErr;
}
} else {
if (direction == kSwapBTNodeHostToBig) {
panic("hfs_swap_HFSBTInternalNode: unrecognized catalog record type (0x%04X; record #%d)\n", srcPtr[0], srcDesc->numRecords-i-1);
} else {
printf("hfs_swap_HFSBTInternalNode: unrecognized catalog record type (0x%04X; record #%d)\n", srcPtr[0], srcDesc->numRecords-i-1);
}
return fsBTInvalidNodeErr;
}
if (direction == kSwapBTNodeHostToBig)
srcPtr[0] = SWAP_BE16 (srcPtr[0]);
}
} else {
panic ("hfs_swap_HFSBTInternalNode: fileID %u is not a system B-tree\n", fileID);
}
return (0);
}