#include "Scavenger.h"
static void CompareVolHeaderBTreeSizes( SGlobPtr GPtr,
VolumeObjectPtr theVOPtr,
HFSPlusVolumeHeader * thePriVHPtr,
HFSPlusVolumeHeader * theAltVHPtr );
static void GetEmbeddedVolumeHeaders( SGlobPtr GPtr,
HFSMasterDirectoryBlock * myMDBPtr,
Boolean isPrimaryMDB );
static OSErr GetVolumeObjectBlock( VolumeObjectPtr theVOPtr,
UInt64 theBlockNum,
BlockDescriptor * theBlockDescPtr );
static OSErr VolumeObjectFixPrimaryBlock( void );
int utf_encodestr(ucsp, ucslen, utf8p, utf8len)
const u_int16_t * ucsp;
size_t ucslen;
unsigned char * utf8p;
size_t * utf8len;
{
unsigned char * bufstart;
u_int16_t ucs_ch;
int charcnt;
bufstart = utf8p;
charcnt = ucslen / 2;
while (charcnt-- > 0) {
ucs_ch = *ucsp++;
if (ucs_ch < 0x0080) {
if (ucs_ch == '\0')
continue;
*utf8p++ = ucs_ch;
} else if (ucs_ch < 0x800) {
*utf8p++ = (ucs_ch >> 6) | 0xc0;
*utf8p++ = (ucs_ch & 0x3f) | 0x80;
} else {
*utf8p++ = (ucs_ch >> 12) | 0xe0;
*utf8p++ = ((ucs_ch >> 6) & 0x3f) | 0x80;
*utf8p++ = ((ucs_ch) & 0x3f) | 0x80;
}
}
*utf8len = utf8p - bufstart;
return (0);
}
int
utf_decodestr(utf8p, utf8len, ucsp, ucslen)
const unsigned char * utf8p;
size_t utf8len;
u_int16_t* ucsp;
size_t *ucslen;
{
u_int16_t* bufstart;
u_int16_t ucs_ch;
u_int8_t byte;
bufstart = ucsp;
while (utf8len-- > 0 && (byte = *utf8p++) != '\0') {
if (byte < 0x80) {
*ucsp++ = byte;
continue;
}
switch (byte & 0xf0) {
case 0xc0:
case 0xd0:
ucs_ch = (byte & 0x1F) << 6;
if (ucs_ch < 0x0080)
return (-1);
break;
case 0xe0:
ucs_ch = (byte & 0x0F) << 6;
if (((byte = *utf8p++) & 0xc0) != 0x80)
return (-1);
utf8len--;
ucs_ch += (byte & 0x3F);
ucs_ch <<= 6;
if (ucs_ch < 0x0800)
return (-1);
break;
default:
return (-1);
}
if (((byte = *utf8p++) & 0xc0) != 0x80)
return (-1);
utf8len--;
ucs_ch += (byte & 0x3F);
*ucsp++ = ucs_ch;
}
*ucslen = (u_int8_t*)ucsp - (u_int8_t*)bufstart;
return (0);
}
OSErr GetFBlk( SGlobPtr GPtr, SInt16 fileRefNum, SInt32 blockNumber, void **bufferH );
UInt32 gDFAStage;
UInt32 GetDFAStage( void )
{
return (gDFAStage);
}
void SetDFAStage( UInt32 stage )
{
gDFAStage = stage;
}
void RcdError( SGlobPtr GPtr, OSErr errorCode )
{
GPtr->ErrCode = errorCode;
WriteError( GPtr, errorCode, GPtr->TarID, GPtr->TarBlock ); }
int IntError( SGlobPtr GPtr, OSErr errorCode )
{
GPtr->RepLevel = repairLevelUnrepairable;
if ( errorCode == ioErr ) errorCode = R_RdErr;
if( (errorCode == R_RdErr) || (errorCode == R_WrErr) )
{
GPtr->ErrCode = GPtr->volumeErrorCode;
GPtr->IntErr = 0;
return( errorCode );
}
else
{
GPtr->ErrCode = R_IntErr;
GPtr->IntErr = errorCode;
return( R_IntErr );
}
}
int AllocBTN( SGlobPtr GPtr, SInt16 fileRefNum, UInt32 nodeNumber )
{
UInt16 bitPos;
unsigned char mask;
char *byteP;
BTreeControlBlock *calculatedBTCB = GetBTreeControlBlock( fileRefNum );
if ( calculatedBTCB->refCon == 0)
return( noErr );
byteP = ( (BTreeExtensionsRec*)calculatedBTCB->refCon)->BTCBMPtr + (nodeNumber / 8 ); bitPos = nodeNumber % 8; mask = ( 0x80 >> bitPos );
if ( (*byteP & mask) != 0 )
{
RcdError( GPtr, E_OvlNode );
return( E_OvlNode ); }
*byteP = *byteP | mask; calculatedBTCB->freeNodes--;
return( noErr );
}
OSErr GetBTreeHeader( SGlobPtr GPtr, SFCB *fcb, BTHeaderRec *header )
{
OSErr err;
BTHeaderRec *headerRec;
BlockDescriptor block;
GPtr->TarBlock = kHeaderNodeNum;
if (fcb->fcbBlockSize == 0)
(void) SetFileBlockSize(fcb, 512);
err = GetFileBlock(fcb, kHeaderNodeNum, kGetBlock, &block);
ReturnIfError(err);
SWAP_BT_NODE(&block, (fcb->fcbVolume->vcbSignature == kHFSPlusSigWord),
fcb->fcbFileID, 3);
headerRec = (BTHeaderRec *)((char*)block.buffer + sizeof(BTNodeDescriptor));
CopyMemory(headerRec, header, sizeof(BTHeaderRec));
SWAP_BT_NODE(&block, (fcb->fcbVolume->vcbSignature == kHFSPlusSigWord),
fcb->fcbFileID, 3);
err = ReleaseFileBlock (fcb, &block, kReleaseBlock);
ReturnIfError(err);
switch (header->nodeSize) {
case 512:
case 1024:
case 2048:
case 4096:
case 8192:
case 16384:
case 32768:
break;
default:
RcdError( GPtr, E_InvalidNodeSize );
err = E_InvalidNodeSize;
}
return( err );
}
RepairOrderPtr AllocMinorRepairOrder( SGlobPtr GPtr, int n )
{
RepairOrderPtr p;
n += sizeof( RepairOrder );
p = (RepairOrderPtr) AllocateClearMemory( n );
if ( p != NULL ) {
p->link = GPtr->MinorRepairsP; GPtr->MinorRepairsP = p;
}
else if ( GPtr->logLevel >= kDebugLog )
printf( "\t%s - AllocateClearMemory failed to allocate %d bytes \n", __FUNCTION__, n);
if ( GPtr->RepLevel == repairLevelNoProblemsFound )
GPtr->RepLevel = repairLevelVolumeRecoverable;
return( p ); }
void InvalidateCalculatedVolumeBitMap( SGlobPtr GPtr )
{
}
#if !BSD
OSErr GetVolumeFeatures( SGlobPtr GPtr )
{
OSErr err;
HParamBlockRec pb;
GetVolParmsInfoBuffer buffer;
long response;
GPtr->volumeFeatures = 0;
err = GetVCBDriveNum( &GPtr->realVCB, GPtr->DrvNum );
ReturnIfError( err );
if ( GPtr->realVCB != nil )
{
GPtr->volumeFeatures |= volumeIsMountedMask;
pb.ioParam.ioNamePtr = nil;
pb.ioParam.ioVRefNum = GPtr->realVCB->vcbVRefNum;
pb.ioParam.ioBuffer = (Ptr) &buffer;
pb.ioParam.ioReqCount = sizeof( buffer );
if ( PBHGetVolParms( &pb, false ) == noErr )
{
if ( buffer.vMAttrib & (1 << bSupportsTrashVolumeCache) )
GPtr->volumeFeatures |= supportsTrashVolumeCacheFeatureMask;
}
}
err = Gestalt( gestaltFSAttr, &response );
ReturnIfError( err );
if ( (response & (1 << gestaltFSSupportsHFSPlusVols)) != 0 )
GPtr->volumeFeatures |= supportsHFSPlusVolsFeatureMask;
return( noErr );
}
#endif
#if !BSD
void ClearMemory( void* start, UInt32 length )
{
UInt32 zero = 0;
UInt32* dataPtr;
UInt8* bytePtr;
UInt32 fragCount;
if ( length == 0 )
return;
if ( length < 4 ) {
bytePtr = (UInt8 *) start;
do
{
*bytePtr++ = zero; }
while ( --length );
return;
}
fragCount = (UInt32) start & 3;
if ( fragCount ) {
bytePtr = (UInt8 *) start;
do
{
*bytePtr++ = zero; ++fragCount;
--length;
}
while ( (fragCount < 4) && (length > 0) );
if ( length == 0 )
return;
dataPtr = (UInt32*) (((UInt32) start & 0xFFFFFFFC) + 4); }
else
{
dataPtr = (UInt32*) ((UInt32) start & 0xFFFFFFFC); }
fragCount = length & 3;
if ( fragCount )
{
bytePtr = (UInt8 *) ((UInt32) dataPtr + (UInt32) length - 1);
length -= fragCount;
do
{
*bytePtr-- = zero; }
while ( --fragCount );
if ( length == 0 )
return;
}
#if DEBUG_BUILD
if ( length < 4 )
DebugStr("\p ClearMemory: length < 4");
#endif
fragCount = length & (64-1);
#if DEBUG_BUILD
if ( fragCount < 4 && fragCount > 0 )
DebugStr("\p ClearMemory: fragCount < 4");
#endif
if ( fragCount )
{
length -= fragCount; fragCount >>= 2; do
{
*dataPtr++ = zero;
}
while (--fragCount);
}
if ( length == 0 )
return;
length >>= 6; do
{
*dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero;
*dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero;
*dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero;
*dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero;
}
while (--length);
}
#endif
void
CopyCatalogName(const CatalogName *srcName, CatalogName *dstName, Boolean isHFSPLus)
{
UInt32 length;
if ( srcName == NULL )
{
if ( dstName != NULL )
dstName->ustr.length = 0; return;
}
if (isHFSPLus)
length = sizeof(UniChar) * (srcName->ustr.length + 1);
else
length = sizeof(UInt8) + srcName->pstr[0];
if ( length > 1 )
CopyMemory(srcName, dstName, length);
else
dstName->ustr.length = 0; }
UInt32
CatalogNameLength(const CatalogName *name, Boolean isHFSPlus)
{
if (isHFSPlus)
return name->ustr.length;
else
return name->pstr[0];
}
UInt32 CatalogNameSize( const CatalogName *name, Boolean isHFSPlus)
{
UInt32 length = CatalogNameLength( name, isHFSPlus );
if ( isHFSPlus )
length *= sizeof(UniChar);
return( length );
}
void
BuildCatalogKey(HFSCatalogNodeID parentID, const CatalogName *cName, Boolean isHFSPlus, CatalogKey *key)
{
if ( isHFSPlus )
{
key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength; key->hfsPlus.parentID = parentID; key->hfsPlus.nodeName.length = 0; if ( cName != NULL )
{
CopyCatalogName(cName, (CatalogName *) &key->hfsPlus.nodeName, isHFSPlus);
key->hfsPlus.keyLength += sizeof(UniChar) * cName->ustr.length; }
}
else
{
key->hfs.keyLength = kHFSCatalogKeyMinimumLength; key->hfs.reserved = 0; key->hfs.parentID = parentID; key->hfs.nodeName[0] = 0; if ( cName != NULL )
{
UpdateCatalogName(cName->pstr, key->hfs.nodeName);
key->hfs.keyLength += key->hfs.nodeName[0]; }
}
}
SInt32 CompareKeys( BTreeControlBlockPtr btreePtr, KeyPtr searchKey, KeyPtr trialKey )
{
KeyCompareProcPtr compareProc = (KeyCompareProcPtr)btreePtr->keyCompareProc;
return( compareProc(searchKey, trialKey) );
}
void
UpdateCatalogName(ConstStr31Param srcName, Str31 destName)
{
Size length = srcName[0];
if (length > kHFSMaxFileNameChars)
length = kHFSMaxFileNameChars;
destName[0] = length;
CopyMemory(&srcName[1], &destName[1], length);
}
void
UpdateVolumeEncodings(SVCB *volume, TextEncoding encoding)
{
UInt32 index;
encoding &= 0x7F;
index = MapEncodingToIndex(encoding);
volume->vcbEncodingsBitmap |= (u_int64_t)(1ULL << index);
}
static OSErr VolumeObjectFixPrimaryBlock( void )
{
OSErr err;
VolumeObjectPtr myVOPtr;
UInt64 myPrimaryBlockNum;
BlockDescriptor myPrimary;
BlockDescriptor myAlternate;
myVOPtr = GetVolumeObjectPtr( );
myPrimary.buffer = NULL;
myAlternate.buffer = NULL;
GetVolumeObjectPrimaryBlockNum( &myPrimaryBlockNum );
if ( myPrimaryBlockNum == 0 )
return( noMacDskErr );
err = GetVolumeObjectPrimaryBlock( &myPrimary );
if ( !(err == noErr || err == badMDBErr || err == noMacDskErr) )
goto ExitThisRoutine;
err = GetVolumeObjectAlternateBlock( &myAlternate );
if ( VolumeObjectIsHFS( ) ) {
if ( (myVOPtr->flags & kVO_AltMDBOK) == 0 )
err = badMDBErr;
}
else if ( (myVOPtr->flags & kVO_AltVHBOK) == 0 ) {
err = badMDBErr;
}
if ( err == noErr ) {
CopyMemory( myAlternate.buffer, myPrimary.buffer, Blk_Size );
(void) ReleaseVolumeBlock( myVOPtr->vcbPtr, &myPrimary, kForceWriteBlock );
myPrimary.buffer = NULL;
if ( myVOPtr->volumeType == kHFSVolumeType )
myVOPtr->flags |= kVO_PriMDBOK;
else
myVOPtr->flags |= kVO_PriVHBOK;
}
ExitThisRoutine:
if ( myPrimary.buffer != NULL )
(void) ReleaseVolumeBlock( myVOPtr->vcbPtr, &myPrimary, kReleaseBlock );
if ( myAlternate.buffer != NULL )
(void) ReleaseVolumeBlock( myVOPtr->vcbPtr, &myAlternate, kReleaseBlock );
return( err );
}
OSErr GetVolumeObjectVHBorMDB( BlockDescriptor * theBlockDescPtr )
{
UInt64 myBlockNum;
VolumeObjectPtr myVOPtr;
OSErr err;
myVOPtr = GetVolumeObjectPtr( );
GetVolumeObjectBlockNum( &myBlockNum );
err = GetVolumeObjectBlock( myVOPtr, myBlockNum, theBlockDescPtr );
if ( err == noErr )
{
if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType ||
myVOPtr->volumeType == kPureHFSPlusVolumeType )
{
err = ValidVolumeHeader( (HFSPlusVolumeHeader*) theBlockDescPtr->buffer );
}
else if ( myVOPtr->volumeType == kHFSVolumeType )
{
HFSMasterDirectoryBlock * myMDBPtr;
myMDBPtr = (HFSMasterDirectoryBlock *) theBlockDescPtr->buffer;
if ( myMDBPtr->drSigWord != kHFSSigWord )
err = noMacDskErr;
}
else
err = noMacDskErr;
}
return( err );
}
OSErr GetVolumeObjectAlternateBlock( BlockDescriptor * theBlockDescPtr )
{
UInt64 myBlockNum;
VolumeObjectPtr myVOPtr;
OSErr err;
myVOPtr = GetVolumeObjectPtr( );
GetVolumeObjectAlternateBlockNum( &myBlockNum );
err = GetVolumeObjectBlock( myVOPtr, myBlockNum, theBlockDescPtr );
if ( err == noErr )
{
if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType ||
myVOPtr->volumeType == kPureHFSPlusVolumeType )
{
err = ValidVolumeHeader( (HFSPlusVolumeHeader*) theBlockDescPtr->buffer );
}
else if ( myVOPtr->volumeType == kHFSVolumeType )
{
HFSMasterDirectoryBlock * myMDBPtr;
myMDBPtr = (HFSMasterDirectoryBlock *) theBlockDescPtr->buffer;
if ( myMDBPtr->drSigWord != kHFSSigWord )
err = noMacDskErr;
}
else
err = noMacDskErr;
}
return( err );
}
OSErr GetVolumeObjectPrimaryBlock( BlockDescriptor * theBlockDescPtr )
{
UInt64 myBlockNum;
VolumeObjectPtr myVOPtr;
OSErr err;
myVOPtr = GetVolumeObjectPtr( );
GetVolumeObjectPrimaryBlockNum( &myBlockNum );
err = GetVolumeObjectBlock( myVOPtr, myBlockNum, theBlockDescPtr );
if ( err == noErr )
{
if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType ||
myVOPtr->volumeType == kPureHFSPlusVolumeType )
{
err = ValidVolumeHeader( (HFSPlusVolumeHeader*) theBlockDescPtr->buffer );
}
else if ( myVOPtr->volumeType == kHFSVolumeType )
{
HFSMasterDirectoryBlock * myMDBPtr;
myMDBPtr = (HFSMasterDirectoryBlock *) theBlockDescPtr->buffer;
if ( myMDBPtr->drSigWord != kHFSSigWord )
err = noMacDskErr;
}
else
err = noMacDskErr;
}
return( err );
}
OSErr GetVolumeObjectVHB( BlockDescriptor * theBlockDescPtr )
{
UInt64 myBlockNum;
VolumeObjectPtr myVOPtr;
OSErr err;
myVOPtr = GetVolumeObjectPtr( );
myBlockNum = ((myVOPtr->flags & kVO_AltVHBOK) != 0) ? myVOPtr->alternateVHB : myVOPtr->primaryVHB;
err = GetVolumeObjectBlock( myVOPtr, myBlockNum, theBlockDescPtr );
if ( err == noErr )
err = ValidVolumeHeader( (HFSPlusVolumeHeader*) theBlockDescPtr->buffer );
return( err );
}
OSErr GetVolumeObjectAlternateMDB( BlockDescriptor * theBlockDescPtr )
{
VolumeObjectPtr myVOPtr;
OSErr err;
myVOPtr = GetVolumeObjectPtr( );
err = GetVolumeObjectBlock( NULL, myVOPtr->alternateMDB, theBlockDescPtr );
if ( err == noErr )
{
HFSMasterDirectoryBlock * myMDBPtr;
myMDBPtr = (HFSMasterDirectoryBlock *) theBlockDescPtr->buffer;
if ( myMDBPtr->drSigWord != kHFSSigWord )
err = noMacDskErr;
}
return( err );
}
OSErr GetVolumeObjectPrimaryMDB( BlockDescriptor * theBlockDescPtr )
{
VolumeObjectPtr myVOPtr;
OSErr err;
myVOPtr = GetVolumeObjectPtr( );
err = GetVolumeObjectBlock( NULL, myVOPtr->primaryMDB, theBlockDescPtr );
if ( err == noErr )
{
HFSMasterDirectoryBlock * myMDBPtr;
myMDBPtr = (HFSMasterDirectoryBlock *) theBlockDescPtr->buffer;
if ( myMDBPtr->drSigWord != kHFSSigWord )
err = noMacDskErr;
}
return( err );
}
static OSErr GetVolumeObjectBlock( VolumeObjectPtr theVOPtr,
UInt64 theBlockNum,
BlockDescriptor * theBlockDescPtr )
{
OSErr err;
if ( theVOPtr == NULL )
theVOPtr = GetVolumeObjectPtr( );
err = GetVolumeBlock( theVOPtr->vcbPtr, theBlockNum, kGetBlock, theBlockDescPtr );
return( err );
}
void GetVolumeObjectBlockNum( UInt64 * theBlockNumPtr )
{
VolumeObjectPtr myVOPtr;
myVOPtr = GetVolumeObjectPtr( );
*theBlockNumPtr = 0;
if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType ||
myVOPtr->volumeType == kPureHFSPlusVolumeType ) {
if ( (myVOPtr->flags & kVO_AltVHBOK) != 0 )
*theBlockNumPtr = myVOPtr->alternateVHB;
else
*theBlockNumPtr = myVOPtr->primaryVHB;
}
else if ( myVOPtr->volumeType == kHFSVolumeType ) {
if ( (myVOPtr->flags & kVO_AltMDBOK) != 0 )
*theBlockNumPtr = myVOPtr->alternateMDB;
else
*theBlockNumPtr = myVOPtr->primaryMDB;
}
return;
}
void GetVolumeObjectAlternateBlockNum( UInt64 * theBlockNumPtr )
{
VolumeObjectPtr myVOPtr;
myVOPtr = GetVolumeObjectPtr( );
*theBlockNumPtr = 0;
if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType ||
myVOPtr->volumeType == kPureHFSPlusVolumeType ) {
*theBlockNumPtr = myVOPtr->alternateVHB;
}
else if ( myVOPtr->volumeType == kHFSVolumeType ) {
*theBlockNumPtr = myVOPtr->alternateMDB;
}
return;
}
void GetVolumeObjectPrimaryBlockNum( UInt64 * theBlockNumPtr )
{
VolumeObjectPtr myVOPtr;
myVOPtr = GetVolumeObjectPtr( );
*theBlockNumPtr = 0;
if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType ||
myVOPtr->volumeType == kPureHFSPlusVolumeType ) {
*theBlockNumPtr = myVOPtr->primaryVHB;
}
else if ( myVOPtr->volumeType == kHFSVolumeType ) {
*theBlockNumPtr = myVOPtr->primaryMDB;
}
return;
}
void InitializeVolumeObject( SGlobPtr GPtr )
{
OSErr err;
HFSMasterDirectoryBlock * myMDBPtr;
HFSPlusVolumeHeader * myVHPtr;
VolumeObjectPtr myVOPtr;
HFSPlusVolumeHeader myPriVolHeader;
BlockDescriptor myBlockDescriptor;
myBlockDescriptor.buffer = NULL;
myVOPtr = GetVolumeObjectPtr( );
myVOPtr->flags |= kVO_Inited;
myVOPtr->vcbPtr = GPtr->calculatedVCB;
err = GetDeviceSize( GPtr->calculatedVCB->vcbDriveNumber,
&myVOPtr->totalDeviceSectors,
&myVOPtr->sectorSize );
if ( (myVOPtr->totalDeviceSectors < 3) || (err != noErr) ) {
if ( GPtr->logLevel >= kDebugLog ) {
printf("\tinvalid device information for volume - total sectors = %qd sector size = %d \n",
myVOPtr->totalDeviceSectors, myVOPtr->sectorSize);
}
goto ExitRoutine;
}
err = GetVolumeObjectBlock( myVOPtr, MDB_BlkN, &myBlockDescriptor );
if ( err == noErr ) {
myMDBPtr = (HFSMasterDirectoryBlock *) myBlockDescriptor.buffer;
if ( myMDBPtr->drSigWord == kHFSPlusSigWord || myMDBPtr->drSigWord == kHFSXSigWord) {
myVHPtr = (HFSPlusVolumeHeader *) myMDBPtr;
myVOPtr->primaryVHB = MDB_BlkN; myVOPtr->alternateVHB = myVOPtr->totalDeviceSectors - 2; err = ValidVolumeHeader( myVHPtr );
if ( err == noErr ) {
myVOPtr->flags |= kVO_PriVHBOK;
bcopy( myVHPtr, &myPriVolHeader, sizeof( *myVHPtr ) );
}
else {
if ( GPtr->logLevel >= kDebugLog ) {
printf( "\tInvalid primary volume header - error %d \n", err );
}
}
}
else if ( myMDBPtr->drSigWord == kHFSSigWord ) {
myVOPtr->primaryMDB = MDB_BlkN; myVOPtr->alternateMDB = myVOPtr->totalDeviceSectors - 2; myVOPtr->flags |= kVO_PriMDBOK;
}
else {
if ( GPtr->logLevel >= kDebugLog ) {
printf( "\tBlock %d is not an MDB or Volume Header \n", MDB_BlkN );
}
}
(void) ReleaseVolumeBlock( GPtr->calculatedVCB, &myBlockDescriptor, kReleaseBlock );
}
else {
if ( GPtr->logLevel >= kDebugLog ) {
printf( "\tcould not get volume block %d, err %d \n", MDB_BlkN, err );
}
}
err = GetVolumeObjectBlock( myVOPtr, myVOPtr->totalDeviceSectors - 2, &myBlockDescriptor );
if ( err == noErr ) {
myMDBPtr = (HFSMasterDirectoryBlock *) myBlockDescriptor.buffer;
if ( myMDBPtr->drSigWord == kHFSPlusSigWord || myMDBPtr->drSigWord == kHFSXSigWord ) {
myVHPtr = (HFSPlusVolumeHeader *) myMDBPtr;
myVOPtr->primaryVHB = MDB_BlkN; myVOPtr->alternateVHB = myVOPtr->totalDeviceSectors - 2; err = ValidVolumeHeader( myVHPtr );
if ( err == noErr ) {
myVOPtr->flags |= kVO_AltVHBOK;
CompareVolHeaderBTreeSizes( GPtr, myVOPtr, &myPriVolHeader, myVHPtr );
}
else {
if ( GPtr->logLevel >= kDebugLog ) {
printf( "\tInvalid alternate volume header - error %d \n", err );
}
}
}
else if ( myMDBPtr->drSigWord == kHFSSigWord ) {
myVOPtr->primaryMDB = MDB_BlkN; myVOPtr->alternateMDB = myVOPtr->totalDeviceSectors - 2; myVOPtr->flags |= kVO_AltMDBOK;
}
else {
if ( GPtr->logLevel >= kDebugLog ) {
printf( "\tBlock %qd is not an MDB or Volume Header \n", myVOPtr->totalDeviceSectors - 2 );
}
}
(void) ReleaseVolumeBlock( GPtr->calculatedVCB, &myBlockDescriptor, kReleaseBlock );
}
else {
if ( GPtr->logLevel >= kDebugLog ) {
printf( "\tcould not get alternate volume header at %qd, err %d \n",
myVOPtr->totalDeviceSectors - 2, err );
}
}
if ( (myVOPtr->flags & kVO_AltMDBOK) != 0 ) {
err = GetVolumeObjectBlock( myVOPtr, myVOPtr->alternateMDB, &myBlockDescriptor );
if ( err == noErr ) {
myMDBPtr = (HFSMasterDirectoryBlock *) myBlockDescriptor.buffer;
GetEmbeddedVolumeHeaders( GPtr, myMDBPtr, false );
(void) ReleaseVolumeBlock( GPtr->calculatedVCB, &myBlockDescriptor, kReleaseBlock );
}
}
if ( (myVOPtr->flags & kVO_PriMDBOK) != 0 &&
((myVOPtr->flags & kVO_PriVHBOK) == 0 || (myVOPtr->flags & kVO_AltVHBOK) == 0) ) {
err = GetVolumeObjectBlock( myVOPtr, myVOPtr->primaryMDB, &myBlockDescriptor );
if ( err == noErr ) {
myMDBPtr = (HFSMasterDirectoryBlock *) myBlockDescriptor.buffer;
GetEmbeddedVolumeHeaders( GPtr, myMDBPtr, true );
(void) ReleaseVolumeBlock( GPtr->calculatedVCB, &myBlockDescriptor, kReleaseBlock );
}
else {
if ( GPtr->logLevel >= kDebugLog ) {
printf( "\tcould not get primary MDB at block %qd, err %d \n", myVOPtr->primaryMDB, err );
}
}
}
ExitRoutine:
if ( ((myVOPtr->flags & kVO_PriVHBOK) != 0 || (myVOPtr->flags & kVO_AltVHBOK) != 0) &&
((myVOPtr->flags & kVO_PriMDBOK) != 0 || (myVOPtr->flags & kVO_AltMDBOK) != 0) ) {
myVOPtr->volumeType = kEmbededHFSPlusVolumeType;
}
else if ( ((myVOPtr->flags & kVO_PriVHBOK) != 0 || (myVOPtr->flags & kVO_AltVHBOK) != 0) &&
(myVOPtr->flags & kVO_PriMDBOK) == 0 && (myVOPtr->flags & kVO_AltMDBOK) == 0 ) {
myVOPtr->volumeType = kPureHFSPlusVolumeType;
}
else if ( (myVOPtr->flags & kVO_PriVHBOK) == 0 && (myVOPtr->flags & kVO_AltVHBOK) == 0 &&
((myVOPtr->flags & kVO_PriMDBOK) != 0 || (myVOPtr->flags & kVO_AltMDBOK) != 0) ) {
myVOPtr->volumeType = kHFSVolumeType;
}
else
myVOPtr->volumeType = kUnknownVolumeType;
return;
}
void PrintVolumeObject( void )
{
VolumeObjectPtr myVOPtr;
myVOPtr = GetVolumeObjectPtr( );
if ( myVOPtr->volumeType == kHFSVolumeType )
printf( "\tvolume type is HFS \n" );
else if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType )
printf( "\tvolume type is embedded HFS+ \n" );
else if ( myVOPtr->volumeType == kPureHFSPlusVolumeType )
printf( "\tvolume type is pure HFS+ \n" );
else
printf( "\tunknown volume type \n" );
printf( "\tprimary MDB is at block %qd 0x%02qx \n", myVOPtr->primaryMDB, myVOPtr->primaryMDB );
printf( "\talternate MDB is at block %qd 0x%02qx \n", myVOPtr->alternateMDB, myVOPtr->alternateMDB );
printf( "\tprimary VHB is at block %qd 0x%02qx \n", myVOPtr->primaryVHB, myVOPtr->primaryVHB );
printf( "\talternate VHB is at block %qd 0x%02qx \n", myVOPtr->alternateVHB, myVOPtr->alternateVHB );
printf( "\tsector size = %d 0x%02x \n", myVOPtr->sectorSize, myVOPtr->sectorSize );
printf( "\tVolumeObject flags = 0x%02X \n", myVOPtr->flags );
printf( "\ttotal sectors for volume = %qd 0x%02qx \n",
myVOPtr->totalDeviceSectors, myVOPtr->totalDeviceSectors );
printf( "\ttotal sectors for embedded volume = %qd 0x%02qx \n",
myVOPtr->totalEmbeddedSectors, myVOPtr->totalEmbeddedSectors );
return;
}
static void GetEmbeddedVolumeHeaders( SGlobPtr GPtr,
HFSMasterDirectoryBlock * theMDBPtr,
Boolean isPrimaryMDB )
{
OSErr err;
HFSPlusVolumeHeader * myVHPtr;
VolumeObjectPtr myVOPtr;
UInt64 myHFSPlusSectors;
UInt64 myPrimaryBlockNum;
UInt64 myAlternateBlockNum;
HFSPlusVolumeHeader myAltVolHeader;
BlockDescriptor myBlockDescriptor;
myBlockDescriptor.buffer = NULL;
myVOPtr = GetVolumeObjectPtr( );
if ( theMDBPtr->drEmbedSigWord == 0 &&
theMDBPtr->drEmbedExtent.blockCount == 0 &&
theMDBPtr->drEmbedExtent.startBlock == 0 ) {
goto ExitRoutine;
}
myHFSPlusSectors = (theMDBPtr->drAlBlkSiz / Blk_Size) * theMDBPtr->drEmbedExtent.blockCount;
myVOPtr->embeddedOffset =
(theMDBPtr->drEmbedExtent.startBlock * theMDBPtr->drAlBlkSiz) +
(theMDBPtr->drAlBlSt * Blk_Size);
myAlternateBlockNum =
theMDBPtr->drAlBlSt +
((theMDBPtr->drAlBlkSiz / Blk_Size) * theMDBPtr->drEmbedExtent.startBlock) +
myHFSPlusSectors - 2;
myPrimaryBlockNum = (theMDBPtr->drEmbedExtent.startBlock * theMDBPtr->drAlBlkSiz / Blk_Size) +
theMDBPtr->drAlBlSt + 2;
err = GetVolumeObjectBlock( myVOPtr, myAlternateBlockNum, &myBlockDescriptor );
if ( err == noErr ) {
myVHPtr = (HFSPlusVolumeHeader *) myBlockDescriptor.buffer;
if ( myVHPtr->signature == kHFSPlusSigWord ) {
myVOPtr->alternateVHB = myAlternateBlockNum; myVOPtr->primaryVHB = myPrimaryBlockNum; err = ValidVolumeHeader( myVHPtr );
if ( err == noErr ) {
myVOPtr->flags |= kVO_AltVHBOK;
myVOPtr->totalEmbeddedSectors = myHFSPlusSectors;
bcopy( myVHPtr, &myAltVolHeader, sizeof( *myVHPtr ) );
}
else {
if ( GPtr->logLevel >= kDebugLog ) {
printf( "\tInvalid embedded alternate volume header at block %qd - error %d \n", myAlternateBlockNum, err );
}
}
}
else {
if ( GPtr->logLevel >= kDebugLog ) {
printf( "\tBlock number %qd is not embedded alternate volume header \n", myAlternateBlockNum );
}
}
(void) ReleaseVolumeBlock( GPtr->calculatedVCB, &myBlockDescriptor, kReleaseBlock );
}
else {
if ( GPtr->logLevel >= kDebugLog ) {
printf( "\tcould not get embedded alternate volume header at %qd, err %d \n",
myAlternateBlockNum, err );
}
}
err = GetVolumeObjectBlock( myVOPtr, myPrimaryBlockNum, &myBlockDescriptor );
if ( err == noErr ) {
myVHPtr = (HFSPlusVolumeHeader *) myBlockDescriptor.buffer;
if ( myVHPtr->signature == kHFSPlusSigWord ) {
myVOPtr->primaryVHB = myPrimaryBlockNum; myVOPtr->alternateVHB = myAlternateBlockNum; err = ValidVolumeHeader( myVHPtr );
if ( err == noErr ) {
myVOPtr->flags |= kVO_PriVHBOK;
myVOPtr->totalEmbeddedSectors = myHFSPlusSectors;
CompareVolHeaderBTreeSizes( GPtr, myVOPtr, myVHPtr, &myAltVolHeader );
}
else {
if ( GPtr->logLevel >= kDebugLog ) {
printf( "\tInvalid embedded primary volume header at block %qd - error %d \n", myPrimaryBlockNum, err );
}
}
}
else {
if ( GPtr->logLevel >= kDebugLog ) {
printf( "\tBlock number %qd is not embedded primary volume header \n", myPrimaryBlockNum );
}
}
(void) ReleaseVolumeBlock( GPtr->calculatedVCB, &myBlockDescriptor, kReleaseBlock );
}
else {
if ( GPtr->logLevel >= kDebugLog ) {
printf( "\tcould not get embedded primary volume header at %qd, err %d \n",
myPrimaryBlockNum, err );
}
}
ExitRoutine:
return;
}
static void CompareVolHeaderBTreeSizes( SGlobPtr GPtr,
VolumeObjectPtr theVOPtr,
HFSPlusVolumeHeader * thePriVHPtr,
HFSPlusVolumeHeader * theAltVHPtr )
{
int weDisagree;
int usePrimary;
int useAlternate;
weDisagree = usePrimary = useAlternate = 0;
if ( (theVOPtr->flags & kVO_PriVHBOK) == 0 || (theVOPtr->flags & kVO_AltVHBOK) == 0 )
return;
if ( thePriVHPtr->catalogFile.totalBlocks != theAltVHPtr->catalogFile.totalBlocks ) {
if ( thePriVHPtr->catalogFile.extents[0].startBlock == theAltVHPtr->catalogFile.extents[0].startBlock ) {
weDisagree = 1;
if ( thePriVHPtr->catalogFile.totalBlocks > theAltVHPtr->catalogFile.totalBlocks )
usePrimary = 1;
else
useAlternate = 1;
if ( GPtr->logLevel >= kDebugLog ) {
printf( "\tvolume headers disagree on catalog file total blocks - primary %d alternate %d \n",
thePriVHPtr->catalogFile.totalBlocks, theAltVHPtr->catalogFile.totalBlocks );
}
}
}
if ( thePriVHPtr->extentsFile.totalBlocks != theAltVHPtr->extentsFile.totalBlocks ) {
if ( thePriVHPtr->extentsFile.extents[0].startBlock == theAltVHPtr->extentsFile.extents[0].startBlock ) {
weDisagree = 1;
if ( thePriVHPtr->extentsFile.totalBlocks > theAltVHPtr->extentsFile.totalBlocks )
usePrimary = 1;
else
useAlternate = 1;
if ( GPtr->logLevel >= kDebugLog ) {
printf( "\tvolume headers disagree on extents file total blocks - primary %d alternate %d \n",
thePriVHPtr->extentsFile.totalBlocks, theAltVHPtr->extentsFile.totalBlocks );
}
}
}
if ( weDisagree == 0 )
return;
if ( usePrimary == 1 && useAlternate == 1 ) {
if ( GPtr->logLevel >= kDebugLog ) {
printf( "\tvolume headers disagree but there is confusion on which to use \n" );
}
return;
}
if ( usePrimary == 1 ) {
theVOPtr->flags &= ~kVO_AltVHBOK;
}
else if ( useAlternate == 1 ) {
theVOPtr->flags &= ~kVO_PriVHBOK;
}
return;
}
Boolean VolumeObjectIsHFSPlus( void )
{
VolumeObjectPtr myVOPtr;
myVOPtr = GetVolumeObjectPtr( );
if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType ||
myVOPtr->volumeType == kPureHFSPlusVolumeType ) {
return( true );
}
return( false );
}
Boolean VolumeObjectIsHFS( void )
{
VolumeObjectPtr myVOPtr;
myVOPtr = GetVolumeObjectPtr( );
if ( myVOPtr->volumeType == kHFSVolumeType )
return( true );
return( false );
}
Boolean VolumeObjectIsEmbeddedHFSPlus( void )
{
VolumeObjectPtr myVOPtr;
myVOPtr = GetVolumeObjectPtr( );
if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType )
return( true );
return( false );
}
Boolean VolumeObjectIsPureHFSPlus( void )
{
VolumeObjectPtr myVOPtr;
myVOPtr = GetVolumeObjectPtr( );
if ( myVOPtr->volumeType == kPureHFSPlusVolumeType )
return( true );
return( false );
}
VolumeObjectPtr GetVolumeObjectPtr( void )
{
static VolumeObject myVolumeObject;
static int myInited = 0;
if ( myInited == 0 ) {
myInited++;
bzero( &myVolumeObject, sizeof(myVolumeObject) );
}
return( &myVolumeObject );
}
void CheckEmbeddedVolInfoInMDBs( SGlobPtr GPtr )
{
OSErr err;
Boolean primaryIsDamaged = false;
Boolean alternateIsDamaged = false;
VolumeObjectPtr myVOPtr;
HFSMasterDirectoryBlock * myPriMDBPtr;
HFSMasterDirectoryBlock * myAltMDBPtr;
UInt64 myOffset;
UInt64 mySectors;
BlockDescriptor myPrimary;
BlockDescriptor myAlternate;
myVOPtr = GetVolumeObjectPtr( );
myPrimary.buffer = NULL;
myAlternate.buffer = NULL;
if ( VolumeObjectIsEmbeddedHFSPlus( ) == false ||
(myVOPtr->flags & kVO_PriMDBOK) == 0 || (myVOPtr->flags & kVO_AltMDBOK) == 0 )
return;
err = GetVolumeObjectPrimaryMDB( &myPrimary );
if ( err != noErr ) {
if ( GPtr->logLevel >= kDebugLog ) {
printf( "\tcould not get primary MDB \n" );
}
goto ExitThisRoutine;
}
myPriMDBPtr = (HFSMasterDirectoryBlock *) myPrimary.buffer;
err = GetVolumeObjectAlternateMDB( &myAlternate );
if ( err != noErr ) {
if ( GPtr->logLevel >= kDebugLog ) {
printf( "\tcould not get alternate MDB \n" );
}
goto ExitThisRoutine;
}
myAltMDBPtr = (HFSMasterDirectoryBlock *) myAlternate.buffer;
if ( myPriMDBPtr->drEmbedSigWord == kHFSPlusSigWord &&
myAltMDBPtr->drEmbedSigWord == kHFSPlusSigWord &&
myPriMDBPtr->drEmbedExtent.blockCount == myAltMDBPtr->drEmbedExtent.blockCount &&
myPriMDBPtr->drEmbedExtent.startBlock == myAltMDBPtr->drEmbedExtent.startBlock )
goto ExitThisRoutine;
myOffset = (myPriMDBPtr->drEmbedExtent.startBlock * myPriMDBPtr->drAlBlkSiz) +
(myPriMDBPtr->drAlBlSt * Blk_Size);
mySectors = (myPriMDBPtr->drAlBlkSiz / Blk_Size) * myPriMDBPtr->drEmbedExtent.blockCount;
if ( myOffset != myVOPtr->embeddedOffset || mySectors != myVOPtr->totalEmbeddedSectors )
primaryIsDamaged = true;
myOffset = (myAltMDBPtr->drEmbedExtent.startBlock * myAltMDBPtr->drAlBlkSiz) +
(myAltMDBPtr->drAlBlSt * Blk_Size);
mySectors = (myAltMDBPtr->drAlBlkSiz / Blk_Size) * myAltMDBPtr->drEmbedExtent.blockCount;
if ( myOffset != myVOPtr->embeddedOffset || mySectors != myVOPtr->totalEmbeddedSectors )
alternateIsDamaged = true;
if ( primaryIsDamaged == false && alternateIsDamaged == false ) {
if ( myPriMDBPtr->drEmbedSigWord != kHFSPlusSigWord )
primaryIsDamaged = true;
else if ( myAltMDBPtr->drEmbedSigWord != kHFSPlusSigWord )
alternateIsDamaged = true;
}
if ( primaryIsDamaged || alternateIsDamaged ) {
GPtr->VIStat |= S_WMDB;
WriteError( GPtr, E_MDBDamaged, 7, 0 );
if ( primaryIsDamaged ) {
myVOPtr->flags &= ~kVO_PriMDBOK; if ( GPtr->logLevel >= kDebugLog )
printf("\tinvalid primary wrapper MDB \n");
}
else {
myVOPtr->flags &= ~kVO_AltMDBOK; if ( GPtr->logLevel >= kDebugLog )
printf("\tinvalid alternate wrapper MDB \n");
}
}
ExitThisRoutine:
if ( myPrimary.buffer != NULL )
(void) ReleaseVolumeBlock( myVOPtr->vcbPtr, &myPrimary, kReleaseBlock );
if ( myAlternate.buffer != NULL )
(void) ReleaseVolumeBlock( myVOPtr->vcbPtr, &myAlternate, kReleaseBlock );
return;
}
OSErr ValidVolumeHeader( HFSPlusVolumeHeader *volumeHeader )
{
OSErr err;
if ((volumeHeader->signature == kHFSPlusSigWord && volumeHeader->version == kHFSPlusVersion) ||
(volumeHeader->signature == kHFSXSigWord && volumeHeader->version == kHFSXVersion))
{
if ( (volumeHeader->blockSize != 0) && ((volumeHeader->blockSize & 0x01FF) == 0) ) err = noErr;
else
err = badMDBErr; }
else
{
err = noMacDskErr;
}
return( err );
}
void InitBTreeHeader (UInt32 fileSize, UInt32 clumpSize, UInt16 nodeSize, UInt16 recordCount, UInt16 keySize,
UInt32 attributes, UInt32 *mapNodes, void *buffer)
{
UInt32 nodeCount;
UInt32 usedNodes;
UInt32 nodeBitsInHeader;
BTHeaderRec *bth;
BTNodeDescriptor *ndp;
UInt32 *bitMapPtr;
SInt16 *offsetPtr;
ClearMemory(buffer, nodeSize);
nodeCount = fileSize / nodeSize;
nodeBitsInHeader = 8 * (nodeSize - sizeof(BTNodeDescriptor) - sizeof(BTHeaderRec) - kBTreeHeaderUserBytes - 4*sizeof(SInt16));
usedNodes = 1; *mapNodes = 0;
ndp = (BTNodeDescriptor*) buffer;
ndp->kind = kBTHeaderNode; ndp->numRecords = 3;
if (nodeCount > nodeBitsInHeader) {
UInt32 nodeBitsInMapNode;
nodeBitsInMapNode = 8 * (nodeSize - sizeof(BTNodeDescriptor) - 2*sizeof(SInt16) - 2);
if (recordCount > 0) ndp->fLink = 2; else
ndp->fLink = 1;
*mapNodes = (nodeCount - nodeBitsInHeader + (nodeBitsInMapNode - 1)) / nodeBitsInMapNode;
usedNodes += *mapNodes;
}
bth = (BTHeaderRec*) ((char*)buffer + sizeof(BTNodeDescriptor));
if (recordCount > 0)
{
++usedNodes;
bth->treeDepth = 1; bth->rootNode = 1; bth->firstLeafNode = 1; bth->lastLeafNode = 1; }
bth->attributes = attributes; bth->leafRecords = recordCount; bth->nodeSize = nodeSize; bth->maxKeyLength = keySize; bth->totalNodes = nodeCount; bth->freeNodes = nodeCount - usedNodes; bth->clumpSize = clumpSize;
bitMapPtr = (UInt32*) ((Byte*) buffer + sizeof(BTNodeDescriptor) + sizeof(BTHeaderRec) + kBTreeHeaderUserBytes);
*bitMapPtr = ~((UInt32) 0xFFFFFFFF >> usedNodes);
offsetPtr = (SInt16*) ((Byte*) buffer + nodeSize - 4*sizeof(SInt16));
*offsetPtr++ = sizeof(BTNodeDescriptor) + sizeof(BTHeaderRec) + kBTreeHeaderUserBytes + nodeBitsInHeader/8; *offsetPtr++ = sizeof(BTNodeDescriptor) + sizeof(BTHeaderRec) + kBTreeHeaderUserBytes; *offsetPtr++ = sizeof(BTNodeDescriptor) + sizeof(BTHeaderRec); *offsetPtr = sizeof(BTNodeDescriptor); }
void CalculateItemCount( SGlob *GPtr, UInt64 *itemCount, UInt64 *onePercent )
{
BTreeControlBlock *btcb;
VolumeObjectPtr myVOPtr;
UInt64 items;
UInt32 realFreeNodes;
SVCB *vcb = GPtr->calculatedVCB;
myVOPtr = GetVolumeObjectPtr( );
items = GPtr->calculatedVCB->vcbTotalBlocks / 1024;
btcb = (BTreeControlBlock*) vcb->vcbCatalogFile->fcbBtree;
realFreeNodes = ((BTreeExtensionsRec*)btcb->refCon)->realFreeNodeCount;
items += (2 * btcb->leafRecords) + (btcb->totalNodes - realFreeNodes);
btcb = (BTreeControlBlock*) vcb->vcbExtentsFile->fcbBtree;
realFreeNodes = ((BTreeExtensionsRec*)btcb->refCon)->realFreeNodeCount;
items += btcb->leafRecords + (btcb->totalNodes - realFreeNodes);
if ( vcb->vcbAttributesFile != NULL )
{
btcb = (BTreeControlBlock*) vcb->vcbAttributesFile->fcbBtree;
realFreeNodes = ((BTreeExtensionsRec*)btcb->refCon)->realFreeNodeCount;
items += (btcb->leafRecords + (btcb->totalNodes - realFreeNodes));
}
*onePercent = items/ 100;
items += *onePercent * 5;
*itemCount = items;
}
SFCB* ResolveFCB(short fileRefNum)
{
return( (SFCB*)((unsigned long)GetFCBSPtr() + (unsigned long)fileRefNum) );
}
void SetupFCB( SVCB *vcb, SInt16 refNum, UInt32 fileID, UInt32 fileClumpSize )
{
SFCB *fcb;
fcb = ResolveFCB(refNum);
fcb->fcbFileID = fileID;
fcb->fcbVolume = vcb;
fcb->fcbClumpSize = fileClumpSize;
}
pascal short ResolveFileRefNum(SFCB * fileCtrlBlockPtr)
{
return( (unsigned long)fileCtrlBlockPtr - (unsigned long)GetFCBSPtr() );
}
Ptr gFCBSPtr;
void SetFCBSPtr( Ptr value )
{
gFCBSPtr = value;
}
Ptr GetFCBSPtr( void )
{
return (gFCBSPtr);
}
OSErr FlushVolumeControlBlock( SVCB *vcb )
{
OSErr err;
HFSPlusVolumeHeader *volumeHeader;
SFCB *fcb;
BlockDescriptor block;
if ( ! IsVCBDirty( vcb ) ) return( noErr );
block.buffer = NULL;
err = GetVolumeObjectPrimaryBlock( &block );
if ( err != noErr )
{
if ( block.buffer != NULL ) {
(void) ReleaseVolumeBlock( vcb, &block, kReleaseBlock );
block.buffer = NULL;
}
err = VolumeObjectFixPrimaryBlock( );
ReturnIfError( err );
err = GetVolumeObjectPrimaryBlock( &block );
ReturnIfError( err );
}
if ( vcb->vcbSignature == kHFSPlusSigWord )
{
volumeHeader = (HFSPlusVolumeHeader *) block.buffer;
if ( vcb->vcbEmbeddedOffset != 0 ) {
HFSMasterDirectoryBlock *mdb;
BlockDescriptor mdb_block;
mdb_block.buffer = NULL;
err = GetVolumeObjectPrimaryMDB( &mdb_block );
if ( err == noErr )
{
mdb = (HFSMasterDirectoryBlock *) mdb_block.buffer;
if ( mdb->drCrDate != vcb->vcbCreateDate ) {
mdb->drCrDate = vcb->vcbCreateDate;
(void) ReleaseVolumeBlock(vcb, &mdb_block, kForceWriteBlock);
mdb_block.buffer = NULL;
}
}
if ( mdb_block.buffer != NULL )
(void) ReleaseVolumeBlock(vcb, &mdb_block, kReleaseBlock);
}
volumeHeader->attributes = vcb->vcbAttributes;
volumeHeader->lastMountedVersion = kFSCKMountVersion;
volumeHeader->createDate = vcb->vcbCreateDate; volumeHeader->modifyDate = vcb->vcbModifyDate;
volumeHeader->backupDate = vcb->vcbBackupDate;
volumeHeader->checkedDate = vcb->vcbCheckedDate;
volumeHeader->fileCount = vcb->vcbFileCount;
volumeHeader->folderCount = vcb->vcbFolderCount;
volumeHeader->blockSize = vcb->vcbBlockSize;
volumeHeader->totalBlocks = vcb->vcbTotalBlocks;
volumeHeader->freeBlocks = vcb->vcbFreeBlocks;
volumeHeader->nextAllocation = vcb->vcbNextAllocation;
volumeHeader->rsrcClumpSize = vcb->vcbRsrcClumpSize;
volumeHeader->dataClumpSize = vcb->vcbDataClumpSize;
volumeHeader->nextCatalogID = vcb->vcbNextCatalogID;
volumeHeader->writeCount = vcb->vcbWriteCount;
volumeHeader->encodingsBitmap = vcb->vcbEncodingsBitmap;
volumeHeader->allocationFile.clumpSize = vcb->vcbAllocationFile->fcbClumpSize;
volumeHeader->extentsFile.clumpSize = vcb->vcbExtentsFile->fcbClumpSize;
volumeHeader->catalogFile.clumpSize = vcb->vcbCatalogFile->fcbClumpSize;
CopyMemory( vcb->vcbFinderInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo) );
fcb = vcb->vcbExtentsFile;
CopyMemory( fcb->fcbExtents32, volumeHeader->extentsFile.extents, sizeof(HFSPlusExtentRecord) );
volumeHeader->extentsFile.logicalSize = fcb->fcbLogicalSize;
volumeHeader->extentsFile.totalBlocks = fcb->fcbPhysicalSize / vcb->vcbBlockSize;
fcb = vcb->vcbCatalogFile;
CopyMemory( fcb->fcbExtents32, volumeHeader->catalogFile.extents, sizeof(HFSPlusExtentRecord) );
volumeHeader->catalogFile.logicalSize = fcb->fcbLogicalSize;
volumeHeader->catalogFile.totalBlocks = fcb->fcbPhysicalSize / vcb->vcbBlockSize;
fcb = vcb->vcbAllocationFile;
CopyMemory( fcb->fcbExtents32, volumeHeader->allocationFile.extents, sizeof(HFSPlusExtentRecord) );
volumeHeader->allocationFile.logicalSize = fcb->fcbLogicalSize;
volumeHeader->allocationFile.totalBlocks = fcb->fcbPhysicalSize / vcb->vcbBlockSize;
if (vcb->vcbAttributesFile != NULL) {
fcb = vcb->vcbAttributesFile;
CopyMemory( fcb->fcbExtents32, volumeHeader->attributesFile.extents, sizeof(HFSPlusExtentRecord) );
volumeHeader->attributesFile.logicalSize = fcb->fcbLogicalSize;
volumeHeader->attributesFile.clumpSize = fcb->fcbClumpSize;
volumeHeader->attributesFile.totalBlocks = fcb->fcbPhysicalSize / vcb->vcbBlockSize;
}
}
else
{
HFSMasterDirectoryBlock *mdbP;
mdbP = (HFSMasterDirectoryBlock *) block.buffer;
mdbP->drCrDate = vcb->vcbCreateDate;
mdbP->drLsMod = vcb->vcbModifyDate;
mdbP->drAtrb = (UInt16)vcb->vcbAttributes;
mdbP->drClpSiz = vcb->vcbDataClumpSize;
mdbP->drNxtCNID = vcb->vcbNextCatalogID;
mdbP->drFreeBks = vcb->vcbFreeBlocks;
mdbP->drXTClpSiz = vcb->vcbExtentsFile->fcbClumpSize;
mdbP->drCTClpSiz = vcb->vcbCatalogFile->fcbClumpSize;
mdbP->drNmFls = vcb->vcbNmFls;
mdbP->drNmRtDirs = vcb->vcbNmRtDirs;
mdbP->drFilCnt = vcb->vcbFileCount;
mdbP->drDirCnt = vcb->vcbFolderCount;
fcb = vcb->vcbExtentsFile;
CopyMemory( fcb->fcbExtents16, mdbP->drXTExtRec, sizeof( mdbP->drXTExtRec ) );
fcb = vcb->vcbCatalogFile;
CopyMemory( fcb->fcbExtents16, mdbP->drCTExtRec, sizeof( mdbP->drCTExtRec ) );
}
if ( block.buffer != NULL ) {
err = ReleaseVolumeBlock(vcb, &block, kForceWriteBlock);
block.buffer = NULL;
}
MarkVCBClean( vcb );
return( err );
}
OSErr FlushAlternateVolumeControlBlock( SVCB *vcb, Boolean isHFSPlus )
{
OSErr err;
VolumeObjectPtr myVOPtr;
UInt64 myBlockNum;
BlockDescriptor pri_block, alt_block;
pri_block.buffer = NULL;
alt_block.buffer = NULL;
myVOPtr = GetVolumeObjectPtr( );
err = FlushVolumeControlBlock( vcb );
err = GetVolumeObjectPrimaryBlock( &pri_block );
if ( VolumeObjectIsHFS( ) ) {
if ( (myVOPtr->flags & kVO_PriMDBOK) == 0 )
err = badMDBErr;
}
else if ( (myVOPtr->flags & kVO_PriVHBOK) == 0 ) {
err = badMDBErr;
}
if ( err != noErr )
goto ExitThisRoutine;
GetVolumeObjectAlternateBlockNum( &myBlockNum );
if ( myBlockNum != 0 ) {
err = GetVolumeObjectAlternateBlock( &alt_block );
if ( err == noErr || err == badMDBErr || err == noMacDskErr ) {
CopyMemory( pri_block.buffer, alt_block.buffer, Blk_Size );
(void) ReleaseVolumeBlock(vcb, &alt_block, kForceWriteBlock);
alt_block.buffer = NULL;
}
}
ExitThisRoutine:
if ( pri_block.buffer != NULL )
(void) ReleaseVolumeBlock( vcb, &pri_block, kReleaseBlock );
if ( alt_block.buffer != NULL )
(void) ReleaseVolumeBlock( vcb, &alt_block, kReleaseBlock );
return( err );
}
void
ConvertToHFSPlusExtent( const HFSExtentRecord oldExtents, HFSPlusExtentRecord newExtents)
{
UInt16 i;
for (i = kHFSPlusExtentDensity-1; i > 2; --i)
{
newExtents[i].blockCount = 0;
newExtents[i].startBlock = 0;
}
newExtents[2].blockCount = oldExtents[2].blockCount;
newExtents[2].startBlock = oldExtents[2].startBlock;
newExtents[1].blockCount = oldExtents[1].blockCount;
newExtents[1].startBlock = oldExtents[1].startBlock;
newExtents[0].blockCount = oldExtents[0].blockCount;
newExtents[0].startBlock = oldExtents[0].startBlock;
}
OSErr CacheWriteInPlace( SVCB *vcb, UInt32 fileRefNum, HIOParam *iopb, UInt64 currentPosition, UInt32 maximumBytes, UInt32 *actualBytes )
{
OSErr err;
UInt64 diskBlock;
UInt32 contiguousBytes;
void* buffer;
*actualBytes = 0;
buffer = (char*)iopb->ioBuffer + iopb->ioActCount;
err = MapFileBlockC(vcb, ResolveFCB(fileRefNum), maximumBytes, (currentPosition >> kSectorShift),
&diskBlock, &contiguousBytes );
if (err)
return (err);
err = DeviceWrite(vcb->vcbDriverWriteRef, vcb->vcbDriveNumber, buffer, (diskBlock << Log2BlkLo), contiguousBytes, actualBytes);
return( err );
}
void PrintName( int theCount, const UInt8 *theNamePtr, Boolean isUnicodeString )
{
int myCount;
int i;
myCount = (isUnicodeString) ? (theCount * 2) : theCount;
for ( i = 0; i < myCount; i++ )
printf( "%02X ", *(theNamePtr + i) );
printf( "\n" );
}
#if DEBUG_XATTR
#define MAX_PRIMES 11
int primes[] = {32, 27, 25, 7, 11, 13, 17, 19, 23, 29, 31};
void print_prime_buckets(PrimeBuckets *cur);
#endif
void RecordXAttrBits(SGlobPtr GPtr, UInt16 flags, HFSCatalogNodeID fileid, UInt16 btreetype)
{
PrimeBuckets *cur_attr = NULL;
PrimeBuckets *cur_sec = NULL;
int r32, r27, r25, r7, r11, r13, r17, r19, r23, r29, r31;
if ( ((flags & kHFSHasAttributesMask) == 0) &&
((flags & kHFSHasSecurityMask) == 0) ) {
goto out;
}
if (btreetype == kCalculatedCatalogRefNum) {
if (flags & kHFSHasAttributesMask) {
cur_attr = &(GPtr->CBTAttrBucket);
}
if (flags & kHFSHasSecurityMask) {
cur_sec = &(GPtr->CBTSecurityBucket);
}
} else if (btreetype == kCalculatedAttributesRefNum) {
if (flags & kHFSHasAttributesMask) {
cur_attr = &(GPtr->ABTAttrBucket);
}
if (flags & kHFSHasSecurityMask) {
cur_sec = &(GPtr->ABTSecurityBucket);
}
} else {
goto out;
}
r32 = fileid % 32;
r27 = fileid % 27;
r25 = fileid % 25;
r7 = fileid % 7;
r11 = fileid % 11;
r13 = fileid % 13;
r17 = fileid % 17;
r19 = fileid % 19;
r23 = fileid % 23;
r29 = fileid % 29;
r31 = fileid % 31;
if (cur_attr) {
cur_attr->n32[r32]++;
cur_attr->n27[r27]++;
cur_attr->n25[r25]++;
cur_attr->n7[r7]++;
cur_attr->n11[r11]++;
cur_attr->n13[r13]++;
cur_attr->n17[r17]++;
cur_attr->n19[r19]++;
cur_attr->n23[r23]++;
cur_attr->n29[r29]++;
cur_attr->n31[r31]++;
}
if (cur_sec) {
cur_sec->n32[r32]++;
cur_sec->n27[r27]++;
cur_sec->n25[r25]++;
cur_sec->n7[r7]++;
cur_sec->n11[r11]++;
cur_sec->n13[r13]++;
cur_sec->n17[r17]++;
cur_sec->n19[r19]++;
cur_sec->n23[r23]++;
cur_sec->n29[r29]++;
cur_sec->n31[r31]++;
}
#if 0
printf ("\nFor fileID = %d\n", fileid);
if (cur_attr) {
printf ("Attributes bucket:\n");
print_prime_buckets(cur_attr);
}
if (cur_sec) {
printf ("Security bucket:\n");
print_prime_buckets(cur_sec);
}
#endif
out:
return;
}
int ComparePrimeBuckets(SGlobPtr GPtr, UInt16 BitMask)
{
int result = 0;
int i;
PrimeBuckets *cat;
PrimeBuckets *attr;
if (BitMask & kHFSHasAttributesMask) {
cat = &(GPtr->CBTAttrBucket);
attr = &(GPtr->ABTAttrBucket);
} else if (BitMask & kHFSHasSecurityMask) {
cat = &(GPtr->CBTSecurityBucket);
attr = &(GPtr->ABTSecurityBucket);
} else {
printf ("%s: Incorrect BitMask found.\n", __FUNCTION__);
goto out;
}
for (i=0; i<32; i++) {
if (cat->n32[i] != attr->n32[i]) {
goto unequal_out;
}
}
for (i=0; i<27; i++) {
if (cat->n27[i] != attr->n27[i]) {
goto unequal_out;
}
}
for (i=0; i<25; i++) {
if (cat->n25[i] != attr->n25[i]) {
goto unequal_out;
}
}
for (i=0; i<7; i++) {
if (cat->n7[i] != attr->n7[i]) {
goto unequal_out;
}
}
for (i=0; i<11; i++) {
if (cat->n11[i] != attr->n11[i]) {
goto unequal_out;
}
}
for (i=0; i<13; i++) {
if (cat->n13[i] != attr->n13[i]) {
goto unequal_out;
}
}
for (i=0; i<17; i++) {
if (cat->n17[i] != attr->n17[i]) {
goto unequal_out;
}
}
for (i=0; i<19; i++) {
if (cat->n19[i] != attr->n19[i]) {
goto unequal_out;
}
}
for (i=0; i<23; i++) {
if (cat->n23[i] != attr->n23[i]) {
goto unequal_out;
}
}
for (i=0; i<29; i++) {
if (cat->n29[i] != attr->n29[i]) {
goto unequal_out;
}
}
for (i=0; i<31; i++) {
if (cat->n31[i] != attr->n31[i]) {
goto unequal_out;
}
}
goto out;
unequal_out:
if (BitMask & kHFSHasAttributesMask) {
RcdError (GPtr, E_IncorrectAttrCount);
GPtr->ABTStat |= S_AttributeCount;
} else {
RcdError (GPtr, E_IncorrectSecurityCount);
GPtr->ABTStat |= S_SecurityCount;
}
#if DEBUG_XATTR
if (BitMask & kHFSHasAttributesMask) {
printf ("For kHFSHasAttributesMask:\n");
} else {
printf ("For kHFSHasSecurityMask:\n");
}
printf("Catalog BTree bucket:\n");
print_prime_buckets(cat);
printf("Attribute BTree bucket\n");
print_prime_buckets(attr);
#endif
out:
return result;
}
#if DEBUG_XATTR
void print_prime_buckets(PrimeBuckets *cur)
{
int i;
printf ("n32 = { ");
for (i=0; i<32; i++) {
printf ("%d,", cur->n32[i]);
}
printf ("}\n");
printf ("n27 = { ");
for (i=0; i<27; i++) {
printf ("%d,", cur->n27[i]);
}
printf ("}\n");
printf ("n25 = { ");
for (i=0; i<25; i++) {
printf ("%d,", cur->n25[i]);
}
printf ("}\n");
printf ("n7 = { ");
for (i=0; i<7; i++) {
printf ("%d,", cur->n7[i]);
}
printf ("}\n");
printf ("n11 = { ");
for (i=0; i<11; i++) {
printf ("%d,", cur->n11[i]);
}
printf ("}\n");
printf ("n13 = { ");
for (i=0; i<13; i++) {
printf ("%d,", cur->n13[i]);
}
printf ("}\n");
printf ("n17 = { ");
for (i=0; i<17; i++) {
printf ("%d,", cur->n17[i]);
}
printf ("}\n");
printf ("n19 = { ");
for (i=0; i<19; i++) {
printf ("%d,", cur->n19[i]);
}
printf ("}\n");
printf ("n23 = { ");
for (i=0; i<23; i++) {
printf ("%d,", cur->n23[i]);
}
printf ("}\n");
printf ("n29 = { ");
for (i=0; i<29; i++) {
printf ("%d,", cur->n29[i]);
}
printf ("}\n");
printf ("n31 = { ");
for (i=0; i<31; i++) {
printf ("%d,", cur->n31[i]);
}
printf ("}\n");
}
#endif