Annotation of XNU/bsd/hfs/hfscommon/Misc/FileExtentMapping.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:        File:           FileExtentMapping.c
        !            24: 
        !            25:        Contains:       xxx put contents here xxx
        !            26: 
        !            27:        Version:        HFS Plus 1.0
        !            28: 
        !            29:        Written by:     Dave Heller, Mark Day
        !            30: 
        !            31:        Copyright:      � 1996-1999 by Apple Computer, Inc., all rights reserved.
        !            32: 
        !            33:        File Ownership:
        !            34: 
        !            35:                DRI:                            Mark Day
        !            36: 
        !            37:                Other Contact:          xxx put other contact here xxx
        !            38: 
        !            39:                Technology:                     xxx put technology here xxx
        !            40: 
        !            41:        Writers:
        !            42: 
        !            43:                (DSH)   Deric Horn
        !            44:                (msd)   Mark Day
        !            45:                (djb)   Don Brady
        !            46: 
        !            47:        Change History (most recent first):
        !            48:          <MacOSX>        9/9/99        djb             Fix fcbModifiedMask flag testing logic.
        !            49:          <MacOSX>       8/25/98        djb             Flush extents b-tree header if dirty (2371088).
        !            50:          <MacOSX>       6/30/98        djb             Add functions NodesAreContiguous and ExtentsAreIntegral (for radar #2249539).
        !            51:          <MacOSX>       6/23/98        djb             Changed DeallocFile to DeleteFile which now deletes the catalog record.
        !            52:                                                                        Fixed UpdateExtentRecord to pass correct fcb to Btree routines. Fixed
        !            53:                                                                        hfs+ bug in CreateExtentRecord (double dereference).
        !            54:          <MacOSX>       5/20/98        djb             In ExtendFileC don't lie about the peof! (radar #2230094).
        !            55:          <MacOSX>       4/17/98        djb             Add VCB locking.
        !            56:          <MacOSX>        4/2/98        djb             Switch over to real BTree interface (no more BTreeWrapper.c).
        !            57:          <MacOSX>       3/31/98        djb             Sync up with final HFSVolumes.h header file.
        !            58: 
        !            59:          <CS24>         1/23/98        msd             Bug 2208024: AllocContig is actually allocating one extent even
        !            60:                                                                        though there is not enough contiguous space.
        !            61:          <CS23>         12/2/97        DSH             GetFCBExtentRecord no longer static so DFA can use it.
        !            62:          <CS22>        10/20/97        msd             When allocating more space for a file, do the clump size
        !            63:                                                                        calculations in ExtendFileC, not BlockAllocate. Undo change from
        !            64:                                                                        <CS18>.
        !            65:          <CS21>        10/17/97        msd             Conditionalize DebugStrs.
        !            66:          <CS20>        10/16/97        msd             Simplify the code path for MapFileBlockC (logical to physical
        !            67:                                                                        block mapping) in the typical case where the file isn't
        !            68:                                                                        fragmented so badly that it has extents in the extents B-tree.
        !            69:                                                                        Simplified some of the calculations for all cases.
        !            70:          <CS19>        10/13/97        DSH             FindExtentRecord & DeleteExtentRecord are also being used by DFA
        !            71:                                                                        no longer static.
        !            72:          <CS18>         10/6/97        msd             When extending a file, set the physical EOF to include any extra
        !            73:                                                                        space allocated due to a file's clump size.
        !            74:          <CS17>         9/19/97        msd             Remove the MapLogicalToPhysical SPI. It was never used and is
        !            75:                                                                        not being tested anyway.
        !            76:          <CS16>          9/5/97        msd             In CompareExtentKeys and CompareExtentKeysPlus, use the symbolic
        !            77:                                                                        constants for key length. Don't DebugStr unless DEBUG_BUILD is
        !            78:                                                                        set.
        !            79:          <CS15>         7/24/97        djb             Add instrumentation to MapFileBlockC
        !            80:          <CS14>         7/16/97        DSH             FilesInternal.i renamed FileMgrInternal.i to avoid name
        !            81:                                                                        collision
        !            82:          <CS13>         7/15/97        DSH             AdjEOF() mark the FCB as modified. (1664389)
        !            83:          <CS12>          7/8/97        DSH             Loading PrecompiledHeaders from define passed in on C line
        !            84:          <CS11>          7/3/97        msd             Bug #1663518. Remove DebugStr when setting the FCB extent record
        !            85:                                                                        for a volume control file.
        !            86:          <CS10>         6/27/97        msd             Moved enum kFirstFileRefnum to FilesInternal.
        !            87:           <CS9>         6/24/97        djb             Include "CatalogPrivate.h"
        !            88:           <CS8>         6/16/97        msd             Finish implementation of CreateLargeFile SPI.
        !            89:           <CS7>         6/12/97        msd             Add stub for CreateLargeFile SPI.
        !            90:           <CS6>          6/5/97        msd             Add MapLogicalToPhysical.
        !            91:           <CS5>          6/2/97        msd             In TruncateFileC, don't update the extent record unless it was
        !            92:                                                                        actually changed (prevents extra updates when truncating to the
        !            93:                                                                        end of the extent, and it is the last extent of the file.) Added
        !            94:                                                                        an AdjustEOF routine called by the assembly AdjEOF routine. It
        !            95:                                                                        copies the EOF, physical length, and extent information from one
        !            96:                                                                        FCB to all other FCBs for that fork.
        !            97:           <CS4>         5/20/97        DSH             Removed const declaration in MapFileBlocC, const is benign when
        !            98:                                                                        passing by value, and SC requires it to match prototype.
        !            99:           <CS3>         5/15/97        msd             Change enum kResourceForkType from -1 to 0xFF since it is now
        !           100:                                                                        unsigned. Change all forkType parameters to UInt8.
        !           101:           <CS2>          5/7/97        msd             When checking for an unused extent descriptor, check the length,
        !           102:                                                                        not the starting block.
        !           103:           <CS1>         4/24/97        djb             first checked in
        !           104:         <HFS25>         4/11/97        DSH             use extended VCB fields catalogRefNum, and extentsRefNum.
        !           105:         <HFS24>          4/4/97        djb             Get in sync with volume format changes.
        !           106:         <HFS23>         3/17/97        DSH             Casting to compile with SC.
        !           107:         <HFS22>         2/26/97        msd             Add instrumentation in ExtendFileC and TruncateFileC. In
        !           108:                                                                        CompareExtentKeys and CompareExtentKeysPlus, make sure the key
        !           109:                                                                        lengths are correct.
        !           110:         <HFS21>          2/5/97        msd             The comparison with fsBTStartOfIterationErr didn't work because
        !           111:                                                                        the enum is an unsigned long; it is now casted to an OSErr
        !           112:                                                                        before comparing.
        !           113:         <HFS20>         1/31/97        msd             In FindExtentRecord, turn an fsBTStartOfIterationErr error into
        !           114:                                                                        btNotFound.
        !           115:         <HFS19>         1/28/97        msd             Fixed bug in MapFileBlockC where it returned the wrong number of
        !           116:                                                                        bytes available at the given block number.  This could
        !           117:                                                                        potentially cause programs to read or write over other files.
        !           118:         <HFS18>         1/16/97        djb             Extent key compare procs now return SInt32. Fixed
        !           119:                                                                        UpdateExtentRecord - it was passing a pointer to an ExtentKey
        !           120:                                                                        pointer.
        !           121:         <HFS17>         1/10/97        msd             Change TruncateFileC to call DellocateFork when the new PEOF is
        !           122:                                                                        0. Fixes a fxRangeErr returned when no extents existed.
        !           123:         <HFS16>          1/6/97        msd             Previous change prevents extent records from being removed if
        !           124:                                                                        the files new PEOF is in the local (FCB/catalog) extents.
        !           125:         <HFS15>          1/3/97        djb             Temp fix in TruncateFileC to prevent unwanted calls to
        !           126:                                                                        TruncateExtents.
        !           127:         <HFS14>        12/23/96        msd             Previous change to SearchExtentFile didn't set up the outputs
        !           128:                                                                        for hint and key when the FCB extent record wasn't full.
        !           129:         <HFS13>        12/20/96        msd             In SearchExtentFile, don't bother searching the extents file if
        !           130:                                                                        the FCB's extent record wasn't full, or if the FCB was for the
        !           131:                                                                        extents file itself. Modified SearchExtentRecord to return a
        !           132:                                                                        Boolean to indicate that the record was not full.
        !           133:         <HFS12>        12/19/96        DSH             Changed refs from VCB to ExtendedVCB
        !           134:         <HFS11>        12/19/96        djb             Updated for new B-tree Manager interface.
        !           135:         <HFS10>        12/12/96        djb             Really use new SPI for GetCatalogNode.
        !           136:          <HFS9>        12/12/96        djb             Use new Catalog SPI for GetCatalogNode. Added Mark's changes to
        !           137:                                                                        MapFileBlockC.
        !           138:          <HFS8>        12/11/96        msd             TruncateFileC must always release extents, even if PEOF hasn't
        !           139:                                                                        changed (since allocation may have been rounded up due to clump
        !           140:                                                                        size).
        !           141:          <HFS7>        12/10/96        msd             Check PRAGMA_LOAD_SUPPORTED before loading precompiled headers.
        !           142:          <HFS6>         12/4/96        DSH             Precompiled headers
        !           143:          <HFS5>        11/26/96        msd             Add an exported routine to grow the parallel FCB table to
        !           144:                                                                        accomodate the HFS+ ExtentRecord.
        !           145:          <HFS4>        11/26/96        msd             Convert internal routines to use ExtentKey and ExtentRecord
        !           146:                                                                        (instead of the raw HFS structures).
        !           147:          <HFS3>        11/21/96        msd             Added CompareExtentKeysPlus().
        !           148:          <HFS2>        11/20/96        msd             Finish porting FXM to C.
        !           149:          <HFS1>         11/6/96        DKH             first checked in
        !           150: 
        !           151: */
        !           152: 
        !           153: 
        !           154: #include "../../hfs.h"
        !           155: #include "../../hfs_format.h"
        !           156: 
        !           157: #include "../headers/FileMgrInternal.h"
        !           158: #include "../headers/BTreesInternal.h"
        !           159: #include "../headers/CatalogPrivate.h"         // calling a private catalog routine (LocateCatalogNode)
        !           160: 
        !           161: #include "../headers/HFSInstrumentation.h"
        !           162: 
        !           163: 
        !           164: /*
        !           165: ============================================================
        !           166: Public (Exported) Routines:
        !           167: ============================================================
        !           168:        DeAllocFile             Deallocate all disk space allocated to a specified file.
        !           169:                                        Both forks are deallocated.
        !           170: 
        !           171:        ExtendFileC             Allocate more space to a given file.
        !           172: 
        !           173:        CompareExtentKeys
        !           174:                                        Compare two extents file keys (a search key and a trial
        !           175:                                        key).  Used by the BTree manager when searching for,
        !           176:                                        adding, or deleting keys in the extents file of an HFS
        !           177:                                        volume.
        !           178:                                        
        !           179:        CompareExtentKeysPlus
        !           180:                                        Compare two extents file keys (a search key and a trial
        !           181:                                        key).  Used by the BTree manager when searching for,
        !           182:                                        adding, or deleting keys in the extents file of an HFS+
        !           183:                                        volume.
        !           184:                                        
        !           185:        MapFileBlockC   Convert (map) an offset within a given file into a
        !           186:                                        physical disk address.
        !           187:                                        
        !           188:        TruncateFileC   Truncates the disk space allocated to a file.  The file
        !           189:                                        space is truncated to a specified new physical EOF, rounded
        !           190:                                        up to the next allocation block boundry.  There is an option
        !           191:                                        to truncate to the end of the extent containing the new EOF.
        !           192:        
        !           193:        FlushExtentFile
        !           194:                                        Flush the extents file for a given volume.
        !           195: 
        !           196:        GrowParallelFCBs
        !           197:                                        Make sure the parallel FCB entries are big enough to support
        !           198:                                        the HFS+ ExtentRecord.  If not, the array is grown and the
        !           199:                                        pre-existing data copied over.
        !           200: 
        !           201:        AdjustEOF
        !           202:                                        Copy EOF, physical length, and extent records from one FCB
        !           203:                                        to all other FCBs for that fork.  This is used when a file is
        !           204:                                        grown or shrunk as the result of a Write, SetEOF, or Allocate.
        !           205: 
        !           206:        MapLogicalToPhysical
        !           207:                                        Map some position in a file to a volume block number.  Also
        !           208:                                        returns the number of contiguous bytes that are mapped there.
        !           209:                                        This is a queued HFSDispatch call that does the equivalent of
        !           210:                                        MapFileBlockC, using a parameter block.
        !           211: 
        !           212: ============================================================
        !           213: Internal Routines:
        !           214: ============================================================
        !           215:        FindExtentRecord
        !           216:                                        Search the extents BTree for a particular extent record.
        !           217:        SearchExtentFile
        !           218:                                        Search the FCB and extents file for an extent record that
        !           219:                                        contains a given file position (in bytes).
        !           220:        SearchExtentRecord
        !           221:                                        Search a given extent record to see if it contains a given
        !           222:                                        file position (in bytes).  Used by SearchExtentFile.
        !           223:        ReleaseExtents
        !           224:                                        Deallocate all allocation blocks in all extents of an extent
        !           225:                                        data record.
        !           226:        TruncateExtents
        !           227:                                        Deallocate blocks and delete extent records for all allocation
        !           228:                                        blocks beyond a certain point in a file.  The starting point
        !           229:                                        must be the first file allocation block for some extent record
        !           230:                                        for the file.
        !           231:        DeallocateFork
        !           232:                                        Deallocate all allocation blocks belonging to a given fork.
        !           233:        UpdateExtentRecord
        !           234:                                        If the extent record came from the extents file, write out
        !           235:                                        the updated record; otherwise, copy the updated record into
        !           236:                                        the FCB resident extent record.  If the record has no extents,
        !           237:                                        and was in the extents file, then delete the record instead.
        !           238: */
        !           239: 
        !           240: enum
        !           241: {
        !           242:        kTwoGigabytes                   = (UInt32) 0x80000000,
        !           243:        
        !           244:        kDataForkType                   = 0,
        !           245:        kResourceForkType               = 0xFF,
        !           246:        
        !           247:        kPreviousRecord                 = -1,
        !           248:        
        !           249:        kSectorSize                             = 512           // Size of a physical sector
        !           250: };
        !           251: 
        !           252: void HFSToHFSPlusExtents(
        !           253:        const HFSExtentRecord   oldExtents,
        !           254:        HFSPlusExtentRecord             newExtents);
        !           255: 
        !           256: OSErr HFSPlusToHFSExtents(
        !           257:        const HFSPlusExtentRecord       oldExtents,
        !           258:        HFSExtentRecord                         newExtents);
        !           259: 
        !           260: OSErr FindExtentRecord(
        !           261:        const ExtendedVCB               *vcb,
        !           262:        UInt8                                   forkType,
        !           263:        UInt32                                  fileID,
        !           264:        UInt32                                  startBlock,
        !           265:        Boolean                                 allowPrevious,
        !           266:        HFSPlusExtentKey                *foundKey,
        !           267:        HFSPlusExtentRecord             foundData,
        !           268:        UInt32                                  *foundHint);
        !           269: 
        !           270: OSErr DeleteExtentRecord(
        !           271:        const ExtendedVCB               *vcb,
        !           272:        UInt8                                   forkType,
        !           273:        UInt32                                  fileID,
        !           274:        UInt32                                  startBlock);
        !           275: 
        !           276: static OSErr CreateExtentRecord(
        !           277:        const ExtendedVCB               *vcb,
        !           278:        HFSPlusExtentKey                *key,
        !           279:        HFSPlusExtentRecord             extents,
        !           280:        UInt32                                  *hint);
        !           281: 
        !           282: 
        !           283: OSErr GetFCBExtentRecord(
        !           284:        const FCB                               *fcb,
        !           285:        HFSPlusExtentRecord             extents);
        !           286: 
        !           287: static OSErr SearchExtentFile(
        !           288:        const ExtendedVCB               *vcb,
        !           289:        const FCB                               *fcb,
        !           290:        SInt64                                  filePosition,
        !           291:        HFSPlusExtentKey                *foundExtentKey,
        !           292:        HFSPlusExtentRecord             foundExtentData,
        !           293:        UInt32                                  *foundExtentDataIndex,
        !           294:        UInt32                                  *extentBTreeHint,
        !           295:        UInt32                                  *endingFABNPlusOne );
        !           296: 
        !           297: static OSErr SearchExtentRecord(
        !           298:        const ExtendedVCB               *vcb,
        !           299:        UInt32                                  searchFABN,
        !           300:        const HFSPlusExtentRecord       extentData,
        !           301:        UInt32                                  extentDataStartFABN,
        !           302:        UInt32                                  *foundExtentDataOffset,
        !           303:        UInt32                                  *endingFABNPlusOne,
        !           304:        Boolean                                 *noMoreExtents);
        !           305: 
        !           306: static OSErr ReleaseExtents(
        !           307:        ExtendedVCB                             *vcb,
        !           308:        const HFSPlusExtentRecord       extentRecord,
        !           309:        UInt32                                  *numReleasedAllocationBlocks,
        !           310:        Boolean                                 *releasedLastExtent);
        !           311: 
        !           312: static OSErr DeallocateFork(
        !           313:        ExtendedVCB             *vcb,
        !           314:        HFSCatalogNodeID        fileID,
        !           315:        UInt8                   forkType,
        !           316:        HFSPlusExtentRecord     catalogExtents,
        !           317:        Boolean *               recordDeleted);
        !           318: 
        !           319: static OSErr TruncateExtents(
        !           320:        ExtendedVCB                     *vcb,
        !           321:        UInt8                           forkType,
        !           322:        UInt32                          fileID,
        !           323:        UInt32                          startBlock,
        !           324:        Boolean *                       recordDeleted);
        !           325: 
        !           326: static OSErr UpdateExtentRecord (
        !           327:        const ExtendedVCB               *vcb,
        !           328:        FCB                                             *fcb,
        !           329:        const HFSPlusExtentKey  *extentFileKey,
        !           330:        const HFSPlusExtentRecord       extentData,
        !           331:        UInt32                                  extentBTreeHint);
        !           332: 
        !           333: static OSErr MapFileBlockFromFCB(
        !           334:        const ExtendedVCB               *vcb,
        !           335:        const FCB                               *fcb,
        !           336:        SInt64                                  offset,                 // Desired offset in bytes from start of file
        !           337:        UInt32                                  *firstFABN,             // FABN of first block of found extent
        !           338:        UInt32                                  *firstBlock,    // Corresponding allocation block number
        !           339:        UInt32                                  *nextFABN);             // FABN of block after end of extent
        !           340: 
        !           341: static Boolean ExtentsAreIntegral(
        !           342:        const HFSPlusExtentRecord extentRecord,
        !           343:        UInt32          mask,
        !           344:        UInt32          *blocksChecked,
        !           345:        Boolean         *checkedLastExtent);
        !           346: 
        !           347: //_________________________________________________________________________________
        !           348: //
        !           349: //     Routine:        FindExtentRecord
        !           350: //
        !           351: //     Purpose:        Search the extents BTree for an extent record matching the given
        !           352: //                             FileID, fork, and starting file allocation block number.
        !           353: //
        !           354: //     Inputs:
        !           355: //             vcb                             Volume to search
        !           356: //             forkType                0 = data fork, -1 = resource fork
        !           357: //             fileID                  File's FileID (CatalogNodeID)
        !           358: //             startBlock              Starting file allocation block number
        !           359: //             allowPrevious   If the desired record isn't found and this flag is set,
        !           360: //                                             then see if the previous record belongs to the same fork.
        !           361: //                                             If so, then return it.
        !           362: //
        !           363: //     Outputs:
        !           364: //             foundKey        The key data for the record actually found
        !           365: //             foundData       The extent record actually found (NOTE: on an HFS volume, the
        !           366: //                                     fourth entry will be zeroes.
        !           367: //             foundHint       The BTree hint to find the node again
        !           368: //_________________________________________________________________________________
        !           369: OSErr FindExtentRecord(
        !           370:        const ExtendedVCB       *vcb,
        !           371:        UInt8                           forkType,
        !           372:        UInt32                          fileID,
        !           373:        UInt32                          startBlock,
        !           374:        Boolean                         allowPrevious,
        !           375:        HFSPlusExtentKey        *foundKey,
        !           376:        HFSPlusExtentRecord     foundData,
        !           377:        UInt32                          *foundHint)
        !           378: {
        !           379:        FCB *                           fcb;
        !           380:        BTreeIterator           btIterator;
        !           381:        FSBufferDescriptor      btRecord;
        !           382:        OSErr                           err;
        !           383:        UInt16                          btRecordSize;
        !           384:        
        !           385:        err = noErr;
        !           386:        *foundHint = 0;
        !           387:        fcb = GetFileControlBlock(vcb->extentsRefNum);
        !           388:        
        !           389:        (void) BTInvalidateHint(&btIterator);
        !           390: 
        !           391:        if (vcb->vcbSigWord == kHFSSigWord) {
        !           392:                HFSExtentKey *          extentKeyPtr;
        !           393:                HFSExtentRecord         extentData;
        !           394: 
        !           395:                extentKeyPtr = (HFSExtentKey*) &btIterator.key;
        !           396:                extentKeyPtr->keyLength = kHFSExtentKeyMaximumLength;
        !           397:                extentKeyPtr->forkType = forkType;
        !           398:                extentKeyPtr->fileID = fileID;
        !           399:                extentKeyPtr->startBlock = startBlock;
        !           400:                
        !           401:                btRecord.bufferAddress = &extentData;
        !           402:                btRecord.itemSize = sizeof(HFSExtentRecord);
        !           403:                btRecord.itemCount = 1;
        !           404: 
        !           405:                err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator);
        !           406: 
        !           407:                if (err == btNotFound && allowPrevious) {
        !           408:                        err = BTIterateRecord(fcb, kBTreePrevRecord, &btIterator, &btRecord, &btRecordSize);
        !           409: 
        !           410:                        //      A previous record may not exist, so just return btNotFound (like we would if
        !           411:                        //      it was for the wrong file/fork).
        !           412:                        if (err == (OSErr) fsBTStartOfIterationErr)             //�� fsBTStartOfIterationErr is type unsigned long
        !           413:                                err = btNotFound;
        !           414: 
        !           415:                        if (err == noErr) {
        !           416:                                //      Found a previous record.  Does it belong to the same fork of the same file?
        !           417:                                if (extentKeyPtr->fileID != fileID || extentKeyPtr->forkType != forkType)
        !           418:                                        err = btNotFound;
        !           419:                        }
        !           420:                }
        !           421: 
        !           422:                if (err == noErr) {
        !           423:                        UInt16  i;
        !           424:                        
        !           425:                        //      Copy the found key back for the caller
        !           426:                        foundKey->keyLength     = kHFSPlusExtentKeyMaximumLength;
        !           427:                        foundKey->forkType              = extentKeyPtr->forkType;
        !           428:                        foundKey->pad                   = 0;
        !           429:                        foundKey->fileID                = extentKeyPtr->fileID;
        !           430:                        foundKey->startBlock    = extentKeyPtr->startBlock;
        !           431:                        
        !           432:                        //      Copy the found data back for the caller
        !           433:                        foundData[0].startBlock = extentData[0].startBlock;
        !           434:                        foundData[0].blockCount = extentData[0].blockCount;
        !           435:                        foundData[1].startBlock = extentData[1].startBlock;
        !           436:                        foundData[1].blockCount = extentData[1].blockCount;
        !           437:                        foundData[2].startBlock = extentData[2].startBlock;
        !           438:                        foundData[2].blockCount = extentData[2].blockCount;
        !           439:                        
        !           440:                        for (i = 3; i < kHFSPlusExtentDensity; ++i)
        !           441:                        {
        !           442:                                foundData[i].startBlock = 0;
        !           443:                                foundData[i].blockCount = 0;
        !           444:                        }
        !           445:                }
        !           446:        }
        !           447:        else {          // HFS Plus volume
        !           448:                HFSPlusExtentKey *      extentKeyPtr;
        !           449:                HFSPlusExtentRecord     extentData;
        !           450: 
        !           451:                extentKeyPtr = (HFSPlusExtentKey*) &btIterator.key;
        !           452:                extentKeyPtr->keyLength  = kHFSPlusExtentKeyMaximumLength;
        !           453:                extentKeyPtr->forkType   = forkType;
        !           454:                extentKeyPtr->pad                = 0;
        !           455:                extentKeyPtr->fileID     = fileID;
        !           456:                extentKeyPtr->startBlock = startBlock;
        !           457:                
        !           458:                btRecord.bufferAddress = &extentData;
        !           459:                btRecord.itemSize = sizeof(HFSPlusExtentRecord);
        !           460:                btRecord.itemCount = 1;
        !           461: 
        !           462:                err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator);
        !           463: 
        !           464:                if (err == btNotFound && allowPrevious) {
        !           465:                        err = BTIterateRecord(fcb, kBTreePrevRecord, &btIterator, &btRecord, &btRecordSize);
        !           466: 
        !           467:                        //      A previous record may not exist, so just return btNotFound (like we would if
        !           468:                        //      it was for the wrong file/fork).
        !           469:                        if (err == (OSErr) fsBTStartOfIterationErr)             //�� fsBTStartOfIterationErr is type unsigned long
        !           470:                                err = btNotFound;
        !           471: 
        !           472:                        if (err == noErr) {
        !           473:                                //      Found a previous record.  Does it belong to the same fork of the same file?
        !           474:                                if (extentKeyPtr->fileID != fileID || extentKeyPtr->forkType != forkType)
        !           475:                                        err = btNotFound;
        !           476:                        }
        !           477:                }
        !           478: 
        !           479:                if (err == noErr) {
        !           480:                        //      Copy the found key back for the caller
        !           481:                        BlockMoveData(extentKeyPtr, foundKey, sizeof(HFSPlusExtentKey));
        !           482:                        //      Copy the found data back for the caller
        !           483:                        BlockMoveData(&extentData, foundData, sizeof(HFSPlusExtentRecord));
        !           484:                }
        !           485:        }
        !           486:        
        !           487:        *foundHint = btIterator.hint.nodeNum;
        !           488:        return err;
        !           489: }
        !           490: 
        !           491: 
        !           492: 
        !           493: static OSErr CreateExtentRecord(
        !           494:        const ExtendedVCB       *vcb,
        !           495:        HFSPlusExtentKey        *key,
        !           496:        HFSPlusExtentRecord     extents,
        !           497:        UInt32                          *hint)
        !           498: {
        !           499:        BTreeIterator           btIterator;
        !           500:        FSBufferDescriptor      btRecord;
        !           501:        UInt16                          btRecordSize;
        !           502:        OSErr                           err;
        !           503:        
        !           504:        err = noErr;
        !           505:        *hint = 0;
        !           506:        (void) BTInvalidateHint(&btIterator);
        !           507:        
        !           508:        if (vcb->vcbSigWord == kHFSSigWord) {
        !           509:                HFSExtentKey *          keyPtr;
        !           510:                HFSExtentRecord         data;
        !           511:                
        !           512:                btRecordSize = sizeof(HFSExtentRecord);
        !           513:                btRecord.bufferAddress = &data;
        !           514:                btRecord.itemSize = btRecordSize;
        !           515:                btRecord.itemCount = 1;
        !           516: 
        !           517:                keyPtr = (HFSExtentKey*) &btIterator.key;
        !           518:                keyPtr->keyLength       = kHFSExtentKeyMaximumLength;
        !           519:                keyPtr->forkType        = key->forkType;
        !           520:                keyPtr->fileID          = key->fileID;
        !           521:                keyPtr->startBlock      = key->startBlock;
        !           522:                
        !           523:                err = HFSPlusToHFSExtents(extents, data);
        !           524:        }
        !           525:        else {          // HFS Plus volume
        !           526:                btRecordSize = sizeof(HFSPlusExtentRecord);
        !           527:                btRecord.bufferAddress = extents;
        !           528:                btRecord.itemSize = btRecordSize;
        !           529:                btRecord.itemCount = 1;
        !           530: 
        !           531:                BlockMoveData(key, &btIterator.key, sizeof(HFSPlusExtentKey));
        !           532:        }
        !           533: 
        !           534:        if (err == noErr)
        !           535:                err = BTInsertRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator, &btRecord, btRecordSize);
        !           536: 
        !           537:        if (err == noErr)
        !           538:                *hint = btIterator.hint.nodeNum;
        !           539: 
        !           540:        return err;
        !           541: }
        !           542: 
        !           543: 
        !           544: OSErr DeleteExtentRecord(
        !           545:        const ExtendedVCB       *vcb,
        !           546:        UInt8                           forkType,
        !           547:        UInt32                          fileID,
        !           548:        UInt32                          startBlock)
        !           549: {
        !           550:        BTreeIterator           btIterator;
        !           551:        OSErr                           err;
        !           552:        
        !           553:        err = noErr;
        !           554:        (void) BTInvalidateHint(&btIterator);
        !           555:        
        !           556:        if (vcb->vcbSigWord == kHFSSigWord) {
        !           557:                HFSExtentKey *  keyPtr;
        !           558: 
        !           559:                keyPtr = (HFSExtentKey*) &btIterator.key;
        !           560:                keyPtr->keyLength       = kHFSExtentKeyMaximumLength;
        !           561:                keyPtr->forkType        = forkType;
        !           562:                keyPtr->fileID          = fileID;
        !           563:                keyPtr->startBlock      = startBlock;
        !           564:        }
        !           565:        else {          //      HFS Plus volume
        !           566:                HFSPlusExtentKey *      keyPtr;
        !           567: 
        !           568:                keyPtr = (HFSPlusExtentKey*) &btIterator.key;
        !           569:                keyPtr->keyLength       = kHFSPlusExtentKeyMaximumLength;
        !           570:                keyPtr->forkType        = forkType;
        !           571:                keyPtr->pad                     = 0;
        !           572:                keyPtr->fileID          = fileID;
        !           573:                keyPtr->startBlock      = startBlock;
        !           574:        }
        !           575: 
        !           576:        err = BTDeleteRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator);
        !           577:        
        !           578:        return err;
        !           579: }
        !           580: 
        !           581: 
        !           582: 
        !           583: //_________________________________________________________________________________
        !           584: //
        !           585: // Routine:            MapFileBlock
        !           586: //
        !           587: // Function:   Maps a file position into a physical disk address.
        !           588: //
        !           589: // Input:              A2.L  -  VCB pointer
        !           590: //                             (A1,D1.W)  -  FCB pointer
        !           591: //                             D4.L  -  number of bytes desired
        !           592: //                             D5.L  -  file position (byte address)
        !           593: //
        !           594: // Output:             D3.L  -  physical start block
        !           595: //                             D6.L  -  number of contiguous bytes available (up to D4 bytes)
        !           596: //                             D0.L  -  result code                                                                                            <01Oct85>
        !           597: //                                                0 = ok
        !           598: //                                                FXRangeErr = file position beyond mapped range                       <17Oct85>
        !           599: //                                                FXOvFlErr = extents file overflow                                            <17Oct85>
        !           600: //                                                other = error                                                                                        <17Oct85>
        !           601: //
        !           602: // Called By:  Log2Phys (read/write in place), Cache (map a file block).
        !           603: //_________________________________________________________________________________
        !           604: 
        !           605: OSErr MapFileBlockC (
        !           606:        ExtendedVCB             *vcb,                           // volume that file resides on
        !           607:        FCB                             *fcb,                           // FCB of file
        !           608:        SInt64                  numberOfBytes,          // number of contiguous bytes desired
        !           609:        SInt64                  offset,                         // starting offset within file (in bytes)
        !           610:        UInt32                  *startSector,           // first 512-byte sector (NOT an allocation block)
        !           611:        UInt32                  *availableBytes)        // number of contiguous bytes (up to numberOfBytes)
        !           612: {
        !           613:        OSErr                           err;
        !           614:        UInt32                          allocBlockSize;                 //      Size of the volume's allocation block
        !           615:        HFSPlusExtentKey        foundKey;
        !           616:        HFSPlusExtentRecord     foundData;
        !           617:        UInt32                          foundIndex;
        !           618:        UInt32                          hint;
        !           619:        UInt32                          firstFABN;                              // file allocation block of first block in found extent
        !           620:        UInt32                          nextFABN;                               // file allocation block of block after end of found extent
        !           621:        SInt64                          dataEnd;                                // (offset) end of range that is contiguous
        !           622:        UInt32                          sectorsPerBlock;                // Number of sectors per allocation block
        !           623:        UInt32                          startBlock;                             // volume allocation block corresponding to firstFABN
        !           624:        UInt32                          temp;
        !           625:        
        !           626:        
        !           627:        LogStartTime(kTraceMapFileBlock);
        !           628: 
        !           629:        allocBlockSize = vcb->blockSize;
        !           630:        
        !           631:        err = MapFileBlockFromFCB(vcb, fcb, offset, &firstFABN, &startBlock, &nextFABN);
        !           632:        if (err != noErr) {
        !           633:                err = SearchExtentFile(vcb, fcb, offset, &foundKey, foundData, &foundIndex, &hint, &nextFABN);
        !           634:                if (err == noErr) {
        !           635:                        startBlock = foundData[foundIndex].startBlock;
        !           636:                        firstFABN = nextFABN - foundData[foundIndex].blockCount;
        !           637:                }
        !           638:        }
        !           639:        
        !           640:        if (err != noErr)
        !           641:        {
        !           642:                LogEndTime(kTraceMapFileBlock, err);
        !           643: 
        !           644:                return err;
        !           645:        }
        !           646: 
        !           647:        //
        !           648:        //      Determine the end of the available space.  It will either be the end of the extent,
        !           649:        //      or the file's PEOF, whichever is smaller.
        !           650:        //
        !           651:        dataEnd = nextFABN * allocBlockSize;            // Assume valid data through end of this extent
        !           652:        if (fcb->fcbPLen < dataEnd)                                     // Is PEOF shorter?
        !           653:                dataEnd = fcb->fcbPLen;                                 // Yes, so only map up to PEOF
        !           654:        
        !           655:        //      Compute the number of sectors in an allocation block
        !           656:        sectorsPerBlock = allocBlockSize / kSectorSize; // sectors per allocation block
        !           657:        
        !           658:        //
        !           659:        //      Compute the absolute sector number that contains the offset of the given file
        !           660:        //
        !           661:        temp  = (UInt32)((offset - (firstFABN * allocBlockSize))/kSectorSize);  // offset in sectors from start of the extent
        !           662:        temp += startBlock * sectorsPerBlock;                   // offset in sectors from start of allocation block space
        !           663:     if (vcb->vcbSigWord == kHFSPlusSigWord)
        !           664:         temp += vcb->hfsPlusIOPosOffset/512;  /* offset inside wrapper */
        !           665:     else
        !           666:         temp += vcb->vcbAlBlSt;                /* offset in sectors from start of volume */
        !           667:        
        !           668:        //      Return the desired sector for file position "offset"
        !           669:        *startSector = temp;
        !           670:        
        !           671:        //
        !           672:        //      Determine the number of contiguous bytes until the end of the extent
        !           673:        //      (or the amount they asked for, whichever comes first).
        !           674:        //
        !           675:        temp = (UInt32)(dataEnd - offset);
        !           676:        if (temp > numberOfBytes)
        !           677:                *availableBytes = numberOfBytes;        // more there than they asked for, so pin the output
        !           678:        else
        !           679:                *availableBytes = temp;
        !           680:        
        !           681:        LogEndTime(kTraceMapFileBlock, noErr);
        !           682: 
        !           683:        return noErr;
        !           684: }
        !           685: 
        !           686: 
        !           687: //�������������������������������������������������������������������������������
        !           688: //     Routine:        ReleaseExtents
        !           689: //
        !           690: //     Function:       Release the extents of a single extent data record.
        !           691: //�������������������������������������������������������������������������������
        !           692: 
        !           693: static OSErr ReleaseExtents(
        !           694:        ExtendedVCB                     *vcb,
        !           695:        const HFSPlusExtentRecord       extentRecord,
        !           696:        UInt32                                  *numReleasedAllocationBlocks,
        !           697:        Boolean                                 *releasedLastExtent)
        !           698: {
        !           699:        UInt32  extentIndex;
        !           700:        UInt32  numberOfExtents;
        !           701:        OSErr   err = noErr;
        !           702:        
        !           703:        *numReleasedAllocationBlocks = 0;
        !           704:        *releasedLastExtent = false;
        !           705:        
        !           706:        if (vcb->vcbSigWord == kHFSPlusSigWord)
        !           707:                numberOfExtents = kHFSPlusExtentDensity;
        !           708:        else
        !           709:                numberOfExtents = kHFSExtentDensity;
        !           710: 
        !           711:        for( extentIndex = 0; extentIndex < numberOfExtents; extentIndex++)
        !           712:        {
        !           713:                UInt32  numAllocationBlocks;
        !           714:                
        !           715:                // Loop over the extent record and release the blocks associated with each extent.
        !           716:                
        !           717:                numAllocationBlocks = extentRecord[extentIndex].blockCount;
        !           718:                if ( numAllocationBlocks == 0 )
        !           719:                {
        !           720:                        *releasedLastExtent = true;
        !           721:                        break;
        !           722:                }
        !           723: 
        !           724:                err = BlockDeallocate( vcb, extentRecord[extentIndex].startBlock, numAllocationBlocks );
        !           725:                if ( err != noErr )
        !           726:                        break;
        !           727:                                        
        !           728:                *numReleasedAllocationBlocks += numAllocationBlocks;            //      bump FABN to beg of next extent
        !           729:        }
        !           730: 
        !           731:        return( err );
        !           732: }
        !           733: 
        !           734: 
        !           735: 
        !           736: //�������������������������������������������������������������������������������
        !           737: //     Routine:        TruncateExtents
        !           738: //
        !           739: //     Purpose:        Delete extent records whose starting file allocation block number
        !           740: //                             is greater than or equal to a given starting block number.  The
        !           741: //                             allocation blocks represented by the extents are deallocated.
        !           742: //
        !           743: //     Inputs:
        !           744: //             vcb                     Volume to operate on
        !           745: //             fileID          Which file to operate on
        !           746: //             startBlock      Starting file allocation block number for first extent
        !           747: //                                     record to delete.
        !           748: //�������������������������������������������������������������������������������
        !           749: 
        !           750: static OSErr TruncateExtents(
        !           751:        ExtendedVCB             *vcb,
        !           752:        UInt8                   forkType,
        !           753:        UInt32                  fileID,
        !           754:        UInt32                  startBlock,
        !           755:        Boolean *               recordDeleted)
        !           756: {
        !           757:        OSErr                           err;
        !           758:        UInt32                          numberExtentsReleased;
        !           759:        Boolean                         releasedLastExtent;
        !           760:        UInt32                          hint;
        !           761:        HFSPlusExtentKey        key;
        !           762:        HFSPlusExtentRecord     extents;
        !           763: 
        !           764:        while (true) {
        !           765:                err = FindExtentRecord(vcb, forkType, fileID, startBlock, false, &key, extents, &hint);
        !           766:                if (err != noErr) {
        !           767:                        if (err == btNotFound)
        !           768:                                err = noErr;
        !           769:                        break;
        !           770:                }
        !           771:                
        !           772:                err = ReleaseExtents( vcb, extents, &numberExtentsReleased, &releasedLastExtent );
        !           773:                if (err != noErr) break;
        !           774:                
        !           775:                err = DeleteExtentRecord(vcb, forkType, fileID, startBlock);
        !           776:                if (err != noErr) break;
        !           777: 
        !           778:                *recordDeleted = true;
        !           779:                startBlock += numberExtentsReleased;
        !           780:        }
        !           781:        
        !           782:        return err;
        !           783: }
        !           784: 
        !           785: 
        !           786: 
        !           787: //�������������������������������������������������������������������������������
        !           788: //     Routine:        DeallocateFork
        !           789: //
        !           790: //     Function:       De-allocates all disk space allocated to a specified fork.
        !           791: //�������������������������������������������������������������������������������
        !           792: 
        !           793: static OSErr DeallocateFork(
        !           794:        ExtendedVCB             *vcb,
        !           795:        HFSCatalogNodeID        fileID,
        !           796:        UInt8                   forkType,
        !           797:        HFSPlusExtentRecord     catalogExtents,
        !           798:        Boolean *               recordDeleted) /* true if a record was deleted */
        !           799: {
        !           800:        OSErr                           err;
        !           801:        UInt32                          numReleasedAllocationBlocks;
        !           802:        Boolean                         releasedLastExtent;
        !           803:        
        !           804:        //      Release the catalog extents
        !           805:        err = ReleaseExtents( vcb, catalogExtents, &numReleasedAllocationBlocks, &releasedLastExtent );
        !           806:        // Release the extra extents, if present
        !           807:        if (err == noErr && !releasedLastExtent)
        !           808:                err = TruncateExtents(vcb, forkType, fileID, numReleasedAllocationBlocks, recordDeleted);
        !           809: 
        !           810:        return( err );
        !           811: }
        !           812: 
        !           813: //�������������������������������������������������������������������������������
        !           814: //     Routine:        FlushExtentFile
        !           815: //
        !           816: //     Function:       Flushes the extent file for a specified volume
        !           817: //�������������������������������������������������������������������������������
        !           818: 
        !           819: OSErr FlushExtentFile( ExtendedVCB *vcb )
        !           820: {
        !           821:        FCB *   fcb;
        !           822:        OSErr   err;
        !           823:        
        !           824:        fcb = GetFileControlBlock(vcb->extentsRefNum);
        !           825:        err = BTFlushPath(fcb);
        !           826:        if ( err == noErr )
        !           827:        {
        !           828:                // If the FCB for the extent "file" is dirty, mark the VCB as dirty.
        !           829:                
        !           830:         if ((fcb->fcbFlags & fcbModifiedMask) != 0)
        !           831:                {
        !           832:                        MarkVCBDirty( vcb );
        !           833:                        err = FlushVolumeControlBlock( vcb );
        !           834:                }
        !           835:        }
        !           836:        
        !           837:        return( err );
        !           838: }
        !           839: 
        !           840: //-------------------------------------------------------------------------------
        !           841: //     Routine:        DeleteFile
        !           842: //
        !           843: //     Function:       De-allocates all disk space allocated to a specified file 
        !           844: //                             including the space used by the catalog (ie the catalog record).
        !           845: //                             The space occupied by both forks is also deallocated.
        !           846: //
        !           847: //-------------------------------------------------------------------------------
        !           848: 
        !           849: OSErr DeleteFile( ExtendedVCB *vcb, HFSCatalogNodeID parDirID, ConstUTF8Param catalogName, UInt32 catalogHint )
        !           850: {
        !           851:        OSErr                   err;
        !           852:        OSErr                   errDF, errRF;
        !           853:        CatalogNodeData catalogData;
        !           854:        FSSpec                  fileSpec;       /* 264 bytes */
        !           855:        Boolean                 recordDeleted;
        !           856:        
        !           857:        recordDeleted = false;
        !           858:        
        !           859:        // Find catalog data in catalog
        !           860:     err = GetCatalogNode( vcb, parDirID, catalogName, kUndefinedStrLen, catalogHint, &fileSpec, &catalogData, &catalogHint);
        !           861:        if( err != noErr )
        !           862:                goto Exit;
        !           863:        
        !           864:        // Check to make sure record is for a file
        !           865:        if ( catalogData.cnd_type != kCatalogFileNode )
        !           866:        {
        !           867:                err = notAFileErr;
        !           868:                goto Exit;
        !           869:        }
        !           870:        
        !           871:        //
        !           872:        // Always delete the Catalog record first (to minimize disk corruption)
        !           873:        //
        !           874:        err = DeleteCatalogNode(vcb, parDirID, catalogName, catalogHint);
        !           875:        if( err != noErr )
        !           876:                goto Exit;
        !           877: 
        !           878:        //
        !           879:        // Note: we don't report errors from DeallocateFork since the
        !           880:        // file no longer exists (since DeleteCatalogNode succeeded).
        !           881:        // Any errors mean that there are possibly some orphaned disk
        !           882:        // blocks but from the clients perspective the file was deleted.
        !           883:        //
        !           884: 
        !           885:        // Deallocate data fork extents
        !           886:        errDF = DeallocateFork( vcb, catalogData.cnd_nodeID, kDataForkType,
        !           887:                    catalogData.cnd_datafork.extents, &recordDeleted );
        !           888: 
        !           889:        // Deallocate resource fork extents
        !           890:        errRF = DeallocateFork( vcb, catalogData.cnd_nodeID, kResourceForkType,
        !           891:                    catalogData.cnd_rsrcfork.extents, &recordDeleted );
        !           892: 
        !           893:        if (recordDeleted)
        !           894:                err = FlushExtentFile( vcb );
        !           895: 
        !           896:        return (errDF ? errDF : (errRF ? errRF : err));
        !           897: Exit:
        !           898:        
        !           899:        return( err );
        !           900: }
        !           901: 
        !           902: //�������������������������������������������������������������������������������
        !           903: //     Routine:        CompareExtentKeys
        !           904: //
        !           905: //     Function:       Compares two extent file keys (a search key and a trial key) for
        !           906: //                             an HFS volume.
        !           907: //�������������������������������������������������������������������������������
        !           908: 
        !           909: SInt32 CompareExtentKeys( const HFSExtentKey *searchKey, const HFSExtentKey *trialKey )
        !           910: {
        !           911:        SInt32  result;         //      � 1
        !           912:        
        !           913:        #if DEBUG_BUILD
        !           914:                if (searchKey->keyLength != kHFSExtentKeyMaximumLength)
        !           915:                        DebugStr("\pHFS: search Key is wrong length");
        !           916:                if (trialKey->keyLength != kHFSExtentKeyMaximumLength)
        !           917:                        DebugStr("\pHFS: trial Key is wrong length");
        !           918:        #endif
        !           919:        
        !           920:        result = -1;            //      assume searchKey < trialKey
        !           921:        
        !           922:        if (searchKey->fileID == trialKey->fileID) {
        !           923:                //
        !           924:                //      FileNum's are equal; compare fork types
        !           925:                //
        !           926:                if (searchKey->forkType == trialKey->forkType) {
        !           927:                        //
        !           928:                        //      Fork types are equal; compare allocation block number
        !           929:                        //
        !           930:                        if (searchKey->startBlock == trialKey->startBlock) {
        !           931:                                //
        !           932:                                //      Everything is equal
        !           933:                                //
        !           934:                                result = 0;
        !           935:                        }
        !           936:                        else {
        !           937:                                //
        !           938:                                //      Allocation block numbers differ; determine sign
        !           939:                                //
        !           940:                                if (searchKey->startBlock > trialKey->startBlock)
        !           941:                                        result = 1;
        !           942:                        }
        !           943:                }
        !           944:                else {
        !           945:                        //
        !           946:                        //      Fork types differ; determine sign
        !           947:                        //
        !           948:                        if (searchKey->forkType > trialKey->forkType)
        !           949:                                result = 1;
        !           950:                }
        !           951:        }
        !           952:        else {
        !           953:                //
        !           954:                //      FileNums differ; determine sign
        !           955:                //
        !           956:                if (searchKey->fileID > trialKey->fileID)
        !           957:                        result = 1;
        !           958:        }
        !           959:        
        !           960:        return( result );
        !           961: }
        !           962: 
        !           963: 
        !           964: 
        !           965: //�������������������������������������������������������������������������������
        !           966: //     Routine:        CompareExtentKeysPlus
        !           967: //
        !           968: //     Function:       Compares two extent file keys (a search key and a trial key) for
        !           969: //                             an HFS volume.
        !           970: //�������������������������������������������������������������������������������
        !           971: 
        !           972: SInt32 CompareExtentKeysPlus( const HFSPlusExtentKey *searchKey, const HFSPlusExtentKey *trialKey )
        !           973: {
        !           974:        SInt32  result;         //      � 1
        !           975:        
        !           976:        #if DEBUG_BUILD
        !           977:                if (searchKey->keyLength != kHFSPlusExtentKeyMaximumLength)
        !           978:                        DebugStr("\pHFS: search Key is wrong length");
        !           979:                if (trialKey->keyLength != kHFSPlusExtentKeyMaximumLength)
        !           980:                        DebugStr("\pHFS: trial Key is wrong length");
        !           981:        #endif
        !           982:        
        !           983:        result = -1;            //      assume searchKey < trialKey
        !           984:        
        !           985:        if (searchKey->fileID == trialKey->fileID) {
        !           986:                //
        !           987:                //      FileNum's are equal; compare fork types
        !           988:                //
        !           989:                if (searchKey->forkType == trialKey->forkType) {
        !           990:                        //
        !           991:                        //      Fork types are equal; compare allocation block number
        !           992:                        //
        !           993:                        if (searchKey->startBlock == trialKey->startBlock) {
        !           994:                                //
        !           995:                                //      Everything is equal
        !           996:                                //
        !           997:                                result = 0;
        !           998:                        }
        !           999:                        else {
        !          1000:                                //
        !          1001:                                //      Allocation block numbers differ; determine sign
        !          1002:                                //
        !          1003:                                if (searchKey->startBlock > trialKey->startBlock)
        !          1004:                                        result = 1;
        !          1005:                        }
        !          1006:                }
        !          1007:                else {
        !          1008:                        //
        !          1009:                        //      Fork types differ; determine sign
        !          1010:                        //
        !          1011:                        if (searchKey->forkType > trialKey->forkType)
        !          1012:                                result = 1;
        !          1013:                }
        !          1014:        }
        !          1015:        else {
        !          1016:                //
        !          1017:                //      FileNums differ; determine sign
        !          1018:                //
        !          1019:                if (searchKey->fileID > trialKey->fileID)
        !          1020:                        result = 1;
        !          1021:        }
        !          1022:        
        !          1023:        return( result );
        !          1024: }
        !          1025: 
        !          1026: 
        !          1027: 
        !          1028: //_________________________________________________________________________________
        !          1029: //
        !          1030: // Routine:            Extendfile
        !          1031: //
        !          1032: // Function:   Extends the disk space allocated to a file.
        !          1033: //
        !          1034: // Input:              A2.L  -  VCB pointer
        !          1035: //                             A1.L  -  pointer to FCB array
        !          1036: //                             D1.W  -  file refnum
        !          1037: //                             D3.B  -  option flags
        !          1038: //                                                     kEFContigMask - force contiguous allocation
        !          1039: //                                                     kEFAllMask - allocate all requested bytes or none
        !          1040: //                                                     NOTE: You may not set both options.
        !          1041: //                             D4.L  -  number of additional bytes to allocate
        !          1042: //
        !          1043: // Output:             D0.W  -  result code
        !          1044: //                                                      0 = ok
        !          1045: //                                                      -n = IO error
        !          1046: //                             D6.L  -  number of bytes allocated
        !          1047: //
        !          1048: // Called by:  FileAloc,FileWrite,SetEof
        !          1049: //
        !          1050: // Note:               ExtendFile updates the PEOF in the FCB.
        !          1051: //_________________________________________________________________________________
        !          1052: 
        !          1053: OSErr ExtendFileC (
        !          1054:        ExtendedVCB             *vcb,                           // volume that file resides on
        !          1055:        FCB                             *fcb,                           // FCB of file to truncate
        !          1056:        SInt64                  bytesToAdd,                     // number of bytes to allocate
        !          1057:        UInt32                  flags,                          // EFContig and/or EFAll
        !          1058:        SInt64                  *actualBytesAdded)      // number of bytes actually allocated
        !          1059: {
        !          1060:        OSErr                           err;
        !          1061:        UInt32                          volumeBlockSize;
        !          1062:        UInt32                          blocksToAdd;
        !          1063:        UInt32                          bytesThisExtent;
        !          1064:        HFSPlusExtentKey        foundKey;
        !          1065:        HFSPlusExtentRecord     foundData;
        !          1066:        UInt32                          foundIndex;
        !          1067:        UInt32                          hint;
        !          1068:        UInt32                          nextBlock;
        !          1069:        UInt32                          startBlock;
        !          1070:        Boolean                         allOrNothing;
        !          1071:        Boolean                         forceContig;
        !          1072:        Boolean                         wantContig;
        !          1073:        Boolean                         needsFlush;
        !          1074:        UInt32                          actualStartBlock;
        !          1075:        UInt32                          actualNumBlocks;
        !          1076:        UInt32                          numExtentsPerRecord;
        !          1077:        SInt64                          maximumBytes;
        !          1078:        SInt64                          peof;
        !          1079:        SInt64                          previousPEOF;
        !          1080:        
        !          1081: 
        !          1082: #if HFSInstrumentation
        !          1083:        InstTraceClassRef       trace;
        !          1084:        InstEventTag            eventTag;
        !          1085:        InstDataDescriptorRef   traceDescriptor;
        !          1086:        FSVarsRec                       *fsVars = (FSVarsRec *) LMGetFSMVars();
        !          1087: 
        !          1088:        traceDescriptor = (InstDataDescriptorRef) fsVars->later[2];
        !          1089:        
        !          1090:        err = InstCreateTraceClass(kInstRootClassRef, "HFS:Extents:ExtendFileC", 'hfs+', kInstEnableClassMask, &trace);
        !          1091:        if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
        !          1092: 
        !          1093:        eventTag = InstCreateEventTag();
        !          1094:        InstLogTraceEvent( trace, eventTag, kInstStartEvent);
        !          1095: #endif
        !          1096: 
        !          1097:        needsFlush = false;
        !          1098:        *actualBytesAdded = 0;
        !          1099:        volumeBlockSize = vcb->blockSize;
        !          1100:        allOrNothing = ((flags & kEFAllMask) != 0);
        !          1101:        forceContig = ((flags & kEFContigMask) != 0);
        !          1102:        previousPEOF = fcb->fcbPLen;
        !          1103: 
        !          1104:        if (vcb->vcbSigWord == kHFSPlusSigWord)
        !          1105:                numExtentsPerRecord = kHFSPlusExtentDensity;
        !          1106:        else
        !          1107:                numExtentsPerRecord = kHFSExtentDensity;
        !          1108: 
        !          1109:        //
        !          1110:        //      Make sure the request and new PEOF are less than 2GB if HFS.
        !          1111:        //
        !          1112:        if (vcb->vcbSigWord == kHFSSigWord) {
        !          1113:                if (bytesToAdd >=  kTwoGigabytes)
        !          1114:                        goto Overflow;
        !          1115:                if ((fcb->fcbPLen + bytesToAdd) >= kTwoGigabytes)
        !          1116:                        goto Overflow;
        !          1117:                }
        !          1118:        //
        !          1119:        //      Determine how many blocks need to be allocated.
        !          1120:        //      Round up the number of desired bytes to add.
        !          1121:        //
        !          1122:        blocksToAdd = FileBytesToBlocks(bytesToAdd, volumeBlockSize);
        !          1123:        bytesToAdd = (SInt64)(blocksToAdd * volumeBlockSize);
        !          1124:        
        !          1125:        //
        !          1126:        //      If the file's clump size is larger than the allocation block size,
        !          1127:        //      then set the maximum number of bytes to the requested number of bytes
        !          1128:        //      rounded up to a multiple of the clump size.
        !          1129:        //
        !          1130:        if (fcb->fcbClmpSize > volumeBlockSize) {
        !          1131:                maximumBytes = (SInt64)FileBytesToBlocks(bytesToAdd, fcb->fcbClmpSize);
        !          1132:                maximumBytes *= fcb->fcbClmpSize;
        !          1133:        }
        !          1134:        else {
        !          1135:                maximumBytes = bytesToAdd;
        !          1136:        }
        !          1137:        
        !          1138:        //
        !          1139:        //      Compute new physical EOF, rounded up to a multiple of a block.
        !          1140:        //
        !          1141:        if ((vcb->vcbSigWord == kHFSSigWord) && ((fcb->fcbPLen + bytesToAdd) >= (SInt64) kTwoGigabytes))        //      Too big?
        !          1142:                if (allOrNothing)                                       // Yes, must they have it all?
        !          1143:                        goto Overflow;                                          // Yes, can't have it
        !          1144:                else {
        !          1145:                        --blocksToAdd;                                          // No, give give 'em one block less
        !          1146:                        bytesToAdd -= volumeBlockSize;
        !          1147:                }
        !          1148: 
        !          1149:        //
        !          1150:        //      If allocation is all-or-nothing, make sure there are
        !          1151:        //      enough free blocks on the volume (quick test).
        !          1152:        //
        !          1153:        if (allOrNothing && blocksToAdd > vcb->freeBlocks) {
        !          1154:                err = dskFulErr;
        !          1155:                goto ErrorExit;
        !          1156:        }
        !          1157:        
        !          1158:        //
        !          1159:        //      See if there are already enough blocks allocated to the file.
        !          1160:        //
        !          1161:        peof = fcb->fcbPLen + bytesToAdd;                       // potential new PEOF
        !          1162:        err = SearchExtentFile(vcb, fcb, peof-1, &foundKey, foundData, &foundIndex, &hint, &nextBlock);
        !          1163:        if (err == noErr) {
        !          1164:                //      Enough blocks are already allocated.  Just update the FCB to reflect the new length.
        !          1165:                fcb->fcbPLen = peof;
        !          1166:                fcb->fcbFlags |= fcbModifiedMask;
        !          1167:                goto Exit;
        !          1168:        }
        !          1169:        if (err != fxRangeErr)          // Any real error?
        !          1170:                goto ErrorExit;                         // Yes, so exit immediately
        !          1171: 
        !          1172:        //
        !          1173:        //      Adjust the PEOF to the end of the last extent.
        !          1174:        //
        !          1175:        peof = (SInt64)(nextBlock * volumeBlockSize);                   // currently allocated PEOF
        !          1176:        bytesThisExtent = (UInt32)(peof - fcb->fcbPLen);
        !          1177:        if (bytesThisExtent != 0) {
        !          1178:                fcb->fcbPLen = peof;
        !          1179:                fcb->fcbFlags |= fcbModifiedMask;
        !          1180:                bytesToAdd -= bytesThisExtent;
        !          1181:        }
        !          1182:        
        !          1183:        //
        !          1184:        //      Allocate some more space.
        !          1185:        //
        !          1186:        //      First try a contiguous allocation (of the whole amount).
        !          1187:        //      If that fails, get whatever we can.
        !          1188:        //              If forceContig, then take whatever we got
        !          1189:        //              else, keep getting bits and pieces (non-contig)
        !          1190:        err = noErr;
        !          1191:        wantContig = true;
        !          1192:        do {
        !          1193:                startBlock = foundData[foundIndex].startBlock + foundData[foundIndex].blockCount;
        !          1194:                err = BlockAllocate(vcb, startBlock, bytesToAdd, maximumBytes, wantContig, &actualStartBlock, &actualNumBlocks);
        !          1195:                if (err == dskFulErr) {
        !          1196:                        if (forceContig)
        !          1197:                                break;                  // AllocContig failed because not enough contiguous space
        !          1198:                        if (wantContig) {
        !          1199:                                //      Couldn't get one big chunk, so get whatever we can.
        !          1200:                                err = noErr;
        !          1201:                                wantContig = false;
        !          1202:                                continue;
        !          1203:                        }
        !          1204:                        if (actualNumBlocks != 0)
        !          1205:                                err = noErr;
        !          1206:                }
        !          1207:                if (err == noErr) {
        !          1208: #if HFSInstrumentation
        !          1209:                        {
        !          1210:                                struct {
        !          1211:                                        UInt32  fileID;
        !          1212:                                        UInt32  start;
        !          1213:                                        UInt32  count;
        !          1214:                                        UInt32  fabn;
        !          1215:                                } x;
        !          1216:                                
        !          1217:                                x.fileID = H_FILEID(fcb);
        !          1218:                                x.start = actualStartBlock;
        !          1219:                                x.count = actualNumBlocks;
        !          1220:                                x.fabn = nextBlock;
        !          1221:                                
        !          1222:                                InstLogTraceEventWithDataStructure( trace, eventTag, kInstMiddleEvent, traceDescriptor,
        !          1223:                                                                                                        (UInt8 *) &x, sizeof(x));
        !          1224:                        }
        !          1225: #endif
        !          1226:                        //      Add the new extent to the existing extent record, or create a new one.
        !          1227:                        if (actualStartBlock == startBlock) {
        !          1228:                                //      We grew the file's last extent, so just adjust the number of blocks.
        !          1229:                                foundData[foundIndex].blockCount += actualNumBlocks;
        !          1230:                                err = UpdateExtentRecord(vcb, fcb, &foundKey, foundData, hint);
        !          1231:                                if (err != noErr) break;
        !          1232:                        }
        !          1233:                        else {
        !          1234:                                UInt16  i;
        !          1235: 
        !          1236:                                //      Need to add a new extent.  See if there is room in the current record.
        !          1237:                                if (foundData[foundIndex].blockCount != 0)      //      Is current extent free to use?
        !          1238:                                        ++foundIndex;                                                   //      No, so use the next one.
        !          1239:                                if (foundIndex == numExtentsPerRecord) {
        !          1240:                                        //      This record is full.  Need to create a new one.
        !          1241:                                        if (H_FILEID(fcb) == kHFSExtentsFileID) {
        !          1242:                                                err = fxOvFlErr;                // Oops.  Can't extend extents file (?? really ??)
        !          1243:                                                break;
        !          1244:                                        }
        !          1245:                                        
        !          1246:                                        foundKey.keyLength = kHFSPlusExtentKeyMaximumLength;
        !          1247:                                        if (fcb->fcbFlags & fcbResourceMask)
        !          1248:                                                foundKey.forkType = kResourceForkType;
        !          1249:                                        else
        !          1250:                                                foundKey.forkType = kDataForkType;
        !          1251:                                        foundKey.pad = 0;
        !          1252:                                        foundKey.fileID = H_FILEID(fcb);
        !          1253:                                        foundKey.startBlock = nextBlock;
        !          1254:                                        
        !          1255:                                        foundData[0].startBlock = actualStartBlock;
        !          1256:                                        foundData[0].blockCount = actualNumBlocks;
        !          1257:                                        
        !          1258:                                        // zero out remaining extents...
        !          1259:                                        for (i = 1; i < kHFSPlusExtentDensity; ++i)
        !          1260:                                        {
        !          1261:                                                foundData[i].startBlock = 0;
        !          1262:                                                foundData[i].blockCount = 0;
        !          1263:                                        }
        !          1264: 
        !          1265:                                        foundIndex = 0;
        !          1266:                                        
        !          1267:                                        err = CreateExtentRecord(vcb, &foundKey, foundData, &hint);
        !          1268:                                        if (err == fxOvFlErr) {
        !          1269:                                                //      We couldn't create an extent record because extents B-tree
        !          1270:                                                //      couldn't grow.  Dellocate the extent just allocated and
        !          1271:                                                //      return a disk full error.
        !          1272:                                                (void) BlockDeallocate(vcb, actualStartBlock, actualNumBlocks);
        !          1273:                                                err = dskFulErr;
        !          1274:                                        }
        !          1275:                                        if (err != noErr) break;
        !          1276: 
        !          1277:                                        needsFlush = true;              //      We need to update the B-tree header
        !          1278:                                }
        !          1279:                                else {
        !          1280:                                        //      Add a new extent into this record and update.
        !          1281:                                        foundData[foundIndex].startBlock = actualStartBlock;
        !          1282:                                        foundData[foundIndex].blockCount = actualNumBlocks;
        !          1283:                                        err = UpdateExtentRecord(vcb, fcb, &foundKey, foundData, hint);
        !          1284:                                        if (err != noErr) break;
        !          1285:                                }
        !          1286:                        }
        !          1287:                        
        !          1288:                        // Figure out how many bytes were actually allocated.
        !          1289:                        // NOTE: BlockAllocate could have allocated more than we asked for.
        !          1290:                        // Don't set the PEOF beyond what our client asked for.
        !          1291:                        nextBlock += actualNumBlocks;
        !          1292:                        bytesThisExtent = actualNumBlocks * volumeBlockSize;
        !          1293:                        if (bytesThisExtent > bytesToAdd) {
        !          1294:                                bytesToAdd = 0;
        !          1295:                        }
        !          1296:                        else {
        !          1297:                                bytesToAdd -= bytesThisExtent;
        !          1298:                                maximumBytes -= bytesThisExtent;
        !          1299:                        }
        !          1300:             fcb->fcbPLen += bytesThisExtent;
        !          1301:                        fcb->fcbFlags |= fcbModifiedMask;
        !          1302: 
        !          1303:                        //      If contiguous allocation was requested, then we've already got one contiguous
        !          1304:                        //      chunk.  If we didn't get all we wanted, then adjust the error to disk full.
        !          1305:                        if (forceContig) {
        !          1306:                                if (bytesToAdd != 0)
        !          1307:                                        err = dskFulErr;
        !          1308:                                break;                  //      We've already got everything that's contiguous
        !          1309:                        }
        !          1310:                }
        !          1311:        } while (err == noErr && bytesToAdd);
        !          1312: 
        !          1313: ErrorExit:
        !          1314: Exit:
        !          1315:        *actualBytesAdded = fcb->fcbPLen - previousPEOF;
        !          1316: 
        !          1317:        if (needsFlush)
        !          1318:                (void) FlushExtentFile(vcb);
        !          1319: 
        !          1320: #if HFSInstrumentation
        !          1321:        InstLogTraceEvent( trace, eventTag, kInstEndEvent);
        !          1322: #endif
        !          1323: 
        !          1324:        return err;
        !          1325: 
        !          1326: Overflow:
        !          1327:        err = fileBoundsErr;
        !          1328:        goto ErrorExit;
        !          1329: }
        !          1330: 
        !          1331: 
        !          1332: 
        !          1333: //_________________________________________________________________________________
        !          1334: //
        !          1335: // Routine:            TruncateFileC
        !          1336: //
        !          1337: // Function:   Truncates the disk space allocated to a file.  The file space is
        !          1338: //                             truncated to a specified new PEOF rounded up to the next allocation
        !          1339: //                             block boundry.  If the 'TFTrunExt' option is specified, the file is
        !          1340: //                             truncated to the end of the extent containing the new PEOF.
        !          1341: //
        !          1342: // Input:              A2.L  -  VCB pointer
        !          1343: //                             A1.L  -  pointer to FCB array
        !          1344: //                             D1.W  -  file refnum
        !          1345: //                             D2.B  -  option flags
        !          1346: //                                                TFTrunExt - truncate to the extent containing new PEOF
        !          1347: //                             D3.L  -  new PEOF
        !          1348: //
        !          1349: // Output:             D0.W  -  result code
        !          1350: //                                                      0 = ok
        !          1351: //                                                      -n = IO error
        !          1352: //
        !          1353: // Note:               TruncateFile updates the PEOF in the FCB.
        !          1354: //_________________________________________________________________________________
        !          1355: 
        !          1356: OSErr TruncateFileC (
        !          1357:        ExtendedVCB             *vcb,                           // volume that file resides on
        !          1358:        FCB                             *fcb,                           // FCB of file to truncate
        !          1359:        SInt64                  peof,                           // new physical size for file
        !          1360:        Boolean                 truncateToExtent)       // if true, truncate to end of extent containing newPEOF
        !          1361: {
        !          1362:        OSErr                           err;
        !          1363:        UInt32                          nextBlock;              //      next file allocation block to consider
        !          1364:        UInt32                          startBlock;             //      Physical (volume) allocation block number of start of a range
        !          1365:        UInt32                          physNumBlocks;  //      Number of allocation blocks in file (according to PEOF)
        !          1366:        UInt32                          numBlocks;
        !          1367:        HFSPlusExtentKey        key;                    //      key for current extent record; key->keyLength == 0 if FCB's extent record
        !          1368:        UInt32                          hint;                   //      BTree hint corresponding to key
        !          1369:        HFSPlusExtentRecord     extentRecord;
        !          1370:        UInt32                          extentIndex;
        !          1371:        UInt32                          extentNextBlock;
        !          1372:        UInt32                          numExtentsPerRecord;
        !          1373:        UInt8                           forkType;
        !          1374:        Boolean                         extentChanged;  // true if we actually changed an extent
        !          1375:        Boolean                         recordDeleted;  // true if an extent record got deleted
        !          1376:        
        !          1377: #if HFSInstrumentation
        !          1378:        InstTraceClassRef       trace;
        !          1379:        InstEventTag            eventTag;
        !          1380:        InstDataDescriptorRef   traceDescriptor;
        !          1381:        FSVarsRec                       *fsVars = (FSVarsRec *) LMGetFSMVars();
        !          1382: 
        !          1383:        traceDescriptor = (InstDataDescriptorRef) fsVars->later[2];
        !          1384:        
        !          1385:        err = InstCreateTraceClass(kInstRootClassRef, "HFS:Extents:TruncateFileC", 'hfs+', kInstEnableClassMask, &trace);
        !          1386:        if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
        !          1387: 
        !          1388:        eventTag = InstCreateEventTag();
        !          1389:        InstLogTraceEvent( trace, eventTag, kInstStartEvent);
        !          1390: #endif
        !          1391: 
        !          1392:        recordDeleted = false;
        !          1393:        
        !          1394:        if (vcb->vcbSigWord == kHFSPlusSigWord)
        !          1395:                numExtentsPerRecord = kHFSPlusExtentDensity;
        !          1396:        else
        !          1397:                numExtentsPerRecord = kHFSExtentDensity;
        !          1398: 
        !          1399:        if (fcb->fcbFlags & fcbResourceMask)
        !          1400:                forkType = kResourceForkType;
        !          1401:        else
        !          1402:                forkType = kDataForkType;
        !          1403: 
        !          1404:        physNumBlocks = fcb->fcbPLen / vcb->blockSize;          // number of allocation blocks currently in file
        !          1405: 
        !          1406:        //
        !          1407:        //      Round newPEOF up to a multiple of the allocation block size.  If new size is
        !          1408:        //      two gigabytes or more, then round down by one allocation block (??? really?
        !          1409:        //      shouldn't that be an error?).
        !          1410:        //
        !          1411:        nextBlock = FileBytesToBlocks(peof, vcb->blockSize);    // number of allocation blocks to remain in file
        !          1412:        peof = (SInt64)(nextBlock * vcb->blockSize);                                    // number of bytes in those blocks
        !          1413:        if ((vcb->vcbSigWord == kHFSSigWord) && (peof >= (UInt32) kTwoGigabytes)) {
        !          1414:                #if DEBUG_BUILD
        !          1415:                        DebugStr("\pHFS: Trying to truncate a file to 2GB or more");
        !          1416:                #endif
        !          1417:                err = fileBoundsErr;
        !          1418:                goto ErrorExit;
        !          1419:        }
        !          1420: 
        !          1421:        //
        !          1422:        //      Update FCB's length
        !          1423:        //
        !          1424:        fcb->fcbPLen = peof;
        !          1425:        fcb->fcbFlags |= fcbModifiedMask;
        !          1426:        
        !          1427:        //
        !          1428:        //      If the new PEOF is 0, then truncateToExtent has no meaning (we should always deallocate
        !          1429:        //      all storage).
        !          1430:        //
        !          1431:        if (peof == 0) {
        !          1432:                int i;
        !          1433:                
        !          1434:                //      Deallocate all the extents for this fork
        !          1435:                err = DeallocateFork(vcb, H_FILEID(fcb), forkType, fcb->fcbExtents, &recordDeleted);
        !          1436:                if (err != noErr) goto ErrorExit;       //      got some error, so return it
        !          1437:                
        !          1438:                //      Update the catalog extent record (making sure it's zeroed out)
        !          1439:                if (err == noErr) {
        !          1440:                        for (i=0; i < kHFSPlusExtentDensity; i++) {
        !          1441:                                fcb->fcbExtents[i].startBlock = 0;
        !          1442:                                fcb->fcbExtents[i].blockCount = 0;
        !          1443:                        }
        !          1444:                }
        !          1445:                goto Done;
        !          1446:        }
        !          1447:        
        !          1448:        //
        !          1449:        //      Find the extent containing byte (peof-1).  This is the last extent we'll keep.
        !          1450:        //      (If truncateToExtent is true, we'll keep the whole extent; otherwise, we'll only
        !          1451:        //      keep up through peof).  The search will tell us how many allocation blocks exist
        !          1452:        //      in the found extent plus all previous extents.
        !          1453:        //
        !          1454:        err = SearchExtentFile(vcb, fcb, peof-1, &key, extentRecord, &extentIndex, &hint, &extentNextBlock);
        !          1455:        if (err != noErr) goto ErrorExit;
        !          1456: 
        !          1457:        extentChanged = false;          //      haven't changed the extent yet
        !          1458:        
        !          1459:        if (!truncateToExtent) {
        !          1460:                //
        !          1461:                //      Shorten this extent.  It may be the case that the entire extent gets
        !          1462:                //      freed here.
        !          1463:                //
        !          1464:                numBlocks = extentNextBlock - nextBlock;        //      How many blocks in this extent to free up
        !          1465:                if (numBlocks != 0) {
        !          1466:                        //      Compute first volume allocation block to free
        !          1467:                        startBlock = extentRecord[extentIndex].startBlock + extentRecord[extentIndex].blockCount - numBlocks;
        !          1468:                        //      Free the blocks in bitmap
        !          1469:                        err = BlockDeallocate(vcb, startBlock, numBlocks);
        !          1470:                        if (err != noErr) goto ErrorExit;
        !          1471:                        //      Adjust length of this extent
        !          1472:                        extentRecord[extentIndex].blockCount -= numBlocks;
        !          1473:                        //      If extent is empty, set start block to 0
        !          1474:                        if (extentRecord[extentIndex].blockCount == 0)
        !          1475:                                extentRecord[extentIndex].startBlock = 0;
        !          1476:                        //      Remember that we changed the extent record
        !          1477:                        extentChanged = true;
        !          1478:                }
        !          1479:        }
        !          1480:        
        !          1481:        //
        !          1482:        //      Now move to the next extent in the record, and set up the file allocation block number
        !          1483:        //
        !          1484:        nextBlock = extentNextBlock;            //      Next file allocation block to free
        !          1485:        ++extentIndex;                                          //      Its index within the extent record
        !          1486:        
        !          1487:        //
        !          1488:        //      Release all following extents in this extent record.  Update the record.
        !          1489:        //
        !          1490:        while (extentIndex < numExtentsPerRecord && extentRecord[extentIndex].blockCount != 0) {
        !          1491:                numBlocks = extentRecord[extentIndex].blockCount;
        !          1492:                //      Deallocate this extent
        !          1493:                err = BlockDeallocate(vcb, extentRecord[extentIndex].startBlock, numBlocks);
        !          1494:                if (err != noErr) goto ErrorExit;
        !          1495:                //      Update next file allocation block number
        !          1496:                nextBlock += numBlocks;
        !          1497:                //      Zero out start and length of this extent to delete it from record
        !          1498:                extentRecord[extentIndex].startBlock = 0;
        !          1499:                extentRecord[extentIndex].blockCount = 0;
        !          1500:                //      Remember that we changed an extent
        !          1501:                extentChanged = true;
        !          1502:                //      Move to next extent in record
        !          1503:                ++extentIndex;
        !          1504:        }
        !          1505:        
        !          1506:        //
        !          1507:        //      If any of the extents in the current record were changed, then update that
        !          1508:        //      record (in the FCB, or extents file).
        !          1509:        //
        !          1510:        if (extentChanged) {
        !          1511:                err = UpdateExtentRecord(vcb, fcb, &key, extentRecord, hint);
        !          1512:                if (err != noErr) goto ErrorExit;
        !          1513:        }
        !          1514:        
        !          1515:        //
        !          1516:        //      If there are any following allocation blocks, then we need
        !          1517:        //      to seach for their extent records and delete those allocation
        !          1518:        //      blocks.
        !          1519:        //
        !          1520:        if (nextBlock < physNumBlocks)
        !          1521:                err = TruncateExtents(vcb, forkType, H_FILEID(fcb), nextBlock, &recordDeleted);
        !          1522: 
        !          1523: Done:
        !          1524: ErrorExit:
        !          1525: 
        !          1526:        if (recordDeleted)
        !          1527:                (void) FlushExtentFile(vcb);
        !          1528: 
        !          1529: #if HFSInstrumentation
        !          1530:        InstLogTraceEvent( trace, eventTag, kInstEndEvent);
        !          1531: #endif
        !          1532: 
        !          1533:        return err;
        !          1534: }
        !          1535: 
        !          1536: 
        !          1537: 
        !          1538: //�������������������������������������������������������������������������������
        !          1539: //     Routine:        SearchExtentRecord (was XRSearch)
        !          1540: //
        !          1541: //     Function:       Searches extent record for the extent mapping a given file
        !          1542: //                             allocation block number (FABN).
        !          1543: //
        !          1544: //     Input:          searchFABN                      -  desired FABN
        !          1545: //                             extentData                      -  pointer to extent data record (xdr)
        !          1546: //                             extentDataStartFABN     -  beginning FABN for extent record
        !          1547: //
        !          1548: //     Output:         foundExtentDataOffset  -  offset to extent entry within xdr
        !          1549: //                                                     result = noErr, offset to extent mapping desired FABN
        !          1550: //                                                     result = FXRangeErr, offset to last extent in record
        !          1551: //                             endingFABNPlusOne       -  ending FABN +1
        !          1552: //                             noMoreExtents           - True if the extent was not found, and the
        !          1553: //                                                                       extent record was not full (so don't bother
        !          1554: //                                                                       looking in subsequent records); false otherwise.
        !          1555: //
        !          1556: //     Result:         noErr = ok
        !          1557: //                             FXRangeErr = desired FABN > last mapped FABN in record
        !          1558: //�������������������������������������������������������������������������������
        !          1559: 
        !          1560: static OSErr SearchExtentRecord(
        !          1561:        const ExtendedVCB               *vcb,
        !          1562:        UInt32                                  searchFABN,
        !          1563:        const HFSPlusExtentRecord       extentData,
        !          1564:        UInt32                                  extentDataStartFABN,
        !          1565:        UInt32                                  *foundExtentIndex,
        !          1566:        UInt32                                  *endingFABNPlusOne,
        !          1567:        Boolean                                 *noMoreExtents)
        !          1568: {
        !          1569:        OSErr   err = noErr;
        !          1570:        UInt32  extentIndex;
        !          1571:        UInt32  numberOfExtents;
        !          1572:        UInt32  numAllocationBlocks;
        !          1573:        Boolean foundExtent;
        !          1574:        
        !          1575:        *endingFABNPlusOne      = extentDataStartFABN;
        !          1576:        *noMoreExtents          = false;
        !          1577:        foundExtent                     = false;
        !          1578: 
        !          1579:        if (vcb->vcbSigWord == kHFSPlusSigWord)
        !          1580:                numberOfExtents = kHFSPlusExtentDensity;
        !          1581:        else
        !          1582:                numberOfExtents = kHFSExtentDensity;
        !          1583:        
        !          1584:        for( extentIndex = 0; extentIndex < numberOfExtents; ++extentIndex )
        !          1585:        {
        !          1586:                
        !          1587:                // Loop over the extent record and find the search FABN.
        !          1588:                
        !          1589:                numAllocationBlocks = extentData[extentIndex].blockCount;
        !          1590:                if ( numAllocationBlocks == 0 )
        !          1591:                {
        !          1592:                        break;
        !          1593:                }
        !          1594: 
        !          1595:                *endingFABNPlusOne += numAllocationBlocks;
        !          1596:                
        !          1597:                if( searchFABN < *endingFABNPlusOne )
        !          1598:                {
        !          1599:                        // Found the extent.
        !          1600:                        foundExtent = true;
        !          1601:                        break;
        !          1602:                }
        !          1603:        }
        !          1604:        
        !          1605:        if( foundExtent )
        !          1606:        {
        !          1607:                // Found the extent. Note the extent offset
        !          1608:                *foundExtentIndex = extentIndex;
        !          1609:        }
        !          1610:        else
        !          1611:        {
        !          1612:                // Did not find the extent. Set foundExtentDataOffset accordingly
        !          1613:                if( extentIndex > 0 )
        !          1614:                {
        !          1615:                        *foundExtentIndex = extentIndex - 1;
        !          1616:                }
        !          1617:                else
        !          1618:                {
        !          1619:                        *foundExtentIndex = 0;
        !          1620:                }
        !          1621:                
        !          1622:                // If we found an empty extent, then set noMoreExtents.
        !          1623:                if (extentIndex < numberOfExtents)
        !          1624:                        *noMoreExtents = true;
        !          1625: 
        !          1626:                // Finally, return an error to the caller
        !          1627:                err = fxRangeErr;
        !          1628:        }
        !          1629: 
        !          1630:        return( err );
        !          1631: }
        !          1632: 
        !          1633: //�������������������������������������������������������������������������������
        !          1634: //     Routine:        SearchExtentFile (was XFSearch)
        !          1635: //
        !          1636: //     Function:       Searches extent file (including the FCB resident extent record)
        !          1637: //                             for the extent mapping a given file position.
        !          1638: //
        !          1639: //     Input:          vcb                     -  VCB pointer
        !          1640: //                             fcb                     -  FCB pointer
        !          1641: //                             filePosition    -  file position (byte address)
        !          1642: //
        !          1643: // Output:             foundExtentKey                  -  extent key record (xkr)
        !          1644: //                                                     If extent was found in the FCB's resident extent record,
        !          1645: //                                                     then foundExtentKey->keyLength will be set to 0.
        !          1646: //                             foundExtentData                 -  extent data record(xdr)
        !          1647: //                             foundExtentIndex        -  index to extent entry in xdr
        !          1648: //                                                     result =  0, offset to extent mapping desired FABN
        !          1649: //                                                     result = FXRangeErr, offset to last extent in record
        !          1650: //                                                                      (i.e., kNumExtentsPerRecord-1)
        !          1651: //                             extentBTreeHint                 -  BTree hint for extent record
        !          1652: //                                                     kNoHint = Resident extent record
        !          1653: //                             endingFABNPlusOne               -  ending FABN +1
        !          1654: //
        !          1655: //     Result:
        !          1656: //             noErr                   Found an extent that contains the given file position
        !          1657: //             FXRangeErr              Given position is beyond the last allocated extent
        !          1658: //             (other)                 (some other internal I/O error)
        !          1659: //�������������������������������������������������������������������������������
        !          1660: 
        !          1661: static OSErr SearchExtentFile(
        !          1662:        const ExtendedVCB       *vcb,
        !          1663:        const FCB                       *fcb,
        !          1664:        SInt64                          filePosition,
        !          1665:        HFSPlusExtentKey        *foundExtentKey,
        !          1666:        HFSPlusExtentRecord     foundExtentData,
        !          1667:        UInt32                          *foundExtentIndex,
        !          1668:        UInt32                          *extentBTreeHint,
        !          1669:        UInt32                          *endingFABNPlusOne )
        !          1670: {
        !          1671:        OSErr                           err;
        !          1672:        UInt32                          filePositionBlock;
        !          1673:        Boolean                         noMoreExtents;
        !          1674:        
        !          1675:        filePositionBlock = filePosition / vcb->blockSize;
        !          1676:     bcopy ( fcb->fcbExtents, foundExtentData, sizeof(HFSPlusExtentRecord));
        !          1677:        
        !          1678:        //      Search the resident FCB first.
        !          1679:     err = SearchExtentRecord( vcb, filePositionBlock, foundExtentData, 0,
        !          1680:                                                                        foundExtentIndex, endingFABNPlusOne, &noMoreExtents );
        !          1681: 
        !          1682:        if( err == noErr ) {
        !          1683:                // Found the extent. Set results accordingly
        !          1684:                *extentBTreeHint = kNoHint;                     // no hint, because not in the BTree
        !          1685:                foundExtentKey->keyLength = 0;          // 0 = the FCB itself
        !          1686:                
        !          1687:                goto Exit;
        !          1688:        }
        !          1689:        
        !          1690:        //      Didn't find extent in FCB.  If FCB's extent record wasn't full, there's no point
        !          1691:        //      in searching the extents file.  Note that SearchExtentRecord left us pointing at
        !          1692:        //      the last valid extent (or the first one, if none were valid).  This means we need
        !          1693:        //      to fill in the hint and key outputs, just like the "if" statement above.
        !          1694:        if ( noMoreExtents ) {
        !          1695:                *extentBTreeHint = kNoHint;                     // no hint, because not in the BTree
        !          1696:                foundExtentKey->keyLength = 0;          // 0 = the FCB itself
        !          1697:                err = fxRangeErr;               // There are no more extents, so must be beyond PEOF
        !          1698:                goto Exit;
        !          1699:        }
        !          1700:        
        !          1701:        //
        !          1702:        //      Find the desired record, or the previous record if it is the same fork
        !          1703:        //
        !          1704:        err = FindExtentRecord(vcb, (fcb->fcbFlags & fcbResourceMask) ? kResourceForkType : kDataForkType,
        !          1705:                                                   H_FILEID(fcb), filePositionBlock, true, foundExtentKey, foundExtentData, extentBTreeHint);
        !          1706: 
        !          1707:        if (err == btNotFound) {
        !          1708:                //
        !          1709:                //      If we get here, the desired position is beyond the extents in the FCB, and there are no extents
        !          1710:                //      in the extents file.  Return the FCB's extents and a range error.
        !          1711:                //
        !          1712:                *extentBTreeHint = kNoHint;
        !          1713:                foundExtentKey->keyLength = 0;
        !          1714:                err = GetFCBExtentRecord(fcb, foundExtentData);
        !          1715:                //      Note: foundExtentIndex and endingFABNPlusOne have already been set as a result of the very
        !          1716:                //      first SearchExtentRecord call in this function (when searching in the FCB's extents, and
        !          1717:                //      we got a range error).
        !          1718:                
        !          1719:                return fxRangeErr;
        !          1720:        }
        !          1721:        
        !          1722:        //
        !          1723:        //      If we get here, there was either a BTree error, or we found an appropriate record.
        !          1724:        //      If we found a record, then search it for the correct index into the extents.
        !          1725:        //
        !          1726:        if (err == noErr) {
        !          1727:                //      Find appropriate index into extent record
        !          1728:                err = SearchExtentRecord(vcb, filePositionBlock, foundExtentData, foundExtentKey->startBlock,
        !          1729:                                                                 foundExtentIndex, endingFABNPlusOne, &noMoreExtents);
        !          1730:        }
        !          1731: 
        !          1732: Exit:
        !          1733:        return err;
        !          1734: }
        !          1735: 
        !          1736: 
        !          1737: 
        !          1738: //�������������������������������������������������������������������������������
        !          1739: //     Routine:        UpdateExtentRecord
        !          1740: //
        !          1741: //     Function:       Write new extent data to an existing extent record with a given key.
        !          1742: //                             If all of the extents are empty, and the extent record is in the
        !          1743: //                             extents file, then the record is deleted.
        !          1744: //
        !          1745: //     Input:          vcb                                             -       the volume containing the extents
        !          1746: //                             fcb                                             -       the file that owns the extents
        !          1747: //                             extentFileKey                   -       pointer to extent key record (xkr)
        !          1748: //                                             If the key length is 0, then the extents are actually part
        !          1749: //                                             of the catalog record, stored in the FCB.
        !          1750: //                             extentData                      -       pointer to extent data record (xdr)
        !          1751: //                             extentBTreeHint                 -       hint for given key, or kNoHint
        !          1752: //
        !          1753: //     Result:         noErr = ok
        !          1754: //                             (other) = error from BTree
        !          1755: //�������������������������������������������������������������������������������
        !          1756: 
        !          1757: static OSErr UpdateExtentRecord (
        !          1758:        const ExtendedVCB               *vcb,
        !          1759:        FCB                                             *fcb,
        !          1760:        const HFSPlusExtentKey  *extentFileKey,
        !          1761:        const HFSPlusExtentRecord       extentData,
        !          1762:        UInt32                                  extentBTreeHint)
        !          1763: {
        !          1764:        BTreeIterator           btIterator;
        !          1765:        FSBufferDescriptor      btRecord;
        !          1766:        UInt16                          btRecordSize;
        !          1767:        FCB *                           btFCB;
        !          1768:     OSErr                              err = noErr;
        !          1769:        
        !          1770:        if (extentFileKey->keyLength == 0) {    // keyLength == 0 means the FCB's extent record
        !          1771:                BlockMoveData(extentData, fcb->fcbExtents, sizeof(HFSPlusExtentRecord));
        !          1772:                fcb->fcbFlags |= fcbModifiedMask;
        !          1773:        }
        !          1774:        else {
        !          1775:                //
        !          1776:                //      Need to find and change a record in Extents BTree
        !          1777:                //
        !          1778:                btFCB = GetFileControlBlock(vcb->extentsRefNum);
        !          1779: 
        !          1780:                if (vcb->vcbSigWord == kHFSSigWord) {
        !          1781:                        HFSExtentKey *  key;                            // Actual extent key used on disk in HFS
        !          1782:                        HFSExtentRecord foundData;                      // The extent data actually found
        !          1783: 
        !          1784:                        key = (HFSExtentKey*) &btIterator.key;
        !          1785:                        key->keyLength  = kHFSExtentKeyMaximumLength;
        !          1786:                        key->forkType   = extentFileKey->forkType;
        !          1787:                        key->fileID             = extentFileKey->fileID;
        !          1788:                        key->startBlock = extentFileKey->startBlock;
        !          1789: 
        !          1790:                        btIterator.hint.index = 0;
        !          1791:                        btIterator.hint.nodeNum = extentBTreeHint;
        !          1792: 
        !          1793:                        btRecord.bufferAddress = &foundData;
        !          1794:                        btRecord.itemSize = sizeof(HFSExtentRecord);
        !          1795:                        btRecord.itemCount = 1;
        !          1796: 
        !          1797:                        err = BTSearchRecord(btFCB, &btIterator, kInvalidMRUCacheKey, &btRecord,
        !          1798:                                                                 &btRecordSize, &btIterator);
        !          1799:                        
        !          1800:                        if (err == noErr)
        !          1801:                                err = HFSPlusToHFSExtents(extentData, (HFSExtentDescriptor *)&foundData);
        !          1802: 
        !          1803:                        if (err == noErr)
        !          1804:                                err = BTReplaceRecord(btFCB, &btIterator, &btRecord, btRecordSize);
        !          1805:                }
        !          1806:                else {          //      HFS Plus volume
        !          1807:                        HFSPlusExtentRecord     foundData;              // The extent data actually found
        !          1808: 
        !          1809:                        BlockMoveData(extentFileKey, &btIterator.key, sizeof(HFSPlusExtentKey));
        !          1810: 
        !          1811:                        btIterator.hint.index = 0;
        !          1812:                        btIterator.hint.nodeNum = extentBTreeHint;
        !          1813: 
        !          1814:                        btRecord.bufferAddress = &foundData;
        !          1815:                        btRecord.itemSize = sizeof(HFSPlusExtentRecord);
        !          1816:                        btRecord.itemCount = 1;
        !          1817: 
        !          1818:                        err = BTSearchRecord(btFCB, &btIterator, kInvalidMRUCacheKey, &btRecord,
        !          1819:                                                                 &btRecordSize, &btIterator);
        !          1820:        
        !          1821:                        if (err == noErr) {
        !          1822:                                BlockMoveData(extentData, &foundData, sizeof(HFSPlusExtentRecord));
        !          1823:                                err = BTReplaceRecord(btFCB, &btIterator, &btRecord, btRecordSize);
        !          1824:                        }
        !          1825:                }
        !          1826:        }
        !          1827:        
        !          1828:        return err;
        !          1829: }
        !          1830: 
        !          1831: 
        !          1832: 
        !          1833: void HFSToHFSPlusExtents(
        !          1834:        const HFSExtentRecord   oldExtents,
        !          1835:        HFSPlusExtentRecord             newExtents)
        !          1836: {
        !          1837:        UInt32  i;
        !          1838: 
        !          1839:        // copy the first 3 extents
        !          1840:        newExtents[0].startBlock = oldExtents[0].startBlock;
        !          1841:        newExtents[0].blockCount = oldExtents[0].blockCount;
        !          1842:        newExtents[1].startBlock = oldExtents[1].startBlock;
        !          1843:        newExtents[1].blockCount = oldExtents[1].blockCount;
        !          1844:        newExtents[2].startBlock = oldExtents[2].startBlock;
        !          1845:        newExtents[2].blockCount = oldExtents[2].blockCount;
        !          1846: 
        !          1847:        // zero out the remaining ones
        !          1848:        for (i = 3; i < kHFSPlusExtentDensity; ++i)
        !          1849:        {
        !          1850:                newExtents[i].startBlock = 0;
        !          1851:                newExtents[i].blockCount = 0;
        !          1852:        }
        !          1853: }
        !          1854: 
        !          1855: 
        !          1856: 
        !          1857: OSErr HFSPlusToHFSExtents(
        !          1858:        const HFSPlusExtentRecord       oldExtents,
        !          1859:        HFSExtentRecord         newExtents)
        !          1860: {
        !          1861:        OSErr   err;
        !          1862:        
        !          1863:        err = noErr;
        !          1864: 
        !          1865:        // copy the first 3 extents
        !          1866:        newExtents[0].startBlock = oldExtents[0].startBlock;
        !          1867:        newExtents[0].blockCount = oldExtents[0].blockCount;
        !          1868:        newExtents[1].startBlock = oldExtents[1].startBlock;
        !          1869:        newExtents[1].blockCount = oldExtents[1].blockCount;
        !          1870:        newExtents[2].startBlock = oldExtents[2].startBlock;
        !          1871:        newExtents[2].blockCount = oldExtents[2].blockCount;
        !          1872: 
        !          1873:        #if DEBUG_BUILD
        !          1874:                if (oldExtents[3].startBlock || oldExtents[3].blockCount) {
        !          1875:                        DebugStr("\pExtentRecord with > 3 extents is invalid for HFS");
        !          1876:                        err = fsDSIntErr;
        !          1877:                }
        !          1878:        #endif
        !          1879:        
        !          1880:        return err;
        !          1881: }
        !          1882: 
        !          1883: 
        !          1884: 
        !          1885: 
        !          1886: OSErr GetFCBExtentRecord(
        !          1887:        const FCB                       *fcb,
        !          1888:        HFSPlusExtentRecord     extents)
        !          1889: {
        !          1890:        
        !          1891:        BlockMoveData(fcb->fcbExtents, extents, sizeof(HFSPlusExtentRecord));
        !          1892:        
        !          1893:        return noErr;
        !          1894: }
        !          1895: 
        !          1896: 
        !          1897: 
        !          1898: //�������������������������������������������������������������������������������
        !          1899: //     Routine:        MapFileBlockFromFCB
        !          1900: //
        !          1901: //     Function:       Determine if the given file offset is within the set of extents
        !          1902: //                             stored in the FCB.  If so, return the file allocation
        !          1903: //                             block number of the start of the extent, volume allocation block number
        !          1904: //                             of the start of the extent, and file allocation block number immediately
        !          1905: //                             following the extent.
        !          1906: //
        !          1907: //     Input:          vcb                                             -       the volume containing the extents
        !          1908: //                             fcb                                             -       the file that owns the extents
        !          1909: //                             offset                                  -       desired offset in bytes
        !          1910: //
        !          1911: //     Output:         firstFABN                               -       file alloc block number of start of extent
        !          1912: //                             firstBlock                              -       volume alloc block number of start of extent
        !          1913: //                             nextFABN                                -       file alloc block number of next extent
        !          1914: //
        !          1915: //     Result:         noErr           = ok
        !          1916: //                             fxRangeErr      = beyond FCB's extents
        !          1917: //�������������������������������������������������������������������������������
        !          1918: static OSErr MapFileBlockFromFCB(
        !          1919:        const ExtendedVCB               *vcb,
        !          1920:        const FCB                               *fcb,
        !          1921:        SInt64                                  offset,                 // Desired offset in bytes from start of file
        !          1922:        UInt32                                  *firstFABN,             // FABN of first block of found extent
        !          1923:        UInt32                                  *firstBlock,    // Corresponding allocation block number
        !          1924:        UInt32                                  *nextFABN)              // FABN of block after end of extent
        !          1925: {
        !          1926:        UInt32  index;
        !          1927:        UInt32  offsetBlocks;
        !          1928:        
        !          1929:        offsetBlocks = offset / vcb->blockSize;
        !          1930:        
        !          1931:        if (vcb->vcbSigWord == kHFSSigWord) {
        !          1932:                /* XXX SER Do we need to test for overflow values ??? */
        !          1933:                UInt16  blockCount;
        !          1934:                UInt16  currentFABN;
        !          1935:                
        !          1936:                currentFABN = 0;
        !          1937:                
        !          1938:                for (index=0; index<kHFSExtentDensity; index++) {
        !          1939: 
        !          1940:                        blockCount = fcb->fcbExtents[index].blockCount;
        !          1941: 
        !          1942:                        if (blockCount == 0)
        !          1943:                                return fxRangeErr;                              //      ran out of extents!
        !          1944: 
        !          1945:                        //      Is it in this extent?
        !          1946:                        if (offsetBlocks < blockCount) {
        !          1947:                                *firstFABN      = currentFABN;
        !          1948:                                *firstBlock     = fcb->fcbExtents[index].startBlock;
        !          1949:                                currentFABN += blockCount;              //      faster to add these as UInt16 first, then extend to UInt32
        !          1950:                                *nextFABN       = currentFABN;
        !          1951:                                return noErr;                                   //      found the right extent
        !          1952:                        }
        !          1953: 
        !          1954:                        //      Not in current extent, so adjust counters and loop again
        !          1955:                        offsetBlocks -= blockCount;
        !          1956:                        currentFABN += blockCount;
        !          1957:                }
        !          1958:        }
        !          1959:        else {
        !          1960:                UInt32  blockCount;
        !          1961:                UInt32  currentFABN;
        !          1962:                
        !          1963:                currentFABN = 0;
        !          1964:                
        !          1965:                for (index=0; index<kHFSPlusExtentDensity; index++) {
        !          1966: 
        !          1967:                        blockCount = fcb->fcbExtents[index].blockCount;
        !          1968: 
        !          1969:                        if (blockCount == 0)
        !          1970:                                return fxRangeErr;                              //      ran out of extents!
        !          1971: 
        !          1972:                        //      Is it in this extent?
        !          1973:                        if (offsetBlocks < blockCount) {
        !          1974:                                *firstFABN      = currentFABN;
        !          1975:                                *firstBlock     = fcb->fcbExtents[index].startBlock;
        !          1976:                                *nextFABN       = currentFABN + blockCount;
        !          1977:                                return noErr;                                   //      found the right extent
        !          1978:                        }
        !          1979: 
        !          1980:                        //      Not in current extent, so adjust counters and loop again
        !          1981:                        offsetBlocks -= blockCount;
        !          1982:                        currentFABN += blockCount;
        !          1983:                }
        !          1984:        }
        !          1985:        
        !          1986:        //      If we fall through here, the extent record was full, but the offset was
        !          1987:        //      beyond those extents.
        !          1988:        
        !          1989:        return fxRangeErr;
        !          1990: }
        !          1991: 
        !          1992: 
        !          1993: //_________________________________________________________________________________
        !          1994: //
        !          1995: // Routine:            ExtentsAreIntegral
        !          1996: //
        !          1997: // Purpose:            Ensure that each extent can hold an integral number of nodes
        !          1998: //                             Called by the NodesAreContiguous function
        !          1999: //_________________________________________________________________________________
        !          2000: 
        !          2001: static Boolean ExtentsAreIntegral(
        !          2002:        const HFSPlusExtentRecord extentRecord,
        !          2003:        UInt32          mask,
        !          2004:        UInt32          *blocksChecked,
        !          2005:        Boolean         *checkedLastExtent)
        !          2006: {
        !          2007:        UInt32          blocks;
        !          2008:        UInt32          extentIndex;
        !          2009: 
        !          2010:        *blocksChecked = 0;
        !          2011:        *checkedLastExtent = false;
        !          2012:        
        !          2013:        for(extentIndex = 0; extentIndex < kHFSPlusExtentDensity; extentIndex++)
        !          2014:        {               
        !          2015:                blocks = extentRecord[extentIndex].blockCount;
        !          2016:                
        !          2017:                if ( blocks == 0 )
        !          2018:                {
        !          2019:                        *checkedLastExtent = true;
        !          2020:                        break;
        !          2021:                }
        !          2022: 
        !          2023:                *blocksChecked += blocks;
        !          2024: 
        !          2025:                if (blocks & mask)
        !          2026:                        return false;
        !          2027:        }
        !          2028:        
        !          2029:        return true;
        !          2030: }
        !          2031: 
        !          2032: 
        !          2033: //_________________________________________________________________________________
        !          2034: //
        !          2035: // Routine:            NodesAreContiguous
        !          2036: //
        !          2037: // Purpose:            Ensure that all b-tree nodes are contiguous on disk
        !          2038: //                             Called by BTOpenPath during volume mount
        !          2039: //_________________________________________________________________________________
        !          2040: 
        !          2041: Boolean NodesAreContiguous(
        !          2042:        ExtendedVCB     *vcb,
        !          2043:        FCB                     *fcb,
        !          2044:        UInt32          nodeSize)
        !          2045: {
        !          2046:        UInt32                          mask;
        !          2047:        UInt32                          startBlock;
        !          2048:        UInt32                          blocksChecked;
        !          2049:        UInt32                          hint;
        !          2050:        HFSPlusExtentKey        key;
        !          2051:        HFSPlusExtentRecord     extents;
        !          2052:        OSErr                           result;
        !          2053:        Boolean                         lastExtentReached;
        !          2054:        
        !          2055: 
        !          2056:        if (vcb->blockSize >= nodeSize)
        !          2057:                return TRUE;
        !          2058: 
        !          2059:        mask = (nodeSize / vcb->blockSize) - 1;
        !          2060: 
        !          2061:        // check the local extents
        !          2062:        (void) GetFCBExtentRecord(fcb, extents);
        !          2063:        if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) )
        !          2064:                return FALSE;
        !          2065: 
        !          2066:        if (lastExtentReached || (blocksChecked * vcb->blockSize) >= fcb->fcbPLen)
        !          2067:                return TRUE;
        !          2068: 
        !          2069:        startBlock = blocksChecked;
        !          2070: 
        !          2071:        // check the overflow extents (if any)
        !          2072:        while ( !lastExtentReached )
        !          2073:        {
        !          2074:                result = FindExtentRecord(vcb, kDataForkType, H_FILEID(fcb), startBlock, FALSE, &key, extents, &hint);
        !          2075:                if (result) break;
        !          2076: 
        !          2077:                if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) )
        !          2078:                        return FALSE;
        !          2079: 
        !          2080:                startBlock += blocksChecked;
        !          2081:        }
        !          2082: 
        !          2083:        return TRUE;
        !          2084: }
        !          2085: 

unix.superglobalmegacorp.com

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