Annotation of kernel/bsd/hfs/hfscommon/Misc/VolumeCheck.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      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.1 (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
                     12:  * this file.
                     13:  * 
                     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
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /*
                     26:        File:           VolumeCheck.c
                     27: 
                     28:        Contains:       Consistency checking code for HFS and HFS Plus volumes.
                     29:                                This code was based off MtCheck (in TFSVol.a).
                     30: 
                     31:        Version:        HFS Plus 1.0
                     32: 
                     33:        Copyright:      � 1995-1998 by Apple Computer, Inc., all rights reserved.
                     34: 
                     35:        File Ownership:
                     36: 
                     37:                DRI:                            Don Brady
                     38: 
                     39:                Other Contact:          xxx put other contact here xxx
                     40: 
                     41:                Technology:                     xxx put technology here xxx
                     42: 
                     43:        Writers:
                     44: 
                     45:                (NG)    Nitin Ganatra
                     46:                (DSH)   Deric Horn
                     47:                (msd)   Mark Day
                     48:                (djb)   Don Brady
                     49: 
                     50:        Change History (most recent first):
                     51: 
                     52:          <Rhap>          6/3/98        djb             Switch RenameCatalogNode to MoveRenameCatalogNode.
                     53:          <Rhap>          4/2/98        djb             FixOrphanFileThreads only works with MacOS.
                     54:          <Rhap>        03/31/98        djb             Sync up with final HFSVolumes.h header file.
                     55:          <Rhap>        03/26/98        djb             Minor cleanup.
                     56:          <Rhap>        03/20/98        djb             Add leaf-order checking back in.  Set USE_BTREE_SCANNER to true
                     57:                                                                        to enable disk order checking.  Add VOLUME_CHECK_LOG messages.
                     58:                                                                        Use PascalBinaryCompare to compare volume names.
                     59: 
                     60:          <CS16>        11/26/97        djb             Radar #2003656 (and others) - remove B-tree header fixing.
                     61:                <15>    10/31/97        DSH             Modify so DFA can call without actually writing to the disk,
                     62:                                                                        added consistencyStatus parameter to MountCheck and fixed bug in
                     63:                                                                        freeBlocks calculation in CheckBitmapAndHeader().
                     64:          <CS14>        10/23/97        msd             Bug 1685113. Fix incorrect volume header creation dates.
                     65:          <CS13>         9/18/97        NG              Don't call Gestalt(osAttr) to check if Temp Mem is available.
                     66:                                                                        Instead, use GetExpandMemProcessMgrExists
                     67:          <CS12>          9/7/97        djb             Turn off DebugStr at MountCheck's ErrorExit.
                     68:          <CS11>          9/5/97        msd             Added CheckBitmapAndHeader to account for space used by the
                     69:                                                                        volume header, alternate volume header, and the allocation file
                     70:                                                                        (bitmap) itself.
                     71:          <CS10>          9/4/97        msd             Added CheckAttributes to account for space used by large
                     72:                                                                        attribute values (the ones that occupy extents).
                     73:           <CS9>         8/29/97        djb             Fixed bug in CheckExtentsOverflow (radar #1675472 and #1675417).
                     74:           <CS8>         8/19/97        msd             In CheckCatalog, don't increment the counts associated with the
                     75:                                                                        root directory twice; only do it in the bulk scan. When counting
                     76:                                                                        folders, don't count the root directory itself.
                     77:           <CS7>         8/11/97        djb             Changed vcb check of largestCNID from "<" to "<=" (radar
                     78:                                                                        #1670614). Use thread records when establishing the largest
                     79:                                                                        CNID.
                     80:           <CS6>         7/30/97        DSH             Casting for SC, needed for DFA compiles
                     81:           <CS5>         7/28/97        msd             Use fast new B-Tree scanner. CheckCatalog was using a variable
                     82:                                                                        before it was defined; the valance computations should have been
                     83:                                                                        wrong.
                     84:           <CS4>         7/16/97        DSH             FilesInternal.i renamed FileMgrInternal.i to avoid name
                     85:                                                                        collision
                     86:           <CS3>          7/8/97        DSH             Loading PrecompiledHeaders from define passed in on C line
                     87:           <CS2>         6/12/97        djb             Get in sync with HFS Plus format changes.
                     88:           <CS1>         4/25/97        djb             first checked in
                     89: 
                     90:         <HFS17>         4/16/97        djb             Remove unused variables to prevent warnings.
                     91:         <HFS16>         4/16/97        djb             Always use new B-tree code.
                     92:         <HFS15>         4/11/97        DSH             use extended VCB fields catalogRefNum, and extentsRefNum.
                     93:         <HFS14>          4/4/97        djb             Get in sync with volume format changes.
                     94:         <HFS13>         2/19/97        djb             Use real B-tree control blocks. Removed caching code.
                     95:         <HFS12>         1/17/97        msd             Fix an illegal cast from one structure type to another in
                     96:                                                                        CheckExtentsOverflow.
                     97:         <HFS11>         1/16/97        djb             Fixing extents overflow check for HFS+ volumes.
                     98:         <HFS10>         1/15/97        djb             Added support for checking HFS+ volumes.
                     99:          <HFS9>          1/3/97        djb             Added support for large keys.Integrated HFSVolumesPriv.h
                    100:                                                                        changes.
                    101:          <HFS8>        12/23/96        djb             Fixed bug in CheckExtentsOverflow (bad key).
                    102:          <HFS8>        12/23/96        djb             Fixed bug in CheckExtentsOverflow (key was wrong).
                    103:          <HFS7>        12/19/96        DSH             All refs to VCB are now refs to ExtendedVCB
                    104:          <HFS6>        12/19/96        djb             Updated for new B-tree Manager interface.
                    105:          <HFS5>        12/13/96        djb             Use new Catalog SPI for GetCatalogNode.
                    106:          <HFS4>         12/4/96        DSH             Precompiled Headers
                    107:          <HFS3>        11/21/96        msd             Removed definition of kHFSSignature since it is now in
                    108:                                                                        FilesInternal.h.
                    109:          <HFS2>        11/19/96        DSH             Removed FilesPriv.h, moved MountCheck prototype to
                    110:                                                                        FilesInternal.h.
                    111:          <HFS1>        11/13/96        djb             first checked in
                    112: 
                    113:        To do:          
                    114:                        - If a cnid of 5 is found in extents btree make sure vcb attribute is set correctly
                    115: */
                    116: #define        USE_BTREE_SCANNER 0
                    117: 
                    118: #if ( PRAGMA_LOAD_SUPPORTED )
                    119:         #pragma        load    PrecompiledHeaders
                    120: #else
                    121:         #if TARGET_OS_MAC
                    122:        #include        <Gestalt.h>
                    123:        #include        <Errors.h>
                    124:        #include        <ExpandMemPriv.h>
                    125:        #include        <Files.h>
                    126:        #include        <StringComparePriv.h>
                    127:        #include        <Types.h>
                    128:         #else
                    129:        #include "../headers/system/MacOSTypes.h"
                    130:     #include "../headers/system/MacOSStubs.h"
                    131:         #endif         /* TARGET_OS_MAC */
                    132: #endif /* PRAGMA_LOAD_SUPPORTED */
                    133: 
                    134: #include       "../headers/FileMgrInternal.h"
                    135: #include       "../headers/HFSBtreesPriv.h"
                    136: #include       "../headers/HFSVolumes.h"
                    137: #include       "../headers/BTreesPrivate.h"
                    138: #include       "../headers/BTreeScanner.h"
                    139: 
                    140: 
                    141: enum {
                    142:        kTypeDataFork                           = 0x00,
                    143:        kTypeResourceFork                       = 0xFF, 
                    144:        
                    145:        kVCBAttrLocked                          = 0x8080,                       // volume locked (software or hardware)
                    146:        kVCBFlagsVolumeDirty            = 0x8000
                    147: };
                    148: 
                    149: 
                    150: enum {
                    151:        kBTreePrevious          = -1,
                    152:        kBTreeCurrent           = 0,
                    153:        kBTreeNext                      = 1
                    154: };
                    155: 
                    156: 
                    157: enum {
                    158:        kHFSOrphanedExtents                             = 0x00000001,
                    159:        kHFSOverlapingExtents                   = 0x00000002,
                    160:        kHFSCatalogBTreeLoop                    = 0x00000004,
                    161:        kHFSExtentsBTreeLoop                    = 0x00000008,
                    162:        kHFSOrphanedThreadRecords               = 0x00000010,
                    163:        kHFSMissingThreadRecords                = 0x00000020,
                    164:        kHFSInvalidPEOF                                 = 0x00000040,
                    165:        kHFSInvalidLEOF                                 = 0x00000080,
                    166:        kHFSInvalidValence                              = 0x00000100,
                    167:        kHFSInvalidBTreeHeader                  = 0x00000200,
                    168:        kHFSInvalidCatalogRecordType    = 0x00000400,   
                    169:        kHFSInconsistentVolumeName              = 0x00000800,
                    170: 
                    171:        kHFSMinorRepairsWereMade                = 0x80000000
                    172: };
                    173: 
                    174: enum {
                    175:        kMinimumBtreeNodesForCache              = 100
                    176: };
                    177: 
                    178: #define        kMDBValidAttributesMask         0x8780
                    179: 
                    180: #define        badCatalogErr   -1311
                    181: 
                    182: 
                    183: typedef struct {
                    184:        Handle  tempBufferHand;
                    185:        UInt32  tempBufferSize;
                    186:        Ptr             savedBufPtr;
                    187:        Ptr             savedGetNode;
                    188:        Ptr             savedRelNode;
                    189:        Ptr             savedNodeCache;
                    190: } BTreeState;
                    191: 
                    192: 
                    193: // Macros
                    194: 
                    195: //void M_ExitOnError(OSErr result);
                    196: //#define              M_ExitOnError( result )         if ( ( result ) != noErr )      goto ErrorExit; else ;
                    197: 
                    198: BTreeControlBlock* GetBTreeControlBlock(short refNum);
                    199: #define                GetBTreeControlBlock(refNum)    ((BTreeControlBlock*) GetFileControlBlock((refNum))->fcbBTCBPtr)
                    200: 
                    201: Ptr LMGetVector(Ptr vector);
                    202: #define        LMGetVector(V)                                  (*(Ptr*) (V))
                    203: 
                    204: void LMSetVector(Ptr vector, Ptr address);
                    205: #define                LMSetVector(V,A)                                (*(Ptr *) (V) = (A))
                    206: 
                    207: Boolean HFSEqualString(ConstStr255Param str1, ConstStr255Param str2);
                    208: #define                HFSEqualString(s1, s2)                  PascalBinaryCompare((s1), (s2))
                    209: 
                    210: #if    DIAGNOSTIC
                    211:        #ifdef KERNEL
                    212:         #include <sys/systm.h>
                    213:         #define PRINTIT kprintf
                    214:     #else /* !KERNEL */
                    215:         #define PRINTIT printf
                    216:     #endif /* KERNEL */
                    217:        #define VOLUME_CHECK_LOG(s)             PRINTIT("   MountCheck: %s\n",(s))
                    218: #else
                    219:        #define VOLUME_CHECK_LOG(s)
                    220: #endif
                    221: 
                    222: 
                    223: #if TARGET_OS_MAC
                    224: #define        GET_SCANNER_BUFFER()            LMGetFSVars()->gAttributesBuffer
                    225: #define        GET_SCANNER_BUFFER_SIZE()       LMGetFSVars()->gAttributesBufferSize
                    226: #endif
                    227: 
                    228: 
                    229: #if TARGET_OS_RHAPSODY
                    230: #define        GET_SCANNER_BUFFER()            NULL
                    231: #define        GET_SCANNER_BUFFER_SIZE()       0
                    232: #endif
                    233: 
                    234: 
                    235: // local prototypes
                    236: 
                    237: static OSErr   CheckCatalog (ExtendedVCB* volume, UInt32* freeBlocks, UInt32 xCatalogBlocks, UInt32* consistencyStatus );
                    238: 
                    239: static OSErr   CheckExtentsOverflow ( ExtendedVCB* volume, UInt32 *freeBlocks, UInt32 *xCatalogBlocks, UInt32* consistencyStatus );
                    240: 
                    241: static OSErr   CheckAttributes ( ExtendedVCB *volume, UInt32 *freeBlocks, UInt32 *consistencyStatus );
                    242: 
                    243: static OSErr   CheckBitmapAndHeader ( ExtendedVCB *volume, UInt32 *freeBlocks, UInt32 *consistencyStatus );
                    244: 
                    245: static void            VolumeBitMapCheckExtents ( ExtendedVCB* volume, HFSPlusExtentDescriptor* theExtents, UInt32* consistencyStatus );
                    246: 
                    247: static OSErr   CheckCreateDate (ExtendedVCB* volume, UInt32* consistencyStatus );
                    248: 
                    249: static Boolean ValidPEOF (     ExtendedVCB* volume, CatalogRecord *file );
                    250: 
                    251: #if TARGET_OS_MAC
                    252:        static OSErr    FixOrphanFileThreads ( ExtendedVCB* volume, UInt32 maxRecords, UInt32 *repairsDone);
                    253: #else
                    254:        #define FixOrphanFileThreads(v, m, f)   0
                    255: #endif
                    256: 
                    257: #if TARGET_OS_RHAPSOY
                    258: static Handle  GetTempBuffer (Size size);
                    259: #endif /* TARGET_OS_MAC */
                    260: 
                    261: static UInt32  CountExtentBlocks (HFSPlusExtentRecord extents, Boolean hfsPlus);
                    262: 
                    263: static void            ConvertToHFSPlusExtent (const HFSExtentRecord oldExtents, HFSPlusExtentRecord newExtents);
                    264: 
                    265: static OSErr   GetFileExtentRecord( const ExtendedVCB  *vcb, const FCB *fcb, HFSPlusExtentRecord extents);
                    266: 
                    267: // glue prototypes
                    268: 
                    269: extern OSErr CacheReadInPlace(ExtendedVCB *volume, HIOParam *iopb, UInt32 currentPosition, UInt32 maximumBytes, UInt32 *actualBytes);
                    270: 
                    271: extern pascal Ptr LowerBufPtr(long size);
                    272: 
                    273: 
                    274: // 68K prototypes
                    275: 
                    276: extern OSErr FastGetNode(void);
                    277: 
                    278: extern OSErr FastRelNode(void);
                    279: 
                    280: 
                    281: /*-------------------------------------------------------------------------------
                    282: 
                    283: Routine:       MountCheck
                    284: 
                    285: Function:      Do a quick check of the volume meta-data to make sure that
                    286:                        it is consistent. Minor inconsistencies in the MDB or volume
                    287:                        bitmap will be repaired all other inconsistencies will be
                    288:                        detected and reported in the consistencyStatus output.
                    289:                        
                    290:                        This check will terminated if any unexpected BTree errors
                    291:                        are encountered.
                    292: 
                    293: Input:         volume                          - pointer to volume control block
                    294:                        consistencyStatus       - ????
                    295: 
                    296: Output:                none
                    297: 
                    298: Result:                noErr                           - success
                    299: 
                    300: -------------------------------------------------------------------------------*/
                    301: OSErr
                    302: MountCheck( ExtendedVCB* volume, UInt32 *consistencyStatus )
                    303: {
                    304:        OSErr                                   result;
                    305:        UInt32                                  freeBlocks;
                    306:        UInt32                                  bitmapFreeBlocks;
                    307:        UInt32                                  xCatalogBlocks;
                    308: 
                    309: 
                    310:        *consistencyStatus = 0;
                    311:        freeBlocks = volume->totalBlocks;       // initially all blocks are free
                    312: 
                    313:        if (volume->vcbSigWord == kHFSPlusSigWord)
                    314:        {
                    315:                //--- make sure the volume header's create date matches the MDB's create date
                    316:                VOLUME_CHECK_LOG("checking HFS Plus wrapper's create date...");
                    317:                result = CheckCreateDate (volume, consistencyStatus);
                    318:                M_ExitOnError(result);
                    319:        }
                    320: 
                    321:        //--- make sure the allocation file, volume header, and alternate volume header are allocated
                    322:        VOLUME_CHECK_LOG("checking allocation file...");
                    323:        result = CheckBitmapAndHeader ( volume, &freeBlocks, consistencyStatus );
                    324:        M_ExitOnError(result);
                    325: 
                    326:        //--- do a quick consistency check of the Extents Overflow b-tree ----------------------------
                    327:        VOLUME_CHECK_LOG("checking extents overflow b-tree...");
                    328:        result = CheckExtentsOverflow(volume, &freeBlocks, &xCatalogBlocks, consistencyStatus);
                    329:        M_ExitOnError(result);
                    330: 
                    331:        //--- do a quick consistency check of the Catalog b-tree ------------------------------------
                    332:        VOLUME_CHECK_LOG("checking catalog b-tree...");
                    333:        result = CheckCatalog( volume, &freeBlocks, xCatalogBlocks, consistencyStatus );
                    334:        M_ExitOnError( result );
                    335: 
                    336:        //--- do a quick consistency check of the Attributes b-tree ------------------------------------
                    337:        result = CheckAttributes( volume, &freeBlocks, consistencyStatus );
                    338:        M_ExitOnError( result );
                    339: 
                    340:        if( freeBlocks != volume->freeBlocks && volume->vcbAtrb & kVCBAttrLocked )
                    341:        {
                    342:                *consistencyStatus |= kHFSMinorRepairsWereMade;
                    343:                VOLUME_CHECK_LOG("repairing free block count");
                    344:        }
                    345: 
                    346:        (void) UpdateFreeCount( volume );       // update freeBlocks from volume bitmap
                    347: 
                    348:        // make sure there are not any doubly allocated blocks...
                    349:        // we are not concerned with orphaned blocks (since this is not fatal)
                    350:        
                    351:        bitmapFreeBlocks = volume->freeBlocks;
                    352:        
                    353:        if ( freeBlocks < bitmapFreeBlocks)                     // there are doubly allocated blocks!
                    354:        {
                    355:                *consistencyStatus |= kHFSOverlapingExtents;
                    356:                VOLUME_CHECK_LOG("uh oh, there are doubly allocated file blocks!");
                    357:                goto ErrorExit;
                    358:        }
                    359:        else if ( freeBlocks > bitmapFreeBlocks)        // there are orphaned blocks
                    360:        {
                    361:                *consistencyStatus |= kHFSOrphanedExtents;
                    362:                VOLUME_CHECK_LOG("orphaned volume bitmap blocks detected");
                    363:        }
                    364: 
                    365:        return noErr;
                    366:        
                    367: ErrorExit:
                    368: 
                    369:        VOLUME_CHECK_LOG("a fatal inconsistency was found! :( ");
                    370: 
                    371:        return badMDBErr;
                    372: }
                    373: 
                    374: 
                    375: /*-------------------------------------------------------------------------------
                    376: 
                    377: Routine:       VolumeCheckCatalog
                    378: 
                    379: Function:      Make sure the name of the root matches the volume name in the MDB.
                    380:                        Make sure the volume bitmap reflects the allocations of all file
                    381:                        extents.
                    382: 
                    383: Assumption:    
                    384: 
                    385: Input:         volume                  - pointer to volume control block
                    386:                        freeBlocks
                    387:                        xCatalogBlocks
                    388:                        consistencyStatus
                    389: 
                    390: Output:                none
                    391: 
                    392: Result:                noErr                   - success
                    393: 
                    394: -------------------------------------------------------------------------------*/
                    395: static OSErr
                    396: CheckCatalog ( ExtendedVCB *volume, UInt32 *freeBlocks, UInt32 xCatalogBlocks, UInt32 *consistencyStatus )
                    397: {
                    398:        UInt32                          maxRecords;
                    399:        UInt32                          largestCNID;
                    400:        UInt32                          fileCount;
                    401:        UInt16                          rootFileCount;                  //XXX can this overflow on HFS Plus volumes?
                    402:        UInt16                          rootDirectoryCount;             //XXX can this overflow on HFS Plus volumes?
                    403:        UInt32                          directoryCount;
                    404:        UInt32                          fileThreads, directoryThreads;
                    405:        UInt32                          fileThreadsExpected;
                    406:        UInt32                          catalogValence;
                    407:        UInt32                          recordsFound;
                    408:        UInt32                          catalogBlocks;
                    409:        OSErr                           result;
                    410:        CatalogNodeData         nodeData;
                    411:        CatalogRecord           *record;
                    412:        CatalogKey                      *key;
                    413:        FSSpec                          spec;
                    414:        UInt16                          recordSize;
                    415:        BTreeControlBlock*      btree;
                    416:        UInt32                          hint;
                    417:        FCB*                            file;
                    418:        HFSPlusExtentRecord     extentRecord;
                    419:        BTScanState                     scanState;
                    420:        Boolean                         hfsPlus = (volume->vcbSigWord == kHFSPlusSigWord);
                    421:        UInt16                          operation;
                    422:        BTreeIterator           btreeIterator;
                    423:        FSBufferDescriptor      btRecord;
                    424:        CatalogRecord           catalogRecord;
                    425: 
                    426:        fileThreads = fileThreadsExpected = directoryThreads = 0;
                    427:        fileCount = directoryCount = 0;
                    428:        rootFileCount = rootDirectoryCount = 0;
                    429:        catalogValence = 0;
                    430:        recordsFound = 0;
                    431:        largestCNID = kHFSFirstUserCatalogNodeID;
                    432: 
                    433:        file = GetFileControlBlock(volume->catalogRefNum);
                    434:        
                    435:        result = GetFileExtentRecord(volume, file, extentRecord);
                    436:        M_ExitOnError(result);
                    437: 
                    438:        catalogBlocks = CountExtentBlocks(extentRecord, hfsPlus);       
                    439:        *freeBlocks -= catalogBlocks;
                    440:        VolumeBitMapCheckExtents(volume, extentRecord, consistencyStatus);
                    441: 
                    442: 
                    443:        //      Read in the root directory's record so we can perform some special checks       
                    444:        hint = 0;
                    445:        result = GetCatalogNode(volume, kHFSRootFolderID, NULL, kNoHint, &spec, &nodeData, &hint);
                    446:        M_ExitOnError(result);
                    447: 
                    448:        if ( DEBUG_BUILD && nodeData.nodeID != kHFSRootFolderID )       // works for small and large folders
                    449:                DebugStr("\p CheckCatalog: nodeData.nodeID != kHFSRootFolderID");
                    450: 
                    451: //     We'll see the root directory's record later, during the full BTree scan, so don't
                    452: //     update the counts here.
                    453: //     ++recordsFound;
                    454: //     catalogValence += nodeData.valence;
                    455:        
                    456:        /* UUU */
                    457:        // make sure the name of the root directory matches the volume name (HFS only)
                    458:        if ( !hfsPlus && false /*&& !HFSEqualString( spec.name, volume->vcbVN )*/ )
                    459:        {
                    460:                if ( volume->vcbAtrb & kVCBAttrLocked )
                    461:                {
                    462:                        *consistencyStatus |= kHFSInconsistentVolumeName;
                    463:                }
                    464:                else // try and repair it
                    465:                {
                    466:                        if (strlen( volume->vcbVN ) > 0)        // check length of volume name
                    467:                        {
                    468:                                if (volume->vcbVN[0] > kHFSMaxVolumeNameChars)  // if name is too long truncate it
                    469:                                        volume->vcbVN[0] = kHFSMaxVolumeNameChars;
                    470:                                        
                    471:                                if ( (!FORDISKFIRSTAID) || (GetDFAStage() == kRepairStage) )
                    472:                                {
                    473:                                        // the length of volume name is OK, rename the root directory
                    474:                                        result = MoveRenameCatalogNode(volume, kHFSRootFolderID, NULL, hint, kHFSRootFolderID, volume->vcbVN, &hint);
                    475:                                        M_ExitOnError(result);
                    476:                                }
                    477:                                *consistencyStatus |= kHFSMinorRepairsWereMade;
                    478:                                
                    479:                                // now we must reset for btree search below!
                    480:                                result = GetCatalogNode(volume, kHFSRootFolderID, NULL, kNoHint, &spec, &nodeData, &hint);
                    481:                                M_ExitOnError(result);
                    482:                        }
                    483:                        else if ( strlen( spec.name ) > 0 )     // check root name length
                    484:                        {
                    485:                                if ( spec.name[0] > kHFSMaxVolumeNameChars )    // if name is too long truncate it
                    486:                                         spec.name[0] = kHFSMaxVolumeNameChars;
                    487:        
                    488:                                // the root name length is OK, change the volume name to match root name
                    489:                                BlockMoveData( spec.name, volume->vcbVN, spec.name[0]+1);
                    490:                                volume->vcbFlags |= kVCBFlagsVolumeDirty;
                    491:                                *consistencyStatus |= kHFSMinorRepairsWereMade;
                    492:                        }
                    493:                }
                    494:                VOLUME_CHECK_LOG("inconsistent volume name (hfs disk)");
                    495:        }
                    496: 
                    497:        // make sure name locked bit is not set
                    498: //     if (record.hfsFolder.finderDirInfo.frFlags & kNameLocked)  //XXX need to use node data, not "record"
                    499: //     {
                    500: //     }
                    501:        
                    502:        // Make a conservative estimate of the upper limit of B*-Tree records that
                    503:        // could conceivably be encountered in a scan of all the leaf nodes.
                    504:        maxRecords = (file->fcbEOF) / sizeof(HFSCatalogFolder);
                    505: 
                    506:        if (USE_BTREE_SCANNER)  // scan the tree in physical order (faster)
                    507:        {
                    508:                result = BTScanInitialize(file, 0, 0, 0, GET_SCANNER_BUFFER(), GET_SCANNER_BUFFER_SIZE(), &scanState);
                    509:                if (result != noErr)
                    510:                        goto ErrorExit;
                    511:        }
                    512:        else // scan in leaf node order (slower but more reliable)
                    513:        {
                    514:                operation = kBTreeFirstRecord;  // first leaf record
                    515: 
                    516:                key = (CatalogKey*) &btreeIterator.key;
                    517: 
                    518:                btRecord.bufferAddress  = record = &catalogRecord;
                    519:                btRecord.itemCount              = 1;
                    520:                btRecord.itemSize               = sizeof(catalogRecord);
                    521:        }
                    522: 
                    523: 
                    524:        // visit all the leaf node data records in the catalog
                    525:        while ( --maxRecords > 0 )
                    526:        {
                    527:                if (USE_BTREE_SCANNER)
                    528:                        result = BTScanNextRecord(&scanState, false, (void**)&key, (void**)&record, (UInt32*) &recordSize);
                    529:                else
                    530:                        result = BTIterateRecord(file, operation, &btreeIterator, &btRecord, &recordSize);
                    531:                                        
                    532:                if ( result != noErr )
                    533:                        break;
                    534: 
                    535:                ++recordsFound;
                    536:                operation = kBTreeNextRecord;
                    537: 
                    538:                switch (record->recordType)
                    539:                {
                    540:                        case kHFSFolderRecord:
                    541:                        {
                    542:                                catalogValence += record->hfsFolder.valence;
                    543:        
                    544:                                //      Count all directories except the root itself
                    545:                                if (key->hfs.parentID != kHFSRootParentID)
                    546:                                ++directoryCount;
                    547: 
                    548:                                //      Count directories directly inside the root
                    549:                                if (key->hfs.parentID == kHFSRootFolderID)
                    550:                                        ++rootDirectoryCount;
                    551:        
                    552:                                if (record->hfsFolder.folderID > largestCNID)
                    553:                                        largestCNID = record->hfsFolder.folderID;
                    554:                                break;
                    555:                        }
                    556: 
                    557:                        case kHFSPlusFolderRecord:
                    558:                        {
                    559:                                catalogValence += record->hfsPlusFolder.valence;
                    560:        
                    561:                                //      Count all directories except the root itself
                    562:                                if (key->hfsPlus.parentID != kHFSRootParentID)
                    563:                                        ++directoryCount;
                    564: 
                    565:                                //      Count directories directly inside the root
                    566:                                if (key->hfsPlus.parentID == kHFSRootFolderID)
                    567:                                        ++rootDirectoryCount;
                    568:                                        
                    569:                                if (record->hfsPlusFolder.folderID > largestCNID)
                    570:                                        largestCNID = record->hfsPlusFolder.folderID;
                    571:                                break;
                    572:                        }
                    573: 
                    574:                        case kHFSFileRecord:
                    575:                        {
                    576:                                ++fileCount;
                    577:                                if ( key->hfs.parentID == kHFSRootFolderID )
                    578:                                        ++rootFileCount;
                    579:        
                    580:                                if ( record->hfsFile.fileID > largestCNID )
                    581:                                        largestCNID = record->hfsFile.fileID;
                    582:        
                    583:                                if ( record->hfsFile.flags & kHFSThreadExistsMask )
                    584:                                        ++fileThreadsExpected;
                    585:        
                    586:                                // check the blocks allocated to this file (both forks)
                    587:                                
                    588:                                ConvertToHFSPlusExtent(record->hfsFile.dataExtents, extentRecord);      
                    589:                                *freeBlocks -= CountExtentBlocks(extentRecord, false);          
                    590:                                VolumeBitMapCheckExtents(volume, extentRecord, consistencyStatus);
                    591:                
                    592:                                ConvertToHFSPlusExtent(record->hfsFile.rsrcExtents, extentRecord);
                    593:                                *freeBlocks -= CountExtentBlocks(extentRecord, false);          
                    594:                                VolumeBitMapCheckExtents(volume, extentRecord, consistencyStatus);
                    595: 
                    596:                                // check the LEOF and PEOF (both forks)
                    597:                                                                
                    598:                                if ( (record->hfsFile.rsrcLogicalSize > record->hfsFile.rsrcPhysicalSize)       ||
                    599:                                         (record->hfsFile.dataLogicalSize > record->hfsFile.dataPhysicalSize) )
                    600:                                {
                    601:                                        *consistencyStatus |= kHFSInvalidLEOF;
                    602:                                        VOLUME_CHECK_LOG("inconsistent file leof (not fixed)");
                    603:                                }
                    604: 
                    605:                                if ( !ValidPEOF(volume, record) )
                    606:                                {
                    607:                                        *consistencyStatus |= kHFSInvalidPEOF;
                    608:                                        VOLUME_CHECK_LOG("inconsistent file peof (not fixed)");
                    609:                                }
                    610:                                break;
                    611:                        }
                    612: 
                    613:                        case kHFSPlusFileRecord:
                    614:                        {
                    615:                                UInt32  blockSize = volume->blockSize;
                    616: 
                    617:                                ++fileCount;
                    618:                                ++fileThreadsExpected;  // HFS Plus files always have thread records
                    619: 
                    620:                                if ( key->hfsPlus.parentID == kHFSRootFolderID )
                    621:                                        ++rootFileCount;
                    622:        
                    623:                                if ( record->hfsPlusFile.fileID > largestCNID )
                    624:                                        largestCNID = record->hfsPlusFile.fileID;
                    625:                
                    626:                                // check the blocks allocated to this file (both forks)
                    627:                                
                    628:                                *freeBlocks -= CountExtentBlocks(record->hfsPlusFile.dataFork.extents, true);           
                    629:                                VolumeBitMapCheckExtents(volume, record->hfsPlusFile.dataFork.extents, consistencyStatus);
                    630:                
                    631:                                *freeBlocks -= CountExtentBlocks(record->hfsPlusFile.resourceFork.extents, true);               
                    632:                                VolumeBitMapCheckExtents(volume, record->hfsPlusFile.resourceFork.extents, consistencyStatus);
                    633: 
                    634:                                // check the LEOF and PEOF (both forks)
                    635:                                                                
                    636:                                if ( (record->hfsPlusFile.resourceFork.logicalSize.lo > record->hfsPlusFile.resourceFork.totalBlocks * blockSize) ||
                    637:                                         (record->hfsPlusFile.dataFork.logicalSize.lo > record->hfsPlusFile.dataFork.totalBlocks * blockSize) )
                    638:                                {
                    639:                                        *consistencyStatus |= kHFSInvalidLEOF;
                    640:                                        VOLUME_CHECK_LOG("inconsistent file leof (not fixed)");
                    641:                                }
                    642: 
                    643:                                if ( !ValidPEOF(volume, record) )
                    644:                                {
                    645:                                        *consistencyStatus |= kHFSInvalidPEOF;
                    646:                                        VOLUME_CHECK_LOG("inconsistent file peof (not fixed)");
                    647:                                }
                    648:                                break;
                    649:                        }
                    650: 
                    651:                        case kHFSFolderThreadRecord:
                    652:                        {
                    653:                                ++directoryThreads;
                    654:                                if ( key->hfs.parentID > largestCNID )          // <CS7>
                    655:                                        largestCNID = key->hfs.parentID;                                
                    656:                                break;
                    657:                        }
                    658: 
                    659:                        case kHFSPlusFolderThreadRecord:
                    660:                        {
                    661:                                ++directoryThreads;
                    662:                                if ( key->hfsPlus.parentID > largestCNID )              // <CS7>
                    663:                                        largestCNID = key->hfsPlus.parentID;
                    664:                                break;
                    665:                        }
                    666: 
                    667:                        case kHFSFileThreadRecord:
                    668:                        {
                    669:                                ++fileThreads;
                    670:                                if ( key->hfs.parentID > largestCNID )          // <CS7>
                    671:                                        largestCNID = key->hfs.parentID;                                
                    672:                                break;
                    673:                        }
                    674: 
                    675:                        case kHFSPlusFileThreadRecord:
                    676:                        {
                    677:                                ++fileThreads;
                    678:                                if ( key->hfsPlus.parentID > largestCNID )              // <CS7>
                    679:                                        largestCNID = key->hfsPlus.parentID;
                    680:                                break;
                    681:                        }
                    682:        
                    683:                        default:
                    684:                                *consistencyStatus |= kHFSInvalidCatalogRecordType;
                    685:                                VOLUME_CHECK_LOG("unknown catalog record");
                    686:                                break;
                    687:                }
                    688:        
                    689:        } // end while
                    690:        
                    691:        if ( result == noErr )
                    692:        {
                    693:                *consistencyStatus |= kHFSCatalogBTreeLoop;
                    694:                goto ErrorExit;         // punt on loop error
                    695:        }
                    696:        
                    697:        if ( result != fsBTRecordNotFoundErr )
                    698:                goto ErrorExit;         // punt on BTree errors
                    699: 
                    700: 
                    701:        // Check if calculated totals match the Volume Control Block
                    702:        
                    703:        if (volume->vcbNxtCNID <= largestCNID)                  // <CS7>
                    704:        {
                    705:                volume->vcbNxtCNID = largestCNID + 1;
                    706:                volume->vcbFlags |= kVCBFlagsVolumeDirty;
                    707:                VOLUME_CHECK_LOG("fixed vcbNxtCNID");
                    708:        }
                    709: 
                    710:        if (volume->vcbFilCnt != fileCount)
                    711:        {
                    712:                volume->vcbFilCnt = fileCount;
                    713:                volume->vcbFlags |= kVCBFlagsVolumeDirty;
                    714:                VOLUME_CHECK_LOG("fixed vcbFilCnt (volume file count)");
                    715:        }
                    716: 
                    717:        if (volume->vcbDirCnt != directoryCount)
                    718:        {
                    719:                volume->vcbDirCnt = directoryCount;
                    720:                volume->vcbFlags |= kVCBFlagsVolumeDirty;
                    721:                VOLUME_CHECK_LOG("fixed vcbDirCnt (volume directory count)");
                    722:        }
                    723: 
                    724:        if (!hfsPlus && volume->vcbNmFls != rootFileCount)
                    725:        {
                    726:                volume->vcbNmFls = rootFileCount;
                    727:                volume->vcbFlags |= kVCBFlagsVolumeDirty;
                    728:                VOLUME_CHECK_LOG("fixed vcbNmFls (root file count)");
                    729:        }
                    730: 
                    731:        if (!hfsPlus && volume->vcbNmRtDirs != rootDirectoryCount)
                    732:        {
                    733:                volume->vcbNmRtDirs = rootDirectoryCount;
                    734:                volume->vcbFlags |= kVCBFlagsVolumeDirty;
                    735:                VOLUME_CHECK_LOG("fixed vcbNmRtDirs (root directory count)");
                    736:        }
                    737:        
                    738:        if ( catalogValence != (fileCount + directoryCount) )
                    739:        {
                    740:                *consistencyStatus |= kHFSInvalidValence;                       // valence inconsistency detected
                    741:                VOLUME_CHECK_LOG("valence inconsistency detected (not fixed)");
                    742:        }
                    743: 
                    744: #if 0  
                    745:        if (volume->vcbAtrb & ~kMDBValidAttributesMask) // check for invalid bits
                    746:        {
                    747:                volume->vcbAtrb &= kMDBValidAttributesMask;
                    748:                volume->vcbFlags |= kVCBFlagsVolumeDirty;
                    749:        }
                    750: #endif
                    751:        
                    752:        if ( (volume->vcbFlags & kVCBFlagsVolumeDirty) && (volume->vcbAtrb & kVCBAttrLocked) == 0 )
                    753:                *consistencyStatus |= kHFSMinorRepairsWereMade;
                    754: 
                    755:        if (directoryThreads > (directoryCount + 1))
                    756:        {
                    757:                *consistencyStatus |= kHFSOrphanedThreadRecords;                // too many directory thread records
                    758:                VOLUME_CHECK_LOG("orphaned directory thread records detected (not fixed)");
                    759:        }
                    760:                
                    761:        if (fileThreads > fileThreadsExpected)
                    762:        {
                    763:                if ( volume->vcbAtrb & kVCBAttrLocked )
                    764:                {
                    765:                        *consistencyStatus |= kHFSOrphanedThreadRecords;        // too many file thread records
                    766:                        VOLUME_CHECK_LOG("orphaned file thread records detected (not fixed)");
                    767:                }
                    768:                else if ( !hfsPlus ) // try and repair orphaned thread records
                    769:                {
                    770:                        // If we fix up some threads, see if we can come out even without counting all the file
                    771:                        // threads again. If we don't, then looks like we have to keep count and do a second
                    772:                        // pass of file records (gotta do that anyway when we fix the KHFSMissingThreadRecords
                    773:                        // case below) and to count thread records again with the FixOrphanFileThreads call.
                    774:        
                    775:                        if ( (!FORDISKFIRSTAID) || (GetDFAStage() == kRepairStage) )
                    776:                        {
                    777:                                UInt32 repairsDone = 0;
                    778:                                        
                    779:                                (void) FixOrphanFileThreads(volume, recordsFound, &repairsDone);
                    780:                                if (repairsDone)
                    781:                                {
                    782:                                        *consistencyStatus |= kHFSMinorRepairsWereMade;
                    783:                                        VOLUME_CHECK_LOG("orphaned file thread records detected (fixed)");
                    784:                                }
                    785:        
                    786:                                if (fileThreads > (fileThreadsExpected + repairsDone) )
                    787:                                {
                    788:                                        *consistencyStatus |= kHFSOrphanedThreadRecords;        // still too many thread records
                    789:                                        VOLUME_CHECK_LOG("orphaned file thread records detected (fix attempt failed)");
                    790:                                }
                    791:                        }
                    792:                }
                    793:        }
                    794: 
                    795:        if ((directoryThreads < (directoryCount + 1)) || (fileThreads < fileThreadsExpected))
                    796:        {
                    797:                *consistencyStatus |= kHFSMissingThreadRecords;         // not enough thread records
                    798:                VOLUME_CHECK_LOG("some catalog thread records are missing (not fixed)");
                    799:        }
                    800: 
                    801:        btree = GetBTreeControlBlock(volume->catalogRefNum);
                    802: 
                    803:        // okay, lets see if the blocks used by the catalog looks right
                    804:        catalogBlocks += xCatalogBlocks;
                    805:        if ( (catalogBlocks * volume->blockSize) != file->fcbPLen )
                    806:        {
                    807:                *consistencyStatus |= kHFSInvalidPEOF;
                    808:                VOLUME_CHECK_LOG("inconsistent catalog file size detected (not fixed)");
                    809:        }
                    810: 
                    811:        if ( btree->totalNodes != (file->fcbPLen / btree->nodeSize) )
                    812:        {
                    813:                *consistencyStatus |= kHFSInvalidBTreeHeader;
                    814:                VOLUME_CHECK_LOG("inconsistent catalog b-tree node count detected (not fixed)");
                    815:        }
                    816: 
                    817:        if (btree->leafRecords != recordsFound)
                    818:        {
                    819:                // We now use the B-tree scanner instead of iterating through all
                    820:                // the leaf nodes in order.  So let's be more conservative and not
                    821:                // fix the leafRecords field until we can do adequate testing of
                    822:                // this new method of visiting nodes. -DJB
                    823: 
                    824:                if (USE_BTREE_SCANNER || volume->vcbAtrb & kVCBAttrLocked)
                    825:                {
                    826:                        *consistencyStatus |= kHFSInvalidBTreeHeader;           // invalid record count
                    827:                        VOLUME_CHECK_LOG("inconsistent catalog b-tree record count detected (not fixed)");
                    828:                }
                    829:                else // go ahead and make this simple repair!
                    830:                {               
                    831:                        btree->leafRecords = recordsFound;
                    832:                        btree->flags |= kBTHeaderDirty;                                         // mark BTreeControlBlock dirty
                    833:                        *consistencyStatus |= kHFSMinorRepairsWereMade;
                    834:                        VOLUME_CHECK_LOG("inconsistent catalog b-tree record count detected (fixed)");
                    835:                }
                    836:        }
                    837:        
                    838:        if ( (!FORDISKFIRSTAID) || (GetDFAStage() == kRepairStage) )
                    839:        {
                    840:                if ( btree->flags & kBTHeaderDirty )    // if we made changes, write them out
                    841:                        (void) BTFlushPath(file);
                    842:        }
                    843: 
                    844:        return noErr;
                    845:        
                    846: ErrorExit:
                    847:        return badCatalogErr;
                    848: 
                    849: } // end CheckCatalog
                    850: 
                    851: 
                    852: /*-------------------------------------------------------------------------------
                    853: 
                    854: Routine:       CheckExtentsOverflow
                    855: 
                    856: Function:      Make sure the volume bitmap reflects the allocations of all extents.
                    857: 
                    858: Assumption:    
                    859: 
                    860: Input:         volume                  - pointer to volume control block
                    861:                        freeBlocks
                    862:                        xCatalogBlocks
                    863:                        consistencyStatus
                    864: 
                    865: Output:                none
                    866: 
                    867: Result:                noErr                   - success
                    868: 
                    869: -------------------------------------------------------------------------------*/
                    870: static OSErr
                    871: CheckExtentsOverflow ( ExtendedVCB *volume, UInt32 *freeBlocks, UInt32 *xCatalogBlocks, UInt32 *consistencyStatus )
                    872: {
                    873:        OSErr                           result;
                    874:        UInt32                          maxRecords;
                    875:        UInt32                          fileID;
                    876:        UInt32                          largestCNID;
                    877:        UInt32                          recordsFound; 
                    878:        UInt32                          extentFileBlocks;
                    879:        UInt32                          extentRecordBlocks;
                    880:        HFSPlusExtentKey        *extentKeyPtr;
                    881:        HFSPlusExtentRecord     *extentDataPtr;
                    882:        HFSPlusExtentRecord     extentRecord;
                    883:        UInt16                          recordSize;
                    884:        BTreeControlBlock       *btree;
                    885:        FCB*                            file;
                    886:        BTScanState                     scanState;
                    887:        Boolean                         hfsPlus = (volume->vcbSigWord == kHFSPlusSigWord);
                    888:        UInt16                          operation;
                    889:        BTreeIterator           btreeIterator;
                    890:        FSBufferDescriptor      btRecord;
                    891: 
                    892:        *xCatalogBlocks = 0;  // set this early since its a return value
                    893:     largestCNID = kHFSFirstUserCatalogNodeID;
                    894:        
                    895:        file = GetFileControlBlock(volume->extentsRefNum);
                    896: 
                    897:        result = GetFileExtentRecord(volume, file, extentRecord);
                    898:        ReturnIfError(result);
                    899: 
                    900:        extentFileBlocks = CountExtentBlocks(extentRecord, hfsPlus);
                    901:        *freeBlocks -= extentFileBlocks;
                    902:        VolumeBitMapCheckExtents(volume, extentRecord, consistencyStatus);
                    903: 
                    904:        // now look at the extent tree...
                    905: 
                    906:        // Make a conservative estimate of the upper limit of B*-Tree records that
                    907:        // could conceivably be encountered in a scan of all the leaf nodes.
                    908:        recordsFound = 0;
                    909:        maxRecords = (file->fcbEOF) / (hfsPlus ? sizeof(HFSPlusExtentRecord) : sizeof(HFSExtentRecord));
                    910: 
                    911:        if (USE_BTREE_SCANNER)  // scan the tree in physical order (faster)
                    912:        {
                    913:                result = BTScanInitialize(file, 0, 0, 0, GET_SCANNER_BUFFER(), GET_SCANNER_BUFFER_SIZE(), &scanState);
                    914:                if (result != noErr)
                    915:                        return badMDBErr;
                    916:        }
                    917:        else // scan in leaf node order (slower but more reliable)
                    918:        {
                    919:                operation = kBTreeFirstRecord;  // first leaf record
                    920:                extentKeyPtr = (HFSPlusExtentKey*) &btreeIterator.key;
                    921: 
                    922:                btRecord.bufferAddress  = &extentRecord;
                    923:                btRecord.itemCount              = 1;
                    924:                btRecord.itemSize               = sizeof(extentRecord);
                    925:        }
                    926: 
                    927:        // visit all the leaf node data records in the extents B*-Tree
                    928:        while ( recordsFound < maxRecords )
                    929:        {
                    930:                if (USE_BTREE_SCANNER)
                    931:                        result = BTScanNextRecord(&scanState, false, (void **) &extentKeyPtr, (void **) &extentDataPtr, (UInt32*) &recordSize);
                    932:                else
                    933:                        result = BTIterateRecord(file, operation, &btreeIterator, &btRecord, &recordSize);
                    934: 
                    935:                if ( result != noErr )
                    936:                        break;
                    937: 
                    938:                ++recordsFound;
                    939: 
                    940:                // check the blocks allocated to this extent record
                    941:                
                    942:                if (USE_BTREE_SCANNER)
                    943:                {
                    944:                        if ( hfsPlus )
                    945:                                BlockMoveData(extentDataPtr, &extentRecord, sizeof(extentRecord));                              // just make a copy
                    946:                        else
                    947:                                ConvertToHFSPlusExtent(*((HFSExtentRecord *) extentDataPtr), extentRecord);             // convert it
                    948:                        }
                    949:                else
                    950:                {
                    951:                        operation = kBTreeNextRecord;
                    952:                        if ( !hfsPlus )
                    953:                                ConvertToHFSPlusExtent(*(HFSExtentRecord*) &extentRecord, extentRecord);        // convert it in place (since its a copy)
                    954:                }
                    955: 
                    956:                extentRecordBlocks = CountExtentBlocks(extentRecord, hfsPlus);
                    957:                
                    958:                *freeBlocks -= extentRecordBlocks;              
                    959:                VolumeBitMapCheckExtents(volume, extentRecord, consistencyStatus);
                    960:                
                    961:                if ( hfsPlus )
                    962:                        fileID = extentKeyPtr->fileID;
                    963:                else
                    964:                        fileID = ((HFSExtentKey*) extentKeyPtr)->fileID;
                    965:                
                    966:                // if these were catalog blocks, we need to keep track 
                    967:                if ( fileID == kHFSCatalogFileID )
                    968:                        *xCatalogBlocks += extentRecordBlocks;
                    969:                        
                    970:                if ( fileID > largestCNID )
                    971:                        largestCNID = fileID;
                    972: 
                    973:        } // end while
                    974: 
                    975:        if ( result != fsBTRecordNotFoundErr) 
                    976:        {
                    977:                VOLUME_CHECK_LOG("extents b-tree has serious problems!");
                    978:                
                    979:                return badMDBErr;               // punt on error (loop error or BTree error)
                    980:        }
                    981: 
                    982:        if (volume->vcbNxtCNID < largestCNID)
                    983:        {
                    984:                volume->vcbNxtCNID = largestCNID + 1;
                    985:                volume->vcbFlags |= kVCBFlagsVolumeDirty;
                    986:                volume->vcbAtrb |= 1;   // need a constant for this!
                    987:        }       
                    988:        
                    989:        btree = GetBTreeControlBlock(volume->extentsRefNum);
                    990: 
                    991:        if ( (extentFileBlocks * volume->blockSize) != file->fcbPLen )
                    992:        {
                    993:                *consistencyStatus |= kHFSInvalidPEOF;
                    994:                VOLUME_CHECK_LOG("inconsistent extents file size detected (not fixed)");
                    995:        }
                    996: 
                    997:        if ( btree->totalNodes != (file->fcbPLen / btree->nodeSize) )
                    998:        {
                    999:                *consistencyStatus |= kHFSInvalidBTreeHeader;
                   1000:                VOLUME_CHECK_LOG("inconsistent extents b-tree node count detected (not fixed)");
                   1001:        }
                   1002:        
                   1003:        if (btree->leafRecords != recordsFound)
                   1004:        {
                   1005:                // We now use the B-tree scanner instead of iterating through all
                   1006:                // the leaf nodes in order.  So let's be more conservative and not
                   1007:                // fix the leafRecords field until we can do adequate testing of
                   1008:                // this new method of visiting nodes. -DJB
                   1009:        
                   1010:                if (USE_BTREE_SCANNER || volume->vcbAtrb & kVCBAttrLocked)
                   1011:                {
                   1012:                        *consistencyStatus |= kHFSInvalidBTreeHeader;
                   1013:                        VOLUME_CHECK_LOG("inconsistent extents b-tree record count detected (not fixed)");
                   1014:                }
                   1015:                else // go ahead and make this simple repair!
                   1016:                {
                   1017:                        btree->leafRecords = recordsFound;
                   1018:                        btree->flags |= kBTHeaderDirty;                         // mark BTreeControlBlock dirty
                   1019:                        *consistencyStatus |= kHFSMinorRepairsWereMade;
                   1020:                        VOLUME_CHECK_LOG("inconsistent extents b-tree record count detected (fixed)");
                   1021:                }
                   1022:        }
                   1023:        
                   1024:        if ( (!FORDISKFIRSTAID) || (GetDFAStage() == kRepairStage) )
                   1025:        {
                   1026:                if ( btree->flags & kBTHeaderDirty )    // if we made changes, write them out
                   1027:                        (void) BTFlushPath(file);
                   1028:        }
                   1029: 
                   1030:        return noErr;
                   1031: 
                   1032: } // end CheckExtentsOverflow
                   1033: 
                   1034: 
                   1035: 
                   1036: /*-------------------------------------------------------------------------------
                   1037: 
                   1038: Routine:       CheckAttributes
                   1039: 
                   1040: Function:      Make sure the volume bitmap reflects the allocations of all attributes
                   1041:                        that occupy extents.
                   1042: 
                   1043: Assumption:    
                   1044: 
                   1045: Input:         volume                  - pointer to volume control block
                   1046:                        freeBlocks
                   1047:                        consistencyStatus
                   1048: 
                   1049: Output:                none
                   1050: 
                   1051: Result:                noErr                   - success
                   1052: 
                   1053: -------------------------------------------------------------------------------*/
                   1054: static OSErr
                   1055: CheckAttributes ( ExtendedVCB *volume, UInt32 *freeBlocks, UInt32 *consistencyStatus )
                   1056: {
                   1057:        OSErr                           result;
                   1058:        UInt32                          maxRecords;
                   1059:        UInt32                          recordsFound; 
                   1060:        UInt32                          attributesFileBlocks;
                   1061:        UInt32                          extentRecordBlocks;
                   1062:        AttributeKey            *attributeKey;
                   1063:        HFSPlusAttrRecord       *attributeData;
                   1064:        HFSPlusExtentRecord     extentRecord;
                   1065:        UInt32                          recordSize;
                   1066:        BTreeControlBlock       *btree;
                   1067:        FCB*                            file;
                   1068:        BTScanState                     scanState;
                   1069:        Boolean                         hfsPlus = (volume->vcbSigWord == kHFSPlusSigWord);
                   1070: 
                   1071:        //
                   1072:        //      If there isn't an attributes B-tree, there's no work to do
                   1073:        //
                   1074:        if (volume->attributesRefNum == 0)
                   1075:                return noErr;
                   1076: 
                   1077:        file = GetFileControlBlock(volume->attributesRefNum);
                   1078: 
                   1079:        result = GetFileExtentRecord(volume, file, extentRecord);
                   1080:        ReturnIfError(result);
                   1081: 
                   1082:        attributesFileBlocks = CountExtentBlocks(extentRecord, hfsPlus);
                   1083:        *freeBlocks -= attributesFileBlocks;
                   1084:        VolumeBitMapCheckExtents(volume, extentRecord, consistencyStatus);
                   1085: 
                   1086: 
                   1087:        // now look at the attributes tree...
                   1088: 
                   1089:        // Make a conservative estimate of the upper limit of B*-Tree records that
                   1090:        // could conceivably be encountered in a scan of all the leaf nodes.
                   1091:        recordsFound = 0;
                   1092:        maxRecords = (file->fcbEOF) / 8;                // 8 = minimum data length (for zero length inline attribute)
                   1093: 
                   1094:        //      Prepare to scan the tree in physical order
                   1095:        result = BTScanInitialize(file, 0, 0, 0, GET_SCANNER_BUFFER(), GET_SCANNER_BUFFER_SIZE(), &scanState);
                   1096:        if (result != noErr)
                   1097:                return badMDBErr;
                   1098: 
                   1099:        // visit all the leaf node data records in the extents B*-Tree
                   1100:        while ( recordsFound < maxRecords )
                   1101:        {
                   1102:                result = BTScanNextRecord(&scanState, false, (void **) &attributeKey, (void **) &attributeData, &recordSize);
                   1103: 
                   1104:                if ( result != noErr )
                   1105:                        break;
                   1106: 
                   1107:                ++recordsFound;
                   1108: 
                   1109:                //      If this block has information about extents, make sure they're allocated
                   1110:                switch (attributeData->recordType) {
                   1111:                        case kHFSPlusAttrInlineData:
                   1112:                                break;
                   1113:             case kHFSPlusAttrForkData:
                   1114:                                extentRecordBlocks = CountExtentBlocks(attributeData->forkData.theFork.extents, true);
                   1115:                                *freeBlocks -= extentRecordBlocks;
                   1116:                                VolumeBitMapCheckExtents(volume, attributeData->forkData.theFork.extents, consistencyStatus);
                   1117:                                break;
                   1118:             case kHFSPlusAttrExtents:
                   1119:                                extentRecordBlocks = CountExtentBlocks(attributeData->overflowExtents.extents, true);
                   1120:                                *freeBlocks -= extentRecordBlocks;
                   1121:                                VolumeBitMapCheckExtents(volume, attributeData->overflowExtents.extents, consistencyStatus);
                   1122:                                break;
                   1123:                        default:
                   1124:                                if (DEBUG_BUILD)
                   1125:                                        DebugStr("\pHFS+: Unknown attribute record");
                   1126:                                break;
                   1127:                }       // end switch
                   1128:        } // end while
                   1129: 
                   1130:        if ( result != fsBTRecordNotFoundErr )
                   1131:        {
                   1132:                VOLUME_CHECK_LOG("extents b-tree has serious problems!");
                   1133:                return badMDBErr;               // punt on error (loop error or BTree error)
                   1134:        }
                   1135: 
                   1136:        btree = GetBTreeControlBlock(volume->attributesRefNum);
                   1137: 
                   1138:        if ( (attributesFileBlocks * volume->blockSize) != file->fcbPLen )
                   1139:                *consistencyStatus |= kHFSInvalidPEOF;
                   1140: 
                   1141:        if ( btree->totalNodes != (file->fcbPLen / btree->nodeSize) )
                   1142:                *consistencyStatus |= kHFSInvalidBTreeHeader;
                   1143:        
                   1144:        if (btree->leafRecords != recordsFound)
                   1145:        {
                   1146:                // We now use the B-tree scanner instead of iterating through all
                   1147:                // the leaf nodes in order.  So let's be more conservative and not
                   1148:                // fix the leafRecords field until we can do adequate testing of
                   1149:                // this new method of visiting nodes. -DJB
                   1150: 
                   1151:                if (USE_BTREE_SCANNER || volume->vcbAtrb & kVCBAttrLocked)
                   1152:                {
                   1153:                        *consistencyStatus |= kHFSInvalidBTreeHeader;
                   1154:                }
                   1155:                else // go ahead and make this simple repair!
                   1156:                {
                   1157:                        btree->leafRecords = recordsFound;
                   1158:                        btree->flags |= kBTHeaderDirty;                         // mark BTreeControlBlock dirty
                   1159:                        *consistencyStatus |= kHFSMinorRepairsWereMade;
                   1160:                }
                   1161:        }
                   1162:        
                   1163:        if ( (!FORDISKFIRSTAID) || (GetDFAStage() == kRepairStage) )
                   1164:        {
                   1165:                if ( btree->flags & kBTHeaderDirty )    // if we made changes, write them out
                   1166:                        (void) BTFlushPath(file);
                   1167:        }
                   1168:        return noErr;
                   1169: 
                   1170: } // end CheckAttributes
                   1171: 
                   1172: 
                   1173: 
                   1174: /*-------------------------------------------------------------------------------
                   1175: 
                   1176: Routine:       CheckBitmapAndHeader
                   1177: 
                   1178: Function:      Make sure the volume header, alternate volume header, and the bitmap
                   1179:                        itself are marked as used in the bitmap.
                   1180: 
                   1181: Assumption:    
                   1182: 
                   1183: Input:         volume                  - pointer to volume control block
                   1184:                        freeBlocks
                   1185:                        consistencyStatus
                   1186: 
                   1187: Output:                none
                   1188: 
                   1189: Result:                noErr                   - success
                   1190: 
                   1191: -------------------------------------------------------------------------------*/
                   1192: static OSErr
                   1193: CheckBitmapAndHeader ( ExtendedVCB *volume, UInt32 *freeBlocks, UInt32 *consistencyStatus )
                   1194: {
                   1195:        OSErr                           result;
                   1196:        UInt32                          blocksUsed;
                   1197:        FCB*                            file;
                   1198:        HFSPlusExtentRecord     extentRecord;
                   1199: 
                   1200:        //
                   1201:        //      If there isn't an allocation file, there's no work to do
                   1202:        //
                   1203:        if (volume->allocationsRefNum == 0)
                   1204:                return noErr;
                   1205: 
                   1206:        file = GetFileControlBlock(volume->allocationsRefNum);
                   1207: 
                   1208:        result = GetFileExtentRecord(volume, file, extentRecord);
                   1209:        ReturnIfError(result);
                   1210: 
                   1211:        //      Mark the space used by the allocation file (bitmap) itself
                   1212:        blocksUsed = CountExtentBlocks(extentRecord, true);
                   1213:        *freeBlocks -= blocksUsed;
                   1214:        VolumeBitMapCheckExtents(volume, extentRecord, consistencyStatus);
                   1215: 
                   1216:        //      Now mark sectors zero through two (boot blocks and volume header)
                   1217:        //      and the last two sectors (alternate volume header and a reserved
                   1218:        //      sector).  The number of allocation blocks depends on the size of
                   1219:        //      an allocation block.  What we do is create a fake extent record
                   1220:        //      for these blocks, and call VolumeBitMapCheckExtents as usual.
                   1221: 
                   1222:        ClearMemory(&extentRecord, sizeof(extentRecord));
                   1223:        
                   1224:        extentRecord[0].startBlock = 0;
                   1225:        extentRecord[0].blockCount = 1 + (1024 / volume->blockSize);    // sectors 0-2
                   1226: 
                   1227:        if (volume->blockSize == 512) {
                   1228:                extentRecord[1].startBlock = volume->totalBlocks - 2;
                   1229:                extentRecord[1].blockCount = 2;
                   1230:        } else {
                   1231:                extentRecord[1].startBlock = volume->totalBlocks - 1;
                   1232:                extentRecord[1].blockCount = 1;
                   1233:        }
                   1234:        
                   1235:        *freeBlocks -= extentRecord[0].blockCount + extentRecord[1].blockCount;
                   1236:        VolumeBitMapCheckExtents(volume, extentRecord, consistencyStatus);
                   1237: 
                   1238:        return noErr;
                   1239: }
                   1240: 
                   1241: 
                   1242: //     For Disk First Aid, this routine will not update the BitMap, but will set the
                   1243: //     kHFSMinorRepairsWereMade bit to indicate the bitmap needs updating.
                   1244: static void VolumeBitMapCheckExtents (
                   1245:                                                        ExtendedVCB*                    volume,
                   1246:                                                        HFSPlusExtentDescriptor*        theExtents,
                   1247:                                                        UInt32*                                 consistencyStatus )
                   1248: {
                   1249:        if ( BlockCheck(volume, theExtents) == -1 )
                   1250:        {
                   1251:                *consistencyStatus |= kHFSMinorRepairsWereMade;
                   1252:                VOLUME_CHECK_LOG("repairing volume bitmap");
                   1253:        }
                   1254: }
                   1255: 
                   1256: 
                   1257: /*-------------------------------------------------------------------------------
                   1258: 
                   1259: Routine:       ValidPEOF
                   1260: 
                   1261: Function:      Make sure the local extents match the PEOF.
                   1262:                        Currently this only checks the local extent.
                   1263:                        We could also check the oveflow extents for
                   1264:                        a more complete (but slower) test.
                   1265: 
                   1266: Assumption:    
                   1267: 
                   1268: Input:         
                   1269: 
                   1270: Output:                
                   1271: 
                   1272: Result:        
                   1273: 
                   1274: -------------------------------------------------------------------------------*/
                   1275: 
                   1276: static Boolean
                   1277: ValidPEOF( ExtendedVCB* volume, CatalogRecord *file )
                   1278: {
                   1279:        UInt32  minPEOF;
                   1280:        UInt32  allocBlkSize = volume->blockSize;
                   1281:        
                   1282:        if (file->recordType == kHFSPlusFileRecord)
                   1283:        {
                   1284:                UInt32  minBlocks;
                   1285: 
                   1286:                minBlocks = CountExtentBlocks(file->hfsPlusFile.resourceFork.extents, true);
                   1287:                
                   1288:                if ( file->hfsPlusFile.resourceFork.totalBlocks < minBlocks )
                   1289:                        return false;
                   1290:                else if ( (file->hfsPlusFile.resourceFork.totalBlocks > minBlocks) && (file->hfsPlusFile.resourceFork.extents[kHFSPlusExtentDensity-1].blockCount == 0) )
                   1291:                        return false;
                   1292:        
                   1293:                minBlocks = CountExtentBlocks(file->hfsPlusFile.dataFork.extents, true);
                   1294:                
                   1295:                if ( file->hfsPlusFile.dataFork.totalBlocks < minBlocks )
                   1296:                        return false;
                   1297:                else if ( (file->hfsPlusFile.dataFork.totalBlocks > minBlocks) && (file->hfsPlusFile.dataFork.extents[kHFSPlusExtentDensity-1].blockCount == 0) )
                   1298:                        return false;
                   1299:        }
                   1300:        else
                   1301:        {
                   1302:                HFSPlusExtentRecord     extentRecord;
                   1303:                
                   1304:                ConvertToHFSPlusExtent(file->hfsFile.rsrcExtents, extentRecord);        
                   1305:                minPEOF = CountExtentBlocks(extentRecord, false) * allocBlkSize;
                   1306:                
                   1307:                if ( file->hfsFile.rsrcPhysicalSize < minPEOF )
                   1308:                        return false;
                   1309:                else if ( (file->hfsFile.rsrcPhysicalSize > minPEOF) && (extentRecord[kHFSExtentDensity-1].blockCount == 0) )
                   1310:                        return false;
                   1311:        
                   1312: 
                   1313:                ConvertToHFSPlusExtent(file->hfsFile.dataExtents, extentRecord);        
                   1314:                minPEOF = CountExtentBlocks(extentRecord, false) * allocBlkSize;
                   1315:                
                   1316:                if ( file->hfsFile.dataPhysicalSize < minPEOF )
                   1317:                        return false;
                   1318:                else if ( (file->hfsFile.dataPhysicalSize > minPEOF) && (extentRecord[kHFSExtentDensity-1].blockCount == 0) )
                   1319:                        return false;
                   1320:        }
                   1321: 
                   1322:                
                   1323:        return true;
                   1324: }
                   1325: 
                   1326: 
                   1327: /*-------------------------------------------------------------------------------
                   1328: 
                   1329: Routine:       FixOrphanFileThreads
                   1330: 
                   1331: Function:      For orphan thread records during VolumeCheckConsistency have the catalog
                   1332:                        searched again for file records that match. If their thread record flag
                   1333:                        is off, mark it. If it is on, do nothing. If the file record doesn't exist,
                   1334:                        delete the thread record.
                   1335: 
                   1336: Assumption:    This is a function to be called only if the thread records detected during
                   1337:                        CheckCatalog was greater than the file records that had their flag set for
                   1338:                        file thread existance. I've thought of doing this differently, like keeping
                   1339:                        a table of all file records or threads scanned in the first pass, but the
                   1340:                        table gets large. You can't predict how large so may to hold upto the max
                   1341:                        fileIDs possible. (2**32). Using two such tables to match file threads
                   1342:                        against file records would be bad. Less space would be keeping a bitmap of
                   1343:                        all fileIDS (to 2**32) and marking those with threads. Then a separate
                   1344:                        bitmap for those file records with thread flags on marked.You do a byte by
                   1345:                        byte comparison across the whole bitmap. When they differ, you know if you're
                   1346:                        missing
                   1347:                        threads or orphans threads. (Note 0s would also mean IDs represented by that
                   1348:                        bit in the bitmap that is non-existant). Though, this sounds clever, it still
                   1349:                        seems it would take 8bits/byte * 512 bytes/sector * 8 sectors/ vmpage = 2**15
                   1350:                        bits per vmpage and 2**17 vmpages to cover the bitmap! Too large. SO, let's
                   1351:                        just scan the catalog again. Yep, it's timeconsuming, but we are only taking
                   1352:                        the hit in repair mode for that particular problem. No extra memory for tables
                   1353:                        or bitmaps are even required during the original scan.
                   1354: 
                   1355: Input:         
                   1356:                                                                
                   1357: Output:                
                   1358: 
                   1359: Result:                E_NoError                               - success
                   1360:                        != E_NoError                    - failure
                   1361: 
                   1362: -------------------------------------------------------------------------------*/
                   1363: #if TARGET_OS_MAC
                   1364: static OSErr FixOrphanFileThreads(ExtendedVCB* volume, UInt32 maxRecords, UInt32 *repairsDone)
                   1365: {
                   1366:        UInt16                          recordSize;
                   1367:        OSErr                           tempResult, result = noErr;
                   1368:        CatalogKey                      key;
                   1369:        FSSpec                          spec;
                   1370:        CatalogRecord           record;
                   1371:        CatalogNodeData         nodeData;
                   1372:        UInt32                          hint = 0;
                   1373:                
                   1374:        // let's iterate the catalog looking for file thread records. As we hit each one, 
                   1375:        // do a search for the file record. If it exists and the thread flag is off,set
                   1376:        // it. If it exists, and the thread flag is on, all is fine and dandy. It it
                   1377:        // doesn't exist, remove the orphaned thread record. 
                   1378:        
                   1379:        *repairsDone = 0;
                   1380:        
                   1381:        result = GetCatalogNode(volume, kHFSRootFolderID, NULL, kNoHint, &spec, &nodeData, &hint);
                   1382:        M_ExitOnError(result);
                   1383:        
                   1384:        // visit all the leaf node data records in the catalog
                   1385:        while ( --maxRecords > 0 )  // starts out at recordsFound value passed in
                   1386:        {
                   1387:                tempResult = GetBTreeRecord(volume->catalogRefNum, kBTreeNext, &key, &record,
                   1388:                                                                 &recordSize, &hint );
                   1389:                if ( tempResult )
                   1390:                {
                   1391:                        //      DebugStr("\p FixOrphanFileThreads: did we run out of records?");
                   1392:                        break;
                   1393:                }
                   1394:                
                   1395:                // if this is a file thread record, check it out...
                   1396:                if (record.recordType == kHFSFileThreadRecord)
                   1397:                {
                   1398:                        CatalogKey      currentKey;
                   1399:                        CatalogKey      fileKey;
                   1400:                        UInt32          fileHint;
                   1401:                                
                   1402:                        // save our current position
                   1403:                        currentKey = key;       
                   1404:                        
                   1405:                        // create a key for the file record
                   1406:                        fileHint = 0;
                   1407:                        fileKey.hfs.parentID = record.hfsThread.parentID;
                   1408:                        BlockMoveData ( record.hfsThread.nodeName, fileKey.hfs.nodeName,
                   1409:                                                        record.hfsThread.nodeName[0] + 1);
                   1410:                        
                   1411:                        // try and get the file record for this thread record...
                   1412:                        tempResult = SearchBTreeRecord ( volume->catalogRefNum, &fileKey, fileHint, &key, &record, &recordSize, &fileHint );
                   1413:                                
                   1414:                        if (tempResult == noErr)
                   1415:                        {               
                   1416:                                if ((record.hfsFile.flags & kHFSThreadExistsMask) == 0)
                   1417:                                {
                   1418:                                        // thread record exists but file record doesn't think so....set it
                   1419:                                        record.hfsFile.flags |= kHFSThreadExistsMask;
                   1420:                                        
                   1421:                                        // update the file record on disk
                   1422:                                        if ( ReplaceBTreeRecord(volume->catalogRefNum, &key, fileHint, &record, recordSize, &fileHint) == noErr )               
                   1423:                                                ++(*repairsDone);
                   1424:                                }
                   1425:                        }               
                   1426:                        else if (tempResult == btNotFound)
                   1427:                        {
                   1428:                                // BTDelete invalidates the current node mark so before we delete the thread record,
                   1429:                                // point currentKey and hint at something valid (ie the previous record)
                   1430:                                
                   1431:                                (void) SearchBTreeRecord( volume->catalogRefNum, &currentKey, hint, &key, &record, &recordSize, &hint );
                   1432:                                (void) GetBTreeRecord( volume->catalogRefNum, kBTreePrevious, &key, &record, &recordSize, &hint );
                   1433: 
                   1434:                                // file record doesn't exist. Delete the thread record.
                   1435:                                if ( DeleteBTreeRecord( volume->catalogRefNum, &currentKey) == noErr )
                   1436:                                        ++(*repairsDone);  
                   1437:                                
                   1438:                                currentKey = key;       // now point to the record before the thread record
                   1439:                        }
                   1440: 
                   1441:                        // now we need to reset the current node mark for GetBTreeRecord iteration...
                   1442:                        (void) SearchBTreeRecord( volume->catalogRefNum, &currentKey, hint, &key, &record, &recordSize, &hint );
                   1443: 
                   1444:                } // end if thread
                   1445:        
                   1446:        } // end while
                   1447:        
                   1448:        return( result );
                   1449: ErrorExit:
                   1450:        return ( result ); //XXX which error should it be ???
                   1451: } // end FixOrphanFileThreads
                   1452: #endif /* TARGET_OS_MAC */
                   1453: 
                   1454: //_______________________________________________________________________
                   1455: //
                   1456: //     GetTempBuffer
                   1457: //     
                   1458: //     This routine allocates a temporary buffer.
                   1459: //
                   1460: //     Note: At startup TempNewHandle may not be available.
                   1461: //_______________________________________________________________________
                   1462: #if TARGET_OS_MAC
                   1463: static Handle GetTempBuffer (Size size)
                   1464: {
                   1465:        OSErr   error;
                   1466:        Handle  tempBuffer;
                   1467: 
                   1468:        if ( GetExpandMemProcessMgrExists() )
                   1469:                tempBuffer = TempNewHandle(size, &error);
                   1470:        else
                   1471:                tempBuffer = NewHandleSys(size);
                   1472:        
                   1473:        return tempBuffer;
                   1474: }
                   1475: #endif         /* TARGET_OS_MAC */
                   1476: 
                   1477: 
                   1478: 
                   1479: static UInt32
                   1480: CountExtentBlocks(HFSPlusExtentRecord extents, Boolean hfsPlus)
                   1481: {
                   1482:        UInt32  blocks;
                   1483:        
                   1484:        // grab the first 3
                   1485:        blocks = extents[0].blockCount + extents[1].blockCount + extents[2].blockCount;
                   1486: 
                   1487:        if (hfsPlus)
                   1488:        {
                   1489:                UInt32  i;
                   1490:                
                   1491:                for (i = 3; i < kHFSPlusExtentDensity; ++i)
                   1492:                        blocks += extents[i].blockCount;                // HFS Plus has additional extents
                   1493:        }
                   1494: 
                   1495:        return blocks;
                   1496: }
                   1497: 
                   1498: 
                   1499: static void
                   1500: ConvertToHFSPlusExtent( const HFSExtentRecord oldExtents, HFSPlusExtentRecord newExtents)
                   1501: {
                   1502:        UInt16  i;
                   1503: 
                   1504:        // go backwards so we can convert in place!
                   1505:        
                   1506:        for (i = kHFSPlusExtentDensity-1; i > 2; --i)
                   1507:        {
                   1508:                newExtents[i].blockCount = 0;
                   1509:                newExtents[i].startBlock = 0;
                   1510:        }
                   1511: 
                   1512:        newExtents[2].blockCount = oldExtents[2].blockCount;
                   1513:        newExtents[2].startBlock = oldExtents[2].startBlock;
                   1514:        newExtents[1].blockCount = oldExtents[1].blockCount;
                   1515:        newExtents[1].startBlock = oldExtents[1].startBlock;
                   1516:        newExtents[0].blockCount = oldExtents[0].blockCount;
                   1517:        newExtents[0].startBlock = oldExtents[0].startBlock;
                   1518: }
                   1519: 
                   1520: 
                   1521: static OSErr
                   1522: GetFileExtentRecord( const ExtendedVCB *vcb, const FCB *fcb, HFSPlusExtentRecord extents)
                   1523: {
                   1524:        OSErr                           err;
                   1525:        ExtendedFCB                     *extendedFCB;
                   1526: 
                   1527:        err = noErr;
                   1528:        
                   1529:        if (vcb->vcbSigWord == kHFSSigWord)
                   1530:        {
                   1531:                ConvertToHFSPlusExtent(fcb->fcbExtRec, extents);
                   1532:        }
                   1533:        else
                   1534:        {
                   1535: /* XXX PPD: Is there any reason this isn't the same for EVERY platform? */
                   1536: #if TARGET_OS_MAC
                   1537:                extendedFCB = ParallelFCBFromRefnum( GetFileRefNumFromFCB(fcb) );
                   1538: #else
                   1539:                extendedFCB = GetParallelFCB( GetFileRefNumFromFCB(fcb) );
                   1540: #endif
                   1541: 
                   1542:                if (extendedFCB == NULL)
                   1543:                {
                   1544:                        if ( DEBUG_BUILD )
                   1545:                                DebugStr("\pFATAL: Extended FCB not found!");
                   1546:                        err = fsDSIntErr;
                   1547:                }
                   1548:                else
                   1549:                {
                   1550:                        BlockMoveData(extendedFCB->extents, extents, sizeof(HFSPlusExtentRecord));
                   1551:                }
                   1552:        }
                   1553:        
                   1554:        return err;
                   1555: }
                   1556: 
                   1557: 
                   1558: 
                   1559: //_______________________________________________________________________
                   1560: //
                   1561: //     CheckCreateDate
                   1562: //     
                   1563: //     For HFS Plus volumes, make sure the createDate in the VolumeHeader
                   1564: //     is the same as in the MDB.  If not, just fix it.
                   1565: //
                   1566: //_______________________________________________________________________
                   1567: 
                   1568: static OSErr CheckCreateDate (ExtendedVCB* volume, UInt32* consistencyStatus )
                   1569: {
                   1570:        OSErr                                   err;
                   1571:        HFSMasterDirectoryBlock *mdb;
                   1572:        UInt32                                  createDate;
                   1573: 
                   1574:        return noErr;
                   1575:        
                   1576:        //
                   1577:        //      Read in the MDB
                   1578:        //
                   1579: #if TARGET_OS_MAC
                   1580:         err = GetBlock_glue(gbReleaseMask, 2, (Ptr *) &mdb, volume->vcbVRefNum, volume);
                   1581: #else
                   1582:         err = GetBlock_glue(gbReleaseMask, 2, (Ptr *) &mdb, kNoFileReference, volume);
                   1583: #endif
                   1584:        if (err != noErr) return err;
                   1585:        
                   1586:        //
                   1587:        //      Make sure it really is a wrappered volume with an MDB
                   1588:        //
                   1589:        if (mdb->drSigWord != kHFSSigWord || mdb->drEmbedSigWord != kHFSPlusSigWord)
                   1590:                return noErr;                   // must not be a wrapper, so nothing to fix
                   1591:        
                   1592:        createDate = mdb->drCrDate;
                   1593:        
                   1594:        if (volume->vcbCrDate != createDate) {
                   1595:                volume->vcbCrDate = createDate;                                 // fix create date in the VCB
                   1596:                volume->vcbFlags |= kVCBFlagsVolumeDirty;               // make it dirty so change will be written to volume header
                   1597:                *consistencyStatus |= kHFSMinorRepairsWereMade; // the problem is now fixed
                   1598:        }
                   1599:        
                   1600:        return noErr;
                   1601: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.