2
* Copyright (c) 1999-2003, 2005 Apple Computer, Inc. All rights reserved.
4
* @APPLE_LICENSE_HEADER_START@
6
* "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7
* Reserved. This file contains Original Code and/or Modifications of
8
* Original Code as defined in and that are subject to the Apple Public
9
* Source License Version 1.0 (the 'License'). You may not use this file
10
* except in compliance with the License. Please obtain a copy of the
11
* License at http://www.apple.com/publicsource and read it before using
14
* The Original Code and all software distributed under the License are
15
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19
* License for the specific language governing rights and limitations
22
* @APPLE_LICENSE_HEADER_END@
27
Contains: xxx put contents here xxx
29
Version: xxx put version here xxx
31
Copyright: � 1997-1999 by Apple Computer, Inc., all rights reserved.
34
#include "Scavenger.h"
36
static void CompareVolHeaderBTreeSizes( SGlobPtr GPtr,
37
VolumeObjectPtr theVOPtr,
38
HFSPlusVolumeHeader * thePriVHPtr,
39
HFSPlusVolumeHeader * theAltVHPtr );
40
static void GetEmbeddedVolumeHeaders( SGlobPtr GPtr,
41
HFSMasterDirectoryBlock * myMDBPtr,
42
Boolean isPrimaryMDB );
43
static OSErr GetVolumeObjectBlock( VolumeObjectPtr theVOPtr,
45
BlockDescriptor * theBlockDescPtr );
46
static OSErr VolumeObjectFixPrimaryBlock( void );
51
* Encode a UCS-2 (Unicode) string to UTF-8
53
int utf_encodestr(ucsp, ucslen, utf8p, utf8len)
54
const u_int16_t * ucsp;
56
unsigned char * utf8p;
59
unsigned char * bufstart;
66
while (charcnt-- > 0) {
69
if (ucs_ch < 0x0080) {
71
continue; /* skip over embedded NULLs */
74
} else if (ucs_ch < 0x800) {
75
*utf8p++ = (ucs_ch >> 6) | 0xc0;
76
*utf8p++ = (ucs_ch & 0x3f) | 0x80;
78
*utf8p++ = (ucs_ch >> 12) | 0xe0;
79
*utf8p++ = ((ucs_ch >> 6) & 0x3f) | 0x80;
80
*utf8p++ = ((ucs_ch) & 0x3f) | 0x80;
84
*utf8len = utf8p - bufstart;
93
* Decode a UTF-8 string back to UCS-2 (Unicode)
96
utf_decodestr(utf8p, utf8len, ucsp, ucslen)
97
const unsigned char * utf8p;
108
while (utf8len-- > 0 && (byte = *utf8p++) != '\0') {
109
/* check for ascii */
115
switch (byte & 0xf0) {
119
/* extract bits 6 - 10 from first byte */
120
ucs_ch = (byte & 0x1F) << 6;
122
return (-1); /* seq not minimal */
126
/* extract bits 12 - 15 from first byte */
127
ucs_ch = (byte & 0x0F) << 6;
129
/* extract bits 6 - 11 from second byte */
130
if (((byte = *utf8p++) & 0xc0) != 0x80)
134
ucs_ch += (byte & 0x3F);
137
return (-1); /* seq not minimal */
143
/* extract bits 0 - 5 from final byte */
144
if (((byte = *utf8p++) & 0xc0) != 0x80)
148
ucs_ch += (byte & 0x3F);
152
*ucslen = (u_int8_t*)ucsp - (u_int8_t*)bufstart;
158
OSErr GetFBlk( SGlobPtr GPtr, SInt16 fileRefNum, SInt32 blockNumber, void **bufferH );
163
UInt32 GetDFAStage( void )
168
void SetDFAStage( UInt32 stage )
174
/*------------------------------------------------------------------------------
178
Function: Record errors detetected by scavenging operation.
180
Input: GPtr - pointer to scavenger global area.
184
------------------------------------------------------------------------------*/
186
void RcdError( SGlobPtr GPtr, OSErr errorCode )
188
GPtr->ErrCode = errorCode;
190
WriteError( GPtr, errorCode, GPtr->TarID, GPtr->TarBlock ); // log to summary window
194
/*------------------------------------------------------------------------------
198
Function: Records an internal Scavenger error.
200
Input: GPtr - pointer to scavenger global area.
201
ErrCode - internal error code
203
Output: IntError - function result:
205
------------------------------------------------------------------------------*/
207
int IntError( SGlobPtr GPtr, OSErr errorCode )
209
GPtr->RepLevel = repairLevelUnrepairable;
211
if ( errorCode == ioErr ) // Cast I/O errors as read errors
214
if( (errorCode == R_RdErr) || (errorCode == R_WrErr) )
216
GPtr->ErrCode = GPtr->volumeErrorCode;
222
GPtr->ErrCode = R_IntErr;
223
GPtr->IntErr = errorCode;
231
/*------------------------------------------------------------------------------
233
Routine: AllocBTN (Allocate BTree Node)
235
Function: Allocates an BTree node in a Scavenger BTree bit map.
237
Input: GPtr - pointer to scavenger global area.
238
StABN - starting allocation block number.
239
NmABlks - number of allocation blocks.
241
Output: AllocBTN - function result:
244
------------------------------------------------------------------------------*/
246
int AllocBTN( SGlobPtr GPtr, SInt16 fileRefNum, UInt32 nodeNumber )
251
BTreeControlBlock *calculatedBTCB = GetBTreeControlBlock( fileRefNum );
254
if ( calculatedBTCB->refCon == 0)
257
byteP = ( (BTreeExtensionsRec*)calculatedBTCB->refCon)->BTCBMPtr + (nodeNumber / 8 ); // ptr to starting byte
258
bitPos = nodeNumber % 8; // bit offset
259
mask = ( 0x80 >> bitPos );
260
if ( (*byteP & mask) != 0 )
262
RcdError( GPtr, E_OvlNode );
263
return( E_OvlNode ); // node already allocated
265
*byteP = *byteP | mask; // allocate it
266
calculatedBTCB->freeNodes--; // decrement free count
272
OSErr GetBTreeHeader( SGlobPtr GPtr, SFCB *fcb, BTHeaderRec *header )
275
BTHeaderRec *headerRec;
276
BlockDescriptor block;
278
GPtr->TarBlock = kHeaderNodeNum;
280
if (fcb->fcbBlockSize == 0)
281
(void) SetFileBlockSize(fcb, 512);
283
err = GetFileBlock(fcb, kHeaderNodeNum, kGetBlock, &block);
286
err = hfs_swap_BTNode(&block, fcb, kSwapBTNodeHeaderRecordOnly);
289
(void) ReleaseFileBlock(fcb, &block, kReleaseBlock | kTrashBlock);
293
headerRec = (BTHeaderRec *)((char*)block.buffer + sizeof(BTNodeDescriptor));
294
CopyMemory(headerRec, header, sizeof(BTHeaderRec));
296
err = hfs_swap_BTNode(&block, fcb, kSwapBTNodeHeaderRecordOnly);
299
(void) ReleaseFileBlock(fcb, &block, kReleaseBlock | kTrashBlock);
303
err = ReleaseFileBlock (fcb, &block, kReleaseBlock);
306
/* Validate Node Size */
307
switch (header->nodeSize) {
318
RcdError( GPtr, E_InvalidNodeSize );
319
err = E_InvalidNodeSize;
327
/*------------------------------------------------------------------------------
329
Routine: Alloc[Minor/Major]RepairOrder
331
Function: Allocate a repair order node and link into the 'GPtr->RepairXxxxxP" list.
332
These are descriptions of minor/major repairs that need to be performed;
333
they are compiled during verification, and executed during minor/major repair.
335
Input: GPtr - scavenger globals
336
n - number of extra bytes needed, in addition to standard node size.
338
Output: Ptr to node, or NULL if out of memory or other error.
339
------------------------------------------------------------------------------*/
341
RepairOrderPtr AllocMinorRepairOrder( SGlobPtr GPtr, int n ) /* #extra bytes needed */
343
RepairOrderPtr p; // the node we allocate
345
n += sizeof( RepairOrder ); // add in size of basic node
347
p = (RepairOrderPtr) AllocateClearMemory( n ); // get the node
349
if ( p != NULL ) // if we got one...
351
p->link = GPtr->MinorRepairsP; // then link into list of repairs
352
GPtr->MinorRepairsP = p;
354
else if ( GPtr->logLevel >= kDebugLog )
355
printf( "\t%s - AllocateClearMemory failed to allocate %d bytes \n", __FUNCTION__, n);
357
if ( GPtr->RepLevel == repairLevelNoProblemsFound )
358
GPtr->RepLevel = repairLevelVolumeRecoverable;
360
return( p ); // return ptr to node
365
void InvalidateCalculatedVolumeBitMap( SGlobPtr GPtr )
372
//------------------------------------------------------------------------------
373
// Routine: GetVolumeFeatures
375
// Function: Sets up some OS and volume specific flags
377
// Input: GPtr->DrvNum The volume to check
379
// Output: GPtr->volumeFeatures Bit vector
380
// GPtr->realVCB Real in-memory vcb
381
//------------------------------------------------------------------------------
384
OSErr GetVolumeFeatures( SGlobPtr GPtr )
388
GetVolParmsInfoBuffer buffer;
391
GPtr->volumeFeatures = 0; // Initialize to zero
393
// Get the "real" vcb
394
err = GetVCBDriveNum( &GPtr->realVCB, GPtr->DrvNum );
395
ReturnIfError( err );
397
if ( GPtr->realVCB != nil )
399
GPtr->volumeFeatures |= volumeIsMountedMask;
401
pb.ioParam.ioNamePtr = nil;
402
pb.ioParam.ioVRefNum = GPtr->realVCB->vcbVRefNum;
403
pb.ioParam.ioBuffer = (Ptr) &buffer;
404
pb.ioParam.ioReqCount = sizeof( buffer );
406
if ( PBHGetVolParms( &pb, false ) == noErr )
408
if ( buffer.vMAttrib & (1 << bSupportsTrashVolumeCache) )
409
GPtr->volumeFeatures |= supportsTrashVolumeCacheFeatureMask;
412
// Check if the running system is HFS+ savy
413
err = Gestalt( gestaltFSAttr, &response );
414
ReturnIfError( err );
415
if ( (response & (1 << gestaltFSSupportsHFSPlusVols)) != 0 )
416
GPtr->volumeFeatures |= supportsHFSPlusVolsFeatureMask;
424
/*-------------------------------------------------------------------------------
425
Routine: ClearMemory - clear a block of memory
427
-------------------------------------------------------------------------------*/
429
void ClearMemory( void* start, UInt32 length )
434
UInt32 fragCount; // serves as both a length and quadlong count
435
// for the beginning and main fragment
440
// is request less than 4 bytes?
441
if ( length < 4 ) // length = 1,2 or 3
443
bytePtr = (UInt8 *) start;
447
*bytePtr++ = zero; // clear one byte at a time
454
// are we aligned on an odd boundry?
455
fragCount = (UInt32) start & 3;
457
if ( fragCount ) // fragCount = 1,2 or 3
459
bytePtr = (UInt8 *) start;
463
*bytePtr++ = zero; // clear one byte at a time
467
while ( (fragCount < 4) && (length > 0) );
472
dataPtr = (UInt32*) (((UInt32) start & 0xFFFFFFFC) + 4); // make it long word aligned
476
dataPtr = (UInt32*) ((UInt32) start & 0xFFFFFFFC); // make it long word aligned
479
// At this point dataPtr is long aligned
481
// are there odd bytes to copy?
482
fragCount = length & 3;
486
bytePtr = (UInt8 *) ((UInt32) dataPtr + (UInt32) length - 1); // point to last byte
488
length -= fragCount; // adjust remaining length
492
*bytePtr-- = zero; // clear one byte at a time
494
while ( --fragCount );
500
// At this point length is a multiple of 4
504
DebugStr("\p ClearMemory: length < 4");
507
// fix up beginning to get us on a 64 byte boundary
508
fragCount = length & (64-1);
511
if ( fragCount < 4 && fragCount > 0 )
512
DebugStr("\p ClearMemory: fragCount < 4");
517
length -= fragCount; // subtract fragment from length now
518
fragCount >>= 2; // divide by 4 to get a count, for DBRA loop
521
// clear 4 bytes at a time...
527
// Are we finished yet?
531
// Time to turn on the fire hose
532
length >>= 6; // divide by 64 to get count
535
// spray 64 bytes at a time...
536
*dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero;
537
*dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero;
538
*dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero;
539
*dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero;
548
CopyCatalogName(const CatalogName *srcName, CatalogName *dstName, Boolean isHFSPLus)
552
if ( srcName == NULL )
554
if ( dstName != NULL )
555
dstName->ustr.length = 0; // set length byte to zero (works for both unicode and pascal)
560
length = sizeof(UniChar) * (srcName->ustr.length + 1);
562
length = sizeof(UInt8) + srcName->pstr[0];
565
CopyMemory(srcName, dstName, length);
567
dstName->ustr.length = 0; // set length byte to zero (works for both unicode and pascal)
572
CatalogNameLength(const CatalogName *name, Boolean isHFSPlus)
575
return name->ustr.length;
577
return name->pstr[0];
581
UInt32 CatalogNameSize( const CatalogName *name, Boolean isHFSPlus)
583
UInt32 length = CatalogNameLength( name, isHFSPlus );
586
length *= sizeof(UniChar);
592
//******************************************************************************
593
// Routine: BuildCatalogKey
595
// Function: Constructs a catalog key record (ckr) given the parent
596
// folder ID and CName. Works for both classic and extended
599
//******************************************************************************
602
BuildCatalogKey(HFSCatalogNodeID parentID, const CatalogName *cName, Boolean isHFSPlus, CatalogKey *key)
606
key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength; // initial key length (4 + 2)
607
key->hfsPlus.parentID = parentID; // set parent ID
608
key->hfsPlus.nodeName.length = 0; // null CName length
611
CopyCatalogName(cName, (CatalogName *) &key->hfsPlus.nodeName, isHFSPlus);
612
key->hfsPlus.keyLength += sizeof(UniChar) * cName->ustr.length; // add CName size to key length
617
key->hfs.keyLength = kHFSCatalogKeyMinimumLength; // initial key length (1 + 4 + 1)
618
key->hfs.reserved = 0; // clear unused byte
619
key->hfs.parentID = parentID; // set parent ID
620
key->hfs.nodeName[0] = 0; // null CName length
623
UpdateCatalogName(cName->pstr, key->hfs.nodeName);
624
key->hfs.keyLength += key->hfs.nodeName[0]; // add CName size to key length
630
// Defined in BTreesPrivate.h, but not implemented in the BTree code?
631
// So... here's the implementation
632
SInt32 CompareKeys( BTreeControlBlockPtr btreePtr, KeyPtr searchKey, KeyPtr trialKey )
634
KeyCompareProcPtr compareProc = (KeyCompareProcPtr)btreePtr->keyCompareProc;
636
return( compareProc(searchKey, trialKey) );
641
UpdateCatalogName(ConstStr31Param srcName, Str31 destName)
643
Size length = srcName[0];
645
if (length > kHFSMaxFileNameChars)
646
length = kHFSMaxFileNameChars; // truncate to max
648
destName[0] = length; // set length byte
650
CopyMemory(&srcName[1], &destName[1], length);
655
UpdateVolumeEncodings(SVCB *volume, TextEncoding encoding)
661
index = MapEncodingToIndex(encoding);
663
volume->vcbEncodingsBitmap |= (u_int64_t)(1ULL << index);
665
// vcb should already be marked dirty
669
//******************************************************************************
670
// Routine: VolumeObjectFixPrimaryBlock
672
// Function: Use the alternate Volume Header or Master Directory block (depending
673
// on the type of volume) to restore the primary block. This routine
674
// depends upon our intialization code to set up where are blocks are
677
// Result: 0 if all is well, noMacDskErr when we do not have a primary block
678
// number or whatever GetVolumeObjectAlternateBlock returns.
679
//******************************************************************************
681
static OSErr VolumeObjectFixPrimaryBlock( void )
684
VolumeObjectPtr myVOPtr;
685
UInt64 myPrimaryBlockNum;
686
BlockDescriptor myPrimary;
687
BlockDescriptor myAlternate;
689
myVOPtr = GetVolumeObjectPtr( );
690
myPrimary.buffer = NULL;
691
myAlternate.buffer = NULL;
693
GetVolumeObjectPrimaryBlockNum( &myPrimaryBlockNum );
694
if ( myPrimaryBlockNum == 0 )
695
return( noMacDskErr );
697
// we don't care if this is a valid primary block since we're
698
// about to write over it
699
err = GetVolumeObjectPrimaryBlock( &myPrimary );
700
if ( !(err == noErr || err == badMDBErr || err == noMacDskErr) )
701
goto ExitThisRoutine;
703
// restore the primary block from the alternate
704
err = GetVolumeObjectAlternateBlock( &myAlternate );
706
// invalidate if we have not marked the alternate as OK
707
if ( VolumeObjectIsHFS( ) ) {
708
if ( (myVOPtr->flags & kVO_AltMDBOK) == 0 )
711
else if ( (myVOPtr->flags & kVO_AltVHBOK) == 0 ) {
715
if ( err == noErr ) {
716
CopyMemory( myAlternate.buffer, myPrimary.buffer, Blk_Size );
717
(void) ReleaseVolumeBlock( myVOPtr->vcbPtr, &myPrimary, kForceWriteBlock );
718
myPrimary.buffer = NULL;
719
if ( myVOPtr->volumeType == kHFSVolumeType )
720
myVOPtr->flags |= kVO_PriMDBOK;
722
myVOPtr->flags |= kVO_PriVHBOK;
726
if ( myPrimary.buffer != NULL )
727
(void) ReleaseVolumeBlock( myVOPtr->vcbPtr, &myPrimary, kReleaseBlock );
728
if ( myAlternate.buffer != NULL )
729
(void) ReleaseVolumeBlock( myVOPtr->vcbPtr, &myAlternate, kReleaseBlock );
733
} /* VolumeObjectFixPrimaryBlock */
736
//******************************************************************************
737
// Routine: GetVolumeObjectVHBorMDB
739
// Function: Get the Volume Header block or Master Directory block (depending
740
// on type of volume). This will normally return the alternate, but
741
// it may return the primary when the alternate is damaged or cannot
744
// Result: returns 0 when all is well.
745
//******************************************************************************
746
OSErr GetVolumeObjectVHBorMDB( BlockDescriptor * theBlockDescPtr )
749
VolumeObjectPtr myVOPtr;
752
myVOPtr = GetVolumeObjectPtr( );
753
GetVolumeObjectBlockNum( &myBlockNum );
755
err = GetVolumeObjectBlock( myVOPtr, myBlockNum, theBlockDescPtr );
758
if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType ||
759
myVOPtr->volumeType == kPureHFSPlusVolumeType )
761
err = ValidVolumeHeader( (HFSPlusVolumeHeader*) theBlockDescPtr->buffer );
763
else if ( myVOPtr->volumeType == kHFSVolumeType )
765
HFSMasterDirectoryBlock * myMDBPtr;
766
myMDBPtr = (HFSMasterDirectoryBlock *) theBlockDescPtr->buffer;
767
if ( myMDBPtr->drSigWord != kHFSSigWord )
776
} /* GetVolumeObjectVHBorMDB */
779
//******************************************************************************
780
// Routine: GetVolumeObjectAlternateBlock
782
// Function: Get the alternate Volume Header block or Master Directory block
783
// (depending on type of volume).
784
// Result: returns 0 when all is well.
785
//******************************************************************************
786
OSErr GetVolumeObjectAlternateBlock( BlockDescriptor * theBlockDescPtr )
789
VolumeObjectPtr myVOPtr;
792
myVOPtr = GetVolumeObjectPtr( );
793
GetVolumeObjectAlternateBlockNum( &myBlockNum );
795
err = GetVolumeObjectBlock( myVOPtr, myBlockNum, theBlockDescPtr );
798
if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType ||
799
myVOPtr->volumeType == kPureHFSPlusVolumeType )
801
err = ValidVolumeHeader( (HFSPlusVolumeHeader*) theBlockDescPtr->buffer );
803
else if ( myVOPtr->volumeType == kHFSVolumeType )
805
HFSMasterDirectoryBlock * myMDBPtr;
806
myMDBPtr = (HFSMasterDirectoryBlock *) theBlockDescPtr->buffer;
807
if ( myMDBPtr->drSigWord != kHFSSigWord )
816
} /* GetVolumeObjectAlternateBlock */
819
//******************************************************************************
820
// Routine: GetVolumeObjectPrimaryBlock
822
// Function: Get the primary Volume Header block or Master Directory block
823
// (depending on type of volume).
824
// Result: returns 0 when all is well.
825
//******************************************************************************
826
OSErr GetVolumeObjectPrimaryBlock( BlockDescriptor * theBlockDescPtr )
829
VolumeObjectPtr myVOPtr;
832
myVOPtr = GetVolumeObjectPtr( );
833
GetVolumeObjectPrimaryBlockNum( &myBlockNum );
835
err = GetVolumeObjectBlock( myVOPtr, myBlockNum, theBlockDescPtr );
838
if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType ||
839
myVOPtr->volumeType == kPureHFSPlusVolumeType )
841
err = ValidVolumeHeader( (HFSPlusVolumeHeader*) theBlockDescPtr->buffer );
843
else if ( myVOPtr->volumeType == kHFSVolumeType )
845
HFSMasterDirectoryBlock * myMDBPtr;
846
myMDBPtr = (HFSMasterDirectoryBlock *) theBlockDescPtr->buffer;
847
if ( myMDBPtr->drSigWord != kHFSSigWord )
856
} /* GetVolumeObjectPrimaryBlock */
859
//******************************************************************************
860
// Routine: GetVolumeObjectVHB
862
// Function: Get the Volume Header block using either the primary or alternate
863
// block number as set up by InitializeVolumeObject. This will normally
864
// return the alternate, but it may return the primary when the
865
// alternate is damaged or cannot be found.
867
// Result: returns 0 when all is well or passes results of GetVolumeBlock or
868
// ValidVolumeHeader.
869
//******************************************************************************
870
OSErr GetVolumeObjectVHB( BlockDescriptor * theBlockDescPtr )
873
VolumeObjectPtr myVOPtr;
876
myVOPtr = GetVolumeObjectPtr( );
877
myBlockNum = ((myVOPtr->flags & kVO_AltVHBOK) != 0) ? myVOPtr->alternateVHB : myVOPtr->primaryVHB;
878
err = GetVolumeObjectBlock( myVOPtr, myBlockNum, theBlockDescPtr );
880
err = ValidVolumeHeader( (HFSPlusVolumeHeader*) theBlockDescPtr->buffer );
884
} /* GetVolumeObjectVHB */
887
//******************************************************************************
888
// Routine: GetVolumeObjectAlternateMDB
890
// Function: Get the Master Directory Block using the alternate master directory
891
// block number as set up by InitializeVolumeObject.
893
// Result: returns 0 when all is well.
894
//******************************************************************************
895
OSErr GetVolumeObjectAlternateMDB( BlockDescriptor * theBlockDescPtr )
897
VolumeObjectPtr myVOPtr;
900
myVOPtr = GetVolumeObjectPtr( );
901
err = GetVolumeObjectBlock( NULL, myVOPtr->alternateMDB, theBlockDescPtr );
904
HFSMasterDirectoryBlock * myMDBPtr;
905
myMDBPtr = (HFSMasterDirectoryBlock *) theBlockDescPtr->buffer;
906
if ( myMDBPtr->drSigWord != kHFSSigWord )
912
} /* GetVolumeObjectAlternateMDB */
915
//******************************************************************************
916
// Routine: GetVolumeObjectPrimaryMDB
918
// Function: Get the Master Directory Block using the primary master directory
919
// block number as set up by InitializeVolumeObject.
921
// Result: returns 0 when all is well.
922
//******************************************************************************
923
OSErr GetVolumeObjectPrimaryMDB( BlockDescriptor * theBlockDescPtr )
925
VolumeObjectPtr myVOPtr;
928
myVOPtr = GetVolumeObjectPtr( );
929
err = GetVolumeObjectBlock( NULL, myVOPtr->primaryMDB, theBlockDescPtr );
932
HFSMasterDirectoryBlock * myMDBPtr;
933
myMDBPtr = (HFSMasterDirectoryBlock *) theBlockDescPtr->buffer;
934
if ( myMDBPtr->drSigWord != kHFSSigWord )
940
} /* GetVolumeObjectPrimaryMDB */
943
//******************************************************************************
944
// Routine: GetVolumeObjectBlock
946
// Function: Get the Volume Header block or Master Directory block using the
947
// given block number.
948
// Result: returns 0 when all is well or passes results of GetVolumeBlock or
949
// ValidVolumeHeader.
950
//******************************************************************************
951
static OSErr GetVolumeObjectBlock( VolumeObjectPtr theVOPtr,
953
BlockDescriptor * theBlockDescPtr )
957
if ( theVOPtr == NULL )
958
theVOPtr = GetVolumeObjectPtr( );
960
err = GetVolumeBlock( theVOPtr->vcbPtr, theBlockNum, kGetBlock, theBlockDescPtr );
964
} /* GetVolumeObjectBlock */
967
//******************************************************************************
968
// Routine: GetVolumeObjectBlockNum
970
// Function: Extract the appropriate block number for the volume header or
971
// master directory (depanding on volume type) from the VolumeObject.
972
// NOTE - this routine may return the primary or alternate block
973
// depending on which one is valid. Preference is always given to
976
// Result: returns block number of MDB or VHB or 0 if none are valid or
977
// if volume type is unknown.
978
//******************************************************************************
979
void GetVolumeObjectBlockNum( UInt64 * theBlockNumPtr )
981
VolumeObjectPtr myVOPtr;
983
myVOPtr = GetVolumeObjectPtr( );
984
*theBlockNumPtr = 0; // default to none
986
// NOTE - we use alternate volume header or master directory
987
// block before the primary because it is less likely to be damaged.
988
if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType ||
989
myVOPtr->volumeType == kPureHFSPlusVolumeType ) {
990
if ( (myVOPtr->flags & kVO_AltVHBOK) != 0 )
991
*theBlockNumPtr = myVOPtr->alternateVHB;
993
*theBlockNumPtr = myVOPtr->primaryVHB;
995
else if ( myVOPtr->volumeType == kHFSVolumeType ) {
996
if ( (myVOPtr->flags & kVO_AltMDBOK) != 0 )
997
*theBlockNumPtr = myVOPtr->alternateMDB;
999
*theBlockNumPtr = myVOPtr->primaryMDB;
1004
} /* GetVolumeObjectBlockNum */
1007
//******************************************************************************
1008
// Routine: GetVolumeObjectAlternateBlockNum
1010
// Function: Extract the alternate block number for the volume header or
1011
// master directory (depanding on volume type) from the VolumeObject.
1013
// Result: returns block number of alternate MDB or VHB or 0 if none are
1014
// valid or if volume type is unknown.
1015
//******************************************************************************
1016
void GetVolumeObjectAlternateBlockNum( UInt64 * theBlockNumPtr )
1018
VolumeObjectPtr myVOPtr;
1020
myVOPtr = GetVolumeObjectPtr( );
1021
*theBlockNumPtr = 0; // default to none
1023
if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType ||
1024
myVOPtr->volumeType == kPureHFSPlusVolumeType ) {
1025
*theBlockNumPtr = myVOPtr->alternateVHB;
1027
else if ( myVOPtr->volumeType == kHFSVolumeType ) {
1028
*theBlockNumPtr = myVOPtr->alternateMDB;
1033
} /* GetVolumeObjectAlternateBlockNum */
1036
//******************************************************************************
1037
// Routine: GetVolumeObjectPrimaryBlockNum
1039
// Function: Extract the primary block number for the volume header or
1040
// master directory (depanding on volume type) from the VolumeObject.
1042
// Result: returns block number of primary MDB or VHB or 0 if none are valid
1043
// or if volume type is unknown.
1044
//******************************************************************************
1045
void GetVolumeObjectPrimaryBlockNum( UInt64 * theBlockNumPtr )
1047
VolumeObjectPtr myVOPtr;
1049
myVOPtr = GetVolumeObjectPtr( );
1050
*theBlockNumPtr = 0; // default to none
1052
if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType ||
1053
myVOPtr->volumeType == kPureHFSPlusVolumeType ) {
1054
*theBlockNumPtr = myVOPtr->primaryVHB;
1056
else if ( myVOPtr->volumeType == kHFSVolumeType ) {
1057
*theBlockNumPtr = myVOPtr->primaryMDB;
1062
} /* GetVolumeObjectPrimaryBlockNum */
1065
//******************************************************************************
1066
// Routine: InitializeVolumeObject
1068
// Function: Locate volume headers and / or master directory blocks for this
1069
// volume and fill where they are located on the volume and the type
1070
// of volume we are dealing with. We have three types of HFS volumes:
1071
// � HFS - standard (old format) where primary MDB is 2nd block into
1072
// the volume and alternate MDB is 2nd to last block on the volume.
1073
// � pure HFS+ - where primary volume header is 2nd block into
1074
// the volume and alternate volume header is 2nd to last block on
1076
// � wrapped HFS+ - where primary MDB is 2nd block into the volume and
1077
// alternate MDB is 2nd to last block on the volume. The embedded
1078
// HFS+ volume header locations are calculated from drEmbedExtent
1081
// Result: returns nothing. Will fill in SGlob.VolumeObject data
1082
//******************************************************************************
1083
void InitializeVolumeObject( SGlobPtr GPtr )
1086
HFSMasterDirectoryBlock * myMDBPtr;
1087
HFSPlusVolumeHeader * myVHPtr;
1088
VolumeObjectPtr myVOPtr;
1089
HFSPlusVolumeHeader myPriVolHeader;
1090
BlockDescriptor myBlockDescriptor;
1092
myBlockDescriptor.buffer = NULL;
1093
myVOPtr = GetVolumeObjectPtr( );
1094
myVOPtr->flags |= kVO_Inited;
1095
myVOPtr->vcbPtr = GPtr->calculatedVCB;
1097
// Determine volume size in sectors
1098
err = GetDeviceSize( GPtr->calculatedVCB->vcbDriveNumber,
1099
&myVOPtr->totalDeviceSectors,
1100
&myVOPtr->sectorSize );
1101
if ( (myVOPtr->totalDeviceSectors < 3) || (err != noErr) ) {
1102
if ( GPtr->logLevel >= kDebugLog ) {
1103
printf("\tinvalid device information for volume - total sectors = %qd sector size = %d \n",
1104
myVOPtr->totalDeviceSectors, myVOPtr->sectorSize);
1109
// get the primary volume header or master directory block (depending on volume type)
1110
// should always be block 2 (relative to 0) into the volume.
1111
err = GetVolumeObjectBlock( myVOPtr, MDB_BlkN, &myBlockDescriptor );
1112
if ( err == noErr ) {
1113
myMDBPtr = (HFSMasterDirectoryBlock *) myBlockDescriptor.buffer;
1114
if ( myMDBPtr->drSigWord == kHFSPlusSigWord || myMDBPtr->drSigWord == kHFSXSigWord) {
1115
myVHPtr = (HFSPlusVolumeHeader *) myMDBPtr;
1117
myVOPtr->primaryVHB = MDB_BlkN; // save location
1118
myVOPtr->alternateVHB = myVOPtr->totalDeviceSectors - 2; // save location
1119
err = ValidVolumeHeader( myVHPtr );
1120
if ( err == noErr ) {
1121
myVOPtr->flags |= kVO_PriVHBOK;
1122
bcopy( myVHPtr, &myPriVolHeader, sizeof( *myVHPtr ) );
1125
if ( GPtr->logLevel >= kDebugLog ) {
1126
printf( "\tInvalid primary volume header - error %d \n", err );
1130
else if ( myMDBPtr->drSigWord == kHFSSigWord ) {
1131
// we could have an HFS or wrapped HFS+ volume
1132
myVOPtr->primaryMDB = MDB_BlkN; // save location
1133
myVOPtr->alternateMDB = myVOPtr->totalDeviceSectors - 2; // save location
1134
myVOPtr->flags |= kVO_PriMDBOK;
1137
if ( GPtr->logLevel >= kDebugLog ) {
1138
printf( "\tBlock %d is not an MDB or Volume Header \n", MDB_BlkN );
1141
(void) ReleaseVolumeBlock( GPtr->calculatedVCB, &myBlockDescriptor, kReleaseBlock );
1144
if ( GPtr->logLevel >= kDebugLog ) {
1145
printf( "\tcould not get volume block %d, err %d \n", MDB_BlkN, err );
1149
// get the alternate volume header or master directory block (depending on volume type)
1150
// should always be 2nd to last sector.
1151
err = GetVolumeObjectBlock( myVOPtr, myVOPtr->totalDeviceSectors - 2, &myBlockDescriptor );
1152
if ( err == noErr ) {
1153
myMDBPtr = (HFSMasterDirectoryBlock *) myBlockDescriptor.buffer;
1154
if ( myMDBPtr->drSigWord == kHFSPlusSigWord || myMDBPtr->drSigWord == kHFSXSigWord ) {
1155
myVHPtr = (HFSPlusVolumeHeader *) myMDBPtr;
1157
myVOPtr->primaryVHB = MDB_BlkN; // save location
1158
myVOPtr->alternateVHB = myVOPtr->totalDeviceSectors - 2; // save location
1159
err = ValidVolumeHeader( myVHPtr );
1160
if ( err == noErr ) {
1161
// check to see if the primary and alternates are in sync. 3137809
1162
myVOPtr->flags |= kVO_AltVHBOK;
1163
CompareVolHeaderBTreeSizes( GPtr, myVOPtr, &myPriVolHeader, myVHPtr );
1166
if ( GPtr->logLevel >= kDebugLog ) {
1167
printf( "\tInvalid alternate volume header - error %d \n", err );
1171
else if ( myMDBPtr->drSigWord == kHFSSigWord ) {
1172
myVOPtr->primaryMDB = MDB_BlkN; // save location
1173
myVOPtr->alternateMDB = myVOPtr->totalDeviceSectors - 2; // save location
1174
myVOPtr->flags |= kVO_AltMDBOK;
1177
if ( GPtr->logLevel >= kDebugLog ) {
1178
printf( "\tBlock %qd is not an MDB or Volume Header \n", myVOPtr->totalDeviceSectors - 2 );
1182
(void) ReleaseVolumeBlock( GPtr->calculatedVCB, &myBlockDescriptor, kReleaseBlock );
1185
if ( GPtr->logLevel >= kDebugLog ) {
1186
printf( "\tcould not get alternate volume header at %qd, err %d \n",
1187
myVOPtr->totalDeviceSectors - 2, err );
1191
// get the embedded volume header (if applicable).
1192
if ( (myVOPtr->flags & kVO_AltMDBOK) != 0 ) {
1193
err = GetVolumeObjectBlock( myVOPtr, myVOPtr->alternateMDB, &myBlockDescriptor );
1194
if ( err == noErr ) {
1195
myMDBPtr = (HFSMasterDirectoryBlock *) myBlockDescriptor.buffer;
1196
GetEmbeddedVolumeHeaders( GPtr, myMDBPtr, false );
1197
(void) ReleaseVolumeBlock( GPtr->calculatedVCB, &myBlockDescriptor, kReleaseBlock );
1201
// Now we will look for embedded HFS+ volume headers using the primary MDB if
1202
// we haven't already located them.
1203
if ( (myVOPtr->flags & kVO_PriMDBOK) != 0 &&
1204
((myVOPtr->flags & kVO_PriVHBOK) == 0 || (myVOPtr->flags & kVO_AltVHBOK) == 0) ) {
1205
err = GetVolumeObjectBlock( myVOPtr, myVOPtr->primaryMDB, &myBlockDescriptor );
1206
if ( err == noErr ) {
1207
myMDBPtr = (HFSMasterDirectoryBlock *) myBlockDescriptor.buffer;
1208
GetEmbeddedVolumeHeaders( GPtr, myMDBPtr, true );
1209
(void) ReleaseVolumeBlock( GPtr->calculatedVCB, &myBlockDescriptor, kReleaseBlock );
1212
if ( GPtr->logLevel >= kDebugLog ) {
1213
printf( "\tcould not get primary MDB at block %qd, err %d \n", myVOPtr->primaryMDB, err );
1219
// set the type of volume using the flags we set as we located the various header / master
1221
if ( ((myVOPtr->flags & kVO_PriVHBOK) != 0 || (myVOPtr->flags & kVO_AltVHBOK) != 0) &&
1222
((myVOPtr->flags & kVO_PriMDBOK) != 0 || (myVOPtr->flags & kVO_AltMDBOK) != 0) ) {
1223
myVOPtr->volumeType = kEmbededHFSPlusVolumeType;
1225
else if ( ((myVOPtr->flags & kVO_PriVHBOK) != 0 || (myVOPtr->flags & kVO_AltVHBOK) != 0) &&
1226
(myVOPtr->flags & kVO_PriMDBOK) == 0 && (myVOPtr->flags & kVO_AltMDBOK) == 0 ) {
1227
myVOPtr->volumeType = kPureHFSPlusVolumeType;
1229
else if ( (myVOPtr->flags & kVO_PriVHBOK) == 0 && (myVOPtr->flags & kVO_AltVHBOK) == 0 &&
1230
((myVOPtr->flags & kVO_PriMDBOK) != 0 || (myVOPtr->flags & kVO_AltMDBOK) != 0) ) {
1231
myVOPtr->volumeType = kHFSVolumeType;
1234
myVOPtr->volumeType = kUnknownVolumeType;
1238
} /* InitializeVolumeObject */
1241
//******************************************************************************
1242
// Routine: PrintVolumeObject
1244
// Function: Print out some helpful info about the state of our VolumeObject.
1246
// Result: returns nothing.
1247
//******************************************************************************
1248
void PrintVolumeObject( void )
1250
VolumeObjectPtr myVOPtr;
1252
myVOPtr = GetVolumeObjectPtr( );
1254
if ( myVOPtr->volumeType == kHFSVolumeType )
1255
printf( "\tvolume type is HFS \n" );
1256
else if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType )
1257
printf( "\tvolume type is embedded HFS+ \n" );
1258
else if ( myVOPtr->volumeType == kPureHFSPlusVolumeType )
1259
printf( "\tvolume type is pure HFS+ \n" );
1261
printf( "\tunknown volume type \n" );
1263
printf( "\tprimary MDB is at block %qd 0x%02qx \n", myVOPtr->primaryMDB, myVOPtr->primaryMDB );
1264
printf( "\talternate MDB is at block %qd 0x%02qx \n", myVOPtr->alternateMDB, myVOPtr->alternateMDB );
1265
printf( "\tprimary VHB is at block %qd 0x%02qx \n", myVOPtr->primaryVHB, myVOPtr->primaryVHB );
1266
printf( "\talternate VHB is at block %qd 0x%02qx \n", myVOPtr->alternateVHB, myVOPtr->alternateVHB );
1267
printf( "\tsector size = %d 0x%02x \n", myVOPtr->sectorSize, myVOPtr->sectorSize );
1268
printf( "\tVolumeObject flags = 0x%02X \n", myVOPtr->flags );
1269
printf( "\ttotal sectors for volume = %qd 0x%02qx \n",
1270
myVOPtr->totalDeviceSectors, myVOPtr->totalDeviceSectors );
1271
printf( "\ttotal sectors for embedded volume = %qd 0x%02qx \n",
1272
myVOPtr->totalEmbeddedSectors, myVOPtr->totalEmbeddedSectors );
1276
} /* PrintVolumeObject */
1279
//******************************************************************************
1280
// Routine: GetEmbeddedVolumeHeaders
1282
// Function: Given a MDB (Master Directory Block) from an HFS volume, check
1283
// to see if there is an embedded HFS+ volume. If we find an
1284
// embedded HFS+ volume fill in relevant SGlob.VolumeObject data.
1286
// Result: returns nothing. Will fill in VolumeObject data
1287
//******************************************************************************
1289
static void GetEmbeddedVolumeHeaders( SGlobPtr GPtr,
1290
HFSMasterDirectoryBlock * theMDBPtr,
1291
Boolean isPrimaryMDB )
1294
HFSPlusVolumeHeader * myVHPtr;
1295
VolumeObjectPtr myVOPtr;
1296
UInt64 myHFSPlusSectors;
1297
UInt64 myPrimaryBlockNum;
1298
UInt64 myAlternateBlockNum;
1299
HFSPlusVolumeHeader myAltVolHeader;
1300
BlockDescriptor myBlockDescriptor;
1302
myBlockDescriptor.buffer = NULL;
1303
myVOPtr = GetVolumeObjectPtr( );
1305
// NOTE - If all of the embedded volume information is zero, then assume
1306
// this really is a plain HFS disk like it says. There could be ghost
1307
// volume headers left over when someone reinitializes a large HFS Plus
1308
// volume as HFS. The original embedded primary volume header and
1309
// alternate volume header are not zeroed out.
1310
if ( theMDBPtr->drEmbedSigWord == 0 &&
1311
theMDBPtr->drEmbedExtent.blockCount == 0 &&
1312
theMDBPtr->drEmbedExtent.startBlock == 0 ) {
1316
// number of sectors in our embedded HFS+ volume
1317
myHFSPlusSectors = (theMDBPtr->drAlBlkSiz / Blk_Size) * theMDBPtr->drEmbedExtent.blockCount;
1319
// offset of embedded HFS+ volume (in bytes) into HFS wrapper volume
1320
// NOTE - UInt32 is OK since we don't support HFS Wrappers on TB volumes
1321
myVOPtr->embeddedOffset =
1322
(theMDBPtr->drEmbedExtent.startBlock * theMDBPtr->drAlBlkSiz) +
1323
(theMDBPtr->drAlBlSt * Blk_Size);
1325
// Embedded alternate volume header is always 2nd to last sector
1326
myAlternateBlockNum =
1327
theMDBPtr->drAlBlSt +
1328
((theMDBPtr->drAlBlkSiz / Blk_Size) * theMDBPtr->drEmbedExtent.startBlock) +
1329
myHFSPlusSectors - 2;
1331
// Embedded primary volume header should always be block 2 (relative to 0)
1332
// into the embedded volume
1333
myPrimaryBlockNum = (theMDBPtr->drEmbedExtent.startBlock * theMDBPtr->drAlBlkSiz / Blk_Size) +
1334
theMDBPtr->drAlBlSt + 2;
1336
// get the embedded alternate volume header
1337
err = GetVolumeObjectBlock( myVOPtr, myAlternateBlockNum, &myBlockDescriptor );
1338
if ( err == noErr ) {
1339
myVHPtr = (HFSPlusVolumeHeader *) myBlockDescriptor.buffer;
1340
if ( myVHPtr->signature == kHFSPlusSigWord ) {
1342
myVOPtr->alternateVHB = myAlternateBlockNum; // save location
1343
myVOPtr->primaryVHB = myPrimaryBlockNum; // save location
1344
err = ValidVolumeHeader( myVHPtr );
1345
if ( err == noErr ) {
1346
myVOPtr->flags |= kVO_AltVHBOK;
1347
myVOPtr->totalEmbeddedSectors = myHFSPlusSectors;
1348
bcopy( myVHPtr, &myAltVolHeader, sizeof( *myVHPtr ) );
1351
if ( GPtr->logLevel >= kDebugLog ) {
1352
printf( "\tInvalid embedded alternate volume header at block %qd - error %d \n", myAlternateBlockNum, err );
1357
if ( GPtr->logLevel >= kDebugLog ) {
1358
printf( "\tBlock number %qd is not embedded alternate volume header \n", myAlternateBlockNum );
1361
(void) ReleaseVolumeBlock( GPtr->calculatedVCB, &myBlockDescriptor, kReleaseBlock );
1364
if ( GPtr->logLevel >= kDebugLog ) {
1365
printf( "\tcould not get embedded alternate volume header at %qd, err %d \n",
1366
myAlternateBlockNum, err );
1370
// get the embedded primary volume header
1371
err = GetVolumeObjectBlock( myVOPtr, myPrimaryBlockNum, &myBlockDescriptor );
1372
if ( err == noErr ) {
1373
myVHPtr = (HFSPlusVolumeHeader *) myBlockDescriptor.buffer;
1374
if ( myVHPtr->signature == kHFSPlusSigWord ) {
1376
myVOPtr->primaryVHB = myPrimaryBlockNum; // save location
1377
myVOPtr->alternateVHB = myAlternateBlockNum; // save location
1378
err = ValidVolumeHeader( myVHPtr );
1379
if ( err == noErr ) {
1380
myVOPtr->flags |= kVO_PriVHBOK;
1381
myVOPtr->totalEmbeddedSectors = myHFSPlusSectors;
1383
// check to see if the primary and alternates are in sync. 3137809
1384
CompareVolHeaderBTreeSizes( GPtr, myVOPtr, myVHPtr, &myAltVolHeader );
1387
if ( GPtr->logLevel >= kDebugLog ) {
1388
printf( "\tInvalid embedded primary volume header at block %qd - error %d \n", myPrimaryBlockNum, err );
1393
if ( GPtr->logLevel >= kDebugLog ) {
1394
printf( "\tBlock number %qd is not embedded primary volume header \n", myPrimaryBlockNum );
1397
(void) ReleaseVolumeBlock( GPtr->calculatedVCB, &myBlockDescriptor, kReleaseBlock );
1400
if ( GPtr->logLevel >= kDebugLog ) {
1401
printf( "\tcould not get embedded primary volume header at %qd, err %d \n",
1402
myPrimaryBlockNum, err );
1409
} /* GetEmbeddedVolumeHeaders */
1412
//******************************************************************************
1413
// Routine: CompareVolHeaderBTreeSizes
1415
// Function: checks to see if the primary and alternate volume headers are in
1416
// sync with regards to the catalog and extents btree file size. If
1417
// we find an anomaly we will give preference to the volume header
1418
// with the larger of the btree files since these files never shrink.
1419
// Added for radar #3137809.
1421
// Result: returns nothing.
1422
//******************************************************************************
1423
static void CompareVolHeaderBTreeSizes( SGlobPtr GPtr,
1424
VolumeObjectPtr theVOPtr,
1425
HFSPlusVolumeHeader * thePriVHPtr,
1426
HFSPlusVolumeHeader * theAltVHPtr )
1432
weDisagree = usePrimary = useAlternate = 0;
1434
// we only check if both volume headers appear to be OK
1435
if ( (theVOPtr->flags & kVO_PriVHBOK) == 0 || (theVOPtr->flags & kVO_AltVHBOK) == 0 )
1438
if ( thePriVHPtr->catalogFile.totalBlocks != theAltVHPtr->catalogFile.totalBlocks ) {
1439
// only continue if the B*Tree files both start at the same block number
1440
if ( thePriVHPtr->catalogFile.extents[0].startBlock == theAltVHPtr->catalogFile.extents[0].startBlock ) {
1442
if ( thePriVHPtr->catalogFile.totalBlocks > theAltVHPtr->catalogFile.totalBlocks )
1446
if ( GPtr->logLevel >= kDebugLog ) {
1447
printf( "\tvolume headers disagree on catalog file total blocks - primary %d alternate %d \n",
1448
thePriVHPtr->catalogFile.totalBlocks, theAltVHPtr->catalogFile.totalBlocks );
1453
if ( thePriVHPtr->extentsFile.totalBlocks != theAltVHPtr->extentsFile.totalBlocks ) {
1454
// only continue if the B*Tree files both start at the same block number
1455
if ( thePriVHPtr->extentsFile.extents[0].startBlock == theAltVHPtr->extentsFile.extents[0].startBlock ) {
1457
if ( thePriVHPtr->extentsFile.totalBlocks > theAltVHPtr->extentsFile.totalBlocks )
1461
if ( GPtr->logLevel >= kDebugLog ) {
1462
printf( "\tvolume headers disagree on extents file total blocks - primary %d alternate %d \n",
1463
thePriVHPtr->extentsFile.totalBlocks, theAltVHPtr->extentsFile.totalBlocks );
1468
if ( weDisagree == 0 )
1471
// we have a disagreement. we resolve the issue by using the larger of the two.
1472
if ( usePrimary == 1 && useAlternate == 1 ) {
1473
// this should never happen, but if it does, bail without choosing a preference
1474
if ( GPtr->logLevel >= kDebugLog ) {
1475
printf( "\tvolume headers disagree but there is confusion on which to use \n" );
1480
if ( usePrimary == 1 ) {
1481
// mark alternate as bogus
1482
theVOPtr->flags &= ~kVO_AltVHBOK;
1484
else if ( useAlternate == 1 ) {
1485
// mark primary as bogus
1486
theVOPtr->flags &= ~kVO_PriVHBOK;
1491
} /* CompareVolHeaderBTreeSizes */
1493
//******************************************************************************
1494
// Routine: VolumeObjectIsValid
1496
// Function: determine if the volume represented by our VolumeObject is a
1497
// valid volume type (i.e. not unknown type)
1499
// Result: returns true if volume is known volume type (i.e. HFS, HFS+)
1501
//******************************************************************************
1502
Boolean VolumeObjectIsValid(void)
1504
VolumeObjectPtr myVOPtr = GetVolumeObjectPtr();
1506
/* Check if the type is unknown type */
1507
if (myVOPtr->volumeType == kUnknownVolumeType) {
1511
/* Check if it is HFS+ volume */
1512
if (VolumeObjectIsHFSPlus() == true) {
1516
/* Check if it is HFS volume */
1517
if (VolumeObjectIsHFS() == true) {
1522
} /* VolumeObjectIsValid */
1524
//******************************************************************************
1525
// Routine: VolumeObjectIsHFSPlus
1527
// Function: determine if the volume represented by our VolumeObject is an
1528
// HFS+ volume (pure or embedded).
1530
// Result: returns true if volume is pure HFS+ or embedded HFS+ else false.
1531
//******************************************************************************
1532
Boolean VolumeObjectIsHFSPlus( void )
1534
VolumeObjectPtr myVOPtr;
1536
myVOPtr = GetVolumeObjectPtr( );
1538
if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType ||
1539
myVOPtr->volumeType == kPureHFSPlusVolumeType ) {
1545
} /* VolumeObjectIsHFSPlus */
1548
//******************************************************************************
1549
// Routine: VolumeObjectIsHFS
1551
// Function: determine if the volume represented by our VolumeObject is an
1552
// HFS (standard) volume.
1554
// Result: returns true if HFS (standard) volume.
1555
//******************************************************************************
1556
Boolean VolumeObjectIsHFS( void )
1558
VolumeObjectPtr myVOPtr;
1560
myVOPtr = GetVolumeObjectPtr( );
1562
if ( myVOPtr->volumeType == kHFSVolumeType )
1567
} /* VolumeObjectIsHFS */
1570
//******************************************************************************
1571
// Routine: VolumeObjectIsEmbeddedHFSPlus
1573
// Function: determine if the volume represented by our VolumeObject is an
1574
// embedded HFS plus volume.
1576
// Result: returns true if embedded HFS plus volume.
1577
//******************************************************************************
1578
Boolean VolumeObjectIsEmbeddedHFSPlus( void )
1580
VolumeObjectPtr myVOPtr;
1582
myVOPtr = GetVolumeObjectPtr( );
1584
if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType )
1589
} /* VolumeObjectIsEmbeddedHFSPlus */
1592
//******************************************************************************
1593
// Routine: VolumeObjectIsPureHFSPlus
1595
// Function: determine if the volume represented by our VolumeObject is an
1596
// pure HFS plus volume.
1598
// Result: returns true if pure HFS plus volume.
1599
//******************************************************************************
1600
Boolean VolumeObjectIsPureHFSPlus( void )
1602
VolumeObjectPtr myVOPtr;
1604
myVOPtr = GetVolumeObjectPtr( );
1606
if ( myVOPtr->volumeType == kPureHFSPlusVolumeType )
1611
} /* VolumeObjectIsPureHFSPlus */
1614
//******************************************************************************
1615
// Routine: GetVolumeObjectPtr
1617
// Function: Accessor routine to get a pointer to our VolumeObject structure.
1619
// Result: returns pointer to our VolumeObject.
1620
//******************************************************************************
1621
VolumeObjectPtr GetVolumeObjectPtr( void )
1623
static VolumeObject myVolumeObject;
1624
static int myInited = 0;
1626
if ( myInited == 0 ) {
1628
bzero( &myVolumeObject, sizeof(myVolumeObject) );
1631
return( &myVolumeObject );
1633
} /* GetVolumeObjectPtr */
1636
//******************************************************************************
1637
// Routine: CheckEmbeddedVolInfoInMDBs
1639
// Function: Check the primary and alternate MDB to see if the embedded volume
1640
// information (drEmbedSigWord and drEmbedExtent) match.
1643
//******************************************************************************
1644
void CheckEmbeddedVolInfoInMDBs( SGlobPtr GPtr )
1647
Boolean primaryIsDamaged = false;
1648
Boolean alternateIsDamaged = false;
1649
VolumeObjectPtr myVOPtr;
1650
HFSMasterDirectoryBlock * myPriMDBPtr;
1651
HFSMasterDirectoryBlock * myAltMDBPtr;
1654
BlockDescriptor myPrimary;
1655
BlockDescriptor myAlternate;
1657
myVOPtr = GetVolumeObjectPtr( );
1658
myPrimary.buffer = NULL;
1659
myAlternate.buffer = NULL;
1661
// we only check this if primary and alternate are OK at this point. OK means
1662
// that the primary and alternate MDBs have the correct signature and at least
1663
// one of them points to a valid embedded HFS+ volume.
1664
if ( VolumeObjectIsEmbeddedHFSPlus( ) == false ||
1665
(myVOPtr->flags & kVO_PriMDBOK) == 0 || (myVOPtr->flags & kVO_AltMDBOK) == 0 )
1668
err = GetVolumeObjectPrimaryMDB( &myPrimary );
1669
if ( err != noErr ) {
1670
if ( GPtr->logLevel >= kDebugLog ) {
1671
printf( "\tcould not get primary MDB \n" );
1673
goto ExitThisRoutine;
1675
myPriMDBPtr = (HFSMasterDirectoryBlock *) myPrimary.buffer;
1676
err = GetVolumeObjectAlternateMDB( &myAlternate );
1677
if ( err != noErr ) {
1678
if ( GPtr->logLevel >= kDebugLog ) {
1679
printf( "\tcould not get alternate MDB \n" );
1681
goto ExitThisRoutine;
1683
myAltMDBPtr = (HFSMasterDirectoryBlock *) myAlternate.buffer;
1685
// bail if everything looks good. NOTE - we can bail if drEmbedExtent info
1686
// is the same in the primary and alternate MDB because we know one of them is
1687
// valid (or VolumeObjectIsEmbeddedHFSPlus would be false and we would not be
1689
if ( myPriMDBPtr->drEmbedSigWord == kHFSPlusSigWord &&
1690
myAltMDBPtr->drEmbedSigWord == kHFSPlusSigWord &&
1691
myPriMDBPtr->drEmbedExtent.blockCount == myAltMDBPtr->drEmbedExtent.blockCount &&
1692
myPriMDBPtr->drEmbedExtent.startBlock == myAltMDBPtr->drEmbedExtent.startBlock )
1693
goto ExitThisRoutine;
1695
// we know that VolumeObject.embeddedOffset and VolumeObject.totalEmbeddedSectors
1696
// are correct so we will verify the info in each MDB calculates to these values.
1697
myOffset = (myPriMDBPtr->drEmbedExtent.startBlock * myPriMDBPtr->drAlBlkSiz) +
1698
(myPriMDBPtr->drAlBlSt * Blk_Size);
1699
mySectors = (myPriMDBPtr->drAlBlkSiz / Blk_Size) * myPriMDBPtr->drEmbedExtent.blockCount;
1701
if ( myOffset != myVOPtr->embeddedOffset || mySectors != myVOPtr->totalEmbeddedSectors )
1702
primaryIsDamaged = true;
1704
myOffset = (myAltMDBPtr->drEmbedExtent.startBlock * myAltMDBPtr->drAlBlkSiz) +
1705
(myAltMDBPtr->drAlBlSt * Blk_Size);
1706
mySectors = (myAltMDBPtr->drAlBlkSiz / Blk_Size) * myAltMDBPtr->drEmbedExtent.blockCount;
1708
if ( myOffset != myVOPtr->embeddedOffset || mySectors != myVOPtr->totalEmbeddedSectors )
1709
alternateIsDamaged = true;
1711
// now check drEmbedSigWord if everything else is OK
1712
if ( primaryIsDamaged == false && alternateIsDamaged == false ) {
1713
if ( myPriMDBPtr->drEmbedSigWord != kHFSPlusSigWord )
1714
primaryIsDamaged = true;
1715
else if ( myAltMDBPtr->drEmbedSigWord != kHFSPlusSigWord )
1716
alternateIsDamaged = true;
1719
if ( primaryIsDamaged || alternateIsDamaged ) {
1720
GPtr->VIStat |= S_WMDB;
1721
WriteError( GPtr, E_MDBDamaged, 7, 0 );
1722
if ( primaryIsDamaged ) {
1723
myVOPtr->flags &= ~kVO_PriMDBOK; // mark the primary MDB as damaged
1724
if ( GPtr->logLevel >= kDebugLog )
1725
printf("\tinvalid primary wrapper MDB \n");
1728
myVOPtr->flags &= ~kVO_AltMDBOK; // mark the alternate MDB as damaged
1729
if ( GPtr->logLevel >= kDebugLog )
1730
printf("\tinvalid alternate wrapper MDB \n");
1735
if ( myPrimary.buffer != NULL )
1736
(void) ReleaseVolumeBlock( myVOPtr->vcbPtr, &myPrimary, kReleaseBlock );
1737
if ( myAlternate.buffer != NULL )
1738
(void) ReleaseVolumeBlock( myVOPtr->vcbPtr, &myAlternate, kReleaseBlock );
1742
} /* CheckEmbeddedVolInfoInMDBs */
1745
//******************************************************************************
1746
// Routine: ValidVolumeHeader
1748
// Function: Run some sanity checks to make sure the HFSPlusVolumeHeader is valid
1751
//******************************************************************************
1752
OSErr ValidVolumeHeader( HFSPlusVolumeHeader *volumeHeader )
1756
if ((volumeHeader->signature == kHFSPlusSigWord && volumeHeader->version == kHFSPlusVersion) ||
1757
(volumeHeader->signature == kHFSXSigWord && volumeHeader->version == kHFSXVersion))
1759
if ( (volumeHeader->blockSize != 0) && ((volumeHeader->blockSize & 0x01FF) == 0) ) // non zero multiple of 512
1762
err = badMDBErr; //�� I want badVolumeHeaderErr in Errors.i
1773
//_______________________________________________________________________
1777
// This routine initializes a B-Tree header.
1779
// Note: Since large volumes will have bigger b-trees they need to
1780
// have map nodes setup.
1781
//_______________________________________________________________________
1783
void InitBTreeHeader (UInt32 fileSize, UInt32 clumpSize, UInt16 nodeSize, UInt16 recordCount, UInt16 keySize,
1784
UInt32 attributes, UInt32 *mapNodes, void *buffer)
1788
UInt32 nodeBitsInHeader;
1790
BTNodeDescriptor *ndp;
1795
ClearMemory(buffer, nodeSize); // start out with clean node
1797
nodeCount = fileSize / nodeSize;
1798
nodeBitsInHeader = 8 * (nodeSize - sizeof(BTNodeDescriptor) - sizeof(BTHeaderRec) - kBTreeHeaderUserBytes - 4*sizeof(SInt16));
1800
usedNodes = 1; // header takes up one node
1801
*mapNodes = 0; // number of map nodes initially (0)
1804
// FILL IN THE NODE DESCRIPTOR:
1805
ndp = (BTNodeDescriptor*) buffer; // point to node descriptor
1807
ndp->kind = kBTHeaderNode; // this node contains the B-tree header
1808
ndp->numRecords = 3; // there are 3 records (header, map, and user)
1810
if (nodeCount > nodeBitsInHeader) // do we need additional map nodes?
1812
UInt32 nodeBitsInMapNode;
1814
nodeBitsInMapNode = 8 * (nodeSize - sizeof(BTNodeDescriptor) - 2*sizeof(SInt16) - 2); //�� why (-2) at end???
1816
if (recordCount > 0) // catalog B-tree?
1817
ndp->fLink = 2; // link points to initial map node
1818
//�� Assumes all records will fit in one node. It would be better
1819
//�� to put the map node(s) first, then the records.
1821
ndp->fLink = 1; // link points to initial map node
1823
*mapNodes = (nodeCount - nodeBitsInHeader + (nodeBitsInMapNode - 1)) / nodeBitsInMapNode;
1824
usedNodes += *mapNodes;
1827
// FILL IN THE HEADER RECORD:
1828
bth = (BTHeaderRec*) ((char*)buffer + sizeof(BTNodeDescriptor)); // point to header
1830
if (recordCount > 0)
1832
++usedNodes; // one more node will be used
1834
bth->treeDepth = 1; // tree depth is one level (leaf)
1835
bth->rootNode = 1; // root node is also leaf
1836
bth->firstLeafNode = 1; // first leaf node
1837
bth->lastLeafNode = 1; // last leaf node
1840
bth->attributes = attributes; // flags for 16-bit key lengths, and variable sized index keys
1841
bth->leafRecords = recordCount; // total number of data records
1842
bth->nodeSize = nodeSize; // size of a node
1843
bth->maxKeyLength = keySize; // maximum length of a key
1844
bth->totalNodes = nodeCount; // total number of nodes
1845
bth->freeNodes = nodeCount - usedNodes; // number of free nodes
1846
bth->clumpSize = clumpSize; //
1847
// bth->btreeType = 0; // 0 = meta data B-tree
1850
// FILL IN THE MAP RECORD:
1851
bitMapPtr = (UInt32*) ((Byte*) buffer + sizeof(BTNodeDescriptor) + sizeof(BTHeaderRec) + kBTreeHeaderUserBytes); // point to bitmap
1853
// MARK NODES THAT ARE IN USE:
1854
// Note - worst case (32MB alloc blk) will have only 18 nodes in use.
1855
*bitMapPtr = ~((UInt32) 0xFFFFFFFF >> usedNodes);
1858
// PLACE RECORD OFFSETS AT THE END OF THE NODE:
1859
offsetPtr = (SInt16*) ((Byte*) buffer + nodeSize - 4*sizeof(SInt16));
1861
*offsetPtr++ = sizeof(BTNodeDescriptor) + sizeof(BTHeaderRec) + kBTreeHeaderUserBytes + nodeBitsInHeader/8; // offset to free space
1862
*offsetPtr++ = sizeof(BTNodeDescriptor) + sizeof(BTHeaderRec) + kBTreeHeaderUserBytes; // offset to allocation map
1863
*offsetPtr++ = sizeof(BTNodeDescriptor) + sizeof(BTHeaderRec); // offset to user space
1864
*offsetPtr = sizeof(BTNodeDescriptor); // offset to BTH
1867
/*------------------------------------------------------------------------------
1869
Routine: CalculateItemCount
1871
Function: determines number of items for progress feedback
1873
Input: vRefNum: the volume to count items
1875
Output: number of items
1877
------------------------------------------------------------------------------*/
1879
void CalculateItemCount( SGlob *GPtr, UInt64 *itemCount, UInt64 *onePercent )
1881
BTreeControlBlock *btcb;
1882
VolumeObjectPtr myVOPtr;
1884
UInt32 realFreeNodes;
1885
SVCB *vcb = GPtr->calculatedVCB;
1887
/* each bitmap segment is an item */
1888
myVOPtr = GetVolumeObjectPtr( );
1889
items = GPtr->calculatedVCB->vcbTotalBlocks / 1024;
1892
// Items is the used node count and leaf record count for each btree...
1895
btcb = (BTreeControlBlock*) vcb->vcbCatalogFile->fcbBtree;
1896
realFreeNodes = ((BTreeExtensionsRec*)btcb->refCon)->realFreeNodeCount;
1897
items += (2 * btcb->leafRecords) + (btcb->totalNodes - realFreeNodes);
1899
btcb = (BTreeControlBlock*) vcb->vcbExtentsFile->fcbBtree;
1900
realFreeNodes = ((BTreeExtensionsRec*)btcb->refCon)->realFreeNodeCount;
1901
items += btcb->leafRecords + (btcb->totalNodes - realFreeNodes);
1903
if ( vcb->vcbAttributesFile != NULL )
1905
btcb = (BTreeControlBlock*) vcb->vcbAttributesFile->fcbBtree;
1906
realFreeNodes = ((BTreeExtensionsRec*)btcb->refCon)->realFreeNodeCount;
1908
items += (btcb->leafRecords + (btcb->totalNodes - realFreeNodes));
1911
*onePercent = items/ 100;
1914
// [2239291] We're calculating the progress for the wrapper and the embedded volume separately, which
1915
// confuses the caller (since they see the progress jump to a large percentage while checking the wrapper,
1916
// then jump to a small percentage when starting to check the embedded volume). To avoid this behavior,
1917
// we pretend the wrapper has 100 times as many items as it really does. This means the progress will
1918
// never exceed 1% for the wrapper.
1920
/* fsck_hfs doesn't deal wih the wrapper at this time (8.29.2002)
1921
if ( (myVOPtr->volumeType == kEmbededHFSPlusVolumeType) && (GPtr->inputFlags & examineWrapperMask) )
1924
// Add en extra � 5% to smooth the progress
1925
items += *onePercent * 5;
1931
SFCB* ResolveFCB(short fileRefNum)
1933
return( (SFCB*)((unsigned long)GetFCBSPtr() + (unsigned long)fileRefNum) );
1937
//******************************************************************************
1938
// Routine: SetupFCB fills in the FCB info
1940
// Returns: The filled up FCB
1941
//******************************************************************************
1942
void SetupFCB( SVCB *vcb, SInt16 refNum, UInt32 fileID, UInt32 fileClumpSize )
1946
fcb = ResolveFCB(refNum);
1948
fcb->fcbFileID = fileID;
1949
fcb->fcbVolume = vcb;
1950
fcb->fcbClumpSize = fileClumpSize;
1954
//******************************************************************************
1956
// Routine: ResolveFileRefNum
1958
// Purpose: Return a file reference number for a given file control block
1962
// fileCtrlBlockPtr Pointer to the SFCB
1965
// result File reference number,
1966
// or 0 if fileCtrlBlockPtr is invalid
1968
pascal short ResolveFileRefNum(SFCB * fileCtrlBlockPtr)
1970
return( (unsigned long)fileCtrlBlockPtr - (unsigned long)GetFCBSPtr() );
1977
void SetFCBSPtr( Ptr value )
1982
Ptr GetFCBSPtr( void )
1988
//_______________________________________________________________________
1990
// Routine: FlushVolumeControlBlock
1991
// Arguments: SVCB *vcb
1992
// Output: OSErr err
1994
// Function: Flush volume information to either the HFSPlusVolumeHeader
1995
// of the Master Directory Block
1996
//_______________________________________________________________________
1998
OSErr FlushVolumeControlBlock( SVCB *vcb )
2001
HFSPlusVolumeHeader *volumeHeader;
2003
BlockDescriptor block;
2005
if ( ! IsVCBDirty( vcb ) ) // if it's not dirty
2008
block.buffer = NULL;
2009
err = GetVolumeObjectPrimaryBlock( &block );
2012
// attempt to fix the primary with alternate
2013
if ( block.buffer != NULL ) {
2014
(void) ReleaseVolumeBlock( vcb, &block, kReleaseBlock );
2015
block.buffer = NULL;
2018
err = VolumeObjectFixPrimaryBlock( );
2019
ReturnIfError( err );
2021
// should be able to get it now
2022
err = GetVolumeObjectPrimaryBlock( &block );
2023
ReturnIfError( err );
2026
if ( vcb->vcbSignature == kHFSPlusSigWord )
2028
volumeHeader = (HFSPlusVolumeHeader *) block.buffer;
2030
// 2005507, Keep the MDB creation date and HFSPlusVolumeHeader creation date in sync.
2031
if ( vcb->vcbEmbeddedOffset != 0 ) // It's a wrapped HFS+ volume
2033
HFSMasterDirectoryBlock *mdb;
2034
BlockDescriptor mdb_block;
2036
mdb_block.buffer = NULL;
2037
err = GetVolumeObjectPrimaryMDB( &mdb_block );
2040
mdb = (HFSMasterDirectoryBlock *) mdb_block.buffer;
2041
if ( mdb->drCrDate != vcb->vcbCreateDate ) // The creation date changed
2043
mdb->drCrDate = vcb->vcbCreateDate;
2044
(void) ReleaseVolumeBlock(vcb, &mdb_block, kForceWriteBlock);
2045
mdb_block.buffer = NULL;
2048
if ( mdb_block.buffer != NULL )
2049
(void) ReleaseVolumeBlock(vcb, &mdb_block, kReleaseBlock);
2052
volumeHeader->attributes = vcb->vcbAttributes;
2053
volumeHeader->lastMountedVersion = kFSCKMountVersion;
2054
volumeHeader->createDate = vcb->vcbCreateDate; // NOTE: local time, not GMT!
2055
volumeHeader->modifyDate = vcb->vcbModifyDate;
2056
volumeHeader->backupDate = vcb->vcbBackupDate;
2057
volumeHeader->checkedDate = vcb->vcbCheckedDate;
2058
volumeHeader->fileCount = vcb->vcbFileCount;
2059
volumeHeader->folderCount = vcb->vcbFolderCount;
2060
volumeHeader->blockSize = vcb->vcbBlockSize;
2061
volumeHeader->totalBlocks = vcb->vcbTotalBlocks;
2062
volumeHeader->freeBlocks = vcb->vcbFreeBlocks;
2063
volumeHeader->nextAllocation = vcb->vcbNextAllocation;
2064
volumeHeader->rsrcClumpSize = vcb->vcbRsrcClumpSize;
2065
volumeHeader->dataClumpSize = vcb->vcbDataClumpSize;
2066
volumeHeader->nextCatalogID = vcb->vcbNextCatalogID;
2067
volumeHeader->writeCount = vcb->vcbWriteCount;
2068
volumeHeader->encodingsBitmap = vcb->vcbEncodingsBitmap;
2070
//���should we use the vcb or fcb clumpSize values ????? -djb
2071
volumeHeader->allocationFile.clumpSize = vcb->vcbAllocationFile->fcbClumpSize;
2072
volumeHeader->extentsFile.clumpSize = vcb->vcbExtentsFile->fcbClumpSize;
2073
volumeHeader->catalogFile.clumpSize = vcb->vcbCatalogFile->fcbClumpSize;
2075
CopyMemory( vcb->vcbFinderInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo) );
2077
fcb = vcb->vcbExtentsFile;
2078
CopyMemory( fcb->fcbExtents32, volumeHeader->extentsFile.extents, sizeof(HFSPlusExtentRecord) );
2079
volumeHeader->extentsFile.logicalSize = fcb->fcbLogicalSize;
2080
volumeHeader->extentsFile.totalBlocks = fcb->fcbPhysicalSize / vcb->vcbBlockSize;
2082
fcb = vcb->vcbCatalogFile;
2083
CopyMemory( fcb->fcbExtents32, volumeHeader->catalogFile.extents, sizeof(HFSPlusExtentRecord) );
2084
volumeHeader->catalogFile.logicalSize = fcb->fcbLogicalSize;
2085
volumeHeader->catalogFile.totalBlocks = fcb->fcbPhysicalSize / vcb->vcbBlockSize;
2087
fcb = vcb->vcbAllocationFile;
2088
CopyMemory( fcb->fcbExtents32, volumeHeader->allocationFile.extents, sizeof(HFSPlusExtentRecord) );
2089
volumeHeader->allocationFile.logicalSize = fcb->fcbLogicalSize;
2090
volumeHeader->allocationFile.totalBlocks = fcb->fcbPhysicalSize / vcb->vcbBlockSize;
2092
if (vcb->vcbAttributesFile != NULL) // Only update fields if an attributes file existed and was open
2094
fcb = vcb->vcbAttributesFile;
2095
CopyMemory( fcb->fcbExtents32, volumeHeader->attributesFile.extents, sizeof(HFSPlusExtentRecord) );
2096
volumeHeader->attributesFile.logicalSize = fcb->fcbLogicalSize;
2097
volumeHeader->attributesFile.clumpSize = fcb->fcbClumpSize;
2098
volumeHeader->attributesFile.totalBlocks = fcb->fcbPhysicalSize / vcb->vcbBlockSize;
2103
HFSMasterDirectoryBlock *mdbP;
2105
mdbP = (HFSMasterDirectoryBlock *) block.buffer;
2107
mdbP->drCrDate = vcb->vcbCreateDate;
2108
mdbP->drLsMod = vcb->vcbModifyDate;
2109
mdbP->drAtrb = (UInt16)vcb->vcbAttributes;
2110
mdbP->drClpSiz = vcb->vcbDataClumpSize;
2111
mdbP->drNxtCNID = vcb->vcbNextCatalogID;
2112
mdbP->drFreeBks = vcb->vcbFreeBlocks;
2113
mdbP->drXTClpSiz = vcb->vcbExtentsFile->fcbClumpSize;
2114
mdbP->drCTClpSiz = vcb->vcbCatalogFile->fcbClumpSize;
2116
mdbP->drNmFls = vcb->vcbNmFls;
2117
mdbP->drNmRtDirs = vcb->vcbNmRtDirs;
2118
mdbP->drFilCnt = vcb->vcbFileCount;
2119
mdbP->drDirCnt = vcb->vcbFolderCount;
2121
fcb = vcb->vcbExtentsFile;
2122
CopyMemory( fcb->fcbExtents16, mdbP->drXTExtRec, sizeof( mdbP->drXTExtRec ) );
2124
fcb = vcb->vcbCatalogFile;
2125
CopyMemory( fcb->fcbExtents16, mdbP->drCTExtRec, sizeof( mdbP->drCTExtRec ) );
2128
//-- Write the VHB/MDB out by releasing the block dirty
2129
if ( block.buffer != NULL ) {
2130
err = ReleaseVolumeBlock(vcb, &block, kForceWriteBlock);
2131
block.buffer = NULL;
2133
MarkVCBClean( vcb );
2139
//_______________________________________________________________________
2141
// Routine: FlushAlternateVolumeControlBlock
2142
// Arguments: SVCB *vcb
2143
// Boolean ifHFSPlus
2144
// Output: OSErr err
2146
// Function: Flush volume information to either the Alternate HFSPlusVolumeHeader or the
2147
// Alternate Master Directory Block. Called by the BTree when the catalog
2148
// or extent files grow. Simply BlockMoves the original to the alternate
2150
//_______________________________________________________________________
2152
OSErr FlushAlternateVolumeControlBlock( SVCB *vcb, Boolean isHFSPlus )
2155
VolumeObjectPtr myVOPtr;
2157
BlockDescriptor pri_block, alt_block;
2159
pri_block.buffer = NULL;
2160
alt_block.buffer = NULL;
2161
myVOPtr = GetVolumeObjectPtr( );
2163
err = FlushVolumeControlBlock( vcb );
2164
err = GetVolumeObjectPrimaryBlock( &pri_block );
2166
// invalidate if we have not marked the primary as OK
2167
if ( VolumeObjectIsHFS( ) ) {
2168
if ( (myVOPtr->flags & kVO_PriMDBOK) == 0 )
2171
else if ( (myVOPtr->flags & kVO_PriVHBOK) == 0 ) {
2175
goto ExitThisRoutine;
2177
GetVolumeObjectAlternateBlockNum( &myBlockNum );
2178
if ( myBlockNum != 0 ) {
2179
// we don't care if this is an invalid MDB / VHB since we will write over it
2180
err = GetVolumeObjectAlternateBlock( &alt_block );
2181
if ( err == noErr || err == badMDBErr || err == noMacDskErr ) {
2182
CopyMemory( pri_block.buffer, alt_block.buffer, Blk_Size );
2183
(void) ReleaseVolumeBlock(vcb, &alt_block, kForceWriteBlock);
2184
alt_block.buffer = NULL;
2189
if ( pri_block.buffer != NULL )
2190
(void) ReleaseVolumeBlock( vcb, &pri_block, kReleaseBlock );
2191
if ( alt_block.buffer != NULL )
2192
(void) ReleaseVolumeBlock( vcb, &alt_block, kReleaseBlock );
2198
ConvertToHFSPlusExtent( const HFSExtentRecord oldExtents, HFSPlusExtentRecord newExtents)
2202
// go backwards so we can convert in place!
2204
for (i = kHFSPlusExtentDensity-1; i > 2; --i)
2206
newExtents[i].blockCount = 0;
2207
newExtents[i].startBlock = 0;
2210
newExtents[2].blockCount = oldExtents[2].blockCount;
2211
newExtents[2].startBlock = oldExtents[2].startBlock;
2212
newExtents[1].blockCount = oldExtents[1].blockCount;
2213
newExtents[1].startBlock = oldExtents[1].startBlock;
2214
newExtents[0].blockCount = oldExtents[0].blockCount;
2215
newExtents[0].startBlock = oldExtents[0].startBlock;
2220
OSErr CacheWriteInPlace( SVCB *vcb, UInt32 fileRefNum, HIOParam *iopb, UInt64 currentPosition, UInt32 maximumBytes, UInt32 *actualBytes )
2224
UInt32 contiguousBytes;
2228
buffer = (char*)iopb->ioBuffer + iopb->ioActCount;
2230
err = MapFileBlockC(vcb, ResolveFCB(fileRefNum), maximumBytes, (currentPosition >> kSectorShift),
2231
&diskBlock, &contiguousBytes );
2235
err = DeviceWrite(vcb->vcbDriverWriteRef, vcb->vcbDriveNumber, buffer, (diskBlock << Log2BlkLo), contiguousBytes, actualBytes);
2241
void PrintName( int theCount, const UInt8 *theNamePtr, Boolean isUnicodeString )
2246
myCount = (isUnicodeString) ? (theCount * 2) : theCount;
2247
for ( i = 0; i < myCount; i++ )
2248
printf( "%02X ", *(theNamePtr + i) );
2254
#define MAX_PRIMES 11
2255
int primes[] = {32, 27, 25, 7, 11, 13, 17, 19, 23, 29, 31};
2256
void print_prime_buckets(PrimeBuckets *cur);
2259
/* Function: RecordXAttrBits
2262
* This function increments the prime number buckets for the associated
2263
* prime bucket set based on the flags and btreetype to determine
2264
* the discrepancy between the attribute btree and catalog btree for
2265
* extended attribute data consistency. This function is based on
2266
* Chinese Remainder Theorem.
2269
* 1. If none of kHFSHasAttributesMask or kHFSHasSecurity mask is set,
2271
* 2. Based on btreetype and the flags, determine which prime number
2272
* bucket should be updated. Initialize pointers accordingly.
2273
* 3. Divide the fileID with pre-defined prime numbers. Store the
2275
* 4. Increment each prime number bucket at an offset of the
2276
* corresponding remainder with one.
2278
* Input: 1. GPtr - pointer to global scavenger area
2279
* 2. flags - can include kHFSHasAttributesMask and/or kHFSHasSecurityMask
2280
* 3. fileid - fileID for which particular extended attribute is seen
2281
* 4. btreetye - can be kHFSPlusCatalogRecord or kHFSPlusAttributeRecord
2282
* indicates which btree prime number bucket should be incremented
2286
void RecordXAttrBits(SGlobPtr GPtr, UInt16 flags, HFSCatalogNodeID fileid, UInt16 btreetype)
2288
PrimeBuckets *cur_attr = NULL;
2289
PrimeBuckets *cur_sec = NULL;
2290
int r32, r27, r25, r7, r11, r13, r17, r19, r23, r29, r31;
2292
if ( ((flags & kHFSHasAttributesMask) == 0) &&
2293
((flags & kHFSHasSecurityMask) == 0) ) {
2294
/* No attributes exists for this fileID */
2298
/* Determine which bucket are we updating */
2299
if (btreetype == kCalculatedCatalogRefNum) {
2300
/* Catalog BTree buckets */
2301
if (flags & kHFSHasAttributesMask) {
2302
cur_attr = &(GPtr->CBTAttrBucket);
2304
if (flags & kHFSHasSecurityMask) {
2305
cur_sec = &(GPtr->CBTSecurityBucket);
2307
} else if (btreetype == kCalculatedAttributesRefNum) {
2308
/* Attribute BTree buckets */
2309
if (flags & kHFSHasAttributesMask) {
2310
cur_attr = &(GPtr->ABTAttrBucket);
2312
if (flags & kHFSHasSecurityMask) {
2313
cur_sec = &(GPtr->ABTSecurityBucket);
2316
/* Incorrect btreetype found */
2320
/* Perform the necessary divisions here */
2333
/* Update bucket for attribute bit */
2335
cur_attr->n32[r32]++;
2336
cur_attr->n27[r27]++;
2337
cur_attr->n25[r25]++;
2339
cur_attr->n11[r11]++;
2340
cur_attr->n13[r13]++;
2341
cur_attr->n17[r17]++;
2342
cur_attr->n19[r19]++;
2343
cur_attr->n23[r23]++;
2344
cur_attr->n29[r29]++;
2345
cur_attr->n31[r31]++;
2348
/* Update bucket for security bit */
2350
cur_sec->n32[r32]++;
2351
cur_sec->n27[r27]++;
2352
cur_sec->n25[r25]++;
2354
cur_sec->n11[r11]++;
2355
cur_sec->n13[r13]++;
2356
cur_sec->n17[r17]++;
2357
cur_sec->n19[r19]++;
2358
cur_sec->n23[r23]++;
2359
cur_sec->n29[r29]++;
2360
cur_sec->n31[r31]++;
2364
printf ("\nFor fileID = %d\n", fileid);
2366
printf ("Attributes bucket:\n");
2367
print_prime_buckets(cur_attr);
2370
printf ("Security bucket:\n");
2371
print_prime_buckets(cur_sec);
2378
/* Function: ComparePrimeBuckets
2381
* This function compares the prime number buckets for catalog btree
2382
* and attribute btree for the given attribute type (normal attribute
2383
* bit or security bit).
2385
* Input: 1. GPtr - pointer to global scavenger area
2386
* 2. BitMask - indicate which attribute type should be compared.
2387
* can include kHFSHasAttributesMask and/or kHFSHasSecurityMask
2388
* Output: zero - the buckets are equal
2389
* non-zero - the buckets are unqual
2391
int ComparePrimeBuckets(SGlobPtr GPtr, UInt16 BitMask)
2395
PrimeBuckets *cat; /* Catalog BTree */
2396
PrimeBuckets *attr; /* Attribute BTree */
2398
/* Find the correct PrimeBuckets to compare */
2399
if (BitMask & kHFSHasAttributesMask) {
2400
/* Compare buckets for attribute bit */
2401
cat = &(GPtr->CBTAttrBucket);
2402
attr = &(GPtr->ABTAttrBucket);
2403
} else if (BitMask & kHFSHasSecurityMask) {
2404
/* Compare buckets for security bit */
2405
cat = &(GPtr->CBTSecurityBucket);
2406
attr = &(GPtr->ABTSecurityBucket);
2408
printf ("%s: Incorrect BitMask found.\n", __FUNCTION__);
2412
for (i=0; i<32; i++) {
2413
if (cat->n32[i] != attr->n32[i]) {
2418
for (i=0; i<27; i++) {
2419
if (cat->n27[i] != attr->n27[i]) {
2424
for (i=0; i<25; i++) {
2425
if (cat->n25[i] != attr->n25[i]) {
2430
for (i=0; i<7; i++) {
2431
if (cat->n7[i] != attr->n7[i]) {
2436
for (i=0; i<11; i++) {
2437
if (cat->n11[i] != attr->n11[i]) {
2442
for (i=0; i<13; i++) {
2443
if (cat->n13[i] != attr->n13[i]) {
2448
for (i=0; i<17; i++) {
2449
if (cat->n17[i] != attr->n17[i]) {
2454
for (i=0; i<19; i++) {
2455
if (cat->n19[i] != attr->n19[i]) {
2460
for (i=0; i<23; i++) {
2461
if (cat->n23[i] != attr->n23[i]) {
2466
for (i=0; i<29; i++) {
2467
if (cat->n29[i] != attr->n29[i]) {
2472
for (i=0; i<31; i++) {
2473
if (cat->n31[i] != attr->n31[i]) {
2481
/* Unequal values found, set the error bit in ABTStat */
2482
if (BitMask & kHFSHasAttributesMask) {
2483
RcdError (GPtr, E_IncorrectAttrCount);
2484
GPtr->ABTStat |= S_AttributeCount;
2486
RcdError (GPtr, E_IncorrectSecurityCount);
2487
GPtr->ABTStat |= S_SecurityCount;
2490
if (BitMask & kHFSHasAttributesMask) {
2491
printf ("For kHFSHasAttributesMask:\n");
2493
printf ("For kHFSHasSecurityMask:\n");
2495
printf("Catalog BTree bucket:\n");
2496
print_prime_buckets(cat);
2497
printf("Attribute BTree bucket\n");
2498
print_prime_buckets(attr);
2505
/* Prints the prime number bucket for the passed pointer */
2506
void print_prime_buckets(PrimeBuckets *cur)
2510
printf ("n32 = { ");
2511
for (i=0; i<32; i++) {
2512
printf ("%d,", cur->n32[i]);
2516
printf ("n27 = { ");
2517
for (i=0; i<27; i++) {
2518
printf ("%d,", cur->n27[i]);
2522
printf ("n25 = { ");
2523
for (i=0; i<25; i++) {
2524
printf ("%d,", cur->n25[i]);
2529
for (i=0; i<7; i++) {
2530
printf ("%d,", cur->n7[i]);
2534
printf ("n11 = { ");
2535
for (i=0; i<11; i++) {
2536
printf ("%d,", cur->n11[i]);
2540
printf ("n13 = { ");
2541
for (i=0; i<13; i++) {
2542
printf ("%d,", cur->n13[i]);
2546
printf ("n17 = { ");
2547
for (i=0; i<17; i++) {
2548
printf ("%d,", cur->n17[i]);
2552
printf ("n19 = { ");
2553
for (i=0; i<19; i++) {
2554
printf ("%d,", cur->n19[i]);
2558
printf ("n23 = { ");
2559
for (i=0; i<23; i++) {
2560
printf ("%d,", cur->n23[i]);
2564
printf ("n29 = { ");
2565
for (i=0; i<29; i++) {
2566
printf ("%d,", cur->n29[i]);
2570
printf ("n31 = { ");
2571
for (i=0; i<31; i++) {
2572
printf ("%d,", cur->n31[i]);