#include "Scavenger.h"
static int RcdValErr( SGlobPtr GPtr, OSErr type, UInt32 correct, UInt32 incorrect, HFSCatalogNodeID parid );
static int RcdNameLockedErr( SGlobPtr GPtr, OSErr type, UInt32 incorrect );
static OSErr RcdMDBEmbededVolDescriptionErr( SGlobPtr GPtr, OSErr type, HFSMasterDirectoryBlock *mdb );
static OSErr CheckNodesFirstOffset( SGlobPtr GPtr, BTreeControlBlock *btcb );
static Boolean ExtentInfoExists( ExtentsTable **extentsTableH, ExtentInfo *extentInfo );
static OSErr ScavengeVolumeType( SGlobPtr GPtr, HFSMasterDirectoryBlock *mdb, UInt32 *volumeType );
static OSErr SeekVolumeHeader( SGlobPtr GPtr, UInt64 startSector, UInt32 numSectors, UInt64 *vHSector );
int
CheckIfJournaled(SGlobPtr GPtr)
{
#define kIDSector 2
OSErr err;
int result;
HFSMasterDirectoryBlock *mdbp;
HFSPlusVolumeHeader *vhp;
SVCB *vcb = GPtr->calculatedVCB;
ReleaseBlockOptions rbOptions;
BlockDescriptor block;
vhp = (HFSPlusVolumeHeader *) NULL;
rbOptions = kReleaseBlock;
err = GetVolumeBlock(vcb, kIDSector, kGetBlock, &block);
if (err) return (0);
mdbp = (HFSMasterDirectoryBlock *) block.buffer;
if (mdbp->drSigWord == kHFSPlusSigWord || mdbp->drSigWord == kHFSXSigWord) {
vhp = (HFSPlusVolumeHeader *) block.buffer;
} else if (mdbp->drSigWord == kHFSSigWord) {
if (mdbp->drEmbedSigWord == kHFSPlusSigWord) {
UInt32 vhSector;
UInt32 blkSectors;
blkSectors = mdbp->drAlBlkSiz / 512;
vhSector = mdbp->drAlBlSt;
vhSector += blkSectors * mdbp->drEmbedExtent.startBlock;
vhSector += kIDSector;
(void) ReleaseVolumeBlock(vcb, &block, kReleaseBlock);
err = GetVolumeBlock(vcb, vhSector, kGetBlock, &block);
if (err) return (0);
vhp = (HFSPlusVolumeHeader *) block.buffer;
mdbp = (HFSMasterDirectoryBlock *) NULL;
}
}
if ((vhp != NULL) && (ValidVolumeHeader(vhp) == noErr)) {
result = ((vhp->attributes & kHFSVolumeJournaledMask) != 0);
if ( vhp->lastMountedVersion != kHFSJMountVersion
&& (vhp->attributes & kHFSVolumeUnmountedMask) == 0) {
result = 0;
}
} else {
result = 0;
}
(void) ReleaseVolumeBlock(vcb, &block, rbOptions);
return (result);
}
int
CheckForClean(SGlobPtr GPtr, Boolean markClean)
{
OSErr err;
int result = -1;
HFSMasterDirectoryBlock *mdbp;
HFSPlusVolumeHeader *vhp;
SVCB *vcb = GPtr->calculatedVCB;
VolumeObjectPtr myVOPtr;
ReleaseBlockOptions rbOptions;
UInt64 blockNum;
BlockDescriptor block;
vhp = (HFSPlusVolumeHeader *) NULL;
rbOptions = kReleaseBlock;
myVOPtr = GetVolumeObjectPtr( );
block.buffer = NULL;
GetVolumeObjectBlockNum( &blockNum );
if ( blockNum == 0 ) {
if ( GPtr->logLevel >= kDebugLog )
printf( "\t%s - unknown volume type \n", __FUNCTION__ );
return (-1);
}
err = GetVolumeObjectPrimaryBlock( &block );
if (err) {
if ( GPtr->logLevel >= kDebugLog )
printf( "\t%s - could not get VHB/MDB at block %qd \n", __FUNCTION__, blockNum );
err = -1;
goto ExitThisRoutine;
}
if ( VolumeObjectIsHFSPlus( ) ) {
vhp = (HFSPlusVolumeHeader *) block.buffer;
result = (vhp->attributes & kHFSVolumeUnmountedMask) != 0;
if (markClean && (result == 0)) {
vhp->attributes |= kHFSVolumeUnmountedMask;
rbOptions = kForceWriteBlock;
}
}
else if ( VolumeObjectIsHFS( ) ) {
mdbp = (HFSMasterDirectoryBlock *) block.buffer;
result = (mdbp->drAtrb & kHFSVolumeUnmountedMask) != 0;
if (markClean && (result == 0)) {
mdbp->drAtrb |= kHFSVolumeUnmountedMask;
rbOptions = kForceWriteBlock;
}
}
ExitThisRoutine:
if ( block.buffer != NULL )
(void) ReleaseVolumeBlock(vcb, &block, rbOptions);
return (result);
}
#define kBitsPerSector 4096
OSErr IVChk( SGlobPtr GPtr )
{
OSErr err;
HFSMasterDirectoryBlock * myMDBPtr;
HFSPlusVolumeHeader * myVHBPtr;
UInt32 numABlks;
UInt32 minABlkSz;
UInt32 maxNumberOfAllocationBlocks;
UInt32 realAllocationBlockSize;
UInt32 realTotalBlocks;
UInt32 i;
BTreeControlBlock *btcb;
SVCB *vcb = GPtr->calculatedVCB;
VolumeObjectPtr myVOPtr;
UInt64 blockNum;
UInt64 totalSectors;
BlockDescriptor myBlockDescriptor;
GPtr->TarID = AMDB_FNum; GPtr->TarBlock = 0;
maxNumberOfAllocationBlocks = 0xFFFFFFFF;
realAllocationBlockSize = 0;
realTotalBlocks = 0;
myBlockDescriptor.buffer = NULL;
myVOPtr = GetVolumeObjectPtr( );
if ( myVOPtr->totalDeviceSectors < 3 ) {
if ( GPtr->logLevel >= kDebugLog )
printf("\tinvalid device information for volume - total sectors = %qd sector size = %d \n",
myVOPtr->totalDeviceSectors, myVOPtr->sectorSize);
return( 123 );
}
GetVolumeObjectBlockNum( &blockNum );
if ( blockNum == 0 || myVOPtr->volumeType == kUnknownVolumeType ) {
if ( GPtr->logLevel >= kDebugLog )
printf( "\t%s - unknown volume type \n", __FUNCTION__ );
err = R_BadSig;
goto ReleaseAndBail;
}
err = GetVolumeObjectVHBorMDB( &myBlockDescriptor );
if ( err != noErr ) {
if ( GPtr->logLevel >= kDebugLog )
printf( "\t%s - bad volume header - err %d \n", __FUNCTION__, err );
goto ReleaseAndBail;
}
myMDBPtr = (HFSMasterDirectoryBlock *) myBlockDescriptor.buffer;
if ( VolumeObjectIsHFS( ) &&
(myMDBPtr->drEmbedSigWord != 0 ||
myMDBPtr->drEmbedExtent.blockCount != 0 ||
myMDBPtr->drEmbedExtent.startBlock != 0) ) {
err = ScavengeVolumeType( GPtr, myMDBPtr, &myVOPtr->volumeType );
if ( err == E_InvalidMDBdrAlBlSt )
err = RcdMDBEmbededVolDescriptionErr( GPtr, E_InvalidMDBdrAlBlSt, myMDBPtr );
if ( VolumeObjectIsEmbeddedHFSPlus( ) ) {
(void) ReleaseVolumeBlock( vcb, &myBlockDescriptor, kReleaseBlock );
myBlockDescriptor.buffer = NULL;
myMDBPtr = NULL;
err = GetVolumeObjectVHB( &myBlockDescriptor );
if ( err != noErr ) {
if ( GPtr->logLevel >= kDebugLog )
printf( "\t%s - bad volume header - err %d \n", __FUNCTION__, err );
WriteError( GPtr, E_InvalidVolumeHeader, 1, 0 );
err = E_InvalidVolumeHeader;
goto ReleaseAndBail;
}
GetVolumeObjectBlockNum( &blockNum ); }
}
totalSectors = ( VolumeObjectIsEmbeddedHFSPlus( ) ) ? myVOPtr->totalEmbeddedSectors : myVOPtr->totalDeviceSectors;
if ( VolumeObjectIsHFSPlus( ) ) {
myVHBPtr = (HFSPlusVolumeHeader *) myBlockDescriptor.buffer;
WriteMsg( GPtr, M_CheckingHFSPlusVolume, kStatusMessage );
GPtr->numExtents = kHFSPlusExtentDensity;
vcb->vcbSignature = kHFSPlusSigWord;
vcb->vcbAlBlSt = myVOPtr->embeddedOffset / 512;
vcb->vcbEmbeddedOffset = myVOPtr->embeddedOffset;
realAllocationBlockSize = myVHBPtr->blockSize;
realTotalBlocks = myVHBPtr->totalBlocks;
vcb->vcbNextCatalogID = myVHBPtr->nextCatalogID;
vcb->vcbCreateDate = myVHBPtr->createDate;
vcb->vcbAttributes = myVHBPtr->attributes & kHFSCatalogNodeIDsReused;
if ( myVHBPtr->attributesFile.totalBlocks == 0 )
vcb->vcbAttributesFile = NULL;
btcb = (BTreeControlBlock *) vcb->vcbExtentsFile->fcbBtree;
btcb->attributes |= kBTBigKeysMask;
numABlks = myVOPtr->totalDeviceSectors / ( myVHBPtr->blockSize / Blk_Size );
if ( myVHBPtr->totalBlocks > numABlks ) {
RcdError( GPtr, E_NABlks );
err = E_NABlks;
if ( GPtr->logLevel >= kDebugLog ) {
printf( "\t%s - volume header total allocation blocks is greater than device size \n", __FUNCTION__ );
printf( "\tvolume allocation block count %d device allocation block count %d \n",
myVHBPtr->totalBlocks, numABlks );
}
goto ReleaseAndBail;
}
}
else if ( VolumeObjectIsHFS( ) ) {
WriteMsg( GPtr, M_CheckingHFSVolume, kStatusMessage );
GPtr->numExtents = kHFSExtentDensity;
vcb->vcbSignature = myMDBPtr->drSigWord;
maxNumberOfAllocationBlocks = 0xFFFF;
vcb->vcbNextCatalogID = myMDBPtr->drNxtCNID;
vcb->vcbCreateDate = myMDBPtr->drCrDate;
realAllocationBlockSize = myMDBPtr->drAlBlkSiz;
realTotalBlocks = myMDBPtr->drNmAlBlks;
}
GPtr->TarBlock = blockNum;
numABlks = totalSectors;
minABlkSz = Blk_Size; for( i = 2; numABlks > maxNumberOfAllocationBlocks; i++ ) {
minABlkSz = i * Blk_Size; numABlks = totalSectors / i; }
vcb->vcbBlockSize = realAllocationBlockSize;
numABlks = totalSectors / ( realAllocationBlockSize / Blk_Size );
if ( VolumeObjectIsHFSPlus( ) ) {
if ( (realAllocationBlockSize < minABlkSz) ||
(realAllocationBlockSize & (realAllocationBlockSize - 1)) != 0 )
realAllocationBlockSize = 0;
}
else {
if ( (realAllocationBlockSize < minABlkSz) ||
(realAllocationBlockSize > Max_ABSiz) ||
((realAllocationBlockSize % Blk_Size) != 0) )
realAllocationBlockSize = 0;
}
if ( realAllocationBlockSize == 0 ) {
RcdError( GPtr, E_ABlkSz );
err = E_ABlkSz; goto ReleaseAndBail;
}
vcb->vcbTotalBlocks = realTotalBlocks;
vcb->vcbFreeBlocks = 0;
if ( VolumeObjectIsHFS( ) ) {
UInt32 bitMapSizeInSectors;
bitMapSizeInSectors = ( numABlks + kBitsPerSector - 1 ) / kBitsPerSector;
numABlks = (totalSectors - 3 - bitMapSizeInSectors) / (realAllocationBlockSize / Blk_Size);
if ( realTotalBlocks > numABlks ) {
RcdError( GPtr, E_NABlks );
err = E_NABlks; goto ReleaseAndBail;
}
if ( myMDBPtr->drVBMSt <= MDB_BlkN ) {
RcdError(GPtr,E_VBMSt);
err = E_VBMSt; goto ReleaseAndBail;
}
vcb->vcbVBMSt = myMDBPtr->drVBMSt;
if (myMDBPtr->drAlBlSt < (myMDBPtr->drVBMSt + bitMapSizeInSectors)) {
RcdError(GPtr,E_ABlkSt);
err = E_ABlkSt; goto ReleaseAndBail;
}
vcb->vcbAlBlSt = myMDBPtr->drAlBlSt;
}
ReleaseAndBail:
if (myBlockDescriptor.buffer != NULL)
(void) ReleaseVolumeBlock(vcb, &myBlockDescriptor, kReleaseBlock);
return( err );
}
static OSErr ScavengeVolumeType( SGlobPtr GPtr, HFSMasterDirectoryBlock *mdb, UInt32 *volumeType )
{
UInt64 vHSector;
UInt64 startSector;
UInt64 altVHSector;
UInt64 hfsPlusSectors = 0;
UInt32 sectorsPerBlock;
UInt32 numSectorsToSearch;
OSErr err;
HFSPlusVolumeHeader *volumeHeader;
HFSExtentDescriptor embededExtent;
SVCB *calculatedVCB = GPtr->calculatedVCB;
VolumeObjectPtr myVOPtr;
UInt16 embedSigWord = mdb->drEmbedSigWord;
BlockDescriptor block;
if (embedSigWord == 0 &&
mdb->drEmbedExtent.blockCount == 0 &&
mdb->drEmbedExtent.startBlock == 0)
{
*volumeType = kHFSVolumeType;
return noErr;
}
myVOPtr = GetVolumeObjectPtr( );
*volumeType = kEmbededHFSPlusVolumeType;
if ( embedSigWord == kHFSPlusSigWord )
{
vHSector = (UInt64)mdb->drAlBlSt +
((UInt64)(mdb->drAlBlkSiz / Blk_Size) * (UInt64)mdb->drEmbedExtent.startBlock) + 2;
err = GetVolumeBlock(calculatedVCB, vHSector, kGetBlock, &block);
volumeHeader = (HFSPlusVolumeHeader *) block.buffer;
if ( err != noErr ) goto AssumeHFS;
myVOPtr->primaryVHB = vHSector;
err = ValidVolumeHeader( volumeHeader );
(void) ReleaseVolumeBlock(calculatedVCB, &block, kReleaseBlock);
if ( err == noErr ) {
myVOPtr->flags |= kVO_PriVHBOK;
return( noErr );
}
}
sectorsPerBlock = mdb->drAlBlkSiz / Blk_Size;
if ( embedSigWord != kHFSPlusSigWord )
{
numSectorsToSearch = mdb->drAlBlkSiz / Blk_Size;
startSector = myVOPtr->totalDeviceSectors - 4 - numSectorsToSearch;
err = SeekVolumeHeader( GPtr, startSector, numSectorsToSearch, &altVHSector );
if ( err != noErr ) goto AssumeHFS;
myVOPtr->alternateVHB = altVHSector;
myVOPtr->flags |= kVO_AltVHBOK;
startSector = mdb->drAlBlSt + (4 * sectorsPerBlock); numSectorsToSearch = 10 * sectorsPerBlock;
err = SeekVolumeHeader( GPtr, startSector, numSectorsToSearch, &vHSector );
if ( err != noErr ) goto AssumeHFS;
myVOPtr->primaryVHB = vHSector;
myVOPtr->flags |= kVO_PriVHBOK;
hfsPlusSectors = altVHSector - vHSector + 1 + 2 + 1;
embededExtent.blockCount = hfsPlusSectors / sectorsPerBlock;
embededExtent.startBlock = (vHSector - 2 - mdb->drAlBlSt ) / sectorsPerBlock;
embedSigWord = kHFSPlusSigWord;
myVOPtr->embeddedOffset =
(embededExtent.startBlock * mdb->drAlBlkSiz) + (mdb->drAlBlSt * Blk_Size);
}
else
{
embedSigWord = mdb->drEmbedSigWord;
embededExtent.blockCount = mdb->drEmbedExtent.blockCount;
embededExtent.startBlock = mdb->drEmbedExtent.startBlock;
}
if ( embedSigWord == kHFSPlusSigWord )
{
startSector = 2 + mdb->drAlBlSt +
((UInt64)embededExtent.startBlock * (mdb->drAlBlkSiz / Blk_Size));
err = SeekVolumeHeader( GPtr, startSector, mdb->drAlBlkSiz / Blk_Size, &vHSector );
if ( err != noErr ) goto AssumeHFS;
mdb->drEmbedExtent.blockCount = embededExtent.blockCount;
mdb->drEmbedExtent.startBlock = embededExtent.startBlock;
mdb->drEmbedSigWord = kHFSPlusSigWord;
mdb->drAlBlSt += vHSector - startSector; myVOPtr->totalEmbeddedSectors = (mdb->drAlBlkSiz / Blk_Size) * mdb->drEmbedExtent.blockCount;
myVOPtr->embeddedOffset =
(mdb->drEmbedExtent.startBlock * mdb->drAlBlkSiz) + (mdb->drAlBlSt * Blk_Size);
myVOPtr->primaryVHB = vHSector;
myVOPtr->flags |= kVO_PriVHBOK;
GPtr->VIStat = GPtr->VIStat | S_MDB; return( E_InvalidMDBdrAlBlSt );
}
AssumeHFS:
*volumeType = kHFSVolumeType;
return( noErr );
}
static OSErr SeekVolumeHeader( SGlobPtr GPtr, UInt64 startSector, UInt32 numSectors, UInt64 *vHSector )
{
OSErr err;
HFSPlusVolumeHeader *volumeHeader;
SVCB *calculatedVCB = GPtr->calculatedVCB;
BlockDescriptor block;
for ( *vHSector = startSector ; *vHSector < startSector + numSectors ; (*vHSector)++ )
{
err = GetVolumeBlock(calculatedVCB, *vHSector, kGetBlock, &block);
volumeHeader = (HFSPlusVolumeHeader *) block.buffer;
if ( err != noErr ) return( err );
err = ValidVolumeHeader(volumeHeader);
(void) ReleaseVolumeBlock(calculatedVCB, &block, kReleaseBlock);
if ( err == noErr )
return( noErr );
}
return( fnfErr );
}
#if 0 // not used at this time
static OSErr CheckWrapperExtents( SGlobPtr GPtr, HFSMasterDirectoryBlock *mdb )
{
OSErr err = noErr;
if ( mdb->drCTExtRec[0].startBlock >= mdb->drEmbedExtent.startBlock)
{
mdb->drCTExtRec[0].startBlock = mdb->drXTExtRec[0].startBlock + mdb->drXTExtRec[0].blockCount;
GPtr->VIStat = GPtr->VIStat | S_MDB; err = RcdInvalidWrapperExtents( GPtr, E_InvalidWrapperExtents );
}
return err;
}
#endif
OSErr CreateExtentsBTreeControlBlock( SGlobPtr GPtr )
{
OSErr err;
SInt32 size;
UInt32 numABlks;
BTHeaderRec header;
BTreeControlBlock * btcb;
SVCB * vcb;
BlockDescriptor block;
Boolean isHFSPlus;
isHFSPlus = VolumeObjectIsHFSPlus( );
GPtr->TarID = kHFSExtentsFileID; GPtr->TarBlock = kHeaderNodeNum; vcb = GPtr->calculatedVCB;
btcb = GPtr->calculatedExtentsBTCB;
block.buffer = NULL;
err = GetVolumeObjectVHBorMDB( &block );
if (err) goto exit;
if (isHFSPlus)
{
HFSPlusVolumeHeader *volumeHeader;
volumeHeader = (HFSPlusVolumeHeader *) block.buffer;
CopyMemory(volumeHeader->extentsFile.extents, GPtr->calculatedExtentsFCB->fcbExtents32, sizeof(HFSPlusExtentRecord) );
err = CheckFileExtents( GPtr, kHFSExtentsFileID, 0, (void *)GPtr->calculatedExtentsFCB->fcbExtents32, &numABlks );
if (err) goto exit;
if ( volumeHeader->extentsFile.totalBlocks != numABlks ) {
RcdError( GPtr, E_ExtPEOF );
err = E_ExtPEOF;
goto exit;
}
else
{
GPtr->calculatedExtentsFCB->fcbLogicalSize = volumeHeader->extentsFile.logicalSize; GPtr->calculatedExtentsFCB->fcbPhysicalSize = (UInt64)volumeHeader->extentsFile.totalBlocks *
(UInt64)volumeHeader->blockSize; }
err = GetBTreeHeader(GPtr, GPtr->calculatedExtentsFCB, &header);
if (err) goto exit;
btcb->maxKeyLength = kHFSPlusExtentKeyMaximumLength; btcb->keyCompareProc = (void *)CompareExtentKeysPlus;
btcb->attributes |=kBTBigKeysMask; btcb->leafRecords = header.leafRecords;
btcb->treeDepth = header.treeDepth;
btcb->rootNode = header.rootNode;
btcb->firstLeafNode = header.firstLeafNode;
btcb->lastLeafNode = header.lastLeafNode;
btcb->nodeSize = header.nodeSize;
btcb->totalNodes = ( GPtr->calculatedExtentsFCB->fcbPhysicalSize / btcb->nodeSize );
btcb->freeNodes = btcb->totalNodes;
err = CheckNodesFirstOffset( GPtr, btcb );
if ( (err != noErr) && (btcb->nodeSize != 1024) ) {
btcb->nodeSize = 1024;
btcb->totalNodes = ( GPtr->calculatedExtentsFCB->fcbPhysicalSize / btcb->nodeSize );
btcb->freeNodes = btcb->totalNodes;
err = CheckNodesFirstOffset( GPtr, btcb );
if (err) goto exit;
GPtr->EBTStat |= S_BTH; }
}
else {
HFSMasterDirectoryBlock *alternateMDB;
alternateMDB = (HFSMasterDirectoryBlock *) block.buffer;
CopyMemory(alternateMDB->drXTExtRec, GPtr->calculatedExtentsFCB->fcbExtents16, sizeof(HFSExtentRecord) );
err = CheckFileExtents( GPtr, kHFSExtentsFileID, 0, (void *)GPtr->calculatedExtentsFCB->fcbExtents16, &numABlks );
if (err) goto exit;
if (alternateMDB->drXTFlSize != ((UInt64)numABlks * (UInt64)GPtr->calculatedVCB->vcbBlockSize)) {
RcdError(GPtr,E_ExtPEOF);
err = E_ExtPEOF;
goto exit;
}
else
{
GPtr->calculatedExtentsFCB->fcbPhysicalSize = alternateMDB->drXTFlSize; GPtr->calculatedExtentsFCB->fcbLogicalSize = GPtr->calculatedExtentsFCB->fcbPhysicalSize;
}
err = GetBTreeHeader(GPtr, GPtr->calculatedExtentsFCB, &header);
if (err) goto exit;
btcb->maxKeyLength = kHFSExtentKeyMaximumLength; btcb->keyCompareProc = (void *)CompareExtentKeys;
btcb->leafRecords = header.leafRecords;
btcb->treeDepth = header.treeDepth;
btcb->rootNode = header.rootNode;
btcb->firstLeafNode = header.firstLeafNode;
btcb->lastLeafNode = header.lastLeafNode;
btcb->nodeSize = header.nodeSize;
btcb->totalNodes = (GPtr->calculatedExtentsFCB->fcbPhysicalSize / btcb->nodeSize );
btcb->freeNodes = btcb->totalNodes;
err = CheckNodesFirstOffset( GPtr, btcb );
if (err) goto exit;
}
if ( header.btreeType != kHFSBTreeType )
{
GPtr->EBTStat |= S_ReservedBTH; }
btcb->refCon = (UInt32) AllocateClearMemory( sizeof(BTreeExtensionsRec) ); if ( btcb->refCon == (UInt32) nil ) {
err = R_NoMem;
goto exit;
}
size = (btcb->totalNodes + 7) / 8; ((BTreeExtensionsRec*)btcb->refCon)->BTCBMPtr = AllocateClearMemory(size); if ( ((BTreeExtensionsRec*)btcb->refCon)->BTCBMPtr == nil )
{
err = R_NoMem;
goto exit;
}
((BTreeExtensionsRec*)btcb->refCon)->BTCBMSize = size; ((BTreeExtensionsRec*)btcb->refCon)->realFreeNodeCount = header.freeNodes;exit:
if ( block.buffer != NULL )
(void) ReleaseVolumeBlock(vcb, &block, kReleaseBlock);
return (err);
}
#define GetRecordOffset(btreePtr,node,index) (*(short *) ((UInt8 *)(node) + (btreePtr)->nodeSize - ((index) << 1) - kOffsetSize))
static OSErr CheckNodesFirstOffset( SGlobPtr GPtr, BTreeControlBlock *btcb )
{
NodeRec nodeRec;
UInt16 offset;
OSErr err;
(void) SetFileBlockSize(btcb->fcbPtr, btcb->nodeSize);
err = GetNode( btcb, kHeaderNodeNum, &nodeRec );
if ( err == noErr )
{
offset = GetRecordOffset( btcb, (NodeDescPtr)nodeRec.buffer, 0 );
if ( (offset < sizeof (BTNodeDescriptor)) || (offset & 1) || (offset >= btcb->nodeSize) ) {
err = fsBTInvalidNodeErr;
}
}
if ( err != noErr )
RcdError( GPtr, E_InvalidNodeSize );
(void) ReleaseNode(btcb, &nodeRec);
return( err );
}
OSErr ExtBTChk( SGlobPtr GPtr )
{
OSErr err;
GPtr->TarID = kHFSExtentsFileID; GetVolumeObjectBlockNum( &GPtr->TarBlock );
err = BTCheck(GPtr, kCalculatedExtentRefNum, NULL);
ReturnIfError( err );
err = BTMapChk( GPtr, kCalculatedExtentRefNum );
ReturnIfError( err );
err = CmpBTH( GPtr, kCalculatedExtentRefNum );
ReturnIfError( err );
err = CmpBTM( GPtr, kCalculatedExtentRefNum );
return( err );
}
OSErr ExtFlChk( SGlobPtr GPtr )
{
UInt32 attributes;
void *p;
OSErr result;
SVCB *vcb;
Boolean isHFSPlus;
BlockDescriptor block;
isHFSPlus = VolumeObjectIsHFSPlus( );
block.buffer = NULL;
vcb = GPtr->calculatedVCB;
result = GetVolumeObjectVHBorMDB( &block );
if ( result != noErr ) goto ExitThisRoutine;
p = (void *) block.buffer;
attributes = isHFSPlus == true ? ((HFSPlusVolumeHeader*)p)->attributes : ((HFSMasterDirectoryBlock*)p)->drAtrb;
if ( attributes & kHFSVolumeSparedBlocksMask ) {
HFSPlusExtentRecord zeroXdr; UInt32 numBadBlocks;
ClearMemory ( zeroXdr, sizeof( HFSPlusExtentRecord ) );
result = CheckFileExtents( GPtr, kHFSBadBlockFileID, 0, (void *)zeroXdr, &numBadBlocks ); }
ExitThisRoutine:
if ( block.buffer != NULL )
(void) ReleaseVolumeBlock(vcb, &block, kReleaseBlock);
return (result);
}
OSErr CreateCatalogBTreeControlBlock( SGlobPtr GPtr )
{
OSErr err;
SInt32 size;
UInt32 numABlks;
BTHeaderRec header;
BTreeControlBlock * btcb;
SVCB * vcb;
BlockDescriptor block;
Boolean isHFSPlus;
isHFSPlus = VolumeObjectIsHFSPlus( );
GPtr->TarID = kHFSCatalogFileID;
GPtr->TarBlock = kHeaderNodeNum;
vcb = GPtr->calculatedVCB;
btcb = GPtr->calculatedCatalogBTCB;
block.buffer = NULL;
err = GetVolumeObjectVHBorMDB( &block );
if ( err != noErr ) goto ExitThisRoutine; if (isHFSPlus)
{
HFSPlusVolumeHeader * volumeHeader;
volumeHeader = (HFSPlusVolumeHeader *) block.buffer;
CopyMemory(volumeHeader->catalogFile.extents, GPtr->calculatedCatalogFCB->fcbExtents32, sizeof(HFSPlusExtentRecord) );
err = CheckFileExtents( GPtr, kHFSCatalogFileID, 0, (void *)GPtr->calculatedCatalogFCB->fcbExtents32, &numABlks );
if (err) goto exit;
if ( volumeHeader->catalogFile.totalBlocks != numABlks )
{
RcdError( GPtr, E_CatPEOF );
err = E_CatPEOF;
goto exit;
}
else
{
GPtr->calculatedCatalogFCB->fcbLogicalSize = volumeHeader->catalogFile.logicalSize;
GPtr->calculatedCatalogFCB->fcbPhysicalSize = (UInt64)volumeHeader->catalogFile.totalBlocks *
(UInt64)volumeHeader->blockSize;
}
err = GetBTreeHeader(GPtr, GPtr->calculatedCatalogFCB, &header);
if (err) goto exit;
btcb->maxKeyLength = kHFSPlusCatalogKeyMaximumLength;
if (header.keyCompareType == kHFSBinaryCompare)
{
btcb->keyCompareProc = (void *)CaseSensitiveCatalogKeyCompare;
PrintStatus(GPtr, M_CaseSensitive, 0);
}
else
{
btcb->keyCompareProc = (void *)CompareExtendedCatalogKeys;
}
btcb->keyCompareType = header.keyCompareType;
btcb->leafRecords = header.leafRecords;
btcb->nodeSize = header.nodeSize;
btcb->totalNodes = ( GPtr->calculatedCatalogFCB->fcbPhysicalSize / btcb->nodeSize );
btcb->freeNodes = btcb->totalNodes; btcb->attributes |=(kBTBigKeysMask + kBTVariableIndexKeysMask);
btcb->treeDepth = header.treeDepth;
btcb->rootNode = header.rootNode;
btcb->firstLeafNode = header.firstLeafNode;
btcb->lastLeafNode = header.lastLeafNode;
err = CheckNodesFirstOffset( GPtr, btcb );
if ( (err != noErr) && (btcb->nodeSize != 4096) ) {
btcb->nodeSize = 4096;
btcb->totalNodes = ( GPtr->calculatedCatalogFCB->fcbPhysicalSize / btcb->nodeSize );
btcb->freeNodes = btcb->totalNodes;
err = CheckNodesFirstOffset( GPtr, btcb );
if (err) goto exit;
GPtr->CBTStat |= S_BTH; }
}
else {
HFSMasterDirectoryBlock *alternateMDB;
alternateMDB = (HFSMasterDirectoryBlock *) block.buffer;
CopyMemory( alternateMDB->drCTExtRec, GPtr->calculatedCatalogFCB->fcbExtents16, sizeof(HFSExtentRecord) );
err = CheckFileExtents( GPtr, kHFSCatalogFileID, 0, (void *)GPtr->calculatedCatalogFCB->fcbExtents16, &numABlks );
if (err) goto exit;
if (alternateMDB->drCTFlSize != ((UInt64)numABlks * (UInt64)vcb->vcbBlockSize)) {
RcdError( GPtr, E_CatPEOF );
err = E_CatPEOF;
goto exit;
}
else
{
GPtr->calculatedCatalogFCB->fcbPhysicalSize = alternateMDB->drCTFlSize; GPtr->calculatedCatalogFCB->fcbLogicalSize = GPtr->calculatedCatalogFCB->fcbPhysicalSize;
}
err = GetBTreeHeader(GPtr, GPtr->calculatedCatalogFCB, &header);
if (err) goto exit;
btcb->maxKeyLength = kHFSCatalogKeyMaximumLength; btcb->keyCompareProc = (void *) CompareCatalogKeys;
btcb->leafRecords = header.leafRecords;
btcb->nodeSize = header.nodeSize;
btcb->totalNodes = (GPtr->calculatedCatalogFCB->fcbPhysicalSize / btcb->nodeSize );
btcb->freeNodes = btcb->totalNodes;
btcb->treeDepth = header.treeDepth;
btcb->rootNode = header.rootNode;
btcb->firstLeafNode = header.firstLeafNode;
btcb->lastLeafNode = header.lastLeafNode;
err = CheckNodesFirstOffset( GPtr, btcb );
if (err) goto exit;
}
#if 0
printf(" Catalog B-tree is %qd bytes\n", (UInt64)btcb->totalNodes * (UInt64) btcb->nodeSize);
#endif
if ( header.btreeType != kHFSBTreeType )
{
GPtr->CBTStat |= S_ReservedBTH; }
btcb->refCon = (UInt32) AllocateClearMemory( sizeof(BTreeExtensionsRec) ); if ( btcb->refCon == (UInt32)nil ) {
err = R_NoMem;
goto exit;
}
size = (btcb->totalNodes + 7) / 8; ((BTreeExtensionsRec*)btcb->refCon)->BTCBMPtr = AllocateClearMemory(size); if ( ((BTreeExtensionsRec*)btcb->refCon)->BTCBMPtr == nil )
{
err = R_NoMem;
goto exit;
}
((BTreeExtensionsRec*)btcb->refCon)->BTCBMSize = size; ((BTreeExtensionsRec*)btcb->refCon)->realFreeNodeCount = header.freeNodes;
{
OSErr result;
UInt16 recSize;
CatalogKey key;
CatalogRecord record;
BuildCatalogKey( kHFSRootFolderID, NULL, isHFSPlus, &key );
result = SearchBTreeRecord( GPtr->calculatedCatalogFCB, &key, kNoHint, NULL, &record, &recSize, NULL );
if ( result == noErr ) {
if ( isHFSPlus ) {
size_t len;
HFSPlusCatalogThread * recPtr = &record.hfsPlusThread;
(void) utf_encodestr( recPtr->nodeName.unicode,
recPtr->nodeName.length * 2,
GPtr->volumeName, &len );
GPtr->volumeName[len] = '\0';
}
else {
HFSCatalogThread * recPtr = &record.hfsThread;
bcopy( &recPtr->nodeName[1], GPtr->volumeName, recPtr->nodeName[0] );
GPtr->volumeName[ recPtr->nodeName[0] ] = '\0';
}
}
}
exit:
ExitThisRoutine:
if ( block.buffer != NULL )
(void) ReleaseVolumeBlock(vcb, &block, kReleaseBlock);
return (err);
}
OSErr CreateExtendedAllocationsFCB( SGlobPtr GPtr )
{
OSErr err = 0;
UInt32 numABlks;
SVCB * vcb;
Boolean isHFSPlus;
BlockDescriptor block;
isHFSPlus = VolumeObjectIsHFSPlus( );
GPtr->TarID = kHFSAllocationFileID;
GetVolumeObjectBlockNum( &GPtr->TarBlock ); vcb = GPtr->calculatedVCB;
block.buffer = NULL;
if ( isHFSPlus )
{
SFCB * fcb;
HFSPlusVolumeHeader *volumeHeader;
err = GetVolumeObjectVHB( &block );
if ( err != noErr )
goto exit;
volumeHeader = (HFSPlusVolumeHeader *) block.buffer;
fcb = GPtr->calculatedAllocationsFCB;
CopyMemory( volumeHeader->allocationFile.extents, fcb->fcbExtents32, sizeof(HFSPlusExtentRecord) );
err = CheckFileExtents( GPtr, kHFSAllocationFileID, 0, (void *)fcb->fcbExtents32, &numABlks );
if (err) goto exit;
(void) SetFileBlockSize (fcb, vcb->vcbBlockSize);
if ( volumeHeader->allocationFile.totalBlocks != numABlks )
{
RcdError( GPtr, E_CatPEOF );
err = E_CatPEOF;
goto exit;
}
else
{
fcb->fcbLogicalSize = volumeHeader->allocationFile.logicalSize;
fcb->fcbPhysicalSize = (UInt64) volumeHeader->allocationFile.totalBlocks *
(UInt64) volumeHeader->blockSize;
}
fcb = GPtr->calculatedStartupFCB;
CopyMemory( volumeHeader->startupFile.extents, fcb->fcbExtents32, sizeof(HFSPlusExtentRecord) );
err = CheckFileExtents( GPtr, kHFSStartupFileID, 0, (void *)fcb->fcbExtents32, &numABlks );
if (err) goto exit;
fcb->fcbLogicalSize = volumeHeader->startupFile.logicalSize;
fcb->fcbPhysicalSize = (UInt64) volumeHeader->startupFile.totalBlocks *
(UInt64) volumeHeader->blockSize;
}
exit:
if (block.buffer)
(void) ReleaseVolumeBlock(vcb, &block, kReleaseBlock);
return (err);
}
OSErr CatHChk( SGlobPtr GPtr )
{
SInt16 i;
OSErr result;
UInt16 recSize;
SInt16 selCode;
UInt32 hint;
UInt32 dirCnt;
UInt32 filCnt;
SInt16 rtdirCnt;
SInt16 rtfilCnt;
SVCB *calculatedVCB;
SDPR *dprP;
SDPR *dprP1;
CatalogKey foundKey;
Boolean validKeyFound;
CatalogKey key;
CatalogRecord record;
CatalogRecord record2;
HFSPlusCatalogFolder *largeCatalogFolderP;
HFSPlusCatalogFile *largeCatalogFileP;
HFSCatalogFile *smallCatalogFileP;
HFSCatalogFolder *smallCatalogFolderP;
CatalogName catalogName;
UInt32 valence;
CatalogRecord threadRecord;
HFSCatalogNodeID parID;
Boolean isHFSPlus;
isHFSPlus = VolumeObjectIsHFSPlus( );
calculatedVCB = GPtr->calculatedVCB;
GPtr->TarID = kHFSCatalogFileID;
GPtr->TarBlock = 0;
{
BuildCatalogKey( 1, (const CatalogName *)nil, isHFSPlus, &key );
result = SearchBTreeRecord( GPtr->calculatedCatalogFCB, &key, kNoHint, &foundKey, &threadRecord, &recSize, &hint );
GPtr->TarBlock = hint;
if ( result != btNotFound )
{
RcdError( GPtr, E_CatRec );
return( E_CatRec );
}
}
GPtr->DirLevel = 1;
dprP = &(*GPtr->DirPTPtr)[0];
dprP->directoryID = 1;
dirCnt = filCnt = rtdirCnt = rtfilCnt = 0;
result = noErr;
selCode = 0x8001;
while ( (GPtr->DirLevel > 0) && (result == noErr) )
{
dprP = &(*GPtr->DirPTPtr)[GPtr->DirLevel -1];
validKeyFound = true;
record.recordType = 0;
result = GetBTreeRecord( GPtr->calculatedCatalogFCB, selCode, &foundKey, &record, &recSize, &hint );
GPtr->TarBlock = hint;
if ( result != noErr )
{
if ( result == btNotFound )
{
result = noErr;
validKeyFound = false;
}
else
{
result = IntError( GPtr, result );
return( result );
}
}
selCode = 1;
GPtr->itemsProcessed++;
parID = isHFSPlus == true ? foundKey.hfsPlus.parentID : foundKey.hfs.parentID;
if ( (validKeyFound == true) && (parID == dprP->directoryID) )
{
dprP->offspringIndex++;
if ( record.recordType == kHFSPlusFolderRecord )
{
result = CheckForStop( GPtr ); ReturnIfError( result );
largeCatalogFolderP = (HFSPlusCatalogFolder *) &record;
GPtr->TarID = largeCatalogFolderP->folderID; GPtr->CNType = record.recordType; CopyCatalogName( (const CatalogName *) &foundKey.hfsPlus.nodeName, &GPtr->CName, isHFSPlus );
if ( dprP->directoryID > 1 )
{
GPtr->DirLevel++; dirCnt++;
}
if ( dprP->directoryID == kHFSRootFolderID ) rtdirCnt++;
if ( GPtr->DirLevel > CMMaxDepth )
{
RcdError(GPtr,E_CatDepth); return noErr; }
dprP = &(*GPtr->DirPTPtr)[GPtr->DirLevel -1];
dprP->directoryID = largeCatalogFolderP->folderID;
dprP->offspringIndex = 1;
dprP->directoryHint = hint;
dprP->parentDirID = foundKey.hfsPlus.parentID;
CopyCatalogName( (const CatalogName *) &foundKey.hfsPlus.nodeName, &dprP->directoryName, isHFSPlus );
for ( i = 1; i < GPtr->DirLevel; i++ )
{
dprP1 = &(*GPtr->DirPTPtr)[i -1];
if (dprP->directoryID == dprP1->directoryID)
{
RcdError( GPtr,E_DirLoop ); return( E_DirLoop );
}
}
BuildCatalogKey( dprP->directoryID, (const CatalogName *) nil, isHFSPlus, &key );
result = SearchBTreeRecord( GPtr->calculatedCatalogFCB, &key, kNoHint, &foundKey, &threadRecord, &recSize, &hint );
if ( result != noErr ) {
char idStr[16];
struct MissingThread *mtp;
sprintf(idStr, "%d", dprP->directoryID);
PrintError(GPtr, E_NoThd, 1, idStr);
if ( !isHFSPlus )
return (E_NoThd);
for (mtp = GPtr->missingThreadList; mtp != NULL; mtp = mtp->link) {
if (mtp->threadID == dprP->directoryID) {
mtp->thread.recordType = kHFSPlusFolderThreadRecord;
mtp->thread.parentID = dprP->parentDirID;
CopyCatalogName(&dprP->directoryName, (CatalogName *)&mtp->thread.nodeName, isHFSPlus);
result = SearchBTreeRecord(GPtr->calculatedCatalogFCB, &mtp->nextKey,
kNoHint, &foundKey, &threadRecord, &recSize, &hint);
if (result) {
return (E_NoThd);
}
selCode = 0;
break;
}
}
if (selCode != 0) {
goto resumeAtParent;
}
}
dprP->threadHint = hint;
GPtr->TarBlock = hint;
}
else if ( record.recordType == kHFSPlusFileRecord )
{
largeCatalogFileP = (HFSPlusCatalogFile *) &record;
GPtr->TarID = largeCatalogFileP->fileID; GPtr->CNType = record.recordType; CopyCatalogName( (const CatalogName *) &foundKey.hfsPlus.nodeName, &GPtr->CName, isHFSPlus );
filCnt++;
if (dprP->directoryID == kHFSRootFolderID)
rtfilCnt++;
}
else if ( record.recordType == kHFSFolderRecord )
{
result = CheckForStop( GPtr ); ReturnIfError( result );
smallCatalogFolderP = (HFSCatalogFolder *) &record;
GPtr->TarID = smallCatalogFolderP->folderID;
GPtr->CNType = record.recordType;
CopyCatalogName( (const CatalogName *) &key.hfs.nodeName, &GPtr->CName, isHFSPlus );
if (dprP->directoryID > 1)
{
GPtr->DirLevel++;
dirCnt++;
}
if (dprP->directoryID == kHFSRootFolderID)
rtdirCnt++;
if (GPtr->DirLevel > CMMaxDepth)
{
RcdError(GPtr,E_CatDepth);
return noErr;
}
dprP = &(*GPtr->DirPTPtr)[GPtr->DirLevel -1];
dprP->directoryID = smallCatalogFolderP->folderID;
dprP->offspringIndex = 1;
dprP->directoryHint = hint;
dprP->parentDirID = foundKey.hfs.parentID;
CopyCatalogName( (const CatalogName *) &foundKey.hfs.nodeName, &dprP->directoryName, isHFSPlus );
for (i = 1; i < GPtr->DirLevel; i++)
{
dprP1 = &(*GPtr->DirPTPtr)[i -1];
if (dprP->directoryID == dprP1->directoryID)
{
RcdError( GPtr,E_DirLoop );
return( E_DirLoop );
}
}
BuildCatalogKey( dprP->directoryID, (const CatalogName *)0, isHFSPlus, &key );
result = SearchBTreeRecord( GPtr->calculatedCatalogFCB, &key, kNoHint, &foundKey, &threadRecord, &recSize, &hint );
if (result != noErr )
{
result = IntError(GPtr,result);
return(result);
}
dprP->threadHint = hint;
GPtr->TarBlock = hint;
}
else if ( record.recordType == kHFSFileRecord )
{
smallCatalogFileP = (HFSCatalogFile *) &record;
GPtr->TarID = smallCatalogFileP->fileID;
GPtr->CNType = record.recordType;
CopyCatalogName( (const CatalogName *) &foundKey.hfs.nodeName, &GPtr->CName, isHFSPlus );
filCnt++;
if (dprP->directoryID == kHFSRootFolderID)
rtfilCnt++;
}
else
{
M_DebugStr("\p Unknown-Bad record type");
return( 123 );
}
}
else if ( (record.recordType == kHFSFileThreadRecord) || (record.recordType == kHFSPlusFileThreadRecord) )
{
GPtr->TarID = parID; GPtr->CNType = record.recordType; GPtr->CName.ustr.length = 0; }
else
{
resumeAtParent:
GPtr->TarID = dprP->directoryID;
GPtr->CNType = record.recordType;
CopyCatalogName( (const CatalogName *) &dprP->directoryName, &GPtr->CName, isHFSPlus );
CopyCatalogName( (const CatalogName *) &dprP->directoryName, &catalogName, isHFSPlus );
BuildCatalogKey( dprP->parentDirID, (const CatalogName *)&catalogName, isHFSPlus, &key );
result = SearchBTreeRecord( GPtr->calculatedCatalogFCB, &key, dprP->directoryHint, &foundKey, &record2, &recSize, &hint );
if ( result != noErr )
{
result = IntError(GPtr,result);
return(result);
}
GPtr->TarBlock = hint;
valence = isHFSPlus == true ? record2.hfsPlusFolder.valence : (UInt32)record2.hfsFolder.valence;
if ( valence != dprP->offspringIndex -1 )
if ( result = RcdValErr( GPtr, E_DirVal, dprP->offspringIndex -1, valence, dprP->parentDirID ) )
return( result );
GPtr->DirLevel--;
if(GPtr->DirLevel > 0)
{
dprP = &(*GPtr->DirPTPtr)[GPtr->DirLevel -1];
GPtr->TarID = dprP->directoryID;
GPtr->CNType = record.recordType;
CopyCatalogName( (const CatalogName *) &dprP->directoryName, &GPtr->CName, isHFSPlus );
}
}
}
if (!isHFSPlus && (rtdirCnt != calculatedVCB->vcbNmRtDirs))
if ( result = RcdValErr(GPtr,E_RtDirCnt,rtdirCnt,calculatedVCB->vcbNmRtDirs,0) )
return( result );
if (!isHFSPlus && (rtfilCnt != calculatedVCB->vcbNmFls))
if ( result = RcdValErr(GPtr,E_RtFilCnt,rtfilCnt,calculatedVCB->vcbNmFls,0) )
return( result );
if (dirCnt != calculatedVCB->vcbFolderCount)
if ( result = RcdValErr(GPtr,E_DirCnt,dirCnt,calculatedVCB->vcbFolderCount,0) )
return( result );
if (filCnt != calculatedVCB->vcbFileCount)
if ( result = RcdValErr(GPtr,E_FilCnt,filCnt,calculatedVCB->vcbFileCount,0) )
return( result );
return( noErr );
}
OSErr CreateAttributesBTreeControlBlock( SGlobPtr GPtr )
{
OSErr err = 0;
SInt32 size;
UInt32 numABlks;
BTreeControlBlock * btcb;
SVCB * vcb;
Boolean isHFSPlus;
BTHeaderRec header;
BlockDescriptor block;
isHFSPlus = VolumeObjectIsHFSPlus( );
GPtr->TarID = kHFSAttributesFileID;
GPtr->TarBlock = kHeaderNodeNum;
block.buffer = NULL;
btcb = GPtr->calculatedAttributesBTCB;
vcb = GPtr->calculatedVCB;
if (isHFSPlus)
{
HFSPlusVolumeHeader *volumeHeader;
err = GetVolumeObjectVHB( &block );
if ( err != noErr )
goto exit;
volumeHeader = (HFSPlusVolumeHeader *) block.buffer;
CopyMemory( volumeHeader->attributesFile.extents, GPtr->calculatedAttributesFCB->fcbExtents32, sizeof(HFSPlusExtentRecord) );
err = CheckFileExtents( GPtr, kHFSAttributesFileID, 0, (void *)GPtr->calculatedAttributesFCB->fcbExtents32, &numABlks );
if (err) goto exit;
if ( volumeHeader->attributesFile.totalBlocks != numABlks ) {
RcdError( GPtr, E_CatPEOF );
err = E_CatPEOF;
goto exit;
}
else
{
GPtr->calculatedAttributesFCB->fcbLogicalSize = (UInt64) volumeHeader->attributesFile.logicalSize; GPtr->calculatedAttributesFCB->fcbPhysicalSize = (UInt64) volumeHeader->attributesFile.totalBlocks *
(UInt64) volumeHeader->blockSize; }
if (numABlks == 0)
{
btcb->maxKeyLength = 0;
btcb->keyCompareProc = 0;
btcb->leafRecords = 0;
btcb->nodeSize = 0;
btcb->totalNodes = 0;
btcb->freeNodes = 0;
btcb->attributes = 0;
btcb->treeDepth = 0;
btcb->rootNode = 0;
btcb->firstLeafNode = 0;
btcb->lastLeafNode = 0;
GPtr->calculatedVCB->vcbAttributesFile = NULL;
}
else
{
err = GetBTreeHeader(GPtr, GPtr->calculatedAttributesFCB, &header);
if (err) goto exit;
btcb->maxKeyLength = kAttributeKeyMaximumLength; btcb->keyCompareProc = (void *)CompareAttributeKeys;
btcb->leafRecords = header.leafRecords;
btcb->nodeSize = header.nodeSize;
btcb->totalNodes = ( GPtr->calculatedAttributesFCB->fcbPhysicalSize / btcb->nodeSize );
btcb->freeNodes = btcb->totalNodes; btcb->attributes |=(kBTBigKeysMask + kBTVariableIndexKeysMask);
btcb->treeDepth = header.treeDepth;
btcb->rootNode = header.rootNode;
btcb->firstLeafNode = header.firstLeafNode;
btcb->lastLeafNode = header.lastLeafNode;
err = CheckNodesFirstOffset( GPtr, btcb );
if (err) goto exit;
}
}
else
{
btcb->maxKeyLength = 0;
btcb->keyCompareProc = 0;
btcb->leafRecords = 0;
btcb->nodeSize = 0;
btcb->totalNodes = 0;
btcb->freeNodes = 0;
btcb->attributes = 0;
btcb->treeDepth = 0;
btcb->rootNode = 0;
btcb->firstLeafNode = 0;
btcb->lastLeafNode = 0;
GPtr->calculatedVCB->vcbAttributesFile = NULL;
}
btcb->refCon = (UInt32) AllocateClearMemory( sizeof(BTreeExtensionsRec) ); if ( btcb->refCon == (UInt32)nil ) {
err = R_NoMem;
goto exit;
}
if (btcb->totalNodes == 0)
{
((BTreeExtensionsRec*)btcb->refCon)->BTCBMPtr = nil;
((BTreeExtensionsRec*)btcb->refCon)->BTCBMSize = 0;
((BTreeExtensionsRec*)btcb->refCon)->realFreeNodeCount = 0;
}
else
{
if ( btcb->refCon == (UInt32)nil ) {
err = R_NoMem;
goto exit;
}
size = (btcb->totalNodes + 7) / 8; ((BTreeExtensionsRec*)btcb->refCon)->BTCBMPtr = AllocateClearMemory(size); if ( ((BTreeExtensionsRec*)btcb->refCon)->BTCBMPtr == nil )
{
err = R_NoMem;
goto exit;
}
((BTreeExtensionsRec*)btcb->refCon)->BTCBMSize = size; ((BTreeExtensionsRec*)btcb->refCon)->realFreeNodeCount = header.freeNodes; }
exit:
if (block.buffer)
(void) ReleaseVolumeBlock(vcb, &block, kReleaseBlock);
return (err);
}
static int
CheckAttributeRecord(SGlobPtr GPtr, const AttributeKey *key, const HFSPlusAttrRecord *rec, UInt16 reclen)
{
int result = 0;
Boolean isHFSPlus;
isHFSPlus = VolumeObjectIsHFSPlus();
if (!isHFSPlus) {
goto out;
}
#if DEBUG_XATTR
char attrName[XATTR_MAXNAMELEN];
size_t len;
(void) utf_encodestr(key->attrName, key->attrNameLen * 2, attrName, &len);
attrName[len] = '\0';
printf ("%s(%s,%d): fileID=%d AttributeName=%s\n", __FUNCTION__, __FILE__, __LINE__, key->cnid, attrName);
#endif
if ((key->cnid < kHFSFirstUserCatalogNodeID) &&
(key->cnid != kHFSRootFolderID)) {
goto out;
}
if (GPtr->lastAttrFileID.fileID != key->cnid) {
GPtr->lastAttrFileID.fileID = key->cnid;
GPtr->lastAttrFileID.hasSecurity = false;
if (!bcmp(key->attrName, GPtr->securityAttrName, GPtr->securityAttrLen)) {
RecordXAttrBits(GPtr, kHFSHasAttributesMask | kHFSHasSecurityMask, key->cnid, kCalculatedAttributesRefNum);
GPtr->lastAttrFileID.hasSecurity = true;
} else {
RecordXAttrBits(GPtr, kHFSHasAttributesMask, key->cnid, kCalculatedAttributesRefNum);
}
} else {
if ((GPtr->lastAttrFileID.hasSecurity == false) && !bcmp(key->attrName, GPtr->securityAttrName, GPtr->securityAttrLen)) {
RecordXAttrBits(GPtr, kHFSHasSecurityMask, key->cnid, kCalculatedAttributesRefNum);
GPtr->lastAttrFileID.hasSecurity = true;
}
}
out:
return(result);
}
OSErr AttrBTChk( SGlobPtr GPtr )
{
OSErr err;
if (GPtr->calculatedVCB->vcbAttributesFile == NULL)
return noErr;
WriteMsg( GPtr, M_AttrBTChk, kStatusMessage );
GPtr->TarID = kHFSAttributesFileID; GetVolumeObjectBlockNum( &GPtr->TarBlock );
err = BTCheck( GPtr, kCalculatedAttributesRefNum, (CheckLeafRecordProcPtr)CheckAttributeRecord);
ReturnIfError( err );
err = ComparePrimeBuckets(GPtr, kHFSHasAttributesMask);
ReturnIfError( err );
err = ComparePrimeBuckets(GPtr, kHFSHasSecurityMask);
ReturnIfError( err );
err = BTMapChk( GPtr, kCalculatedAttributesRefNum );
ReturnIfError( err );
err = CmpBTH( GPtr, kCalculatedAttributesRefNum );
ReturnIfError( err );
err = CmpBTM( GPtr, kCalculatedAttributesRefNum );
return( err );
}
static int RcdValErr( SGlobPtr GPtr, OSErr type, UInt32 correct, UInt32 incorrect, HFSCatalogNodeID parid )
{
RepairOrderPtr p;
SInt16 n;
Boolean isHFSPlus;
char goodStr[32], badStr[32];
isHFSPlus = VolumeObjectIsHFSPlus( );
PrintError(GPtr, type, 0);
sprintf(goodStr, "%d", correct);
sprintf(badStr, "%d", incorrect);
PrintError(GPtr, E_BadValue, 2, goodStr, badStr);
if (type == E_DirVal)
n = CatalogNameSize( &GPtr->CName, isHFSPlus);
else
n = 0;
p = AllocMinorRepairOrder( GPtr,n );
if (p==NULL)
return (R_NoMem);
p->type = type;
p->correct = correct;
p->incorrect = incorrect;
p->parid = parid;
if ( n != 0 )
CopyCatalogName( (const CatalogName *) &GPtr->CName, (CatalogName*)&p->name, isHFSPlus );
GPtr->CatStat |= S_Valence;
return( noErr );
}
static OSErr RcdMDBEmbededVolDescriptionErr( SGlobPtr GPtr, OSErr type, HFSMasterDirectoryBlock *mdb )
{
RepairOrderPtr p; EmbededVolDescription *desc;
RcdError( GPtr, type );
p = AllocMinorRepairOrder( GPtr, sizeof(EmbededVolDescription) ); if ( p == nil ) return( R_NoMem );
p->type = type; desc = (EmbededVolDescription *) &(p->name);
desc->drAlBlSt = mdb->drAlBlSt;
desc->drEmbedSigWord = mdb->drEmbedSigWord;
desc->drEmbedExtent.startBlock = mdb->drEmbedExtent.startBlock;
desc->drEmbedExtent.blockCount = mdb->drEmbedExtent.blockCount;
GPtr->VIStat |= S_InvalidWrapperExtents;
return( noErr ); }
#if 0 // not used at this time
static OSErr RcdInvalidWrapperExtents( SGlobPtr GPtr, OSErr type )
{
RepairOrderPtr p;
RcdError( GPtr, type );
p = AllocMinorRepairOrder( GPtr, 0 ); if ( p == nil ) return( R_NoMem );
p->type = type;
GPtr->VIStat |= S_BadMDBdrAlBlSt;
return( noErr ); }
#endif
#if(0) // We just check and fix them in SRepair.c
static OSErr RcdOrphanedExtentErr ( SGlobPtr GPtr, SInt16 type, void *theKey )
{
RepairOrderPtr p;
SInt16 n;
Boolean isHFSPlus;
isHFSPlus = VolumeObjectIsHFSPlus( );
RcdError( GPtr,type );
if ( isHFSPlus )
n = sizeof( HFSPlusExtentKey );
else
n = sizeof( HFSExtentKey );
p = AllocMinorRepairOrder( GPtr, n );
if ( p == NULL )
return( R_NoMem );
CopyMemory( theKey, p->name, n );
p->type = type;
GPtr->EBTStat |= S_OrphanedExtent;
return( noErr );
}
#endif
OSErr VInfoChk( SGlobPtr GPtr )
{
OSErr result;
UInt16 recSize;
Boolean isHFSPlus;
UInt32 hint;
UInt32 maxClump;
SVCB *vcb;
VolumeObjectPtr myVOPtr;
CatalogRecord record;
CatalogKey foundKey;
BlockDescriptor altBlock;
BlockDescriptor priBlock;
vcb = GPtr->calculatedVCB;
altBlock.buffer = priBlock.buffer = NULL;
isHFSPlus = VolumeObjectIsHFSPlus( );
myVOPtr = GetVolumeObjectPtr( );
result = GetBTreeRecord( GPtr->calculatedCatalogFCB, 0x8001, &foundKey, &record, &recSize, &hint );
GPtr->TarID = kHFSCatalogFileID;
GPtr->TarBlock = hint;
if ( result != noErr )
{
result = IntError( GPtr, result );
return( result );
}
GPtr->TarID = AMDB_FNum; GetVolumeObjectAlternateBlockNum( &GPtr->TarBlock );
result = GetVolumeObjectAlternateBlock( &altBlock );
if ( isHFSPlus ) {
if ( (myVOPtr->flags & kVO_AltVHBOK) == 0 )
result = badMDBErr;
}
else if ( (myVOPtr->flags & kVO_AltMDBOK) == 0 ) {
result = badMDBErr;
}
if ( result != noErr ) {
GPtr->VIStat = GPtr->VIStat | S_MDB;
if ( VolumeObjectIsHFS( ) ) {
WriteError( GPtr, E_MDBDamaged, 0, 0 );
if ( GPtr->logLevel >= kDebugLog )
printf("\tinvalid alternate MDB at %qd result %d \n", GPtr->TarBlock, result);
}
else {
WriteError( GPtr, E_VolumeHeaderDamaged, 0, 0 );
if ( GPtr->logLevel >= kDebugLog )
printf("\tinvalid alternate VHB at %qd result %d \n", GPtr->TarBlock, result);
}
result = noErr;
goto exit;
}
GPtr->TarID = MDB_FNum; GetVolumeObjectPrimaryBlockNum( &GPtr->TarBlock );
result = GetVolumeObjectPrimaryBlock( &priBlock );
if ( isHFSPlus ) {
if ( (myVOPtr->flags & kVO_PriVHBOK) == 0 )
result = badMDBErr;
}
else if ( (myVOPtr->flags & kVO_PriMDBOK) == 0 ) {
result = badMDBErr;
}
if ( result != noErr ) {
GPtr->VIStat = GPtr->VIStat | S_MDB;
if ( VolumeObjectIsHFS( ) ) {
WriteError( GPtr, E_MDBDamaged, 1, 0 );
if ( GPtr->logLevel >= kDebugLog )
printf("\tinvalid primary MDB at %qd result %d \n", GPtr->TarBlock, result);
}
else {
WriteError( GPtr, E_VolumeHeaderDamaged, 1, 0 );
if ( GPtr->logLevel >= kDebugLog )
printf("\tinvalid primary VHB at %qd result %d \n", GPtr->TarBlock, result);
}
result = noErr;
goto exit;
}
if ( VolumeObjectIsEmbeddedHFSPlus( ) &&
( (myVOPtr->flags & kVO_PriMDBOK) == 0 || (myVOPtr->flags & kVO_AltMDBOK) == 0 ) )
{
GPtr->VIStat |= S_WMDB;
WriteError( GPtr, E_MDBDamaged, 0, 0 );
if ( GPtr->logLevel >= kDebugLog )
printf("\tinvalid wrapper MDB \n");
}
if ( isHFSPlus )
{
HFSPlusVolumeHeader * volumeHeader;
HFSPlusVolumeHeader * alternateVolumeHeader;
UInt64 totalSectors;
alternateVolumeHeader = (HFSPlusVolumeHeader *) altBlock.buffer;
volumeHeader = (HFSPlusVolumeHeader *) priBlock.buffer;
maxClump = (vcb->vcbTotalBlocks / 4) * vcb->vcbBlockSize;
vcb->vcbCreateDate = alternateVolumeHeader->createDate; vcb->vcbModifyDate = volumeHeader->modifyDate; vcb->vcbCheckedDate = volumeHeader->checkedDate;
if ( ((UInt16)volumeHeader->attributes & VAtrb_Msk) == 0 )
vcb->vcbAttributes = (UInt16)volumeHeader->attributes;
else
vcb->vcbAttributes = VAtrb_DFlt;
if ( volumeHeader->nextAllocation < vcb->vcbTotalBlocks )
vcb->vcbNextAllocation = volumeHeader->nextAllocation;
else
vcb->vcbNextAllocation = 0;
if ( (volumeHeader->rsrcClumpSize > 0) &&
(volumeHeader->rsrcClumpSize <= kMaxClumpSize) &&
((volumeHeader->rsrcClumpSize % vcb->vcbBlockSize) == 0) )
vcb->vcbRsrcClumpSize = volumeHeader->rsrcClumpSize;
else if ( (alternateVolumeHeader->rsrcClumpSize > 0) &&
(alternateVolumeHeader->rsrcClumpSize <= kMaxClumpSize) &&
((alternateVolumeHeader->rsrcClumpSize % vcb->vcbBlockSize) == 0) )
vcb->vcbRsrcClumpSize = alternateVolumeHeader->rsrcClumpSize;
else
vcb->vcbRsrcClumpSize = 4 * vcb->vcbBlockSize;
if ( vcb->vcbRsrcClumpSize > kMaxClumpSize )
vcb->vcbRsrcClumpSize = vcb->vcbBlockSize;
if ( (volumeHeader->dataClumpSize > 0) && (volumeHeader->dataClumpSize <= kMaxClumpSize) &&
((volumeHeader->dataClumpSize % vcb->vcbBlockSize) == 0) )
vcb->vcbDataClumpSize = volumeHeader->dataClumpSize;
else if ( (alternateVolumeHeader->dataClumpSize > 0) &&
(alternateVolumeHeader->dataClumpSize <= kMaxClumpSize) &&
((alternateVolumeHeader->dataClumpSize % vcb->vcbBlockSize) == 0) )
vcb->vcbDataClumpSize = alternateVolumeHeader->dataClumpSize;
else
vcb->vcbDataClumpSize = 4 * vcb->vcbBlockSize;
if ( vcb->vcbDataClumpSize > kMaxClumpSize )
vcb->vcbDataClumpSize = vcb->vcbBlockSize;
if ( (volumeHeader->nextCatalogID > vcb->vcbNextCatalogID) &&
(volumeHeader->nextCatalogID <= (vcb->vcbNextCatalogID + 4096)) )
vcb->vcbNextCatalogID = volumeHeader->nextCatalogID;
result = ChkCName( GPtr, (const CatalogName*) &foundKey.hfsPlus.nodeName, isHFSPlus );
vcb->vcbBackupDate = volumeHeader->backupDate;
vcb->vcbWriteCount = volumeHeader->writeCount;
if ( ((volumeHeader->extentsFile.clumpSize % vcb->vcbBlockSize) == 0) &&
(volumeHeader->extentsFile.clumpSize <= maxClump) )
vcb->vcbExtentsFile->fcbClumpSize = volumeHeader->extentsFile.clumpSize;
else if ( ((alternateVolumeHeader->extentsFile.clumpSize % vcb->vcbBlockSize) == 0) &&
(alternateVolumeHeader->extentsFile.clumpSize <= maxClump) )
vcb->vcbExtentsFile->fcbClumpSize = alternateVolumeHeader->extentsFile.clumpSize;
else
vcb->vcbExtentsFile->fcbClumpSize =
(alternateVolumeHeader->extentsFile.extents[0].blockCount * vcb->vcbBlockSize);
if ( ((volumeHeader->catalogFile.clumpSize % vcb->vcbBlockSize) == 0) &&
(volumeHeader->catalogFile.clumpSize <= maxClump) )
vcb->vcbCatalogFile->fcbClumpSize = volumeHeader->catalogFile.clumpSize;
else if ( ((alternateVolumeHeader->catalogFile.clumpSize % vcb->vcbBlockSize) == 0) &&
(alternateVolumeHeader->catalogFile.clumpSize <= maxClump) )
vcb->vcbCatalogFile->fcbClumpSize = alternateVolumeHeader->catalogFile.clumpSize;
else
vcb->vcbCatalogFile->fcbClumpSize =
(alternateVolumeHeader->catalogFile.extents[0].blockCount * vcb->vcbBlockSize);
totalSectors = ( VolumeObjectIsEmbeddedHFSPlus( ) ) ? myVOPtr->totalEmbeddedSectors
: myVOPtr->totalDeviceSectors;
if ( (totalSectors * myVOPtr->sectorSize) > (1024 * 1024 * 500) )
{
if ( vcb->vcbCatalogFile->fcbClumpSize < (1024 * 1024) )
vcb->vcbCatalogFile->fcbClumpSize = (1024 * 1024);
}
if ( ((volumeHeader->allocationFile.clumpSize % vcb->vcbBlockSize) == 0) &&
(volumeHeader->allocationFile.clumpSize <= maxClump) )
vcb->vcbAllocationFile->fcbClumpSize = volumeHeader->allocationFile.clumpSize;
else if ( ((alternateVolumeHeader->allocationFile.clumpSize % vcb->vcbBlockSize) == 0) &&
(alternateVolumeHeader->allocationFile.clumpSize <= maxClump) )
vcb->vcbAllocationFile->fcbClumpSize = alternateVolumeHeader->allocationFile.clumpSize;
else
vcb->vcbAllocationFile->fcbClumpSize =
(alternateVolumeHeader->allocationFile.extents[0].blockCount * vcb->vcbBlockSize);
CopyMemory( volumeHeader->finderInfo, vcb->vcbFinderInfo, sizeof(vcb->vcbFinderInfo) );
result = CompareVolumeHeader( GPtr, volumeHeader );
CheckEmbeddedVolInfoInMDBs( GPtr );
}
else {
HFSMasterDirectoryBlock *mdbP;
HFSMasterDirectoryBlock *alternateMDB;
alternateMDB = (HFSMasterDirectoryBlock *) altBlock.buffer;
mdbP = (HFSMasterDirectoryBlock *) priBlock.buffer;
maxClump = (vcb->vcbTotalBlocks / 4) * vcb->vcbBlockSize;
vcb->vcbCreateDate = alternateMDB->drCrDate;
vcb->vcbModifyDate = mdbP->drLsMod;
if ( (mdbP->drAtrb & VAtrb_Msk) == 0 )
vcb->vcbAttributes = mdbP->drAtrb;
else
vcb->vcbAttributes = VAtrb_DFlt;
if ( mdbP->drAllocPtr < vcb->vcbTotalBlocks )
vcb->vcbNextAllocation = mdbP->drAllocPtr;
else
vcb->vcbNextAllocation = 0;
if ( (mdbP->drClpSiz > 0) &&
(mdbP->drClpSiz <= maxClump) &&
((mdbP->drClpSiz % vcb->vcbBlockSize) == 0) )
vcb->vcbDataClumpSize = mdbP->drClpSiz;
else if ( (alternateMDB->drClpSiz > 0) &&
(alternateMDB->drClpSiz <= maxClump) &&
((alternateMDB->drClpSiz % vcb->vcbBlockSize) == 0) )
vcb->vcbDataClumpSize = alternateMDB->drClpSiz;
else
vcb->vcbDataClumpSize = 4 * vcb->vcbBlockSize;
if ( vcb->vcbDataClumpSize > kMaxClumpSize )
vcb->vcbDataClumpSize = vcb->vcbBlockSize;
if ( (mdbP->drNxtCNID > vcb->vcbNextCatalogID) && (mdbP->drNxtCNID <= (vcb->vcbNextCatalogID + 4096)) )
vcb->vcbNextCatalogID = mdbP->drNxtCNID;
result = ChkCName( GPtr, (const CatalogName*) &vcb->vcbVN, isHFSPlus );
if ( result == noErr )
if ( CmpBlock( mdbP->drVN, vcb->vcbVN, vcb->vcbVN[0] + 1 ) == 0 )
CopyMemory( mdbP->drVN, vcb->vcbVN, kHFSMaxVolumeNameChars + 1 );
vcb->vcbBackupDate = mdbP->drVolBkUp;
vcb->vcbVSeqNum = mdbP->drVSeqNum;
vcb->vcbWriteCount = mdbP->drWrCnt;
if ( ((mdbP->drXTClpSiz % vcb->vcbBlockSize) == 0) && (mdbP->drXTClpSiz <= maxClump) )
vcb->vcbExtentsFile->fcbClumpSize = mdbP->drXTClpSiz;
else if ( ((alternateMDB->drXTClpSiz % vcb->vcbBlockSize) == 0) && (alternateMDB->drXTClpSiz <= maxClump) )
vcb->vcbExtentsFile->fcbClumpSize = alternateMDB->drXTClpSiz;
else
vcb->vcbExtentsFile->fcbClumpSize = (alternateMDB->drXTExtRec[0].blockCount * vcb->vcbBlockSize);
if ( ((mdbP->drCTClpSiz % vcb->vcbBlockSize) == 0) && (mdbP->drCTClpSiz <= maxClump) )
vcb->vcbCatalogFile->fcbClumpSize = mdbP->drCTClpSiz;
else if ( ((alternateMDB->drCTClpSiz % vcb->vcbBlockSize) == 0) && (alternateMDB->drCTClpSiz <= maxClump) )
vcb->vcbCatalogFile->fcbClumpSize = alternateMDB->drCTClpSiz;
else
vcb->vcbCatalogFile->fcbClumpSize = (alternateMDB->drCTExtRec[0].blockCount * vcb->vcbBlockSize);
CopyMemory(mdbP->drFndrInfo, vcb->vcbFinderInfo, sizeof(mdbP->drFndrInfo));
result = CmpMDB( GPtr, mdbP);
}
exit:
if (priBlock.buffer)
(void) ReleaseVolumeBlock(vcb, &priBlock, kReleaseBlock);
if (altBlock.buffer)
(void) ReleaseVolumeBlock(vcb, &altBlock, kReleaseBlock);
return (result);
}
OSErr VLockedChk( SGlobPtr GPtr )
{
UInt32 hint;
CatalogKey foundKey;
CatalogRecord record;
UInt16 recSize;
OSErr result;
UInt16 frFlags;
Boolean isHFSPlus;
SVCB *calculatedVCB = GPtr->calculatedVCB;
VolumeObjectPtr myVOPtr;
myVOPtr = GetVolumeObjectPtr( );
isHFSPlus = VolumeObjectIsHFSPlus( );
GPtr->TarID = kHFSCatalogFileID;
GPtr->TarBlock = 0;
result = GetBTreeRecord( GPtr->calculatedCatalogFCB, 0x8001, &foundKey, &record, &recSize, &hint );
if ( result)
{
RcdError( GPtr, E_EntryNotFound );
return( E_EntryNotFound );
}
if ( isHFSPlus == false )
{
CopyMemory( foundKey.hfs.nodeName, calculatedVCB->vcbVN, sizeof(calculatedVCB->vcbVN) );
}
else if ( myVOPtr->volumeType != kPureHFSPlusVolumeType )
{
HFSMasterDirectoryBlock *mdbP;
BlockDescriptor block;
block.buffer = NULL;
if ( (myVOPtr->flags & kVO_PriMDBOK) != 0 )
result = GetVolumeObjectPrimaryMDB( &block );
else
result = GetVolumeObjectAlternateMDB( &block );
if ( result == noErr ) {
mdbP = (HFSMasterDirectoryBlock *) block.buffer;
CopyMemory( mdbP->drVN, calculatedVCB->vcbVN, sizeof(mdbP->drVN) );
}
if ( block.buffer != NULL )
(void) ReleaseVolumeBlock(calculatedVCB, &block, kReleaseBlock );
ReturnIfError(result);
}
else {
CopyMemory( "\x0dPure HFS Plus", calculatedVCB->vcbVN, sizeof(Str27) );
}
GPtr->TarBlock = hint;
if ( isHFSPlus )
CopyCatalogName( (const CatalogName *)&foundKey.hfsPlus.nodeName, &GPtr->CName, isHFSPlus );
else
CopyCatalogName( (const CatalogName *)&foundKey.hfs.nodeName, &GPtr->CName, isHFSPlus );
if ( (record.recordType == kHFSPlusFolderRecord) || (record.recordType == kHFSFolderRecord) )
{
frFlags = record.recordType == kHFSPlusFolderRecord ?
SWAP_BE16(record.hfsPlusFolder.userInfo.frFlags) :
SWAP_BE16(record.hfsFolder.userInfo.frFlags);
if ( frFlags & fNameLocked ) RcdNameLockedErr( GPtr, E_LockedDirName, frFlags );
}
return( noErr );
}
static int RcdNameLockedErr( SGlobPtr GPtr, SInt16 type, UInt32 incorrect )
{
RepairOrderPtr p;
int n;
Boolean isHFSPlus;
isHFSPlus = VolumeObjectIsHFSPlus( );
RcdError( GPtr, type );
n = CatalogNameSize( &GPtr->CName, isHFSPlus );
p = AllocMinorRepairOrder( GPtr, n );
if ( p==NULL )
return ( R_NoMem );
CopyCatalogName( (const CatalogName *) &GPtr->CName, (CatalogName*)&p->name, isHFSPlus );
p->type = type;
p->correct = incorrect & ~fNameLocked;
p->incorrect = incorrect;
p->maskBit = (UInt16)fNameLocked;
p->parid = 1;
GPtr->CatStat |= S_LockedDirName;
return( noErr );
}
OSErr CheckFileExtents( SGlobPtr GPtr, UInt32 fileNumber, UInt8 forkType,
const void *extents, UInt32 *blocksUsed )
{
UInt32 blockCount;
UInt32 extentBlockCount;
UInt32 extentStartBlock;
UInt32 hint;
HFSPlusExtentKey key;
HFSPlusExtentKey extentKey;
HFSPlusExtentRecord extentRecord;
UInt16 recSize;
OSErr err;
SInt16 i;
Boolean firstRecord;
Boolean isHFSPlus;
isHFSPlus = VolumeObjectIsHFSPlus( );
firstRecord = true;
err = noErr;
blockCount = 0;
while ( (extents != nil) && (err == noErr) )
{
err = ChkExtRec( GPtr, extents ); if ( err != noErr ) break;
for ( i=0 ; i<GPtr->numExtents ; i++ ) {
if ( isHFSPlus == true )
{
extentBlockCount = ((HFSPlusExtentDescriptor *)extents)[i].blockCount;
extentStartBlock = ((HFSPlusExtentDescriptor *)extents)[i].startBlock;
}
else
{
extentBlockCount = ((HFSExtentDescriptor *)extents)[i].blockCount;
extentStartBlock = ((HFSExtentDescriptor *)extents)[i].startBlock;
}
if ( extentBlockCount == 0 )
break;
err = CaptureBitmapBits(extentStartBlock, extentBlockCount);
if (err == E_OvlExt) {
err = AddExtentToOverlapList(GPtr, fileNumber, extentStartBlock, extentBlockCount, forkType);
}
blockCount += extentBlockCount;
}
if ( fileNumber == kHFSExtentsFileID ) break;
if ( firstRecord == true )
{
firstRecord = false;
BuildExtentKey( isHFSPlus, forkType, fileNumber, blockCount, (void *)&key );
err = SearchBTreeRecord( GPtr->calculatedExtentsFCB, &key, kNoHint, (void *) &extentKey, (void *) &extentRecord, &recSize, &hint );
if ( err == btNotFound )
{
err = noErr; extents = nil;
break;
}
else if ( err != noErr )
{
err = IntError( GPtr, err ); return( err );
}
}
else
{
err = GetBTreeRecord( GPtr->calculatedExtentsFCB, 1, &extentKey, extentRecord, &recSize, &hint );
if ( err == btNotFound )
{
err = noErr; extents = nil;
break;
}
else if ( err != noErr )
{
err = IntError( GPtr, err );
return( err );
}
if ( isHFSPlus )
{
if ( (extentKey.fileID != fileNumber) || (extentKey.forkType != forkType) )
break;
}
else
{
if ( (((HFSExtentKey *) &extentKey)->fileID != fileNumber) || (((HFSExtentKey *) &extentKey)->forkType != forkType) )
break;
}
}
extents = (void *) &extentRecord;
}
*blocksUsed = blockCount;
return( err );
}
void BuildExtentKey( Boolean isHFSPlus, UInt8 forkType, HFSCatalogNodeID fileNumber, UInt32 blockNumber, void * key )
{
if ( isHFSPlus )
{
HFSPlusExtentKey *hfsPlusKey = (HFSPlusExtentKey*) key;
hfsPlusKey->keyLength = kHFSPlusExtentKeyMaximumLength;
hfsPlusKey->forkType = forkType;
hfsPlusKey->pad = 0;
hfsPlusKey->fileID = fileNumber;
hfsPlusKey->startBlock = blockNumber;
}
else
{
HFSExtentKey *hfsKey = (HFSExtentKey*) key;
hfsKey->keyLength = kHFSExtentKeyMaximumLength;
hfsKey->forkType = forkType;
hfsKey->fileID = fileNumber;
hfsKey->startBlock = (UInt16) blockNumber;
}
}
OSErr AddExtentToOverlapList( SGlobPtr GPtr, HFSCatalogNodeID fileNumber, UInt32 extentStartBlock, UInt32 extentBlockCount, UInt8 forkType )
{
UInt32 newHandleSize;
ExtentInfo extentInfo;
ExtentsTable **extentsTableH;
char fileno[32];
sprintf(fileno, "%ud", fileNumber);
PrintError(GPtr, E_OvlExt, 1, fileno);
GPtr->VIStat |= S_OverlappingExtents;
extentInfo.fileNumber = fileNumber;
extentInfo.startBlock = extentStartBlock;
extentInfo.blockCount = extentBlockCount;
extentInfo.forkType = forkType;
if ( GPtr->overlappedExtents == nil )
{
GPtr->overlappedExtents = (ExtentsTable **) NewHandleClear( sizeof(ExtentsTable) );
extentsTableH = GPtr->overlappedExtents;
}
else
{
extentsTableH = GPtr->overlappedExtents;
if ( ExtentInfoExists( extentsTableH, &extentInfo ) == true )
return( noErr );
newHandleSize = ( sizeof(ExtentInfo) ) + ( GetHandleSize( (Handle)extentsTableH ) );
SetHandleSize( (Handle)extentsTableH, newHandleSize );
}
CopyMemory( &extentInfo, &((**extentsTableH).extentInfo[(**extentsTableH).count]), sizeof(ExtentInfo) );
(**extentsTableH).count++;
return( noErr );
}
static Boolean ExtentInfoExists( ExtentsTable **extentsTableH, ExtentInfo *extentInfo )
{
UInt32 i;
ExtentInfo *aryExtentInfo;
for ( i = 0 ; i < (**extentsTableH).count ; i++ )
{
aryExtentInfo = &((**extentsTableH).extentInfo[i]);
if ( extentInfo->fileNumber == aryExtentInfo->fileNumber )
{
if ( (extentInfo->startBlock == aryExtentInfo->startBlock) &&
(extentInfo->blockCount == aryExtentInfo->blockCount) &&
(extentInfo->forkType == aryExtentInfo->forkType) )
{
return( true );
}
}
}
return( false );
}