Annotation of kernel/bsd/hfs/hfscommon/Misc/VolumeCheck.c, revision 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.