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

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:        File:           VolumeAllocation.c
        !            24: 
        !            25:        Contains:       Routines for accessing and modifying the volume bitmap.
        !            26: 
        !            27:        Version:        HFS Plus 1.0
        !            28: 
        !            29:        Copyright:      � 1996-2000 by Apple Computer, Inc., all rights reserved.
        !            30: 
        !            31:        File Ownership:
        !            32: 
        !            33:                DRI:                            Mark Day
        !            34: 
        !            35:                Other Contact:          Greg Parks
        !            36: 
        !            37:                Technology:                     HFS+
        !            38: 
        !            39:        Writers:
        !            40: 
        !            41:                (djb)   Don Brady
        !            42:                (DSH)   Deric Horn
        !            43:                (msd)   Mark Day
        !            44: 
        !            45:        Change History (most recent first):
        !            46:          <MacOSX>       1/22/2000      djb     Removed unused BlockCheck and BlockVerifyAllocated routines.
        !            47:          <MacOSX>       4/27/98        djb     Remove references to unused/legacy vcbFreeBks.
        !            48:          <MacOSX>       4/27/98        djb     Remove unneccessary DebugStr in BlockVerifyAllocated.
        !            49:          <MacOSX>       4/17/98        djb     Add VCB locking.
        !            50:          <MacOSX>       4/13/98        djb     Add RequireFileLock checking to ReadBitmapBlock.
        !            51:          <MacOSX>       3/31/98        djb     Sync up with final HFSVolumes.h header file.
        !            52: 
        !            53:          <12>  1       0/31/97         DSH             Modify BlockVerifyAllocated() so DFA can call without actually
        !            54:                                                                        writing to the disk.
        !            55:          <CS11>        10/20/97        msd             The way BlockAllocate rounds up to a multiple of the clump size
        !            56:                                                                        is wrong. ExtendFileC should do the round-up and pass the result
        !            57:                                                                        into BlockAllocate. Removed the fcb parameter to BlockAllocate;
        !            58:                                                                        added a bytesMaximum parameter.
        !            59:          <CS10>        10/17/97        msd             Conditionalize DebugStrs.
        !            60:           <CS9>          9/4/97        djb             Add logging to BlockAllocate.
        !            61:           <CS8>          9/4/97        msd             Add a histogram of allocation sizes. Use DEBUG_BUILD instead of
        !            62:                                                                        VSM_DEBUG to generate DebugStr messages.
        !            63:           <CS7>         8/14/97        msd             Bug 1662332. Don't mark blocks dirty in UpdateFreeCount. In
        !            64:                                                                        BlockVerifyAllocated, only mark blocks dirty if they've actually
        !            65:                                                                        changed.
        !            66:           <CS6>         7/16/97        DSH             FilesInternal.i renamed FileMgrInternal.i to avoid name
        !            67:                                                                        collision
        !            68:           <CS5>          7/8/97        DSH             Loading PrecompiledHeaders from define passed in on C line
        !            69:           <CS4>         6/12/97        msd             Export BlockAllocateAny and UpdateVCBFreeBlks.
        !            70:                 <3>      5/8/97        DSH             Added comments and ascii diagram of new BlockFindContiguous()
        !            71:                                                                        algorithm.
        !            72:                 <2>      5/7/97        DSH             New faster BlockFindContiguous algorithm.  It searches backwards
        !            73:                                                                        until a dirty bit is found instead of forwards.
        !            74:           <CS1>         4/25/97        djb             first checked in
        !            75: 
        !            76:         <HFS21>         4/14/97        msd             Fix UpdateVCBFreeBlks so free space calculation doesn't overflow
        !            77:                                                                        on volumes bigger than 4GB.
        !            78:         <HFS20>          4/4/97        djb             Get in sync with volume format changes.
        !            79:         <HFS19>         1/27/97        msd             Speed up BlockCheck and UpdateFreeCount. Removed DebugStr from
        !            80:                                                                        BlockCheck; there are now DebugStr's in BlockVerifyAllocated,
        !            81:                                                                        before the bitmap gets fixed (so potential problems can be
        !            82:                                                                        debugged easier). Adjusted comments about internal routines.
        !            83:                                                                        Changed names of "Fast" routines back to their original names
        !            84:                                                                        (since the originals are now removed).
        !            85:         <HFS18>         1/24/97        msd             Speed up allocation and deallocation.
        !            86:         <HFS17>         1/21/97        msd             Add instrumentation for function entry/exit.  BlockAllocate and
        !            87:                                                                        ReadBitMapBlock use the event tag to log bytes requested and
        !            88:                                                                        block number (respectively).
        !            89:         <HFS16>         1/15/97        djb             Add HFS+ supprt to BlockCheck (for MountCheck).
        !            90:         <HFS15>         1/13/97        DSH             Use vcb->nextAllocation instead of vcbAllocPtr.
        !            91:         <HFS14>          1/9/97        djb             UpdateVCBFreeBlks is not converting correctly.
        !            92:         <HFS13>          1/6/97        djb             Use vcb's allocationsRefNum to access allocation file.
        !            93:         <HFS12>          1/2/97        DSH             Added UpdateVCBFreeBlks() to update vcbFreeBks whenever we
        !            94:                                                                        update vcb->freeblocks.
        !            95:         <HFS11>        12/19/96        DSH             All refs to VCB are now refs to ExtendedVCB
        !            96:         <HFS10>        12/12/96        msd             DivideAndRoundUp should not be declared as static.
        !            97:          <HFS9>        12/10/96        msd             Check PRAGMA_LOAD_SUPPORTED before loading precompiled headers.
        !            98:          <HFS8>         12/4/96        DSH             PrecompiledHeaders
        !            99:          <HFS7>        11/27/96        djb             Added AllocateFreeSpace for HFS wrapper support.
        !           100:          <HFS6>        11/27/96        msd             Changed ReadBitmapBlock to read from HFS+ allocation file.
        !           101:                                                                        Temporarily uses the vcbVBMSt field of the VCB as the allocation
        !           102:                                                                        file's refnum until extended VCB changes are checked in.
        !           103:          <HFS5>        11/26/96        msd             VSM and FileExtentMapping routines use FCB instead of FCBRec.
        !           104:          <HFS4>        11/20/96        DSH             Changed a parameter in GetBlock_glue, so I also changed the
        !           105:                                                                        caller.
        !           106:          <HFS3>        11/20/96        msd             Include FilesInternal.h. Remove definition of MarkVCBDirty
        !           107:                                                                        (since it is now in FilesInternal.h).
        !           108:          <HFS2>        11/12/96        msd             Need to bound allocations to be within the last allocation block
        !           109:                                                                        of the volume (function AllocateAt).
        !           110:          <HFS1>        11/11/96        msd             first checked in
        !           111: */
        !           112: 
        !           113: /*
        !           114: Public routines:
        !           115:        BlockAllocate
        !           116:                                        Allocate space on a volume.  Can allocate space contiguously.
        !           117:                                        If not contiguous, then allocation may be less than what was
        !           118:                                        asked for.  Returns the starting block number, and number of
        !           119:                                        blocks.  (Will only do a single extent???)
        !           120:        BlockDeallocate
        !           121:                                        Deallocate a contiguous run of allocation blocks.
        !           122:        UpdateFreeCount
        !           123:                                        Computes the number of free allocation blocks on a volume.
        !           124:                                        The vcb's free block count is updated.
        !           125: 
        !           126:        AllocateFreeSpace
        !           127:                                        Allocates all the remaining free space (used for embedding HFS+ volumes).
        !           128: 
        !           129:        BlockAllocateAny
        !           130:                                        Find and allocate a contiguous range of blocks up to a given size.  The
        !           131:                                        first range of contiguous free blocks found are allocated, even if there
        !           132:                                        are fewer blocks than requested (and even if a contiguous range of blocks
        !           133:                                        of the given size exists elsewhere).
        !           134: 
        !           135:        UpdateVCBFreeBlks
        !           136:                                        Given an ExtenddVCB, calculate the vcbFreeBks value
        !           137:                                        so that vcbFreeBks*vcbAlBlkSiz == freeBlocks*blockSize.
        !           138: 
        !           139: Internal routines:
        !           140:        BlockMarkFree
        !           141:                                        Mark a contiguous range of blocks as free.  The corresponding
        !           142:                                        bits in the volume bitmap will be cleared.
        !           143:        BlockMarkAllocated
        !           144:                                        Mark a contiguous range of blocks as allocated.  The cor-
        !           145:                                        responding bits in the volume bitmap are set.  Also tests to see
        !           146:                                        if any of the blocks were previously unallocated.
        !           147:        FindContiguous
        !           148:                                        Find a contiguous range of blocks of a given size.  The caller
        !           149:                                        specifies where to begin the search (by block number).  The
        !           150:                                        block number of the first block in the range is returned.
        !           151:        BlockAllocateContig
        !           152:                                        Find and allocate a contiguous range of blocks of a given size.  If
        !           153:                                        a contiguous range of free blocks of the given size isn't found, then
        !           154:                                        the allocation fails (i.e. it is "all or nothing").
        !           155:        ReadBitmapBlock
        !           156:                                        Given an allocation block number, read the bitmap block that
        !           157:                                        contains that allocation block into a caller-supplied buffer.
        !           158: */
        !           159: 
        !           160: #include "../../hfs_macos_defs.h"
        !           161: 
        !           162: #include <sys/types.h>
        !           163: #include <sys/buf.h>
        !           164: #include <sys/systm.h>
        !           165: 
        !           166: #include "../../hfs.h"
        !           167: #include "../../hfs_dbg.h"
        !           168: #include "../../hfs_format.h"
        !           169: 
        !           170: #include "../headers/FileMgrInternal.h"
        !           171: 
        !           172: #include "../headers/HFSInstrumentation.h"
        !           173: 
        !           174: #define EXPLICIT_BUFFER_RELEASES 1
        !           175: 
        !           176: enum {
        !           177:        kBitsPerByte                    =       8,
        !           178:        kBitsPerWord                    =       32,
        !           179:        kWordsPerBlock                  =       128,
        !           180:        kBytesPerBlock                  =       512,
        !           181:        kBitsPerBlock                   =       4096,
        !           182:        
        !           183:        kBitsWithinWordMask             =       kBitsPerWord-1,
        !           184:        kBitsWithinBlockMask    =       kBitsPerBlock-1,
        !           185:        kWordsWithinBlockMask   =       kWordsPerBlock-1,
        !           186:        
        !           187:        kExtentsPerRecord               =       3
        !           188: };
        !           189: 
        !           190: #define kLowBitInWordMask      0x00000001ul
        !           191: #define kHighBitInWordMask     0x80000000ul
        !           192: #define kAllBitsSetInWord      0xFFFFFFFFul
        !           193: 
        !           194: 
        !           195: static OSErr ReadBitmapBlock(
        !           196:        ExtendedVCB             *vcb,
        !           197:        UInt32                  block,
        !           198:        UInt32                  **buffer);
        !           199: 
        !           200: static OSErr BlockAllocateContig(
        !           201:        ExtendedVCB             *vcb,
        !           202:        UInt32                  startingBlock,
        !           203:        UInt32                  minBlocks,
        !           204:        UInt32                  maxBlocks,
        !           205:        UInt32                  *actualStartBlock,
        !           206:        UInt32                  *actualNumBlocks);
        !           207: 
        !           208: static OSErr BlockFindContiguous(
        !           209:        ExtendedVCB             *vcb,
        !           210:        UInt32                  startingBlock,
        !           211:        UInt32                  endingBlock,
        !           212:        UInt32                  minBlocks,
        !           213:        UInt32                  maxBlocks,
        !           214:        UInt32                  *actualStartBlock,
        !           215:        UInt32                  *actualNumBlocks);
        !           216: 
        !           217: static OSErr BlockMarkAllocated(
        !           218:        ExtendedVCB             *vcb,
        !           219:        UInt32                  startingBlock,
        !           220:        UInt32                  numBlocks);
        !           221: 
        !           222: static OSErr BlockMarkFree(
        !           223:        ExtendedVCB             *vcb,
        !           224:        UInt32                  startingBlock,
        !           225:        UInt32                  numBlocks);
        !           226: 
        !           227: 
        !           228: /*
        !           229: ;________________________________________________________________________________
        !           230: ;
        !           231: ; Routine:        BlkAlloc
        !           232: ;
        !           233: ; Function:    Allocate space on a volume.     If contiguous allocation is requested,
        !           234: ;                         at least the requested number of bytes will be allocated or an
        !           235: ;                         error will be returned.      If contiguous allocation is not forced,
        !           236: ;                         the space will be allocated at the first free fragment following
        !           237: ;                         the requested starting allocation block.  If there is not enough
        !           238: ;                         room there, a block of less than the requested size will be
        !           239: ;                         allocated.
        !           240: ;
        !           241: ;                         If the requested starting block is 0 (for new file allocations),
        !           242: ;                         the volume's allocation block pointer will be used as a starting
        !           243: ;                         point.
        !           244: ;
        !           245: ;                         All requests will be rounded up to the next highest clump size, as
        !           246: ;                         indicated in the file's FCB.
        !           247: ;
        !           248: ; Input Arguments:
        !           249: ;       vcb                     - Pointer to ExtendedVCB for the volume to allocate space on
        !           250: ;       fcb                     - Pointer to FCB for the file for which storage is being allocated
        !           251: ;       startingBlock   - Preferred starting allocation block, 0 = no preference
        !           252: ;       forceContiguous - Force contiguous flag - if bit 0 set (NE), allocation is contiguous
        !           253: ;                                         or an error is returned
        !           254: ;       bytesRequested  - Number of bytes requested.   If the allocation is non-contiguous,
        !           255: ;                                         less than this may actually be allocated
        !           256: ;       bytesMaximum    - The maximum number of bytes to allocate.  If there is additional free
        !           257: ;                                         space after bytesRequested, then up to bytesMaximum bytes should really
        !           258: ;                                         be allocated.  (Used by ExtendFileC to round up allocations to a multiple
        !           259: ;                                         of the file's clump size.)
        !           260: ;
        !           261: ; Output:
        !           262: ;       (result)                - Error code, zero for successful allocation
        !           263: ;       *startBlock     - Actual starting allocation block
        !           264: ;       *actualBlocks   - Actual number of allocation blocks allocated
        !           265: ;
        !           266: ; Side effects:
        !           267: ;       The volume bitmap is read and updated; the volume bitmap cache may be changed.
        !           268: ;
        !           269: ; Modification history:
        !           270: ;      <06Oct85>  PWD  Changed to check for errors after calls to ReadBM and NextWord
        !           271: ;                                      Relocated call to MarkBlock in allocation loop
        !           272: ;                                      Changed to call NextBit
        !           273: ; <21Oct85>   PWD      Changed to check VCBFreeBks before attempting to allocate any block.
        !           274: ;                                      Speed up scan for free space by checking for all 1's.
        !           275: ;________________________________________________________________________________
        !           276: */
        !           277: 
        !           278: OSErr BlockAllocate (
        !           279:        ExtendedVCB             *vcb,                           /* which volume to allocate space on */
        !           280:        UInt32                  startingBlock,          /* preferred starting block, or 0 for no preference */
        !           281:        SInt64                  bytesRequested,         /* desired number of BYTES to allocate */
        !           282:        SInt64                  bytesMaximum,           /* maximum number of bytes to allocate */
        !           283:        Boolean                 forceContiguous,        /* non-zero to force contiguous allocation and to force */
        !           284:                                                                                /* bytesRequested bytes to actually be allocated */
        !           285:        UInt32                  *actualStartBlock,      /* actual first block of allocation */
        !           286:        UInt32                  *actualNumBlocks)       /* number of blocks actually allocated; if forceContiguous */
        !           287:                                                                                /* was zero, then this may represent fewer than bytesRequested */
        !           288:                                                                                /* bytes */
        !           289: {
        !           290:        OSErr                   err;
        !           291:        UInt32                  minBlocks;                                      //      minimum number of allocation blocks requested
        !           292:        UInt32                  maxBlocks;                                      //      number of allocation blocks requested, rounded to clump size
        !           293:        Boolean                 updateAllocPtr = false;         //      true if nextAllocation needs to be updated
        !           294: 
        !           295:        LogStartTime(kTraceBlockAllocate);
        !           296: 
        !           297: #if HFSInstrumentation
        !           298:        InstSplitHistogramClassRef      histogram;
        !           299:        InstTraceClassRef                       trace;
        !           300:        InstEventTag                            eventTag;
        !           301:        
        !           302:        err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:BlockAllocate", 'hfs+', kInstEnableClassMask, &trace);
        !           303:        if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
        !           304: 
        !           305:        err = InstCreateSplitHistogramClass(kInstRootClassRef, "HFS:VSM:BlockAllocate size", 0, 512, 16384, 262144, 16384,
        !           306:                                                                                kInstEnableClassMask, &histogram);
        !           307:        if (err != noErr) DebugStr("\pError from InstCreateHistogramClass");
        !           308: 
        !           309:        eventTag = bytesRequested;              // a cheap way to get bytesRequested into the log
        !           310:        InstLogTraceEvent( trace, eventTag, kInstStartEvent);
        !           311:        InstUpdateHistogram( histogram, bytesRequested, 1);
        !           312: #endif
        !           313: 
        !           314:        //
        !           315:        //      Initialize outputs in case we get an error
        !           316:        //
        !           317:        *actualStartBlock = 0;
        !           318:        *actualNumBlocks = 0;
        !           319:        
        !           320:        //
        !           321:        //      Compute the number of allocation blocks requested, and maximum
        !           322:        //
        !           323:        minBlocks = FileBytesToBlocks(bytesRequested, vcb->blockSize);
        !           324:        maxBlocks = FileBytesToBlocks(bytesMaximum, vcb->blockSize);
        !           325:        
        !           326:        //
        !           327:        //      If the disk is already full, don't bother.
        !           328:        //
        !           329:        if (vcb->freeBlocks == 0) {
        !           330:                err = dskFulErr;
        !           331:                goto Exit;
        !           332:        }
        !           333:        if (forceContiguous && vcb->freeBlocks < minBlocks) {
        !           334:                err = dskFulErr;
        !           335:                goto Exit;
        !           336:        }
        !           337:        
        !           338:        //
        !           339:        //      If caller didn't specify a starting block number, then use the volume's
        !           340:        //      next block to allocate from.
        !           341:        //
        !           342:        if (startingBlock == 0) {
        !           343:                VCB_LOCK(vcb);
        !           344:                startingBlock = vcb->nextAllocation;
        !           345:                VCB_UNLOCK(vcb);
        !           346:                updateAllocPtr = true;
        !           347:        }
        !           348:        
        !           349:        //
        !           350:        //      If the request must be contiguous, then find a sequence of free blocks
        !           351:        //      that is long enough.  Otherwise, find the first free block.
        !           352:        //
        !           353:        if (forceContiguous) {
        !           354:                err = BlockAllocateContig(vcb, startingBlock, minBlocks, maxBlocks, actualStartBlock, actualNumBlocks);
        !           355:        } else {
        !           356:                err = BlockAllocateAny(vcb, startingBlock, vcb->totalBlocks, maxBlocks, actualStartBlock, actualNumBlocks);
        !           357:                if (err == dskFulErr) {
        !           358:                        err = BlockAllocateAny(vcb, 0, startingBlock, maxBlocks, actualStartBlock, actualNumBlocks);
        !           359:                        };
        !           360:        }
        !           361: 
        !           362:        if (err == noErr) {
        !           363:                //
        !           364:                //      If we used the volume's roving allocation pointer, then we need to update it.
        !           365:                //      Adding in the length of the current allocation might reduce the next allocate
        !           366:                //      call by avoiding a re-scan of the already allocated space.  However, the clump
        !           367:                //      just allocated can quite conceivably end up being truncated or released when
        !           368:                //      the file is closed or its EOF changed.  Leaving the allocation pointer at the
        !           369:                //      start of the last allocation will avoid unnecessary fragmentation in this case.
        !           370:                //
        !           371:                VCB_LOCK(vcb);
        !           372: 
        !           373:                if (updateAllocPtr)
        !           374:                        vcb->nextAllocation = *actualStartBlock;
        !           375:                
        !           376:                //
        !           377:                //      Update the number of free blocks on the volume
        !           378:                //
        !           379:                vcb->freeBlocks -= *actualNumBlocks;
        !           380:                VCB_UNLOCK(vcb);
        !           381: 
        !           382:                UpdateVCBFreeBlks( vcb );
        !           383:                MarkVCBDirty(vcb);
        !           384:        }
        !           385:        
        !           386: Exit:
        !           387: 
        !           388: #if HFSInstrumentation
        !           389:        InstLogTraceEvent( trace, eventTag, kInstEndEvent);
        !           390: #endif
        !           391:        LogEndTime(kTraceBlockAllocate, err);
        !           392: 
        !           393:        return err;
        !           394: }
        !           395: 
        !           396: 
        !           397: /*
        !           398: ;________________________________________________________________________________
        !           399: ;
        !           400: ; Routine:        UpdateVCBFreeBlks
        !           401: ;
        !           402: ; Function:    Whenever the freeBlocks field in the ExtendedVCB is updated,
        !           403: ;                         we must also recalculate the (UInt16) vcbFreeBks field in the
        !           404: ;                         traditional HFS VCB structure.
        !           405: ;
        !           406: ; Input Arguments:
        !           407: ;       vcb            - Pointer to ExtendedVCB for the volume to free space on
        !           408: ;________________________________________________________________________________
        !           409: */
        !           410: void UpdateVCBFreeBlks( ExtendedVCB *vcb )
        !           411: {
        !           412:        #if DEBUG_BUILD
        !           413:                if ( vcb->vcbSigWord == kHFSSigWord && vcb->freeBlocks > 0xFFFF )
        !           414:                        DebugStr("\p UpdateVCBFreeBlks: freeBlocks overflow!");
        !           415:        #endif
        !           416: }
        !           417: 
        !           418: 
        !           419: /*
        !           420: ;________________________________________________________________________________
        !           421: ;
        !           422: ; Routine:        BlkDealloc
        !           423: ;
        !           424: ; Function:    Update the bitmap to deallocate a run of disk allocation blocks
        !           425: ;
        !           426: ; Input Arguments:
        !           427: ;       vcb            - Pointer to ExtendedVCB for the volume to free space on
        !           428: ;       firstBlock     - First allocation block to be freed
        !           429: ;       numBlocks      - Number of allocation blocks to free up (must be > 0!)
        !           430: ;
        !           431: ; Output:
        !           432: ;       (result)       - Result code
        !           433: ;
        !           434: ; Side effects:
        !           435: ;       The volume bitmap is read and updated; the volume bitmap cache may be changed.
        !           436: ;
        !           437: ; Modification history:
        !           438: ;
        !           439: ;      <06Oct85>  PWD  Changed to check for error after calls to ReadBM and NextWord
        !           440: ;                                      Now calls NextBit to read successive bits from the bitmap
        !           441: ;________________________________________________________________________________
        !           442: */
        !           443: 
        !           444: OSErr BlockDeallocate (
        !           445:        ExtendedVCB             *vcb,                   //      Which volume to deallocate space on
        !           446:        UInt32                  firstBlock,             //      First block in range to deallocate
        !           447:        UInt32                  numBlocks)              //      Number of contiguous blocks to deallocate
        !           448: {
        !           449:        OSErr                   err;
        !           450:        
        !           451: #if HFSInstrumentation
        !           452:        InstTraceClassRef       trace;
        !           453:        InstEventTag            eventTag;
        !           454:        
        !           455:        err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:BlockDeallocate", 'hfs+', kInstEnableClassMask, &trace);
        !           456:        if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
        !           457: 
        !           458:        eventTag = InstCreateEventTag();
        !           459:        InstLogTraceEvent( trace, eventTag, kInstStartEvent);
        !           460: #endif
        !           461: 
        !           462:        //
        !           463:        //      If no blocks to deallocate, then exit early
        !           464:        //
        !           465:        if (numBlocks == 0) {
        !           466:                err = noErr;
        !           467:                goto Exit;
        !           468:        }
        !           469: 
        !           470:        //
        !           471:        //      Call internal routine to free the sequence of blocks
        !           472:        //
        !           473:        err = BlockMarkFree(vcb, firstBlock, numBlocks);
        !           474:        if (err)
        !           475:                goto Exit;
        !           476: 
        !           477:        //
        !           478:        //      Update the volume's free block count, and mark the VCB as dirty.
        !           479:        //
        !           480:        VCB_LOCK(vcb);
        !           481:        vcb->freeBlocks += numBlocks;
        !           482:        VCB_UNLOCK(vcb);
        !           483:        UpdateVCBFreeBlks( vcb );
        !           484:        MarkVCBDirty(vcb);
        !           485: 
        !           486: Exit:
        !           487: 
        !           488: #if HFSInstrumentation
        !           489:        InstLogTraceEvent( trace, eventTag, kInstEndEvent);
        !           490: #endif
        !           491: 
        !           492:        return err;
        !           493: }
        !           494: 
        !           495: 
        !           496: /*
        !           497: ;_______________________________________________________________________
        !           498: ;
        !           499: ; Routine:             UpdateFree
        !           500: ; Arguments:   vcb     -- ExtendedVCB for volume
        !           501: ;
        !           502: ; Called By:   MountVol
        !           503: ; Function:    This routine is used as part of the MountVol consistency check
        !           504: ;                              to figure out the number of free allocation blocks in the volume.
        !           505: ;
        !           506: ; Modification History:
        !           507: ;      <08Sep85>  LAK  New today.
        !           508: ;      <06Oct85>  PWD  Added explicit check for errors after calls to ReadBM, NextWord
        !           509: ;                                      Now calls NextBit.
        !           510: ;_______________________________________________________________________
        !           511: */
        !           512: 
        !           513: OSErr UpdateFreeCount (
        !           514:        ExtendedVCB     *vcb)                           //      Volume whose free block count should be updated
        !           515: {
        !           516:        OSErr                   err;
        !           517:        register UInt32 wordsLeft;              //      Number of words left in this bitmap block
        !           518:        register UInt32 numBlocks;              //      Number of blocks left to scan
        !           519:        register UInt32 freeCount;              //      Running count of free blocks found so far
        !           520:        register UInt32 temp;
        !           521:        UInt32                  blockNum;               //      Block number of first block in this bitmap block
        !           522:        UInt32                  *buffer = NULL; //      Pointer to bitmap block
        !           523:        register UInt32 *currentWord;   //      Pointer to current word in bitmap block
        !           524:        
        !           525: #if HFSInstrumentation
        !           526:        InstTraceClassRef       trace;
        !           527:        InstEventTag            eventTag;
        !           528:        
        !           529:        err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:UpdateFreeCount", 'hfs+', kInstEnableClassMask, &trace);
        !           530:        if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
        !           531: 
        !           532:        eventTag = InstCreateEventTag();
        !           533:        InstLogTraceEvent( trace, eventTag, kInstStartEvent);
        !           534: #endif
        !           535: 
        !           536:        //
        !           537:        //      Pre-read the first bitmap block
        !           538:        //
        !           539: 
        !           540:        err = ReadBitmapBlock(vcb, 0, &buffer);
        !           541:        if (err != noErr) goto Exit;
        !           542: 
        !           543:        //
        !           544:        //      Initialize buffer stuff
        !           545:        //
        !           546:        currentWord = buffer;
        !           547:        wordsLeft = kWordsPerBlock;
        !           548:        numBlocks = vcb->totalBlocks;
        !           549:        freeCount = 0;
        !           550:        blockNum = 0;
        !           551:        
        !           552:        //
        !           553:        //      Scan whole words first
        !           554:        //
        !           555:        
        !           556:        while (numBlocks >= kBitsPerWord) {
        !           557:                //      See if it's time to move to the next bitmap block
        !           558:                if (wordsLeft == 0) {
        !           559:                        //      Read in the next bitmap block
        !           560:                        blockNum += kBitsPerBlock;                              //      generate a block number in the next bitmap block
        !           561:                        
        !           562: #if EXPLICIT_BUFFER_RELEASES
        !           563:                        err = RelBlock_glue((Ptr)buffer, rbDefault);
        !           564:                        if (err != noErr) goto Exit;
        !           565:                        buffer = NULL;
        !           566: #endif
        !           567:                        err = ReadBitmapBlock(vcb, blockNum, &buffer);
        !           568:                        if (err != noErr) goto Exit;
        !           569:                        
        !           570:                        //      Readjust currentWord, wordsLeft
        !           571:                        currentWord = buffer;
        !           572:                        wordsLeft = kWordsPerBlock;
        !           573:                }
        !           574:                
        !           575:                //      We count free blocks by inverting the word in the bitmap and counting set bits.
        !           576:                temp = ~(*currentWord);
        !           577:                while (temp) {
        !           578:                        ++freeCount;
        !           579:                        temp &= temp-1;                 //      this clears least significant bit that is currently set
        !           580:                }
        !           581: 
        !           582:                numBlocks -= kBitsPerWord;
        !           583:                ++currentWord;                                                          //      move to next word
        !           584:                --wordsLeft;                                                            //      one less word left in this block
        !           585:        }
        !           586:        
        !           587:        //
        !           588:        //      Check any remaining blocks.
        !           589:        //
        !           590:        
        !           591:        if (numBlocks != 0) {
        !           592:                if (wordsLeft == 0) {
        !           593:                        //      Read in the next bitmap block
        !           594:                        blockNum += kBitsPerBlock;                              //      generate a block number in the next bitmap block
        !           595:                        
        !           596: #if EXPLICIT_BUFFER_RELEASES
        !           597:                        err = RelBlock_glue((Ptr)buffer, rbDefault);
        !           598:                        if (err != noErr) goto Exit;
        !           599:                        buffer = NULL;
        !           600: #endif
        !           601:                        err = ReadBitmapBlock(vcb, blockNum, &buffer);
        !           602:                        if (err != noErr) goto Exit;
        !           603:                        
        !           604:                        //      Readjust currentWord, wordsLeft
        !           605:                        currentWord = buffer;
        !           606:                        wordsLeft = kWordsPerBlock;
        !           607:                }
        !           608:                
        !           609:                //      We count free blocks by inverting the word in the bitmap and counting set bits.
        !           610:                temp = ~(*currentWord);
        !           611:                while (numBlocks != 0) {
        !           612:                        if (temp & kHighBitInWordMask)
        !           613:                                ++freeCount;
        !           614:                        temp <<= 1;
        !           615:                        --numBlocks;
        !           616:                }
        !           617:        }
        !           618: 
        !           619:        VCB_LOCK(vcb);
        !           620:        vcb->freeBlocks = freeCount;
        !           621:        VCB_UNLOCK(vcb);
        !           622:        UpdateVCBFreeBlks( vcb );
        !           623: 
        !           624: Exit:
        !           625: 
        !           626: #if EXPLICIT_BUFFER_RELEASES
        !           627:        if (buffer) {
        !           628:                (void)RelBlock_glue((Ptr)buffer, rbDefault);            /* Ignore any additional errors */
        !           629:        };
        !           630: #endif
        !           631: 
        !           632: #if HFSInstrumentation
        !           633:        InstLogTraceEvent( trace, eventTag, kInstEndEvent);
        !           634: #endif
        !           635: 
        !           636:        return err;
        !           637: }
        !           638: 
        !           639: 
        !           640: 
        !           641: /*
        !           642: ;_______________________________________________________________________
        !           643: ;
        !           644: ; Routine:             AllocateFreeSpace
        !           645: ; Arguments:   vcb     -- ExtendedVCB for volume
        !           646: ;
        !           647: ; Called By:   HFSDiskInitComponent
        !           648: ; Function:    This routine is used as part of DiskInit to create an
        !           649: ;                              embedded HFS+ volume.
        !           650: ;
        !           651: ; Note: Assumes that the free space is contiguous (true for a freshly erased disk)
        !           652: ;_______________________________________________________________________
        !           653: */
        !           654: 
        !           655: OSErr AllocateFreeSpace (
        !           656:        ExtendedVCB             *vcb,                           //      Volume whose free space is about to be expropriated
        !           657:        UInt32                  *startBlock,            // return where free space starts
        !           658:        UInt32                  *actualBlocks)          // return the number of blocks in free space
        !           659: {
        !           660:        OSErr                   err;
        !           661: 
        !           662:        err = BlockAllocateAny(vcb, 0, vcb->totalBlocks, vcb->freeBlocks, startBlock, actualBlocks);
        !           663: 
        !           664:        if (err == noErr) {
        !           665:                VCB_LOCK(vcb);
        !           666:                vcb->freeBlocks = 0;    // sorry, no more blocks left!
        !           667:                VCB_UNLOCK(vcb);
        !           668:                MarkVCBDirty(vcb);
        !           669:        }
        !           670:        
        !           671:        return err;
        !           672: }
        !           673: 
        !           674: /*
        !           675: ;_______________________________________________________________________
        !           676: ;
        !           677: ; Routine:     FileBytesToBlocks
        !           678: ;
        !           679: ; Function:    Divide numerator by denominator, rounding up the result if there
        !           680: ;                      was a remainder.  This is frequently used for computing the number
        !           681: ;                      of whole and/or partial blocks used by some count of bytes.
        !           682: ;                      Actuall divides a 64 bit by a 32 bit into a 32bit result
        !           683: ;              
        !           684: ;                      CAREFULL!!! THIS CAN CAUSE OVERFLOW....USER BEWARE!!!
        !           685: ;_______________________________________________________________________
        !           686: */
        !           687: UInt32 FileBytesToBlocks(
        !           688:        SInt64 numerator,
        !           689:        UInt32 denominator)
        !           690: {
        !           691:        UInt32  quotient;
        !           692:        
        !           693:        quotient = (UInt32)(numerator / denominator);
        !           694:        if (quotient * denominator != numerator)
        !           695:                quotient++;
        !           696:        
        !           697:        return quotient;
        !           698: }
        !           699: 
        !           700: 
        !           701: 
        !           702: /*
        !           703: ;_______________________________________________________________________
        !           704: ;
        !           705: ; Routine:     ReadBitmapBlock
        !           706: ;
        !           707: ; Function:    Read in a bitmap block corresponding to a given allocation
        !           708: ;                      block.  Return a pointer to the bitmap block.
        !           709: ;
        !           710: ; Inputs:
        !           711: ;      vcb                     --      Pointer to ExtendedVCB
        !           712: ;      block           --      Allocation block whose bitmap block is desired
        !           713: ;
        !           714: ; Outputs:
        !           715: ;      buffer          --      Pointer to bitmap block corresonding to "block"
        !           716: ;_______________________________________________________________________
        !           717: */
        !           718: static OSErr ReadBitmapBlock(
        !           719:        ExtendedVCB             *vcb,
        !           720:        UInt32                  block,
        !           721:        UInt32                  **buffer)
        !           722: {
        !           723:        OSErr                   err;
        !           724: 
        !           725: #if HFSInstrumentation
        !           726:        InstTraceClassRef       trace;
        !           727:        InstEventTag            eventTag;
        !           728:        
        !           729:        err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:ReadBitmapBlock", 'hfs+', kInstEnableClassMask, &trace);
        !           730:        if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
        !           731: 
        !           732:        eventTag = block;               // a cheap way to get the block number into the log
        !           733:        InstLogTraceEvent( trace, eventTag, kInstStartEvent);
        !           734: #endif
        !           735: 
        !           736:        err = noErr;
        !           737: 
        !           738:        RequireFileLock(vcb->extentsRefNum, false);     /* bitmap blocks are covered by the Extents B-tree lock */
        !           739: 
        !           740:        if (vcb->vcbSigWord == kHFSSigWord) {
        !           741:                //
        !           742:                //      HFS: Turn block number into physical block offset within the
        !           743:                //      bitmap, and then the physical block within the volume.
        !           744:                //
        !           745:                block /= kBitsPerBlock;         // block offset within bitmap
        !           746:                block += vcb->vcbVBMSt;         // block within whole volume
        !           747:        }
        !           748:        else {
        !           749:                FCB             *allocFile;
        !           750:                UInt32  startBlock;
        !           751:                UInt32  availableBytes;
        !           752:                
        !           753:                //
        !           754:                //      HFS+: Read from allocation file.  We simply convert the block number into a byte
        !           755:                //      offset within the allocation file and then determine which block that byte is in.
        !           756:                //
        !           757:                allocFile = GetFileControlBlock(vcb->allocationsRefNum);
        !           758: 
        !           759:                //
        !           760:                //      Find out which physical block holds byte #offset in allocation file.  Note that we
        !           761:                //      map only 1 byte (the one we asked for).
        !           762:                //
        !           763:                err = MapFileBlockC(vcb, allocFile, 1, block/kBitsPerByte, &startBlock, &availableBytes);
        !           764:                block = startBlock;
        !           765:        }
        !           766: 
        !           767:        if (err == noErr) {
        !           768:                    err = GetBlock_glue(
        !           769: #if EXPLICIT_BUFFER_RELEASES
        !           770:                                                                0,                                              // No options
        !           771: #else
        !           772:                                 gbReleaseMask,                 // Release block immediately.  We only work on one
        !           773:                                                                                                                // block at a time.  Call MarkBlock later if dirty.
        !           774: #endif
        !           775:                                 block,                                 // Physical block on volume
        !           776:                                 (Ptr *) buffer,                        // A place to return the buffer pointer
        !           777:                                 kNoFileReference,              // Not a file read
        !           778:                                 vcb);                                  // Volume to read from
        !           779:        }
        !           780: 
        !           781: #if HFSInstrumentation
        !           782:        InstLogTraceEvent( trace, eventTag, kInstEndEvent);
        !           783: #endif
        !           784: 
        !           785:        return err;
        !           786: }
        !           787: 
        !           788: 
        !           789: 
        !           790: /*
        !           791: _______________________________________________________________________
        !           792: 
        !           793: Routine:       BlockAllocateContig
        !           794: 
        !           795: Function:      Allocate a contiguous group of allocation blocks.  The
        !           796:                        allocation is all-or-nothing.  The caller guarantees that
        !           797:                        there are enough free blocks (though they may not be
        !           798:                        contiguous, in which case this call will fail).
        !           799: 
        !           800: Inputs:
        !           801:        vcb                             Pointer to volume where space is to be allocated
        !           802:        startingBlock   Preferred first block for allocation
        !           803:        minBlocks               Minimum number of contiguous blocks to allocate
        !           804:        maxBlocks               Maximum number of contiguous blocks to allocate
        !           805: 
        !           806: Outputs:
        !           807:        actualStartBlock        First block of range allocated, or 0 if error
        !           808:        actualNumBlocks         Number of blocks allocated, or 0 if error
        !           809: _______________________________________________________________________
        !           810: */
        !           811: static OSErr BlockAllocateContig(
        !           812:        ExtendedVCB             *vcb,
        !           813:        UInt32                  startingBlock,
        !           814:        UInt32                  minBlocks,
        !           815:        UInt32                  maxBlocks,
        !           816:        UInt32                  *actualStartBlock,
        !           817:        UInt32                  *actualNumBlocks)
        !           818: {
        !           819:        OSErr   err;
        !           820: 
        !           821:        //
        !           822:        //      Find a contiguous group of blocks at least minBlocks long.
        !           823:        //      Determine the number of contiguous blocks available (up
        !           824:        //      to maxBlocks).
        !           825:        //
        !           826:        err = BlockFindContiguous(vcb, startingBlock, vcb->totalBlocks, minBlocks, maxBlocks,
        !           827:                                                                  actualStartBlock, actualNumBlocks);
        !           828:        if (err == dskFulErr) {
        !           829:                //�� Should constrain the endingBlock here, so we don't bother looking for ranges
        !           830:                //�� that start after startingBlock, since we already checked those.
        !           831:                err = BlockFindContiguous(vcb, 0, vcb->totalBlocks, minBlocks, maxBlocks,
        !           832:                                                                          actualStartBlock, actualNumBlocks);
        !           833:        }
        !           834:        if (err != noErr) goto Exit;
        !           835: 
        !           836:        //
        !           837:        //      Now mark those blocks allocated.
        !           838:        //
        !           839:        err = BlockMarkAllocated(vcb, *actualStartBlock, *actualNumBlocks);
        !           840:        
        !           841: Exit:
        !           842:        if (err != noErr) {
        !           843:                *actualStartBlock = 0;
        !           844:                *actualNumBlocks = 0;
        !           845:        }
        !           846:        
        !           847:        return err;
        !           848: }
        !           849: 
        !           850: extern OSErr LookupBufferMapping(caddr_t bufferAddress, struct buf **bpp, int *mappingIndexPtr);
        !           851: 
        !           852: /*
        !           853: _______________________________________________________________________
        !           854: 
        !           855: Routine:       BlockAllocateAny
        !           856: 
        !           857: Function:      Allocate one or more allocation blocks.  If there are fewer
        !           858:                        free blocks than requested, all free blocks will be
        !           859:                        allocated.  The caller guarantees that there is at least
        !           860:                        one free block.
        !           861: 
        !           862: Inputs:
        !           863:        vcb                             Pointer to volume where space is to be allocated
        !           864:        startingBlock   Preferred first block for allocation
        !           865:        endingBlock             Last block to check + 1
        !           866:        maxBlocks               Maximum number of contiguous blocks to allocate
        !           867: 
        !           868: Outputs:
        !           869:        actualStartBlock        First block of range allocated, or 0 if error
        !           870:        actualNumBlocks         Number of blocks allocated, or 0 if error
        !           871: _______________________________________________________________________
        !           872: */
        !           873: OSErr BlockAllocateAny(
        !           874:        ExtendedVCB             *vcb,
        !           875:        UInt32                  startingBlock,
        !           876:        register UInt32 endingBlock,
        !           877:        UInt32                  maxBlocks,
        !           878:        UInt32                  *actualStartBlock,
        !           879:        UInt32                  *actualNumBlocks)
        !           880: {
        !           881:        OSErr                   err;
        !           882:        register UInt32 block;                  //      current block number
        !           883:        register UInt32 currentWord;    //      Pointer to current word within bitmap block
        !           884:        register UInt32 bitMask;                //      Word with given bits already set (ready to OR in)
        !           885:        register UInt32 wordsLeft;              //      Number of words left in this bitmap block
        !           886:     UInt32                     *buffer = NULL;
        !           887:     UInt32                     *currCache = NULL;
        !           888: 
        !           889: #if HFS_DIAGNOSTIC
        !           890:     struct buf *bp = NULL;
        !           891:     int mappingEntry;
        !           892: #endif
        !           893: 
        !           894:        //      Since this routine doesn't wrap around
        !           895:        if (maxBlocks > (endingBlock - startingBlock)) {
        !           896:                maxBlocks = endingBlock - startingBlock;
        !           897:        }
        !           898: 
        !           899:     DBG_TREE (("\nAllocating starting at %ld, maxblocks %ld\n", startingBlock, maxBlocks));    
        !           900:        //
        !           901:        //      Pre-read the first bitmap block
        !           902:        //
        !           903:     err = ReadBitmapBlock(vcb, startingBlock, &currCache);
        !           904:     DBG_TREE (("\n1. Read bit map at %ld, buffer is 0x%x\n", startingBlock, (int)currCache));  
        !           905:        if (err != noErr) goto Exit;
        !           906:     buffer = currCache;
        !           907:     MarkBlock_glue((Ptr) currCache);           //      this block will be dirty
        !           908:     DBG_ASSERT(! LookupBufferMapping((caddr_t)currCache, &bp, &mappingEntry));
        !           909: 
        !           910:        //
        !           911:        //      Set up the current position within the block
        !           912:        //
        !           913:        {
        !           914:                UInt32 wordIndexInBlock;
        !           915: 
        !           916:                wordIndexInBlock = (startingBlock & kBitsWithinBlockMask) / kBitsPerWord;
        !           917:                buffer += wordIndexInBlock;
        !           918:                wordsLeft = kWordsPerBlock - wordIndexInBlock;
        !           919:                currentWord = *buffer;
        !           920:                bitMask = kHighBitInWordMask >> (startingBlock & kBitsWithinWordMask);
        !           921:        }
        !           922:        
        !           923:        //
        !           924:        //      Find the first unallocated block
        !           925:        //
        !           926:        block=startingBlock;
        !           927:        while (block < endingBlock) {
        !           928:                if ((currentWord & bitMask) == 0)
        !           929:                        break;
        !           930:                
        !           931:                //      Next bit
        !           932:                ++block;
        !           933:                bitMask >>= 1;
        !           934:                if (bitMask == 0) {
        !           935:                        //      Next word
        !           936:                        bitMask = kHighBitInWordMask;
        !           937:                        ++buffer;
        !           938:                        
        !           939:                        if (--wordsLeft == 0) {
        !           940:                                //      Next block
        !           941: #if EXPLICIT_BUFFER_RELEASES
        !           942:                DBG_ASSERT(! LookupBufferMapping((caddr_t)currCache, &bp, &mappingEntry));
        !           943:                err = RelBlock_glue((Ptr)currCache, rbDefault);
        !           944:                                if (err != noErr) goto Exit;
        !           945:                 buffer = currCache = NULL;
        !           946: #endif
        !           947:                 err = ReadBitmapBlock(vcb, block, &currCache);
        !           948:                                if (err != noErr) goto Exit;
        !           949:                 buffer = currCache;
        !           950:                 DBG_TREE (("\n2. Read bit map at %ld, buffer is 0x%x\n", block, (int)currCache));      
        !           951:                 DBG_ASSERT(! LookupBufferMapping((caddr_t)currCache, &bp, &mappingEntry));
        !           952:                 MarkBlock_glue((Ptr) currCache);               //      this block will be dirty
        !           953: 
        !           954:                                wordsLeft = kWordsPerBlock;
        !           955:                        }
        !           956:                        
        !           957:                        currentWord = *buffer;
        !           958:                }
        !           959:        }
        !           960: 
        !           961:        //      Did we get to the end of the bitmap before finding a free block?
        !           962:        //      If so, then couldn't allocate anything.
        !           963:        if (block == endingBlock) {
        !           964:                err = dskFulErr;
        !           965:                goto Exit;
        !           966:        }
        !           967: 
        !           968:        //      Return the first block in the allocated range
        !           969:        *actualStartBlock = block;
        !           970:        
        !           971:        //      If we could get the desired number of blocks before hitting endingBlock,
        !           972:        //      then adjust endingBlock so we won't keep looking.  Ideally, the comparison
        !           973:        //      would be (block + maxBlocks) < endingBlock, but that could overflow.  The
        !           974:        //      comparison below yields identical results, but without overflow.
        !           975:        if (block < (endingBlock-maxBlocks)) {
        !           976:                endingBlock = block + maxBlocks;        //      if we get this far, we've found enough
        !           977:        }
        !           978:        
        !           979:        //
        !           980:        //      Allocate all of the consecutive blocks
        !           981:        //
        !           982:        while ((currentWord & bitMask) == 0) {
        !           983:                //      Allocate this block
        !           984:                currentWord |= bitMask;
        !           985:                
        !           986:                //      Move to the next block.  If no more, then exit.
        !           987:                ++block;
        !           988:                if (block == endingBlock)
        !           989:                        break;
        !           990: 
        !           991:                //      Next bit
        !           992:                bitMask >>= 1;
        !           993:                if (bitMask == 0) {
        !           994:                        *buffer = currentWord;                                  //      update value in bitmap
        !           995:                        
        !           996:                        //      Next word
        !           997:                        bitMask = kHighBitInWordMask;
        !           998:                        ++buffer;
        !           999:                        
        !          1000:                        if (--wordsLeft == 0) {
        !          1001:                                //      Next block
        !          1002: #if EXPLICIT_BUFFER_RELEASES
        !          1003:                DBG_ASSERT(! LookupBufferMapping((caddr_t)currCache, &bp, &mappingEntry));
        !          1004:                        err = RelBlock_glue((Ptr)currCache, rbDefault);
        !          1005:                                if (err != noErr) goto Exit;
        !          1006:                 buffer = currCache = NULL;
        !          1007: #endif
        !          1008:                 err = ReadBitmapBlock(vcb, block, &currCache);
        !          1009:                                if (err != noErr) goto Exit;
        !          1010:                 buffer = currCache;
        !          1011:                 DBG_TREE (("\n3. Read bit map at %ld, buffer is 0x%x\n", block, (int)currCache));      
        !          1012:                 DBG_ASSERT(! LookupBufferMapping((caddr_t)currCache, &bp, &mappingEntry));
        !          1013:                 MarkBlock_glue((Ptr) currCache);               //      this block will be dirty
        !          1014: 
        !          1015:                                wordsLeft = kWordsPerBlock;
        !          1016:                        }
        !          1017:                        
        !          1018:                        currentWord = *buffer;
        !          1019:                }
        !          1020:        }
        !          1021:        *buffer = currentWord;                                                  //      update the last change
        !          1022: 
        !          1023: Exit:
        !          1024:        if (err == noErr) {
        !          1025:                *actualNumBlocks = block - *actualStartBlock;
        !          1026:        }
        !          1027:        else {
        !          1028:                *actualStartBlock = 0;
        !          1029:                *actualNumBlocks = 0;
        !          1030:        }
        !          1031:        
        !          1032: #if EXPLICIT_BUFFER_RELEASES
        !          1033:     if (currCache) {
        !          1034:         DBG_ASSERT(! LookupBufferMapping((caddr_t)currCache, &bp, &mappingEntry));
        !          1035:         (void)RelBlock_glue((Ptr)currCache, rbDefault);                /* Ignore any additional errors */
        !          1036:         };
        !          1037: #endif
        !          1038: 
        !          1039:        return err;
        !          1040: }
        !          1041: 
        !          1042: 
        !          1043: 
        !          1044: /*
        !          1045: _______________________________________________________________________
        !          1046: 
        !          1047: Routine:       BlockMarkAllocated
        !          1048: 
        !          1049: Function:      Mark a contiguous group of blocks as allocated (set in the
        !          1050:                        bitmap).  It assumes those bits are currently marked
        !          1051:                        deallocated (clear in the bitmap).
        !          1052: 
        !          1053: Inputs:
        !          1054:        vcb                             Pointer to volume where space is to be allocated
        !          1055:        startingBlock   First block number to mark as allocated
        !          1056:        numBlocks               Number of blocks to mark as allocated
        !          1057: _______________________________________________________________________
        !          1058: */
        !          1059: static OSErr BlockMarkAllocated(
        !          1060:        ExtendedVCB             *vcb,
        !          1061:        UInt32                  startingBlock,
        !          1062:        register UInt32 numBlocks)
        !          1063: {
        !          1064:        OSErr                   err;
        !          1065:        register UInt32 *currentWord;   //      Pointer to current word within bitmap block
        !          1066:        register UInt32 wordsLeft;              //      Number of words left in this bitmap block
        !          1067:        register UInt32 bitMask;                //      Word with given bits already set (ready to OR in)
        !          1068:        UInt32                  firstBit;               //      Bit index within word of first bit to allocate
        !          1069:        UInt32                  numBits;                //      Number of bits in word to allocate
        !          1070:        UInt32                  *buffer = NULL;
        !          1071: 
        !          1072: #if HFSInstrumentation
        !          1073:        InstTraceClassRef       trace;
        !          1074:        InstEventTag            eventTag;
        !          1075:        
        !          1076:        err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:BlockMarkAllocated", 'hfs+', kInstEnableClassMask, &trace);
        !          1077:        if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
        !          1078: 
        !          1079:        eventTag = InstCreateEventTag();
        !          1080:        InstLogTraceEvent( trace, eventTag, kInstStartEvent);
        !          1081: #endif
        !          1082: 
        !          1083:        //
        !          1084:        //      Pre-read the bitmap block containing the first word of allocation
        !          1085:        //
        !          1086: 
        !          1087:        err = ReadBitmapBlock(vcb, startingBlock, &buffer);
        !          1088:        if (err != noErr) goto Exit;
        !          1089:        MarkBlock_glue((Ptr) buffer);           //      this block will be dirty
        !          1090: 
        !          1091:        //
        !          1092:        //      Initialize currentWord, and wordsLeft.
        !          1093:        //
        !          1094:        {
        !          1095:                UInt32 wordIndexInBlock;
        !          1096: 
        !          1097:                wordIndexInBlock = (startingBlock & kBitsWithinBlockMask) / kBitsPerWord;
        !          1098:                currentWord = buffer + wordIndexInBlock;
        !          1099:                wordsLeft = kWordsPerBlock - wordIndexInBlock;
        !          1100:        }
        !          1101:        
        !          1102:        //
        !          1103:        //      If the first block to allocate doesn't start on a word
        !          1104:        //      boundary in the bitmap, then treat that first word
        !          1105:        //      specially.
        !          1106:        //
        !          1107: 
        !          1108:        firstBit = startingBlock % kBitsPerWord;
        !          1109:        if (firstBit != 0) {
        !          1110:                bitMask = kAllBitsSetInWord >> firstBit;        //      turn off all bits before firstBit
        !          1111:                numBits = kBitsPerWord - firstBit;                      //      number of remaining bits in this word
        !          1112:                if (numBits > numBlocks) {
        !          1113:                        numBits = numBlocks;                                    //      entire allocation is inside this one word
        !          1114:                        bitMask &= ~(kAllBitsSetInWord >> (firstBit + numBits));        //      turn off bits after last
        !          1115:                }
        !          1116: #if DEBUG_BUILD
        !          1117:                if ((*currentWord & bitMask) != 0) {
        !          1118:                        DebugStr("\pFATAL: blocks already allocated!");
        !          1119:                        //err = fsDSIntErr;
        !          1120:                        //goto Exit;
        !          1121:                }
        !          1122: #endif
        !          1123:                *currentWord |= bitMask;                                        //      set the bits in the bitmap
        !          1124:                numBlocks -= numBits;                                           //      adjust number of blocks left to allocate
        !          1125: 
        !          1126:                ++currentWord;                                                          //      move to next word
        !          1127:                --wordsLeft;                                                            //      one less word left in this block
        !          1128:        }
        !          1129: 
        !          1130:        //
        !          1131:        //      Allocate whole words (32 blocks) at a time.
        !          1132:        //
        !          1133: 
        !          1134:        bitMask = kAllBitsSetInWord;                                    //      put this in a register for 68K
        !          1135:        while (numBlocks >= kBitsPerWord) {
        !          1136:                if (wordsLeft == 0) {
        !          1137:                        //      Read in the next bitmap block
        !          1138:                        startingBlock += kBitsPerBlock;                 //      generate a block number in the next bitmap block
        !          1139:                        
        !          1140: #if EXPLICIT_BUFFER_RELEASES
        !          1141:                        err = RelBlock_glue((Ptr)buffer, rbDefault);
        !          1142:                        if (err != noErr) goto Exit;
        !          1143:                        buffer = NULL;
        !          1144: #endif
        !          1145:                        err = ReadBitmapBlock(vcb, startingBlock, &buffer);
        !          1146:                        if (err != noErr) goto Exit;
        !          1147:                        MarkBlock_glue((Ptr) buffer);                   //      this block will be dirty
        !          1148:                        
        !          1149:                        //      Readjust currentWord and wordsLeft
        !          1150:                        currentWord = buffer;
        !          1151:                        wordsLeft = kWordsPerBlock;
        !          1152:                }
        !          1153: #if DEBUG_BUILD
        !          1154:                if (*currentWord != 0) {
        !          1155:                        DebugStr("\pFATAL: blocks already allocated!");
        !          1156:                        //err = fsDSIntErr;
        !          1157:                        //goto Exit;
        !          1158:                }
        !          1159: #endif
        !          1160:                *currentWord = bitMask;
        !          1161:                numBlocks -= kBitsPerWord;
        !          1162: 
        !          1163:                ++currentWord;                                                          //      move to next word
        !          1164:                --wordsLeft;                                                            //      one less word left in this block
        !          1165:        }
        !          1166:        
        !          1167:        //
        !          1168:        //      Allocate any remaining blocks.
        !          1169:        //
        !          1170:        
        !          1171:        if (numBlocks != 0) {
        !          1172:                bitMask = ~(kAllBitsSetInWord >> numBlocks);    //      set first numBlocks bits
        !          1173:                if (wordsLeft == 0) {
        !          1174:                        //      Read in the next bitmap block
        !          1175:                        startingBlock += kBitsPerBlock;                         //      generate a block number in the next bitmap block
        !          1176:                        
        !          1177: #if EXPLICIT_BUFFER_RELEASES
        !          1178:                        err = RelBlock_glue((Ptr)buffer, rbDefault);
        !          1179:                        if (err != noErr) goto Exit;
        !          1180:                        buffer = NULL;
        !          1181: #endif
        !          1182:                        err = ReadBitmapBlock(vcb, startingBlock, &buffer);
        !          1183:                        if (err != noErr) goto Exit;
        !          1184:                        MarkBlock_glue((Ptr) buffer);                           //      this block will be dirty
        !          1185:                        
        !          1186:                        //      Readjust currentWord and wordsLeft
        !          1187:                        currentWord = buffer;
        !          1188:                        wordsLeft = kWordsPerBlock;
        !          1189:                }
        !          1190: #if DEBUG_BUILD
        !          1191:                if ((*currentWord & bitMask) != 0) {
        !          1192:                        DebugStr("\pFATAL: blocks already allocated!");
        !          1193:                        //err = fsDSIntErr;
        !          1194:                        //goto Exit;
        !          1195:                }
        !          1196: #endif
        !          1197:                *currentWord |= bitMask;                                                //      set the bits in the bitmap
        !          1198: 
        !          1199:                //      No need to update currentWord or wordsLeft
        !          1200:        }
        !          1201: 
        !          1202: Exit:
        !          1203: 
        !          1204: #if EXPLICIT_BUFFER_RELEASES
        !          1205:        if (buffer) {
        !          1206:                (void)RelBlock_glue((Ptr)buffer, rbDefault);            /* Ignore any additional errors */
        !          1207:        };
        !          1208: #endif
        !          1209: 
        !          1210: #if HFSInstrumentation
        !          1211:        InstLogTraceEvent( trace, eventTag, kInstEndEvent);
        !          1212: #endif
        !          1213: 
        !          1214:        return err;
        !          1215: }
        !          1216: 
        !          1217: 
        !          1218: 
        !          1219: /*
        !          1220: _______________________________________________________________________
        !          1221: 
        !          1222: Routine:       BlockMarkFree
        !          1223: 
        !          1224: Function:      Mark a contiguous group of blocks as free (clear in the
        !          1225:                        bitmap).  It assumes those bits are currently marked
        !          1226:                        allocated (set in the bitmap).
        !          1227: 
        !          1228: Inputs:
        !          1229:        vcb                             Pointer to volume where space is to be freed
        !          1230:        startingBlock   First block number to mark as freed
        !          1231:        numBlocks               Number of blocks to mark as freed
        !          1232: _______________________________________________________________________
        !          1233: */
        !          1234: static OSErr BlockMarkFree(
        !          1235:        ExtendedVCB             *vcb,
        !          1236:        UInt32                  startingBlock,
        !          1237:        register UInt32 numBlocks)
        !          1238: {
        !          1239:        OSErr                   err;
        !          1240:        register UInt32 *currentWord;   //      Pointer to current word within bitmap block
        !          1241:        register UInt32 wordsLeft;              //      Number of words left in this bitmap block
        !          1242:        register UInt32 bitMask;                //      Word with given bits already set (ready to OR in)
        !          1243:        UInt32                  firstBit;               //      Bit index within word of first bit to allocate
        !          1244:        UInt32                  numBits;                //      Number of bits in word to allocate
        !          1245:        UInt32                  *buffer = NULL;
        !          1246: 
        !          1247: #if HFSInstrumentation
        !          1248:        InstTraceClassRef       trace;
        !          1249:        InstEventTag            eventTag;
        !          1250:        
        !          1251:        err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:BlockMarkFree", 'hfs+', kInstEnableClassMask, &trace);
        !          1252:        if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
        !          1253: 
        !          1254:        eventTag = InstCreateEventTag();
        !          1255:        InstLogTraceEvent( trace, eventTag, kInstStartEvent);
        !          1256: #endif
        !          1257: 
        !          1258:        //
        !          1259:        //      Pre-read the bitmap block containing the first word of allocation
        !          1260:        //
        !          1261: 
        !          1262:        err = ReadBitmapBlock(vcb, startingBlock, &buffer);
        !          1263:        if (err != noErr) goto Exit;
        !          1264:        MarkBlock_glue((Ptr) buffer);           //      this block will be dirty
        !          1265: 
        !          1266:        //
        !          1267:        //      Initialize currentWord, and wordsLeft.
        !          1268:        //
        !          1269:        {
        !          1270:                UInt32 wordIndexInBlock;
        !          1271: 
        !          1272:                wordIndexInBlock = (startingBlock & kBitsWithinBlockMask) / kBitsPerWord;
        !          1273:                currentWord = buffer + wordIndexInBlock;
        !          1274:                wordsLeft = kWordsPerBlock - wordIndexInBlock;
        !          1275:        }
        !          1276:        
        !          1277:        //
        !          1278:        //      If the first block to free doesn't start on a word
        !          1279:        //      boundary in the bitmap, then treat that first word
        !          1280:        //      specially.
        !          1281:        //
        !          1282: 
        !          1283:        firstBit = startingBlock % kBitsPerWord;
        !          1284:        if (firstBit != 0) {
        !          1285:                bitMask = kAllBitsSetInWord >> firstBit;        //      turn off all bits before firstBit
        !          1286:                numBits = kBitsPerWord - firstBit;                      //      number of remaining bits in this word
        !          1287:                if (numBits > numBlocks) {
        !          1288:                        numBits = numBlocks;                                    //      entire allocation is inside this one word
        !          1289:                        bitMask &= ~(kAllBitsSetInWord >> (firstBit + numBits));        //      turn off bits after last
        !          1290:                }
        !          1291: #if DEBUG_BUILD
        !          1292:                if ((*currentWord & bitMask) != bitMask) {
        !          1293:                        DebugStr("\pFATAL: blocks not allocated!");
        !          1294:                        //err = fsDSIntErr;
        !          1295:                        //goto Exit;
        !          1296:                }
        !          1297: #endif
        !          1298:                *currentWord &= ~bitMask;                                       //      clear the bits in the bitmap
        !          1299:                numBlocks -= numBits;                                           //      adjust number of blocks left to free
        !          1300: 
        !          1301:                ++currentWord;                                                          //      move to next word
        !          1302:                --wordsLeft;                                                            //      one less word left in this block
        !          1303:        }
        !          1304: 
        !          1305:        //
        !          1306:        //      Allocate whole words (32 blocks) at a time.
        !          1307:        //
        !          1308: 
        !          1309:        while (numBlocks >= kBitsPerWord) {
        !          1310:                if (wordsLeft == 0) {
        !          1311:                        //      Read in the next bitmap block
        !          1312:                        startingBlock += kBitsPerBlock;                 //      generate a block number in the next bitmap block
        !          1313:                        
        !          1314: #if EXPLICIT_BUFFER_RELEASES
        !          1315:                        err = RelBlock_glue((Ptr)buffer, rbDefault);
        !          1316:                        if (err != noErr) goto Exit;
        !          1317:                        buffer = NULL;
        !          1318: #endif
        !          1319:                        err = ReadBitmapBlock(vcb, startingBlock, &buffer);
        !          1320:                        if (err != noErr) goto Exit;
        !          1321:                        MarkBlock_glue((Ptr) buffer);                   //      this block will be dirty
        !          1322:                        
        !          1323:                        //      Readjust currentWord and wordsLeft
        !          1324:                        currentWord = buffer;
        !          1325:                        wordsLeft = kWordsPerBlock;
        !          1326:                }
        !          1327: 
        !          1328: #if DEBUG_BUILD
        !          1329:                if (*currentWord != kAllBitsSetInWord) {
        !          1330:                        DebugStr("\pFATAL: blocks not allocated!");
        !          1331:                        //err = fsDSIntErr;
        !          1332:                        //goto Exit;
        !          1333:                }
        !          1334: #endif
        !          1335:                *currentWord = 0;                                                       //      clear the entire word
        !          1336:                numBlocks -= kBitsPerWord;
        !          1337:                
        !          1338:                ++currentWord;                                                          //      move to next word
        !          1339:                --wordsLeft;                                                            //      one less word left in this block
        !          1340:        }
        !          1341:        
        !          1342:        //
        !          1343:        //      Allocate any remaining blocks.
        !          1344:        //
        !          1345:        
        !          1346:        if (numBlocks != 0) {
        !          1347:                bitMask = ~(kAllBitsSetInWord >> numBlocks);    //      set first numBlocks bits
        !          1348:                if (wordsLeft == 0) {
        !          1349:                        //      Read in the next bitmap block
        !          1350:                        startingBlock += kBitsPerBlock;                         //      generate a block number in the next bitmap block
        !          1351:                        
        !          1352: #if EXPLICIT_BUFFER_RELEASES
        !          1353:                        err = RelBlock_glue((Ptr)buffer, rbDefault);
        !          1354:                        if (err != noErr) goto Exit;
        !          1355:                        buffer = NULL;
        !          1356: #endif
        !          1357:                        err = ReadBitmapBlock(vcb, startingBlock, &buffer);
        !          1358:                        if (err != noErr) goto Exit;
        !          1359:                        MarkBlock_glue((Ptr) buffer);                           //      this block will be dirty
        !          1360:                        
        !          1361:                        //      Readjust currentWord and wordsLeft
        !          1362:                        currentWord = buffer;
        !          1363:                        wordsLeft = kWordsPerBlock;
        !          1364:                }
        !          1365: #if DEBUG_BUILD
        !          1366:                if ((*currentWord & bitMask) != bitMask) {
        !          1367:                        DebugStr("\pFATAL: blocks not allocated!");
        !          1368:                        //err = fsDSIntErr;
        !          1369:                        //goto Exit;
        !          1370:                }
        !          1371: #endif
        !          1372:                *currentWord &= ~bitMask;                                               //      clear the bits in the bitmap
        !          1373: 
        !          1374:                //      No need to update currentWord or wordsLeft
        !          1375:        }
        !          1376: 
        !          1377: Exit:
        !          1378: 
        !          1379: #if EXPLICIT_BUFFER_RELEASES
        !          1380:        if (buffer) {
        !          1381:                (void)RelBlock_glue((Ptr)buffer, rbDefault);            /* Ignore any additional errors */
        !          1382:        };
        !          1383: #endif
        !          1384: 
        !          1385: #if HFSInstrumentation
        !          1386:        InstLogTraceEvent( trace, eventTag, kInstEndEvent);
        !          1387: #endif
        !          1388: 
        !          1389:        return err;
        !          1390: }
        !          1391: 
        !          1392: 
        !          1393: /*
        !          1394: _______________________________________________________________________
        !          1395: 
        !          1396: Routine:       BlockFindContiguous
        !          1397: 
        !          1398: Function:      Find a contiguous range of blocks that are free (bits
        !          1399:                        clear in the bitmap).  If a contiguous range of the
        !          1400:                        minimum size can't be found, an error will be returned.
        !          1401:                        
        !          1402:                        �� It would be nice if we could skip over whole words
        !          1403:                        �� with all bits set.
        !          1404:                        
        !          1405:                        �� When we find a bit set, and are about to set freeBlocks
        !          1406:                        �� to 0, we should check to see whether there are still
        !          1407:                        �� minBlocks bits left in the bitmap.
        !          1408: 
        !          1409: Inputs:
        !          1410:        vcb                             Pointer to volume where space is to be allocated
        !          1411:        startingBlock   Preferred first block of range
        !          1412:        endingBlock             Last possible block in range + 1
        !          1413:        minBlocks               Minimum number of blocks needed.  Must be > 0.
        !          1414:        maxBlocks               Maximum (ideal) number of blocks desired
        !          1415: 
        !          1416: Outputs:
        !          1417:        actualStartBlock        First block of range found, or 0 if error
        !          1418:        actualNumBlocks         Number of blocks found, or 0 if error
        !          1419: _______________________________________________________________________
        !          1420: */
        !          1421: /*
        !          1422: _________________________________________________________________________________________
        !          1423:        (DSH) 5/8/97 Description of BlockFindContiguous() algorithm
        !          1424:        Finds a contiguous range of free blocks by searching back to front.  This
        !          1425:        allows us to skip ranges of bits knowing that they are not candidates for
        !          1426:        a match because they are too small.  The below ascii diagrams illustrate
        !          1427:        the algorithm in action.
        !          1428:        
        !          1429:        Representation of a piece of a volume bitmap file
        !          1430:        If BlockFindContiguous() is called with minBlocks == 10, maxBlocks == 20
        !          1431: 
        !          1432: 
        !          1433: Fig. 1 initialization of variables, "<--" represents direction of travel
        !          1434: 
        !          1435: startingBlock (passed in)
        !          1436:        |
        !          1437:        1  0  1  0  1  0  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1
        !          1438:        |                       <--|
        !          1439: stopBlock                 currentBlock                        freeBlocks == 0
        !          1440:                                                               countedFreeBlocks == 0
        !          1441: 
        !          1442: Fig. 2 dirty bit found
        !          1443: 
        !          1444:        1  0  1  0  1  0  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1
        !          1445:        |                 |
        !          1446: stopBlock        currentBlock                                 freeBlocks == 3
        !          1447:                                                               countedFreeBlocks == 0
        !          1448: 
        !          1449: Fig. 3 reset variables to search for remainder of minBlocks
        !          1450: 
        !          1451:        1  0  1  0  1  0  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1
        !          1452:        |_________________|           |                 |
        !          1453:             Unsearched            stopBlock        currentBlock    freeBlocks == 0
        !          1454:                                                                    countedFreeBlocks == 3
        !          1455: 
        !          1456: Fig. 4 minBlocks contiguous blocks found, *actualStartBlock is set
        !          1457: 
        !          1458:        1  0  1  0  1  0  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1
        !          1459:        |_________________|           |
        !          1460:             Unsearched            stopBlock                      freeBlocks == 7
        !          1461:                                  currentBlock                    countedFreeBlocks == 3
        !          1462: 
        !          1463: Fig. 5 Now run it forwards trying to accumalate up to maxBlocks if possible
        !          1464: 
        !          1465:        1  0  1  0  1  0  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1
        !          1466:        |_________________|                                | -->
        !          1467:             Unsearched                               currentBlock
        !          1468:                                                                      *actualNumBlocks == 10
        !          1469: 
        !          1470: Fig. 6 Dirty bit is found, return actual number of contiguous blocks found
        !          1471: 
        !          1472:        1  0  1  0  1  0  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1
        !          1473:        |_________________|                                                  |
        !          1474:             Unsearched                                                 currentBlock
        !          1475:                                                                      *actualNumBlocks == 16
        !          1476: _________________________________________________________________________________________
        !          1477: */
        !          1478: 
        !          1479: static OSErr BlockFindContiguous(
        !          1480:        ExtendedVCB             *vcb,
        !          1481:        UInt32                  startingBlock,
        !          1482:        register UInt32 endingBlock,
        !          1483:        UInt32                  minBlocks,
        !          1484:        UInt32                  maxBlocks,
        !          1485:        UInt32                  *actualStartBlock,
        !          1486:        UInt32                  *actualNumBlocks)
        !          1487: {
        !          1488:        OSErr                   err;
        !          1489:        register UInt32 bitMask;                        //      mask of bit within word for currentBlock
        !          1490:        register UInt32 tempWord;                       //      bitmap word currently being examined
        !          1491:        register UInt32 freeBlocks;                     //      number of contiguous free blocks so far
        !          1492:        register UInt32 currentBlock;           //      block number we're currently examining
        !          1493:        UInt32                  wordsLeft;                      //      words remaining in bitmap block
        !          1494:        UInt32                  *buffer = NULL;
        !          1495:        register UInt32 *currentWord;
        !          1496:        
        !          1497:        UInt32                  stopBlock;                      //      when all blocks until stopBlock are free, we found enough
        !          1498:        UInt32                  countedFreeBlocks;      //      how many contiguous free block behind stopBlock
        !          1499:        UInt32                  currentSector;          //      which allocations file sector
        !          1500: 
        !          1501: #if HFSInstrumentation
        !          1502:        InstTraceClassRef               trace;
        !          1503:        InstEventTag                    eventTag;
        !          1504:        
        !          1505:        err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:BlockFindContiguous", 'hfs+', kInstEnableClassMask, &trace);
        !          1506:        if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
        !          1507: 
        !          1508:        eventTag = InstCreateEventTag();
        !          1509:        InstLogTraceEvent( trace, eventTag, kInstStartEvent);
        !          1510: #endif
        !          1511: 
        !          1512:        if ((endingBlock - startingBlock) < minBlocks) {
        !          1513:                //      The set of blocks we're checking is smaller than the minimum number
        !          1514:                //      of blocks, so we couldn't possibly find a good range.
        !          1515:                err = dskFulErr;
        !          1516:                goto Exit;
        !          1517:        }
        !          1518:        
        !          1519:        //      Search for min blocks from back to front.
        !          1520:        //      If min blocks is found, advance the allocation pointer up to max blocks
        !          1521:        
        !          1522:        //
        !          1523:        //      Pre-read the bitmap block containing currentBlock
        !          1524:        //
        !          1525:        stopBlock               = startingBlock;
        !          1526:        currentBlock    = startingBlock + minBlocks - 1;                //      (-1) to include startingBlock
        !          1527:        
        !          1528:        err = ReadBitmapBlock( vcb, currentBlock, &buffer );
        !          1529:        if ( err != noErr ) goto Exit;
        !          1530:        
        !          1531:        //
        !          1532:        //      Init buffer, currentWord, wordsLeft, and bitMask
        !          1533:        //
        !          1534:        {
        !          1535:                UInt32 wordIndexInBlock;
        !          1536: 
        !          1537:                wordIndexInBlock = ( currentBlock & kBitsWithinBlockMask ) / kBitsPerWord;
        !          1538:                currentWord             = buffer + wordIndexInBlock;
        !          1539:                                
        !          1540:                wordsLeft               = wordIndexInBlock;
        !          1541:                tempWord                = *currentWord;
        !          1542:                bitMask                 = kHighBitInWordMask >> ( currentBlock & kBitsWithinWordMask );
        !          1543:                currentSector   = currentBlock / kBitsPerBlock;
        !          1544:        }
        !          1545:        
        !          1546:        //
        !          1547:        //      Look for maxBlocks free blocks.  If we find an allocated block,
        !          1548:        //      see if we've found minBlocks.
        !          1549:        //
        !          1550:        freeBlocks                      = 0;
        !          1551:        countedFreeBlocks       = 0;
        !          1552: 
        !          1553:        while ( currentBlock >= stopBlock )
        !          1554:        {
        !          1555:                //      Check current bit
        !          1556:                if ((tempWord & bitMask) == 0)
        !          1557:                {
        !          1558:                        ++freeBlocks;
        !          1559:                }
        !          1560:                else                                                                                                                    //      Used bitmap block found
        !          1561:                {
        !          1562:                        if ( ( freeBlocks +  countedFreeBlocks ) >= minBlocks )
        !          1563:                        {
        !          1564:                                break;                                                                                                  //      Found enough
        !          1565:                        }
        !          1566:                        else
        !          1567:                        {
        !          1568:                                //      We found a dirty bit, so we want to check if the next (minBlocks-freeBlocks) blocks
        !          1569:                                //      are free beyond what we have already checked. At Fig.2 setting up for Fig.3
        !          1570:                                
        !          1571:                                stopBlock                       = currentBlock + 1 + freeBlocks;        //      Advance stop condition
        !          1572:                                currentBlock            += minBlocks;
        !          1573:                                if ( currentBlock >= endingBlock ) break;
        !          1574:                                countedFreeBlocks       = freeBlocks;
        !          1575:                                freeBlocks                      = 0;                                                            //      Not enough; look for another range
        !          1576: 
        !          1577:                                if ( currentSector != currentBlock / kBitsPerBlock )
        !          1578:                                {
        !          1579: #if EXPLICIT_BUFFER_RELEASES
        !          1580:                                        err = RelBlock_glue((Ptr)buffer, rbDefault);
        !          1581:                                        if (err != noErr) goto Exit;
        !          1582:                                        buffer = NULL;
        !          1583: #endif
        !          1584:                                        err = ReadBitmapBlock( vcb, currentBlock, &buffer );
        !          1585:                                        if (err != noErr) goto Exit;
        !          1586:                                        currentSector = currentBlock / kBitsPerBlock;
        !          1587:                                }
        !          1588:                                        
        !          1589:                                wordsLeft       = ( currentBlock & kBitsWithinBlockMask ) / kBitsPerWord;
        !          1590:                                currentWord     = buffer + wordsLeft;
        !          1591:                                tempWord        = *currentWord;
        !          1592:                                bitMask         = kHighBitInWordMask >> ( currentBlock & kBitsWithinWordMask );
        !          1593: 
        !          1594:                                continue;                                                                                               //      Back to the while loop
        !          1595:                        }
        !          1596:                }
        !          1597:                
        !          1598:                //      Move to next bit
        !          1599:                --currentBlock;
        !          1600:                bitMask <<= 1;
        !          1601:                if (bitMask == 0)                                                                                               //      On a word boundry, start masking words
        !          1602:                {
        !          1603:                        bitMask = kLowBitInWordMask;
        !          1604: 
        !          1605:                        //      Move to next word
        !          1606: NextWord:
        !          1607:                        if ( wordsLeft != 0 )
        !          1608:                        {
        !          1609:                                --currentWord;
        !          1610:                                --wordsLeft;
        !          1611:                        }
        !          1612:                        else
        !          1613:                        {
        !          1614:                                //      Read in the next bitmap block
        !          1615: #if EXPLICIT_BUFFER_RELEASES
        !          1616:                                err = RelBlock_glue((Ptr)buffer, rbDefault);
        !          1617:                                if (err != noErr) goto Exit;
        !          1618:                                buffer = NULL;
        !          1619: #endif
        !          1620:                                err = ReadBitmapBlock( vcb, currentBlock, &buffer );
        !          1621:                                if (err != noErr) goto Exit;
        !          1622:                                
        !          1623:                                //      Adjust currentWord, wordsLeft, currentSector
        !          1624:                                currentSector   = currentBlock / kBitsPerBlock;
        !          1625:                                currentWord             = buffer + kWordsPerBlock - 1;  //      Last word in buffer
        !          1626:                                wordsLeft               = kWordsPerBlock - 1;
        !          1627:                        }
        !          1628:                        
        !          1629:                        tempWord = *currentWord;                                                        //      Grab the current word
        !          1630: 
        !          1631:                        //
        !          1632:                        //      If we found a whole word of free blocks, quickly skip over it.
        !          1633:                        //      NOTE: we could actually go beyond the end of the bitmap if the
        !          1634:                        //      number of allocation blocks on the volume is not a multiple of
        !          1635:                        //      32.  If this happens, we'll adjust currentBlock and freeBlocks
        !          1636:                        //      after the loop.
        !          1637:                        //
        !          1638:                        if ( tempWord == 0 )
        !          1639:                        {
        !          1640:                                freeBlocks              += kBitsPerWord;
        !          1641:                                currentBlock    -= kBitsPerWord;
        !          1642:                                if ( freeBlocks + countedFreeBlocks >= minBlocks )
        !          1643:                                        break;                                                                  //      Found enough
        !          1644:                                goto NextWord;
        !          1645:                        }
        !          1646:                }
        !          1647:        }
        !          1648: 
        !          1649:        if ( freeBlocks + countedFreeBlocks < minBlocks )
        !          1650:        {
        !          1651:                *actualStartBlock       = 0;
        !          1652:                *actualNumBlocks        = 0;
        !          1653:                err                                     = dskFulErr;
        !          1654:                goto Exit;
        !          1655:        }
        !          1656: 
        !          1657:        //
        !          1658:        //      When we get here, we know we've found minBlocks continuous space.
        !          1659:        //      At Fig.4, setting up for Fig.5
        !          1660:        //      From here we do a forward search accumalating additional free blocks.
        !          1661:        //
        !          1662:        
        !          1663:        *actualNumBlocks        = minBlocks;
        !          1664:        *actualStartBlock       = stopBlock - countedFreeBlocks;        //      ActualStartBlock is set to return to the user
        !          1665:        currentBlock            = *actualStartBlock + minBlocks;        //      Right after found free space
        !          1666:        
        !          1667:        //      Now lets see if we can run the actualNumBlocks number all the way up to maxBlocks
        !          1668:        if ( currentSector != currentBlock / kBitsPerBlock )
        !          1669:        {
        !          1670: #if EXPLICIT_BUFFER_RELEASES
        !          1671:                err = RelBlock_glue((Ptr)buffer, rbDefault);
        !          1672:                if (err != noErr) goto Exit;
        !          1673:                buffer = NULL;
        !          1674: #endif
        !          1675:                err = ReadBitmapBlock( vcb, currentBlock, &buffer );
        !          1676:                if (err != noErr)
        !          1677:                {
        !          1678:                        err     = noErr;                                                                        //      We already found the space
        !          1679:                        goto Exit;
        !          1680:                }
        !          1681:                
        !          1682:                currentSector = currentBlock / kBitsPerBlock;
        !          1683:        }
        !          1684: 
        !          1685:        //
        !          1686:        //      Init buffer, currentWord, wordsLeft, and bitMask
        !          1687:        //
        !          1688:        {
        !          1689:                UInt32 wordIndexInBlock;
        !          1690: 
        !          1691:                wordIndexInBlock = (currentBlock & kBitsWithinBlockMask) / kBitsPerWord;
        !          1692:                currentWord             = buffer + wordIndexInBlock;
        !          1693:                tempWord                = *currentWord;
        !          1694:                wordsLeft               = kWordsPerBlock - wordIndexInBlock;
        !          1695:                bitMask                 = kHighBitInWordMask >> (currentBlock & kBitsWithinWordMask);
        !          1696:        }
        !          1697: 
        !          1698:        if ( *actualNumBlocks < maxBlocks )
        !          1699:        {
        !          1700:                while ( currentBlock < endingBlock )
        !          1701:                {
        !          1702:                                
        !          1703:                        if ( (tempWord & bitMask) == 0 )
        !          1704:                        {
        !          1705:                                *actualNumBlocks        += 1;
        !          1706:                                
        !          1707:                                if ( *actualNumBlocks == maxBlocks )
        !          1708:                                        break;
        !          1709:                        }
        !          1710:                        else
        !          1711:                        {
        !          1712:                                break;
        !          1713:                        }
        !          1714:        
        !          1715:                        //      Move to next bit
        !          1716:                        ++currentBlock;
        !          1717:                        bitMask >>= 1;
        !          1718:                        if (bitMask == 0)
        !          1719:                        {
        !          1720:                                bitMask = kHighBitInWordMask;
        !          1721:                                ++currentWord;
        !          1722:        
        !          1723:                                if ( --wordsLeft == 0)
        !          1724:                                {
        !          1725: #if EXPLICIT_BUFFER_RELEASES
        !          1726:                                        err = RelBlock_glue((Ptr)buffer, rbDefault);
        !          1727:                                        if (err != noErr) goto Exit;
        !          1728:                                        buffer = NULL;
        !          1729: #endif
        !          1730:                                        err = ReadBitmapBlock(vcb, currentBlock, &buffer);
        !          1731:                                        if (err != noErr) break;
        !          1732:                                        
        !          1733:                                        //      Adjust currentWord, wordsLeft
        !          1734:                                        currentWord             = buffer;
        !          1735:                                        wordsLeft               = kWordsPerBlock;
        !          1736:                                }
        !          1737:                                tempWord = *currentWord;                        //      grab the current word
        !          1738:                        }
        !          1739:                }
        !          1740:        }
        !          1741:        
        !          1742: Exit:
        !          1743: 
        !          1744: #if EXPLICIT_BUFFER_RELEASES
        !          1745:        if (buffer) {
        !          1746:                (void)RelBlock_glue((Ptr)buffer, rbDefault);            /* Ignore any additional errors */
        !          1747:        };
        !          1748: #endif
        !          1749: 
        !          1750: #if HFSInstrumentation
        !          1751:        InstLogTraceEvent( trace, eventTag, kInstEndEvent);
        !          1752: #endif
        !          1753: 
        !          1754:        return err;
        !          1755: }
        !          1756: 
        !          1757: 

unix.superglobalmegacorp.com

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