#include "Scavenger.h"
#include "../cache.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 OSErr ScavengeVolumeType( SGlobPtr GPtr, HFSMasterDirectoryBlock *mdb, UInt32 *volumeType );
static OSErr SeekVolumeHeader( SGlobPtr GPtr, UInt64 startSector, UInt32 numSectors, UInt64 *vHSector );
static OSErr AddExtentToOverlapList( SGlobPtr GPtr, HFSCatalogNodeID fileNumber, const char *attrName, UInt32 extentStartBlock, UInt32 extentBlockCount, UInt8 forkType );
static Boolean ExtentInfoExists( ExtentsTable **extentsTableH, ExtentInfo *extentInfo);
static void CheckHFSPlusExtentRecords(SGlobPtr GPtr, UInt32 fileID, const char *attrname, HFSPlusExtentRecord extent, UInt8 forkType);
static void CheckHFSExtentRecords(SGlobPtr GPtr, UInt32 fileID, HFSExtentRecord extent, UInt8 forkType);
static Boolean DoesOverlap(SGlobPtr GPtr, UInt32 fileID, const char *attrname, UInt32 startBlock, UInt32 blockCount, UInt8 forkType);
static int CompareExtentFileID(const void *first, const void *second);
int
CheckIfJournaled(SGlobPtr GPtr, Boolean journal_bit_only)
{
#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 (journal_bit_only == true) {
goto out;
}
if ( vhp->lastMountedVersion == kFSKMountVersion ||
(vhp->attributes & kHFSVolumeInconsistentMask) ||
((vhp->lastMountedVersion != kHFSJMountVersion) &&
(vhp->attributes & kHFSVolumeUnmountedMask) == 0)) {
result = 0;
}
} else {
result = 0;
}
out:
(void) ReleaseVolumeBlock(vcb, &block, rbOptions);
return (result);
}
int CheckForClean(SGlobPtr GPtr, UInt8 operation, Boolean *modified)
{
enum { unknownVolume = -1, cleanUnmount = 1, dirtyUnmount = 0};
int result = unknownVolume;
Boolean update = false;
HFSMasterDirectoryBlock *mdbp;
HFSPlusVolumeHeader *vhp;
BlockDescriptor block;
ReleaseBlockOptions rbOptions;
UInt64 blockNum;
SVCB *vcb;
*modified = false;
vcb = GPtr->calculatedVCB;
block.buffer = NULL;
rbOptions = kReleaseBlock;
GetVolumeObjectBlockNum(&blockNum);
if (blockNum == 0) {
if (GPtr->logLevel >= kDebugLog)
plog( "\t%s - unknown volume type \n", __FUNCTION__ );
goto ExitThisRoutine;
}
result = GetVolumeObjectPrimaryBlock(&block);
if (result) {
if ( GPtr->logLevel >= kDebugLog )
plog( "\t%s - could not get VHB/MDB at block %qd \n", __FUNCTION__, blockNum );
result = unknownVolume;
goto ExitThisRoutine;
}
result = cleanUnmount;
if (VolumeObjectIsHFSPlus()) {
vhp = (HFSPlusVolumeHeader *) block.buffer;
if (((vhp->attributes & kHFSVolumeUnmountedMask) == 0) ||
(vhp->attributes & kHFSVolumeInconsistentMask))
result = dirtyUnmount;
if (vhp->lastMountedVersion == kFSKMountVersion) {
GPtr->JStat |= S_BadJournal;
RcdError (GPtr, E_BadJournal);
result = dirtyUnmount;
}
if (operation == kMarkVolumeDirty) {
if (vhp->attributes & kHFSVolumeUnmountedMask) {
vhp->attributes &= ~kHFSVolumeUnmountedMask;
update = true;
}
if ((vhp->attributes & kHFSVolumeInconsistentMask) == 0) {
vhp->attributes |= kHFSVolumeInconsistentMask;
update = true;
}
} else if (operation == kMarkVolumeClean) {
if ((vhp->attributes & kHFSVolumeUnmountedMask) == 0) {
vhp->attributes |= kHFSVolumeUnmountedMask;
update = true;
}
if (vhp->attributes & kHFSVolumeInconsistentMask) {
vhp->attributes &= ~kHFSVolumeInconsistentMask;
update = true;
}
}
if (update == true) {
vhp->lastMountedVersion = kFSCKMountVersion;
}
} else if (VolumeObjectIsHFS()) {
mdbp = (HFSMasterDirectoryBlock *) block.buffer;
if (((mdbp->drAtrb & kHFSVolumeUnmountedMask) == 0) ||
(mdbp->drAtrb & kHFSVolumeInconsistentMask))
result = dirtyUnmount;
if (operation == kMarkVolumeDirty) {
if (mdbp->drAtrb & kHFSVolumeUnmountedMask) {
mdbp->drAtrb &= ~kHFSVolumeUnmountedMask;
update = true;
}
if ((mdbp->drAtrb & kHFSVolumeInconsistentMask) == 0) {
mdbp->drAtrb |= kHFSVolumeInconsistentMask;
update = true;
}
} else if (operation == kMarkVolumeClean) {
if ((mdbp->drAtrb & kHFSVolumeUnmountedMask) == 0) {
mdbp->drAtrb |= kHFSVolumeUnmountedMask;
update = true;
}
if (mdbp->drAtrb & kHFSVolumeInconsistentMask) {
mdbp->drAtrb &= ~kHFSVolumeInconsistentMask;
update = true;
}
}
}
ExitThisRoutine:
if (update == true) {
*modified = true;
rbOptions = kForceWriteBlock;
if (operation == kMarkVolumeDirty) {
result = dirtyUnmount;
} else if (operation == kMarkVolumeClean) {
result = cleanUnmount;
}
}
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 )
plog("\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 )
plog( "\t%s - unknown volume type \n", __FUNCTION__ );
err = R_BadSig;
goto ReleaseAndBail;
}
err = GetVolumeObjectVHBorMDB( &myBlockDescriptor );
if ( err != noErr ) {
if ( GPtr->logLevel >= kDebugLog )
plog( "\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 )
plog( "\t%s - bad volume header - err %d \n", __FUNCTION__, err );
WriteError( GPtr, E_InvalidVolumeHeader, 1, 0 );
err = E_InvalidVolumeHeader;
goto ReleaseAndBail;
}
GetVolumeObjectBlockNum( &blockNum ); }
else {
if ( GPtr->logLevel >= kDebugLog )
plog( "\t%s - bad volume header - err %d \n", __FUNCTION__, err );
WriteError( GPtr, E_InvalidVolumeHeader, 1, 0 );
err = E_InvalidVolumeHeader;
goto ReleaseAndBail;
}
}
totalSectors = ( VolumeObjectIsEmbeddedHFSPlus( ) ) ? myVOPtr->totalEmbeddedSectors : myVOPtr->totalDeviceSectors;
if ( VolumeObjectIsHFSPlus( ) ) {
myVHBPtr = (HFSPlusVolumeHeader *) myBlockDescriptor.buffer;
if (myVHBPtr->attributes & kHFSVolumeJournaledMask) {
WriteMsg( GPtr, M_CheckingJnlHFSPlusVolume, kStatusMessage );
} else {
WriteMsg( GPtr, M_CheckingNoJnlHFSPlusVolume, 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 ) {
plog( "\t%s - volume header total allocation blocks is greater than device size \n", __FUNCTION__ );
plog( "\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, kDataFork, NULL, (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, kDataFork, NULL, (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 BadBlockFileExtentCheck( 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, kDataFork, NULL, (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, kDataFork, NULL, (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, kDataFork, NULL, (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
plog(" 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, sizeof(GPtr->volumeName) );
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, kDataFork, NULL, (void *)fcb->fcbExtents32, &numABlks);
if (err) goto exit;
if (vcb->vcbBlockSize < fscache.BlockSize)
(void) SetFileBlockSize (fcb, vcb->vcbBlockSize);
else
(void) SetFileBlockSize (fcb, fscache.BlockSize);
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, kDataFork, NULL, (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, kDataFork, NULL, (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 void RecordLastAttrBits(SGlobPtr GPtr)
{
if ((GPtr->lastAttrInfo.fileID == 0) ||
((GPtr->lastAttrInfo.fileID < kHFSFirstUserCatalogNodeID) &&
(GPtr->lastAttrInfo.fileID != kHFSRootFolderID))) {
return;
}
if (GPtr->lastAttrInfo.hasSecurity == true) {
RecordXAttrBits(GPtr, kHFSHasAttributesMask | kHFSHasSecurityMask,
GPtr->lastAttrInfo.fileID, kCalculatedAttributesRefNum);
GPtr->lastAttrInfo.hasSecurity = false;
} else {
RecordXAttrBits(GPtr, kHFSHasAttributesMask,
GPtr->lastAttrInfo.fileID, kCalculatedAttributesRefNum);
}
}
static void setLastAttrAllocInfo(SGlobPtr GPtr, u_int32_t totalBlocks,
u_int64_t logicalSize, u_int32_t calculatedTotalBlocks)
{
GPtr->lastAttrInfo.totalBlocks = totalBlocks;
GPtr->lastAttrInfo.logicalSize = logicalSize;
GPtr->lastAttrInfo.calculatedTotalBlocks = calculatedTotalBlocks;
GPtr->lastAttrInfo.isValid = true;
}
static int CheckLastAttrAllocation(SGlobPtr GPtr)
{
int result = 0;
u_int64_t bytes;
if (GPtr->lastAttrInfo.isValid == true) {
if (GPtr->lastAttrInfo.totalBlocks !=
GPtr->lastAttrInfo.calculatedTotalBlocks) {
result = RecordBadAllocation(GPtr->lastAttrInfo.fileID,
GPtr->lastAttrInfo.attrname, kEAData,
GPtr->lastAttrInfo.totalBlocks,
GPtr->lastAttrInfo.calculatedTotalBlocks);
} else {
bytes = (u_int64_t)GPtr->lastAttrInfo.calculatedTotalBlocks *
(u_int64_t)GPtr->calculatedVCB->vcbBlockSize;
if (GPtr->lastAttrInfo.logicalSize > bytes) {
result = RecordTruncation(GPtr->lastAttrInfo.fileID,
GPtr->lastAttrInfo.attrname, kEAData,
GPtr->lastAttrInfo.logicalSize, bytes);
}
}
GPtr->lastAttrInfo.isValid = false;
}
return (result);
}
int
CheckAttributeRecord(SGlobPtr GPtr, const HFSPlusAttrKey *key, const HFSPlusAttrRecord *rec, UInt16 reclen)
{
int result = 0;
unsigned char attrname[XATTR_MAXNAMELEN+1];
size_t attrlen;
u_int32_t blocks;
u_int32_t fileID;
struct attributeInfo *prevAttr;
Boolean isSameAttr = true;
Boolean doDelete = false;
u_int16_t dfaStage = GetDFAStage();
assert(VolumeObjectIsHFSPlus() == true);
prevAttr = &(GPtr->lastAttrInfo);
fileID = key->fileID;
(void) utf_encodestr(key->attrName, key->attrNameLen * 2, attrname, &attrlen, sizeof(attrname));
attrname[attrlen] = '\0';
if ((fileID != prevAttr->fileID) ||
(strcmp((char *)attrname, (char *)prevAttr->attrname) != 0)) {
isSameAttr = false;
}
if (dfaStage == kVerifyStage) {
if (isSameAttr == false) {
result = CheckLastAttrAllocation(GPtr);
if (result) {
goto update_out;
}
}
if (fileID != prevAttr->fileID) {
RecordLastAttrBits(GPtr);
}
}
switch (rec->recordType) {
case kHFSPlusAttrForkData: {
if (dfaStage == kVerifyStage) {
if (key->startBlock != 0) {
RcdError(GPtr, E_ABlkSt);
result = E_ABlkSt;
goto err_out;
}
result = CheckFileExtents (GPtr, fileID, kEAData, attrname,
rec->forkData.theFork.extents, &blocks);
if (result) {
goto update_out;
}
(void) setLastAttrAllocInfo(GPtr, rec->forkData.theFork.totalBlocks,
rec->forkData.theFork.logicalSize, blocks);
}
break;
}
case kHFSPlusAttrExtents: {
if ((isSameAttr == false) ||
((prevAttr->recordType != kHFSPlusAttrExtents) &&
(prevAttr->recordType != kHFSPlusAttrForkData))) {
if (dfaStage == kRepairStage) {
doDelete = true;
} else {
RcdError(GPtr, E_AttrRec);
GPtr->ABTStat |= S_AttrRec;
goto err_out;
}
}
if (dfaStage == kVerifyStage) {
if (key->startBlock != prevAttr->calculatedTotalBlocks) {
RcdError(GPtr, E_ABlkSt);
result = E_ABlkSt;
goto err_out;
}
result = CheckFileExtents (GPtr, fileID, kEAData, attrname,
rec->overflowExtents.extents, &blocks);
if (result) {
goto update_out;
}
prevAttr->calculatedTotalBlocks += blocks;
}
break;
}
case kHFSPlusAttrInlineData: {
if (dfaStage == kVerifyStage) {
if (key->startBlock != 0) {
RcdError(GPtr, E_ABlkSt);
result = E_ABlkSt;
goto err_out;
}
}
break;
}
default: {
if (dfaStage == kRepairStage) {
doDelete = true;
} else {
RcdError(GPtr, E_AttrRec);
GPtr->ABTStat |= S_AttrRec;
goto err_out;
}
break;
}
};
if (doDelete == true) {
result = DeleteBTreeRecord(GPtr->calculatedAttributesFCB, key);
dprintf (d_info|d_xattr, "%s: Deleting attribute %s for fileID %d, type = %d\n", __FUNCTION__, attrname, key->fileID, rec->recordType);
if (result) {
dprintf (d_error|d_xattr, "%s: Error in deleting record for %s for fileID %d, type = %d\n", __FUNCTION__, attrname, key->fileID, rec->recordType);
}
GPtr->ABTStat |= S_BTH + S_BTM;
goto err_out;
}
update_out:
if (strcmp((char *)attrname, KAUTH_FILESEC_XATTR) == 0) {
prevAttr->hasSecurity = true;
}
prevAttr->recordType = rec->recordType;
prevAttr->fileID = fileID;
(void) strlcpy((char *)prevAttr->attrname, (char *)attrname, sizeof(prevAttr->attrname));
goto out;
err_out:
if (prevAttr->fileID != fileID) {
prevAttr->fileID = 0;
}
out:
return(result);
}
void RecordXAttrBits(SGlobPtr GPtr, UInt16 flags, HFSCatalogNodeID fileid, UInt16 btreetype)
{
PrimeBuckets *cur_attr = NULL;
PrimeBuckets *cur_sec = NULL;
if ( ((flags & kHFSHasAttributesMask) == 0) &&
((flags & kHFSHasSecurityMask) == 0) ) {
goto out;
}
if (btreetype == kCalculatedCatalogRefNum) {
if (flags & kHFSHasAttributesMask) {
cur_attr = &(GPtr->CBTAttrBucket);
GPtr->cat_ea_count++;
}
if (flags & kHFSHasSecurityMask) {
cur_sec = &(GPtr->CBTSecurityBucket);
GPtr->cat_acl_count++;
}
} else if (btreetype == kCalculatedAttributesRefNum) {
if (flags & kHFSHasAttributesMask) {
cur_attr = &(GPtr->ABTAttrBucket);
GPtr->attr_ea_count++;
}
if (flags & kHFSHasSecurityMask) {
cur_sec = &(GPtr->ABTSecurityBucket);
GPtr->attr_acl_count++;
}
} else {
goto out;
}
if (cur_attr) {
add_prime_bucket_uint32(cur_attr, fileid);
}
if (cur_sec) {
add_prime_bucket_uint32(cur_sec, fileid);
}
out:
return;
}
static int CompareXattrPrimeBuckets(SGlobPtr GPtr, UInt16 BitMask)
{
int result = 1;
PrimeBuckets *cat;
PrimeBuckets *attr;
if (BitMask & kHFSHasAttributesMask) {
cat = &(GPtr->CBTAttrBucket);
attr = &(GPtr->ABTAttrBucket);
} else if (BitMask & kHFSHasSecurityMask) {
cat = &(GPtr->CBTSecurityBucket);
attr = &(GPtr->ABTSecurityBucket);
} else {
plog ("%s: Incorrect BitMask found.\n", __FUNCTION__);
goto out;
}
result = compare_prime_buckets(cat, attr);
if (result) {
char catbtree[32], attrbtree[32];
if (BitMask & kHFSHasAttributesMask) {
PrintError (GPtr, E_IncorrectAttrCount, 0);
sprintf (catbtree, "%u", GPtr->cat_ea_count);
sprintf (attrbtree, "%u", GPtr->attr_ea_count);
PrintError (GPtr, E_BadValue, 2, attrbtree, catbtree);
GPtr->ABTStat |= S_AttributeCount;
} else {
PrintError (GPtr, E_IncorrectSecurityCount, 0);
sprintf (catbtree, "%u", GPtr->cat_acl_count);
sprintf (attrbtree, "%u", GPtr->attr_acl_count);
PrintError (GPtr, E_BadValue, 2, attrbtree, catbtree);
GPtr->ABTStat |= S_SecurityCount;
}
}
result = 0;
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 = CheckLastAttrAllocation(GPtr);
ReturnIfError(err);
RecordLastAttrBits(GPtr);
err = CompareXattrPrimeBuckets(GPtr, kHFSHasAttributesMask);
ReturnIfError( err );
err = CompareXattrPrimeBuckets(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 );
}
int RcdHsFldCntErr( SGlobPtr GPtr, OSErr type, UInt32 correct, UInt32 incorrect, HFSCatalogNodeID fid )
{
RepairOrderPtr p;
char goodStr[32], badStr[32];
snprintf(goodStr, sizeof(goodStr), "%u", fid);
PrintError(GPtr, type, 1, goodStr);
sprintf(goodStr, "%#x", correct);
sprintf(badStr, "%#x", incorrect);
PrintError(GPtr, E_BadValue, 2, goodStr, badStr);
p = AllocMinorRepairOrder( GPtr,0 );
if (p==NULL)
return (R_NoMem);
p->type = type;
p->correct = correct;
p->incorrect = incorrect;
p->parid = fid;
return( noErr );
}
int RcdFCntErr( SGlobPtr GPtr, OSErr type, UInt32 correct, UInt32 incorrect, HFSCatalogNodeID fid )
{
RepairOrderPtr p;
char goodStr[32], badStr[32];
snprintf(goodStr, sizeof(goodStr), "%u", fid);
PrintError(GPtr, type, 1, goodStr);
sprintf(goodStr, "%d", correct);
sprintf(badStr, "%d", incorrect);
PrintError(GPtr, E_BadValue, 2, goodStr, badStr);
p = AllocMinorRepairOrder( GPtr,0 );
if (p==NULL)
return (R_NoMem);
p->type = type;
p->correct = correct;
p->incorrect = incorrect;
p->parid = fid;
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;
UInt64 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 )
plog("\tinvalid alternate MDB at %qd result %d \n", GPtr->TarBlock, result);
}
else {
WriteError( GPtr, E_VolumeHeaderDamaged, 0, 0 );
if ( GPtr->logLevel >= kDebugLog )
plog("\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 )
plog("\tinvalid primary MDB at %qd result %d \n", GPtr->TarBlock, result);
}
else {
WriteError( GPtr, E_VolumeHeaderDamaged, 1, 0 );
if ( GPtr->logLevel >= kDebugLog )
plog("\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 )
plog("\tinvalid wrapper MDB \n");
}
if ( isHFSPlus )
{
HFSPlusVolumeHeader * volumeHeader;
HFSPlusVolumeHeader * alternateVolumeHeader;
UInt64 totalSectors;
alternateVolumeHeader = (HFSPlusVolumeHeader *) altBlock.buffer;
volumeHeader = (HFSPlusVolumeHeader *) priBlock.buffer;
maxClump = (UInt64) (vcb->vcbTotalBlocks / 4) * vcb->vcbBlockSize;
vcb->vcbCreateDate = alternateVolumeHeader->createDate; vcb->vcbModifyDate = volumeHeader->modifyDate; vcb->vcbCheckedDate = volumeHeader->checkedDate;
vcb->vcbAttributes = volumeHeader->attributes;
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) )
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);
if (vcb->vcbAttributesFile) {
if ( ((volumeHeader->attributesFile.clumpSize % vcb->vcbBlockSize) == 0) &&
(volumeHeader->attributesFile.clumpSize <= maxClump) &&
(volumeHeader->attributesFile.clumpSize != 0))
vcb->vcbAttributesFile->fcbClumpSize = volumeHeader->attributesFile.clumpSize;
else if ( ((alternateVolumeHeader->attributesFile.clumpSize % vcb->vcbBlockSize) == 0) &&
(alternateVolumeHeader->attributesFile.clumpSize <= maxClump) &&
(alternateVolumeHeader->attributesFile.clumpSize != 0))
vcb->vcbAttributesFile->fcbClumpSize = alternateVolumeHeader->attributesFile.clumpSize;
else if (vcb->vcbCatalogFile->fcbClumpSize != 0)
vcb->vcbAttributesFile->fcbClumpSize = vcb->vcbCatalogFile->fcbClumpSize;
else
vcb->vcbAttributesFile->fcbClumpSize =
alternateVolumeHeader->attributesFile.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 = (UInt64) (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 ?
record.hfsPlusFolder.userInfo.frFlags :
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 );
}
static int RecordBadExtent(SGlobPtr GPtr, UInt32 fileID, UInt8 forkType,
UInt32 startBlock, UInt32 badExtentIndex)
{
RepairOrderPtr p;
Boolean isHFSPlus;
isHFSPlus = VolumeObjectIsHFSPlus();
p = AllocMinorRepairOrder(GPtr, 0);
if (p == NULL) {
return(R_NoMem);
}
p->type = E_ExtEnt;
p->forkType = forkType;
p->correct = badExtentIndex;
p->hint = startBlock;
p->parid = fileID;
GPtr->CatStat |= S_BadExtent;
return (0);
}
OSErr CheckFileExtents( SGlobPtr GPtr, UInt32 fileNumber, UInt8 forkType,
const unsigned char *attrname, const void *extents,
UInt32 *blocksUsed)
{
UInt32 blockCount = 0;
UInt32 extentBlockCount;
UInt32 extentStartBlock;
UInt32 hint;
HFSPlusExtentKey key;
HFSPlusExtentKey extentKey;
HFSPlusExtentRecord extentRecord;
UInt16 recSize;
OSErr err = noErr;
SInt16 i;
Boolean firstRecord;
Boolean isHFSPlus;
unsigned int lastExtentIndex;
Boolean foundBadExtent;
if (forkType == kEAData) {
assert(attrname != NULL);
}
isHFSPlus = VolumeObjectIsHFSPlus( );
firstRecord = true;
foundBadExtent = false;
lastExtentIndex = GPtr->numExtents;
while ( (extents != nil) && (err == noErr) )
{
err = ChkExtRec( GPtr, extents, &lastExtentIndex );
if (err != noErr) {
dprintf (d_info, "%s: Bad extent for fileID %u in extent %u for startblock %u\n", __FUNCTION__, fileNumber, lastExtentIndex, blockCount);
if ((fileNumber < kHFSFirstUserCatalogNodeID) ||
(forkType == kEAData)) {
break;
}
(void) RecordBadExtent(GPtr, fileNumber, forkType, blockCount, lastExtentIndex);
foundBadExtent = true;
err = noErr;
}
for ( i=0 ; i<lastExtentIndex ; 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, (char *)attrname, extentStartBlock, extentBlockCount, forkType);
}
blockCount += extentBlockCount;
}
if ( fileNumber == kHFSExtentsFileID ) break;
if (foundBadExtent == true) {
break;
}
if (forkType == kEAData) {
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;
}
}
static OSErr AddExtentToOverlapList( SGlobPtr GPtr, HFSCatalogNodeID fileNumber, const char *attrname, UInt32 extentStartBlock, UInt32 extentBlockCount, UInt8 forkType )
{
UInt32 newHandleSize;
ExtentInfo extentInfo;
ExtentsTable **extentsTableH;
size_t attrlen;
ClearMemory(&extentInfo, sizeof(extentInfo));
extentInfo.fileID = fileNumber;
extentInfo.startBlock = extentStartBlock;
extentInfo.blockCount = extentBlockCount;
extentInfo.forkType = forkType;
if (forkType == kEAData) {
assert(attrname != NULL);
attrlen = strlen(attrname) + 1;
extentInfo.attrname = malloc(attrlen);
if (extentInfo.attrname == NULL) {
return(memFullErr);
}
strlcpy(extentInfo.attrname, attrname, attrlen);
}
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) );
GPtr->VIStat |= S_OverlappingExtents;
(**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->fileID == aryExtentInfo->fileID )
{
if ( (extentInfo->startBlock == aryExtentInfo->startBlock) &&
(extentInfo->blockCount == aryExtentInfo->blockCount) &&
(extentInfo->forkType == aryExtentInfo->forkType) )
{
if ((extentInfo->attrname == NULL) &&
(aryExtentInfo->attrname == NULL)) {
return(true);
}
if (((extentInfo->attrname != NULL) && (aryExtentInfo->attrname == NULL)) ||
((extentInfo->attrname == NULL) && (aryExtentInfo->attrname != NULL))) {
return(false);
}
if (!strcmp(extentInfo->attrname, aryExtentInfo->attrname)) {
return (true);
} else {
return (false);
}
}
}
}
return( false );
}
static Boolean DoesOverlap(SGlobPtr GPtr, UInt32 fileID, const char *attrname, UInt32 startBlock, UInt32 blockCount, UInt8 forkType)
{
int i;
Boolean isOverlapped = false;
ExtentInfo *curExtentInfo;
ExtentsTable **extentsTableH = GPtr->overlappedExtents;
for (i = 0; i < (**extentsTableH).count; i++) {
curExtentInfo = &((**extentsTableH).extentInfo[i]);
if (curExtentInfo->startBlock < startBlock) {
if ((curExtentInfo->startBlock + curExtentInfo->blockCount) > startBlock) {
isOverlapped = true;
break;
}
} else {
if (curExtentInfo->startBlock < (startBlock + blockCount)) {
isOverlapped = true;
break;
}
}
}
if (isOverlapped) {
AddExtentToOverlapList(GPtr, fileID, attrname, startBlock, blockCount, forkType);
}
return isOverlapped;
}
static void CheckHFSPlusExtentRecords(SGlobPtr GPtr, UInt32 fileID, const char *attrname, HFSPlusExtentRecord extent, UInt8 forkType)
{
int i;
for (i = 0; i < kHFSPlusExtentDensity; i++) {
if (extent[i].startBlock == 0) {
break;
}
DoesOverlap(GPtr, fileID, attrname, extent[i].startBlock, extent[i].blockCount, forkType);
}
return;
}
static void CheckHFSExtentRecords(SGlobPtr GPtr, UInt32 fileID, HFSExtentRecord extent, UInt8 forkType)
{
int i;
for (i = 0; i < kHFSExtentDensity; i++) {
if (extent[i].startBlock == 0) {
break;
}
DoesOverlap(GPtr, fileID, NULL, extent[i].startBlock, extent[i].blockCount, forkType);
}
return;
}
int FindOrigOverlapFiles(SGlobPtr GPtr)
{
OSErr err = noErr;
Boolean isHFSPlus;
UInt16 selCode;
UInt16 recordSize;
UInt32 hint;
CatalogRecord catRecord;
CatalogKey catKey;
ExtentRecord extentRecord;
ExtentKey extentKey;
HFSPlusAttrRecord attrRecord;
HFSPlusAttrKey attrKey;
char attrName[XATTR_MAXNAMELEN];
size_t len;
SVCB *calculatedVCB = GPtr->calculatedVCB;
isHFSPlus = VolumeObjectIsHFSPlus();
if (isHFSPlus) {
if (calculatedVCB->vcbAllocationFile) {
CheckHFSPlusExtentRecords(GPtr, calculatedVCB->vcbAllocationFile->fcbFileID, NULL,
calculatedVCB->vcbAllocationFile->fcbExtents32, kDataFork);
}
if (calculatedVCB->vcbExtentsFile) {
CheckHFSPlusExtentRecords(GPtr, calculatedVCB->vcbExtentsFile->fcbFileID, NULL,
calculatedVCB->vcbExtentsFile->fcbExtents32, kDataFork);
}
if (calculatedVCB->vcbCatalogFile) {
CheckHFSPlusExtentRecords(GPtr, calculatedVCB->vcbCatalogFile->fcbFileID, NULL,
calculatedVCB->vcbCatalogFile->fcbExtents32, kDataFork);
}
if (calculatedVCB->vcbAttributesFile) {
CheckHFSPlusExtentRecords(GPtr, calculatedVCB->vcbAttributesFile->fcbFileID, NULL,
calculatedVCB->vcbAttributesFile->fcbExtents32, kDataFork);
}
if (calculatedVCB->vcbStartupFile) {
CheckHFSPlusExtentRecords(GPtr, calculatedVCB->vcbStartupFile->fcbFileID, NULL,
calculatedVCB->vcbStartupFile->fcbExtents32, kDataFork);
}
} else {
if (calculatedVCB->vcbExtentsFile) {
CheckHFSExtentRecords(GPtr, calculatedVCB->vcbExtentsFile->fcbFileID,
calculatedVCB->vcbExtentsFile->fcbExtents16, kDataFork);
}
if (calculatedVCB->vcbCatalogFile) {
CheckHFSExtentRecords(GPtr, calculatedVCB->vcbCatalogFile->fcbFileID,
calculatedVCB->vcbCatalogFile->fcbExtents16, kDataFork);
}
}
selCode = 0x8001;
err = GetBTreeRecord(GPtr->calculatedCatalogFCB, selCode, &catKey, &catRecord, &recordSize, &hint);
if (err != noErr) {
goto traverseExtents;
}
selCode = 1;
do {
if ((catRecord.recordType == kHFSPlusFileRecord) ||
(catRecord.recordType == kHFSFileRecord)) {
if (isHFSPlus) {
CheckHFSPlusExtentRecords(GPtr, catRecord.hfsPlusFile.fileID, NULL,
catRecord.hfsPlusFile.dataFork.extents, kDataFork);
CheckHFSPlusExtentRecords(GPtr, catRecord.hfsPlusFile.fileID, NULL,
catRecord.hfsPlusFile.resourceFork.extents, kRsrcFork);
} else {
CheckHFSExtentRecords(GPtr, catRecord.hfsFile.fileID,
catRecord.hfsFile.dataExtents, kDataFork);
CheckHFSExtentRecords(GPtr, catRecord.hfsFile.fileID,
catRecord.hfsFile.rsrcExtents, kRsrcFork);
}
}
err = GetBTreeRecord( GPtr->calculatedCatalogFCB, selCode, &catKey, &catRecord, &recordSize, &hint );
} while (err == noErr);
traverseExtents:
selCode = 0x8001;
err = GetBTreeRecord(GPtr->calculatedExtentsFCB, selCode, &extentKey, &extentRecord, &recordSize, &hint);
if (err != noErr) {
goto traverseAttribute;
}
selCode = 1;
do {
if (isHFSPlus) {
CheckHFSPlusExtentRecords(GPtr, extentKey.hfsPlus.fileID, NULL,
extentRecord.hfsPlus, extentKey.hfsPlus.forkType);
} else {
CheckHFSExtentRecords(GPtr, extentKey.hfs.fileID, extentRecord.hfs,
extentKey.hfs.forkType);
}
err = GetBTreeRecord(GPtr->calculatedExtentsFCB, selCode, &extentKey, &extentRecord, &recordSize, &hint);
} while (err == noErr);
traverseAttribute:
if (!isHFSPlus) {
goto out;
}
selCode = 0x8001;
err = GetBTreeRecord(GPtr->calculatedAttributesFCB, selCode, &attrKey, &attrRecord, &recordSize, &hint);
if (err != noErr) {
goto out;
}
selCode = 1;
do {
if (attrRecord.recordType == kHFSPlusAttrForkData) {
(void) utf_encodestr(attrKey.attrName, attrKey.attrNameLen * 2, (unsigned char *)attrName, &len, sizeof(attrName));
attrName[len] = '\0';
CheckHFSPlusExtentRecords(GPtr, attrKey.fileID, attrName, attrRecord.forkData.theFork.extents, kEAData);
} else if (attrRecord.recordType == kHFSPlusAttrExtents) {
(void) utf_encodestr(attrKey.attrName, attrKey.attrNameLen * 2, (unsigned char *)attrName, &len, sizeof(attrName));
attrName[len] = '\0';
CheckHFSPlusExtentRecords(GPtr, attrKey.fileID, attrName, attrRecord.overflowExtents.extents, kEAData);
}
err = GetBTreeRecord(GPtr->calculatedAttributesFCB, selCode, &attrKey, &attrRecord, &recordSize, &hint);
} while (err == noErr);
out:
if (err == btNotFound) {
err = noErr;
}
return err;
}
void PrintOverlapFiles (SGlobPtr GPtr)
{
OSErr err;
ExtentsTable **extentsTableH;
ExtentInfo *extentInfo;
unsigned int numOverlapExtents;
unsigned int buflen, filepathlen;
char *filepath = NULL;
char filenum[32];
UInt32 lastID = 0;
UInt32 bytesWritten;
Boolean printMsg;
Boolean isHFSPlus;
int i;
isHFSPlus = VolumeObjectIsHFSPlus();
extentsTableH = GPtr->overlappedExtents;
numOverlapExtents = (**extentsTableH).count;
qsort((**extentsTableH).extentInfo, numOverlapExtents, sizeof(ExtentInfo),
CompareExtentFileID);
buflen = PATH_MAX * 4;
if (isHFSPlus) {
filepath = malloc (buflen);
}
for (i = 0; i < numOverlapExtents; i++) {
extentInfo = &((**extentsTableH).extentInfo[i]);
if (lastID == extentInfo->fileID) {
continue;
}
lastID = extentInfo->fileID;
printMsg = false;
if (filepath) {
bytesWritten = sprintf (filepath, "%u ", extentInfo->fileID);
filepathlen = buflen - bytesWritten;
if (extentInfo->fileID >= kHFSFirstUserCatalogNodeID) {
err = GetFileNamePathByID (GPtr, extentInfo->fileID, (filepath + bytesWritten), &filepathlen, NULL, NULL, NULL);
} else {
err = GetSystemFileName (extentInfo->fileID, (filepath + bytesWritten), &filepathlen);
}
if (err == noErr) {
PrintError(GPtr, E_OvlExt, 1, filepath);
printMsg = true;
}
if (GPtr->logLevel >= kDebugLog) {
plog ("\textentType=0x%x, startBlock=0x%x, blockCount=0x%x, attrName=%s\n",
extentInfo->forkType, extentInfo->startBlock, extentInfo->blockCount, extentInfo->attrname);
}
}
if (printMsg == false) {
sprintf(filenum, "%u", extentInfo->fileID);
PrintError(GPtr, E_OvlExt, 1, filenum);
}
}
if (filepath) {
free (filepath);
}
return;
}
static int CompareExtentFileID(const void *first, const void *second)
{
return (((ExtentInfo *)first)->fileID -
((ExtentInfo *)second)->fileID);
}
int journal_replay(SGlobPtr gptr)
{
int retval = 0;
struct vfsconf vfc;
int mib[3];
char *devnode;
size_t devnodelen;
if (gptr->deviceNode[0] == '\0') {
goto out;
}
retval = getvfsbyname("hfs", &vfc);
if (retval) {
goto out;
}
mib[0] = CTL_VFS;
mib[1] = vfc.vfc_typenum;
mib[2] = HFS_REPLAY_JOURNAL;
devnode = gptr->deviceNode;
devnodelen = strlen(devnode);
retval = sysctl(mib, 3, devnode, &devnodelen, NULL, 0);
if (retval) {
retval = errno;
}
out:
return retval;
}