|
|
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: FileIDServices.c ! 24: ! 25: Contains: File ID manipulating routines. ! 26: ! 27: Version: HFS Plus 1.0 ! 28: ! 29: Written by: Deric Horn ! 30: ! 31: Copyright: � 1996-1999 by Apple Computer, Inc., all rights reserved. ! 32: ! 33: File Ownership: ! 34: ! 35: DRI: Deric Horn ! 36: ! 37: Other Contact: xxx put other contact here xxx ! 38: ! 39: Technology: xxx put technology here xxx ! 40: ! 41: Writers: ! 42: ! 43: (JL) Jim Luther ! 44: (msd) Mark Day ! 45: (djb) Don Brady ! 46: (DSH) Deric Horn ! 47: ! 48: Change History (most recent first): ! 49: <MacOSX> 3/2/98 djb Fix extents corruption bug in MoveExtents (radar #2309434). ! 50: <MacOSX> 11/20/98 djb Add support for UTF-8 names. ! 51: <MacOSX> 4/2/98 djb Switch over to real BTree interface in MoveExtents and DeleteExtents. ! 52: <MacOSX> 3/31/98 djb Sync up with final HFSVolumes.h header file. ! 53: ! 54: <CS21> 11/17/97 djb PrepareInputName routine now returns an error. ! 55: <CS20> 11/13/97 djb Radar #2001699 ResolveFileID needs to use CMNotFound error. ! 56: <CS19> 10/31/97 JL #2000184 - CreateFileThreadID and ExchangeFiles now return the ! 57: WDCBRecPtr or NULL for external file systems. ExchangeFiles no ! 58: longer returns length of FCB table to caller since that wasn't ! 59: ever needed. ! 60: <18> 10/23/97 DSH 1685058, Fix ExchangeFiles by invalidating the node cache before ! 61: switching the files. ! 62: <CS17> 10/19/97 msd Bug 1684586. GetCatInfo and SetCatInfo use only contentModDate. ! 63: <CS16> 10/16/97 DSH Return badFidErr in ResolveFileID if LocateCatalogThread fails ! 64: <CS15> 10/15/97 DSH CreateFileThreadID(), remap btExists to fidExists. ! 65: <CS14> 9/7/97 djb Turn off some DebugStr calls. ! 66: <CS13> 9/4/97 msd Remove call to PropertyExchangeObjects. ! 67: <CS12> 8/14/97 djb Remove hard link support. ! 68: <CS11> 7/18/97 msd Include LowMemPriv.h. ! 69: <CS10> 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name ! 70: collision ! 71: <CS9> 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line ! 72: <CS8> 6/24/97 djb Add hard link support to ResolveFileID and CreateFileIDRef. ! 73: <CS7> 6/20/97 msd Use contentModDate and attributeModDate fields instead of ! 74: modifyDate. ! 75: <CS6> 6/13/97 djb Switch over from PrepareOutputName to ConvertUnicodeToHFSName. ! 76: PrepareInputName now takes an encoding. ! 77: <CS5> 5/28/97 msd Move the declaration of FindFileName to FilesInternal.i. ! 78: <CS4> 5/19/97 djb No longer need to invalidate vcbDirIDM field. ! 79: <CS3> 5/16/97 msd In ExchangeFiles, change srcNamePtr from char * to StringPtr ! 80: (fixes warnings). ! 81: <CS2> 4/28/97 djb (DSH) Added VolumeWritable check back into CreateFileIDThread. ! 82: <CS1> 4/24/97 djb first checked in ! 83: <HFS23> 4/11/97 DSH Use extended VCB fields catalogRefNum, and extentsRefNum. ! 84: <HFS22> 4/9/97 msd Rewrite CreateFileThreadID so that it properly handles ! 85: pathnames, and doesn't overwrite the ioNamePtr. The data field ! 86: of FindFileNameGlueRec points to a CatalogNodeData, not ! 87: CatalogRecord. ! 88: <HFS21> 4/4/97 djb Get in sync with volume format changes. ! 89: <HFS20> 3/31/97 djb Change ClearMem to ClearMemory. ! 90: <HFS19> 3/17/97 DSH C_FlushCache prototype to FilesInternal.h ! 91: <HFS18> 3/5/97 msd ExchangeFiles needs to call PropertyExchangeObjects. ! 92: <HFS17> 2/13/97 msd Fix MoveExtents and DeleteExtents to work with HFS+ extent ! 93: records. ! 94: <HFS16> 1/31/97 msd In MoveExtents, when a record isn't found and you want the next ! 95: record in order, use the "next record" offset = 1 instead of ! 96: "current record" offset = 0. DeleteExtents would always exit ! 97: without doing anything because it was searching for an invalid ! 98: key. Removed several DebugStrs that were used as cheap code ! 99: coverage. ! 100: <HFS15> 1/15/97 DSH Resolve wasn't passing the name back for HFS ! 101: <HFS14> 1/13/97 djb LocateCatalogThread now passes back the thread record size. ! 102: <HFS13> 1/11/97 DSH HFS+, fixed some Unicode/Pascal strings related bugs for use on ! 103: HFS+ volumes. ! 104: <HFS12> 1/9/97 DSH Fix ExchangeFiles extents ! 105: <HFS11> 1/6/97 DSH pass VCB in CloseFile() routine. ! 106: <HFS10> 1/6/97 djb Fixed ResolveFileID - it was not returning a directory ID! ! 107: <HFS9> 1/3/97 msd Fix prototype for C_FlushCache. Fix prototype for ! 108: TrashFileBlocks. ! 109: <HFS8> 1/3/97 djb Integrate latest HFSVolumesPriv.h changes. ! 110: <HFS7> 1/2/97 DSH C port of ExchangeFileIDs ! 111: <HFS6> 12/20/96 djb Fixed bug in CreateFileID. ! 112: <HFS5> 12/19/96 DSH All refs to VCB are now refs to ExtendedVCB ! 113: <HFS4> 12/19/96 msd Use kFileThreadExistsMask (from HFSVolumesPriv.h) instead of ! 114: kFileThreadMask (from FilesInternal.h) since the latter was ! 115: incorrectly defined and has now been removed. ! 116: <HFS3> 12/19/96 djb Updated for new B-tree Manager interface. ! 117: <HFS2> 12/18/96 msd GetFileThreadID was using a bitwise-OR (|) instead of ! 118: bitwise-AND (&) to test for a bit being set. ! 119: <HFS1> 12/12/96 DSH first checked in ! 120: ! 121: */ ! 122: ! 123: #include "../../hfs_macos_defs.h" ! 124: #include "../../hfs_format.h" ! 125: ! 126: #include "../headers/FileMgrInternal.h" ! 127: #include "../headers/HFSUnicodeWrappers.h" ! 128: #include "../headers/CatalogPrivate.h" ! 129: ! 130: ! 131: struct ExtentsRecBuffer { ! 132: ExtentKey extentKey; ! 133: ExtentRecord extentData; ! 134: }; ! 135: typedef struct ExtentsRecBuffer ExtentsRecBuffer; ! 136: ! 137: ! 138: OSErr CreateFileID( ExtendedVCB *vcb, HFSCatalogNodeID fileID, CatalogName *name, HFSCatalogNodeID *threadID ); ! 139: OSErr GetFileThreadID( ExtendedVCB *vcb, HFSCatalogNodeID id, const CatalogName *name, Boolean isHFSPlus, UInt32 *threadID ); ! 140: ! 141: UInt32 CheckExtents( void *extents, UInt32 blocks, Boolean isHFSPlus ); ! 142: OSErr DeleteExtents( ExtendedVCB *vcb, UInt32 fileNumber, Boolean isHFSPlus ); ! 143: OSErr MoveExtents( ExtendedVCB *vcb, UInt32 srcFileID, UInt32 destFileID, Boolean isHFSPlus ); ! 144: void CopyCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest ); ! 145: void CopyBigCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest ); ! 146: ! 147: void CopyExtentInfo( ExtentKey *key, ExtentRecord *data, ExtentsRecBuffer *buffer, UInt16 bufferCount ); ! 148: extern void TrashFileBlocks( ExtendedVCB *vcb, UInt32 fileNumber ); ! 149: ! 150: ! 151: ! 152: OSErr ExchangeFileIDs( ExtendedVCB *vcb, ConstUTF8Param srcName, ConstUTF8Param destName, HFSCatalogNodeID srcID, HFSCatalogNodeID destID, UInt32 srcHint, UInt32 destHint ) ! 153: { ! 154: CatalogKey srcKey; // 518 bytes ! 155: CatalogRecord srcData; // 520 bytes ! 156: CatalogKey destKey; // 518 bytes ! 157: CatalogRecord destData; // 520 bytes ! 158: CatalogRecord swapData; // 520 bytes ! 159: SInt16 numSrcExtentBlocks; ! 160: SInt16 numDestExtentBlocks; ! 161: UInt32 textEncoding; ! 162: OSErr err; ! 163: Boolean isHFSPlus = ( vcb->vcbSigWord == kHFSPlusSigWord ); ! 164: ! 165: TrashCatalogIterator(vcb, srcID); // invalidate any iterators for this parentID ! 166: TrashCatalogIterator(vcb, destID); // invalidate any iterators for this parentID ! 167: ! 168: err = BuildCatalogKeyUTF8(vcb, srcID, srcName, kUndefinedStrLen, &srcKey, &textEncoding); ! 169: ReturnIfError(err); ! 170: ! 171: err = BuildCatalogKeyUTF8(vcb, destID, destName, kUndefinedStrLen, &destKey, &textEncoding); ! 172: ReturnIfError(err); ! 173: ! 174: if ( isHFSPlus ) ! 175: { ! 176: //-- Step 1: Check the catalog nodes for extents ! 177: ! 178: //-- locate the source file, test for extents in extent file, and copy the cat record for later ! 179: err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint ); ! 180: ReturnIfError( err ); ! 181: ! 182: if ( srcData.recordType != kHFSPlusFileRecord ) ! 183: return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory" ! 184: ! 185: //-- Check if there are any extents in the source file ! 186: //�� I am only checling the extents in the low 32 bits, routine will fail if files extents after 2 gig are in overflow ! 187: numSrcExtentBlocks = CheckExtents( srcData.hfsPlusFile.dataFork.extents, srcData.hfsPlusFile.dataFork.totalBlocks, isHFSPlus ); ! 188: if ( numSrcExtentBlocks == 0 ) // then check the resource fork extents ! 189: numSrcExtentBlocks = CheckExtents( srcData.hfsPlusFile.resourceFork.extents, srcData.hfsPlusFile.resourceFork.totalBlocks, isHFSPlus ); ! 190: ! 191: //-- Check if there are any extents in the destination file ! 192: err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint ); ! 193: ReturnIfError( err ); ! 194: ! 195: if ( destData.recordType != kHFSPlusFileRecord ) ! 196: return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory" ! 197: ! 198: numDestExtentBlocks = CheckExtents( destData.hfsPlusFile.dataFork.extents, destData.hfsPlusFile.dataFork.totalBlocks, isHFSPlus ); ! 199: if ( numDestExtentBlocks == 0 ) // then check the resource fork extents ! 200: numDestExtentBlocks = CheckExtents( destData.hfsPlusFile.resourceFork.extents, destData.hfsPlusFile.resourceFork.totalBlocks, isHFSPlus ); ! 201: ! 202: //-- Step 2: Exchange the Extent key in the extent file ! 203: ! 204: //-- Exchange the extents key in the extent file ! 205: err = DeleteExtents( vcb, kHFSBogusExtentFileID, isHFSPlus ); ! 206: ReturnIfError( err ); ! 207: ! 208: if ( numSrcExtentBlocks && numDestExtentBlocks ) // if both files have extents ! 209: { ! 210: //-- Change the source extents file ids to our known bogus value ! 211: err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, kHFSBogusExtentFileID, isHFSPlus ); ! 212: if ( err != noErr ) ! 213: { ! 214: if ( err != dskFulErr ) ! 215: return( err ); ! 216: else ! 217: goto ExUndo1a; ! 218: } ! 219: ! 220: //-- Change the destination extents file id's to the source id's ! 221: err = MoveExtents( vcb, destData.hfsPlusFile.fileID, srcData.hfsPlusFile.fileID, isHFSPlus ); ! 222: if ( err != noErr ) ! 223: { ! 224: if ( err != dskFulErr ) ! 225: return( err ); ! 226: ! 227: ExUndo2aPlus: err = DeleteExtents( vcb, srcData.hfsPlusFile.fileID, isHFSPlus ); ! 228: ReturnIfError( err ); // we are doomed. Just QUIT! ! 229: ! 230: err = MoveExtents( vcb, kHFSBogusExtentFileID, srcData.hfsPlusFile.fileID, isHFSPlus ); // Move the extents back ! 231: ReturnIfError( err ); // we are doomed. Just QUIT! ! 232: ! 233: goto ExUndo1a; ! 234: } ! 235: ! 236: //-- Change the bogus extents file id's to the dest id's ! 237: err = MoveExtents( vcb, kHFSBogusExtentFileID, destData.hfsPlusFile.fileID, isHFSPlus ); ! 238: if ( err != noErr ) ! 239: { ! 240: if ( err != dskFulErr ) ! 241: return( err ); ! 242: ! 243: err = DeleteExtents( vcb, destData.hfsPlusFile.fileID, isHFSPlus ); ! 244: ReturnIfError( err ); // we are doomed. Just QUIT! ! 245: ! 246: err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, destData.hfsPlusFile.fileID, isHFSPlus ); // Move the extents back ! 247: ReturnIfError( err ); // we are doomed. Just QUIT! ! 248: ! 249: goto ExUndo2aPlus; ! 250: } ! 251: ! 252: } ! 253: else if ( numSrcExtentBlocks ) // just the source file has extents ! 254: { ! 255: err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, destData.hfsPlusFile.fileID, isHFSPlus ); ! 256: if ( err != noErr ) ! 257: { ! 258: if ( err != dskFulErr ) ! 259: return( err ); ! 260: ! 261: err = DeleteExtents( vcb, srcData.hfsPlusFile.fileID, isHFSPlus ); ! 262: ReturnIfError( err ); // we are doomed. Just QUIT! ! 263: ! 264: goto FlushAndReturn; ! 265: } ! 266: } ! 267: else if ( numDestExtentBlocks ) // just the destination file has extents ! 268: { ! 269: err = MoveExtents( vcb, destData.hfsPlusFile.fileID, srcData.hfsPlusFile.fileID, isHFSPlus ); ! 270: if ( err != noErr ) ! 271: { ! 272: if ( err != dskFulErr ) ! 273: return( err ); ! 274: ! 275: err = DeleteExtents( vcb, destData.hfsPlusFile.fileID, isHFSPlus ); ! 276: ReturnIfError( err ); // we are doomed. Just QUIT! ! 277: ! 278: goto FlushAndReturn; ! 279: } ! 280: } ! 281: ! 282: //-- Step 3: Change the data in the catalog nodes ! 283: ! 284: //-- find the source cnode and put dest info in it ! 285: err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint ); ! 286: if ( err != noErr ) ! 287: return( cmBadNews ); ! 288: ! 289: BlockMoveData( &srcData, &swapData, sizeof(CatalogRecord) ); ! 290: CopyBigCatalogNodeInfo( &destData, &srcData ); ! 291: ! 292: err = ReplaceBTreeRecord( vcb->catalogRefNum, &srcKey, srcHint, &srcData, sizeof(HFSPlusCatalogFile), &srcHint ); ! 293: ReturnIfError( err ); ! 294: ! 295: // find the destination cnode and put source info in it ! 296: err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint ); ! 297: if ( err != noErr ) ! 298: return( cmBadNews ); ! 299: ! 300: CopyBigCatalogNodeInfo( &swapData, &destData ); ! 301: err = ReplaceBTreeRecord( vcb->catalogRefNum, &destKey, destHint, &destData, sizeof(HFSPlusCatalogFile), &destHint ); ! 302: ReturnIfError( err ); ! 303: } ! 304: else // HFS // ! 305: { ! 306: //-- Step 1: Check the catalog nodes for extents ! 307: ! 308: //-- locate the source file, test for extents in extent file, and copy the cat record for later ! 309: err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint ); ! 310: ReturnIfError( err ); ! 311: ! 312: if ( srcData.recordType != kHFSFileRecord ) ! 313: return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory" ! 314: ! 315: //-- Check if there are any extents in the source file ! 316: numSrcExtentBlocks = CheckExtents( srcData.hfsFile.dataExtents, srcData.hfsFile.dataPhysicalSize / vcb->blockSize, isHFSPlus ); ! 317: if ( numSrcExtentBlocks == 0 ) // then check the resource fork extents ! 318: numSrcExtentBlocks = CheckExtents( srcData.hfsFile.rsrcExtents, srcData.hfsFile.rsrcPhysicalSize / vcb->blockSize, isHFSPlus ); ! 319: ! 320: ! 321: //�� Do we save the found source node for later use? ! 322: ! 323: ! 324: //-- Check if there are any extents in the destination file ! 325: err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint ); ! 326: ReturnIfError( err ); ! 327: ! 328: if ( destData.recordType != kHFSFileRecord ) ! 329: return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory" ! 330: ! 331: numDestExtentBlocks = CheckExtents( destData.hfsFile.dataExtents, destData.hfsFile.dataPhysicalSize / vcb->blockSize, isHFSPlus ); ! 332: if ( numDestExtentBlocks == 0 ) // then check the resource fork extents ! 333: numDestExtentBlocks = CheckExtents( destData.hfsFile.rsrcExtents, destData.hfsFile.rsrcPhysicalSize / vcb->blockSize, isHFSPlus ); ! 334: ! 335: //�� Do we save the found destination node for later use? ! 336: ! 337: ! 338: //-- Step 2: Exchange the Extent key in the extent file ! 339: ! 340: //-- Exchange the extents key in the extent file ! 341: err = DeleteExtents( vcb, kHFSBogusExtentFileID, isHFSPlus ); ! 342: ReturnIfError( err ); ! 343: ! 344: if ( numSrcExtentBlocks && numDestExtentBlocks ) // if both files have extents ! 345: { ! 346: //-- Change the source extents file ids to our known bogus value ! 347: err = MoveExtents( vcb, srcData.hfsFile.fileID, kHFSBogusExtentFileID, isHFSPlus ); ! 348: if ( err != noErr ) ! 349: { ! 350: if ( err != dskFulErr ) ! 351: return( err ); ! 352: ! 353: ExUndo1a: err = DeleteExtents( vcb, kHFSBogusExtentFileID, isHFSPlus ); ! 354: ReturnIfError( err ); // we are doomed. Just QUIT! ! 355: ! 356: err = FlushCatalog( vcb ); // flush the catalog ! 357: err = FlushExtentFile( vcb ); // flush the extent file (unneeded for common case, but it's cheap) ! 358: return( dskFulErr ); ! 359: } ! 360: ! 361: //-- Change the destination extents file id's to the source id's ! 362: err = MoveExtents( vcb, destData.hfsFile.fileID, srcData.hfsFile.fileID, isHFSPlus ); ! 363: if ( err != noErr ) ! 364: { ! 365: if ( err != dskFulErr ) ! 366: return( err ); ! 367: ! 368: ExUndo2a: err = DeleteExtents( vcb, srcData.hfsFile.fileID, isHFSPlus ); ! 369: ReturnIfError( err ); // we are doomed. Just QUIT! ! 370: ! 371: err = MoveExtents( vcb, kHFSBogusExtentFileID, srcData.hfsFile.fileID, isHFSPlus ); // Move the extents back ! 372: ReturnIfError( err ); // we are doomed. Just QUIT! ! 373: ! 374: goto ExUndo1a; ! 375: } ! 376: ! 377: //-- Change the bogus extents file id's to the dest id's ! 378: err = MoveExtents( vcb, kHFSBogusExtentFileID, destData.hfsFile.fileID, isHFSPlus ); ! 379: if ( err != noErr ) ! 380: { ! 381: if ( err != dskFulErr ) ! 382: return( err ); ! 383: ! 384: err = DeleteExtents( vcb, destData.hfsFile.fileID, isHFSPlus ); ! 385: ReturnIfError( err ); // we are doomed. Just QUIT! ! 386: ! 387: err = MoveExtents( vcb, srcData.hfsFile.fileID, destData.hfsFile.fileID, isHFSPlus ); // Move the extents back ! 388: ReturnIfError( err ); // we are doomed. Just QUIT! ! 389: ! 390: goto ExUndo2a; ! 391: } ! 392: ! 393: } ! 394: else if ( numSrcExtentBlocks ) // just the source file has extents ! 395: { ! 396: err = MoveExtents( vcb, srcData.hfsFile.fileID, destData.hfsFile.fileID, isHFSPlus ); ! 397: if ( err != noErr ) ! 398: { ! 399: if ( err != dskFulErr ) ! 400: return( err ); ! 401: ! 402: err = DeleteExtents( vcb, srcData.hfsFile.fileID, isHFSPlus ); ! 403: ReturnIfError( err ); // we are doomed. Just QUIT! ! 404: ! 405: goto FlushAndReturn; ! 406: } ! 407: } ! 408: else if ( numDestExtentBlocks ) // just the destination file has extents ! 409: { ! 410: err = MoveExtents( vcb, destData.hfsFile.fileID, srcData.hfsFile.fileID, isHFSPlus ); ! 411: if ( err != noErr ) ! 412: { ! 413: if ( err != dskFulErr ) ! 414: return( err ); ! 415: ! 416: err = DeleteExtents( vcb, destData.hfsFile.fileID, isHFSPlus ); ! 417: ReturnIfError( err ); // we are doomed. Just QUIT! ! 418: ! 419: goto FlushAndReturn; ! 420: } ! 421: } ! 422: ! 423: //-- Step 3: Change the data in the catalog nodes ! 424: ! 425: //-- find the source cnode and put dest info in it ! 426: err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint ); ! 427: if ( err != noErr ) ! 428: return( cmBadNews ); ! 429: ! 430: BlockMoveData( &srcData, &swapData, sizeof(CatalogRecord) ); ! 431: //�� Asm source copies from the saved dest catalog node ! 432: CopyCatalogNodeInfo( &destData, &srcData ); ! 433: ! 434: err = ReplaceBTreeRecord( vcb->catalogRefNum, &srcKey, srcHint, &srcData, sizeof(HFSCatalogFile), &srcHint ); ! 435: ReturnIfError( err ); ! 436: ! 437: ! 438: // find the destination cnode and put source info in it ! 439: err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint ); ! 440: if ( err != noErr ) ! 441: return( cmBadNews ); ! 442: ! 443: CopyCatalogNodeInfo( &swapData, &destData ); ! 444: err = ReplaceBTreeRecord( vcb->catalogRefNum, &destKey, destHint, &destData, sizeof(HFSCatalogFile), &destHint ); ! 445: ReturnIfError( err ); ! 446: } ! 447: ! 448: err = noErr; ! 449: ! 450: //-- Step 4: Error Handling section ! 451: ! 452: ! 453: FlushAndReturn: ! 454: err = FlushCatalog( vcb ); // flush the catalog ! 455: err = FlushExtentFile( vcb ); // flush the extent file (unneeded for common case, but it's cheap) ! 456: return( err ); ! 457: } ! 458: ! 459: ! 460: void CopyCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest ) ! 461: { ! 462: // dest->hfsFile.filStBlk = src->hfsFile.filStBlk; ! 463: dest->hfsFile.dataLogicalSize = src->hfsFile.dataLogicalSize; ! 464: dest->hfsFile.dataPhysicalSize = src->hfsFile.dataPhysicalSize; ! 465: // dest->hfsFile.filRStBlk = src->hfsFile.filRStBlk; ! 466: dest->hfsFile.rsrcLogicalSize = src->hfsFile.rsrcLogicalSize; ! 467: dest->hfsFile.rsrcPhysicalSize = src->hfsFile.rsrcPhysicalSize; ! 468: dest->hfsFile.modifyDate = src->hfsFile.modifyDate; ! 469: BlockMoveData( src->hfsFile.dataExtents, dest->hfsFile.dataExtents, sizeof(HFSExtentRecord) ); ! 470: BlockMoveData( src->hfsFile.rsrcExtents, dest->hfsFile.rsrcExtents, sizeof(HFSExtentRecord) ); ! 471: } ! 472: ! 473: void CopyBigCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest ) ! 474: { ! 475: BlockMoveData( &src->hfsPlusFile.dataFork, &dest->hfsPlusFile.dataFork, sizeof(HFSPlusForkData) ); ! 476: BlockMoveData( &src->hfsPlusFile.resourceFork, &dest->hfsPlusFile.resourceFork, sizeof(HFSPlusForkData) ); ! 477: dest->hfsPlusFile.contentModDate = src->hfsPlusFile.contentModDate; ! 478: } ! 479: ! 480: ! 481: OSErr MoveExtents( ExtendedVCB *vcb, UInt32 srcFileID, UInt32 destFileID, Boolean isHFSPlus ) ! 482: { ! 483: FCB * fcb; ! 484: ExtentsRecBuffer extentsBuffer[kNumExtentsToCache]; ! 485: ExtentKey * extentKeyPtr; ! 486: ExtentRecord extentData; ! 487: BTreeIterator btIterator; ! 488: FSBufferDescriptor btRecord; ! 489: UInt16 btKeySize; ! 490: UInt16 btRecordSize; ! 491: SInt16 i, j; ! 492: OSErr err; ! 493: ! 494: ! 495: fcb = GetFileControlBlock(vcb->extentsRefNum); ! 496: ! 497: (void) BTInvalidateHint(&btIterator); ! 498: extentKeyPtr = (ExtentKey*) &btIterator.key; ! 499: btRecord.bufferAddress = &extentData; ! 500: btRecord.itemCount = 1; ! 501: ! 502: //-- Collect the extent records ! 503: ! 504: // ! 505: // A search on the following key will cause the BTree to be positioned immediately ! 506: // before the first extent record for file #srcFileID, but not actually positioned ! 507: // on any record. This is because there cannot be an extent record with FABN = 0 ! 508: // (the first extent of the fork, which would be in the catalog entry, not an extent ! 509: // record). ! 510: // ! 511: // Using BTIterateRecord with kBTreeNextRecord will then get that first extent record. ! 512: // ! 513: if (isHFSPlus) { ! 514: btRecord.itemSize = sizeof(HFSPlusExtentRecord); ! 515: btKeySize = sizeof(HFSPlusExtentKey); ! 516: ! 517: extentKeyPtr->hfsPlus.keyLength = kHFSPlusExtentKeyMaximumLength; ! 518: extentKeyPtr->hfsPlus.forkType = 0; ! 519: extentKeyPtr->hfsPlus.pad = 0; ! 520: extentKeyPtr->hfsPlus.fileID = srcFileID; ! 521: extentKeyPtr->hfsPlus.startBlock = 0; ! 522: } ! 523: else { ! 524: btRecord.itemSize = sizeof(HFSExtentRecord); ! 525: btKeySize = sizeof(HFSExtentKey); ! 526: ! 527: extentKeyPtr->hfs.keyLength = kHFSExtentKeyMaximumLength; ! 528: extentKeyPtr->hfs.forkType = 0; ! 529: extentKeyPtr->hfs.fileID = srcFileID; ! 530: extentKeyPtr->hfs.startBlock = 0; ! 531: } ! 532: ! 533: // ! 534: // We do an initial BTSearchRecord to position the BTree's iterator just before any extent ! 535: // records for srcFileID. We then do a few BTIterateRecord and BTInsertRecord of those found ! 536: // records, but with destFileID as the file number in the key. Keep doing this sequence of ! 537: // BTIterateRecord and BTInsertRecord until we find an extent for another file, or there are ! 538: // no more extent records in the tree. ! 539: // ! 540: // Basically, we're copying records kNumExtentsToCache at a time. The copies have their file ID ! 541: // set to destFileID. ! 542: // ! 543: // This depends on BTInsertRecord not effecting the iterator used by BTIterateRecord. If it ! 544: // _did_ effect the iterator, then we would need to do a BTSearchRecord before each series ! 545: // of BTIterateRecord. We'd need to set up the key for BTSearchRecord to find the last record ! 546: // we found, so that BTIterateRecord would get the next one (the first we haven't processed). ! 547: // ! 548: ! 549: err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator); ! 550: ! 551: // We expect a btNotFound here, since there shouldn't be an extent record with FABN = 0. ! 552: if (err != btNotFound) ! 553: { ! 554: if ( DEBUG_BUILD ) ! 555: DebugStr("\pUnexpected error from SearchBTreeRecord"); ! 556: ! 557: if (err == noErr) // If we found such a bogus extent record, then the tree is really messed up ! 558: err = cmBadNews; // so return an error that conveys the disk is hosed. ! 559: ! 560: return err; ! 561: } ! 562: ! 563: do ! 564: { ! 565: btRecord.bufferAddress = &extentData; ! 566: btRecord.itemCount = 1; ! 567: ! 568: for ( i=0 ; i<kNumExtentsToCache ; i++ ) ! 569: { ! 570: HFSCatalogNodeID foundFileID; ! 571: ! 572: err = BTIterateRecord(fcb, kBTreeNextRecord, &btIterator, &btRecord, &btRecordSize); ! 573: if ( err == btNotFound ) // Did we run out of extent records in the extents tree? ! 574: break; // if xkrFNum(A0) is cleared on this error, then this test is bogus! ! 575: else if ( err != noErr ) ! 576: return( err ); // must be ioError ! 577: ! 578: foundFileID = isHFSPlus ? extentKeyPtr->hfsPlus.fileID : extentKeyPtr->hfs.fileID; ! 579: if ( foundFileID == srcFileID ) ! 580: { ! 581: CopyExtentInfo(extentKeyPtr, &extentData, extentsBuffer, i); ! 582: } ! 583: else ! 584: { ! 585: break; ! 586: } ! 587: } ! 588: ! 589: //-- edit each extent key, and reinsert each extent record in the extent file ! 590: if (isHFSPlus) ! 591: btRecordSize = sizeof(HFSPlusExtentRecord); ! 592: else ! 593: btRecordSize = sizeof(HFSExtentRecord); ! 594: ! 595: for ( j=0 ; j<i ; j++ ) ! 596: { ! 597: BTreeIterator tmpIterator; ! 598: ! 599: if (isHFSPlus) ! 600: extentsBuffer[j].extentKey.hfsPlus.fileID = destFileID; // change only the id in the key to dest ID ! 601: else ! 602: extentsBuffer[j].extentKey.hfs.fileID = destFileID; // change only the id in the key to dest ID ! 603: ! 604: // get iterator and buffer descriptor ready... ! 605: (void) BTInvalidateHint(&tmpIterator); ! 606: BlockMoveData(&(extentsBuffer[j].extentKey), &tmpIterator.key, btKeySize); ! 607: btRecord.bufferAddress = &(extentsBuffer[j].extentData); ! 608: ! 609: err = BTInsertRecord(fcb, &tmpIterator, &btRecord, btRecordSize); ! 610: if ( err != noErr ) ! 611: { // parse the error ! 612: if ( err == btExists ) ! 613: { ! 614: if ( DEBUG_BUILD ) ! 615: DebugStr("\pCan't insert record -- already exists"); ! 616: return( cmBadNews ); ! 617: } ! 618: else ! 619: return( err ); ! 620: } ! 621: } ! 622: ! 623: //-- okay, done with this buffered batch, go get the next set of extent records ! 624: // If our buffer is not full, we must be done, or recieved an error ! 625: ! 626: if ( i != kNumExtentsToCache ) // if the buffer is not full, we must be done ! 627: { ! 628: err = DeleteExtents( vcb, srcFileID, isHFSPlus ); // Now delete all the extent entries with the sourceID ! 629: if ( DEBUG_BUILD && err != noErr ) ! 630: DebugStr("\pError from DeleteExtents"); ! 631: break; // we're done! ! 632: } ! 633: } while ( true ); ! 634: ! 635: return( err ); ! 636: } ! 637: ! 638: ! 639: void CopyExtentInfo( ExtentKey *key, ExtentRecord *data, ExtentsRecBuffer *buffer, UInt16 bufferCount ) ! 640: { ! 641: BlockMoveData( key, &(buffer[bufferCount].extentKey), sizeof( ExtentKey ) ); ! 642: BlockMoveData( data, &(buffer[bufferCount].extentData), sizeof( ExtentRecord ) ); ! 643: } ! 644: ! 645: ! 646: //-- Delete all extents in extent file that have the ID given. ! 647: OSErr DeleteExtents( ExtendedVCB *vcb, UInt32 fileID, Boolean isHFSPlus ) ! 648: { ! 649: FCB * fcb; ! 650: ExtentKey * extentKeyPtr; ! 651: ExtentRecord extentData; ! 652: BTreeIterator btIterator; ! 653: FSBufferDescriptor btRecord; ! 654: UInt16 btRecordSize; ! 655: OSErr err; ! 656: ! 657: fcb = GetFileControlBlock(vcb->extentsRefNum); ! 658: ! 659: (void) BTInvalidateHint(&btIterator); ! 660: extentKeyPtr = (ExtentKey*) &btIterator.key; ! 661: btRecord.bufferAddress = &extentData; ! 662: btRecord.itemCount = 1; ! 663: ! 664: // The algorithm is to position the BTree just before any extent records for fileID. ! 665: // Then just keep getting successive records. If the record is still for fileID, ! 666: // then delete it. ! 667: ! 668: if (isHFSPlus) { ! 669: btRecord.itemSize = sizeof(HFSPlusExtentRecord); ! 670: ! 671: extentKeyPtr->hfsPlus.keyLength = kHFSPlusExtentKeyMaximumLength; ! 672: extentKeyPtr->hfsPlus.forkType = 0; ! 673: extentKeyPtr->hfsPlus.pad = 0; ! 674: extentKeyPtr->hfsPlus.fileID = fileID; ! 675: extentKeyPtr->hfsPlus.startBlock = 0; ! 676: } ! 677: else { ! 678: btRecord.itemSize = sizeof(HFSExtentRecord); ! 679: ! 680: extentKeyPtr->hfs.keyLength = kHFSExtentKeyMaximumLength; ! 681: extentKeyPtr->hfs.forkType = 0; ! 682: extentKeyPtr->hfs.fileID = fileID; ! 683: extentKeyPtr->hfs.startBlock = 0; ! 684: } ! 685: ! 686: err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator); ! 687: if ( err != btNotFound ) ! 688: { ! 689: if (err == noErr) { // Did we find a bogus extent record? ! 690: err = cmBadNews; // Yes, so indicate things are messed up. ! 691: } ! 692: ! 693: return err; // Got some unexpected error, so return it ! 694: } ! 695: ! 696: do ! 697: { ! 698: BTreeIterator tmpIterator; ! 699: HFSCatalogNodeID foundFileID; ! 700: ! 701: err = BTIterateRecord(fcb, kBTreeNextRecord, &btIterator, &btRecord, &btRecordSize); ! 702: if ( err != noErr ) ! 703: { ! 704: if (err == btNotFound) // If we hit the end of the BTree ! 705: err = noErr; // then it's OK ! 706: ! 707: break; // We're done now. ! 708: } ! 709: ! 710: foundFileID = isHFSPlus ? extentKeyPtr->hfsPlus.fileID : extentKeyPtr->hfs.fileID; ! 711: if ( foundFileID != fileID ) ! 712: break; // numbers don't match, we must be done ! 713: ! 714: tmpIterator = btIterator; ! 715: err = BTDeleteRecord( fcb, &tmpIterator ); ! 716: if (err != noErr) ! 717: break; ! 718: } while ( true ); ! 719: ! 720: return( err ); ! 721: } ! 722: ! 723: ! 724: // Check if there are extents represented in the extents overflow file. ! 725: UInt32 CheckExtents( void *extents, UInt32 totalBlocks, Boolean isHFSPlus ) ! 726: { ! 727: UInt32 extentAllocationBlocks; ! 728: UInt16 i; ! 729: ! 730: ! 731: if ( totalBlocks == 0 ) ! 732: return( 0 ); ! 733: ! 734: extentAllocationBlocks = 0; ! 735: ! 736: if ( isHFSPlus ) ! 737: { ! 738: for ( i = 0 ; i < kHFSPlusExtentDensity ; i++ ) ! 739: { ! 740: extentAllocationBlocks += ((HFSPlusExtentDescriptor *)extents)[i].blockCount; ! 741: if ( extentAllocationBlocks >= totalBlocks ) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump) ! 742: return( 0 ); ! 743: } ! 744: } ! 745: else ! 746: { ! 747: for ( i = 0 ; i < kHFSExtentDensity ; i++ ) ! 748: { ! 749: extentAllocationBlocks += ((HFSExtentDescriptor *)extents)[i].blockCount; ! 750: if ( extentAllocationBlocks >= totalBlocks ) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump) ! 751: return( 0 ); ! 752: } ! 753: } ! 754: ! 755: return( extentAllocationBlocks ); ! 756: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.