Annotation of XNU/bsd/hfs/hfscommon/Misc/FileExtentMapping.c, revision 1.1.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.