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

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