|
|
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: FileExtentMapping.c ! 24: ! 25: Contains: xxx put contents here xxx ! 26: ! 27: Version: HFS Plus 1.0 ! 28: ! 29: Written by: Dave Heller, Mark Day ! 30: ! 31: Copyright: � 1996-1999 by Apple Computer, Inc., all rights reserved. ! 32: ! 33: File Ownership: ! 34: ! 35: DRI: Mark Day ! 36: ! 37: Other Contact: xxx put other contact here xxx ! 38: ! 39: Technology: xxx put technology here xxx ! 40: ! 41: Writers: ! 42: ! 43: (DSH) Deric Horn ! 44: (msd) Mark Day ! 45: (djb) Don Brady ! 46: ! 47: Change History (most recent first): ! 48: <MacOSX> 9/9/99 djb Fix fcbModifiedMask flag testing logic. ! 49: <MacOSX> 8/25/98 djb Flush extents b-tree header if dirty (2371088). ! 50: <MacOSX> 6/30/98 djb Add functions NodesAreContiguous and ExtentsAreIntegral (for radar #2249539). ! 51: <MacOSX> 6/23/98 djb Changed DeallocFile to DeleteFile which now deletes the catalog record. ! 52: Fixed UpdateExtentRecord to pass correct fcb to Btree routines. Fixed ! 53: hfs+ bug in CreateExtentRecord (double dereference). ! 54: <MacOSX> 5/20/98 djb In ExtendFileC don't lie about the peof! (radar #2230094). ! 55: <MacOSX> 4/17/98 djb Add VCB locking. ! 56: <MacOSX> 4/2/98 djb Switch over to real BTree interface (no more BTreeWrapper.c). ! 57: <MacOSX> 3/31/98 djb Sync up with final HFSVolumes.h header file. ! 58: ! 59: <CS24> 1/23/98 msd Bug 2208024: AllocContig is actually allocating one extent even ! 60: though there is not enough contiguous space. ! 61: <CS23> 12/2/97 DSH GetFCBExtentRecord no longer static so DFA can use it. ! 62: <CS22> 10/20/97 msd When allocating more space for a file, do the clump size ! 63: calculations in ExtendFileC, not BlockAllocate. Undo change from ! 64: <CS18>. ! 65: <CS21> 10/17/97 msd Conditionalize DebugStrs. ! 66: <CS20> 10/16/97 msd Simplify the code path for MapFileBlockC (logical to physical ! 67: block mapping) in the typical case where the file isn't ! 68: fragmented so badly that it has extents in the extents B-tree. ! 69: Simplified some of the calculations for all cases. ! 70: <CS19> 10/13/97 DSH FindExtentRecord & DeleteExtentRecord are also being used by DFA ! 71: no longer static. ! 72: <CS18> 10/6/97 msd When extending a file, set the physical EOF to include any extra ! 73: space allocated due to a file's clump size. ! 74: <CS17> 9/19/97 msd Remove the MapLogicalToPhysical SPI. It was never used and is ! 75: not being tested anyway. ! 76: <CS16> 9/5/97 msd In CompareExtentKeys and CompareExtentKeysPlus, use the symbolic ! 77: constants for key length. Don't DebugStr unless DEBUG_BUILD is ! 78: set. ! 79: <CS15> 7/24/97 djb Add instrumentation to MapFileBlockC ! 80: <CS14> 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name ! 81: collision ! 82: <CS13> 7/15/97 DSH AdjEOF() mark the FCB as modified. (1664389) ! 83: <CS12> 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line ! 84: <CS11> 7/3/97 msd Bug #1663518. Remove DebugStr when setting the FCB extent record ! 85: for a volume control file. ! 86: <CS10> 6/27/97 msd Moved enum kFirstFileRefnum to FilesInternal. ! 87: <CS9> 6/24/97 djb Include "CatalogPrivate.h" ! 88: <CS8> 6/16/97 msd Finish implementation of CreateLargeFile SPI. ! 89: <CS7> 6/12/97 msd Add stub for CreateLargeFile SPI. ! 90: <CS6> 6/5/97 msd Add MapLogicalToPhysical. ! 91: <CS5> 6/2/97 msd In TruncateFileC, don't update the extent record unless it was ! 92: actually changed (prevents extra updates when truncating to the ! 93: end of the extent, and it is the last extent of the file.) Added ! 94: an AdjustEOF routine called by the assembly AdjEOF routine. It ! 95: copies the EOF, physical length, and extent information from one ! 96: FCB to all other FCBs for that fork. ! 97: <CS4> 5/20/97 DSH Removed const declaration in MapFileBlocC, const is benign when ! 98: passing by value, and SC requires it to match prototype. ! 99: <CS3> 5/15/97 msd Change enum kResourceForkType from -1 to 0xFF since it is now ! 100: unsigned. Change all forkType parameters to UInt8. ! 101: <CS2> 5/7/97 msd When checking for an unused extent descriptor, check the length, ! 102: not the starting block. ! 103: <CS1> 4/24/97 djb first checked in ! 104: <HFS25> 4/11/97 DSH use extended VCB fields catalogRefNum, and extentsRefNum. ! 105: <HFS24> 4/4/97 djb Get in sync with volume format changes. ! 106: <HFS23> 3/17/97 DSH Casting to compile with SC. ! 107: <HFS22> 2/26/97 msd Add instrumentation in ExtendFileC and TruncateFileC. In ! 108: CompareExtentKeys and CompareExtentKeysPlus, make sure the key ! 109: lengths are correct. ! 110: <HFS21> 2/5/97 msd The comparison with fsBTStartOfIterationErr didn't work because ! 111: the enum is an unsigned long; it is now casted to an OSErr ! 112: before comparing. ! 113: <HFS20> 1/31/97 msd In FindExtentRecord, turn an fsBTStartOfIterationErr error into ! 114: btNotFound. ! 115: <HFS19> 1/28/97 msd Fixed bug in MapFileBlockC where it returned the wrong number of ! 116: bytes available at the given block number. This could ! 117: potentially cause programs to read or write over other files. ! 118: <HFS18> 1/16/97 djb Extent key compare procs now return SInt32. Fixed ! 119: UpdateExtentRecord - it was passing a pointer to an ExtentKey ! 120: pointer. ! 121: <HFS17> 1/10/97 msd Change TruncateFileC to call DellocateFork when the new PEOF is ! 122: 0. Fixes a fxRangeErr returned when no extents existed. ! 123: <HFS16> 1/6/97 msd Previous change prevents extent records from being removed if ! 124: the files new PEOF is in the local (FCB/catalog) extents. ! 125: <HFS15> 1/3/97 djb Temp fix in TruncateFileC to prevent unwanted calls to ! 126: TruncateExtents. ! 127: <HFS14> 12/23/96 msd Previous change to SearchExtentFile didn't set up the outputs ! 128: for hint and key when the FCB extent record wasn't full. ! 129: <HFS13> 12/20/96 msd In SearchExtentFile, don't bother searching the extents file if ! 130: the FCB's extent record wasn't full, or if the FCB was for the ! 131: extents file itself. Modified SearchExtentRecord to return a ! 132: Boolean to indicate that the record was not full. ! 133: <HFS12> 12/19/96 DSH Changed refs from VCB to ExtendedVCB ! 134: <HFS11> 12/19/96 djb Updated for new B-tree Manager interface. ! 135: <HFS10> 12/12/96 djb Really use new SPI for GetCatalogNode. ! 136: <HFS9> 12/12/96 djb Use new Catalog SPI for GetCatalogNode. Added Mark's changes to ! 137: MapFileBlockC. ! 138: <HFS8> 12/11/96 msd TruncateFileC must always release extents, even if PEOF hasn't ! 139: changed (since allocation may have been rounded up due to clump ! 140: size). ! 141: <HFS7> 12/10/96 msd Check PRAGMA_LOAD_SUPPORTED before loading precompiled headers. ! 142: <HFS6> 12/4/96 DSH Precompiled headers ! 143: <HFS5> 11/26/96 msd Add an exported routine to grow the parallel FCB table to ! 144: accomodate the HFS+ ExtentRecord. ! 145: <HFS4> 11/26/96 msd Convert internal routines to use ExtentKey and ExtentRecord ! 146: (instead of the raw HFS structures). ! 147: <HFS3> 11/21/96 msd Added CompareExtentKeysPlus(). ! 148: <HFS2> 11/20/96 msd Finish porting FXM to C. ! 149: <HFS1> 11/6/96 DKH first checked in ! 150: ! 151: */ ! 152: ! 153: ! 154: #include "../../hfs.h" ! 155: #include "../../hfs_format.h" ! 156: ! 157: #include "../headers/FileMgrInternal.h" ! 158: #include "../headers/BTreesInternal.h" ! 159: #include "../headers/CatalogPrivate.h" // calling a private catalog routine (LocateCatalogNode) ! 160: ! 161: #include "../headers/HFSInstrumentation.h" ! 162: ! 163: ! 164: /* ! 165: ============================================================ ! 166: Public (Exported) Routines: ! 167: ============================================================ ! 168: DeAllocFile Deallocate all disk space allocated to a specified file. ! 169: Both forks are deallocated. ! 170: ! 171: ExtendFileC Allocate more space to a given file. ! 172: ! 173: CompareExtentKeys ! 174: Compare two extents file keys (a search key and a trial ! 175: key). Used by the BTree manager when searching for, ! 176: adding, or deleting keys in the extents file of an HFS ! 177: volume. ! 178: ! 179: CompareExtentKeysPlus ! 180: Compare two extents file keys (a search key and a trial ! 181: key). Used by the BTree manager when searching for, ! 182: adding, or deleting keys in the extents file of an HFS+ ! 183: volume. ! 184: ! 185: MapFileBlockC Convert (map) an offset within a given file into a ! 186: physical disk address. ! 187: ! 188: TruncateFileC Truncates the disk space allocated to a file. The file ! 189: space is truncated to a specified new physical EOF, rounded ! 190: up to the next allocation block boundry. There is an option ! 191: to truncate to the end of the extent containing the new EOF. ! 192: ! 193: FlushExtentFile ! 194: Flush the extents file for a given volume. ! 195: ! 196: GrowParallelFCBs ! 197: Make sure the parallel FCB entries are big enough to support ! 198: the HFS+ ExtentRecord. If not, the array is grown and the ! 199: pre-existing data copied over. ! 200: ! 201: AdjustEOF ! 202: Copy EOF, physical length, and extent records from one FCB ! 203: to all other FCBs for that fork. This is used when a file is ! 204: grown or shrunk as the result of a Write, SetEOF, or Allocate. ! 205: ! 206: MapLogicalToPhysical ! 207: Map some position in a file to a volume block number. Also ! 208: returns the number of contiguous bytes that are mapped there. ! 209: This is a queued HFSDispatch call that does the equivalent of ! 210: MapFileBlockC, using a parameter block. ! 211: ! 212: ============================================================ ! 213: Internal Routines: ! 214: ============================================================ ! 215: FindExtentRecord ! 216: Search the extents BTree for a particular extent record. ! 217: SearchExtentFile ! 218: Search the FCB and extents file for an extent record that ! 219: contains a given file position (in bytes). ! 220: SearchExtentRecord ! 221: Search a given extent record to see if it contains a given ! 222: file position (in bytes). Used by SearchExtentFile. ! 223: ReleaseExtents ! 224: Deallocate all allocation blocks in all extents of an extent ! 225: data record. ! 226: TruncateExtents ! 227: Deallocate blocks and delete extent records for all allocation ! 228: blocks beyond a certain point in a file. The starting point ! 229: must be the first file allocation block for some extent record ! 230: for the file. ! 231: DeallocateFork ! 232: Deallocate all allocation blocks belonging to a given fork. ! 233: UpdateExtentRecord ! 234: If the extent record came from the extents file, write out ! 235: the updated record; otherwise, copy the updated record into ! 236: the FCB resident extent record. If the record has no extents, ! 237: and was in the extents file, then delete the record instead. ! 238: */ ! 239: ! 240: enum ! 241: { ! 242: kTwoGigabytes = (UInt32) 0x80000000, ! 243: ! 244: kDataForkType = 0, ! 245: kResourceForkType = 0xFF, ! 246: ! 247: kPreviousRecord = -1, ! 248: ! 249: kSectorSize = 512 // Size of a physical sector ! 250: }; ! 251: ! 252: void HFSToHFSPlusExtents( ! 253: const HFSExtentRecord oldExtents, ! 254: HFSPlusExtentRecord newExtents); ! 255: ! 256: OSErr HFSPlusToHFSExtents( ! 257: const HFSPlusExtentRecord oldExtents, ! 258: HFSExtentRecord newExtents); ! 259: ! 260: OSErr FindExtentRecord( ! 261: const ExtendedVCB *vcb, ! 262: UInt8 forkType, ! 263: UInt32 fileID, ! 264: UInt32 startBlock, ! 265: Boolean allowPrevious, ! 266: HFSPlusExtentKey *foundKey, ! 267: HFSPlusExtentRecord foundData, ! 268: UInt32 *foundHint); ! 269: ! 270: OSErr DeleteExtentRecord( ! 271: const ExtendedVCB *vcb, ! 272: UInt8 forkType, ! 273: UInt32 fileID, ! 274: UInt32 startBlock); ! 275: ! 276: static OSErr CreateExtentRecord( ! 277: const ExtendedVCB *vcb, ! 278: HFSPlusExtentKey *key, ! 279: HFSPlusExtentRecord extents, ! 280: UInt32 *hint); ! 281: ! 282: ! 283: OSErr GetFCBExtentRecord( ! 284: const FCB *fcb, ! 285: HFSPlusExtentRecord extents); ! 286: ! 287: static OSErr SearchExtentFile( ! 288: const ExtendedVCB *vcb, ! 289: const FCB *fcb, ! 290: SInt64 filePosition, ! 291: HFSPlusExtentKey *foundExtentKey, ! 292: HFSPlusExtentRecord foundExtentData, ! 293: UInt32 *foundExtentDataIndex, ! 294: UInt32 *extentBTreeHint, ! 295: UInt32 *endingFABNPlusOne ); ! 296: ! 297: static OSErr SearchExtentRecord( ! 298: const ExtendedVCB *vcb, ! 299: UInt32 searchFABN, ! 300: const HFSPlusExtentRecord extentData, ! 301: UInt32 extentDataStartFABN, ! 302: UInt32 *foundExtentDataOffset, ! 303: UInt32 *endingFABNPlusOne, ! 304: Boolean *noMoreExtents); ! 305: ! 306: static OSErr ReleaseExtents( ! 307: ExtendedVCB *vcb, ! 308: const HFSPlusExtentRecord extentRecord, ! 309: UInt32 *numReleasedAllocationBlocks, ! 310: Boolean *releasedLastExtent); ! 311: ! 312: static OSErr DeallocateFork( ! 313: ExtendedVCB *vcb, ! 314: HFSCatalogNodeID fileID, ! 315: UInt8 forkType, ! 316: HFSPlusExtentRecord catalogExtents, ! 317: Boolean * recordDeleted); ! 318: ! 319: static OSErr TruncateExtents( ! 320: ExtendedVCB *vcb, ! 321: UInt8 forkType, ! 322: UInt32 fileID, ! 323: UInt32 startBlock, ! 324: Boolean * recordDeleted); ! 325: ! 326: static OSErr UpdateExtentRecord ( ! 327: const ExtendedVCB *vcb, ! 328: FCB *fcb, ! 329: const HFSPlusExtentKey *extentFileKey, ! 330: const HFSPlusExtentRecord extentData, ! 331: UInt32 extentBTreeHint); ! 332: ! 333: static OSErr MapFileBlockFromFCB( ! 334: const ExtendedVCB *vcb, ! 335: const FCB *fcb, ! 336: SInt64 offset, // Desired offset in bytes from start of file ! 337: UInt32 *firstFABN, // FABN of first block of found extent ! 338: UInt32 *firstBlock, // Corresponding allocation block number ! 339: UInt32 *nextFABN); // FABN of block after end of extent ! 340: ! 341: static Boolean ExtentsAreIntegral( ! 342: const HFSPlusExtentRecord extentRecord, ! 343: UInt32 mask, ! 344: UInt32 *blocksChecked, ! 345: Boolean *checkedLastExtent); ! 346: ! 347: //_________________________________________________________________________________ ! 348: // ! 349: // Routine: FindExtentRecord ! 350: // ! 351: // Purpose: Search the extents BTree for an extent record matching the given ! 352: // FileID, fork, and starting file allocation block number. ! 353: // ! 354: // Inputs: ! 355: // vcb Volume to search ! 356: // forkType 0 = data fork, -1 = resource fork ! 357: // fileID File's FileID (CatalogNodeID) ! 358: // startBlock Starting file allocation block number ! 359: // allowPrevious If the desired record isn't found and this flag is set, ! 360: // then see if the previous record belongs to the same fork. ! 361: // If so, then return it. ! 362: // ! 363: // Outputs: ! 364: // foundKey The key data for the record actually found ! 365: // foundData The extent record actually found (NOTE: on an HFS volume, the ! 366: // fourth entry will be zeroes. ! 367: // foundHint The BTree hint to find the node again ! 368: //_________________________________________________________________________________ ! 369: OSErr FindExtentRecord( ! 370: const ExtendedVCB *vcb, ! 371: UInt8 forkType, ! 372: UInt32 fileID, ! 373: UInt32 startBlock, ! 374: Boolean allowPrevious, ! 375: HFSPlusExtentKey *foundKey, ! 376: HFSPlusExtentRecord foundData, ! 377: UInt32 *foundHint) ! 378: { ! 379: FCB * fcb; ! 380: BTreeIterator btIterator; ! 381: FSBufferDescriptor btRecord; ! 382: OSErr err; ! 383: UInt16 btRecordSize; ! 384: ! 385: err = noErr; ! 386: *foundHint = 0; ! 387: fcb = GetFileControlBlock(vcb->extentsRefNum); ! 388: ! 389: (void) BTInvalidateHint(&btIterator); ! 390: ! 391: if (vcb->vcbSigWord == kHFSSigWord) { ! 392: HFSExtentKey * extentKeyPtr; ! 393: HFSExtentRecord extentData; ! 394: ! 395: extentKeyPtr = (HFSExtentKey*) &btIterator.key; ! 396: extentKeyPtr->keyLength = kHFSExtentKeyMaximumLength; ! 397: extentKeyPtr->forkType = forkType; ! 398: extentKeyPtr->fileID = fileID; ! 399: extentKeyPtr->startBlock = startBlock; ! 400: ! 401: btRecord.bufferAddress = &extentData; ! 402: btRecord.itemSize = sizeof(HFSExtentRecord); ! 403: btRecord.itemCount = 1; ! 404: ! 405: err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator); ! 406: ! 407: if (err == btNotFound && allowPrevious) { ! 408: err = BTIterateRecord(fcb, kBTreePrevRecord, &btIterator, &btRecord, &btRecordSize); ! 409: ! 410: // A previous record may not exist, so just return btNotFound (like we would if ! 411: // it was for the wrong file/fork). ! 412: if (err == (OSErr) fsBTStartOfIterationErr) //�� fsBTStartOfIterationErr is type unsigned long ! 413: err = btNotFound; ! 414: ! 415: if (err == noErr) { ! 416: // Found a previous record. Does it belong to the same fork of the same file? ! 417: if (extentKeyPtr->fileID != fileID || extentKeyPtr->forkType != forkType) ! 418: err = btNotFound; ! 419: } ! 420: } ! 421: ! 422: if (err == noErr) { ! 423: UInt16 i; ! 424: ! 425: // Copy the found key back for the caller ! 426: foundKey->keyLength = kHFSPlusExtentKeyMaximumLength; ! 427: foundKey->forkType = extentKeyPtr->forkType; ! 428: foundKey->pad = 0; ! 429: foundKey->fileID = extentKeyPtr->fileID; ! 430: foundKey->startBlock = extentKeyPtr->startBlock; ! 431: ! 432: // Copy the found data back for the caller ! 433: foundData[0].startBlock = extentData[0].startBlock; ! 434: foundData[0].blockCount = extentData[0].blockCount; ! 435: foundData[1].startBlock = extentData[1].startBlock; ! 436: foundData[1].blockCount = extentData[1].blockCount; ! 437: foundData[2].startBlock = extentData[2].startBlock; ! 438: foundData[2].blockCount = extentData[2].blockCount; ! 439: ! 440: for (i = 3; i < kHFSPlusExtentDensity; ++i) ! 441: { ! 442: foundData[i].startBlock = 0; ! 443: foundData[i].blockCount = 0; ! 444: } ! 445: } ! 446: } ! 447: else { // HFS Plus volume ! 448: HFSPlusExtentKey * extentKeyPtr; ! 449: HFSPlusExtentRecord extentData; ! 450: ! 451: extentKeyPtr = (HFSPlusExtentKey*) &btIterator.key; ! 452: extentKeyPtr->keyLength = kHFSPlusExtentKeyMaximumLength; ! 453: extentKeyPtr->forkType = forkType; ! 454: extentKeyPtr->pad = 0; ! 455: extentKeyPtr->fileID = fileID; ! 456: extentKeyPtr->startBlock = startBlock; ! 457: ! 458: btRecord.bufferAddress = &extentData; ! 459: btRecord.itemSize = sizeof(HFSPlusExtentRecord); ! 460: btRecord.itemCount = 1; ! 461: ! 462: err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator); ! 463: ! 464: if (err == btNotFound && allowPrevious) { ! 465: err = BTIterateRecord(fcb, kBTreePrevRecord, &btIterator, &btRecord, &btRecordSize); ! 466: ! 467: // A previous record may not exist, so just return btNotFound (like we would if ! 468: // it was for the wrong file/fork). ! 469: if (err == (OSErr) fsBTStartOfIterationErr) //�� fsBTStartOfIterationErr is type unsigned long ! 470: err = btNotFound; ! 471: ! 472: if (err == noErr) { ! 473: // Found a previous record. Does it belong to the same fork of the same file? ! 474: if (extentKeyPtr->fileID != fileID || extentKeyPtr->forkType != forkType) ! 475: err = btNotFound; ! 476: } ! 477: } ! 478: ! 479: if (err == noErr) { ! 480: // Copy the found key back for the caller ! 481: BlockMoveData(extentKeyPtr, foundKey, sizeof(HFSPlusExtentKey)); ! 482: // Copy the found data back for the caller ! 483: BlockMoveData(&extentData, foundData, sizeof(HFSPlusExtentRecord)); ! 484: } ! 485: } ! 486: ! 487: *foundHint = btIterator.hint.nodeNum; ! 488: return err; ! 489: } ! 490: ! 491: ! 492: ! 493: static OSErr CreateExtentRecord( ! 494: const ExtendedVCB *vcb, ! 495: HFSPlusExtentKey *key, ! 496: HFSPlusExtentRecord extents, ! 497: UInt32 *hint) ! 498: { ! 499: BTreeIterator btIterator; ! 500: FSBufferDescriptor btRecord; ! 501: UInt16 btRecordSize; ! 502: OSErr err; ! 503: ! 504: err = noErr; ! 505: *hint = 0; ! 506: (void) BTInvalidateHint(&btIterator); ! 507: ! 508: if (vcb->vcbSigWord == kHFSSigWord) { ! 509: HFSExtentKey * keyPtr; ! 510: HFSExtentRecord data; ! 511: ! 512: btRecordSize = sizeof(HFSExtentRecord); ! 513: btRecord.bufferAddress = &data; ! 514: btRecord.itemSize = btRecordSize; ! 515: btRecord.itemCount = 1; ! 516: ! 517: keyPtr = (HFSExtentKey*) &btIterator.key; ! 518: keyPtr->keyLength = kHFSExtentKeyMaximumLength; ! 519: keyPtr->forkType = key->forkType; ! 520: keyPtr->fileID = key->fileID; ! 521: keyPtr->startBlock = key->startBlock; ! 522: ! 523: err = HFSPlusToHFSExtents(extents, data); ! 524: } ! 525: else { // HFS Plus volume ! 526: btRecordSize = sizeof(HFSPlusExtentRecord); ! 527: btRecord.bufferAddress = extents; ! 528: btRecord.itemSize = btRecordSize; ! 529: btRecord.itemCount = 1; ! 530: ! 531: BlockMoveData(key, &btIterator.key, sizeof(HFSPlusExtentKey)); ! 532: } ! 533: ! 534: if (err == noErr) ! 535: err = BTInsertRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator, &btRecord, btRecordSize); ! 536: ! 537: if (err == noErr) ! 538: *hint = btIterator.hint.nodeNum; ! 539: ! 540: return err; ! 541: } ! 542: ! 543: ! 544: OSErr DeleteExtentRecord( ! 545: const ExtendedVCB *vcb, ! 546: UInt8 forkType, ! 547: UInt32 fileID, ! 548: UInt32 startBlock) ! 549: { ! 550: BTreeIterator btIterator; ! 551: OSErr err; ! 552: ! 553: err = noErr; ! 554: (void) BTInvalidateHint(&btIterator); ! 555: ! 556: if (vcb->vcbSigWord == kHFSSigWord) { ! 557: HFSExtentKey * keyPtr; ! 558: ! 559: keyPtr = (HFSExtentKey*) &btIterator.key; ! 560: keyPtr->keyLength = kHFSExtentKeyMaximumLength; ! 561: keyPtr->forkType = forkType; ! 562: keyPtr->fileID = fileID; ! 563: keyPtr->startBlock = startBlock; ! 564: } ! 565: else { // HFS Plus volume ! 566: HFSPlusExtentKey * keyPtr; ! 567: ! 568: keyPtr = (HFSPlusExtentKey*) &btIterator.key; ! 569: keyPtr->keyLength = kHFSPlusExtentKeyMaximumLength; ! 570: keyPtr->forkType = forkType; ! 571: keyPtr->pad = 0; ! 572: keyPtr->fileID = fileID; ! 573: keyPtr->startBlock = startBlock; ! 574: } ! 575: ! 576: err = BTDeleteRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator); ! 577: ! 578: return err; ! 579: } ! 580: ! 581: ! 582: ! 583: //_________________________________________________________________________________ ! 584: // ! 585: // Routine: MapFileBlock ! 586: // ! 587: // Function: Maps a file position into a physical disk address. ! 588: // ! 589: // Input: A2.L - VCB pointer ! 590: // (A1,D1.W) - FCB pointer ! 591: // D4.L - number of bytes desired ! 592: // D5.L - file position (byte address) ! 593: // ! 594: // Output: D3.L - physical start block ! 595: // D6.L - number of contiguous bytes available (up to D4 bytes) ! 596: // D0.L - result code <01Oct85> ! 597: // 0 = ok ! 598: // FXRangeErr = file position beyond mapped range <17Oct85> ! 599: // FXOvFlErr = extents file overflow <17Oct85> ! 600: // other = error <17Oct85> ! 601: // ! 602: // Called By: Log2Phys (read/write in place), Cache (map a file block). ! 603: //_________________________________________________________________________________ ! 604: ! 605: OSErr MapFileBlockC ( ! 606: ExtendedVCB *vcb, // volume that file resides on ! 607: FCB *fcb, // FCB of file ! 608: SInt64 numberOfBytes, // number of contiguous bytes desired ! 609: SInt64 offset, // starting offset within file (in bytes) ! 610: UInt32 *startSector, // first 512-byte sector (NOT an allocation block) ! 611: UInt32 *availableBytes) // number of contiguous bytes (up to numberOfBytes) ! 612: { ! 613: OSErr err; ! 614: UInt32 allocBlockSize; // Size of the volume's allocation block ! 615: HFSPlusExtentKey foundKey; ! 616: HFSPlusExtentRecord foundData; ! 617: UInt32 foundIndex; ! 618: UInt32 hint; ! 619: UInt32 firstFABN; // file allocation block of first block in found extent ! 620: UInt32 nextFABN; // file allocation block of block after end of found extent ! 621: SInt64 dataEnd; // (offset) end of range that is contiguous ! 622: UInt32 sectorsPerBlock; // Number of sectors per allocation block ! 623: UInt32 startBlock; // volume allocation block corresponding to firstFABN ! 624: UInt32 temp; ! 625: ! 626: ! 627: LogStartTime(kTraceMapFileBlock); ! 628: ! 629: allocBlockSize = vcb->blockSize; ! 630: ! 631: err = MapFileBlockFromFCB(vcb, fcb, offset, &firstFABN, &startBlock, &nextFABN); ! 632: if (err != noErr) { ! 633: err = SearchExtentFile(vcb, fcb, offset, &foundKey, foundData, &foundIndex, &hint, &nextFABN); ! 634: if (err == noErr) { ! 635: startBlock = foundData[foundIndex].startBlock; ! 636: firstFABN = nextFABN - foundData[foundIndex].blockCount; ! 637: } ! 638: } ! 639: ! 640: if (err != noErr) ! 641: { ! 642: LogEndTime(kTraceMapFileBlock, err); ! 643: ! 644: return err; ! 645: } ! 646: ! 647: // ! 648: // Determine the end of the available space. It will either be the end of the extent, ! 649: // or the file's PEOF, whichever is smaller. ! 650: // ! 651: dataEnd = nextFABN * allocBlockSize; // Assume valid data through end of this extent ! 652: if (fcb->fcbPLen < dataEnd) // Is PEOF shorter? ! 653: dataEnd = fcb->fcbPLen; // Yes, so only map up to PEOF ! 654: ! 655: // Compute the number of sectors in an allocation block ! 656: sectorsPerBlock = allocBlockSize / kSectorSize; // sectors per allocation block ! 657: ! 658: // ! 659: // Compute the absolute sector number that contains the offset of the given file ! 660: // ! 661: temp = (UInt32)((offset - (firstFABN * allocBlockSize))/kSectorSize); // offset in sectors from start of the extent ! 662: temp += startBlock * sectorsPerBlock; // offset in sectors from start of allocation block space ! 663: if (vcb->vcbSigWord == kHFSPlusSigWord) ! 664: temp += vcb->hfsPlusIOPosOffset/512; /* offset inside wrapper */ ! 665: else ! 666: temp += vcb->vcbAlBlSt; /* offset in sectors from start of volume */ ! 667: ! 668: // Return the desired sector for file position "offset" ! 669: *startSector = temp; ! 670: ! 671: // ! 672: // Determine the number of contiguous bytes until the end of the extent ! 673: // (or the amount they asked for, whichever comes first). ! 674: // ! 675: temp = (UInt32)(dataEnd - offset); ! 676: if (temp > numberOfBytes) ! 677: *availableBytes = numberOfBytes; // more there than they asked for, so pin the output ! 678: else ! 679: *availableBytes = temp; ! 680: ! 681: LogEndTime(kTraceMapFileBlock, noErr); ! 682: ! 683: return noErr; ! 684: } ! 685: ! 686: ! 687: //������������������������������������������������������������������������������� ! 688: // Routine: ReleaseExtents ! 689: // ! 690: // Function: Release the extents of a single extent data record. ! 691: //������������������������������������������������������������������������������� ! 692: ! 693: static OSErr ReleaseExtents( ! 694: ExtendedVCB *vcb, ! 695: const HFSPlusExtentRecord extentRecord, ! 696: UInt32 *numReleasedAllocationBlocks, ! 697: Boolean *releasedLastExtent) ! 698: { ! 699: UInt32 extentIndex; ! 700: UInt32 numberOfExtents; ! 701: OSErr err = noErr; ! 702: ! 703: *numReleasedAllocationBlocks = 0; ! 704: *releasedLastExtent = false; ! 705: ! 706: if (vcb->vcbSigWord == kHFSPlusSigWord) ! 707: numberOfExtents = kHFSPlusExtentDensity; ! 708: else ! 709: numberOfExtents = kHFSExtentDensity; ! 710: ! 711: for( extentIndex = 0; extentIndex < numberOfExtents; extentIndex++) ! 712: { ! 713: UInt32 numAllocationBlocks; ! 714: ! 715: // Loop over the extent record and release the blocks associated with each extent. ! 716: ! 717: numAllocationBlocks = extentRecord[extentIndex].blockCount; ! 718: if ( numAllocationBlocks == 0 ) ! 719: { ! 720: *releasedLastExtent = true; ! 721: break; ! 722: } ! 723: ! 724: err = BlockDeallocate( vcb, extentRecord[extentIndex].startBlock, numAllocationBlocks ); ! 725: if ( err != noErr ) ! 726: break; ! 727: ! 728: *numReleasedAllocationBlocks += numAllocationBlocks; // bump FABN to beg of next extent ! 729: } ! 730: ! 731: return( err ); ! 732: } ! 733: ! 734: ! 735: ! 736: //������������������������������������������������������������������������������� ! 737: // Routine: TruncateExtents ! 738: // ! 739: // Purpose: Delete extent records whose starting file allocation block number ! 740: // is greater than or equal to a given starting block number. The ! 741: // allocation blocks represented by the extents are deallocated. ! 742: // ! 743: // Inputs: ! 744: // vcb Volume to operate on ! 745: // fileID Which file to operate on ! 746: // startBlock Starting file allocation block number for first extent ! 747: // record to delete. ! 748: //������������������������������������������������������������������������������� ! 749: ! 750: static OSErr TruncateExtents( ! 751: ExtendedVCB *vcb, ! 752: UInt8 forkType, ! 753: UInt32 fileID, ! 754: UInt32 startBlock, ! 755: Boolean * recordDeleted) ! 756: { ! 757: OSErr err; ! 758: UInt32 numberExtentsReleased; ! 759: Boolean releasedLastExtent; ! 760: UInt32 hint; ! 761: HFSPlusExtentKey key; ! 762: HFSPlusExtentRecord extents; ! 763: ! 764: while (true) { ! 765: err = FindExtentRecord(vcb, forkType, fileID, startBlock, false, &key, extents, &hint); ! 766: if (err != noErr) { ! 767: if (err == btNotFound) ! 768: err = noErr; ! 769: break; ! 770: } ! 771: ! 772: err = ReleaseExtents( vcb, extents, &numberExtentsReleased, &releasedLastExtent ); ! 773: if (err != noErr) break; ! 774: ! 775: err = DeleteExtentRecord(vcb, forkType, fileID, startBlock); ! 776: if (err != noErr) break; ! 777: ! 778: *recordDeleted = true; ! 779: startBlock += numberExtentsReleased; ! 780: } ! 781: ! 782: return err; ! 783: } ! 784: ! 785: ! 786: ! 787: //������������������������������������������������������������������������������� ! 788: // Routine: DeallocateFork ! 789: // ! 790: // Function: De-allocates all disk space allocated to a specified fork. ! 791: //������������������������������������������������������������������������������� ! 792: ! 793: static OSErr DeallocateFork( ! 794: ExtendedVCB *vcb, ! 795: HFSCatalogNodeID fileID, ! 796: UInt8 forkType, ! 797: HFSPlusExtentRecord catalogExtents, ! 798: Boolean * recordDeleted) /* true if a record was deleted */ ! 799: { ! 800: OSErr err; ! 801: UInt32 numReleasedAllocationBlocks; ! 802: Boolean releasedLastExtent; ! 803: ! 804: // Release the catalog extents ! 805: err = ReleaseExtents( vcb, catalogExtents, &numReleasedAllocationBlocks, &releasedLastExtent ); ! 806: // Release the extra extents, if present ! 807: if (err == noErr && !releasedLastExtent) ! 808: err = TruncateExtents(vcb, forkType, fileID, numReleasedAllocationBlocks, recordDeleted); ! 809: ! 810: return( err ); ! 811: } ! 812: ! 813: //������������������������������������������������������������������������������� ! 814: // Routine: FlushExtentFile ! 815: // ! 816: // Function: Flushes the extent file for a specified volume ! 817: //������������������������������������������������������������������������������� ! 818: ! 819: OSErr FlushExtentFile( ExtendedVCB *vcb ) ! 820: { ! 821: FCB * fcb; ! 822: OSErr err; ! 823: ! 824: fcb = GetFileControlBlock(vcb->extentsRefNum); ! 825: err = BTFlushPath(fcb); ! 826: if ( err == noErr ) ! 827: { ! 828: // If the FCB for the extent "file" is dirty, mark the VCB as dirty. ! 829: ! 830: if ((fcb->fcbFlags & fcbModifiedMask) != 0) ! 831: { ! 832: MarkVCBDirty( vcb ); ! 833: err = FlushVolumeControlBlock( vcb ); ! 834: } ! 835: } ! 836: ! 837: return( err ); ! 838: } ! 839: ! 840: //------------------------------------------------------------------------------- ! 841: // Routine: DeleteFile ! 842: // ! 843: // Function: De-allocates all disk space allocated to a specified file ! 844: // including the space used by the catalog (ie the catalog record). ! 845: // The space occupied by both forks is also deallocated. ! 846: // ! 847: //------------------------------------------------------------------------------- ! 848: ! 849: OSErr DeleteFile( ExtendedVCB *vcb, HFSCatalogNodeID parDirID, ConstUTF8Param catalogName, UInt32 catalogHint ) ! 850: { ! 851: OSErr err; ! 852: OSErr errDF, errRF; ! 853: CatalogNodeData catalogData; ! 854: FSSpec fileSpec; /* 264 bytes */ ! 855: Boolean recordDeleted; ! 856: ! 857: recordDeleted = false; ! 858: ! 859: // Find catalog data in catalog ! 860: err = GetCatalogNode( vcb, parDirID, catalogName, kUndefinedStrLen, catalogHint, &fileSpec, &catalogData, &catalogHint); ! 861: if( err != noErr ) ! 862: goto Exit; ! 863: ! 864: // Check to make sure record is for a file ! 865: if ( catalogData.cnd_type != kCatalogFileNode ) ! 866: { ! 867: err = notAFileErr; ! 868: goto Exit; ! 869: } ! 870: ! 871: // ! 872: // Always delete the Catalog record first (to minimize disk corruption) ! 873: // ! 874: err = DeleteCatalogNode(vcb, parDirID, catalogName, catalogHint); ! 875: if( err != noErr ) ! 876: goto Exit; ! 877: ! 878: // ! 879: // Note: we don't report errors from DeallocateFork since the ! 880: // file no longer exists (since DeleteCatalogNode succeeded). ! 881: // Any errors mean that there are possibly some orphaned disk ! 882: // blocks but from the clients perspective the file was deleted. ! 883: // ! 884: ! 885: // Deallocate data fork extents ! 886: errDF = DeallocateFork( vcb, catalogData.cnd_nodeID, kDataForkType, ! 887: catalogData.cnd_datafork.extents, &recordDeleted ); ! 888: ! 889: // Deallocate resource fork extents ! 890: errRF = DeallocateFork( vcb, catalogData.cnd_nodeID, kResourceForkType, ! 891: catalogData.cnd_rsrcfork.extents, &recordDeleted ); ! 892: ! 893: if (recordDeleted) ! 894: err = FlushExtentFile( vcb ); ! 895: ! 896: return (errDF ? errDF : (errRF ? errRF : err)); ! 897: Exit: ! 898: ! 899: return( err ); ! 900: } ! 901: ! 902: //������������������������������������������������������������������������������� ! 903: // Routine: CompareExtentKeys ! 904: // ! 905: // Function: Compares two extent file keys (a search key and a trial key) for ! 906: // an HFS volume. ! 907: //������������������������������������������������������������������������������� ! 908: ! 909: SInt32 CompareExtentKeys( const HFSExtentKey *searchKey, const HFSExtentKey *trialKey ) ! 910: { ! 911: SInt32 result; // � 1 ! 912: ! 913: #if DEBUG_BUILD ! 914: if (searchKey->keyLength != kHFSExtentKeyMaximumLength) ! 915: DebugStr("\pHFS: search Key is wrong length"); ! 916: if (trialKey->keyLength != kHFSExtentKeyMaximumLength) ! 917: DebugStr("\pHFS: trial Key is wrong length"); ! 918: #endif ! 919: ! 920: result = -1; // assume searchKey < trialKey ! 921: ! 922: if (searchKey->fileID == trialKey->fileID) { ! 923: // ! 924: // FileNum's are equal; compare fork types ! 925: // ! 926: if (searchKey->forkType == trialKey->forkType) { ! 927: // ! 928: // Fork types are equal; compare allocation block number ! 929: // ! 930: if (searchKey->startBlock == trialKey->startBlock) { ! 931: // ! 932: // Everything is equal ! 933: // ! 934: result = 0; ! 935: } ! 936: else { ! 937: // ! 938: // Allocation block numbers differ; determine sign ! 939: // ! 940: if (searchKey->startBlock > trialKey->startBlock) ! 941: result = 1; ! 942: } ! 943: } ! 944: else { ! 945: // ! 946: // Fork types differ; determine sign ! 947: // ! 948: if (searchKey->forkType > trialKey->forkType) ! 949: result = 1; ! 950: } ! 951: } ! 952: else { ! 953: // ! 954: // FileNums differ; determine sign ! 955: // ! 956: if (searchKey->fileID > trialKey->fileID) ! 957: result = 1; ! 958: } ! 959: ! 960: return( result ); ! 961: } ! 962: ! 963: ! 964: ! 965: //������������������������������������������������������������������������������� ! 966: // Routine: CompareExtentKeysPlus ! 967: // ! 968: // Function: Compares two extent file keys (a search key and a trial key) for ! 969: // an HFS volume. ! 970: //������������������������������������������������������������������������������� ! 971: ! 972: SInt32 CompareExtentKeysPlus( const HFSPlusExtentKey *searchKey, const HFSPlusExtentKey *trialKey ) ! 973: { ! 974: SInt32 result; // � 1 ! 975: ! 976: #if DEBUG_BUILD ! 977: if (searchKey->keyLength != kHFSPlusExtentKeyMaximumLength) ! 978: DebugStr("\pHFS: search Key is wrong length"); ! 979: if (trialKey->keyLength != kHFSPlusExtentKeyMaximumLength) ! 980: DebugStr("\pHFS: trial Key is wrong length"); ! 981: #endif ! 982: ! 983: result = -1; // assume searchKey < trialKey ! 984: ! 985: if (searchKey->fileID == trialKey->fileID) { ! 986: // ! 987: // FileNum's are equal; compare fork types ! 988: // ! 989: if (searchKey->forkType == trialKey->forkType) { ! 990: // ! 991: // Fork types are equal; compare allocation block number ! 992: // ! 993: if (searchKey->startBlock == trialKey->startBlock) { ! 994: // ! 995: // Everything is equal ! 996: // ! 997: result = 0; ! 998: } ! 999: else { ! 1000: // ! 1001: // Allocation block numbers differ; determine sign ! 1002: // ! 1003: if (searchKey->startBlock > trialKey->startBlock) ! 1004: result = 1; ! 1005: } ! 1006: } ! 1007: else { ! 1008: // ! 1009: // Fork types differ; determine sign ! 1010: // ! 1011: if (searchKey->forkType > trialKey->forkType) ! 1012: result = 1; ! 1013: } ! 1014: } ! 1015: else { ! 1016: // ! 1017: // FileNums differ; determine sign ! 1018: // ! 1019: if (searchKey->fileID > trialKey->fileID) ! 1020: result = 1; ! 1021: } ! 1022: ! 1023: return( result ); ! 1024: } ! 1025: ! 1026: ! 1027: ! 1028: //_________________________________________________________________________________ ! 1029: // ! 1030: // Routine: Extendfile ! 1031: // ! 1032: // Function: Extends the disk space allocated to a file. ! 1033: // ! 1034: // Input: A2.L - VCB pointer ! 1035: // A1.L - pointer to FCB array ! 1036: // D1.W - file refnum ! 1037: // D3.B - option flags ! 1038: // kEFContigMask - force contiguous allocation ! 1039: // kEFAllMask - allocate all requested bytes or none ! 1040: // NOTE: You may not set both options. ! 1041: // D4.L - number of additional bytes to allocate ! 1042: // ! 1043: // Output: D0.W - result code ! 1044: // 0 = ok ! 1045: // -n = IO error ! 1046: // D6.L - number of bytes allocated ! 1047: // ! 1048: // Called by: FileAloc,FileWrite,SetEof ! 1049: // ! 1050: // Note: ExtendFile updates the PEOF in the FCB. ! 1051: //_________________________________________________________________________________ ! 1052: ! 1053: OSErr ExtendFileC ( ! 1054: ExtendedVCB *vcb, // volume that file resides on ! 1055: FCB *fcb, // FCB of file to truncate ! 1056: SInt64 bytesToAdd, // number of bytes to allocate ! 1057: UInt32 flags, // EFContig and/or EFAll ! 1058: SInt64 *actualBytesAdded) // number of bytes actually allocated ! 1059: { ! 1060: OSErr err; ! 1061: UInt32 volumeBlockSize; ! 1062: UInt32 blocksToAdd; ! 1063: UInt32 bytesThisExtent; ! 1064: HFSPlusExtentKey foundKey; ! 1065: HFSPlusExtentRecord foundData; ! 1066: UInt32 foundIndex; ! 1067: UInt32 hint; ! 1068: UInt32 nextBlock; ! 1069: UInt32 startBlock; ! 1070: Boolean allOrNothing; ! 1071: Boolean forceContig; ! 1072: Boolean wantContig; ! 1073: Boolean needsFlush; ! 1074: UInt32 actualStartBlock; ! 1075: UInt32 actualNumBlocks; ! 1076: UInt32 numExtentsPerRecord; ! 1077: SInt64 maximumBytes; ! 1078: SInt64 peof; ! 1079: SInt64 previousPEOF; ! 1080: ! 1081: ! 1082: #if HFSInstrumentation ! 1083: InstTraceClassRef trace; ! 1084: InstEventTag eventTag; ! 1085: InstDataDescriptorRef traceDescriptor; ! 1086: FSVarsRec *fsVars = (FSVarsRec *) LMGetFSMVars(); ! 1087: ! 1088: traceDescriptor = (InstDataDescriptorRef) fsVars->later[2]; ! 1089: ! 1090: err = InstCreateTraceClass(kInstRootClassRef, "HFS:Extents:ExtendFileC", 'hfs+', kInstEnableClassMask, &trace); ! 1091: if (err != noErr) DebugStr("\pError from InstCreateTraceClass"); ! 1092: ! 1093: eventTag = InstCreateEventTag(); ! 1094: InstLogTraceEvent( trace, eventTag, kInstStartEvent); ! 1095: #endif ! 1096: ! 1097: needsFlush = false; ! 1098: *actualBytesAdded = 0; ! 1099: volumeBlockSize = vcb->blockSize; ! 1100: allOrNothing = ((flags & kEFAllMask) != 0); ! 1101: forceContig = ((flags & kEFContigMask) != 0); ! 1102: previousPEOF = fcb->fcbPLen; ! 1103: ! 1104: if (vcb->vcbSigWord == kHFSPlusSigWord) ! 1105: numExtentsPerRecord = kHFSPlusExtentDensity; ! 1106: else ! 1107: numExtentsPerRecord = kHFSExtentDensity; ! 1108: ! 1109: // ! 1110: // Make sure the request and new PEOF are less than 2GB if HFS. ! 1111: // ! 1112: if (vcb->vcbSigWord == kHFSSigWord) { ! 1113: if (bytesToAdd >= kTwoGigabytes) ! 1114: goto Overflow; ! 1115: if ((fcb->fcbPLen + bytesToAdd) >= kTwoGigabytes) ! 1116: goto Overflow; ! 1117: } ! 1118: // ! 1119: // Determine how many blocks need to be allocated. ! 1120: // Round up the number of desired bytes to add. ! 1121: // ! 1122: blocksToAdd = FileBytesToBlocks(bytesToAdd, volumeBlockSize); ! 1123: bytesToAdd = (SInt64)(blocksToAdd * volumeBlockSize); ! 1124: ! 1125: // ! 1126: // If the file's clump size is larger than the allocation block size, ! 1127: // then set the maximum number of bytes to the requested number of bytes ! 1128: // rounded up to a multiple of the clump size. ! 1129: // ! 1130: if (fcb->fcbClmpSize > volumeBlockSize) { ! 1131: maximumBytes = (SInt64)FileBytesToBlocks(bytesToAdd, fcb->fcbClmpSize); ! 1132: maximumBytes *= fcb->fcbClmpSize; ! 1133: } ! 1134: else { ! 1135: maximumBytes = bytesToAdd; ! 1136: } ! 1137: ! 1138: // ! 1139: // Compute new physical EOF, rounded up to a multiple of a block. ! 1140: // ! 1141: if ((vcb->vcbSigWord == kHFSSigWord) && ((fcb->fcbPLen + bytesToAdd) >= (SInt64) kTwoGigabytes)) // Too big? ! 1142: if (allOrNothing) // Yes, must they have it all? ! 1143: goto Overflow; // Yes, can't have it ! 1144: else { ! 1145: --blocksToAdd; // No, give give 'em one block less ! 1146: bytesToAdd -= volumeBlockSize; ! 1147: } ! 1148: ! 1149: // ! 1150: // If allocation is all-or-nothing, make sure there are ! 1151: // enough free blocks on the volume (quick test). ! 1152: // ! 1153: if (allOrNothing && blocksToAdd > vcb->freeBlocks) { ! 1154: err = dskFulErr; ! 1155: goto ErrorExit; ! 1156: } ! 1157: ! 1158: // ! 1159: // See if there are already enough blocks allocated to the file. ! 1160: // ! 1161: peof = fcb->fcbPLen + bytesToAdd; // potential new PEOF ! 1162: err = SearchExtentFile(vcb, fcb, peof-1, &foundKey, foundData, &foundIndex, &hint, &nextBlock); ! 1163: if (err == noErr) { ! 1164: // Enough blocks are already allocated. Just update the FCB to reflect the new length. ! 1165: fcb->fcbPLen = peof; ! 1166: fcb->fcbFlags |= fcbModifiedMask; ! 1167: goto Exit; ! 1168: } ! 1169: if (err != fxRangeErr) // Any real error? ! 1170: goto ErrorExit; // Yes, so exit immediately ! 1171: ! 1172: // ! 1173: // Adjust the PEOF to the end of the last extent. ! 1174: // ! 1175: peof = (SInt64)(nextBlock * volumeBlockSize); // currently allocated PEOF ! 1176: bytesThisExtent = (UInt32)(peof - fcb->fcbPLen); ! 1177: if (bytesThisExtent != 0) { ! 1178: fcb->fcbPLen = peof; ! 1179: fcb->fcbFlags |= fcbModifiedMask; ! 1180: bytesToAdd -= bytesThisExtent; ! 1181: } ! 1182: ! 1183: // ! 1184: // Allocate some more space. ! 1185: // ! 1186: // First try a contiguous allocation (of the whole amount). ! 1187: // If that fails, get whatever we can. ! 1188: // If forceContig, then take whatever we got ! 1189: // else, keep getting bits and pieces (non-contig) ! 1190: err = noErr; ! 1191: wantContig = true; ! 1192: do { ! 1193: startBlock = foundData[foundIndex].startBlock + foundData[foundIndex].blockCount; ! 1194: err = BlockAllocate(vcb, startBlock, bytesToAdd, maximumBytes, wantContig, &actualStartBlock, &actualNumBlocks); ! 1195: if (err == dskFulErr) { ! 1196: if (forceContig) ! 1197: break; // AllocContig failed because not enough contiguous space ! 1198: if (wantContig) { ! 1199: // Couldn't get one big chunk, so get whatever we can. ! 1200: err = noErr; ! 1201: wantContig = false; ! 1202: continue; ! 1203: } ! 1204: if (actualNumBlocks != 0) ! 1205: err = noErr; ! 1206: } ! 1207: if (err == noErr) { ! 1208: #if HFSInstrumentation ! 1209: { ! 1210: struct { ! 1211: UInt32 fileID; ! 1212: UInt32 start; ! 1213: UInt32 count; ! 1214: UInt32 fabn; ! 1215: } x; ! 1216: ! 1217: x.fileID = H_FILEID(fcb); ! 1218: x.start = actualStartBlock; ! 1219: x.count = actualNumBlocks; ! 1220: x.fabn = nextBlock; ! 1221: ! 1222: InstLogTraceEventWithDataStructure( trace, eventTag, kInstMiddleEvent, traceDescriptor, ! 1223: (UInt8 *) &x, sizeof(x)); ! 1224: } ! 1225: #endif ! 1226: // Add the new extent to the existing extent record, or create a new one. ! 1227: if (actualStartBlock == startBlock) { ! 1228: // We grew the file's last extent, so just adjust the number of blocks. ! 1229: foundData[foundIndex].blockCount += actualNumBlocks; ! 1230: err = UpdateExtentRecord(vcb, fcb, &foundKey, foundData, hint); ! 1231: if (err != noErr) break; ! 1232: } ! 1233: else { ! 1234: UInt16 i; ! 1235: ! 1236: // Need to add a new extent. See if there is room in the current record. ! 1237: if (foundData[foundIndex].blockCount != 0) // Is current extent free to use? ! 1238: ++foundIndex; // No, so use the next one. ! 1239: if (foundIndex == numExtentsPerRecord) { ! 1240: // This record is full. Need to create a new one. ! 1241: if (H_FILEID(fcb) == kHFSExtentsFileID) { ! 1242: err = fxOvFlErr; // Oops. Can't extend extents file (?? really ??) ! 1243: break; ! 1244: } ! 1245: ! 1246: foundKey.keyLength = kHFSPlusExtentKeyMaximumLength; ! 1247: if (fcb->fcbFlags & fcbResourceMask) ! 1248: foundKey.forkType = kResourceForkType; ! 1249: else ! 1250: foundKey.forkType = kDataForkType; ! 1251: foundKey.pad = 0; ! 1252: foundKey.fileID = H_FILEID(fcb); ! 1253: foundKey.startBlock = nextBlock; ! 1254: ! 1255: foundData[0].startBlock = actualStartBlock; ! 1256: foundData[0].blockCount = actualNumBlocks; ! 1257: ! 1258: // zero out remaining extents... ! 1259: for (i = 1; i < kHFSPlusExtentDensity; ++i) ! 1260: { ! 1261: foundData[i].startBlock = 0; ! 1262: foundData[i].blockCount = 0; ! 1263: } ! 1264: ! 1265: foundIndex = 0; ! 1266: ! 1267: err = CreateExtentRecord(vcb, &foundKey, foundData, &hint); ! 1268: if (err == fxOvFlErr) { ! 1269: // We couldn't create an extent record because extents B-tree ! 1270: // couldn't grow. Dellocate the extent just allocated and ! 1271: // return a disk full error. ! 1272: (void) BlockDeallocate(vcb, actualStartBlock, actualNumBlocks); ! 1273: err = dskFulErr; ! 1274: } ! 1275: if (err != noErr) break; ! 1276: ! 1277: needsFlush = true; // We need to update the B-tree header ! 1278: } ! 1279: else { ! 1280: // Add a new extent into this record and update. ! 1281: foundData[foundIndex].startBlock = actualStartBlock; ! 1282: foundData[foundIndex].blockCount = actualNumBlocks; ! 1283: err = UpdateExtentRecord(vcb, fcb, &foundKey, foundData, hint); ! 1284: if (err != noErr) break; ! 1285: } ! 1286: } ! 1287: ! 1288: // Figure out how many bytes were actually allocated. ! 1289: // NOTE: BlockAllocate could have allocated more than we asked for. ! 1290: // Don't set the PEOF beyond what our client asked for. ! 1291: nextBlock += actualNumBlocks; ! 1292: bytesThisExtent = actualNumBlocks * volumeBlockSize; ! 1293: if (bytesThisExtent > bytesToAdd) { ! 1294: bytesToAdd = 0; ! 1295: } ! 1296: else { ! 1297: bytesToAdd -= bytesThisExtent; ! 1298: maximumBytes -= bytesThisExtent; ! 1299: } ! 1300: fcb->fcbPLen += bytesThisExtent; ! 1301: fcb->fcbFlags |= fcbModifiedMask; ! 1302: ! 1303: // If contiguous allocation was requested, then we've already got one contiguous ! 1304: // chunk. If we didn't get all we wanted, then adjust the error to disk full. ! 1305: if (forceContig) { ! 1306: if (bytesToAdd != 0) ! 1307: err = dskFulErr; ! 1308: break; // We've already got everything that's contiguous ! 1309: } ! 1310: } ! 1311: } while (err == noErr && bytesToAdd); ! 1312: ! 1313: ErrorExit: ! 1314: Exit: ! 1315: *actualBytesAdded = fcb->fcbPLen - previousPEOF; ! 1316: ! 1317: if (needsFlush) ! 1318: (void) FlushExtentFile(vcb); ! 1319: ! 1320: #if HFSInstrumentation ! 1321: InstLogTraceEvent( trace, eventTag, kInstEndEvent); ! 1322: #endif ! 1323: ! 1324: return err; ! 1325: ! 1326: Overflow: ! 1327: err = fileBoundsErr; ! 1328: goto ErrorExit; ! 1329: } ! 1330: ! 1331: ! 1332: ! 1333: //_________________________________________________________________________________ ! 1334: // ! 1335: // Routine: TruncateFileC ! 1336: // ! 1337: // Function: Truncates the disk space allocated to a file. The file space is ! 1338: // truncated to a specified new PEOF rounded up to the next allocation ! 1339: // block boundry. If the 'TFTrunExt' option is specified, the file is ! 1340: // truncated to the end of the extent containing the new PEOF. ! 1341: // ! 1342: // Input: A2.L - VCB pointer ! 1343: // A1.L - pointer to FCB array ! 1344: // D1.W - file refnum ! 1345: // D2.B - option flags ! 1346: // TFTrunExt - truncate to the extent containing new PEOF ! 1347: // D3.L - new PEOF ! 1348: // ! 1349: // Output: D0.W - result code ! 1350: // 0 = ok ! 1351: // -n = IO error ! 1352: // ! 1353: // Note: TruncateFile updates the PEOF in the FCB. ! 1354: //_________________________________________________________________________________ ! 1355: ! 1356: OSErr TruncateFileC ( ! 1357: ExtendedVCB *vcb, // volume that file resides on ! 1358: FCB *fcb, // FCB of file to truncate ! 1359: SInt64 peof, // new physical size for file ! 1360: Boolean truncateToExtent) // if true, truncate to end of extent containing newPEOF ! 1361: { ! 1362: OSErr err; ! 1363: UInt32 nextBlock; // next file allocation block to consider ! 1364: UInt32 startBlock; // Physical (volume) allocation block number of start of a range ! 1365: UInt32 physNumBlocks; // Number of allocation blocks in file (according to PEOF) ! 1366: UInt32 numBlocks; ! 1367: HFSPlusExtentKey key; // key for current extent record; key->keyLength == 0 if FCB's extent record ! 1368: UInt32 hint; // BTree hint corresponding to key ! 1369: HFSPlusExtentRecord extentRecord; ! 1370: UInt32 extentIndex; ! 1371: UInt32 extentNextBlock; ! 1372: UInt32 numExtentsPerRecord; ! 1373: UInt8 forkType; ! 1374: Boolean extentChanged; // true if we actually changed an extent ! 1375: Boolean recordDeleted; // true if an extent record got deleted ! 1376: ! 1377: #if HFSInstrumentation ! 1378: InstTraceClassRef trace; ! 1379: InstEventTag eventTag; ! 1380: InstDataDescriptorRef traceDescriptor; ! 1381: FSVarsRec *fsVars = (FSVarsRec *) LMGetFSMVars(); ! 1382: ! 1383: traceDescriptor = (InstDataDescriptorRef) fsVars->later[2]; ! 1384: ! 1385: err = InstCreateTraceClass(kInstRootClassRef, "HFS:Extents:TruncateFileC", 'hfs+', kInstEnableClassMask, &trace); ! 1386: if (err != noErr) DebugStr("\pError from InstCreateTraceClass"); ! 1387: ! 1388: eventTag = InstCreateEventTag(); ! 1389: InstLogTraceEvent( trace, eventTag, kInstStartEvent); ! 1390: #endif ! 1391: ! 1392: recordDeleted = false; ! 1393: ! 1394: if (vcb->vcbSigWord == kHFSPlusSigWord) ! 1395: numExtentsPerRecord = kHFSPlusExtentDensity; ! 1396: else ! 1397: numExtentsPerRecord = kHFSExtentDensity; ! 1398: ! 1399: if (fcb->fcbFlags & fcbResourceMask) ! 1400: forkType = kResourceForkType; ! 1401: else ! 1402: forkType = kDataForkType; ! 1403: ! 1404: physNumBlocks = fcb->fcbPLen / vcb->blockSize; // number of allocation blocks currently in file ! 1405: ! 1406: // ! 1407: // Round newPEOF up to a multiple of the allocation block size. If new size is ! 1408: // two gigabytes or more, then round down by one allocation block (??? really? ! 1409: // shouldn't that be an error?). ! 1410: // ! 1411: nextBlock = FileBytesToBlocks(peof, vcb->blockSize); // number of allocation blocks to remain in file ! 1412: peof = (SInt64)(nextBlock * vcb->blockSize); // number of bytes in those blocks ! 1413: if ((vcb->vcbSigWord == kHFSSigWord) && (peof >= (UInt32) kTwoGigabytes)) { ! 1414: #if DEBUG_BUILD ! 1415: DebugStr("\pHFS: Trying to truncate a file to 2GB or more"); ! 1416: #endif ! 1417: err = fileBoundsErr; ! 1418: goto ErrorExit; ! 1419: } ! 1420: ! 1421: // ! 1422: // Update FCB's length ! 1423: // ! 1424: fcb->fcbPLen = peof; ! 1425: fcb->fcbFlags |= fcbModifiedMask; ! 1426: ! 1427: // ! 1428: // If the new PEOF is 0, then truncateToExtent has no meaning (we should always deallocate ! 1429: // all storage). ! 1430: // ! 1431: if (peof == 0) { ! 1432: int i; ! 1433: ! 1434: // Deallocate all the extents for this fork ! 1435: err = DeallocateFork(vcb, H_FILEID(fcb), forkType, fcb->fcbExtents, &recordDeleted); ! 1436: if (err != noErr) goto ErrorExit; // got some error, so return it ! 1437: ! 1438: // Update the catalog extent record (making sure it's zeroed out) ! 1439: if (err == noErr) { ! 1440: for (i=0; i < kHFSPlusExtentDensity; i++) { ! 1441: fcb->fcbExtents[i].startBlock = 0; ! 1442: fcb->fcbExtents[i].blockCount = 0; ! 1443: } ! 1444: } ! 1445: goto Done; ! 1446: } ! 1447: ! 1448: // ! 1449: // Find the extent containing byte (peof-1). This is the last extent we'll keep. ! 1450: // (If truncateToExtent is true, we'll keep the whole extent; otherwise, we'll only ! 1451: // keep up through peof). The search will tell us how many allocation blocks exist ! 1452: // in the found extent plus all previous extents. ! 1453: // ! 1454: err = SearchExtentFile(vcb, fcb, peof-1, &key, extentRecord, &extentIndex, &hint, &extentNextBlock); ! 1455: if (err != noErr) goto ErrorExit; ! 1456: ! 1457: extentChanged = false; // haven't changed the extent yet ! 1458: ! 1459: if (!truncateToExtent) { ! 1460: // ! 1461: // Shorten this extent. It may be the case that the entire extent gets ! 1462: // freed here. ! 1463: // ! 1464: numBlocks = extentNextBlock - nextBlock; // How many blocks in this extent to free up ! 1465: if (numBlocks != 0) { ! 1466: // Compute first volume allocation block to free ! 1467: startBlock = extentRecord[extentIndex].startBlock + extentRecord[extentIndex].blockCount - numBlocks; ! 1468: // Free the blocks in bitmap ! 1469: err = BlockDeallocate(vcb, startBlock, numBlocks); ! 1470: if (err != noErr) goto ErrorExit; ! 1471: // Adjust length of this extent ! 1472: extentRecord[extentIndex].blockCount -= numBlocks; ! 1473: // If extent is empty, set start block to 0 ! 1474: if (extentRecord[extentIndex].blockCount == 0) ! 1475: extentRecord[extentIndex].startBlock = 0; ! 1476: // Remember that we changed the extent record ! 1477: extentChanged = true; ! 1478: } ! 1479: } ! 1480: ! 1481: // ! 1482: // Now move to the next extent in the record, and set up the file allocation block number ! 1483: // ! 1484: nextBlock = extentNextBlock; // Next file allocation block to free ! 1485: ++extentIndex; // Its index within the extent record ! 1486: ! 1487: // ! 1488: // Release all following extents in this extent record. Update the record. ! 1489: // ! 1490: while (extentIndex < numExtentsPerRecord && extentRecord[extentIndex].blockCount != 0) { ! 1491: numBlocks = extentRecord[extentIndex].blockCount; ! 1492: // Deallocate this extent ! 1493: err = BlockDeallocate(vcb, extentRecord[extentIndex].startBlock, numBlocks); ! 1494: if (err != noErr) goto ErrorExit; ! 1495: // Update next file allocation block number ! 1496: nextBlock += numBlocks; ! 1497: // Zero out start and length of this extent to delete it from record ! 1498: extentRecord[extentIndex].startBlock = 0; ! 1499: extentRecord[extentIndex].blockCount = 0; ! 1500: // Remember that we changed an extent ! 1501: extentChanged = true; ! 1502: // Move to next extent in record ! 1503: ++extentIndex; ! 1504: } ! 1505: ! 1506: // ! 1507: // If any of the extents in the current record were changed, then update that ! 1508: // record (in the FCB, or extents file). ! 1509: // ! 1510: if (extentChanged) { ! 1511: err = UpdateExtentRecord(vcb, fcb, &key, extentRecord, hint); ! 1512: if (err != noErr) goto ErrorExit; ! 1513: } ! 1514: ! 1515: // ! 1516: // If there are any following allocation blocks, then we need ! 1517: // to seach for their extent records and delete those allocation ! 1518: // blocks. ! 1519: // ! 1520: if (nextBlock < physNumBlocks) ! 1521: err = TruncateExtents(vcb, forkType, H_FILEID(fcb), nextBlock, &recordDeleted); ! 1522: ! 1523: Done: ! 1524: ErrorExit: ! 1525: ! 1526: if (recordDeleted) ! 1527: (void) FlushExtentFile(vcb); ! 1528: ! 1529: #if HFSInstrumentation ! 1530: InstLogTraceEvent( trace, eventTag, kInstEndEvent); ! 1531: #endif ! 1532: ! 1533: return err; ! 1534: } ! 1535: ! 1536: ! 1537: ! 1538: //������������������������������������������������������������������������������� ! 1539: // Routine: SearchExtentRecord (was XRSearch) ! 1540: // ! 1541: // Function: Searches extent record for the extent mapping a given file ! 1542: // allocation block number (FABN). ! 1543: // ! 1544: // Input: searchFABN - desired FABN ! 1545: // extentData - pointer to extent data record (xdr) ! 1546: // extentDataStartFABN - beginning FABN for extent record ! 1547: // ! 1548: // Output: foundExtentDataOffset - offset to extent entry within xdr ! 1549: // result = noErr, offset to extent mapping desired FABN ! 1550: // result = FXRangeErr, offset to last extent in record ! 1551: // endingFABNPlusOne - ending FABN +1 ! 1552: // noMoreExtents - True if the extent was not found, and the ! 1553: // extent record was not full (so don't bother ! 1554: // looking in subsequent records); false otherwise. ! 1555: // ! 1556: // Result: noErr = ok ! 1557: // FXRangeErr = desired FABN > last mapped FABN in record ! 1558: //������������������������������������������������������������������������������� ! 1559: ! 1560: static OSErr SearchExtentRecord( ! 1561: const ExtendedVCB *vcb, ! 1562: UInt32 searchFABN, ! 1563: const HFSPlusExtentRecord extentData, ! 1564: UInt32 extentDataStartFABN, ! 1565: UInt32 *foundExtentIndex, ! 1566: UInt32 *endingFABNPlusOne, ! 1567: Boolean *noMoreExtents) ! 1568: { ! 1569: OSErr err = noErr; ! 1570: UInt32 extentIndex; ! 1571: UInt32 numberOfExtents; ! 1572: UInt32 numAllocationBlocks; ! 1573: Boolean foundExtent; ! 1574: ! 1575: *endingFABNPlusOne = extentDataStartFABN; ! 1576: *noMoreExtents = false; ! 1577: foundExtent = false; ! 1578: ! 1579: if (vcb->vcbSigWord == kHFSPlusSigWord) ! 1580: numberOfExtents = kHFSPlusExtentDensity; ! 1581: else ! 1582: numberOfExtents = kHFSExtentDensity; ! 1583: ! 1584: for( extentIndex = 0; extentIndex < numberOfExtents; ++extentIndex ) ! 1585: { ! 1586: ! 1587: // Loop over the extent record and find the search FABN. ! 1588: ! 1589: numAllocationBlocks = extentData[extentIndex].blockCount; ! 1590: if ( numAllocationBlocks == 0 ) ! 1591: { ! 1592: break; ! 1593: } ! 1594: ! 1595: *endingFABNPlusOne += numAllocationBlocks; ! 1596: ! 1597: if( searchFABN < *endingFABNPlusOne ) ! 1598: { ! 1599: // Found the extent. ! 1600: foundExtent = true; ! 1601: break; ! 1602: } ! 1603: } ! 1604: ! 1605: if( foundExtent ) ! 1606: { ! 1607: // Found the extent. Note the extent offset ! 1608: *foundExtentIndex = extentIndex; ! 1609: } ! 1610: else ! 1611: { ! 1612: // Did not find the extent. Set foundExtentDataOffset accordingly ! 1613: if( extentIndex > 0 ) ! 1614: { ! 1615: *foundExtentIndex = extentIndex - 1; ! 1616: } ! 1617: else ! 1618: { ! 1619: *foundExtentIndex = 0; ! 1620: } ! 1621: ! 1622: // If we found an empty extent, then set noMoreExtents. ! 1623: if (extentIndex < numberOfExtents) ! 1624: *noMoreExtents = true; ! 1625: ! 1626: // Finally, return an error to the caller ! 1627: err = fxRangeErr; ! 1628: } ! 1629: ! 1630: return( err ); ! 1631: } ! 1632: ! 1633: //������������������������������������������������������������������������������� ! 1634: // Routine: SearchExtentFile (was XFSearch) ! 1635: // ! 1636: // Function: Searches extent file (including the FCB resident extent record) ! 1637: // for the extent mapping a given file position. ! 1638: // ! 1639: // Input: vcb - VCB pointer ! 1640: // fcb - FCB pointer ! 1641: // filePosition - file position (byte address) ! 1642: // ! 1643: // Output: foundExtentKey - extent key record (xkr) ! 1644: // If extent was found in the FCB's resident extent record, ! 1645: // then foundExtentKey->keyLength will be set to 0. ! 1646: // foundExtentData - extent data record(xdr) ! 1647: // foundExtentIndex - index to extent entry in xdr ! 1648: // result = 0, offset to extent mapping desired FABN ! 1649: // result = FXRangeErr, offset to last extent in record ! 1650: // (i.e., kNumExtentsPerRecord-1) ! 1651: // extentBTreeHint - BTree hint for extent record ! 1652: // kNoHint = Resident extent record ! 1653: // endingFABNPlusOne - ending FABN +1 ! 1654: // ! 1655: // Result: ! 1656: // noErr Found an extent that contains the given file position ! 1657: // FXRangeErr Given position is beyond the last allocated extent ! 1658: // (other) (some other internal I/O error) ! 1659: //������������������������������������������������������������������������������� ! 1660: ! 1661: static OSErr SearchExtentFile( ! 1662: const ExtendedVCB *vcb, ! 1663: const FCB *fcb, ! 1664: SInt64 filePosition, ! 1665: HFSPlusExtentKey *foundExtentKey, ! 1666: HFSPlusExtentRecord foundExtentData, ! 1667: UInt32 *foundExtentIndex, ! 1668: UInt32 *extentBTreeHint, ! 1669: UInt32 *endingFABNPlusOne ) ! 1670: { ! 1671: OSErr err; ! 1672: UInt32 filePositionBlock; ! 1673: Boolean noMoreExtents; ! 1674: ! 1675: filePositionBlock = filePosition / vcb->blockSize; ! 1676: bcopy ( fcb->fcbExtents, foundExtentData, sizeof(HFSPlusExtentRecord)); ! 1677: ! 1678: // Search the resident FCB first. ! 1679: err = SearchExtentRecord( vcb, filePositionBlock, foundExtentData, 0, ! 1680: foundExtentIndex, endingFABNPlusOne, &noMoreExtents ); ! 1681: ! 1682: if( err == noErr ) { ! 1683: // Found the extent. Set results accordingly ! 1684: *extentBTreeHint = kNoHint; // no hint, because not in the BTree ! 1685: foundExtentKey->keyLength = 0; // 0 = the FCB itself ! 1686: ! 1687: goto Exit; ! 1688: } ! 1689: ! 1690: // Didn't find extent in FCB. If FCB's extent record wasn't full, there's no point ! 1691: // in searching the extents file. Note that SearchExtentRecord left us pointing at ! 1692: // the last valid extent (or the first one, if none were valid). This means we need ! 1693: // to fill in the hint and key outputs, just like the "if" statement above. ! 1694: if ( noMoreExtents ) { ! 1695: *extentBTreeHint = kNoHint; // no hint, because not in the BTree ! 1696: foundExtentKey->keyLength = 0; // 0 = the FCB itself ! 1697: err = fxRangeErr; // There are no more extents, so must be beyond PEOF ! 1698: goto Exit; ! 1699: } ! 1700: ! 1701: // ! 1702: // Find the desired record, or the previous record if it is the same fork ! 1703: // ! 1704: err = FindExtentRecord(vcb, (fcb->fcbFlags & fcbResourceMask) ? kResourceForkType : kDataForkType, ! 1705: H_FILEID(fcb), filePositionBlock, true, foundExtentKey, foundExtentData, extentBTreeHint); ! 1706: ! 1707: if (err == btNotFound) { ! 1708: // ! 1709: // If we get here, the desired position is beyond the extents in the FCB, and there are no extents ! 1710: // in the extents file. Return the FCB's extents and a range error. ! 1711: // ! 1712: *extentBTreeHint = kNoHint; ! 1713: foundExtentKey->keyLength = 0; ! 1714: err = GetFCBExtentRecord(fcb, foundExtentData); ! 1715: // Note: foundExtentIndex and endingFABNPlusOne have already been set as a result of the very ! 1716: // first SearchExtentRecord call in this function (when searching in the FCB's extents, and ! 1717: // we got a range error). ! 1718: ! 1719: return fxRangeErr; ! 1720: } ! 1721: ! 1722: // ! 1723: // If we get here, there was either a BTree error, or we found an appropriate record. ! 1724: // If we found a record, then search it for the correct index into the extents. ! 1725: // ! 1726: if (err == noErr) { ! 1727: // Find appropriate index into extent record ! 1728: err = SearchExtentRecord(vcb, filePositionBlock, foundExtentData, foundExtentKey->startBlock, ! 1729: foundExtentIndex, endingFABNPlusOne, &noMoreExtents); ! 1730: } ! 1731: ! 1732: Exit: ! 1733: return err; ! 1734: } ! 1735: ! 1736: ! 1737: ! 1738: //������������������������������������������������������������������������������� ! 1739: // Routine: UpdateExtentRecord ! 1740: // ! 1741: // Function: Write new extent data to an existing extent record with a given key. ! 1742: // If all of the extents are empty, and the extent record is in the ! 1743: // extents file, then the record is deleted. ! 1744: // ! 1745: // Input: vcb - the volume containing the extents ! 1746: // fcb - the file that owns the extents ! 1747: // extentFileKey - pointer to extent key record (xkr) ! 1748: // If the key length is 0, then the extents are actually part ! 1749: // of the catalog record, stored in the FCB. ! 1750: // extentData - pointer to extent data record (xdr) ! 1751: // extentBTreeHint - hint for given key, or kNoHint ! 1752: // ! 1753: // Result: noErr = ok ! 1754: // (other) = error from BTree ! 1755: //������������������������������������������������������������������������������� ! 1756: ! 1757: static OSErr UpdateExtentRecord ( ! 1758: const ExtendedVCB *vcb, ! 1759: FCB *fcb, ! 1760: const HFSPlusExtentKey *extentFileKey, ! 1761: const HFSPlusExtentRecord extentData, ! 1762: UInt32 extentBTreeHint) ! 1763: { ! 1764: BTreeIterator btIterator; ! 1765: FSBufferDescriptor btRecord; ! 1766: UInt16 btRecordSize; ! 1767: FCB * btFCB; ! 1768: OSErr err = noErr; ! 1769: ! 1770: if (extentFileKey->keyLength == 0) { // keyLength == 0 means the FCB's extent record ! 1771: BlockMoveData(extentData, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); ! 1772: fcb->fcbFlags |= fcbModifiedMask; ! 1773: } ! 1774: else { ! 1775: // ! 1776: // Need to find and change a record in Extents BTree ! 1777: // ! 1778: btFCB = GetFileControlBlock(vcb->extentsRefNum); ! 1779: ! 1780: if (vcb->vcbSigWord == kHFSSigWord) { ! 1781: HFSExtentKey * key; // Actual extent key used on disk in HFS ! 1782: HFSExtentRecord foundData; // The extent data actually found ! 1783: ! 1784: key = (HFSExtentKey*) &btIterator.key; ! 1785: key->keyLength = kHFSExtentKeyMaximumLength; ! 1786: key->forkType = extentFileKey->forkType; ! 1787: key->fileID = extentFileKey->fileID; ! 1788: key->startBlock = extentFileKey->startBlock; ! 1789: ! 1790: btIterator.hint.index = 0; ! 1791: btIterator.hint.nodeNum = extentBTreeHint; ! 1792: ! 1793: btRecord.bufferAddress = &foundData; ! 1794: btRecord.itemSize = sizeof(HFSExtentRecord); ! 1795: btRecord.itemCount = 1; ! 1796: ! 1797: err = BTSearchRecord(btFCB, &btIterator, kInvalidMRUCacheKey, &btRecord, ! 1798: &btRecordSize, &btIterator); ! 1799: ! 1800: if (err == noErr) ! 1801: err = HFSPlusToHFSExtents(extentData, (HFSExtentDescriptor *)&foundData); ! 1802: ! 1803: if (err == noErr) ! 1804: err = BTReplaceRecord(btFCB, &btIterator, &btRecord, btRecordSize); ! 1805: } ! 1806: else { // HFS Plus volume ! 1807: HFSPlusExtentRecord foundData; // The extent data actually found ! 1808: ! 1809: BlockMoveData(extentFileKey, &btIterator.key, sizeof(HFSPlusExtentKey)); ! 1810: ! 1811: btIterator.hint.index = 0; ! 1812: btIterator.hint.nodeNum = extentBTreeHint; ! 1813: ! 1814: btRecord.bufferAddress = &foundData; ! 1815: btRecord.itemSize = sizeof(HFSPlusExtentRecord); ! 1816: btRecord.itemCount = 1; ! 1817: ! 1818: err = BTSearchRecord(btFCB, &btIterator, kInvalidMRUCacheKey, &btRecord, ! 1819: &btRecordSize, &btIterator); ! 1820: ! 1821: if (err == noErr) { ! 1822: BlockMoveData(extentData, &foundData, sizeof(HFSPlusExtentRecord)); ! 1823: err = BTReplaceRecord(btFCB, &btIterator, &btRecord, btRecordSize); ! 1824: } ! 1825: } ! 1826: } ! 1827: ! 1828: return err; ! 1829: } ! 1830: ! 1831: ! 1832: ! 1833: void HFSToHFSPlusExtents( ! 1834: const HFSExtentRecord oldExtents, ! 1835: HFSPlusExtentRecord newExtents) ! 1836: { ! 1837: UInt32 i; ! 1838: ! 1839: // copy the first 3 extents ! 1840: newExtents[0].startBlock = oldExtents[0].startBlock; ! 1841: newExtents[0].blockCount = oldExtents[0].blockCount; ! 1842: newExtents[1].startBlock = oldExtents[1].startBlock; ! 1843: newExtents[1].blockCount = oldExtents[1].blockCount; ! 1844: newExtents[2].startBlock = oldExtents[2].startBlock; ! 1845: newExtents[2].blockCount = oldExtents[2].blockCount; ! 1846: ! 1847: // zero out the remaining ones ! 1848: for (i = 3; i < kHFSPlusExtentDensity; ++i) ! 1849: { ! 1850: newExtents[i].startBlock = 0; ! 1851: newExtents[i].blockCount = 0; ! 1852: } ! 1853: } ! 1854: ! 1855: ! 1856: ! 1857: OSErr HFSPlusToHFSExtents( ! 1858: const HFSPlusExtentRecord oldExtents, ! 1859: HFSExtentRecord newExtents) ! 1860: { ! 1861: OSErr err; ! 1862: ! 1863: err = noErr; ! 1864: ! 1865: // copy the first 3 extents ! 1866: newExtents[0].startBlock = oldExtents[0].startBlock; ! 1867: newExtents[0].blockCount = oldExtents[0].blockCount; ! 1868: newExtents[1].startBlock = oldExtents[1].startBlock; ! 1869: newExtents[1].blockCount = oldExtents[1].blockCount; ! 1870: newExtents[2].startBlock = oldExtents[2].startBlock; ! 1871: newExtents[2].blockCount = oldExtents[2].blockCount; ! 1872: ! 1873: #if DEBUG_BUILD ! 1874: if (oldExtents[3].startBlock || oldExtents[3].blockCount) { ! 1875: DebugStr("\pExtentRecord with > 3 extents is invalid for HFS"); ! 1876: err = fsDSIntErr; ! 1877: } ! 1878: #endif ! 1879: ! 1880: return err; ! 1881: } ! 1882: ! 1883: ! 1884: ! 1885: ! 1886: OSErr GetFCBExtentRecord( ! 1887: const FCB *fcb, ! 1888: HFSPlusExtentRecord extents) ! 1889: { ! 1890: ! 1891: BlockMoveData(fcb->fcbExtents, extents, sizeof(HFSPlusExtentRecord)); ! 1892: ! 1893: return noErr; ! 1894: } ! 1895: ! 1896: ! 1897: ! 1898: //������������������������������������������������������������������������������� ! 1899: // Routine: MapFileBlockFromFCB ! 1900: // ! 1901: // Function: Determine if the given file offset is within the set of extents ! 1902: // stored in the FCB. If so, return the file allocation ! 1903: // block number of the start of the extent, volume allocation block number ! 1904: // of the start of the extent, and file allocation block number immediately ! 1905: // following the extent. ! 1906: // ! 1907: // Input: vcb - the volume containing the extents ! 1908: // fcb - the file that owns the extents ! 1909: // offset - desired offset in bytes ! 1910: // ! 1911: // Output: firstFABN - file alloc block number of start of extent ! 1912: // firstBlock - volume alloc block number of start of extent ! 1913: // nextFABN - file alloc block number of next extent ! 1914: // ! 1915: // Result: noErr = ok ! 1916: // fxRangeErr = beyond FCB's extents ! 1917: //������������������������������������������������������������������������������� ! 1918: static OSErr MapFileBlockFromFCB( ! 1919: const ExtendedVCB *vcb, ! 1920: const FCB *fcb, ! 1921: SInt64 offset, // Desired offset in bytes from start of file ! 1922: UInt32 *firstFABN, // FABN of first block of found extent ! 1923: UInt32 *firstBlock, // Corresponding allocation block number ! 1924: UInt32 *nextFABN) // FABN of block after end of extent ! 1925: { ! 1926: UInt32 index; ! 1927: UInt32 offsetBlocks; ! 1928: ! 1929: offsetBlocks = offset / vcb->blockSize; ! 1930: ! 1931: if (vcb->vcbSigWord == kHFSSigWord) { ! 1932: /* XXX SER Do we need to test for overflow values ??? */ ! 1933: UInt16 blockCount; ! 1934: UInt16 currentFABN; ! 1935: ! 1936: currentFABN = 0; ! 1937: ! 1938: for (index=0; index<kHFSExtentDensity; index++) { ! 1939: ! 1940: blockCount = fcb->fcbExtents[index].blockCount; ! 1941: ! 1942: if (blockCount == 0) ! 1943: return fxRangeErr; // ran out of extents! ! 1944: ! 1945: // Is it in this extent? ! 1946: if (offsetBlocks < blockCount) { ! 1947: *firstFABN = currentFABN; ! 1948: *firstBlock = fcb->fcbExtents[index].startBlock; ! 1949: currentFABN += blockCount; // faster to add these as UInt16 first, then extend to UInt32 ! 1950: *nextFABN = currentFABN; ! 1951: return noErr; // found the right extent ! 1952: } ! 1953: ! 1954: // Not in current extent, so adjust counters and loop again ! 1955: offsetBlocks -= blockCount; ! 1956: currentFABN += blockCount; ! 1957: } ! 1958: } ! 1959: else { ! 1960: UInt32 blockCount; ! 1961: UInt32 currentFABN; ! 1962: ! 1963: currentFABN = 0; ! 1964: ! 1965: for (index=0; index<kHFSPlusExtentDensity; index++) { ! 1966: ! 1967: blockCount = fcb->fcbExtents[index].blockCount; ! 1968: ! 1969: if (blockCount == 0) ! 1970: return fxRangeErr; // ran out of extents! ! 1971: ! 1972: // Is it in this extent? ! 1973: if (offsetBlocks < blockCount) { ! 1974: *firstFABN = currentFABN; ! 1975: *firstBlock = fcb->fcbExtents[index].startBlock; ! 1976: *nextFABN = currentFABN + blockCount; ! 1977: return noErr; // found the right extent ! 1978: } ! 1979: ! 1980: // Not in current extent, so adjust counters and loop again ! 1981: offsetBlocks -= blockCount; ! 1982: currentFABN += blockCount; ! 1983: } ! 1984: } ! 1985: ! 1986: // If we fall through here, the extent record was full, but the offset was ! 1987: // beyond those extents. ! 1988: ! 1989: return fxRangeErr; ! 1990: } ! 1991: ! 1992: ! 1993: //_________________________________________________________________________________ ! 1994: // ! 1995: // Routine: ExtentsAreIntegral ! 1996: // ! 1997: // Purpose: Ensure that each extent can hold an integral number of nodes ! 1998: // Called by the NodesAreContiguous function ! 1999: //_________________________________________________________________________________ ! 2000: ! 2001: static Boolean ExtentsAreIntegral( ! 2002: const HFSPlusExtentRecord extentRecord, ! 2003: UInt32 mask, ! 2004: UInt32 *blocksChecked, ! 2005: Boolean *checkedLastExtent) ! 2006: { ! 2007: UInt32 blocks; ! 2008: UInt32 extentIndex; ! 2009: ! 2010: *blocksChecked = 0; ! 2011: *checkedLastExtent = false; ! 2012: ! 2013: for(extentIndex = 0; extentIndex < kHFSPlusExtentDensity; extentIndex++) ! 2014: { ! 2015: blocks = extentRecord[extentIndex].blockCount; ! 2016: ! 2017: if ( blocks == 0 ) ! 2018: { ! 2019: *checkedLastExtent = true; ! 2020: break; ! 2021: } ! 2022: ! 2023: *blocksChecked += blocks; ! 2024: ! 2025: if (blocks & mask) ! 2026: return false; ! 2027: } ! 2028: ! 2029: return true; ! 2030: } ! 2031: ! 2032: ! 2033: //_________________________________________________________________________________ ! 2034: // ! 2035: // Routine: NodesAreContiguous ! 2036: // ! 2037: // Purpose: Ensure that all b-tree nodes are contiguous on disk ! 2038: // Called by BTOpenPath during volume mount ! 2039: //_________________________________________________________________________________ ! 2040: ! 2041: Boolean NodesAreContiguous( ! 2042: ExtendedVCB *vcb, ! 2043: FCB *fcb, ! 2044: UInt32 nodeSize) ! 2045: { ! 2046: UInt32 mask; ! 2047: UInt32 startBlock; ! 2048: UInt32 blocksChecked; ! 2049: UInt32 hint; ! 2050: HFSPlusExtentKey key; ! 2051: HFSPlusExtentRecord extents; ! 2052: OSErr result; ! 2053: Boolean lastExtentReached; ! 2054: ! 2055: ! 2056: if (vcb->blockSize >= nodeSize) ! 2057: return TRUE; ! 2058: ! 2059: mask = (nodeSize / vcb->blockSize) - 1; ! 2060: ! 2061: // check the local extents ! 2062: (void) GetFCBExtentRecord(fcb, extents); ! 2063: if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) ) ! 2064: return FALSE; ! 2065: ! 2066: if (lastExtentReached || (blocksChecked * vcb->blockSize) >= fcb->fcbPLen) ! 2067: return TRUE; ! 2068: ! 2069: startBlock = blocksChecked; ! 2070: ! 2071: // check the overflow extents (if any) ! 2072: while ( !lastExtentReached ) ! 2073: { ! 2074: result = FindExtentRecord(vcb, kDataForkType, H_FILEID(fcb), startBlock, FALSE, &key, extents, &hint); ! 2075: if (result) break; ! 2076: ! 2077: if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) ) ! 2078: return FALSE; ! 2079: ! 2080: startBlock += blocksChecked; ! 2081: } ! 2082: ! 2083: return TRUE; ! 2084: } ! 2085:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.