static long ReadFile(void * file, unsigned long * length, void * base, long offset) { void *extents; long fileID; long fileLength; HFSCatalogFile *hfsFile = file; HFSPlusCatalogFile *hfsPlusFile = file; if (gIsHFSPlus) { fileID = SWAP_BE32(hfsPlusFile->fileID); fileLength = (long)SWAP_BE64(hfsPlusFile->dataFork.logicalSize); extents = &hfsPlusFile->dataFork.extents; } else { fileID = SWAP_BE32(hfsFile->fileID); fileLength = SWAP_BE32(hfsFile->dataLogicalSize); extents = &hfsFile->dataExtents; } if (offset > fileLength) { printf("Offset is too large.\n"); return -1; } if ((*length == 0) || ((offset + *length) > fileLength)) { *length = fileLength - offset; } if (*length > kLoadSize) { printf("File is too large.\n"); return -1; } *length = ReadExtent((char *)extents, fileLength, fileID, offset, *length, (char *)base, 0); return 0; }
static long ReadFile(void *file, long *length, void *base, long offset) { void *extents; unsigned long fileID; u_int64_t fileLength; HFSCatalogFile *hfsFile = file; HFSPlusCatalogFile *hfsPlusFile = file; if (gIsHFSPlus) { fileID = hfsPlusFile->fileID; fileLength = hfsPlusFile->dataFork.logicalSize; extents = &hfsPlusFile->dataFork.extents; } else { fileID = hfsFile->fileID; fileLength = hfsFile->dataLogicalSize; extents = &hfsFile->dataExtents; } if (offset > fileLength) { printf("Offset is too large.\n"); return -1; } if ((*length == 0) || ((offset + *length) > fileLength)) { *length = (long)(fileLength - offset); } if (*length > kLoadSize) { printf("File is too large.\n"); return -1; } *length = ReadExtent(extents, fileLength, fileID, offset, *length, base, 0); return 0; }
static long ReadBTreeEntry(long btree, void * key, char * entry, long * dirIndex) { long extentSize; void *extent; short extentFile; char *nodeBuf; BTNodeDescriptor *node; long nodeSize, result = 0, entrySize = 0; long curNode, index = 0, lowerBound, upperBound; char *testKey, *recordData; // Figure out which tree is being looked at. if (btree == kBTreeCatalog) { if (gIsHFSPlus) { extent = &gHFSPlus->catalogFile.extents; extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize); } else { extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec; extentSize = SWAP_BE32(gHFSMDB->drCTFlSize); } extentFile = kHFSCatalogFileID; } else { if (gIsHFSPlus) { extent = &gHFSPlus->extentsFile.extents; extentSize = SWAP_BE64(gHFSPlus->extentsFile.logicalSize); } else { extent = (HFSExtentDescriptor *)&gHFSMDB->drXTExtRec; extentSize = SWAP_BE32(gHFSMDB->drXTFlSize); } extentFile = kHFSExtentsFileID; } // Read the BTree Header if needed. if (gBTHeaders[btree] == 0) { ReadExtent(extent, extentSize, extentFile, 0, 256, gBTreeHeaderBuffer + btree * 256, 0); gBTHeaders[btree] = (BTHeaderRec *)(gBTreeHeaderBuffer + btree * 256 + sizeof(BTNodeDescriptor)); if ((gIsHFSPlus && btree == kBTreeCatalog) && (gBTHeaders[btree]->keyCompareType == kHFSBinaryCompare)) { gCaseSensitive = 1; } } curNode = SWAP_BE32(gBTHeaders[btree]->rootNode); nodeSize = SWAP_BE16(gBTHeaders[btree]->nodeSize); nodeBuf = (char *)malloc(nodeSize); node = (BTNodeDescriptor *)nodeBuf; while (1) { // Read the current node. ReadExtent(extent, extentSize, extentFile, curNode * nodeSize, nodeSize, nodeBuf, 1); // Find the matching key. lowerBound = 0; upperBound = SWAP_BE16(node->numRecords) - 1; while (lowerBound <= upperBound) { index = (lowerBound + upperBound) / 2; GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &recordData); if (gIsHFSPlus) { if (btree == kBTreeCatalog) { result = CompareHFSPlusCatalogKeys(key, testKey); } else { result = CompareHFSPlusExtentsKeys(key, testKey); } } else { if (btree == kBTreeCatalog) { result = CompareHFSCatalogKeys(key, testKey); } else { result = CompareHFSExtentsKeys(key, testKey); } } if (result < 0) upperBound = index - 1; // search < trial else if (result > 0) lowerBound = index + 1; // search > trial else break; // search = trial } if (result < 0) { index = upperBound; GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &recordData); } // Found the closest key... Recurse on it if this is an index node. if (node->kind == kBTIndexNode) { curNode = SWAP_BE32( *((long *)recordData) ); } else break; } // Return error if the file was not found. if (result != 0) { free(nodeBuf); return -1; } if (btree == kBTreeCatalog) { switch (SWAP_BE16(*(short *)recordData)) { case kHFSFolderRecord : entrySize = 70; break; case kHFSFileRecord : entrySize = 102; break; case kHFSFolderThreadRecord : entrySize = 46; break; case kHFSFileThreadRecord : entrySize = 46; break; case kHFSPlusFolderRecord : entrySize = 88; break; case kHFSPlusFileRecord : entrySize = 248; break; case kHFSPlusFolderThreadRecord : entrySize = 264; break; case kHFSPlusFileThreadRecord : entrySize = 264; break; } } else { if (gIsHFSPlus) entrySize = sizeof(HFSPlusExtentRecord); else entrySize = sizeof(HFSExtentRecord); } bcopy(recordData, entry, entrySize); // Update dirIndex. if (dirIndex != 0) { index++; if (index == SWAP_BE16(node->numRecords)) { index = 0; curNode = SWAP_BE32(node->fLink); } *dirIndex = curNode * nodeSize + index; } free(nodeBuf); return 0; }
long HFSInitPartition(CICell ih) { long extentSize, extentFile, nodeSize; void *extent; if (ih == gCurrentIH) { #ifdef __i386__ CacheInit(ih, gCacheBlockSize); #endif return 0; } #ifdef __i386__ if (!gTempStr) gTempStr = (char *)malloc(4096); if (!gLinkTemp) gLinkTemp = (char *)malloc(64); if (!gBTreeHeaderBuffer) gBTreeHeaderBuffer = (char *)malloc(512); if (!gHFSMdbVib) { gHFSMdbVib = (char *)malloc(kBlockSize); gHFSMDB = (HFSMasterDirectoryBlock *)gHFSMdbVib; } if (!gHFSPlusHeader) { gHFSPlusHeader = (char *)malloc(kBlockSize); gHFSPlus = (HFSPlusVolumeHeader *)gHFSPlusHeader; } if (!gTempStr || !gLinkTemp || !gBTreeHeaderBuffer || !gHFSMdbVib || !gHFSPlusHeader) return -1; #endif /* __i386__ */ gAllocationOffset = 0; gIsHFSPlus = 0; gCaseSensitive = 0; gBTHeaders[0] = 0; gBTHeaders[1] = 0; // Look for the HFS MDB Seek(ih, kMDBBaseOffset); Read(ih, (long)gHFSMdbVib, kBlockSize); if ( SWAP_BE16(gHFSMDB->drSigWord) == kHFSSigWord ) { gAllocationOffset = SWAP_BE16(gHFSMDB->drAlBlSt) * kBlockSize; // See if it is HFSPlus if (SWAP_BE16(gHFSMDB->drEmbedSigWord) != kHFSPlusSigWord) { // Normal HFS; gCacheBlockSize = gBlockSize = SWAP_BE32(gHFSMDB->drAlBlkSiz); CacheInit(ih, gCacheBlockSize); gCurrentIH = ih; // grab the 64 bit volume ID bcopy(&gHFSMDB->drFndrInfo[6], &gVolID, 8); // Get the Catalog BTree node size. extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec; extentSize = SWAP_BE32(gHFSMDB->drCTFlSize); extentFile = kHFSCatalogFileID; ReadExtent(extent, extentSize, extentFile, 0, 256, gBTreeHeaderBuffer + kBTreeCatalog * 256, 0); nodeSize = SWAP_BE16(((BTHeaderRec *)(gBTreeHeaderBuffer + kBTreeCatalog * 256 + sizeof(BTNodeDescriptor)))->nodeSize); // If the BTree node size is larger than the block size, reset the cache. if (nodeSize > gBlockSize) { gCacheBlockSize = nodeSize; CacheInit(ih, gCacheBlockSize); } return 0; } // Calculate the offset to the embeded HFSPlus volume. gAllocationOffset += (long long)SWAP_BE16(gHFSMDB->drEmbedExtent.startBlock) * SWAP_BE32(gHFSMDB->drAlBlkSiz); } // Look for the HFSPlus Header Seek(ih, gAllocationOffset + kMDBBaseOffset); Read(ih, (long)gHFSPlusHeader, kBlockSize); // Not a HFS+ or HFSX volume. if (SWAP_BE16(gHFSPlus->signature) != kHFSPlusSigWord && SWAP_BE16(gHFSPlus->signature) != kHFSXSigWord) { verbose("HFS signature was not present.\n"); gCurrentIH = 0; return -1; } gIsHFSPlus = 1; gCacheBlockSize = gBlockSize = SWAP_BE32(gHFSPlus->blockSize); CacheInit(ih, gCacheBlockSize); gCurrentIH = ih; // grab the 64 bit volume ID bcopy(&gHFSPlus->finderInfo[24], &gVolID, 8); // Get the Catalog BTree node size. extent = &gHFSPlus->catalogFile.extents; extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize); extentFile = kHFSCatalogFileID; ReadExtent(extent, extentSize, extentFile, 0, 256, gBTreeHeaderBuffer + kBTreeCatalog * 256, 0); nodeSize = SWAP_BE16(((BTHeaderRec *)(gBTreeHeaderBuffer + kBTreeCatalog * 256 + sizeof(BTNodeDescriptor)))->nodeSize); // If the BTree node size is larger than the block size, reset the cache. if (nodeSize > gBlockSize) { gCacheBlockSize = nodeSize; CacheInit(ih, gCacheBlockSize); } return 0; }
static long GetCatalogEntry(long long * dirIndex, char ** name, long * flags, u_int32_t * time, FinderInfo * finderInfo, long * infoValid) { u_int64_t extentSize; void *extent; char *nodeBuf, *testKey, *entry; BTNodeDescriptor *node; u_int32_t curNode; u_int16_t nodeSize, index; if (gIsHFSPlus) { extent = &gHFSPlus->catalogFile.extents; extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize); } else { extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec; extentSize = SWAP_BE32(gHFSMDB->drCTFlSize); } nodeSize = SWAP_BE16(gBTHeaders[kBTreeCatalog]->nodeSize); nodeBuf = (char *)malloc(nodeSize); node = (BTNodeDescriptor *)nodeBuf; index = (u_int16_t) (*dirIndex % nodeSize); curNode = (u_int32_t) (*dirIndex / nodeSize); // Read the BTree node and get the record for index. ReadExtent(extent, extentSize, kHFSCatalogFileID, (long long) curNode * nodeSize, nodeSize, nodeBuf, 1); GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &entry); GetCatalogEntryInfo(entry, flags, time, finderInfo, infoValid); // Get the file name. if (gIsHFSPlus) { utf_encodestr(((HFSPlusCatalogKey *)testKey)->nodeName.unicode, SWAP_BE16(((HFSPlusCatalogKey *)testKey)->nodeName.length), (u_int8_t *)gTempStr, 256, OSBigEndian); } else { strncpy(gTempStr, (const char *)&((HFSCatalogKey *)testKey)->nodeName[1], ((HFSCatalogKey *)testKey)->nodeName[0]); gTempStr[((HFSCatalogKey *)testKey)->nodeName[0]] = '\0'; } *name = gTempStr; // Update dirIndex. index++; if (index == SWAP_BE16(node->numRecords)) { index = 0; curNode = SWAP_BE32(node->fLink); } *dirIndex = (long long) curNode * nodeSize + index; free(nodeBuf); return 0; }
long HFSInitPartition(CICell ih) { long extentSize, extentFile, nodeSize; void *extent; if (ih == gCurrentIH) return 0; printf("HFSInitPartition: %x\n", ih); gAllocationOffset = 0; gIsHFSPlus = 0; gCaseSensitive = 0; gBTHeaders[0] = 0; gBTHeaders[1] = 0; // Look for the HFS MDB Seek(ih, kMDBBaseOffset); Read(ih, (long)gHFSMdbVib, kBlockSize); if (gHFSMDB->drSigWord == kHFSSigWord) { gAllocationOffset = gHFSMDB->drAlBlSt * kBlockSize; // See if it is HFSPlus if (gHFSMDB->drEmbedSigWord != kHFSPlusSigWord) { // Normal HFS; gBlockSize = gHFSMDB->drAlBlkSiz; CacheInit(ih, gBlockSize); gCurrentIH = ih; // Get the Catalog BTree node size. extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec; extentSize = gHFSMDB->drCTFlSize; extentFile = kHFSCatalogFileID; ReadExtent(extent, extentSize, extentFile, 0, 256, gBTreeHeaderBuffer + kBTreeCatalog * 256, 0); nodeSize = ((BTHeaderRec *)(gBTreeHeaderBuffer + kBTreeCatalog * 256 + sizeof(BTNodeDescriptor)))->nodeSize; // If the BTree node size is larger than the block size, reset the cache. if (nodeSize > gBlockSize) CacheInit(ih, nodeSize); return 0; } // Calculate the offset to the embeded HFSPlus volume. gAllocationOffset += (long long)gHFSMDB->drEmbedExtent.startBlock * gHFSMDB->drAlBlkSiz; } // Look for the HFSPlus Header Seek(ih, gAllocationOffset + kMDBBaseOffset); Read(ih, (long)gHFSPlusHeader, kBlockSize); // Not a HFS[+] volume. if ((gHFSPlus->signature != kHFSPlusSigWord) && (gHFSPlus->signature != kHFSXSigWord)) return -1; gIsHFSPlus = 1; gBlockSize = gHFSPlus->blockSize; CacheInit(ih, gBlockSize); gCurrentIH = ih; // Get the Catalog BTree node size. extent = &gHFSPlus->catalogFile.extents; extentSize = gHFSPlus->catalogFile.logicalSize; extentFile = kHFSCatalogFileID; ReadExtent(extent, extentSize, extentFile, 0, 256, gBTreeHeaderBuffer + kBTreeCatalog * 256, 0); nodeSize = ((BTHeaderRec *)(gBTreeHeaderBuffer + kBTreeCatalog * 256 + sizeof(BTNodeDescriptor)))->nodeSize; // If the BTree node size is larger than the block size, reset the cache. if (nodeSize > gBlockSize) CacheInit(ih, nodeSize); return 0; }