SRebuildCatalogBTree.c [plain text]
#define SHOW_ELAPSED_TIMES 0
#define DEBUG_REBUILD 0
#if SHOW_ELAPSED_TIMES
#include <sys/time.h>
#endif
#include "Scavenger.h"
#include "../cache.h"
static OSErr CreateNewCatalogBTree( SGlobPtr theSGlobPtr );
static OSErr DeleteCatalogBTree( SGlobPtr theSGlobPtr, SFCB * theFCBPtr );
static OSErr InitializeBTree( BTreeControlBlock * theBTreeCBPtr,
UInt32 * theBytesUsedPtr,
UInt32 * theMapNodeCountPtr );
static OSErr ReleaseExtentsInExtentsBTree( SGlobPtr theSGlobPtr,
SFCB * theFCBPtr );
static OSErr ValidateRecordLength( SGlobPtr theSGlobPtr,
CatalogRecord * 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 RebuildCatalogBTree( SGlobPtr theSGlobPtr )
{
BlockDescriptor myBlockDescriptor;
BTreeKeyPtr myCurrentKeyPtr;
CatalogRecord * myCurrentDataPtr;
SFCB * myFCBPtr = NULL;
SVCB * myVCBPtr;
UInt32 myDataSize;
UInt32 myHint;
OSErr myErr;
Boolean isHFSPlus;
#if SHOW_ELAPSED_TIMES
struct timeval myStartTime;
struct timeval myEndTime;
struct timeval myElapsedTime;
struct timezone zone;
#endif
theSGlobPtr->TarID = kHFSCatalogFileID;
theSGlobPtr->TarBlock = 0;
myBlockDescriptor.buffer = NULL;
myVCBPtr = theSGlobPtr->calculatedVCB;
myErr = BTScanInitialize( theSGlobPtr->calculatedCatalogFCB,
&theSGlobPtr->scanState );
if ( noErr != myErr )
goto ExitThisRoutine;
isHFSPlus = ( myVCBPtr->vcbSignature == kHFSPlusSigWord );
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->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;
myErr = CreateNewCatalogBTree( theSGlobPtr );
if ( noErr != myErr )
goto ExitThisRoutine;
myFCBPtr = theSGlobPtr->calculatedRepairFCB;
#if SHOW_ELAPSED_TIMES
gettimeofday( &myStartTime, &zone );
#endif
while ( true )
{
myErr = BTScanNextRecord( &theSGlobPtr->scanState,
(void **) &myCurrentKeyPtr,
(void **) &myCurrentDataPtr,
&myDataSize );
if ( noErr != myErr )
break;
theSGlobPtr->TarBlock = theSGlobPtr->scanState.nodeNum;
myErr = ValidateRecordLength( theSGlobPtr, myCurrentDataPtr, myDataSize );
if ( noErr != myErr )
{
#if DEBUG_REBUILD
{
printf( "%s - ValidateRecordLength failed! \n", __FUNCTION__ );
printf( "%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
{
printf( "%s - InsertBTreeRecord failed with err %d 0x%02X \n",
__FUNCTION__, myErr, myErr );
printf( "%s - record %d in node %d is not recoverable. \n",
__FUNCTION__, (theSGlobPtr->scanState.recordNum - 1),
theSGlobPtr->scanState.nodeNum );
PrintBTreeKey( myCurrentKeyPtr, theSGlobPtr->calculatedCatalogBTCB );
}
#endif
myErr = R_RFail;
break; }
}
#if SHOW_ELAPSED_TIMES
gettimeofday( &myEndTime, &zone );
timersub( &myEndTime, &myStartTime, &myElapsedTime );
printf( "\n%s - rebuild catalog elapsed time \n", __FUNCTION__ );
printf( ">>>>>>>>>>>>> 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;
theSGlobPtr->calculatedRepairFCB = theSGlobPtr->calculatedCatalogFCB;
theSGlobPtr->calculatedCatalogFCB = myFCBPtr;
myVCBPtr->vcbCatalogFile = myFCBPtr;
MarkVCBDirty( myVCBPtr );
myErr = FlushAlternateVolumeControlBlock( myVCBPtr, isHFSPlus );
if ( noErr != myErr )
{
theSGlobPtr->calculatedCatalogFCB = theSGlobPtr->calculatedRepairFCB;
theSGlobPtr->calculatedRepairFCB = myFCBPtr;
myVCBPtr->vcbCatalogFile = theSGlobPtr->calculatedCatalogFCB;
MarkVCBDirty( myVCBPtr );
(void) FlushAlternateVolumeControlBlock( myVCBPtr, isHFSPlus );
goto ExitThisRoutine;
}
(void) DeleteCatalogBTree( theSGlobPtr, theSGlobPtr->calculatedRepairFCB );
ExitThisRoutine:
if ( myBlockDescriptor.buffer != NULL )
(void) ReleaseVolumeBlock( myVCBPtr, &myBlockDescriptor, kReleaseBlock );
if ( myErr != noErr && myFCBPtr != NULL )
(void) DeleteCatalogBTree( theSGlobPtr, myFCBPtr );
BTScanTerminate( &theSGlobPtr->scanState );
return( myErr );
}
static OSErr CreateNewCatalogBTree( SGlobPtr theSGlobPtr )
{
OSErr myErr;
BTreeControlBlock * myBTreeCBPtr;
SVCB * myVCBPtr;
SFCB * myFCBPtr;
UInt32 myBytesUsed = 0;
UInt32 myMapNodeCount;
FSSize myNewEOF;
BTHeaderRec myHeaderRec;
myBTreeCBPtr = theSGlobPtr->calculatedRepairBTCB;
myFCBPtr = theSGlobPtr->calculatedRepairFCB;
ClearMemory( (Ptr) myFCBPtr, sizeof( *myFCBPtr ) );
ClearMemory( (Ptr) myBTreeCBPtr, sizeof( *myBTreeCBPtr ) );
myVCBPtr = theSGlobPtr->calculatedCatalogFCB->fcbVolume;
myFCBPtr->fcbFileID = kHFSRepairCatalogFileID;
myFCBPtr->fcbVolume = myVCBPtr;
myFCBPtr->fcbBtree = myBTreeCBPtr;
myFCBPtr->fcbBlockSize = theSGlobPtr->calculatedCatalogBTCB->nodeSize;
myBTreeCBPtr->fcbPtr = myFCBPtr;
myBTreeCBPtr->btreeType = kHFSBTreeType;
myBTreeCBPtr->keyCompareType = theSGlobPtr->calculatedCatalogBTCB->keyCompareType;
myBTreeCBPtr->keyCompareProc = theSGlobPtr->calculatedCatalogBTCB->keyCompareProc;
myBTreeCBPtr->nodeSize = theSGlobPtr->calculatedCatalogBTCB->nodeSize;
myBTreeCBPtr->maxKeyLength = theSGlobPtr->calculatedCatalogBTCB->maxKeyLength;
if ( myVCBPtr->vcbSignature == kHFSPlusSigWord )
myBTreeCBPtr->attributes |= ( kBTBigKeysMask + kBTVariableIndexKeysMask );
myBTreeCBPtr->getBlockProc = GetFileBlock;
myBTreeCBPtr->releaseBlockProc = ReleaseFileBlock;
myBTreeCBPtr->setEndOfForkProc = SetEndOfForkProc;
myNewEOF = theSGlobPtr->calculatedCatalogFCB->fcbPhysicalSize;
myErr = myBTreeCBPtr->setEndOfForkProc( myBTreeCBPtr->fcbPtr, myNewEOF, 0 );
ReturnIfError( myErr );
myFCBPtr->fcbLogicalSize = myFCBPtr->fcbPhysicalSize; myFCBPtr->fcbClumpSize = myVCBPtr->vcbCatalogFile->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 = 1;
myHeaderRecPtr->rootNode = 1;
myHeaderRecPtr->firstLeafNode = 1;
myHeaderRecPtr->lastLeafNode = 1;
myHeaderRecPtr->nodeSize = theBTreeCBPtr->nodeSize;
myHeaderRecPtr->totalNodes = theBTreeCBPtr->totalNodes;
myHeaderRecPtr->freeNodes = myHeaderRecPtr->totalNodes - 2;
myHeaderRecPtr->clumpSize = theBTreeCBPtr->fcbPtr->fcbClumpSize;
if ( isHFSPlus )
{
myHeaderRecPtr->attributes |= (kBTVariableIndexKeysMask + kBTBigKeysMask);
myHeaderRecPtr->maxKeyLength = kHFSPlusCatalogKeyMaximumLength;
myHeaderRecPtr->keyCompareType = theBTreeCBPtr->keyCompareType;
}
else
myHeaderRecPtr->maxKeyLength = kHFSCatalogKeyMaximumLength;
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 );
myErr = GetNewNode( theBTreeCBPtr, kHeaderNodeNum + 1, &myNode );
ReturnIfError( myErr );
myBufferPtr = (UInt8 *) myNode.buffer;
myNodeDescPtr = (BTNodeDescriptor *) myBufferPtr;
myNodeDescPtr->kind = kBTLeafNode;
myNodeDescPtr->height = 1;
myNodeDescPtr->numRecords = 0;
myOffset = sizeof( BTNodeDescriptor );
SETOFFSET( myBufferPtr, theBTreeCBPtr->nodeSize, myOffset, 1 );
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 DeleteCatalogBTree( 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 ValidateRecordLength( 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 )
{
printf( "\n xxxxxxxx BTNodeDescriptor xxxxxxxx \n" );
printf( " fLink %d \n", thePtr->fLink );
printf( " bLink %d \n", thePtr->bLink );
printf( " kind %d ", thePtr->kind );
if ( thePtr->kind == kBTLeafNode )
printf( "%s \n", "kBTLeafNode" );
else if ( thePtr->kind == kBTIndexNode )
printf( "%s \n", "kBTIndexNode" );
else if ( thePtr->kind == kBTHeaderNode )
printf( "%s \n", "kBTHeaderNode" );
else if ( thePtr->kind == kBTMapNode )
printf( "%s \n", "kBTMapNode" );
else
printf( "do not know?? \n" );
printf( " height %d \n", thePtr->height );
printf( " numRecords %d \n", thePtr->numRecords );
}
static void PrintBTHeaderRec( BTHeaderRec * thePtr )
{
printf( "\n xxxxxxxx BTHeaderRec xxxxxxxx \n" );
printf( " treeDepth %d \n", thePtr->treeDepth );
printf( " rootNode %d \n", thePtr->rootNode );
printf( " leafRecords %d \n", thePtr->leafRecords );
printf( " firstLeafNode %d \n", thePtr->firstLeafNode );
printf( " lastLeafNode %d \n", thePtr->lastLeafNode );
printf( " nodeSize %d \n", thePtr->nodeSize );
printf( " maxKeyLength %d \n", thePtr->maxKeyLength );
printf( " totalNodes %d \n", thePtr->totalNodes );
printf( " freeNodes %d \n", thePtr->freeNodes );
printf( " clumpSize %d \n", thePtr->clumpSize );
printf( " btreeType 0x%02X \n", thePtr->btreeType );
printf( " attributes 0x%02X \n", thePtr->attributes );
}
static void PrintBTreeKey( KeyPtr thePtr, BTreeControlBlock * theBTreeCBPtr )
{
int myKeyLength, i;
UInt8 * myPtr = (UInt8 *)thePtr;
myKeyLength = CalcKeySize( theBTreeCBPtr, thePtr) ;
printf( "\n xxxxxxxx BTreeKey xxxxxxxx \n" );
printf( " length %d \n", myKeyLength );
for ( i = 0; i < myKeyLength; i++ )
printf( "%02X", *(myPtr + i) );
printf( "\n" );
}
static void PrintIndexNodeRec( UInt32 theNodeNum )
{
printf( "\n xxxxxxxx IndexNodeRec xxxxxxxx \n" );
printf( " node number %d \n", theNodeNum );
}
static void PrintLeafNodeRec( HFSPlusCatalogFolder * thePtr )
{
printf( "\n xxxxxxxx LeafNodeRec xxxxxxxx \n" );
printf( " recordType %d ", thePtr->recordType );
if ( thePtr->recordType == kHFSPlusFolderRecord )
printf( "%s \n", "kHFSPlusFolderRecord" );
else if ( thePtr->recordType == kHFSPlusFileRecord )
printf( "%s \n", "kHFSPlusFileRecord" );
else if ( thePtr->recordType == kHFSPlusFolderThreadRecord )
printf( "%s \n", "kHFSPlusFolderThreadRecord" );
else if ( thePtr->recordType == kHFSPlusFileThreadRecord )
printf( "%s \n", "kHFSPlusFileThreadRecord" );
else
printf( "do not know?? \n" );
}
#endif // DEBUG_REBUILD