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