+ } else if (fileID == kHFSAttributesFileID) {
+ HFSPlusAttrKey *srcKey;
+ HFSPlusAttrRecord *srcRec;
+ u_int16_t keyLength;
+ u_int32_t attrSize = 0;
+
+ for (i = 0; i < srcDesc->numRecords; i++) {
+ /* Point to the start of the record we're currently checking. */
+ srcKey = (HFSPlusAttrKey *)((char *)src->buffer + srcOffs[i]);
+
+ /*
+ * Point to start of next (larger offset) record. We'll use this
+ * to be sure the current record doesn't overflow into the next
+ * record.
+ */
+ nextRecord = (char *)src->buffer + srcOffs[i-1];
+
+ /* Make sure there is room in the buffer for a minimal key */
+ 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;
+ }
+
+ /* Swap the key length field */
+ if (direction == kSwapBTNodeBigToHost)
+ srcKey->keyLength = SWAP_BE16(srcKey->keyLength);
+ keyLength = srcKey->keyLength; /* Keep a copy in native order */
+ if (direction == kSwapBTNodeHostToBig)
+ srcKey->keyLength = SWAP_BE16(srcKey->keyLength);
+
+ /*
+ * Make sure that we can safely dereference the record's type field or
+ * an index node's child node number.
+ */
+ 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);
+
+ /*
+ * Swap and check the attribute name
+ */
+ if (direction == kSwapBTNodeBigToHost)
+ srcKey->attrNameLen = SWAP_BE16(srcKey->attrNameLen);
+ /* Sanity check the attribute name length */
+ 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);
+
+ /*
+ * For index nodes, the record data is just the child's node number.
+ * Skip over swapping the various types of attribute record.
+ */
+ if (srcDesc->kind == kBTIndexNode) {
+ *((u_int32_t *)srcRec) = SWAP_BE32 (*((u_int32_t *)srcRec));
+ continue;
+ }
+
+ /* Swap the record data */
+ if (direction == kSwapBTNodeBigToHost)
+ srcRec->recordType = SWAP_BE32(srcRec->recordType);
+ switch (srcRec->recordType) {
+ case kHFSPlusAttrInlineData:
+ /* Is there room for the inline data header? */
+ 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;
+ }
+
+ /* We're not swapping the reserved fields */
+
+ /* Swap the attribute size */
+ if (direction == kSwapBTNodeHostToBig)
+ attrSize = srcRec->attrData.attrSize;
+ srcRec->attrData.attrSize = SWAP_BE32(srcRec->attrData.attrSize);
+ if (direction == kSwapBTNodeBigToHost)
+ attrSize = srcRec->attrData.attrSize;
+
+ /* Is there room for the inline attribute data? */
+ 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;
+ }
+
+ /* Not swapping the attribute data itself */
+ break;
+
+ case kHFSPlusAttrForkData:
+ /* Is there room for the fork data record? */
+ 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;
+ }
+
+ /* We're not swapping the reserved field */
+
+ hfs_swap_HFSPlusForkData(&srcRec->forkData.theFork);
+ break;
+
+ case kHFSPlusAttrExtents:
+ /* Is there room for an extent record? */
+ 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;
+ }
+
+ /* We're not swapping the reserved field */
+
+ 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);
+ }