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

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /*
                     26:        File:           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.