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

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: 
        !            25: /*
        !            26:        File:           FileExtentMapping.c
        !            27: 
        !            28:        Contains:       xxx put contents here xxx
        !            29: 
        !            30:        Version:        HFS Plus 1.0
        !            31: 
        !            32:        Written by:     Dave Heller, Mark Day
        !            33: 
        !            34:        Copyright:      � 1996-1998 by Apple Computer, Inc., all rights reserved.
        !            35: 
        !            36:        File Ownership:
        !            37: 
        !            38:                DRI:                            Mark Day
        !            39: 
        !            40:                Other Contact:          xxx put other contact here xxx
        !            41: 
        !            42:                Technology:                     xxx put technology here xxx
        !            43: 
        !            44:        Writers:
        !            45: 
        !            46:                (DSH)   Deric Horn
        !            47:                (msd)   Mark Day
        !            48:                (djb)   Don Brady
        !            49: 
        !            50:        Change History (most recent first):
        !            51:          <Rhap>         6/30/98        djb             Add functions NodesAreContiguous and ExtentsAreIntegral (for radar #2249539).
        !            52:          <Rhap>         6/23/98        djb             Changed DeallocFile to DeleteFile which now deletes the catalog record.
        !            53:                                                                        Fixed UpdateExtentRecord to pass correct fcb to Btree routines. Fixed
        !            54:                                                                        hfs+ bug in CreateExtentRecord (double dereference).
        !            55:          <Rhap>         5/20/98        djb             In ExtendFileC don't lie about the peof! (radar #2230094).
        !            56:          <Rhap>         4/17/98        djb             Add VCB locking.
        !            57:          <Rhap>          4/2/98        djb             Switch over to real BTree interface (no more BTreeWrapper.c).
        !            58:          <Rhap>         3/31/98        djb             Sync up with final HFSVolumes.h header file.
        !            59: 
        !            60:          <CS24>         1/23/98        msd             Bug 2208024: AllocContig is actually allocating one extent even
        !            61:                                                                        though there is not enough contiguous space.
        !            62:          <CS23>         12/2/97        DSH             GetFCBExtentRecord no longer static so DFA can use it.
        !            63:          <CS22>        10/20/97        msd             When allocating more space for a file, do the clump size
        !            64:                                                                        calculations in ExtendFileC, not BlockAllocate. Undo change from
        !            65:                                                                        <CS18>.
        !            66:          <CS21>        10/17/97        msd             Conditionalize DebugStrs.
        !            67:          <CS20>        10/16/97        msd             Simplify the code path for MapFileBlockC (logical to physical
        !            68:                                                                        block mapping) in the typical case where the file isn't
        !            69:                                                                        fragmented so badly that it has extents in the extents B-tree.
        !            70:                                                                        Simplified some of the calculations for all cases.
        !            71:          <CS19>        10/13/97        DSH             FindExtentRecord & DeleteExtentRecord are also being used by DFA
        !            72:                                                                        no longer static.
        !            73:          <CS18>         10/6/97        msd             When extending a file, set the physical EOF to include any extra
        !            74:                                                                        space allocated due to a file's clump size.
        !            75:          <CS17>         9/19/97        msd             Remove the MapLogicalToPhysical SPI. It was never used and is
        !            76:                                                                        not being tested anyway.
        !            77:          <CS16>          9/5/97        msd             In CompareExtentKeys and CompareExtentKeysPlus, use the symbolic
        !            78:                                                                        constants for key length. Don't DebugStr unless DEBUG_BUILD is
        !            79:                                                                        set.
        !            80:          <CS15>         7/24/97        djb             Add instrumentation to MapFileBlockC
        !            81:          <CS14>         7/16/97        DSH             FilesInternal.i renamed FileMgrInternal.i to avoid name
        !            82:                                                                        collision
        !            83:          <CS13>         7/15/97        DSH             AdjEOF() mark the FCB as modified. (1664389)
        !            84:          <CS12>          7/8/97        DSH             Loading PrecompiledHeaders from define passed in on C line
        !            85:          <CS11>          7/3/97        msd             Bug #1663518. Remove DebugStr when setting the FCB extent record
        !            86:                                                                        for a volume control file.
        !            87:          <CS10>         6/27/97        msd             Moved enum kFirstFileRefnum to FilesInternal.
        !            88:           <CS9>         6/24/97        djb             Include "CatalogPrivate.h"
        !            89:           <CS8>         6/16/97        msd             Finish implementation of CreateLargeFile SPI.
        !            90:           <CS7>         6/12/97        msd             Add stub for CreateLargeFile SPI.
        !            91:           <CS6>          6/5/97        msd             Add MapLogicalToPhysical.
        !            92:           <CS5>          6/2/97        msd             In TruncateFileC, don't update the extent record unless it was
        !            93:                                                                        actually changed (prevents extra updates when truncating to the
        !            94:                                                                        end of the extent, and it is the last extent of the file.) Added
        !            95:                                                                        an AdjustEOF routine called by the assembly AdjEOF routine. It
        !            96:                                                                        copies the EOF, physical length, and extent information from one
        !            97:                                                                        FCB to all other FCBs for that fork.
        !            98:           <CS4>         5/20/97        DSH             Removed const declaration in MapFileBlocC, const is benign when
        !            99:                                                                        passing by value, and SC requires it to match prototype.
        !           100:           <CS3>         5/15/97        msd             Change enum kResourceForkType from -1 to 0xFF since it is now
        !           101:                                                                        unsigned. Change all forkType parameters to UInt8.
        !           102:           <CS2>          5/7/97        msd             When checking for an unused extent descriptor, check the length,
        !           103:                                                                        not the starting block.
        !           104:           <CS1>         4/24/97        djb             first checked in
        !           105:         <HFS25>         4/11/97        DSH             use extended VCB fields catalogRefNum, and extentsRefNum.
        !           106:         <HFS24>          4/4/97        djb             Get in sync with volume format changes.
        !           107:         <HFS23>         3/17/97        DSH             Casting to compile with SC.
        !           108:         <HFS22>         2/26/97        msd             Add instrumentation in ExtendFileC and TruncateFileC. In
        !           109:                                                                        CompareExtentKeys and CompareExtentKeysPlus, make sure the key
        !           110:                                                                        lengths are correct.
        !           111:         <HFS21>          2/5/97        msd             The comparison with fsBTStartOfIterationErr didn't work because
        !           112:                                                                        the enum is an unsigned long; it is now casted to an OSErr
        !           113:                                                                        before comparing.
        !           114:         <HFS20>         1/31/97        msd             In FindExtentRecord, turn an fsBTStartOfIterationErr error into
        !           115:                                                                        btNotFound.
        !           116:         <HFS19>         1/28/97        msd             Fixed bug in MapFileBlockC where it returned the wrong number of
        !           117:                                                                        bytes available at the given block number.  This could
        !           118:                                                                        potentially cause programs to read or write over other files.
        !           119:         <HFS18>         1/16/97        djb             Extent key compare procs now return SInt32. Fixed
        !           120:                                                                        UpdateExtentRecord - it was passing a pointer to an ExtentKey
        !           121:                                                                        pointer.
        !           122:         <HFS17>         1/10/97        msd             Change TruncateFileC to call DellocateFork when the new PEOF is
        !           123:                                                                        0. Fixes a fxRangeErr returned when no extents existed.
        !           124:         <HFS16>          1/6/97        msd             Previous change prevents extent records from being removed if
        !           125:                                                                        the files new PEOF is in the local (FCB/catalog) extents.
        !           126:         <HFS15>          1/3/97        djb             Temp fix in TruncateFileC to prevent unwanted calls to
        !           127:                                                                        TruncateExtents.
        !           128:         <HFS14>        12/23/96        msd             Previous change to SearchExtentFile didn't set up the outputs
        !           129:                                                                        for hint and key when the FCB extent record wasn't full.
        !           130:         <HFS13>        12/20/96        msd             In SearchExtentFile, don't bother searching the extents file if
        !           131:                                                                        the FCB's extent record wasn't full, or if the FCB was for the
        !           132:                                                                        extents file itself. Modified SearchExtentRecord to return a
        !           133:                                                                        Boolean to indicate that the record was not full.
        !           134:         <HFS12>        12/19/96        DSH             Changed refs from VCB to ExtendedVCB
        !           135:         <HFS11>        12/19/96        djb             Updated for new B-tree Manager interface.
        !           136:         <HFS10>        12/12/96        djb             Really use new SPI for GetCatalogNode.
        !           137:          <HFS9>        12/12/96        djb             Use new Catalog SPI for GetCatalogNode. Added Mark's changes to
        !           138:                                                                        MapFileBlockC.
        !           139:          <HFS8>        12/11/96        msd             TruncateFileC must always release extents, even if PEOF hasn't
        !           140:                                                                        changed (since allocation may have been rounded up due to clump
        !           141:                                                                        size).
        !           142:          <HFS7>        12/10/96        msd             Check PRAGMA_LOAD_SUPPORTED before loading precompiled headers.
        !           143:          <HFS6>         12/4/96        DSH             Precompiled headers
        !           144:          <HFS5>        11/26/96        msd             Add an exported routine to grow the parallel FCB table to
        !           145:                                                                        accomodate the HFS+ ExtentRecord.
        !           146:          <HFS4>        11/26/96        msd             Convert internal routines to use ExtentKey and ExtentRecord
        !           147:                                                                        (instead of the raw HFS structures).
        !           148:          <HFS3>        11/21/96        msd             Added CompareExtentKeysPlus().
        !           149:          <HFS2>        11/20/96        msd             Finish porting FXM to C.
        !           150:          <HFS1>         11/6/96        DKH             first checked in
        !           151: 
        !           152: */
        !           153: 
        !           154: 
        !           155: #if ( PRAGMA_LOAD_SUPPORTED )
        !           156:         #pragma        load    PrecompiledHeaders
        !           157: #else
        !           158:         #if TARGET_OS_MAC
        !           159:        #include        <FSM.h>
        !           160:        #include        <LowMem.h>
        !           161:        #include        <LowMemPriv.h>
        !           162:        #include        <Memory.h>
        !           163:        #include        <stddef.h>
        !           164:        #include        <Math64.h>
        !           165:        #else
        !           166:        #include "../../hfs.h"
        !           167:        #include "../headers/system/MacOSStubs.h"
        !           168:        #endif  /* TARGET_OS_MAC */
        !           169: #endif /* PRAGMA_LOAD_SUPPORTED */
        !           170: 
        !           171: #if TARGET_OS_MAC
        !           172: #include       <Math64.h>
        !           173: #endif
        !           174: #include       "../headers/HFSVolumes.h"
        !           175: #include       "../headers/FileMgrInternal.h"
        !           176: #include       "../headers/BTreesInternal.h"
        !           177: #include       "../headers/CatalogPrivate.h"           // calling a private catalog routine (LocateCatalogNode)
        !           178: 
        !           179: #include "../headers/system/HFSInstrumentation.h"
        !           180: 
        !           181: 
        !           182: /*
        !           183: ============================================================
        !           184: Public (Exported) Routines:
        !           185: ============================================================
        !           186:        DeAllocFile             Deallocate all disk space allocated to a specified file.
        !           187:                                        Both forks are deallocated.
        !           188: 
        !           189:        ExtendFileC             Allocate more space to a given file.
        !           190: 
        !           191:        CompareExtentKeys
        !           192:                                        Compare two extents file keys (a search key and a trial
        !           193:                                        key).  Used by the BTree manager when searching for,
        !           194:                                        adding, or deleting keys in the extents file of an HFS
        !           195:                                        volume.
        !           196:                                        
        !           197:        CompareExtentKeysPlus
        !           198:                                        Compare two extents file keys (a search key and a trial
        !           199:                                        key).  Used by the BTree manager when searching for,
        !           200:                                        adding, or deleting keys in the extents file of an HFS+
        !           201:                                        volume.
        !           202:                                        
        !           203:        MapFileBlockC   Convert (map) an offset within a given file into a
        !           204:                                        physical disk address.
        !           205:                                        
        !           206:        TruncateFileC   Truncates the disk space allocated to a file.  The file
        !           207:                                        space is truncated to a specified new physical EOF, rounded
        !           208:                                        up to the next allocation block boundry.  There is an option
        !           209:                                        to truncate to the end of the extent containing the new EOF.
        !           210:        
        !           211:        FlushExtentFile
        !           212:                                        Flush the extents file for a given volume.
        !           213: 
        !           214:        GrowParallelFCBs
        !           215:                                        Make sure the parallel FCB entries are big enough to support
        !           216:                                        the HFS+ ExtentRecord.  If not, the array is grown and the
        !           217:                                        pre-existing data copied over.
        !           218: 
        !           219:        AdjustEOF
        !           220:                                        Copy EOF, physical length, and extent records from one FCB
        !           221:                                        to all other FCBs for that fork.  This is used when a file is
        !           222:                                        grown or shrunk as the result of a Write, SetEOF, or Allocate.
        !           223: 
        !           224:        MapLogicalToPhysical
        !           225:                                        Map some position in a file to a volume block number.  Also
        !           226:                                        returns the number of contiguous bytes that are mapped there.
        !           227:                                        This is a queued HFSDispatch call that does the equivalent of
        !           228:                                        MapFileBlockC, using a parameter block.
        !           229: 
        !           230: ============================================================
        !           231: Internal Routines:
        !           232: ============================================================
        !           233:        FindExtentRecord
        !           234:                                        Search the extents BTree for a particular extent record.
        !           235:        SearchExtentFile
        !           236:                                        Search the FCB and extents file for an extent record that
        !           237:                                        contains a given file position (in bytes).
        !           238:        SearchExtentRecord
        !           239:                                        Search a given extent record to see if it contains a given
        !           240:                                        file position (in bytes).  Used by SearchExtentFile.
        !           241:        ReleaseExtents
        !           242:                                        Deallocate all allocation blocks in all extents of an extent
        !           243:                                        data record.
        !           244:        TruncateExtents
        !           245:                                        Deallocate blocks and delete extent records for all allocation
        !           246:                                        blocks beyond a certain point in a file.  The starting point
        !           247:                                        must be the first file allocation block for some extent record
        !           248:                                        for the file.
        !           249:        DeallocateFork
        !           250:                                        Deallocate all allocation blocks belonging to a given fork.
        !           251:        UpdateExtentRecord
        !           252:                                        If the extent record came from the extents file, write out
        !           253:                                        the updated record; otherwise, copy the updated record into
        !           254:                                        the FCB resident extent record.  If the record has no extents,
        !           255:                                        and was in the extents file, then delete the record instead.
        !           256: */
        !           257: 
        !           258: enum
        !           259: {
        !           260:        kTwoGigabytes                   = (UInt32) 0x80000000,
        !           261:        
        !           262:        kDataForkType                   = 0,
        !           263:        kResourceForkType               = 0xFF,
        !           264:        
        !           265:        kPreviousRecord                 = -1,
        !           266:        
        !           267:        kSectorSize                             = 512           // Size of a physical sector
        !           268: };
        !           269: 
        !           270: static void ExtDataRecToExtents(
        !           271:        const HFSExtentRecord   oldExtents,
        !           272:        HFSPlusExtentRecord             newExtents);
        !           273: 
        !           274: static OSErr ExtentsToExtDataRec(
        !           275:        const HFSPlusExtentRecord       oldExtents,
        !           276:        HFSExtentRecord                         newExtents);
        !           277: 
        !           278: OSErr FindExtentRecord(
        !           279:        const ExtendedVCB               *vcb,
        !           280:        UInt8                                   forkType,
        !           281:        UInt32                                  fileID,
        !           282:        UInt32                                  startBlock,
        !           283:        Boolean                                 allowPrevious,
        !           284:        HFSPlusExtentKey                *foundKey,
        !           285:        HFSPlusExtentRecord             foundData,
        !           286:        UInt32                                  *foundHint);
        !           287: 
        !           288: OSErr DeleteExtentRecord(
        !           289:        const ExtendedVCB               *vcb,
        !           290:        UInt8                                   forkType,
        !           291:        UInt32                                  fileID,
        !           292:        UInt32                                  startBlock);
        !           293: 
        !           294: static OSErr CreateExtentRecord(
        !           295:        const ExtendedVCB               *vcb,
        !           296:        HFSPlusExtentKey                *key,
        !           297:        HFSPlusExtentRecord             extents,
        !           298:        UInt32                                  *hint);
        !           299: 
        !           300: static ExtendedFCB *GetExtendedFCB(const FCB *fcb);
        !           301: 
        !           302: OSErr GetFCBExtentRecord(
        !           303:        const ExtendedVCB               *vcb,
        !           304:        const FCB                               *fcb,
        !           305:        HFSPlusExtentRecord             extents);
        !           306: 
        !           307: static OSErr SetFCBExtentRecord(
        !           308:        const ExtendedVCB               *vcb,
        !           309:        FCB                                             *fcb,
        !           310:        const HFSPlusExtentRecord       extents);
        !           311: 
        !           312: static OSErr SearchExtentFile(
        !           313:        const ExtendedVCB               *vcb,
        !           314:        const FCB                               *fcb,
        !           315:        UInt32                                  filePosition,
        !           316:        HFSPlusExtentKey                *foundExtentKey,
        !           317:        HFSPlusExtentRecord             foundExtentData,
        !           318:        UInt32                                  *foundExtentDataIndex,
        !           319:        UInt32                                  *extentBTreeHint,
        !           320:        UInt32                                  *endingFABNPlusOne );
        !           321: 
        !           322: static OSErr SearchExtentRecord(
        !           323:        const ExtendedVCB               *vcb,
        !           324:        UInt32                                  searchFABN,
        !           325:        const HFSPlusExtentRecord       extentData,
        !           326:        UInt32                                  extentDataStartFABN,
        !           327:        UInt32                                  *foundExtentDataOffset,
        !           328:        UInt32                                  *endingFABNPlusOne,
        !           329:        Boolean                                 *noMoreExtents);
        !           330: 
        !           331: static OSErr ReleaseExtents(
        !           332:        ExtendedVCB                             *vcb,
        !           333:        const HFSPlusExtentRecord       extentRecord,
        !           334:        UInt32                                  *numReleasedAllocationBlocks,
        !           335:        Boolean                                 *releasedLastExtent);
        !           336: 
        !           337: static OSErr DeallocateFork(
        !           338:        ExtendedVCB             *vcb,
        !           339:        HFSCatalogNodeID        fileID,
        !           340:        UInt8                           forkType,
        !           341:        HFSPlusExtentRecord     catalogExtents);
        !           342: 
        !           343: static OSErr TruncateExtents(
        !           344:        ExtendedVCB                     *vcb,
        !           345:        UInt8                           forkType,
        !           346:        UInt32                          fileID,
        !           347:        UInt32                          startBlock);
        !           348: 
        !           349: static OSErr UpdateExtentRecord (
        !           350:        const ExtendedVCB               *vcb,
        !           351:        FCB                                             *fcb,
        !           352:        const HFSPlusExtentKey  *extentFileKey,
        !           353:        const HFSPlusExtentRecord       extentData,
        !           354:        UInt32                                  extentBTreeHint);
        !           355: 
        !           356: static OSErr MapFileBlockFromFCB(
        !           357:        const ExtendedVCB               *vcb,
        !           358:        const FCB                               *fcb,
        !           359:        UInt32                                  offset,                 // Desired offset in bytes from start of file
        !           360:        UInt32                                  *firstFABN,             // FABN of first block of found extent
        !           361:        UInt32                                  *firstBlock,    // Corresponding allocation block number
        !           362:        UInt32                                  *nextFABN);             // FABN of block after end of extent
        !           363: 
        !           364: static Boolean ExtentsAreIntegral(
        !           365:        const HFSPlusExtentRecord extentRecord,
        !           366:        UInt32          mask,
        !           367:        UInt32          *blocksChecked,
        !           368:        Boolean         *checkedLastExtent);
        !           369: 
        !           370: //_________________________________________________________________________________
        !           371: //
        !           372: //     Routine:        FindExtentRecord
        !           373: //
        !           374: //     Purpose:        Search the extents BTree for an extent record matching the given
        !           375: //                             FileID, fork, and starting file allocation block number.
        !           376: //
        !           377: //     Inputs:
        !           378: //             vcb                             Volume to search
        !           379: //             forkType                0 = data fork, -1 = resource fork
        !           380: //             fileID                  File's FileID (CatalogNodeID)
        !           381: //             startBlock              Starting file allocation block number
        !           382: //             allowPrevious   If the desired record isn't found and this flag is set,
        !           383: //                                             then see if the previous record belongs to the same fork.
        !           384: //                                             If so, then return it.
        !           385: //
        !           386: //     Outputs:
        !           387: //             foundKey        The key data for the record actually found
        !           388: //             foundData       The extent record actually found (NOTE: on an HFS volume, the
        !           389: //                                     fourth entry will be zeroes.
        !           390: //             foundHint       The BTree hint to find the node again
        !           391: //_________________________________________________________________________________
        !           392: OSErr FindExtentRecord(
        !           393:        const ExtendedVCB       *vcb,
        !           394:        UInt8                           forkType,
        !           395:        UInt32                          fileID,
        !           396:        UInt32                          startBlock,
        !           397:        Boolean                         allowPrevious,
        !           398:        HFSPlusExtentKey        *foundKey,
        !           399:        HFSPlusExtentRecord     foundData,
        !           400:        UInt32                          *foundHint)
        !           401: {
        !           402:        FCB *                           fcb;
        !           403:        BTreeIterator           btIterator;
        !           404:        FSBufferDescriptor      btRecord;
        !           405:        OSErr                           err;
        !           406:        UInt16                          btRecordSize;
        !           407:        
        !           408:        err = noErr;
        !           409:        *foundHint = 0;
        !           410:        fcb = GetFileControlBlock(vcb->extentsRefNum);
        !           411:        
        !           412:        (void) BTInvalidateHint(&btIterator);
        !           413: 
        !           414:        if (vcb->vcbSigWord == kHFSSigWord) {
        !           415:                HFSExtentKey *          extentKeyPtr;
        !           416:                HFSExtentRecord         extentData;
        !           417: 
        !           418:                extentKeyPtr = (HFSExtentKey*) &btIterator.key;
        !           419:                extentKeyPtr->keyLength = kHFSExtentKeyMaximumLength;
        !           420:                extentKeyPtr->forkType = forkType;
        !           421:                extentKeyPtr->fileID = fileID;
        !           422:                extentKeyPtr->startBlock = startBlock;
        !           423:                
        !           424:                btRecord.bufferAddress = &extentData;
        !           425:                btRecord.itemSize = sizeof(HFSExtentRecord);
        !           426:                btRecord.itemCount = 1;
        !           427: 
        !           428:                err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator);
        !           429: 
        !           430:                if (err == btNotFound && allowPrevious) {
        !           431:                        err = BTIterateRecord(fcb, kBTreePrevRecord, &btIterator, &btRecord, &btRecordSize);
        !           432: 
        !           433:                        //      A previous record may not exist, so just return btNotFound (like we would if
        !           434:                        //      it was for the wrong file/fork).
        !           435:                        if (err == (OSErr) fsBTStartOfIterationErr)             //�� fsBTStartOfIterationErr is type unsigned long
        !           436:                                err = btNotFound;
        !           437: 
        !           438:                        if (err == noErr) {
        !           439:                                //      Found a previous record.  Does it belong to the same fork of the same file?
        !           440:                                if (extentKeyPtr->fileID != fileID || extentKeyPtr->forkType != forkType)
        !           441:                                        err = btNotFound;
        !           442:                        }
        !           443:                }
        !           444: 
        !           445:                if (err == noErr) {
        !           446:                        UInt16  i;
        !           447:                        
        !           448:                        //      Copy the found key back for the caller
        !           449:                        foundKey->keyLength     = kHFSPlusExtentKeyMaximumLength;
        !           450:                        foundKey->forkType              = extentKeyPtr->forkType;
        !           451:                        foundKey->pad                   = 0;
        !           452:                        foundKey->fileID                = extentKeyPtr->fileID;
        !           453:                        foundKey->startBlock    = extentKeyPtr->startBlock;
        !           454:                        
        !           455:                        //      Copy the found data back for the caller
        !           456:                        foundData[0].startBlock = extentData[0].startBlock;
        !           457:                        foundData[0].blockCount = extentData[0].blockCount;
        !           458:                        foundData[1].startBlock = extentData[1].startBlock;
        !           459:                        foundData[1].blockCount = extentData[1].blockCount;
        !           460:                        foundData[2].startBlock = extentData[2].startBlock;
        !           461:                        foundData[2].blockCount = extentData[2].blockCount;
        !           462:                        
        !           463:                        for (i = 3; i < kHFSPlusExtentDensity; ++i)
        !           464:                        {
        !           465:                                foundData[i].startBlock = 0;
        !           466:                                foundData[i].blockCount = 0;
        !           467:                        }
        !           468:                }
        !           469:        }
        !           470:        else {          // HFS Plus volume
        !           471:                HFSPlusExtentKey *      extentKeyPtr;
        !           472:                HFSPlusExtentRecord     extentData;
        !           473: 
        !           474:                extentKeyPtr = (HFSPlusExtentKey*) &btIterator.key;
        !           475:                extentKeyPtr->keyLength  = kHFSPlusExtentKeyMaximumLength;
        !           476:                extentKeyPtr->forkType   = forkType;
        !           477:                extentKeyPtr->pad                = 0;
        !           478:                extentKeyPtr->fileID     = fileID;
        !           479:                extentKeyPtr->startBlock = startBlock;
        !           480:                
        !           481:                btRecord.bufferAddress = &extentData;
        !           482:                btRecord.itemSize = sizeof(HFSPlusExtentRecord);
        !           483:                btRecord.itemCount = 1;
        !           484: 
        !           485:                err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator);
        !           486: 
        !           487:                if (err == btNotFound && allowPrevious) {
        !           488:                        err = BTIterateRecord(fcb, kBTreePrevRecord, &btIterator, &btRecord, &btRecordSize);
        !           489: 
        !           490:                        //      A previous record may not exist, so just return btNotFound (like we would if
        !           491:                        //      it was for the wrong file/fork).
        !           492:                        if (err == (OSErr) fsBTStartOfIterationErr)             //�� fsBTStartOfIterationErr is type unsigned long
        !           493:                                err = btNotFound;
        !           494: 
        !           495:                        if (err == noErr) {
        !           496:                                //      Found a previous record.  Does it belong to the same fork of the same file?
        !           497:                                if (extentKeyPtr->fileID != fileID || extentKeyPtr->forkType != forkType)
        !           498:                                        err = btNotFound;
        !           499:                        }
        !           500:                }
        !           501: 
        !           502:                if (err == noErr) {
        !           503:                        //      Copy the found key back for the caller
        !           504:                        BlockMoveData(extentKeyPtr, foundKey, sizeof(HFSPlusExtentKey));
        !           505:                        //      Copy the found data back for the caller
        !           506:                        BlockMoveData(&extentData, foundData, sizeof(HFSPlusExtentRecord));
        !           507:                }
        !           508:        }
        !           509:        
        !           510:        *foundHint = btIterator.hint.nodeNum;
        !           511:        return err;
        !           512: }
        !           513: 
        !           514: 
        !           515: 
        !           516: static OSErr CreateExtentRecord(
        !           517:        const ExtendedVCB       *vcb,
        !           518:        HFSPlusExtentKey        *key,
        !           519:        HFSPlusExtentRecord     extents,
        !           520:        UInt32                          *hint)
        !           521: {
        !           522:        BTreeIterator           btIterator;
        !           523:        FSBufferDescriptor      btRecord;
        !           524:        UInt16                          btRecordSize;
        !           525:        OSErr                           err;
        !           526:        
        !           527:        err = noErr;
        !           528:        *hint = 0;
        !           529:        (void) BTInvalidateHint(&btIterator);
        !           530:        
        !           531:        if (vcb->vcbSigWord == kHFSSigWord) {
        !           532:                HFSExtentKey *          keyPtr;
        !           533:                HFSExtentRecord         data;
        !           534:                
        !           535:                btRecordSize = sizeof(HFSExtentRecord);
        !           536:                btRecord.bufferAddress = &data;
        !           537:                btRecord.itemSize = btRecordSize;
        !           538:                btRecord.itemCount = 1;
        !           539: 
        !           540:                keyPtr = (HFSExtentKey*) &btIterator.key;
        !           541:                keyPtr->keyLength       = kHFSExtentKeyMaximumLength;
        !           542:                keyPtr->forkType        = key->forkType;
        !           543:                keyPtr->fileID          = key->fileID;
        !           544:                keyPtr->startBlock      = key->startBlock;
        !           545:                
        !           546:                err = ExtentsToExtDataRec(extents, data);
        !           547:        }
        !           548:        else {          // HFS Plus volume
        !           549:                btRecordSize = sizeof(HFSPlusExtentRecord);
        !           550:                btRecord.bufferAddress = extents;
        !           551:                btRecord.itemSize = btRecordSize;
        !           552:                btRecord.itemCount = 1;
        !           553: 
        !           554:                BlockMoveData(key, &btIterator.key, sizeof(HFSPlusExtentKey));
        !           555:        }
        !           556: 
        !           557:        if (err == noErr)
        !           558:                err = BTInsertRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator, &btRecord, btRecordSize);
        !           559: 
        !           560:        if (err == noErr)
        !           561:                *hint = btIterator.hint.nodeNum;
        !           562: 
        !           563:        return err;
        !           564: }
        !           565: 
        !           566: 
        !           567: OSErr DeleteExtentRecord(
        !           568:        const ExtendedVCB       *vcb,
        !           569:        UInt8                           forkType,
        !           570:        UInt32                          fileID,
        !           571:        UInt32                          startBlock)
        !           572: {
        !           573:        BTreeIterator           btIterator;
        !           574:        OSErr                           err;
        !           575:        
        !           576:        err = noErr;
        !           577:        (void) BTInvalidateHint(&btIterator);
        !           578:        
        !           579:        if (vcb->vcbSigWord == kHFSSigWord) {
        !           580:                HFSExtentKey *  keyPtr;
        !           581: 
        !           582:                keyPtr = (HFSExtentKey*) &btIterator.key;
        !           583:                keyPtr->keyLength       = kHFSExtentKeyMaximumLength;
        !           584:                keyPtr->forkType        = forkType;
        !           585:                keyPtr->fileID          = fileID;
        !           586:                keyPtr->startBlock      = startBlock;
        !           587:        }
        !           588:        else {          //      HFS Plus volume
        !           589:                HFSPlusExtentKey *      keyPtr;
        !           590: 
        !           591:                keyPtr = (HFSPlusExtentKey*) &btIterator.key;
        !           592:                keyPtr->keyLength       = kHFSPlusExtentKeyMaximumLength;
        !           593:                keyPtr->forkType        = forkType;
        !           594:                keyPtr->pad                     = 0;
        !           595:                keyPtr->fileID          = fileID;
        !           596:                keyPtr->startBlock      = startBlock;
        !           597:        }
        !           598: 
        !           599:        err = BTDeleteRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator);
        !           600:        
        !           601:        return err;
        !           602: }
        !           603: 
        !           604: 
        !           605: 
        !           606: //_________________________________________________________________________________
        !           607: //
        !           608: // Routine:            MapFileBlock
        !           609: //
        !           610: // Function:   Maps a file position into a physical disk address.
        !           611: //
        !           612: // Input:              A2.L  -  VCB pointer
        !           613: //                             (A1,D1.W)  -  FCB pointer
        !           614: //                             D4.L  -  number of bytes desired
        !           615: //                             D5.L  -  file position (byte address)
        !           616: //
        !           617: // Output:             D3.L  -  physical start block
        !           618: //                             D6.L  -  number of contiguous bytes available (up to D4 bytes)
        !           619: //                             D0.L  -  result code                                                                                            <01Oct85>
        !           620: //                                                0 = ok
        !           621: //                                                FXRangeErr = file position beyond mapped range                       <17Oct85>
        !           622: //                                                FXOvFlErr = extents file overflow                                            <17Oct85>
        !           623: //                                                other = error                                                                                        <17Oct85>
        !           624: //
        !           625: // Called By:  Log2Phys (read/write in place), Cache (map a file block).
        !           626: //_________________________________________________________________________________
        !           627: 
        !           628: OSErr MapFileBlockC (
        !           629:        ExtendedVCB             *vcb,                           // volume that file resides on
        !           630:        FCB                             *fcb,                           // FCB of file
        !           631:        UInt32                  numberOfBytes,          // number of contiguous bytes desired
        !           632:        UInt32                  offset,                         // starting offset within file (in bytes)
        !           633:        UInt32                  *startSector,           // first 512-byte sector (NOT an allocation block)
        !           634:        UInt32                  *availableBytes)        // number of contiguous bytes (up to numberOfBytes)
        !           635: {
        !           636:        OSErr                           err;
        !           637:        UInt32                          allocBlockSize;                 //      Size of the volume's allocation block
        !           638:        HFSPlusExtentKey        foundKey;
        !           639:        HFSPlusExtentRecord     foundData;
        !           640:        UInt32                          foundIndex;
        !           641:        UInt32                          hint;
        !           642:        UInt32                          firstFABN;                              // file allocation block of first block in found extent
        !           643:        UInt32                          nextFABN;                               // file allocation block of block after end of found extent
        !           644:        UInt32                          dataEnd;                                // (offset) end of range that is contiguous
        !           645:        UInt32                          sectorsPerBlock;                // Number of sectors per allocation block
        !           646:        UInt32                          startBlock;                             // volume allocation block corresponding to firstFABN
        !           647:        UInt32                          temp;
        !           648:        
        !           649:        
        !           650:        LogStartTime(kTraceMapFileBlock);
        !           651: 
        !           652:        allocBlockSize = vcb->blockSize;
        !           653:        
        !           654:        err = MapFileBlockFromFCB(vcb, fcb, offset, &firstFABN, &startBlock, &nextFABN);
        !           655:        if (err != noErr) {
        !           656:                err = SearchExtentFile(vcb, fcb, offset, &foundKey, foundData, &foundIndex, &hint, &nextFABN);
        !           657:                if (err == noErr) {
        !           658:                        startBlock = foundData[foundIndex].startBlock;
        !           659:                        firstFABN = nextFABN - foundData[foundIndex].blockCount;
        !           660:                }
        !           661:        }
        !           662:        
        !           663:        if (err != noErr)
        !           664:        {
        !           665:                LogEndTime(kTraceMapFileBlock, err);
        !           666: 
        !           667:                return err;
        !           668:        }
        !           669: 
        !           670:        //
        !           671:        //      Determine the end of the available space.  It will either be the end of the extent,
        !           672:        //      or the file's PEOF, whichever is smaller.
        !           673:        //
        !           674:        dataEnd = nextFABN * allocBlockSize;            // Assume valid data through end of this extent
        !           675:        if (fcb->fcbPLen < dataEnd)                                     // Is PEOF shorter?
        !           676:                dataEnd = fcb->fcbPLen;                                 // Yes, so only map up to PEOF
        !           677:        
        !           678:        //      Compute the number of sectors in an allocation block
        !           679:        sectorsPerBlock = allocBlockSize / kSectorSize; // sectors per allocation block
        !           680:        
        !           681:        //
        !           682:        //      Compute the absolute sector number that contains the offset of the given file
        !           683:        //
        !           684:        temp  = offset - (firstFABN * allocBlockSize);  // offset in bytes from start of the extent
        !           685:        temp /= kSectorSize;                                                    // offset in sectors from start of the extent
        !           686:        temp += startBlock * sectorsPerBlock;                   // offset in sectors from start of allocation block space
        !           687:        temp += vcb->vcbAlBlSt;                                                 // offset in sectors from start of volume
        !           688:        
        !           689:        //      Return the desired sector for file position "offset"
        !           690:        *startSector = temp;
        !           691:        
        !           692:        //
        !           693:        //      Determine the number of contiguous bytes until the end of the extent
        !           694:        //      (or the amount they asked for, whichever comes first).
        !           695:        //
        !           696:        temp = dataEnd - offset;
        !           697:        if (temp > numberOfBytes)
        !           698:                *availableBytes = numberOfBytes;        // more there than they asked for, so pin the output
        !           699:        else
        !           700:                *availableBytes = temp;
        !           701:        
        !           702:        LogEndTime(kTraceMapFileBlock, noErr);
        !           703: 
        !           704:        return noErr;
        !           705: }
        !           706: 
        !           707: 
        !           708: //�������������������������������������������������������������������������������
        !           709: //     Routine:        ReleaseExtents
        !           710: //
        !           711: //     Function:       Release the extents of a single extent data record.
        !           712: //�������������������������������������������������������������������������������
        !           713: 
        !           714: static OSErr ReleaseExtents(
        !           715:        ExtendedVCB                     *vcb,
        !           716:        const HFSPlusExtentRecord       extentRecord,
        !           717:        UInt32                                  *numReleasedAllocationBlocks,
        !           718:        Boolean                                 *releasedLastExtent)
        !           719: {
        !           720:        UInt32  extentIndex;
        !           721:        UInt32  numberOfExtents;
        !           722:        OSErr   err = noErr;
        !           723:        
        !           724:        *numReleasedAllocationBlocks = 0;
        !           725:        *releasedLastExtent = false;
        !           726:        
        !           727:        if (vcb->vcbSigWord == kHFSPlusSigWord)
        !           728:                numberOfExtents = kHFSPlusExtentDensity;
        !           729:        else
        !           730:                numberOfExtents = kHFSExtentDensity;
        !           731: 
        !           732:        for( extentIndex = 0; extentIndex < numberOfExtents; extentIndex++)
        !           733:        {
        !           734:                UInt32  numAllocationBlocks;
        !           735:                
        !           736:                // Loop over the extent record and release the blocks associated with each extent.
        !           737:                
        !           738:                numAllocationBlocks = extentRecord[extentIndex].blockCount;
        !           739:                if ( numAllocationBlocks == 0 )
        !           740:                {
        !           741:                        *releasedLastExtent = true;
        !           742:                        break;
        !           743:                }
        !           744: 
        !           745:                err = BlockDeallocate( vcb, extentRecord[extentIndex].startBlock, numAllocationBlocks );
        !           746:                if ( err != noErr )
        !           747:                        break;
        !           748:                                        
        !           749:                *numReleasedAllocationBlocks += numAllocationBlocks;            //      bump FABN to beg of next extent
        !           750:        }
        !           751: 
        !           752:        return( err );
        !           753: }
        !           754: 
        !           755: 
        !           756: 
        !           757: //�������������������������������������������������������������������������������
        !           758: //     Routine:        TruncateExtents
        !           759: //
        !           760: //     Purpose:        Delete extent records whose starting file allocation block number
        !           761: //                             is greater than or equal to a given starting block number.  The
        !           762: //                             allocation blocks represented by the extents are deallocated.
        !           763: //
        !           764: //     Inputs:
        !           765: //             vcb                     Volume to operate on
        !           766: //             fileID          Which file to operate on
        !           767: //             startBlock      Starting file allocation block number for first extent
        !           768: //                                     record to delete.
        !           769: //�������������������������������������������������������������������������������
        !           770: 
        !           771: static OSErr TruncateExtents(
        !           772:        ExtendedVCB             *vcb,
        !           773:        UInt8                   forkType,
        !           774:        UInt32                  fileID,
        !           775:        UInt32                  startBlock)
        !           776: {
        !           777:        OSErr                           err;
        !           778:        UInt32                          numberExtentsReleased;
        !           779:        Boolean                         releasedLastExtent;
        !           780:        UInt32                          hint;
        !           781:        HFSPlusExtentKey        key;
        !           782:        HFSPlusExtentRecord     extents;
        !           783: 
        !           784:        while (true) {
        !           785:                err = FindExtentRecord(vcb, forkType, fileID, startBlock, false, &key, extents, &hint);
        !           786:                if (err != noErr) {
        !           787:                        if (err == btNotFound)
        !           788:                                err = noErr;
        !           789:                        break;
        !           790:                }
        !           791:                
        !           792:                err = ReleaseExtents( vcb, extents, &numberExtentsReleased, &releasedLastExtent );
        !           793:                if (err != noErr) break;
        !           794:                
        !           795:                err = DeleteExtentRecord(vcb, forkType, fileID, startBlock);
        !           796:                if (err != noErr) break;
        !           797: 
        !           798:                startBlock += numberExtentsReleased;
        !           799:        }
        !           800:        
        !           801:        return err;
        !           802: }
        !           803: 
        !           804: 
        !           805: 
        !           806: //�������������������������������������������������������������������������������
        !           807: //     Routine:        DeallocateFork
        !           808: //
        !           809: //     Function:       De-allocates all disk space allocated to a specified fork.
        !           810: //�������������������������������������������������������������������������������
        !           811: 
        !           812: static OSErr DeallocateFork(
        !           813:        ExtendedVCB             *vcb,
        !           814:        HFSCatalogNodeID        fileID,
        !           815:        UInt8                           forkType,
        !           816:        HFSPlusExtentRecord     catalogExtents)
        !           817: {
        !           818:        OSErr                           err;
        !           819:        UInt32                          numReleasedAllocationBlocks;
        !           820:        Boolean                         releasedLastExtent;
        !           821:        
        !           822:        //      Release the catalog extents
        !           823:        err = ReleaseExtents( vcb, catalogExtents, &numReleasedAllocationBlocks, &releasedLastExtent );
        !           824:        // Release the extra extents, if present
        !           825:        if (err == noErr && !releasedLastExtent)
        !           826:                err = TruncateExtents(vcb, forkType, fileID, numReleasedAllocationBlocks);
        !           827: 
        !           828:        return( err );
        !           829: }
        !           830: 
        !           831: //�������������������������������������������������������������������������������
        !           832: //     Routine:        FlushExtentFile
        !           833: //
        !           834: //     Function:       Flushes the extent file for a specified volume
        !           835: //�������������������������������������������������������������������������������
        !           836: 
        !           837: OSErr FlushExtentFile( ExtendedVCB *vcb )
        !           838: {
        !           839:        FCB *   fcb;
        !           840:        OSErr   err;
        !           841:        
        !           842:        fcb = GetFileControlBlock(vcb->extentsRefNum);
        !           843:        err = BTFlushPath(fcb);
        !           844:        if ( err == noErr )
        !           845:        {
        !           846:                // If the FCB for the extent "file" is dirty, mark the VCB as dirty.
        !           847:                
        !           848:                if ((fcb->fcbFlags && fcbModifiedMask) != 0)
        !           849:                {
        !           850:                        MarkVCBDirty( vcb );
        !           851:                        err = FlushVolumeControlBlock( vcb );
        !           852:                }
        !           853:        }
        !           854:        
        !           855:        return( err );
        !           856: }
        !           857: 
        !           858: //-------------------------------------------------------------------------------
        !           859: //     Routine:        DeleteFile
        !           860: //
        !           861: //     Function:       De-allocates all disk space allocated to a specified file 
        !           862: //                             including the space used by the catalog (ie the catalog record).
        !           863: //                             The space occupied by both forks is also deallocated.
        !           864: //
        !           865: //-------------------------------------------------------------------------------
        !           866: 
        !           867: OSErr DeleteFile( ExtendedVCB *vcb, HFSCatalogNodeID parDirID, ConstUTF8Param catalogName, UInt32 catalogHint )
        !           868: {
        !           869:        OSErr                   err;
        !           870:        OSErr                   errDF, errRF;
        !           871:        CatalogNodeData catalogData;
        !           872:        FSSpec                  fileSpec;       /* 264 bytes */
        !           873:        
        !           874:        // Find catalog data in catalog
        !           875:        err = GetCatalogNode( vcb, parDirID, catalogName, catalogHint, &fileSpec, &catalogData, &catalogHint);
        !           876:        if( err != noErr )
        !           877:                goto Exit;
        !           878:        
        !           879:        // Check to make sure record is for a file
        !           880:        if ( catalogData.nodeType != kCatalogFileNode )
        !           881:        {
        !           882:                err = notAFileErr;
        !           883:                goto Exit;
        !           884:        }
        !           885:        
        !           886:        //
        !           887:        // Always delete the Catalog record first (to minimize disk corruption)
        !           888:        //
        !           889:        err = DeleteCatalogNode(vcb, parDirID, catalogName, catalogHint);
        !           890:        if( err != noErr )
        !           891:                goto Exit;
        !           892: 
        !           893:        //
        !           894:        // Note: we don't report errors from DeallocateFork since the
        !           895:        // file no longer exists (since DeleteCatalogNode succeeded).
        !           896:        // Any errors mean that there are possibly some orphaned disk
        !           897:        // blocks but from the clients perspective the file was deleted.
        !           898:        //
        !           899: 
        !           900:        // Deallocate data fork extents
        !           901:        errDF = DeallocateFork( vcb, catalogData.nodeID, kDataForkType, catalogData.dataExtents );
        !           902: 
        !           903:        // Deallocate resource fork extents
        !           904:        errRF = DeallocateFork( vcb, catalogData.nodeID, kResourceForkType, catalogData.rsrcExtents );
        !           905: 
        !           906:        if ((errDF | errRF) == 0)
        !           907:                (void) FlushExtentFile( vcb );
        !           908:        
        !           909: Exit:
        !           910:        
        !           911:        return( err );
        !           912: }
        !           913: 
        !           914: //�������������������������������������������������������������������������������
        !           915: //     Routine:        CompareExtentKeys
        !           916: //
        !           917: //     Function:       Compares two extent file keys (a search key and a trial key) for
        !           918: //                             an HFS volume.
        !           919: //�������������������������������������������������������������������������������
        !           920: 
        !           921: SInt32 CompareExtentKeys( const HFSExtentKey *searchKey, const HFSExtentKey *trialKey )
        !           922: {
        !           923:        SInt32  result;         //      � 1
        !           924:        
        !           925:        #if DEBUG_BUILD
        !           926:                if (searchKey->keyLength != kHFSExtentKeyMaximumLength)
        !           927:                        DebugStr("\pHFS: search Key is wrong length");
        !           928:                if (trialKey->keyLength != kHFSExtentKeyMaximumLength)
        !           929:                        DebugStr("\pHFS: trial Key is wrong length");
        !           930:        #endif
        !           931:        
        !           932:        result = -1;            //      assume searchKey < trialKey
        !           933:        
        !           934:        if (searchKey->fileID == trialKey->fileID) {
        !           935:                //
        !           936:                //      FileNum's are equal; compare fork types
        !           937:                //
        !           938:                if (searchKey->forkType == trialKey->forkType) {
        !           939:                        //
        !           940:                        //      Fork types are equal; compare allocation block number
        !           941:                        //
        !           942:                        if (searchKey->startBlock == trialKey->startBlock) {
        !           943:                                //
        !           944:                                //      Everything is equal
        !           945:                                //
        !           946:                                result = 0;
        !           947:                        }
        !           948:                        else {
        !           949:                                //
        !           950:                                //      Allocation block numbers differ; determine sign
        !           951:                                //
        !           952:                                if (searchKey->startBlock > trialKey->startBlock)
        !           953:                                        result = 1;
        !           954:                        }
        !           955:                }
        !           956:                else {
        !           957:                        //
        !           958:                        //      Fork types differ; determine sign
        !           959:                        //
        !           960:                        if (searchKey->forkType > trialKey->forkType)
        !           961:                                result = 1;
        !           962:                }
        !           963:        }
        !           964:        else {
        !           965:                //
        !           966:                //      FileNums differ; determine sign
        !           967:                //
        !           968:                if (searchKey->fileID > trialKey->fileID)
        !           969:                        result = 1;
        !           970:        }
        !           971:        
        !           972:        return( result );
        !           973: }
        !           974: 
        !           975: 
        !           976: 
        !           977: //�������������������������������������������������������������������������������
        !           978: //     Routine:        CompareExtentKeysPlus
        !           979: //
        !           980: //     Function:       Compares two extent file keys (a search key and a trial key) for
        !           981: //                             an HFS volume.
        !           982: //�������������������������������������������������������������������������������
        !           983: 
        !           984: SInt32 CompareExtentKeysPlus( const HFSPlusExtentKey *searchKey, const HFSPlusExtentKey *trialKey )
        !           985: {
        !           986:        SInt32  result;         //      � 1
        !           987:        
        !           988:        #if DEBUG_BUILD
        !           989:                if (searchKey->keyLength != kHFSPlusExtentKeyMaximumLength)
        !           990:                        DebugStr("\pHFS: search Key is wrong length");
        !           991:                if (trialKey->keyLength != kHFSPlusExtentKeyMaximumLength)
        !           992:                        DebugStr("\pHFS: trial Key is wrong length");
        !           993:        #endif
        !           994:        
        !           995:        result = -1;            //      assume searchKey < trialKey
        !           996:        
        !           997:        if (searchKey->fileID == trialKey->fileID) {
        !           998:                //
        !           999:                //      FileNum's are equal; compare fork types
        !          1000:                //
        !          1001:                if (searchKey->forkType == trialKey->forkType) {
        !          1002:                        //
        !          1003:                        //      Fork types are equal; compare allocation block number
        !          1004:                        //
        !          1005:                        if (searchKey->startBlock == trialKey->startBlock) {
        !          1006:                                //
        !          1007:                                //      Everything is equal
        !          1008:                                //
        !          1009:                                result = 0;
        !          1010:                        }
        !          1011:                        else {
        !          1012:                                //
        !          1013:                                //      Allocation block numbers differ; determine sign
        !          1014:                                //
        !          1015:                                if (searchKey->startBlock > trialKey->startBlock)
        !          1016:                                        result = 1;
        !          1017:                        }
        !          1018:                }
        !          1019:                else {
        !          1020:                        //
        !          1021:                        //      Fork types differ; determine sign
        !          1022:                        //
        !          1023:                        if (searchKey->forkType > trialKey->forkType)
        !          1024:                                result = 1;
        !          1025:                }
        !          1026:        }
        !          1027:        else {
        !          1028:                //
        !          1029:                //      FileNums differ; determine sign
        !          1030:                //
        !          1031:                if (searchKey->fileID > trialKey->fileID)
        !          1032:                        result = 1;
        !          1033:        }
        !          1034:        
        !          1035:        return( result );
        !          1036: }
        !          1037: 
        !          1038: 
        !          1039: 
        !          1040: //_________________________________________________________________________________
        !          1041: //
        !          1042: // Routine:            Extendfile
        !          1043: //
        !          1044: // Function:   Extends the disk space allocated to a file.
        !          1045: //
        !          1046: // Input:              A2.L  -  VCB pointer
        !          1047: //                             A1.L  -  pointer to FCB array
        !          1048: //                             D1.W  -  file refnum
        !          1049: //                             D3.B  -  option flags
        !          1050: //                                                     kEFContigMask - force contiguous allocation
        !          1051: //                                                     kEFAllMask - allocate all requested bytes or none
        !          1052: //                                                     NOTE: You may not set both options.
        !          1053: //                             D4.L  -  number of additional bytes to allocate
        !          1054: //
        !          1055: // Output:             D0.W  -  result code
        !          1056: //                                                      0 = ok
        !          1057: //                                                      -n = IO error
        !          1058: //                             D6.L  -  number of bytes allocated
        !          1059: //
        !          1060: // Called by:  FileAloc,FileWrite,SetEof
        !          1061: //
        !          1062: // Note:               ExtendFile updates the PEOF in the FCB.
        !          1063: //_________________________________________________________________________________
        !          1064: 
        !          1065: OSErr ExtendFileC (
        !          1066:        ExtendedVCB             *vcb,                           // volume that file resides on
        !          1067:        FCB                             *fcb,                           // FCB of file to truncate
        !          1068:        UInt32                  bytesToAdd,                     // number of bytes to allocate
        !          1069:        UInt32                  flags,                          // EFContig and/or EFAll
        !          1070:        UInt32                  *actualBytesAdded)      // number of bytes actually allocated
        !          1071: {
        !          1072:        OSErr                           err;
        !          1073:        UInt32                          volumeBlockSize;
        !          1074:        UInt32                          blocksToAdd;
        !          1075:        UInt32                          peof;
        !          1076:        UInt32                          bytesThisExtent;
        !          1077:        HFSPlusExtentKey        foundKey;
        !          1078:        HFSPlusExtentRecord     foundData;
        !          1079:        UInt32                          foundIndex;
        !          1080:        UInt32                          hint;
        !          1081:        UInt32                          nextBlock;
        !          1082:        UInt32                          startBlock;
        !          1083:        Boolean                         allOrNothing;
        !          1084:        Boolean                         forceContig;
        !          1085:        Boolean                         wantContig;
        !          1086:        UInt32                          actualStartBlock;
        !          1087:        UInt32                          actualNumBlocks;
        !          1088:        UInt32                          previousPEOF;
        !          1089:        UInt32                          numExtentsPerRecord;
        !          1090:        UInt32                          maximumBytes;
        !          1091:        
        !          1092: 
        !          1093: #if HFSInstrumentation
        !          1094:        InstTraceClassRef       trace;
        !          1095:        InstEventTag            eventTag;
        !          1096:        InstDataDescriptorRef   traceDescriptor;
        !          1097:        FSVarsRec                       *fsVars = (FSVarsRec *) LMGetFSMVars();
        !          1098: 
        !          1099:        traceDescriptor = (InstDataDescriptorRef) fsVars->later[2];
        !          1100:        
        !          1101:        err = InstCreateTraceClass(kInstRootClassRef, "HFS:Extents:ExtendFileC", 'hfs+', kInstEnableClassMask, &trace);
        !          1102:        if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
        !          1103: 
        !          1104:        eventTag = InstCreateEventTag();
        !          1105:        InstLogTraceEvent( trace, eventTag, kInstStartEvent);
        !          1106: #endif
        !          1107: 
        !          1108:        *actualBytesAdded = 0;
        !          1109:        volumeBlockSize = vcb->blockSize;
        !          1110:        allOrNothing = ((flags & kEFAllMask) != 0);
        !          1111:        forceContig = ((flags & kEFContigMask) != 0);
        !          1112:        previousPEOF = fcb->fcbPLen;
        !          1113: 
        !          1114:        if (vcb->vcbSigWord == kHFSPlusSigWord)
        !          1115:                numExtentsPerRecord = kHFSPlusExtentDensity;
        !          1116:        else
        !          1117:                numExtentsPerRecord = kHFSExtentDensity;
        !          1118: 
        !          1119:        //
        !          1120:        //      Make sure the request and new PEOF are less than 2GB.
        !          1121:        //
        !          1122:        if (bytesToAdd >= (UInt32) kTwoGigabytes)
        !          1123:                goto Overflow;
        !          1124:        if ((fcb->fcbPLen + bytesToAdd) >= (UInt32) kTwoGigabytes)
        !          1125:                goto Overflow;
        !          1126:        //
        !          1127:        //      Determine how many blocks need to be allocated.
        !          1128:        //      Round up the number of desired bytes to add.
        !          1129:        //
        !          1130:        blocksToAdd = DivideAndRoundUp(bytesToAdd, volumeBlockSize);
        !          1131:        bytesToAdd = blocksToAdd * volumeBlockSize;
        !          1132:        
        !          1133:        //
        !          1134:        //      If the file's clump size is larger than the allocation block size,
        !          1135:        //      then set the maximum number of bytes to the requested number of bytes
        !          1136:        //      rounded up to a multiple of the clump size.
        !          1137:        //
        !          1138:        if (fcb->fcbClmpSize > volumeBlockSize) {
        !          1139:                maximumBytes = DivideAndRoundUp(bytesToAdd, fcb->fcbClmpSize);
        !          1140:                maximumBytes *= fcb->fcbClmpSize;
        !          1141:        }
        !          1142:        else {
        !          1143:                maximumBytes = bytesToAdd;
        !          1144:        }
        !          1145:        
        !          1146:        //
        !          1147:        //      Compute new physical EOF, rounded up to a multiple of a block.
        !          1148:        //
        !          1149:        if ((fcb->fcbPLen + bytesToAdd) >= (UInt32) kTwoGigabytes)      //      Too big?
        !          1150:                if (allOrNothing)                                       // Yes, must they have it all?
        !          1151:                        goto Overflow;                                          // Yes, can't have it
        !          1152:                else {
        !          1153:                        --blocksToAdd;                                          // No, give give 'em one block less
        !          1154:                        bytesToAdd -= volumeBlockSize;
        !          1155:                }
        !          1156: 
        !          1157:        //
        !          1158:        //      If allocation is all-or-nothing, make sure there are
        !          1159:        //      enough free blocks on the volume (quick test).
        !          1160:        //
        !          1161:        if (allOrNothing && blocksToAdd > vcb->freeBlocks) {
        !          1162:                err = dskFulErr;
        !          1163:                goto ErrorExit;
        !          1164:        }
        !          1165:        
        !          1166:        //
        !          1167:        //      See if there are already enough blocks allocated to the file.
        !          1168:        //
        !          1169:        peof = fcb->fcbPLen + bytesToAdd;                       // potential new PEOF
        !          1170:        err = SearchExtentFile(vcb, fcb, peof-1, &foundKey, foundData, &foundIndex, &hint, &nextBlock);
        !          1171:        if (err == noErr) {
        !          1172:                //      Enough blocks are already allocated.  Just update the FCB to reflect the new length.
        !          1173:                fcb->fcbPLen = peof;
        !          1174:                fcb->fcbFlags |= fcbModifiedMask;
        !          1175:                goto Exit;
        !          1176:        }
        !          1177:        if (err != fxRangeErr)          // Any real error?
        !          1178:                goto ErrorExit;                         // Yes, so exit immediately
        !          1179: 
        !          1180:        //
        !          1181:        //      Adjust the PEOF to the end of the last extent.
        !          1182:        //
        !          1183:        peof = nextBlock * volumeBlockSize;                     // currently allocated PEOF
        !          1184:        bytesThisExtent = peof - fcb->fcbPLen;
        !          1185:        if (bytesThisExtent != 0) {
        !          1186:                fcb->fcbPLen = peof;
        !          1187:                fcb->fcbFlags |= fcbModifiedMask;
        !          1188:                bytesToAdd -= bytesThisExtent;
        !          1189:        }
        !          1190:        
        !          1191:        //
        !          1192:        //      Allocate some more space.
        !          1193:        //
        !          1194:        //      First try a contiguous allocation (of the whole amount).
        !          1195:        //      If that fails, get whatever we can.
        !          1196:        //              If forceContig, then take whatever we got
        !          1197:        //              else, keep getting bits and pieces (non-contig)
        !          1198:        err = noErr;
        !          1199:        wantContig = true;
        !          1200:        do {
        !          1201:                startBlock = foundData[foundIndex].startBlock + foundData[foundIndex].blockCount;
        !          1202:                err = BlockAllocate(vcb, startBlock, bytesToAdd, maximumBytes, wantContig, &actualStartBlock, &actualNumBlocks);
        !          1203:                if (err == dskFulErr) {
        !          1204:                        if (forceContig)
        !          1205:                                break;                  // AllocContig failed because not enough contiguous space
        !          1206:                        if (wantContig) {
        !          1207:                                //      Couldn't get one big chunk, so get whatever we can.
        !          1208:                                err = noErr;
        !          1209:                                wantContig = false;
        !          1210:                                continue;
        !          1211:                        }
        !          1212:                        if (actualNumBlocks != 0)
        !          1213:                                err = noErr;
        !          1214:                }
        !          1215:                if (err == noErr) {
        !          1216: #if HFSInstrumentation
        !          1217:                        {
        !          1218:                                struct {
        !          1219:                                        UInt32  fileID;
        !          1220:                                        UInt32  start;
        !          1221:                                        UInt32  count;
        !          1222:                                        UInt32  fabn;
        !          1223:                                } x;
        !          1224:                                
        !          1225:                                x.fileID = fcb->fcbFlNm;
        !          1226:                                x.start = actualStartBlock;
        !          1227:                                x.count = actualNumBlocks;
        !          1228:                                x.fabn = nextBlock;
        !          1229:                                
        !          1230:                                InstLogTraceEventWithDataStructure( trace, eventTag, kInstMiddleEvent, traceDescriptor,
        !          1231:                                                                                                        (UInt8 *) &x, sizeof(x));
        !          1232:                        }
        !          1233: #endif
        !          1234:                        //      Add the new extent to the existing extent record, or create a new one.
        !          1235:                        if (actualStartBlock == startBlock) {
        !          1236:                                //      We grew the file's last extent, so just adjust the number of blocks.
        !          1237:                                foundData[foundIndex].blockCount += actualNumBlocks;
        !          1238:                                err = UpdateExtentRecord(vcb, fcb, &foundKey, foundData, hint);
        !          1239:                                if (err != noErr) break;
        !          1240:                        }
        !          1241:                        else {
        !          1242:                                UInt16  i;
        !          1243: 
        !          1244:                                //      Need to add a new extent.  See if there is room in the current record.
        !          1245:                                if (foundData[foundIndex].blockCount != 0)      //      Is current extent free to use?
        !          1246:                                        ++foundIndex;                                                   //      No, so use the next one.
        !          1247:                                if (foundIndex == numExtentsPerRecord) {
        !          1248:                                        //      This record is full.  Need to create a new one.
        !          1249:                                        if (fcb->fcbFlNm == kHFSExtentsFileID) {
        !          1250:                                                err = fxOvFlErr;                // Oops.  Can't extend extents file (?? really ??)
        !          1251:                                                break;
        !          1252:                                        }
        !          1253:                                        
        !          1254:                                        foundKey.keyLength = kHFSPlusExtentKeyMaximumLength;
        !          1255:                                        if (fcb->fcbFlags & fcbResourceMask)
        !          1256:                                                foundKey.forkType = kResourceForkType;
        !          1257:                                        else
        !          1258:                                                foundKey.forkType = kDataForkType;
        !          1259:                                        foundKey.pad = 0;
        !          1260:                                        foundKey.fileID = fcb->fcbFlNm;
        !          1261:                                        foundKey.startBlock = nextBlock;
        !          1262:                                        
        !          1263:                                        foundData[0].startBlock = actualStartBlock;
        !          1264:                                        foundData[0].blockCount = actualNumBlocks;
        !          1265:                                        
        !          1266:                                        // zero out remaining extents...
        !          1267:                                        for (i = 1; i < kHFSPlusExtentDensity; ++i)
        !          1268:                                        {
        !          1269:                                                foundData[i].startBlock = 0;
        !          1270:                                                foundData[i].blockCount = 0;
        !          1271:                                        }
        !          1272: 
        !          1273:                                        foundIndex = 0;
        !          1274:                                        
        !          1275:                                        err = CreateExtentRecord(vcb, &foundKey, foundData, &hint);
        !          1276:                                        if (err != noErr) break;
        !          1277:                                }
        !          1278:                                else {
        !          1279:                                        //      Add a new extent into this record and update.
        !          1280:                                        foundData[foundIndex].startBlock = actualStartBlock;
        !          1281:                                        foundData[foundIndex].blockCount = actualNumBlocks;
        !          1282:                                        err = UpdateExtentRecord(vcb, fcb, &foundKey, foundData, hint);
        !          1283:                                        if (err != noErr) break;
        !          1284:                                }
        !          1285:                        }
        !          1286:                        
        !          1287:                        // Figure out how many bytes were actually allocated.
        !          1288:                        // NOTE: BlockAllocate could have allocated more than we asked for.
        !          1289:                        // Don't set the PEOF beyond what our client asked for.
        !          1290:                        nextBlock += actualNumBlocks;
        !          1291:                        bytesThisExtent = actualNumBlocks * volumeBlockSize;
        !          1292:                        if (bytesThisExtent > bytesToAdd) {
        !          1293:                                if (TARGET_OS_RHAPSODY)
        !          1294:                                        fcb->fcbPLen += bytesThisExtent;        /* don't lie about the peof in Rhapsody */
        !          1295:                                else
        !          1296:                                        fcb->fcbPLen += bytesToAdd;                     /* Mac OS semantics support lying (peof <= sum of extents) */
        !          1297:                                bytesToAdd = 0;
        !          1298:                        }
        !          1299:                        else {
        !          1300:                                bytesToAdd -= bytesThisExtent;
        !          1301:                                maximumBytes -= bytesThisExtent;
        !          1302:                                fcb->fcbPLen += bytesThisExtent;
        !          1303:                        }
        !          1304:                        fcb->fcbFlags |= fcbModifiedMask;
        !          1305: 
        !          1306:                        //      If contiguous allocation was requested, then we've already got one contiguous
        !          1307:                        //      chunk.  If we didn't get all we wanted, then adjust the error to disk full.
        !          1308:                        if (forceContig) {
        !          1309:                                if (bytesToAdd != 0)
        !          1310:                                        err = dskFulErr;
        !          1311:                                break;                  //      We've already got everything that's contiguous
        !          1312:                        }
        !          1313:                }
        !          1314:        } while (err == noErr && bytesToAdd);
        !          1315: 
        !          1316: ErrorExit:
        !          1317: Exit:
        !          1318:        *actualBytesAdded = fcb->fcbPLen - previousPEOF;
        !          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:        UInt32                  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:        
        !          1376: #if HFSInstrumentation
        !          1377:        InstTraceClassRef       trace;
        !          1378:        InstEventTag            eventTag;
        !          1379:        InstDataDescriptorRef   traceDescriptor;
        !          1380:        FSVarsRec                       *fsVars = (FSVarsRec *) LMGetFSMVars();
        !          1381: 
        !          1382:        traceDescriptor = (InstDataDescriptorRef) fsVars->later[2];
        !          1383:        
        !          1384:        err = InstCreateTraceClass(kInstRootClassRef, "HFS:Extents:TruncateFileC", 'hfs+', kInstEnableClassMask, &trace);
        !          1385:        if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
        !          1386: 
        !          1387:        eventTag = InstCreateEventTag();
        !          1388:        InstLogTraceEvent( trace, eventTag, kInstStartEvent);
        !          1389: #endif
        !          1390: 
        !          1391:        if (vcb->vcbSigWord == kHFSPlusSigWord)
        !          1392:                numExtentsPerRecord = kHFSPlusExtentDensity;
        !          1393:        else
        !          1394:                numExtentsPerRecord = kHFSExtentDensity;
        !          1395: 
        !          1396:        if (fcb->fcbFlags & fcbResourceMask)
        !          1397:                forkType = kResourceForkType;
        !          1398:        else
        !          1399:                forkType = kDataForkType;
        !          1400: 
        !          1401:        physNumBlocks = fcb->fcbPLen / vcb->blockSize;          // number of allocation blocks currently in file
        !          1402: 
        !          1403:        //
        !          1404:        //      Round newPEOF up to a multiple of the allocation block size.  If new size is
        !          1405:        //      two gigabytes or more, then round down by one allocation block (??? really?
        !          1406:        //      shouldn't that be an error?).
        !          1407:        //
        !          1408:        nextBlock = DivideAndRoundUp(peof, vcb->blockSize);     // number of allocation blocks to remain in file
        !          1409:        peof = nextBlock * vcb->blockSize;                                      // number of bytes in those blocks
        !          1410:        if (peof >= (UInt32) kTwoGigabytes) {
        !          1411:                #if DEBUG_BUILD
        !          1412:                        DebugStr("\pHFS: Trying to truncate a file to 2GB or more");
        !          1413:                #endif
        !          1414:                err = fileBoundsErr;
        !          1415:                goto ErrorExit;
        !          1416:        }
        !          1417: 
        !          1418:        //
        !          1419:        //      Update FCB's length
        !          1420:        //
        !          1421:        fcb->fcbPLen = peof;
        !          1422:        fcb->fcbFlags |= fcbModifiedMask;
        !          1423:        
        !          1424:        //
        !          1425:        //      If the new PEOF is 0, then truncateToExtent has no meaning (we should always deallocate
        !          1426:        //      all storage).
        !          1427:        //
        !          1428:        if (peof == 0) {
        !          1429:                int i;
        !          1430:                
        !          1431:                //      Find the catalog extent record
        !          1432:                err = GetFCBExtentRecord(vcb, fcb, extentRecord);
        !          1433:                if (err != noErr) goto ErrorExit;       //      got some error, so return it
        !          1434:                
        !          1435:                //      Deallocate all the extents for this fork
        !          1436:                err = DeallocateFork(vcb, fcb->fcbFlNm, forkType, extentRecord);
        !          1437:                if (err != noErr) goto ErrorExit;       //      got some error, so return it
        !          1438:                
        !          1439:                //      Update the catalog extent record (making sure it's zeroed out)
        !          1440:                if (err == noErr) {
        !          1441:                        for (i=0; i < numExtentsPerRecord; i++) {
        !          1442:                                extentRecord[i].startBlock = 0;
        !          1443:                                extentRecord[i].blockCount = 0;
        !          1444:                        }
        !          1445:                }
        !          1446:                err = SetFCBExtentRecord(vcb, fcb, extentRecord);
        !          1447:                goto Done;
        !          1448:        }
        !          1449:        
        !          1450:        //
        !          1451:        //      Find the extent containing byte (peof-1).  This is the last extent we'll keep.
        !          1452:        //      (If truncateToExtent is true, we'll keep the whole extent; otherwise, we'll only
        !          1453:        //      keep up through peof).  The search will tell us how many allocation blocks exist
        !          1454:        //      in the found extent plus all previous extents.
        !          1455:        //
        !          1456:        err = SearchExtentFile(vcb, fcb, peof-1, &key, extentRecord, &extentIndex, &hint, &extentNextBlock);
        !          1457:        if (err != noErr) goto ErrorExit;
        !          1458: 
        !          1459:        extentChanged = false;          //      haven't changed the extent yet
        !          1460:        
        !          1461:        if (!truncateToExtent) {
        !          1462:                //
        !          1463:                //      Shorten this extent.  It may be the case that the entire extent gets
        !          1464:                //      freed here.
        !          1465:                //
        !          1466:                numBlocks = extentNextBlock - nextBlock;        //      How many blocks in this extent to free up
        !          1467:                if (numBlocks != 0) {
        !          1468:                        //      Compute first volume allocation block to free
        !          1469:                        startBlock = extentRecord[extentIndex].startBlock + extentRecord[extentIndex].blockCount - numBlocks;
        !          1470:                        //      Free the blocks in bitmap
        !          1471:                        err = BlockDeallocate(vcb, startBlock, numBlocks);
        !          1472:                        if (err != noErr) goto ErrorExit;
        !          1473:                        //      Adjust length of this extent
        !          1474:                        extentRecord[extentIndex].blockCount -= numBlocks;
        !          1475:                        //      If extent is empty, set start block to 0
        !          1476:                        if (extentRecord[extentIndex].blockCount == 0)
        !          1477:                                extentRecord[extentIndex].startBlock = 0;
        !          1478:                        //      Remember that we changed the extent record
        !          1479:                        extentChanged = true;
        !          1480:                }
        !          1481:        }
        !          1482:        
        !          1483:        //
        !          1484:        //      Now move to the next extent in the record, and set up the file allocation block number
        !          1485:        //
        !          1486:        nextBlock = extentNextBlock;            //      Next file allocation block to free
        !          1487:        ++extentIndex;                                          //      Its index within the extent record
        !          1488:        
        !          1489:        //
        !          1490:        //      Release all following extents in this extent record.  Update the record.
        !          1491:        //
        !          1492:        while (extentIndex < numExtentsPerRecord && extentRecord[extentIndex].blockCount != 0) {
        !          1493:                numBlocks = extentRecord[extentIndex].blockCount;
        !          1494:                //      Deallocate this extent
        !          1495:                err = BlockDeallocate(vcb, extentRecord[extentIndex].startBlock, numBlocks);
        !          1496:                if (err != noErr) goto ErrorExit;
        !          1497:                //      Update next file allocation block number
        !          1498:                nextBlock += numBlocks;
        !          1499:                //      Zero out start and length of this extent to delete it from record
        !          1500:                extentRecord[extentIndex].startBlock = 0;
        !          1501:                extentRecord[extentIndex].blockCount = 0;
        !          1502:                //      Remember that we changed an extent
        !          1503:                extentChanged = true;
        !          1504:                //      Move to next extent in record
        !          1505:                ++extentIndex;
        !          1506:        }
        !          1507:        
        !          1508:        //
        !          1509:        //      If any of the extents in the current record were changed, then update that
        !          1510:        //      record (in the FCB, or extents file).
        !          1511:        //
        !          1512:        if (extentChanged) {
        !          1513:                err = UpdateExtentRecord(vcb, fcb, &key, extentRecord, hint);
        !          1514:                if (err != noErr) goto ErrorExit;
        !          1515:        }
        !          1516:        
        !          1517:        //
        !          1518:        //      If there are any following allocation blocks, then we need
        !          1519:        //      to seach for their extent records and delete those allocation
        !          1520:        //      blocks.
        !          1521:        //
        !          1522:        if (nextBlock < physNumBlocks)
        !          1523:                err = TruncateExtents(vcb, forkType, fcb->fcbFlNm, nextBlock);
        !          1524: 
        !          1525: Done:
        !          1526: ErrorExit:
        !          1527: 
        !          1528: #if HFSInstrumentation
        !          1529:        InstLogTraceEvent( trace, eventTag, kInstEndEvent);
        !          1530: #endif
        !          1531: 
        !          1532:        return err;
        !          1533: }
        !          1534: 
        !          1535: 
        !          1536: 
        !          1537: //�������������������������������������������������������������������������������
        !          1538: //     Routine:        SearchExtentRecord (was XRSearch)
        !          1539: //
        !          1540: //     Function:       Searches extent record for the extent mapping a given file
        !          1541: //                             allocation block number (FABN).
        !          1542: //
        !          1543: //     Input:          searchFABN                      -  desired FABN
        !          1544: //                             extentData                      -  pointer to extent data record (xdr)
        !          1545: //                             extentDataStartFABN     -  beginning FABN for extent record
        !          1546: //
        !          1547: //     Output:         foundExtentDataOffset  -  offset to extent entry within xdr
        !          1548: //                                                     result = noErr, offset to extent mapping desired FABN
        !          1549: //                                                     result = FXRangeErr, offset to last extent in record
        !          1550: //                             endingFABNPlusOne       -  ending FABN +1
        !          1551: //                             noMoreExtents           - True if the extent was not found, and the
        !          1552: //                                                                       extent record was not full (so don't bother
        !          1553: //                                                                       looking in subsequent records); false otherwise.
        !          1554: //
        !          1555: //     Result:         noErr = ok
        !          1556: //                             FXRangeErr = desired FABN > last mapped FABN in record
        !          1557: //�������������������������������������������������������������������������������
        !          1558: 
        !          1559: static OSErr SearchExtentRecord(
        !          1560:        const ExtendedVCB               *vcb,
        !          1561:        UInt32                                  searchFABN,
        !          1562:        const HFSPlusExtentRecord       extentData,
        !          1563:        UInt32                                  extentDataStartFABN,
        !          1564:        UInt32                                  *foundExtentIndex,
        !          1565:        UInt32                                  *endingFABNPlusOne,
        !          1566:        Boolean                                 *noMoreExtents)
        !          1567: {
        !          1568:        OSErr   err = noErr;
        !          1569:        UInt32  extentIndex;
        !          1570:        UInt32  numberOfExtents;
        !          1571:        UInt32  numAllocationBlocks;
        !          1572:        Boolean foundExtent;
        !          1573:        
        !          1574:        *endingFABNPlusOne      = extentDataStartFABN;
        !          1575:        *noMoreExtents          = false;
        !          1576:        foundExtent                     = false;
        !          1577: 
        !          1578:        if (vcb->vcbSigWord == kHFSPlusSigWord)
        !          1579:                numberOfExtents = kHFSPlusExtentDensity;
        !          1580:        else
        !          1581:                numberOfExtents = kHFSExtentDensity;
        !          1582:        
        !          1583:        for( extentIndex = 0; extentIndex < numberOfExtents; ++extentIndex )
        !          1584:        {
        !          1585:                
        !          1586:                // Loop over the extent record and find the search FABN.
        !          1587:                
        !          1588:                numAllocationBlocks = extentData[extentIndex].blockCount;
        !          1589:                if ( numAllocationBlocks == 0 )
        !          1590:                {
        !          1591:                        break;
        !          1592:                }
        !          1593: 
        !          1594:                *endingFABNPlusOne += numAllocationBlocks;
        !          1595:                
        !          1596:                if( searchFABN < *endingFABNPlusOne )
        !          1597:                {
        !          1598:                        // Found the extent.
        !          1599:                        foundExtent = true;
        !          1600:                        break;
        !          1601:                }
        !          1602:        }
        !          1603:        
        !          1604:        if( foundExtent )
        !          1605:        {
        !          1606:                // Found the extent. Note the extent offset
        !          1607:                *foundExtentIndex = extentIndex;
        !          1608:        }
        !          1609:        else
        !          1610:        {
        !          1611:                // Did not find the extent. Set foundExtentDataOffset accordingly
        !          1612:                if( extentIndex > 0 )
        !          1613:                {
        !          1614:                        *foundExtentIndex = extentIndex - 1;
        !          1615:                }
        !          1616:                else
        !          1617:                {
        !          1618:                        *foundExtentIndex = 0;
        !          1619:                }
        !          1620:                
        !          1621:                // If we found an empty extent, then set noMoreExtents.
        !          1622:                if (extentIndex < numberOfExtents)
        !          1623:                        *noMoreExtents = true;
        !          1624: 
        !          1625:                // Finally, return an error to the caller
        !          1626:                err = fxRangeErr;
        !          1627:        }
        !          1628: 
        !          1629:        return( err );
        !          1630: }
        !          1631: 
        !          1632: //�������������������������������������������������������������������������������
        !          1633: //     Routine:        SearchExtentFile (was XFSearch)
        !          1634: //
        !          1635: //     Function:       Searches extent file (including the FCB resident extent record)
        !          1636: //                             for the extent mapping a given file position.
        !          1637: //
        !          1638: //     Input:          vcb                     -  VCB pointer
        !          1639: //                             fcb                     -  FCB pointer
        !          1640: //                             filePosition    -  file position (byte address)
        !          1641: //
        !          1642: // Output:             foundExtentKey                  -  extent key record (xkr)
        !          1643: //                                                     If extent was found in the FCB's resident extent record,
        !          1644: //                                                     then foundExtentKey->keyLength will be set to 0.
        !          1645: //                             foundExtentData                 -  extent data record(xdr)
        !          1646: //                             foundExtentIndex        -  index to extent entry in xdr
        !          1647: //                                                     result =  0, offset to extent mapping desired FABN
        !          1648: //                                                     result = FXRangeErr, offset to last extent in record
        !          1649: //                                                                      (i.e., kNumExtentsPerRecord-1)
        !          1650: //                             extentBTreeHint                 -  BTree hint for extent record
        !          1651: //                                                     kNoHint = Resident extent record
        !          1652: //                             endingFABNPlusOne               -  ending FABN +1
        !          1653: //
        !          1654: //     Result:
        !          1655: //             noErr                   Found an extent that contains the given file position
        !          1656: //             FXRangeErr              Given position is beyond the last allocated extent
        !          1657: //             (other)                 (some other internal I/O error)
        !          1658: //�������������������������������������������������������������������������������
        !          1659: 
        !          1660: static OSErr SearchExtentFile(
        !          1661:        const ExtendedVCB       *vcb,
        !          1662:        const FCB                       *fcb,
        !          1663:        UInt32                          filePosition,
        !          1664:        HFSPlusExtentKey        *foundExtentKey,
        !          1665:        HFSPlusExtentRecord     foundExtentData,
        !          1666:        UInt32                          *foundExtentIndex,
        !          1667:        UInt32                          *extentBTreeHint,
        !          1668:        UInt32                          *endingFABNPlusOne )
        !          1669: {
        !          1670:        OSErr                           err;
        !          1671:        UInt32                          filePositionBlock;
        !          1672:        Boolean                         noMoreExtents;
        !          1673:        
        !          1674:        filePositionBlock = filePosition / vcb->blockSize;
        !          1675:        
        !          1676:        //      Search the resident FCB first.
        !          1677:        err = GetFCBExtentRecord(vcb, fcb, foundExtentData);
        !          1678:        if (err == noErr)
        !          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:                                                   fcb->fcbFlNm, 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(vcb, 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;
        !          1769:        
        !          1770:        if (extentFileKey->keyLength == 0) {    // keyLength == 0 means the FCB's extent record
        !          1771:                err = SetFCBExtentRecord(vcb, fcb, extentData);
        !          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 = ExtentsToExtDataRec(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: static void ExtDataRecToExtents(
        !          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: static OSErr ExtentsToExtDataRec(
        !          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: #if TARGET_OS_MAC
        !          1886: OSErr GrowParallelFCBs(void)
        !          1887: {
        !          1888:        ParallelFCB     *parallelFCBs;
        !          1889:        ParallelFCB     *newParallel;
        !          1890:        char            *oldData;
        !          1891:        char            *newData;
        !          1892:        UInt32          i;
        !          1893:        UInt32          count;
        !          1894:        UInt32          oldSize;
        !          1895:        
        !          1896:        //
        !          1897:        //      Get header for parallel FCB array
        !          1898:        //
        !          1899:        parallelFCBs = ((FSVarsRec *) LMGetFSMVars())->fcbPBuf;
        !          1900:        
        !          1901:        //
        !          1902:        //      See if the array needs to grow
        !          1903:        //
        !          1904:        if (parallelFCBs->unitSize < sizeof(ExtendedFCB)) {
        !          1905:                //
        !          1906:                //      Get the size and count from existing array
        !          1907:                //
        !          1908:                count = parallelFCBs->count;
        !          1909:                oldSize = parallelFCBs->unitSize;
        !          1910:                oldData = (char *) &parallelFCBs->extendedFCB[0];
        !          1911:                
        !          1912:                //
        !          1913:                //      Allocate the new array
        !          1914:                //
        !          1915:                newParallel = (ParallelFCB *) NewPtrSysClear(offsetof(ParallelFCB, extendedFCB[count]));
        !          1916:                if (newParallel == NULL)
        !          1917:                        return memFullErr;
        !          1918:                
        !          1919:                //
        !          1920:                //      Initialize the header of the new array
        !          1921:                //
        !          1922:                newParallel->count = count;
        !          1923:                newParallel->unitSize = sizeof(ExtendedFCB);
        !          1924:                newData = (char *) &newParallel->extendedFCB[0];
        !          1925:                
        !          1926:                //
        !          1927:                //      Copy the existing data into the new array
        !          1928:                //
        !          1929:                for (i=0; i<count; i++) {
        !          1930:                        BlockMoveData(oldData, newData, oldSize);       // copy the old data into new array
        !          1931:                        oldData += oldSize;
        !          1932:                        newData += sizeof(ExtendedFCB);
        !          1933:                }
        !          1934:                
        !          1935:                //
        !          1936:                //      Install the new array and deallocate the old one
        !          1937:                //
        !          1938:                ((FSVarsRec *) LMGetFSMVars())->fcbPBuf = newParallel;
        !          1939:                DisposePtr((Ptr) parallelFCBs);
        !          1940:        }
        !          1941: 
        !          1942:        return noErr;
        !          1943: }
        !          1944: #endif
        !          1945: 
        !          1946: 
        !          1947: 
        !          1948: static ExtendedFCB *GetExtendedFCB(const FCB *fcb)
        !          1949: {
        !          1950: #if TARGET_OS_MAC
        !          1951:        ParallelFCB     *parallelFCBs;
        !          1952:        UInt32          index;
        !          1953:        
        !          1954:        //
        !          1955:        //      First, turn the FCB pointer into an index into the FCB table
        !          1956:        //
        !          1957:        index = (((UInt32) fcb) - ((UInt32) LMGetFCBSPtr())) / sizeof(FCB);
        !          1958:        
        !          1959:        //
        !          1960:        //      Get header for parallel FCB array
        !          1961:        //
        !          1962:        parallelFCBs = ((FSVarsRec *) LMGetFSMVars())->fcbPBuf;
        !          1963:        
        !          1964:        //
        !          1965:        //      Make sure parallel FCBs are big enough
        !          1966:        //
        !          1967:        #if DEBUG_BUILD
        !          1968:                if (parallelFCBs->unitSize < sizeof(ExtendedFCB)) {
        !          1969:                        DebugStr("\pFATAL: Parallel FCBs are too small!");
        !          1970:                        return NULL;
        !          1971:                }
        !          1972:        #endif
        !          1973:        //
        !          1974:        //      Finally, return a pointer to the index'th element of
        !          1975:        //      the parallel FCB array.
        !          1976:        //
        !          1977:        return &(parallelFCBs->extendedFCB[index]);
        !          1978: #else
        !          1979:         return &(((struct vfsFCB *)(fcb))->fcb_extFCB);
        !          1980: #endif
        !          1981: }
        !          1982: 
        !          1983: 
        !          1984: 
        !          1985: 
        !          1986: OSErr GetFCBExtentRecord(
        !          1987:        const ExtendedVCB       *vcb,
        !          1988:        const FCB                       *fcb,
        !          1989:        HFSPlusExtentRecord     extents)
        !          1990: {
        !          1991:        OSErr                           err;
        !          1992:        ExtendedFCB                     *extendedFCB;
        !          1993: 
        !          1994:        err = noErr;
        !          1995:        
        !          1996:        if (vcb->vcbSigWord == kHFSSigWord) {
        !          1997:                ExtDataRecToExtents(fcb->fcbExtRec, extents);
        !          1998:        }
        !          1999:        else {
        !          2000:                extendedFCB = GetExtendedFCB(fcb);
        !          2001:                BlockMoveData(extendedFCB->extents, extents, sizeof(HFSPlusExtentRecord));
        !          2002:        }
        !          2003:        
        !          2004:        return err;
        !          2005: }
        !          2006: 
        !          2007: 
        !          2008: 
        !          2009: static OSErr SetFCBExtentRecord(
        !          2010:        const ExtendedVCB               *vcb,
        !          2011:        FCB                                             *fcb,
        !          2012:        const HFSPlusExtentRecord       extents)
        !          2013: {
        !          2014:        OSErr           err;
        !          2015:        Boolean         isHFSPlus;
        !          2016:        UInt32          fileNum;
        !          2017:        ExtendedFCB     *extendedFCB;
        !          2018:        UInt8           resourceFlag;           //      fcbResourceMask bit from fcbFlags
        !          2019:        
        !          2020:        isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
        !          2021:        fileNum = fcb->fcbFlNm;
        !          2022:        resourceFlag = fcb->fcbFlags & fcbResourceMask;
        !          2023:        
        !          2024:        err = noErr;
        !          2025: 
        !          2026:        #if DEBUG_BUILD
        !          2027:                if (fcb->fcbVPtr != vcb)
        !          2028:                        DebugStr("\pVCB does not match FCB");
        !          2029:        #endif
        !          2030:        
        !          2031:        if ( isHFSPlus ) {
        !          2032:                extendedFCB = GetExtendedFCB(fcb);
        !          2033:                BlockMoveData(extents, extendedFCB->extents, sizeof(HFSPlusExtentRecord));
        !          2034:        }
        !          2035:        else {
        !          2036:                err = ExtentsToExtDataRec(extents, fcb->fcbExtRec);
        !          2037:        }
        !          2038: 
        !          2039:        return err;
        !          2040: }
        !          2041: 
        !          2042: 
        !          2043: 
        !          2044: //�������������������������������������������������������������������������������
        !          2045: //     Routine:        MapFileBlockFromFCB
        !          2046: //
        !          2047: //     Function:       Determine if the given file offset is within the set of extents
        !          2048: //                             stored in the FCB or ExtendedFCB.  If so, return the file allocation
        !          2049: //                             block number of the start of the extent, volume allocation block number
        !          2050: //                             of the start of the extent, and file allocation block number immediately
        !          2051: //                             following the extent.
        !          2052: //
        !          2053: //     Input:          vcb                                             -       the volume containing the extents
        !          2054: //                             fcb                                             -       the file that owns the extents
        !          2055: //                             offset                                  -       desired offset in bytes
        !          2056: //
        !          2057: //     Output:         firstFABN                               -       file alloc block number of start of extent
        !          2058: //                             firstBlock                              -       volume alloc block number of start of extent
        !          2059: //                             nextFABN                                -       file alloc block number of next extent
        !          2060: //
        !          2061: //     Result:         noErr           = ok
        !          2062: //                             fxRangeErr      = beyond FCB's extents
        !          2063: //�������������������������������������������������������������������������������
        !          2064: static OSErr MapFileBlockFromFCB(
        !          2065:        const ExtendedVCB               *vcb,
        !          2066:        const FCB                               *fcb,
        !          2067:        UInt32                                  offset,                 // Desired offset in bytes from start of file
        !          2068:        UInt32                                  *firstFABN,             // FABN of first block of found extent
        !          2069:        UInt32                                  *firstBlock,    // Corresponding allocation block number
        !          2070:        UInt32                                  *nextFABN)              // FABN of block after end of extent
        !          2071: {
        !          2072:        UInt32  index;
        !          2073:        UInt32  offsetBlocks;
        !          2074:        
        !          2075:        offsetBlocks = offset / vcb->blockSize;
        !          2076:        
        !          2077:        if (vcb->vcbSigWord == kHFSSigWord) {
        !          2078:                const HFSExtentDescriptor       *extent;
        !          2079:                UInt16  blockCount;
        !          2080:                UInt16  currentFABN;
        !          2081:                
        !          2082:                extent = fcb->fcbExtRec;
        !          2083:                currentFABN = 0;
        !          2084:                
        !          2085:                for (index=0; index<kHFSExtentDensity; index++) {
        !          2086: 
        !          2087:                        blockCount = extent->blockCount;
        !          2088: 
        !          2089:                        if (blockCount == 0)
        !          2090:                                return fxRangeErr;                              //      ran out of extents!
        !          2091: 
        !          2092:                        //      Is it in this extent?
        !          2093:                        if (offsetBlocks < blockCount) {
        !          2094:                                *firstFABN      = currentFABN;
        !          2095:                                *firstBlock     = extent->startBlock;
        !          2096:                                currentFABN += blockCount;              //      faster to add these as UInt16 first, then extend to UInt32
        !          2097:                                *nextFABN       = currentFABN;
        !          2098:                                return noErr;                                   //      found the right extent
        !          2099:                        }
        !          2100: 
        !          2101:                        //      Not in current extent, so adjust counters and loop again
        !          2102:                        offsetBlocks -= blockCount;
        !          2103:                        currentFABN += blockCount;
        !          2104:                        extent++;
        !          2105:                }
        !          2106:        }
        !          2107:        else {
        !          2108:                const HFSPlusExtentDescriptor   *extent;
        !          2109:                UInt32  blockCount;
        !          2110:                UInt32  currentFABN;
        !          2111:                
        !          2112:                extent = GetExtendedFCB(fcb)->extents;
        !          2113:                currentFABN = 0;
        !          2114:                
        !          2115:                for (index=0; index<kHFSPlusExtentDensity; index++) {
        !          2116: 
        !          2117:                        blockCount = extent->blockCount;
        !          2118: 
        !          2119:                        if (blockCount == 0)
        !          2120:                                return fxRangeErr;                              //      ran out of extents!
        !          2121: 
        !          2122:                        //      Is it in this extent?
        !          2123:                        if (offsetBlocks < blockCount) {
        !          2124:                                *firstFABN      = currentFABN;
        !          2125:                                *firstBlock     = extent->startBlock;
        !          2126:                                *nextFABN       = currentFABN + blockCount;
        !          2127:                                return noErr;                                   //      found the right extent
        !          2128:                        }
        !          2129: 
        !          2130:                        //      Not in current extent, so adjust counters and loop again
        !          2131:                        offsetBlocks -= blockCount;
        !          2132:                        currentFABN += blockCount;
        !          2133:                        extent++;
        !          2134:                }
        !          2135:        }
        !          2136:        
        !          2137:        //      If we fall through here, the extent record was full, but the offset was
        !          2138:        //      beyond those extents.
        !          2139:        
        !          2140:        return fxRangeErr;
        !          2141: }
        !          2142: 
        !          2143: 
        !          2144: //_________________________________________________________________________________
        !          2145: //
        !          2146: // Routine:            ExtentsAreIntegral
        !          2147: //
        !          2148: // Purpose:            Ensure that each extent can hold an integral number of nodes
        !          2149: //                             Called by the NodesAreContiguous function
        !          2150: //_________________________________________________________________________________
        !          2151: 
        !          2152: static Boolean ExtentsAreIntegral(
        !          2153:        const HFSPlusExtentRecord extentRecord,
        !          2154:        UInt32          mask,
        !          2155:        UInt32          *blocksChecked,
        !          2156:        Boolean         *checkedLastExtent)
        !          2157: {
        !          2158:        UInt32          blocks;
        !          2159:        UInt32          extentIndex;
        !          2160: 
        !          2161:        *blocksChecked = 0;
        !          2162:        *checkedLastExtent = false;
        !          2163:        
        !          2164:        for(extentIndex = 0; extentIndex < kHFSPlusExtentDensity; extentIndex++)
        !          2165:        {               
        !          2166:                blocks = extentRecord[extentIndex].blockCount;
        !          2167:                
        !          2168:                if ( blocks == 0 )
        !          2169:                {
        !          2170:                        *checkedLastExtent = true;
        !          2171:                        break;
        !          2172:                }
        !          2173: 
        !          2174:                *blocksChecked += blocks;
        !          2175: 
        !          2176:                if (blocks & mask)
        !          2177:                        return false;
        !          2178:        }
        !          2179:        
        !          2180:        return true;
        !          2181: }
        !          2182: 
        !          2183: 
        !          2184: //_________________________________________________________________________________
        !          2185: //
        !          2186: // Routine:            NodesAreContiguous
        !          2187: //
        !          2188: // Purpose:            Ensure that all b-tree nodes are contiguous on disk
        !          2189: //                             Called by BTOpenPath during volume mount
        !          2190: //_________________________________________________________________________________
        !          2191: 
        !          2192: Boolean NodesAreContiguous(
        !          2193:        ExtendedVCB     *vcb,
        !          2194:        FCB                     *fcb,
        !          2195:        UInt32          nodeSize)
        !          2196: {
        !          2197:        UInt32                          mask;
        !          2198:        UInt32                          startBlock;
        !          2199:        UInt32                          blocksChecked;
        !          2200:        UInt32                          hint;
        !          2201:        HFSPlusExtentKey        key;
        !          2202:        HFSPlusExtentRecord     extents;
        !          2203:        OSErr                           result;
        !          2204:        Boolean                         lastExtentReached;
        !          2205:        
        !          2206: 
        !          2207:        if (vcb->blockSize >= nodeSize)
        !          2208:                return TRUE;
        !          2209: 
        !          2210:        mask = (nodeSize / vcb->blockSize) - 1;
        !          2211: 
        !          2212:        // check the local extents
        !          2213:        (void) GetFCBExtentRecord(vcb, fcb, extents);
        !          2214:        if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) )
        !          2215:                return FALSE;
        !          2216: 
        !          2217:        if (lastExtentReached || (blocksChecked * vcb->blockSize) >= fcb->fcbPLen)
        !          2218:                return TRUE;
        !          2219: 
        !          2220:        startBlock = blocksChecked;
        !          2221: 
        !          2222:        // check the overflow extents (if any)
        !          2223:        while ( !lastExtentReached )
        !          2224:        {
        !          2225:                result = FindExtentRecord(vcb, kDataForkType, fcb->fcbFlNm, startBlock, FALSE, &key, extents, &hint);
        !          2226:                if (result) break;
        !          2227: 
        !          2228:                if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) )
        !          2229:                        return FALSE;
        !          2230: 
        !          2231:                startBlock += blocksChecked;
        !          2232:        }
        !          2233: 
        !          2234:        return TRUE;
        !          2235: }
        !          2236: 
        !          2237: 
        !          2238: #if TARGET_OS_MAC
        !          2239: void AdjustEOF(FCB *sourceFCB)
        !          2240: {
        !          2241:        ExtendedVCB     *vcb;                   //      sourceFCB's volume
        !          2242:        UInt32          fileID;                 //      File's ID
        !          2243:        FCB                     *destFCB;               //      A matching FCB
        !          2244:        FileReference           refnum;                 //      Used for iterating over FCBs
        !          2245:        UInt16          maxRefnum;              //      First refnum beyond end of FCB table
        !          2246:        UInt16          lengthFCB;              //      Size of an FCB
        !          2247:        Boolean         isHFSPlus;              //      True if sourceFCB is on an HFS Plus volume
        !          2248:        UInt8           resourceFlag;   //      Contains fcbResourceMask bit from fcbFlags
        !          2249: 
        !          2250:        vcb = sourceFCB->fcbVPtr;
        !          2251:        sourceFCB->fcbFlags |= fcbModifiedMask;
        !          2252:        fileID = sourceFCB->fcbFlNm;
        !          2253:        resourceFlag = sourceFCB->fcbFlags & fcbResourceMask;
        !          2254:        
        !          2255:        isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
        !          2256:        
        !          2257:        maxRefnum = * ((UInt16 *) LMGetFCBSPtr());
        !          2258:        lengthFCB = LMGetFSFCBLen();
        !          2259:        
        !          2260:        for (refnum=kFirstFileRefnum; refnum<maxRefnum; refnum+=lengthFCB) {
        !          2261:                destFCB = GetFileControlBlock(refnum);
        !          2262:                if (destFCB->fcbFlNm == fileID &&
        !          2263:                        destFCB->fcbVPtr == vcb &&
        !          2264:                        destFCB != sourceFCB &&
        !          2265:                        (destFCB->fcbFlags & fcbResourceMask) == resourceFlag)
        !          2266:                {
        !          2267:                        //      We found another FCB for the same fork.  Copy the fields.
        !          2268:                        destFCB->fcbSBlk        = sourceFCB->fcbSBlk;   //���MFS only?
        !          2269:                        destFCB->fcbEOF         = sourceFCB->fcbEOF;
        !          2270:                        destFCB->fcbPLen        = sourceFCB->fcbPLen;
        !          2271:                        
        !          2272:                        //      Copy extent info, too
        !          2273:                        if (isHFSPlus) {
        !          2274:                                ExtendedFCB     *srcExtendedFCB;
        !          2275:                                ExtendedFCB     *destExtendedFCB;
        !          2276:                                
        !          2277:                                srcExtendedFCB = GetExtendedFCB(sourceFCB);
        !          2278:                                destExtendedFCB = GetExtendedFCB(destFCB);
        !          2279:                                
        !          2280:                                BlockMoveData(srcExtendedFCB->extents, destExtendedFCB->extents, sizeof(HFSPlusExtentRecord));
        !          2281:                        }
        !          2282:                        else {
        !          2283:                                destFCB->fcbExtRec[0] = sourceFCB->fcbExtRec[0];
        !          2284:                                destFCB->fcbExtRec[1] = sourceFCB->fcbExtRec[1];
        !          2285:                                destFCB->fcbExtRec[2] = sourceFCB->fcbExtRec[2];
        !          2286:                        }
        !          2287:                }
        !          2288:        }
        !          2289: }
        !          2290: #endif /* TARGET_OS_MAC */
        !          2291: 
        !          2292: 
        !          2293: #if TARGET_OS_MAC
        !          2294: static OSErr ValidateRefnum(short ref)
        !          2295: {
        !          2296:        FCB                             *fcb;
        !          2297: 
        !          2298:        //
        !          2299:        //      Make sure refnum is multiple of FCB length, plus 2.
        !          2300:        //
        !          2301:        if ((ref % LMGetFSFCBLen()) != 2)
        !          2302:                return rfNumErr;
        !          2303:        
        !          2304:        //
        !          2305:        //      Make sure refnum isn't too large
        !          2306:        //
        !          2307:        if (ref > *((short *) LMGetFCBSPtr()))
        !          2308:                return rfNumErr;
        !          2309:        
        !          2310:        //
        !          2311:        //      Make sure file is open
        !          2312:        //
        !          2313:        fcb = GetFileControlBlock(ref);
        !          2314:        if (fcb->fcbFlNm == 0)
        !          2315:                return fnOpnErr;
        !          2316:        
        !          2317:        //
        !          2318:        //      If we got here, refnum was valid and file was open
        !          2319:        //
        !          2320:        return noErr;
        !          2321: }
        !          2322: #endif /* TARGET_OS_MAC */
        !          2323: 
        !          2324: 
        !          2325: #if TARGET_OS_MAC
        !          2326: static UInt32 BytesToBlocks(UInt64 bytes, UInt32 blockSize)
        !          2327: {
        !          2328:        UInt32                  carry;
        !          2329:        UnsignedWide    temp;
        !          2330:        
        !          2331:        temp = UInt64ToUnsignedWide(bytes);
        !          2332: 
        !          2333:        //      This loop divides "bytes" by "blockSize".  It assumes blockSize
        !          2334:        //      is a power of two.  The division is done by shifting both numerator
        !          2335:        //      and divisor until the divisor is one.
        !          2336:        
        !          2337:        while (blockSize > 1) {
        !          2338:                blockSize >>= 1;
        !          2339:                carry = (temp.hi & 1) ? 0x80000000 : 0;
        !          2340:                temp.hi >>= 1;
        !          2341:                temp.lo = carry | temp.lo >> 1;
        !          2342:        }
        !          2343:        
        !          2344:        return temp.lo;
        !          2345: }
        !          2346: #endif /* TARGET_OS_MAC */
        !          2347: 
        !          2348: #if TARGET_OS_MAC
        !          2349: static OSErr AllocateLargeFile(
        !          2350:        CreateLargeFileParam    *pb,
        !          2351:        ExtendedVCB                             *vcb,
        !          2352:        UInt32                                  *dataBlocks,
        !          2353:        UInt32                                  *rsrcBlocks,
        !          2354:        HFSPlusExtentRecord             dataExtents,
        !          2355:        HFSPlusExtentRecord             rsrcExtents)
        !          2356: {
        !          2357:        OSErr                           err;
        !          2358:        int                                     i;
        !          2359:        UInt32                          blockSize;
        !          2360:        UInt32                          blocksToAllocate;       //      how many blocks are left to allocate
        !          2361:        UInt32                          startBlock;
        !          2362:        UInt32                          numBlocks;
        !          2363: 
        !          2364: 
        !          2365:        //      Initialize the extent lists
        !          2366:        ClearMemory(dataExtents, sizeof(HFSPlusExtentRecord));
        !          2367:        ClearMemory(rsrcExtents, sizeof(HFSPlusExtentRecord));
        !          2368:        
        !          2369:        blockSize = vcb->blockSize;
        !          2370:        
        !          2371:        //      Allocate data fork
        !          2372:        blocksToAllocate = BytesToBlocks(pb->dataPhysicalEOF, blockSize);
        !          2373:        if (blocksToAllocate > vcb->freeBlocks) {
        !          2374:                err = dskFulErr;
        !          2375:                goto Cleanup;
        !          2376:        }
        !          2377:        *dataBlocks = blocksToAllocate;
        !          2378:        
        !          2379:        if (blocksToAllocate) {
        !          2380:                for (i=0; i<kHFSPlusExtentDensity && blocksToAllocate; i++) {
        !          2381:                        err = BlockAllocateAny(vcb, 0, vcb->totalBlocks, blocksToAllocate, &startBlock, &numBlocks);
        !          2382:                        if (err != noErr) goto Cleanup;
        !          2383:                        
        !          2384:                        dataExtents[i].startBlock = startBlock;
        !          2385:                        dataExtents[i].blockCount = numBlocks;
        !          2386:                        
        !          2387:                        blocksToAllocate -= numBlocks;
        !          2388:                        VCB_LOCK(vcb);
        !          2389:                        vcb->freeBlocks -= numBlocks;
        !          2390:                        VCB_UNLOCK(vcb);
        !          2391:                }
        !          2392:                
        !          2393:                if (blocksToAllocate != 0) {            //      too fragmented?
        !          2394:                        err = fsDataTooBigErr;
        !          2395:                        goto Cleanup;
        !          2396:                }
        !          2397:        }
        !          2398:        
        !          2399:        //      Allocate resource fork
        !          2400:        blocksToAllocate = BytesToBlocks(pb->rsrcPhysicalEOF, blockSize);
        !          2401:        if (blocksToAllocate > vcb->freeBlocks) {
        !          2402:                err = dskFulErr;
        !          2403:                goto Cleanup;
        !          2404:        }
        !          2405:        *rsrcBlocks = blocksToAllocate;
        !          2406:        
        !          2407:        if (blocksToAllocate) {
        !          2408:                for (i=0; i<kHFSPlusExtentDensity && blocksToAllocate; i++) {
        !          2409:                        err = BlockAllocateAny(vcb, 0, vcb->totalBlocks, blocksToAllocate, &startBlock, &numBlocks);
        !          2410:                        if (err != noErr) goto Cleanup;
        !          2411:                        
        !          2412:                        rsrcExtents[i].startBlock = startBlock;
        !          2413:                        rsrcExtents[i].blockCount = numBlocks;
        !          2414:                        
        !          2415:                        blocksToAllocate -= numBlocks;
        !          2416:                        VCB_LOCK(vcb);
        !          2417:                        vcb->freeBlocks -= numBlocks;
        !          2418:                        VCB_UNLOCK(vcb);
        !          2419:                }
        !          2420:                
        !          2421:                if (blocksToAllocate != 0) {            //      too fragmented?
        !          2422:                        err = fsDataTooBigErr;
        !          2423:                        goto Cleanup;
        !          2424:                }
        !          2425:        }
        !          2426:        
        !          2427:        UpdateVCBFreeBlks( vcb );
        !          2428:        MarkVCBDirty(vcb);
        !          2429: 
        !          2430:        return noErr;
        !          2431: 
        !          2432: //
        !          2433: //     If we get here, there was an error.  Deallocate anything we allocated and then
        !          2434: //     return the previous error.
        !          2435: //
        !          2436: Cleanup:
        !          2437:        for (i=0; i<kHFSPlusExtentDensity; i++) {
        !          2438:                BlockDeallocate(vcb, dataExtents[i].startBlock, dataExtents[i].blockCount);
        !          2439:                BlockDeallocate(vcb, rsrcExtents[i].startBlock, rsrcExtents[i].blockCount);
        !          2440:                *dataBlocks = 0;
        !          2441:                *rsrcBlocks = 0;
        !          2442:        }
        !          2443:        
        !          2444:        return err;
        !          2445: }
        !          2446: #endif /* TARGET_OS_MAC */
        !          2447: 
        !          2448: #if TARGET_OS_MAC
        !          2449: OSErr CreateLargeFile(CreateLargeFileParam *pb)
        !          2450: {
        !          2451:        OSErr                           err;
        !          2452:        ExtendedVCB                     *vcb;
        !          2453:        FindFileNameGlueRec     fileInfo;
        !          2454:        Str31                           name;
        !          2455:        CatalogNodeID           fileID;
        !          2456:        UInt32                          hint;
        !          2457:        UInt32                          dataBlocks;
        !          2458:        UInt32                          rsrcBlocks;
        !          2459:        HFSPlusExtentRecord     dataExtents;
        !          2460:        HFSPlusExtentRecord     rsrcExtents;
        !          2461:        CatalogKey                      recordKey;
        !          2462:        CatalogRecord           recordData;
        !          2463:        
        !          2464:        //
        !          2465:        //      Try finding the file
        !          2466:        //
        !          2467:        err = FindFileName((ParamBlockRec *) pb, &fileInfo);
        !          2468:        
        !          2469:        //
        !          2470:        //      Make sure file wasn't found
        !          2471:        //
        !          2472:        if (err == noErr)               //      did file already exist?
        !          2473:                err = dupFNErr;         //      if so, duplicate error
        !          2474:        if (err != fnfErr)              //      we expect a not found error
        !          2475:                return err;                     //      anything else is a real error
        !          2476: 
        !          2477:        //
        !          2478:        //      Make sure volume is writable and online
        !          2479:        //
        !          2480:        vcb = fileInfo.vcb;
        !          2481: 
        !          2482:        err = VolumeWritable( vcb );
        !          2483:        ReturnIfError( err );
        !          2484: 
        !          2485:        err = CheckVolumeOffLine( vcb );
        !          2486:        ReturnIfError( err );
        !          2487:        
        !          2488:        //
        !          2489:        //      And make sure it is HFS Plus.
        !          2490:        //
        !          2491:        if (vcb->vcbSigWord != kHFSPlusSigWord)
        !          2492:                return wrgVolTypErr;
        !          2493:        
        !          2494:        //
        !          2495:        //      Allocate the space
        !          2496:        //
        !          2497:        err = AllocateHFSPlusFile(pb, vcb, &dataBlocks, &rsrcBlocks, dataExtents, rsrcExtents);
        !          2498:        ReturnIfError( err );
        !          2499:        
        !          2500:        //
        !          2501:        //      Copy the name into a p-string buffer
        !          2502:        //
        !          2503:        BlockMoveData(fileInfo.nameBuffer, name+1, fileInfo.nameLength);
        !          2504:        name[0] = fileInfo.nameLength;
        !          2505:        
        !          2506:        //
        !          2507:        //      Create a new (empty) file
        !          2508:        //
        !          2509:        err = CreateCatalogNode(vcb, fileInfo.id, name, kHFSFileRecord, &fileID, &hint);
        !          2510:        ReturnIfError( err );
        !          2511: 
        !          2512:        //
        !          2513:        //      Get the raw b-tree record for the new file
        !          2514:        //
        !          2515:        //�� LocateCatalogNode is a private Catalog routine, should probally call GetCatalogNode and UpdateCatalogNode instead...
        !          2516:        err = LocateCatalogNode(vcb, fileID, NULL, kNoHint, &recordKey, &recordData, &hint);
        !          2517:        ReturnIfError( err );
        !          2518:        
        !          2519:        //
        !          2520:        //      Update the record's data
        !          2521:        //
        !          2522:        recordData.hfsPlusFile.dataFork.logicalSize = pb->dataLogicalEOF;
        !          2523:        recordData.hfsPlusFile.dataFork.totalBlocks = dataBlocks;
        !          2524:        BlockMoveData(dataExtents, recordData.hfsPlusFile.dataFork.extents, sizeof(HFSPlusExtentRecord));
        !          2525: 
        !          2526:        recordData.hfsPlusFile.resourceFork.logicalSize = pb->rsrcLogicalEOF;
        !          2527:        recordData.hfsPlusFile.resourceFork.totalBlocks = rsrcBlocks;
        !          2528:        BlockMoveData(rsrcExtents, recordData.hfsPlusFile.resourceFork.extents, sizeof(HFSPlusExtentRecord));
        !          2529:        
        !          2530:        //
        !          2531:        //      Write the updated record back out
        !          2532:        //
        !          2533:        err = ReplaceBTreeRecord(vcb->catalogRefNum, &recordKey, hint, &recordData, sizeof(HFSPlusCatalogFile), &hint);
        !          2534:        
        !          2535:        return err;
        !          2536: }
        !          2537: #endif /* TARGET_OS_MAC */

unix.superglobalmegacorp.com

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