|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.