#define SHOW_ELAPSED_TIMES 0
#define DEBUG_REBUILD 0
extern void MyIndirectLog(const char *);
#if SHOW_ELAPSED_TIMES
#include <sys/time.h>
#endif
#include "Scavenger.h"
#include "../cache.h"
OSErr CreateNewBTree( SGlobPtr theSGlobPtr, int FileID );
static OSErr DeleteBTree( SGlobPtr theSGlobPtr, SFCB * theFCBPtr );
static OSErr InitializeBTree( BTreeControlBlock * theBTreeCBPtr,
UInt32 * theBytesUsedPtr,
UInt32 * theMapNodeCountPtr );
static OSErr ReleaseExtentsInExtentsBTree( SGlobPtr theSGlobPtr,
SFCB * theFCBPtr );
static OSErr ValidateCatalogRecordLength( SGlobPtr theSGlobPtr,
CatalogRecord * theRecPtr,
UInt32 theRecSize );
static OSErr ValidateAttributeRecordLength (SGlobPtr s, HFSPlusAttrRecord * theRecPtr, UInt32 theRecSize);
static OSErr ValidateExtentRecordLength (SGlobPtr s, ExtentRecord * theRecPtr, UInt32 theRecSize);
static OSErr WriteMapNodes( BTreeControlBlock * theBTreeCBPtr,
UInt32 theFirstMapNode,
UInt32 theNodeCount );
#if DEBUG_REBUILD
static void PrintBTHeaderRec( BTHeaderRec * thePtr );
static void PrintNodeDescriptor( NodeDescPtr thePtr );
static void PrintBTreeKey( KeyPtr thePtr, BTreeControlBlock * theBTreeCBPtr );
static void PrintIndexNodeRec( UInt32 theNodeNum );
static void PrintLeafNodeRec( HFSPlusCatalogFolder * thePtr );
#endif
void SETOFFSET ( void *buffer, UInt16 btNodeSize, SInt16 recOffset, SInt16 vecOffset );
#define SETOFFSET( buf,ndsiz,offset,rec ) \
( *(SInt16 *)((UInt8 *)(buf) + (ndsiz) + (-2 * (rec))) = (offset) )
OSErr RebuildBTree( SGlobPtr theSGlobPtr, int FileID )
{
BlockDescriptor myBlockDescriptor;
BTreeKeyPtr myCurrentKeyPtr;
void * myCurrentDataPtr;
SFCB * myFCBPtr = NULL;
SFCB * oldFCBPtr = NULL;
SVCB * myVCBPtr;
UInt32 myDataSize;
UInt32 myHint;
OSErr myErr;
Boolean isHFSPlus;
UInt32 numRecords = 0;
#if SHOW_ELAPSED_TIMES
struct timeval myStartTime;
struct timeval myEndTime;
struct timeval myElapsedTime;
struct timezone zone;
#endif
theSGlobPtr->TarID = FileID;
theSGlobPtr->TarBlock = 0;
myBlockDescriptor.buffer = NULL;
myVCBPtr = theSGlobPtr->calculatedVCB;
if (kHFSCatalogFileID == FileID) {
oldFCBPtr = theSGlobPtr->calculatedCatalogFCB;
} else if (kHFSAttributesFileID == FileID) {
oldFCBPtr = theSGlobPtr->calculatedAttributesFCB;
} else if (kHFSExtentsFileID == FileID) {
oldFCBPtr = theSGlobPtr->calculatedExtentsFCB;
} else {
abort();
}
myErr = BTScanInitialize( oldFCBPtr, &theSGlobPtr->scanState );
if ( noErr != myErr )
goto ExitThisRoutine;
isHFSPlus = ( myVCBPtr->vcbSignature == kHFSPlusSigWord );
if (!isHFSPlus) {
myErr = noMacDskErr;
goto ExitThisRoutine;
}
myErr = GetVolumeObjectVHBorMDB( &myBlockDescriptor );
if ( noErr != myErr )
goto ExitThisRoutine;
if ( isHFSPlus )
{
HFSPlusVolumeHeader * myVHBPtr;
myVHBPtr = (HFSPlusVolumeHeader *) myBlockDescriptor.buffer;
myVCBPtr->vcbFreeBlocks = myVHBPtr->freeBlocks;
myVCBPtr->vcbFileCount = myVHBPtr->fileCount;
myVCBPtr->vcbFolderCount = myVHBPtr->folderCount;
myVCBPtr->vcbEncodingsBitmap = myVHBPtr->encodingsBitmap;
myVCBPtr->vcbRsrcClumpSize = myVHBPtr->rsrcClumpSize;
myVCBPtr->vcbDataClumpSize = myVHBPtr->dataClumpSize;
myVCBPtr->vcbCreateDate = myVHBPtr->createDate;
myVCBPtr->vcbModifyDate = myVHBPtr->modifyDate;
myVCBPtr->vcbCheckedDate = myVHBPtr->checkedDate;
myVCBPtr->vcbBackupDate = myVHBPtr->backupDate;
myVCBPtr->vcbCatalogFile->fcbClumpSize = myVHBPtr->catalogFile.clumpSize;
myVCBPtr->vcbAttributesFile->fcbClumpSize = myVHBPtr->attributesFile.clumpSize;
myVCBPtr->vcbExtentsFile->fcbClumpSize = myVHBPtr->extentsFile.clumpSize;
myVCBPtr->vcbAttributes = myVHBPtr->attributes;
CopyMemory( myVHBPtr->finderInfo, myVCBPtr->vcbFinderInfo, sizeof(myVCBPtr->vcbFinderInfo) );
}
else
{
HFSMasterDirectoryBlock * myMDBPtr;
myMDBPtr = (HFSMasterDirectoryBlock *) myBlockDescriptor.buffer;
myVCBPtr->vcbFreeBlocks = myMDBPtr->drFreeBks;
myVCBPtr->vcbFileCount = myMDBPtr->drFilCnt;
myVCBPtr->vcbFolderCount = myMDBPtr->drDirCnt;
myVCBPtr->vcbDataClumpSize = myMDBPtr->drClpSiz;
myVCBPtr->vcbCatalogFile->fcbClumpSize = myMDBPtr->drCTClpSiz;
myVCBPtr->vcbNmRtDirs = myMDBPtr->drNmRtDirs;
myVCBPtr->vcbCreateDate = myMDBPtr->drCrDate;
myVCBPtr->vcbModifyDate = myMDBPtr->drLsMod;
if ( (myMDBPtr->drAtrb & VAtrb_Msk) == 0 )
myVCBPtr->vcbAttributes = myMDBPtr->drAtrb;
else
myVCBPtr->vcbAttributes = VAtrb_DFlt;
myVCBPtr->vcbBackupDate = myMDBPtr->drVolBkUp;
myVCBPtr->vcbVSeqNum = myMDBPtr->drVSeqNum;
CopyMemory( myMDBPtr->drFndrInfo, myVCBPtr->vcbFinderInfo, sizeof(myMDBPtr->drFndrInfo) );
}
(void) ReleaseVolumeBlock( myVCBPtr, &myBlockDescriptor, kReleaseBlock );
myBlockDescriptor.buffer = NULL;
if (FileID == kHFSCatalogFileID || FileID == kHFSAttributesFileID || FileID == kHFSExtentsFileID) {
myErr = CreateNewBTree( theSGlobPtr, FileID );
} else {
myErr = EINVAL;
}
if ( noErr != myErr ) {
#if DEBUG_REBUILD
plog("CreateNewBTree returned %d\n", myErr);
#endif
if (myErr == dskFulErr) {
fsckPrint(theSGlobPtr->context, E_DiskFull);
}
goto ExitThisRoutine;
}
myFCBPtr = theSGlobPtr->calculatedRepairFCB;
#if SHOW_ELAPSED_TIMES
gettimeofday( &myStartTime, &zone );
#endif
#if DEBUG_REBUILD
if (debug) {
int i;
HFSPlusExtentDescriptor *te = (HFSPlusExtentDescriptor*)&theSGlobPtr->calculatedRepairFCB->fcbExtents32;
printf("Extent records for rebuilt file %u:\n", FileID);
for (i = 0; i < kHFSPlusExtentDensity; i++) {
printf("\t[ %u, %u ]\n", te[i].startBlock, te[i].blockCount);
}
}
#endif
while ( true )
{
myErr = BTScanNextRecord( &theSGlobPtr->scanState,
(void **) &myCurrentKeyPtr,
(void **) &myCurrentDataPtr,
&myDataSize );
if ( noErr != myErr )
break;
theSGlobPtr->TarBlock = theSGlobPtr->scanState.nodeNum;
if (FileID == kHFSCatalogFileID) {
myErr = ValidateCatalogRecordLength( theSGlobPtr, myCurrentDataPtr, myDataSize );
} else if (FileID == kHFSAttributesFileID) {
myErr = ValidateAttributeRecordLength( theSGlobPtr, myCurrentDataPtr, myDataSize );
} else if (FileID == kHFSExtentsFileID) {
myErr = ValidateExtentRecordLength( theSGlobPtr, myCurrentDataPtr, myDataSize );
}
if ( noErr != myErr )
{
#if DEBUG_REBUILD
{
plog( "%s - Record length validation (file %d) failed! \n", __FUNCTION__, FileID );
plog( "%s - record %d in node %d is not recoverable. \n",
__FUNCTION__, (theSGlobPtr->scanState.recordNum - 1),
theSGlobPtr->scanState.nodeNum );
}
#endif
myErr = R_RFail;
break; }
myErr = InsertBTreeRecord( myFCBPtr, myCurrentKeyPtr,
myCurrentDataPtr, myDataSize, &myHint );
if ( noErr != myErr )
{
#if DEBUG_REBUILD
{
plog( "%s - InsertBTreeRecord failed with err %d 0x%02X \n",
__FUNCTION__, myErr, myErr );
plog( "%s - numRecords = %d\n", __FUNCTION__, numRecords);
plog( "%s - record %d in node %d is not recoverable. \n",
__FUNCTION__, (theSGlobPtr->scanState.recordNum - 1),
theSGlobPtr->scanState.nodeNum );
PrintBTreeKey( myCurrentKeyPtr, theSGlobPtr->calculatedCatalogBTCB );
}
#endif
if (dskFulErr == myErr)
{
fsckPrint(theSGlobPtr->context, E_DiskFull);
}
myErr = R_RFail;
break; }
numRecords++;
#if DEBUG_REBUILD
if (debug && ((numRecords % 1000) == 0) || printEvery)
plog("btree file %d: %u records\n", FileID, numRecords);
#endif
}
#if SHOW_ELAPSED_TIMES
gettimeofday( &myEndTime, &zone );
timersub( &myEndTime, &myStartTime, &myElapsedTime );
plog( "\n%s - rebuild btree %u %u records elapsed time \n", __FUNCTION__, FileID, numRecords );
plog( ">>>>>>>>>>>>> secs %d msecs %d \n\n", myElapsedTime.tv_sec, myElapsedTime.tv_usec );
#endif
if ( btNotFound == myErr )
myErr = noErr;
if ( noErr != myErr )
goto ExitThisRoutine;
myErr = BTFlushPath( myFCBPtr );
if ( noErr != myErr )
goto ExitThisRoutine;
myErr = CacheFlush( myVCBPtr->vcbBlockCache );
if ( noErr != myErr )
goto ExitThisRoutine;
if (FileID == kHFSCatalogFileID) {
theSGlobPtr->calculatedRepairFCB = theSGlobPtr->calculatedCatalogFCB;
theSGlobPtr->calculatedCatalogFCB = myFCBPtr;
myVCBPtr->vcbCatalogFile = myFCBPtr;
theSGlobPtr->calculatedCatalogFCB->fcbFileID = kHFSCatalogFileID;
theSGlobPtr->calculatedRepairBTCB = theSGlobPtr->calculatedCatalogBTCB;
} else if (FileID == kHFSAttributesFileID) {
theSGlobPtr->calculatedRepairFCB = theSGlobPtr->calculatedAttributesFCB;
theSGlobPtr->calculatedAttributesFCB = myFCBPtr;
myVCBPtr->vcbAttributesFile = myFCBPtr;
theSGlobPtr->calculatedAttributesFCB->fcbFileID = kHFSAttributesFileID;
theSGlobPtr->calculatedRepairBTCB = theSGlobPtr->calculatedAttributesBTCB;
} else if (FileID == kHFSExtentsFileID) {
theSGlobPtr->calculatedRepairFCB = theSGlobPtr->calculatedExtentsFCB;
theSGlobPtr->calculatedExtentsFCB = myFCBPtr;
myVCBPtr->vcbExtentsFile = myFCBPtr;
theSGlobPtr->calculatedExtentsFCB->fcbFileID = kHFSExtentsFileID;
theSGlobPtr->calculatedRepairBTCB = theSGlobPtr->calculatedExtentsBTCB;
}
MarkVCBDirty( myVCBPtr );
myErr = FlushAlternateVolumeControlBlock( myVCBPtr, isHFSPlus );
if ( noErr != myErr )
{
if (FileID == kHFSCatalogFileID) {
theSGlobPtr->calculatedCatalogFCB = theSGlobPtr->calculatedRepairFCB;
theSGlobPtr->calculatedRepairFCB = myFCBPtr;
myVCBPtr->vcbCatalogFile = theSGlobPtr->calculatedCatalogFCB;
} else if (FileID == kHFSAttributesFileID) {
theSGlobPtr->calculatedAttributesFCB = theSGlobPtr->calculatedRepairFCB;
theSGlobPtr->calculatedRepairFCB = myFCBPtr;
myVCBPtr->vcbAttributesFile = theSGlobPtr->calculatedAttributesFCB;
} else if (FileID == kHFSExtentsFileID) {
theSGlobPtr->calculatedExtentsFCB = theSGlobPtr->calculatedRepairFCB;
theSGlobPtr->calculatedRepairFCB = myFCBPtr;
myVCBPtr->vcbExtentsFile = theSGlobPtr->calculatedExtentsFCB;
}
MarkVCBDirty( myVCBPtr );
(void) FlushAlternateVolumeControlBlock( myVCBPtr, isHFSPlus );
goto ExitThisRoutine;
}
(void) DeleteBTree( theSGlobPtr, theSGlobPtr->calculatedRepairFCB );
if (FileID == kHFSExtentsFileID)
(void)FlushExtentFile(myVCBPtr);
ExitThisRoutine:
if ( myBlockDescriptor.buffer != NULL )
(void) ReleaseVolumeBlock( myVCBPtr, &myBlockDescriptor, kReleaseBlock );
if ( myErr != noErr && myFCBPtr != NULL )
(void) DeleteBTree( theSGlobPtr, myFCBPtr );
BTScanTerminate( &theSGlobPtr->scanState );
return( myErr );
}
OSErr CreateNewBTree( SGlobPtr theSGlobPtr, int FileID )
{
OSErr myErr;
BTreeControlBlock * myBTreeCBPtr, * oldBCBPtr;
SVCB * myVCBPtr;
SFCB * myFCBPtr, * oldFCBPtr;
UInt32 myBytesUsed = 0;
UInt32 myMapNodeCount;
UInt64 myNumBlocks;
FSSize myNewEOF;
BTHeaderRec myHeaderRec;
myBTreeCBPtr = theSGlobPtr->calculatedRepairBTCB;
myFCBPtr = theSGlobPtr->calculatedRepairFCB;
ClearMemory( (Ptr) myFCBPtr, sizeof( *myFCBPtr ) );
ClearMemory( (Ptr) myBTreeCBPtr, sizeof( *myBTreeCBPtr ) );
if (FileID == kHFSCatalogFileID) {
oldFCBPtr = theSGlobPtr->calculatedCatalogFCB;
oldBCBPtr = theSGlobPtr->calculatedCatalogBTCB;
} else if (FileID == kHFSAttributesFileID) {
oldFCBPtr = theSGlobPtr->calculatedAttributesFCB;
oldBCBPtr = theSGlobPtr->calculatedAttributesBTCB;
} else if (FileID == kHFSExtentsFileID) {
oldFCBPtr = theSGlobPtr->calculatedExtentsFCB;
oldBCBPtr = theSGlobPtr->calculatedExtentsBTCB;
} else
abort();
myVCBPtr = oldFCBPtr->fcbVolume;
if (FileID == kHFSCatalogFileID)
myFCBPtr->fcbFileID = kHFSCatalogFileID;
else if (FileID == kHFSAttributesFileID)
myFCBPtr->fcbFileID = kHFSAttributesFileID;
else if (FileID == kHFSExtentsFileID)
myFCBPtr->fcbFileID = kHFSExtentsFileID;
myFCBPtr->fcbVolume = myVCBPtr;
myFCBPtr->fcbBtree = myBTreeCBPtr;
myFCBPtr->fcbBlockSize = oldBCBPtr->nodeSize;
myBTreeCBPtr->fcbPtr = myFCBPtr;
myBTreeCBPtr->btreeType = kHFSBTreeType;
myBTreeCBPtr->keyCompareType = oldBCBPtr->keyCompareType;
myBTreeCBPtr->keyCompareProc = oldBCBPtr->keyCompareProc;
myBTreeCBPtr->nodeSize = oldBCBPtr->nodeSize;
myBTreeCBPtr->maxKeyLength = oldBCBPtr->maxKeyLength;
if (myVCBPtr->vcbSignature == kHFSPlusSigWord) {
if (FileID == kHFSExtentsFileID)
myBTreeCBPtr->attributes = kBTBigKeysMask;
else
myBTreeCBPtr->attributes = ( kBTBigKeysMask + kBTVariableIndexKeysMask );
}
myBTreeCBPtr->getBlockProc = GetFileBlock;
myBTreeCBPtr->releaseBlockProc = ReleaseFileBlock;
myBTreeCBPtr->setEndOfForkProc = SetEndOfForkProc;
myNewEOF = oldFCBPtr->fcbPhysicalSize;
myNumBlocks = myNewEOF / myVCBPtr->vcbBlockSize;
myErr = BlockFindAll( myBTreeCBPtr->fcbPtr, myNumBlocks);
ReturnIfError( myErr );
myBTreeCBPtr->fcbPtr->fcbPhysicalSize = myNewEOF;
myErr = ZeroFileBlocks( myVCBPtr, myBTreeCBPtr->fcbPtr, 0, myNewEOF >> kSectorShift );
ReturnIfError( myErr );
myFCBPtr->fcbLogicalSize = myFCBPtr->fcbPhysicalSize; if (FileID == kHFSCatalogFileID)
myFCBPtr->fcbClumpSize = myVCBPtr->vcbCatalogFile->fcbClumpSize;
else if (FileID == kHFSAttributesFileID)
myFCBPtr->fcbClumpSize = myVCBPtr->vcbAttributesFile->fcbClumpSize;
else if (FileID == kHFSExtentsFileID)
myFCBPtr->fcbClumpSize = myVCBPtr->vcbExtentsFile->fcbClumpSize;
myBTreeCBPtr->totalNodes = ( myFCBPtr->fcbPhysicalSize / myBTreeCBPtr->nodeSize );
myBTreeCBPtr->freeNodes = myBTreeCBPtr->totalNodes;
myErr = InitializeBTree( myBTreeCBPtr, &myBytesUsed, &myMapNodeCount );
ReturnIfError( myErr );
myErr = GetBTreeHeader( theSGlobPtr, myFCBPtr, &myHeaderRec );
ReturnIfError( myErr );
myBTreeCBPtr->treeDepth = myHeaderRec.treeDepth;
myBTreeCBPtr->rootNode = myHeaderRec.rootNode;
myBTreeCBPtr->leafRecords = myHeaderRec.leafRecords;
myBTreeCBPtr->firstLeafNode = myHeaderRec.firstLeafNode;
myBTreeCBPtr->lastLeafNode = myHeaderRec.lastLeafNode;
myBTreeCBPtr->totalNodes = myHeaderRec.totalNodes;
myBTreeCBPtr->freeNodes = myHeaderRec.freeNodes;
myBTreeCBPtr->maxKeyLength = myHeaderRec.maxKeyLength;
if ( myMapNodeCount > 0 )
{
myErr = WriteMapNodes( myBTreeCBPtr, (myBytesUsed / myBTreeCBPtr->nodeSize ), myMapNodeCount );
ReturnIfError( myErr );
}
return( myErr );
}
static OSErr InitializeBTree( BTreeControlBlock * theBTreeCBPtr,
UInt32 * theBytesUsedPtr,
UInt32 * theMapNodeCountPtr )
{
OSErr myErr;
BlockDescriptor myNode;
Boolean isHFSPlus = false;
SVCB * myVCBPtr;
BTNodeDescriptor * myNodeDescPtr;
BTHeaderRec * myHeaderRecPtr;
UInt8 * myBufferPtr;
UInt8 * myBitMapPtr;
UInt32 myNodeBitsInHeader;
UInt32 temp;
SInt16 myOffset;
myVCBPtr = theBTreeCBPtr->fcbPtr->fcbVolume;
isHFSPlus = ( myVCBPtr->vcbSignature == kHFSPlusSigWord) ;
*theMapNodeCountPtr = 0;
myErr = GetNewNode( theBTreeCBPtr, kHeaderNodeNum, &myNode );
ReturnIfError( myErr );
myBufferPtr = (UInt8 *) myNode.buffer;
myNodeDescPtr = (BTNodeDescriptor *) myBufferPtr;
myNodeDescPtr->kind = kBTHeaderNode;
myNodeDescPtr->numRecords = 3;
myOffset = sizeof( BTNodeDescriptor );
SETOFFSET( myBufferPtr, theBTreeCBPtr->nodeSize, myOffset, 1 );
myHeaderRecPtr = (BTHeaderRec *)((UInt8 *)myBufferPtr + myOffset);
myHeaderRecPtr->treeDepth = 0;
myHeaderRecPtr->rootNode = 0;
myHeaderRecPtr->firstLeafNode = 0;
myHeaderRecPtr->lastLeafNode = 0;
myHeaderRecPtr->nodeSize = theBTreeCBPtr->nodeSize;
myHeaderRecPtr->totalNodes = theBTreeCBPtr->totalNodes;
myHeaderRecPtr->freeNodes = myHeaderRecPtr->totalNodes - 1;
myHeaderRecPtr->clumpSize = theBTreeCBPtr->fcbPtr->fcbClumpSize;
myHeaderRecPtr->attributes = theBTreeCBPtr->attributes;
myHeaderRecPtr->maxKeyLength = theBTreeCBPtr->maxKeyLength;
myHeaderRecPtr->keyCompareType = theBTreeCBPtr->keyCompareType;
myOffset += sizeof( BTHeaderRec );
SETOFFSET( myBufferPtr, theBTreeCBPtr->nodeSize, myOffset, 2 );
myOffset += kBTreeHeaderUserBytes;
SETOFFSET( myBufferPtr, theBTreeCBPtr->nodeSize, myOffset, 3 );
myNodeBitsInHeader = 8 * (theBTreeCBPtr->nodeSize
- sizeof(BTNodeDescriptor)
- sizeof(BTHeaderRec)
- kBTreeHeaderUserBytes
- (4 * sizeof(SInt16)) );
if ( myHeaderRecPtr->totalNodes > myNodeBitsInHeader )
{
UInt32 nodeBitsInMapNode;
myNodeDescPtr->fLink = myHeaderRecPtr->lastLeafNode + 1;
nodeBitsInMapNode = 8 * (theBTreeCBPtr->nodeSize
- sizeof(BTNodeDescriptor)
- (2 * sizeof(SInt16))
- 2 );
*theMapNodeCountPtr = (myHeaderRecPtr->totalNodes - myNodeBitsInHeader +
(nodeBitsInMapNode - 1)) / nodeBitsInMapNode;
myHeaderRecPtr->freeNodes = myHeaderRecPtr->freeNodes - *theMapNodeCountPtr;
}
myBitMapPtr = ((UInt8 *)myBufferPtr + myOffset);
temp = myHeaderRecPtr->totalNodes - myHeaderRecPtr->freeNodes;
while ( temp >= 8 )
{
*myBitMapPtr = 0xFF;
temp -= 8;
myBitMapPtr++;
}
*myBitMapPtr = ~(0xFF >> temp);
myOffset += myNodeBitsInHeader / 8;
SETOFFSET( myBufferPtr, theBTreeCBPtr->nodeSize, myOffset, 4 );
*theBytesUsedPtr =
( myHeaderRecPtr->totalNodes - myHeaderRecPtr->freeNodes - *theMapNodeCountPtr )
* theBTreeCBPtr->nodeSize;
myErr = UpdateNode( theBTreeCBPtr, &myNode );
M_ExitOnError( myErr );
return noErr;
ErrorExit:
(void) ReleaseNode( theBTreeCBPtr, &myNode );
return( myErr );
}
static OSErr WriteMapNodes( BTreeControlBlock * theBTreeCBPtr,
UInt32 theFirstMapNode,
UInt32 theNodeCount )
{
OSErr myErr;
UInt16 i;
UInt32 mapRecordBytes;
BTNodeDescriptor * myNodeDescPtr;
BlockDescriptor myNode;
myNode.buffer = NULL;
for ( i = 0; i < theNodeCount; i++ )
{
myErr = GetNewNode( theBTreeCBPtr, theFirstMapNode, &myNode );
M_ExitOnError( myErr );
myNodeDescPtr = (BTNodeDescriptor *) myNode.buffer;
myNodeDescPtr->kind = kBTMapNode;
myNodeDescPtr->numRecords = 1;
mapRecordBytes = theBTreeCBPtr->nodeSize - sizeof(BTNodeDescriptor) - 2 * sizeof(SInt16) - 2;
SETOFFSET( myNodeDescPtr, theBTreeCBPtr->nodeSize, sizeof(BTNodeDescriptor), 1 );
SETOFFSET( myNodeDescPtr, theBTreeCBPtr->nodeSize, sizeof(BTNodeDescriptor) + mapRecordBytes, 2) ;
if ( (i + 1) < theNodeCount )
myNodeDescPtr->fLink = ++theFirstMapNode;
else
myNodeDescPtr->fLink = 0;
myErr = UpdateNode( theBTreeCBPtr, &myNode );
M_ExitOnError( myErr );
}
return noErr;
ErrorExit:
(void) ReleaseNode( theBTreeCBPtr, &myNode );
return( myErr );
}
enum
{
kDataForkType = 0,
kResourceForkType = 0xFF
};
static OSErr DeleteBTree( SGlobPtr theSGlobPtr, SFCB * theFCBPtr )
{
OSErr myErr;
SVCB * myVCBPtr;
int i;
Boolean isHFSPlus;
Boolean checkExtentsBTree = true;
myVCBPtr = theFCBPtr->fcbVolume;
isHFSPlus = ( myVCBPtr->vcbSignature == kHFSPlusSigWord) ;
if ( isHFSPlus )
{
for ( i = 0; i < kHFSPlusExtentDensity; ++i )
{
if ( theFCBPtr->fcbExtents32[ i ].blockCount == 0 )
{
checkExtentsBTree = false;
break;
}
(void) BlockDeallocate( myVCBPtr,
theFCBPtr->fcbExtents32[ i ].startBlock,
theFCBPtr->fcbExtents32[ i ].blockCount );
theFCBPtr->fcbExtents32[ i ].startBlock = 0;
theFCBPtr->fcbExtents32[ i ].blockCount = 0;
}
}
else
{
for ( i = 0; i < kHFSExtentDensity; ++i )
{
if ( theFCBPtr->fcbExtents16[ i ].blockCount == 0 )
{
checkExtentsBTree = false;
break;
}
(void) BlockDeallocate( myVCBPtr,
theFCBPtr->fcbExtents16[ i ].startBlock,
theFCBPtr->fcbExtents16[ i ].blockCount );
theFCBPtr->fcbExtents16[ i ].startBlock = 0;
theFCBPtr->fcbExtents16[ i ].blockCount = 0;
}
}
if ( checkExtentsBTree )
{
(void) ReleaseExtentsInExtentsBTree( theSGlobPtr, theFCBPtr );
(void) FlushExtentFile( myVCBPtr );
}
(void) MarkVCBDirty( myVCBPtr );
(void) FlushAlternateVolumeControlBlock( myVCBPtr, isHFSPlus );
myErr = noErr;
return( myErr );
}
static OSErr ReleaseExtentsInExtentsBTree( SGlobPtr theSGlobPtr,
SFCB * theFCBPtr )
{
BTreeIterator myIterator;
ExtentRecord myExtentRecord;
FSBufferDescriptor myBTRec;
ExtentKey * myKeyPtr;
SVCB * myVCBPtr;
UInt16 myRecLen;
UInt16 i;
OSErr myErr;
Boolean isHFSPlus;
myVCBPtr = theFCBPtr->fcbVolume;
isHFSPlus = ( myVCBPtr->vcbSignature == kHFSPlusSigWord );
ClearMemory( &myIterator, sizeof(myIterator) );
myBTRec.bufferAddress = &myExtentRecord;
myBTRec.itemCount = 1;
myBTRec.itemSize = sizeof(myExtentRecord);
myKeyPtr = (ExtentKey *) &myIterator.key;
BuildExtentKey( isHFSPlus, kDataForkType, theFCBPtr->fcbFileID,
0, (void *) myKeyPtr );
for ( ;; )
{
myErr = BTIterateRecord( theSGlobPtr->calculatedExtentsFCB,
kBTreeNextRecord, &myIterator,
&myBTRec, &myRecLen );
if ( noErr != myErr )
{
myErr = noErr;
break;
}
if ( isHFSPlus )
{
if ( myKeyPtr->hfsPlus.fileID != theFCBPtr->fcbFileID ||
myKeyPtr->hfsPlus.forkType != kDataForkType )
break;
for ( i = 0; i < kHFSPlusExtentDensity; ++i )
{
if ( myExtentRecord.hfsPlus[ i ].blockCount == 0 )
break;
(void) BlockDeallocate( myVCBPtr,
myExtentRecord.hfsPlus[ i ].startBlock,
myExtentRecord.hfsPlus[ i ].blockCount );
}
}
else
{
if ( myKeyPtr->hfs.fileID != theFCBPtr->fcbFileID ||
myKeyPtr->hfs.forkType != kDataForkType )
break;
for ( i = 0; i < kHFSExtentDensity; ++i )
{
if ( myExtentRecord.hfs[ i ].blockCount == 0 )
break;
(void) BlockDeallocate( myVCBPtr,
myExtentRecord.hfs[ i ].startBlock,
myExtentRecord.hfs[ i ].blockCount );
}
}
myErr = DeleteBTreeRecord( theSGlobPtr->calculatedExtentsFCB, myKeyPtr );
}
return( myErr );
}
static OSErr ValidateExtentRecordLength (SGlobPtr s, ExtentRecord * theRecPtr, UInt32 theRecSize)
{
Boolean isHFSPlus = ( s->calculatedVCB->vcbSignature == kHFSPlusSigWord );
if (isHFSPlus) {
if (theRecSize != sizeof(HFSPlusExtentRecord))
return -1;
} else {
if (theRecSize != sizeof(HFSExtentRecord))
return -1;
}
return noErr;
}
static OSErr ValidateAttributeRecordLength (SGlobPtr s, HFSPlusAttrRecord * theRecPtr, UInt32 theRecSize)
{
OSErr retval = noErr;
static UInt32 maxInlineSize;
if (maxInlineSize == 0) {
maxInlineSize = s->calculatedAttributesBTCB->nodeSize;
maxInlineSize -= sizeof(BTNodeDescriptor); maxInlineSize -= 3 * sizeof(u_int16_t); maxInlineSize /= 2; maxInlineSize -= sizeof(HFSPlusAttrKey); maxInlineSize &= 0xFFFFFFFE; }
switch (theRecPtr->recordType) {
case kHFSPlusAttrInlineData:
if (theRecSize > maxInlineSize) {
if (debug)
plog("Inline Attribute size %u is larger than maxsize %u\n", theRecSize, maxInlineSize);
retval = -1;
}
break;
case kHFSPlusAttrForkData:
if (theRecSize != sizeof(HFSPlusAttrForkData)) {
if (debug)
plog("Fork Data attribute size %u is larger then HFSPlusAttrForkData size %u\n", theRecSize, sizeof(HFSPlusAttrForkData));
retval = -1;
}
break;
case kHFSPlusAttrExtents:
if (theRecSize != sizeof(HFSPlusAttrExtents)) {
if (debug)
plog("Extents Data attribute size %u is larger than HFSPlusAttrExtents size %u\n", theRecSize, sizeof(HFSPlusAttrExtents));
retval = -1;
}
break;
default:
if (debug)
plog("Unknown attribute type %u\n", theRecPtr->recordType);
retval = -1;
break;
}
return retval;
}
static OSErr ValidateCatalogRecordLength( SGlobPtr theSGlobPtr,
CatalogRecord * theRecPtr,
UInt32 theRecSize )
{
SVCB * myVCBPtr;
Boolean isHFSPlus = false;
myVCBPtr = theSGlobPtr->calculatedVCB;
isHFSPlus = ( myVCBPtr->vcbSignature == kHFSPlusSigWord );
if ( isHFSPlus )
{
switch ( theRecPtr->recordType )
{
case kHFSPlusFolderRecord:
if ( theRecSize != sizeof( HFSPlusCatalogFolder ) )
{
return( -1 );
}
break;
case kHFSPlusFileRecord:
if ( theRecSize != sizeof(HFSPlusCatalogFile) )
{
return( -1 );
}
break;
case kHFSPlusFolderThreadRecord:
case kHFSPlusFileThreadRecord:
if ( theRecSize > sizeof(HFSPlusCatalogThread) ||
theRecSize < sizeof(HFSPlusCatalogThread) - sizeof(HFSUniStr255) + sizeof(UniChar) )
{
return( -1 );
}
break;
default:
return( -1 );
}
}
else
{
switch ( theRecPtr->recordType )
{
case kHFSFolderRecord:
if ( theRecSize != sizeof(HFSCatalogFolder) )
return( -1 );
break;
case kHFSFileRecord:
if ( theRecSize != sizeof(HFSCatalogFile) )
return( -1 );
break;
case kHFSFolderThreadRecord:
case kHFSFileThreadRecord:
if ( theRecSize != sizeof(HFSCatalogThread))
return( -1 );
break;
default:
return( -1 );
}
}
return( noErr );
}
#if DEBUG_REBUILD
static void PrintNodeDescriptor( NodeDescPtr thePtr )
{
plog( "\n xxxxxxxx BTNodeDescriptor xxxxxxxx \n" );
plog( " fLink %d \n", thePtr->fLink );
plog( " bLink %d \n", thePtr->bLink );
plog( " kind %d ", thePtr->kind );
if ( thePtr->kind == kBTLeafNode )
plog( "%s \n", "kBTLeafNode" );
else if ( thePtr->kind == kBTIndexNode )
plog( "%s \n", "kBTIndexNode" );
else if ( thePtr->kind == kBTHeaderNode )
plog( "%s \n", "kBTHeaderNode" );
else if ( thePtr->kind == kBTMapNode )
plog( "%s \n", "kBTMapNode" );
else
plog( "do not know?? \n" );
plog( " height %d \n", thePtr->height );
plog( " numRecords %d \n", thePtr->numRecords );
}
static void PrintBTHeaderRec( BTHeaderRec * thePtr )
{
plog( "\n xxxxxxxx BTHeaderRec xxxxxxxx \n" );
plog( " treeDepth %d \n", thePtr->treeDepth );
plog( " rootNode %d \n", thePtr->rootNode );
plog( " leafRecords %d \n", thePtr->leafRecords );
plog( " firstLeafNode %d \n", thePtr->firstLeafNode );
plog( " lastLeafNode %d \n", thePtr->lastLeafNode );
plog( " nodeSize %d \n", thePtr->nodeSize );
plog( " maxKeyLength %d \n", thePtr->maxKeyLength );
plog( " totalNodes %d \n", thePtr->totalNodes );
plog( " freeNodes %d \n", thePtr->freeNodes );
plog( " clumpSize %d \n", thePtr->clumpSize );
plog( " btreeType 0x%02X \n", thePtr->btreeType );
plog( " attributes 0x%02X \n", thePtr->attributes );
}
static void PrintBTreeKey( KeyPtr thePtr, BTreeControlBlock * theBTreeCBPtr )
{
int myKeyLength, i;
UInt8 * myPtr = (UInt8 *)thePtr;
myKeyLength = CalcKeySize( theBTreeCBPtr, thePtr) ;
plog( "\n xxxxxxxx BTreeKey xxxxxxxx \n" );
plog( " length %d \n", myKeyLength );
for ( i = 0; i < myKeyLength; i++ )
plog( "%02X", *(myPtr + i) );
plog( "\n" );
}
static void PrintIndexNodeRec( UInt32 theNodeNum )
{
plog( "\n xxxxxxxx IndexNodeRec xxxxxxxx \n" );
plog( " node number %d \n", theNodeNum );
}
static void PrintLeafNodeRec( HFSPlusCatalogFolder * thePtr )
{
plog( "\n xxxxxxxx LeafNodeRec xxxxxxxx \n" );
plog( " recordType %d ", thePtr->recordType );
if ( thePtr->recordType == kHFSPlusFolderRecord )
plog( "%s \n", "kHFSPlusFolderRecord" );
else if ( thePtr->recordType == kHFSPlusFileRecord )
plog( "%s \n", "kHFSPlusFileRecord" );
else if ( thePtr->recordType == kHFSPlusFolderThreadRecord )
plog( "%s \n", "kHFSPlusFolderThreadRecord" );
else if ( thePtr->recordType == kHFSPlusFileThreadRecord )
plog( "%s \n", "kHFSPlusFileThreadRecord" );
else
plog( "do not know?? \n" );
}
#endif // DEBUG_REBUILD