|
|
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: FileIDServices.c ! 27: ! 28: Contains: File ID manipulating routines. ! 29: ! 30: Version: HFS Plus 1.0 ! 31: ! 32: Written by: Deric Horn ! 33: ! 34: Copyright: � 1996-1999 by Apple Computer, Inc., all rights reserved. ! 35: ! 36: File Ownership: ! 37: ! 38: DRI: Deric Horn ! 39: ! 40: Other Contact: xxx put other contact here xxx ! 41: ! 42: Technology: xxx put technology here xxx ! 43: ! 44: Writers: ! 45: ! 46: (JL) Jim Luther ! 47: (msd) Mark Day ! 48: (djb) Don Brady ! 49: (DSH) Deric Horn ! 50: ! 51: Change History (most recent first): ! 52: <Rhap> 3/2/98 djb Fix extents corruption bug in MoveExtents (radar #2309434). ! 53: <Rhap> 11/20/98 djb Add support for UTF-8 names. ! 54: <Rhap> 4/2/98 djb Switch over to real BTree interface in MoveExtents and DeleteExtents. ! 55: <Rhap> 3/31/98 djb Sync up with final HFSVolumes.h header file. ! 56: ! 57: <CS21> 11/17/97 djb PrepareInputName routine now returns an error. ! 58: <CS20> 11/13/97 djb Radar #2001699 ResolveFileID needs to use CMNotFound error. ! 59: <CS19> 10/31/97 JL #2000184 - CreateFileThreadID and ExchangeFiles now return the ! 60: WDCBRecPtr or NULL for external file systems. ExchangeFiles no ! 61: longer returns length of FCB table to caller since that wasn't ! 62: ever needed. ! 63: <18> 10/23/97 DSH 1685058, Fix ExchangeFiles by invalidating the node cache before ! 64: switching the files. ! 65: <CS17> 10/19/97 msd Bug 1684586. GetCatInfo and SetCatInfo use only contentModDate. ! 66: <CS16> 10/16/97 DSH Return badFidErr in ResolveFileID if LocateCatalogThread fails ! 67: <CS15> 10/15/97 DSH CreateFileThreadID(), remap btExists to fidExists. ! 68: <CS14> 9/7/97 djb Turn off some DebugStr calls. ! 69: <CS13> 9/4/97 msd Remove call to PropertyExchangeObjects. ! 70: <CS12> 8/14/97 djb Remove hard link support. ! 71: <CS11> 7/18/97 msd Include LowMemPriv.h. ! 72: <CS10> 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name ! 73: collision ! 74: <CS9> 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line ! 75: <CS8> 6/24/97 djb Add hard link support to ResolveFileID and CreateFileIDRef. ! 76: <CS7> 6/20/97 msd Use contentModDate and attributeModDate fields instead of ! 77: modifyDate. ! 78: <CS6> 6/13/97 djb Switch over from PrepareOutputName to ConvertUnicodeToHFSName. ! 79: PrepareInputName now takes an encoding. ! 80: <CS5> 5/28/97 msd Move the declaration of FindFileName to FilesInternal.i. ! 81: <CS4> 5/19/97 djb No longer need to invalidate vcbDirIDM field. ! 82: <CS3> 5/16/97 msd In ExchangeFiles, change srcNamePtr from char * to StringPtr ! 83: (fixes warnings). ! 84: <CS2> 4/28/97 djb (DSH) Added VolumeWritable check back into CreateFileIDThread. ! 85: <CS1> 4/24/97 djb first checked in ! 86: <HFS23> 4/11/97 DSH Use extended VCB fields catalogRefNum, and extentsRefNum. ! 87: <HFS22> 4/9/97 msd Rewrite CreateFileThreadID so that it properly handles ! 88: pathnames, and doesn't overwrite the ioNamePtr. The data field ! 89: of FindFileNameGlueRec points to a CatalogNodeData, not ! 90: CatalogRecord. ! 91: <HFS21> 4/4/97 djb Get in sync with volume format changes. ! 92: <HFS20> 3/31/97 djb Change ClearMem to ClearMemory. ! 93: <HFS19> 3/17/97 DSH C_FlushCache prototype to FilesInternal.h ! 94: <HFS18> 3/5/97 msd ExchangeFiles needs to call PropertyExchangeObjects. ! 95: <HFS17> 2/13/97 msd Fix MoveExtents and DeleteExtents to work with HFS+ extent ! 96: records. ! 97: <HFS16> 1/31/97 msd In MoveExtents, when a record isn't found and you want the next ! 98: record in order, use the "next record" offset = 1 instead of ! 99: "current record" offset = 0. DeleteExtents would always exit ! 100: without doing anything because it was searching for an invalid ! 101: key. Removed several DebugStrs that were used as cheap code ! 102: coverage. ! 103: <HFS15> 1/15/97 DSH Resolve wasn't passing the name back for HFS ! 104: <HFS14> 1/13/97 djb LocateCatalogThread now passes back the thread record size. ! 105: <HFS13> 1/11/97 DSH HFS+, fixed some Unicode/Pascal strings related bugs for use on ! 106: HFS+ volumes. ! 107: <HFS12> 1/9/97 DSH Fix ExchangeFiles extents ! 108: <HFS11> 1/6/97 DSH pass VCB in CloseFile() routine. ! 109: <HFS10> 1/6/97 djb Fixed ResolveFileID - it was not returning a directory ID! ! 110: <HFS9> 1/3/97 msd Fix prototype for C_FlushCache. Fix prototype for ! 111: TrashFileBlocks. ! 112: <HFS8> 1/3/97 djb Integrate latest HFSVolumesPriv.h changes. ! 113: <HFS7> 1/2/97 DSH C port of ExchangeFileIDs ! 114: <HFS6> 12/20/96 djb Fixed bug in CreateFileID. ! 115: <HFS5> 12/19/96 DSH All refs to VCB are now refs to ExtendedVCB ! 116: <HFS4> 12/19/96 msd Use kFileThreadExistsMask (from HFSVolumesPriv.h) instead of ! 117: kFileThreadMask (from FilesInternal.h) since the latter was ! 118: incorrectly defined and has now been removed. ! 119: <HFS3> 12/19/96 djb Updated for new B-tree Manager interface. ! 120: <HFS2> 12/18/96 msd GetFileThreadID was using a bitwise-OR (|) instead of ! 121: bitwise-AND (&) to test for a bit being set. ! 122: <HFS1> 12/12/96 DSH first checked in ! 123: ! 124: */ ! 125: ! 126: #if ( PRAGMA_LOAD_SUPPORTED ) ! 127: #pragma load PrecompiledHeaders ! 128: #else ! 129: #if TARGET_OS_MAC ! 130: #include <Types.h> ! 131: #include <Files.h> ! 132: #include <LowMemPriv.h> ! 133: #else ! 134: #include "../headers/system/MacOSStubs.h" ! 135: #endif /* TARGET_OS_MAC */ ! 136: #endif /* PRAGMA_LOAD_SUPPORTED */ ! 137: ! 138: #include "../headers/FileMgrInternal.h" ! 139: #include "../headers/HFSVolumes.h" ! 140: #include "../headers/system/HFSUnicodeWrappers.h" ! 141: #include "../headers/CatalogPrivate.h" ! 142: ! 143: ! 144: struct ExtentsRecBuffer { ! 145: ExtentKey extentKey; ! 146: ExtentRecord extentData; ! 147: }; ! 148: typedef struct ExtentsRecBuffer ExtentsRecBuffer; ! 149: ! 150: ! 151: OSErr CreateFileID( ExtendedVCB *vcb, HFSCatalogNodeID fileID, CatalogName *name, HFSCatalogNodeID *threadID ); ! 152: OSErr GetFileThreadID( ExtendedVCB *vcb, HFSCatalogNodeID id, const CatalogName *name, Boolean isHFSPlus, UInt32 *threadID ); ! 153: ! 154: UInt32 CheckExtents( void *extents, UInt32 blocks, Boolean isHFSPlus ); ! 155: OSErr DeleteExtents( ExtendedVCB *vcb, UInt32 fileNumber, Boolean isHFSPlus ); ! 156: OSErr MoveExtents( ExtendedVCB *vcb, UInt32 srcFileID, UInt32 destFileID, Boolean isHFSPlus ); ! 157: void CopyCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest ); ! 158: void CopyBigCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest ); ! 159: ! 160: void CopyExtentInfo( ExtentKey *key, ExtentRecord *data, ExtentsRecBuffer *buffer, UInt16 bufferCount ); ! 161: extern void TrashFileBlocks( ExtendedVCB *vcb, UInt32 fileNumber ); ! 162: ! 163: ! 164: ! 165: //������������������������������������������������������������������������������� ! 166: // Routine: ResolveFileID from Asm : FIDResolveID ! 167: // ! 168: // Function: ResolveFileID finds the dirID and CName for a file, given it's thread. ! 169: // ! 170: // Output: OSErr err ! 171: // Str31 name - resolved name ! 172: // HFSCatalogNodeID parentID - resolved parent ID ! 173: //������������������������������������������������������������������������������� ! 174: ! 175: #if TARGET_OS_MAC ! 176: ! 177: OSErr ResolveFileID( ExtendedVCB *vcb, HFSCatalogNodeID fileID, HFSCatalogNodeID *parentID, Str31 name ) ! 178: { ! 179: OSErr err; ! 180: CatalogRecord threadData; ! 181: CatalogKey key; ! 182: CatalogRecord data; ! 183: UInt32 threadHint; ! 184: UInt32 tempHint; ! 185: UInt16 threadSize; ! 186: Boolean isHFSPlus; ! 187: ! 188: ! 189: err = CheckVolumeOffLine( vcb ); ! 190: ReturnIfError( err ); ! 191: ! 192: isHFSPlus = ( vcb->vcbSigWord == kHFSPlusSigWord ); ! 193: ! 194: //-- if it's not an HFS Plus volume, make sure it's an HFS volume ! 195: if ( (! isHFSPlus) && (vcb->vcbSigWord != kHFSSigWord) ) ! 196: return( wrgVolTypErr ); ! 197: ! 198: threadHint = kNoHint; ! 199: ! 200: //-- Locate the file thread ! 201: ! 202: err = LocateCatalogThread( vcb, fileID, &threadData, &threadSize, &threadHint ); // This call returns nodeName as either Str31 or HFSUniStr255, no need to call PrepareInputName() ! 203: if ( err != noErr ) ! 204: return( cmNotFound ); // treat it as fidNotFound error ! 205: ! 206: ! 207: if ( (threadData.recordType != kHFSFileThreadRecord) && (threadData.recordType != kHFSPlusFileThreadRecord) ) ! 208: return( cmFThdDirErr ); ! 209: ! 210: ! 211: isHFSPlus = ( vcb->vcbSigWord == kHFSPlusSigWord ); ! 212: ! 213: if ( isHFSPlus ) ! 214: { ! 215: TextEncoding encoding; ! 216: ByteCount actualDstLen; ! 217: ! 218: //-- Check if the file exists ! 219: ! 220: err = LocateCatalogNode( vcb, threadData.hfsPlusThread.parentID, (const CatalogName *) &(threadData.hfsPlusThread.nodeName), kNoHint, &key, &data, &tempHint); ! 221: ! 222: //-- We found the file, but is this the file we really want? ! 223: ! 224: if ( err || data.hfsPlusFile.fileID != fileID ) ! 225: return( badFidErr ); ! 226: ! 227: encoding = data.hfsPlusFile.textEncoding; // note: text encoding and fileID is at same offset for folders ! 228: ! 229: // Copy the name back for output ! 230: err = ConvertUnicodeToUTF8( threadData.hfsPlusThread.nodeName.length * sizeof(UniChar), ! 231: threadData.hfsPlusThread.nodeName.unicode, ! 232: NAME_MAX+1, ! 233: &actualDstLen, ! 234: name); ! 235: *parentID = threadData.hfsPlusThread.parentID; ! 236: } ! 237: else ! 238: { ! 239: //-- Check if the file exists ! 240: // No need to prepare name for in/output, it will stay a Str31 in HFS ! 241: ! 242: err = LocateCatalogNode( vcb, threadData.hfsThread.parentID, (const CatalogName *) &(threadData.hfsThread.nodeName), kNoHint, &key, &data, &tempHint ); ! 243: ! 244: //-- We found the file, but is this the file we really want? ! 245: ! 246: if ( err || data.hfsFile.fileID != fileID ) ! 247: return( badFidErr ); ! 248: ! 249: // Copy the name back for output ! 250: BlockMoveData( threadData.hfsThread.nodeName, name, StrLength(threadData.hfsThread.nodeName) + 1 ); ! 251: *parentID = threadData.hfsThread.parentID; ! 252: } ! 253: ! 254: return( noErr ); ! 255: } ! 256: ! 257: #endif /* TARGET_OS_MAC */ ! 258: ! 259: ! 260: //������������������������������������������������������������������������������� ! 261: // Routine: GetFileThreadID from Asm : FIDGetID ! 262: // ! 263: // Function: GetFileThreadID returns a file thread to a file if it exists. ! 264: // ! 265: // Input: ExtendedVCB* - VCB pointer ! 266: // HFSCatalogNodeID - DirID ! 267: // CatalogName - CName pointer ! 268: // ! 269: // Output: OSErr - result code ! 270: // 0 = ok ! 271: // CMnotfound = CNode not found ! 272: // cmFThdGone = File thread not found ! 273: // cmFThdDirErr = file is a directory, not a file ! 274: // -n = IO Error ! 275: // UInt32 - file thread ID ! 276: //������������������������������������������������������������������������������� ! 277: ! 278: #if TARGET_OS_MAC ! 279: ! 280: OSErr GetFileThreadID( ExtendedVCB *vcb, HFSCatalogNodeID id, const CatalogName *name, Boolean isHFSPlus, UInt32 *threadID ) ! 281: { ! 282: OSErr err; ! 283: CatalogKey key; ! 284: CatalogRecord data; ! 285: UInt32 hint; ! 286: ! 287: ! 288: *threadID = 0; ! 289: ! 290: //-- Locate the file thread ! 291: ! 292: err = LocateCatalogNode( vcb, id, name, kNoHint, &key, &data, &hint ); ! 293: ReturnIfError( err ); ! 294: ! 295: if ( isHFSPlus ) ! 296: { ! 297: if ( data.recordType != kHFSPlusFileRecord ) ! 298: return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory" ! 299: ! 300: *threadID = data.hfsPlusFile.fileID; ! 301: } ! 302: else ! 303: { ! 304: if ( data.recordType != kHFSFileRecord ) ! 305: return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory" ! 306: ! 307: if ( (data.hfsFile.flags & kHFSThreadExistsMask) != 0 ) ! 308: *threadID = data.hfsFile.fileID; ! 309: else ! 310: err = cmFThdGone; ! 311: } ! 312: ! 313: return( err ); ! 314: } ! 315: #endif /* TARGET_OS_MAC */ ! 316: ! 317: ! 318: ! 319: #if TARGET_OS_MAC ! 320: OSErr CreateFileThreadID( FIDParam *filePB, WDCBRecPtr *wdcbPtr ) ! 321: { ! 322: OSErr err; ! 323: Boolean isHFSPlus; ! 324: UInt32 fileHint; ! 325: UInt32 threadHint; ! 326: Str31 name; ! 327: FindFileNameGlueRec fileInfo; ! 328: HFSCatalogKey threadKey; ! 329: HFSCatalogThread threadData; ! 330: CatalogKey fileKey; ! 331: CatalogRecord fileData; ! 332: ! 333: ! 334: err = FindFileName( (ParamBlockRec *) filePB, &fileInfo ); ! 335: *wdcbPtr = fileInfo.wdcb; // return the WDCB pointer to the glue so it can set up A3. ! 336: if (err != noErr) goto ErrorExit; ! 337: ! 338: isHFSPlus = ( fileInfo.vcb->vcbSigWord == kHFSPlusSigWord ); ! 339: ! 340: // ! 341: // Make sure we just found a file record. ! 342: // ! 343: if (fileInfo.data->nodeType != kCatalogFileNode) { ! 344: err = notAFileErr; ! 345: goto ErrorExit; ! 346: } ! 347: ! 348: // ! 349: // Figure out which FileID this is, and return it. ! 350: // ! 351: filePB->ioFileID = fileInfo.data->nodeID; ! 352: ! 353: // ! 354: // If the volume is HFS, see if we need to create the thread record. For HFS Plus, there ! 355: // is always a thread record. ! 356: // ! 357: ! 358: if (isHFSPlus || fileInfo.data->nodeFlags & kFileThreadExistsMask) { ! 359: err = fidExists; ! 360: goto ErrorExit; ! 361: } ! 362: ! 363: err = VolumeWritable( fileInfo.vcb ); ! 364: if ( err != noErr ) ! 365: goto ErrorExit; ! 366: ! 367: ! 368: // ! 369: // If we get here, we need to create a thread record on an HFS volume. ! 370: // Start by building finding the original catalog record, so we can get ! 371: // its key with correct capitalization, etc. ! 372: // ! 373: //�� Is there any way to get the actual key back from FindFileName? ! 374: // ! 375: name[0] = fileInfo.nameLength; ! 376: BlockMoveData(fileInfo.nameBuffer, &name[1], fileInfo.nameLength); ! 377: err = LocateCatalogNode( fileInfo.vcb, fileInfo.id, (CatalogName *) &name, fileInfo.hint, &fileKey, &fileData, &fileHint ); ! 378: if (err != noErr) goto ErrorExit; ! 379: ! 380: // ! 381: // Build the key and data for the thread record. ! 382: // ! 383: ! 384: BuildCatalogKey( filePB->ioFileID, NULL, false, (CatalogKey *) &threadKey ); ! 385: ! 386: ClearMemory( (Ptr)&threadData, sizeof(HFSCatalogThread) ); ! 387: threadData.recordType = kHFSFileThreadRecord; ! 388: threadData.parentID = fileKey.hfs.parentID; ! 389: BlockMoveData(&fileKey.hfs.nodeName[0], &threadData.nodeName[0], fileKey.hfs.nodeName[0]+1); ! 390: ! 391: // ! 392: // Insert the thread record ! 393: // ! 394: err = InsertBTreeRecord( fileInfo.vcb->catalogRefNum, &threadKey, &threadData, sizeof(HFSCatalogThread), &threadHint ); ! 395: if (err != noErr) ! 396: { ! 397: if ( err == btExists ) err = fidExists; // Remap btExists to fidExists ! 398: goto ErrorExit; ! 399: } ! 400: ! 401: // ! 402: // Finally, set the flag in the file record to say this file has a thread record. ! 403: // ! 404: fileData.hfsFile.flags |= kFileThreadExistsMask; ! 405: err = ReplaceBTreeRecord( fileInfo.vcb->catalogRefNum, &fileKey, fileHint, &fileData, sizeof(HFSCatalogFile), &fileHint ); ! 406: if (err != noErr) goto ErrorExit; ! 407: ! 408: FlushCatalog( fileInfo.vcb ); ! 409: ! 410: ErrorExit: ! 411: ! 412: return err; ! 413: } ! 414: #endif /* TARGET_OS_MAC */ ! 415: ! 416: ! 417: //������������������������������������������������������������������������������� ! 418: // Routine: DeleteFileID from Asm : FIDDeleteID ! 419: // ! 420: // Function: DeleteFileID invalidates a file id, by removing the thread from the ! 421: // from the cat file and by turning off the file CNode link flag. ! 422: // ! 423: // Output: OSErr err ! 424: //������������������������������������������������������������������������������� ! 425: // ! 426: // We don't know why anyone would use this routine, so in HFS Plus we want to obsolete it ! 427: // ! 428: //������������������������������������������������������������������������������� ! 429: ! 430: #if( 0 ) ! 431: OSErr DeleteFileID( ExtendedVCB *vcb, HFSCatalogNodeID fileID ) ! 432: { ! 433: OSErr err; ! 434: OSErr btError; ! 435: Boolean isHFSPlus; ! 436: CatalogRecord *threadData; ! 437: CatalogKey key; ! 438: CatalogRecord record; ! 439: UInt32 threadHint; ! 440: UInt16 threadSize; ! 441: CatalogKey key; ! 442: ! 443: ! 444: //-- Locate the file thread ! 445: ! 446: threadHint = kNoHint; ! 447: ! 448: err = LocateCatalogThread( vcb, fileID, &threadData, &threadSize, &threadHint ); ! 449: ! 450: if ( err != noErr ) ! 451: { // translate the error so callee knows it wasn't a fnfErr ! 452: if ( err != cmNotFound ) ! 453: err = cmFThdGone; ! 454: return( err ); ! 455: } ! 456: ! 457: if ( (threadData->recordType != kHFSFileThreadRecord) && (threadData->recordType != kHFSPlussFileThreadRecord) ) ! 458: return( cmFThdDirErr ); ! 459: ! 460: //-- Find the file ! 461: ! 462: isHFSPlus = ( vcb->vcbSigWord == kHFSPlusSigWord ); ! 463: ! 464: if ( isHFSPlus ) ! 465: { ! 466: err = LocateCatalogNode( vcb, threadData->hfsPlusThread.parentID, (const CatalogName *) &(threadData->hfsPlusThread.nodeName), kNoHint, &key, &record, &threadHint ); ! 467: ! 468: if ( err == noErr ) ! 469: { // Turn off thread flag in file CNode ! 470: record.hfsPlusFile.flags &= ~kFileThreadExistsMask; // clear the fThreadFlag bit ! 471: err = ReplaceBTreeRecord( vcb->catalogRefNum, &key, threadHint, &record, sizeof(CatalogThreadRecord), &threadHint); // tell the B-Tree ! 472: ReturnIfError( err ); ! 473: } ! 474: } ! 475: else ! 476: { ! 477: err = LocateCatalogNode( vcb, threadData->hfsThread.parentID, (const CatalogName *) &(threadData->hfsThread.nodeName), kNoHint, &key, &record, &threadHint ); ! 478: ! 479: if ( err == noErr ) ! 480: { // Turn off thread flag in file CNode ! 481: record.hfsFile.flags &= ~kFileThreadExistsMask; // clear the fThreadFlag bit ! 482: err = ReplaceBTreeRecord( vcb->catalogRefNum, &key, threadHint, &record, sizeof(CatThdRec), &threadHint); // tell the B-Tree ! 483: ReturnIfError( err ); ! 484: } ! 485: } ! 486: ! 487: //-- Delete the file thread in the catalog btree ! 488: ! 489: BuildCatalogKey( fileID, nil, isHFSPlus, &key ); ! 490: ! 491: btError = DeleteBTreeRecord( vcb->catalogRefNum, &key ); ! 492: ReturnIfError( btError ); // we know it exists, so must be IOError... ! 493: // ...Oh well, leave the cnode's fthread flag off. ! 494: //-- Get it out to disk. ! 495: (void) FlushCatalog( vcb ); ! 496: ! 497: return( err ); ! 498: } ! 499: ! 500: ! 501: ! 502: #if TARGET_OS_MAC ! 503: OSErr ExchangeFiles( FIDParam *filePB, WDCBRecPtr *wdcbPtr ) ! 504: { ! 505: FindFileNameGlueRec srcFileInfo; ! 506: FindFileNameGlueRec destFileInfo; ! 507: OSErr err; ! 508: ExtendedVCB *vcb; ! 509: CatalogName srcName; ! 510: CatalogName destName; ! 511: Str31 pSrcName; ! 512: Str31 pDestName; ! 513: CatalogKey srcKey; ! 514: CatalogRecord srcData; ! 515: CatalogKey destKey; ! 516: CatalogRecord destData; ! 517: HFSCatalogNodeID srcFileID; ! 518: HFSCatalogNodeID destFileID; ! 519: UInt32 srcHint; ! 520: UInt32 destHint; ! 521: UInt32 srcDirID; ! 522: StringPtr srcNamePtr; ! 523: Boolean isHFSPlus; ! 524: Ptr fcbs; ! 525: UInt16 fcbIndex; ! 526: FCB *fcb; ! 527: ! 528: err = FindFileName( (ParamBlockRec *) filePB, &srcFileInfo ); ! 529: *wdcbPtr = srcFileInfo.wdcb; // return the WDCB pointer to the glue so it can set up A3. ! 530: ReturnIfError( err ); ! 531: ! 532: srcNamePtr = filePB->ioNamePtr; ! 533: srcDirID = filePB->ioSrcDirID; ! 534: ! 535: filePB->ioNamePtr = filePB->ioDestNamePtr; ! 536: filePB->ioSrcDirID = filePB->ioDestDirID; ! 537: ! 538: err = FindFileName( (ParamBlockRec *) filePB, &destFileInfo ); ! 539: ! 540: filePB->ioNamePtr = srcNamePtr; ! 541: filePB->ioSrcDirID = srcDirID; ! 542: ! 543: ReturnIfError( err ); ! 544: ! 545: if ( srcFileInfo.vcb != destFileInfo.vcb ) ! 546: return( diffVolErr ); ! 547: ! 548: //-- since the vcb's are the same, let's use a local variable ! 549: vcb = srcFileInfo.vcb; ! 550: ! 551: err = VolumeWritable( vcb ); ! 552: ReturnIfError( err ); ! 553: ! 554: err = CheckVolumeOffLine( vcb ); ! 555: ReturnIfError( err ); ! 556: ! 557: isHFSPlus = ( vcb->vcbSigWord == kHFSPlusSigWord ); ! 558: ! 559: //-- if it's not an HFS Plus volume, make sure it's an HFS volume ! 560: if ( (! isHFSPlus) && (vcb->vcbSigWord != kHFSSigWord) ) ! 561: return( wrgVolTypErr ); ! 562: ! 563: //-- Set up the names into pascal strings ! 564: pDestName[0] = destFileInfo.nameLength; ! 565: BlockMoveData( destFileInfo.nameBuffer, &(pDestName[1]), pDestName[0] ); ! 566: ! 567: pSrcName[0] = srcFileInfo.nameLength; ! 568: BlockMoveData( srcFileInfo.nameBuffer, &(pSrcName[1]), pSrcName[0] ); ! 569: ! 570: //-- Now prepare the pascal names for input ! 571: err = PrepareInputName( pSrcName, isHFSPlus, GetTextEncodingFromHint(srcFileInfo.hint), &srcName ); ! 572: if ( err != noErr ) goto ParseError; ! 573: ! 574: err = PrepareInputName( pDestName, isHFSPlus, GetTextEncodingFromHint(destFileInfo.hint), &destName ); ! 575: if ( err != noErr ) goto ParseError; ! 576: ! 577: //-- locate the source file ! 578: err = LocateCatalogNode( vcb, srcFileInfo.id, &srcName, srcFileInfo.hint, &srcKey, &srcData, &srcHint ); ! 579: if ( err != noErr ) goto ParseError; ! 580: ! 581: //-- locate the dest file ! 582: err = LocateCatalogNode( vcb, destFileInfo.id, &destName, destFileInfo.hint, &destKey, &destData, &destHint ); ! 583: if ( err != noErr ) goto ParseError; ! 584: ! 585: //-- Are we trying to exchange the file with itself? ! 586: if ( isHFSPlus ) ! 587: { ! 588: srcFileID = srcData.hfsPlusFile.fileID; ! 589: destFileID = destData.hfsPlusFile.fileID; ! 590: } ! 591: else ! 592: { ! 593: srcFileID = srcData.hfsFile.fileID; ! 594: destFileID = destData.hfsFile.fileID; ! 595: } ! 596: ! 597: if ( srcFileID == destFileID ) ! 598: return( sameFileErr ); ! 599: ! 600: ! 601: // Flush any open paths with the files in question! (release cache buffers) <KSCT> ! 602: ! 603: // Note: The cache takes fcb refnum as an argument for flushing. The only way to get ! 604: // this value is to walk the fcb array and find matches of the file number. If a match ! 605: // is found, that fcb refnum can be used for flushing. BUT, the fcb walk continues, since ! 606: // there can be more than one open path per file. ! 607: ! 608: // FINE TUNING: Flag if either file is open. THEN after FidExchangeFiles, if none, skip fcb walking. ! 609: ! 610: Get1stFileControlBlock( &fcbIndex, &fcbs ); ! 611: do ! 612: { ! 613: fcb = GetFileControlBlock( fcbIndex ); ! 614: if ( fcb->fcbVPtr == (ExtendedVCB *) vcb ) // make sure we're on the right volume ! 615: { ! 616: if ( (fcb->fcbFlNm == srcFileID) || (fcb->fcbFlNm == destFileID) ) ! 617: { ! 618: //-- Flush and continue ! 619: LMSetFlushOnly( 0xFF ); ! 620: err = CloseFile( vcb, fcbIndex, fcbs ); ! 621: ReturnIfError( err ); ! 622: ! 623: LMSetCacheFlag( 0xFF ); ! 624: ! 625: (void) C_FlushCache( vcb, fcTrashBit, fcbIndex ); ! 626: } ! 627: } ! 628: } while ( GetNextFileControlBlock( &fcbIndex, fcbs ) == false ); // while there's still some left ! 629: ! 630: // valid buffer in the free queue has a file number tag to it in the header, however, ! 631: // after FIDExchangeFiles the file number is no longer valid. So we have to call TrashFBlocks ! 632: // to invalidate all the buffer associated with the files. <16Apr91 #12 ksct> ! 633: ! 634: TrashCatalogIterator( vcb, srcFileInfo.id ); // invalidate any iterators for this parentID ! 635: InvalidateCatalogNodeCache( vcb, srcFileInfo.id ); // invalidate node cache ! 636: if ( srcFileInfo.id != destFileInfo.id ) ! 637: { ! 638: TrashCatalogIterator( vcb, destFileInfo.id ); // invalidate any iterators for this parentID ! 639: InvalidateCatalogNodeCache( vcb, destFileInfo.id ); // invalidate node cache ! 640: } ! 641: TrashFileBlocks( vcb, destFileID ); ! 642: TrashFileBlocks( vcb, srcFileID ); ! 643: ! 644: ! 645: //-- Do the stuff! ! 646: err = ExchangeFileIDs( vcb, &srcName, &destName, srcFileInfo.id, destFileInfo.id, srcHint, destHint ); ! 647: if ( DEBUG_BUILD && err != noErr) ! 648: { ! 649: DebugStr("\pError from ExchangeFileIDs"); ! 650: } ! 651: ! 652: //-- Now get the names ready for output ! 653: if ( isHFSPlus ) ! 654: { ! 655: err = ConvertUnicodeToHFSName( &srcName.ustr, srcData.hfsPlusFile.textEncoding, srcData.hfsPlusFile.fileID, pSrcName ); ! 656: if ( err != noErr ) ! 657: goto ParseError; ! 658: ! 659: err = ConvertUnicodeToHFSName( &destName.ustr, destData.hfsPlusFile.textEncoding, srcData.hfsPlusFile.fileID, pDestName ); ! 660: } ! 661: else ! 662: { ! 663: BlockMoveData( srcName.pstr, pSrcName, StrLength(srcName.pstr) + 1 ); ! 664: BlockMoveData( destName.pstr, pDestName, StrLength(srcName.pstr) + 1 ); ! 665: } ! 666: ! 667: if ( err != noErr ) ! 668: goto ParseError; ! 669: ! 670: //-- Exchange fcb info (file number, file name, and file parID only!) ! 671: Get1stFileControlBlock( &fcbIndex, &fcbs ); ! 672: do ! 673: { ! 674: fcb = GetFileControlBlock( fcbIndex ); ! 675: if ( fcb->fcbVPtr == vcb ) ! 676: { ! 677: if ( fcb->fcbFlNm == srcFileID ) ! 678: { ! 679: fcb->fcbCatPos = 0; ! 680: fcb->fcbFlNm = destFileID; ! 681: fcb->fcbDirID = destFileInfo.id; ! 682: ! 683: BlockMoveData( pDestName, fcb->fcbCName, pDestName[0]+1 ); ! 684: } ! 685: else if ( fcb->fcbFlNm == destFileID ) ! 686: { ! 687: fcb->fcbCatPos = 0; ! 688: fcb->fcbFlNm = srcFileID; ! 689: fcb->fcbDirID = srcFileInfo.id; ! 690: ! 691: BlockMoveData( pSrcName, fcb->fcbCName, pSrcName[0]+1 ); ! 692: } ! 693: } ! 694: } while ( GetNextFileControlBlock( &fcbIndex, fcbs ) == false ); // while there's still some left ! 695: ! 696: return( err ); ! 697: ! 698: ParseError: ! 699: if ( err == cmNotFound ) return( fnfErr ); ! 700: else if ( err == cmFThdDirErr ) return( notAFileErr ); ! 701: else return( err ); ! 702: } ! 703: #endif /* TARGET_OS_MAC */ ! 704: #endif ! 705: ! 706: ! 707: OSErr ExchangeFileIDs( ExtendedVCB *vcb, ConstUTF8Param srcName, ConstUTF8Param destName, HFSCatalogNodeID srcID, HFSCatalogNodeID destID, UInt32 srcHint, UInt32 destHint ) ! 708: { ! 709: CatalogKey srcKey; // 518 bytes ! 710: CatalogRecord srcData; // 520 bytes ! 711: CatalogKey destKey; // 518 bytes ! 712: CatalogRecord destData; // 520 bytes ! 713: CatalogRecord swapData; // 520 bytes ! 714: SInt16 numSrcExtentBlocks; ! 715: SInt16 numDestExtentBlocks; ! 716: UInt32 textEncoding; ! 717: OSErr err; ! 718: Boolean isHFSPlus = ( vcb->vcbSigWord == kHFSPlusSigWord ); ! 719: ! 720: TrashCatalogIterator(vcb, srcID); // invalidate any iterators for this parentID ! 721: TrashCatalogIterator(vcb, destID); // invalidate any iterators for this parentID ! 722: ! 723: err = BuildCatalogKeyUTF8(srcID, srcName, isHFSPlus, &srcKey, &textEncoding); ! 724: ReturnIfError(err); ! 725: ! 726: err = BuildCatalogKeyUTF8(destID, destName, isHFSPlus, &destKey, &textEncoding); ! 727: ReturnIfError(err); ! 728: ! 729: if ( isHFSPlus ) ! 730: { ! 731: //-- Step 1: Check the catalog nodes for extents ! 732: ! 733: //-- locate the source file, test for extents in extent file, and copy the cat record for later ! 734: err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint ); ! 735: ReturnIfError( err ); ! 736: ! 737: if ( srcData.recordType != kHFSPlusFileRecord ) ! 738: return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory" ! 739: ! 740: //-- Check if there are any extents in the source file ! 741: //�� I am only checling the extents in the low 32 bits, routine will fail if files extents after 2 gig are in overflow ! 742: numSrcExtentBlocks = CheckExtents( srcData.hfsPlusFile.dataFork.extents, srcData.hfsPlusFile.dataFork.totalBlocks, isHFSPlus ); ! 743: if ( numSrcExtentBlocks == 0 ) // then check the resource fork extents ! 744: numSrcExtentBlocks = CheckExtents( srcData.hfsPlusFile.resourceFork.extents, srcData.hfsPlusFile.resourceFork.totalBlocks, isHFSPlus ); ! 745: ! 746: //-- Check if there are any extents in the destination file ! 747: err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint ); ! 748: ReturnIfError( err ); ! 749: ! 750: if ( destData.recordType != kHFSPlusFileRecord ) ! 751: return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory" ! 752: ! 753: numDestExtentBlocks = CheckExtents( destData.hfsPlusFile.dataFork.extents, destData.hfsPlusFile.dataFork.totalBlocks, isHFSPlus ); ! 754: if ( numDestExtentBlocks == 0 ) // then check the resource fork extents ! 755: numDestExtentBlocks = CheckExtents( destData.hfsPlusFile.resourceFork.extents, destData.hfsPlusFile.resourceFork.totalBlocks, isHFSPlus ); ! 756: ! 757: //-- Step 2: Exchange the Extent key in the extent file ! 758: ! 759: //-- Exchange the extents key in the extent file ! 760: err = DeleteExtents( vcb, kHFSBogusExtentFileID, isHFSPlus ); ! 761: ReturnIfError( err ); ! 762: ! 763: if ( numSrcExtentBlocks && numDestExtentBlocks ) // if both files have extents ! 764: { ! 765: //-- Change the source extents file ids to our known bogus value ! 766: err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, kHFSBogusExtentFileID, isHFSPlus ); ! 767: if ( err != noErr ) ! 768: { ! 769: if ( err != dskFulErr ) ! 770: return( err ); ! 771: else ! 772: goto ExUndo1a; ! 773: } ! 774: ! 775: //-- Change the destination extents file id's to the source id's ! 776: err = MoveExtents( vcb, destData.hfsPlusFile.fileID, srcData.hfsPlusFile.fileID, isHFSPlus ); ! 777: if ( err != noErr ) ! 778: { ! 779: if ( err != dskFulErr ) ! 780: return( err ); ! 781: ! 782: ExUndo2aPlus: err = DeleteExtents( vcb, srcData.hfsPlusFile.fileID, isHFSPlus ); ! 783: ReturnIfError( err ); // we are doomed. Just QUIT! ! 784: ! 785: err = MoveExtents( vcb, kHFSBogusExtentFileID, srcData.hfsPlusFile.fileID, isHFSPlus ); // Move the extents back ! 786: ReturnIfError( err ); // we are doomed. Just QUIT! ! 787: ! 788: goto ExUndo1a; ! 789: } ! 790: ! 791: //-- Change the bogus extents file id's to the dest id's ! 792: err = MoveExtents( vcb, kHFSBogusExtentFileID, destData.hfsPlusFile.fileID, isHFSPlus ); ! 793: if ( err != noErr ) ! 794: { ! 795: if ( err != dskFulErr ) ! 796: return( err ); ! 797: ! 798: err = DeleteExtents( vcb, destData.hfsPlusFile.fileID, isHFSPlus ); ! 799: ReturnIfError( err ); // we are doomed. Just QUIT! ! 800: ! 801: err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, destData.hfsPlusFile.fileID, isHFSPlus ); // Move the extents back ! 802: ReturnIfError( err ); // we are doomed. Just QUIT! ! 803: ! 804: goto ExUndo2aPlus; ! 805: } ! 806: ! 807: } ! 808: else if ( numSrcExtentBlocks ) // just the source file has extents ! 809: { ! 810: err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, destData.hfsPlusFile.fileID, isHFSPlus ); ! 811: if ( err != noErr ) ! 812: { ! 813: if ( err != dskFulErr ) ! 814: return( err ); ! 815: ! 816: err = DeleteExtents( vcb, srcData.hfsPlusFile.fileID, isHFSPlus ); ! 817: ReturnIfError( err ); // we are doomed. Just QUIT! ! 818: ! 819: goto FlushAndReturn; ! 820: } ! 821: } ! 822: else if ( numDestExtentBlocks ) // just the destination file has extents ! 823: { ! 824: err = MoveExtents( vcb, destData.hfsPlusFile.fileID, srcData.hfsPlusFile.fileID, isHFSPlus ); ! 825: if ( err != noErr ) ! 826: { ! 827: if ( err != dskFulErr ) ! 828: return( err ); ! 829: ! 830: err = DeleteExtents( vcb, destData.hfsPlusFile.fileID, isHFSPlus ); ! 831: ReturnIfError( err ); // we are doomed. Just QUIT! ! 832: ! 833: goto FlushAndReturn; ! 834: } ! 835: } ! 836: ! 837: //-- Step 3: Change the data in the catalog nodes ! 838: ! 839: //-- find the source cnode and put dest info in it ! 840: err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint ); ! 841: if ( err != noErr ) ! 842: return( cmBadNews ); ! 843: ! 844: BlockMoveData( &srcData, &swapData, sizeof(CatalogRecord) ); ! 845: CopyBigCatalogNodeInfo( &destData, &srcData ); ! 846: ! 847: err = ReplaceBTreeRecord( vcb->catalogRefNum, &srcKey, srcHint, &srcData, sizeof(HFSPlusCatalogFile), &srcHint ); ! 848: ReturnIfError( err ); ! 849: ! 850: // find the destination cnode and put source info in it ! 851: err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint ); ! 852: if ( err != noErr ) ! 853: return( cmBadNews ); ! 854: ! 855: CopyBigCatalogNodeInfo( &swapData, &destData ); ! 856: err = ReplaceBTreeRecord( vcb->catalogRefNum, &destKey, destHint, &destData, sizeof(HFSPlusCatalogFile), &destHint ); ! 857: ReturnIfError( err ); ! 858: } ! 859: else // HFS // ! 860: { ! 861: //-- Step 1: Check the catalog nodes for extents ! 862: ! 863: //-- locate the source file, test for extents in extent file, and copy the cat record for later ! 864: err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint ); ! 865: ReturnIfError( err ); ! 866: ! 867: if ( srcData.recordType != kHFSFileRecord ) ! 868: return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory" ! 869: ! 870: //-- Check if there are any extents in the source file ! 871: numSrcExtentBlocks = CheckExtents( srcData.hfsFile.dataExtents, srcData.hfsFile.dataPhysicalSize / vcb->blockSize, isHFSPlus ); ! 872: if ( numSrcExtentBlocks == 0 ) // then check the resource fork extents ! 873: numSrcExtentBlocks = CheckExtents( srcData.hfsFile.rsrcExtents, srcData.hfsFile.rsrcPhysicalSize / vcb->blockSize, isHFSPlus ); ! 874: ! 875: ! 876: //�� Do we save the found source node for later use? ! 877: ! 878: ! 879: //-- Check if there are any extents in the destination file ! 880: err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint ); ! 881: ReturnIfError( err ); ! 882: ! 883: if ( destData.recordType != kHFSFileRecord ) ! 884: return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory" ! 885: ! 886: numDestExtentBlocks = CheckExtents( destData.hfsFile.dataExtents, destData.hfsFile.dataPhysicalSize / vcb->blockSize, isHFSPlus ); ! 887: if ( numDestExtentBlocks == 0 ) // then check the resource fork extents ! 888: numDestExtentBlocks = CheckExtents( destData.hfsFile.rsrcExtents, destData.hfsFile.rsrcPhysicalSize / vcb->blockSize, isHFSPlus ); ! 889: ! 890: //�� Do we save the found destination node for later use? ! 891: ! 892: ! 893: //-- Step 2: Exchange the Extent key in the extent file ! 894: ! 895: //-- Exchange the extents key in the extent file ! 896: err = DeleteExtents( vcb, kHFSBogusExtentFileID, isHFSPlus ); ! 897: ReturnIfError( err ); ! 898: ! 899: if ( numSrcExtentBlocks && numDestExtentBlocks ) // if both files have extents ! 900: { ! 901: //-- Change the source extents file ids to our known bogus value ! 902: err = MoveExtents( vcb, srcData.hfsFile.fileID, kHFSBogusExtentFileID, isHFSPlus ); ! 903: if ( err != noErr ) ! 904: { ! 905: if ( err != dskFulErr ) ! 906: return( err ); ! 907: ! 908: ExUndo1a: err = DeleteExtents( vcb, kHFSBogusExtentFileID, isHFSPlus ); ! 909: ReturnIfError( err ); // we are doomed. Just QUIT! ! 910: ! 911: err = FlushCatalog( vcb ); // flush the catalog ! 912: err = FlushExtentFile( vcb ); // flush the extent file (unneeded for common case, but it's cheap) ! 913: return( dskFulErr ); ! 914: } ! 915: ! 916: //-- Change the destination extents file id's to the source id's ! 917: err = MoveExtents( vcb, destData.hfsFile.fileID, srcData.hfsFile.fileID, isHFSPlus ); ! 918: if ( err != noErr ) ! 919: { ! 920: if ( err != dskFulErr ) ! 921: return( err ); ! 922: ! 923: ExUndo2a: err = DeleteExtents( vcb, srcData.hfsFile.fileID, isHFSPlus ); ! 924: ReturnIfError( err ); // we are doomed. Just QUIT! ! 925: ! 926: err = MoveExtents( vcb, kHFSBogusExtentFileID, srcData.hfsFile.fileID, isHFSPlus ); // Move the extents back ! 927: ReturnIfError( err ); // we are doomed. Just QUIT! ! 928: ! 929: goto ExUndo1a; ! 930: } ! 931: ! 932: //-- Change the bogus extents file id's to the dest id's ! 933: err = MoveExtents( vcb, kHFSBogusExtentFileID, destData.hfsFile.fileID, isHFSPlus ); ! 934: if ( err != noErr ) ! 935: { ! 936: if ( err != dskFulErr ) ! 937: return( err ); ! 938: ! 939: err = DeleteExtents( vcb, destData.hfsFile.fileID, isHFSPlus ); ! 940: ReturnIfError( err ); // we are doomed. Just QUIT! ! 941: ! 942: err = MoveExtents( vcb, srcData.hfsFile.fileID, destData.hfsFile.fileID, isHFSPlus ); // Move the extents back ! 943: ReturnIfError( err ); // we are doomed. Just QUIT! ! 944: ! 945: goto ExUndo2a; ! 946: } ! 947: ! 948: } ! 949: else if ( numSrcExtentBlocks ) // just the source file has extents ! 950: { ! 951: err = MoveExtents( vcb, srcData.hfsFile.fileID, destData.hfsFile.fileID, isHFSPlus ); ! 952: if ( err != noErr ) ! 953: { ! 954: if ( err != dskFulErr ) ! 955: return( err ); ! 956: ! 957: err = DeleteExtents( vcb, srcData.hfsFile.fileID, isHFSPlus ); ! 958: ReturnIfError( err ); // we are doomed. Just QUIT! ! 959: ! 960: goto FlushAndReturn; ! 961: } ! 962: } ! 963: else if ( numDestExtentBlocks ) // just the destination file has extents ! 964: { ! 965: err = MoveExtents( vcb, destData.hfsFile.fileID, srcData.hfsFile.fileID, isHFSPlus ); ! 966: if ( err != noErr ) ! 967: { ! 968: if ( err != dskFulErr ) ! 969: return( err ); ! 970: ! 971: err = DeleteExtents( vcb, destData.hfsFile.fileID, isHFSPlus ); ! 972: ReturnIfError( err ); // we are doomed. Just QUIT! ! 973: ! 974: goto FlushAndReturn; ! 975: } ! 976: } ! 977: ! 978: //-- Step 3: Change the data in the catalog nodes ! 979: ! 980: //-- find the source cnode and put dest info in it ! 981: err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint ); ! 982: if ( err != noErr ) ! 983: return( cmBadNews ); ! 984: ! 985: BlockMoveData( &srcData, &swapData, sizeof(CatalogRecord) ); ! 986: //�� Asm source copies from the saved dest catalog node ! 987: CopyCatalogNodeInfo( &destData, &srcData ); ! 988: ! 989: err = ReplaceBTreeRecord( vcb->catalogRefNum, &srcKey, srcHint, &srcData, sizeof(HFSCatalogFile), &srcHint ); ! 990: ReturnIfError( err ); ! 991: ! 992: ! 993: // find the destination cnode and put source info in it ! 994: err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint ); ! 995: if ( err != noErr ) ! 996: return( cmBadNews ); ! 997: ! 998: CopyCatalogNodeInfo( &swapData, &destData ); ! 999: err = ReplaceBTreeRecord( vcb->catalogRefNum, &destKey, destHint, &destData, sizeof(HFSCatalogFile), &destHint ); ! 1000: ReturnIfError( err ); ! 1001: } ! 1002: ! 1003: err = noErr; ! 1004: ! 1005: //-- Step 4: Error Handling section ! 1006: ! 1007: ! 1008: FlushAndReturn: ! 1009: err = FlushCatalog( vcb ); // flush the catalog ! 1010: err = FlushExtentFile( vcb ); // flush the extent file (unneeded for common case, but it's cheap) ! 1011: return( err ); ! 1012: } ! 1013: ! 1014: ! 1015: void CopyCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest ) ! 1016: { ! 1017: // dest->hfsFile.filStBlk = src->hfsFile.filStBlk; ! 1018: dest->hfsFile.dataLogicalSize = src->hfsFile.dataLogicalSize; ! 1019: dest->hfsFile.dataPhysicalSize = src->hfsFile.dataPhysicalSize; ! 1020: // dest->hfsFile.filRStBlk = src->hfsFile.filRStBlk; ! 1021: dest->hfsFile.rsrcLogicalSize = src->hfsFile.rsrcLogicalSize; ! 1022: dest->hfsFile.rsrcPhysicalSize = src->hfsFile.rsrcPhysicalSize; ! 1023: dest->hfsFile.modifyDate = src->hfsFile.modifyDate; ! 1024: BlockMoveData( src->hfsFile.dataExtents, dest->hfsFile.dataExtents, sizeof(HFSExtentRecord) ); ! 1025: BlockMoveData( src->hfsFile.rsrcExtents, dest->hfsFile.rsrcExtents, sizeof(HFSExtentRecord) ); ! 1026: } ! 1027: ! 1028: void CopyBigCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest ) ! 1029: { ! 1030: BlockMoveData( &src->hfsPlusFile.dataFork, &dest->hfsPlusFile.dataFork, sizeof(HFSPlusForkData) ); ! 1031: BlockMoveData( &src->hfsPlusFile.resourceFork, &dest->hfsPlusFile.resourceFork, sizeof(HFSPlusForkData) ); ! 1032: dest->hfsPlusFile.contentModDate = src->hfsPlusFile.contentModDate; ! 1033: } ! 1034: ! 1035: ! 1036: OSErr MoveExtents( ExtendedVCB *vcb, UInt32 srcFileID, UInt32 destFileID, Boolean isHFSPlus ) ! 1037: { ! 1038: FCB * fcb; ! 1039: ExtentsRecBuffer extentsBuffer[kNumExtentsToCache]; ! 1040: ExtentKey * extentKeyPtr; ! 1041: ExtentRecord extentData; ! 1042: BTreeIterator btIterator; ! 1043: FSBufferDescriptor btRecord; ! 1044: UInt16 btKeySize; ! 1045: UInt16 btRecordSize; ! 1046: SInt16 i, j; ! 1047: OSErr err; ! 1048: ! 1049: ! 1050: fcb = GetFileControlBlock(vcb->extentsRefNum); ! 1051: ! 1052: (void) BTInvalidateHint(&btIterator); ! 1053: extentKeyPtr = (ExtentKey*) &btIterator.key; ! 1054: btRecord.bufferAddress = &extentData; ! 1055: btRecord.itemCount = 1; ! 1056: ! 1057: //-- Collect the extent records ! 1058: ! 1059: // ! 1060: // A search on the following key will cause the BTree to be positioned immediately ! 1061: // before the first extent record for file #srcFileID, but not actually positioned ! 1062: // on any record. This is because there cannot be an extent record with FABN = 0 ! 1063: // (the first extent of the fork, which would be in the catalog entry, not an extent ! 1064: // record). ! 1065: // ! 1066: // Using BTIterateRecord with kBTreeNextRecord will then get that first extent record. ! 1067: // ! 1068: if (isHFSPlus) { ! 1069: btRecord.itemSize = sizeof(HFSPlusExtentRecord); ! 1070: btKeySize = sizeof(HFSPlusExtentKey); ! 1071: ! 1072: extentKeyPtr->hfsPlus.keyLength = kHFSPlusExtentKeyMaximumLength; ! 1073: extentKeyPtr->hfsPlus.forkType = 0; ! 1074: extentKeyPtr->hfsPlus.pad = 0; ! 1075: extentKeyPtr->hfsPlus.fileID = srcFileID; ! 1076: extentKeyPtr->hfsPlus.startBlock = 0; ! 1077: } ! 1078: else { ! 1079: btRecord.itemSize = sizeof(HFSExtentRecord); ! 1080: btKeySize = sizeof(HFSExtentKey); ! 1081: ! 1082: extentKeyPtr->hfs.keyLength = kHFSExtentKeyMaximumLength; ! 1083: extentKeyPtr->hfs.forkType = 0; ! 1084: extentKeyPtr->hfs.fileID = srcFileID; ! 1085: extentKeyPtr->hfs.startBlock = 0; ! 1086: } ! 1087: ! 1088: // ! 1089: // We do an initial BTSearchRecord to position the BTree's iterator just before any extent ! 1090: // records for srcFileID. We then do a few BTIterateRecord and BTInsertRecord of those found ! 1091: // records, but with destFileID as the file number in the key. Keep doing this sequence of ! 1092: // BTIterateRecord and BTInsertRecord until we find an extent for another file, or there are ! 1093: // no more extent records in the tree. ! 1094: // ! 1095: // Basically, we're copying records kNumExtentsToCache at a time. The copies have their file ID ! 1096: // set to destFileID. ! 1097: // ! 1098: // This depends on BTInsertRecord not effecting the iterator used by BTIterateRecord. If it ! 1099: // _did_ effect the iterator, then we would need to do a BTSearchRecord before each series ! 1100: // of BTIterateRecord. We'd need to set up the key for BTSearchRecord to find the last record ! 1101: // we found, so that BTIterateRecord would get the next one (the first we haven't processed). ! 1102: // ! 1103: ! 1104: err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator); ! 1105: ! 1106: // We expect a btNotFound here, since there shouldn't be an extent record with FABN = 0. ! 1107: if (err != btNotFound) ! 1108: { ! 1109: if ( DEBUG_BUILD ) ! 1110: DebugStr("\pUnexpected error from SearchBTreeRecord"); ! 1111: ! 1112: if (err == noErr) // If we found such a bogus extent record, then the tree is really messed up ! 1113: err = cmBadNews; // so return an error that conveys the disk is hosed. ! 1114: ! 1115: return err; ! 1116: } ! 1117: ! 1118: do ! 1119: { ! 1120: btRecord.bufferAddress = &extentData; ! 1121: btRecord.itemCount = 1; ! 1122: ! 1123: for ( i=0 ; i<kNumExtentsToCache ; i++ ) ! 1124: { ! 1125: HFSCatalogNodeID foundFileID; ! 1126: ! 1127: err = BTIterateRecord(fcb, kBTreeNextRecord, &btIterator, &btRecord, &btRecordSize); ! 1128: if ( err == btNotFound ) // Did we run out of extent records in the extents tree? ! 1129: break; // if xkrFNum(A0) is cleared on this error, then this test is bogus! ! 1130: else if ( err != noErr ) ! 1131: return( err ); // must be ioError ! 1132: ! 1133: foundFileID = isHFSPlus ? extentKeyPtr->hfsPlus.fileID : extentKeyPtr->hfs.fileID; ! 1134: if ( foundFileID == srcFileID ) ! 1135: { ! 1136: CopyExtentInfo(extentKeyPtr, &extentData, extentsBuffer, i); ! 1137: } ! 1138: else ! 1139: { ! 1140: break; ! 1141: } ! 1142: } ! 1143: ! 1144: //-- edit each extent key, and reinsert each extent record in the extent file ! 1145: if (isHFSPlus) ! 1146: btRecordSize = sizeof(HFSPlusExtentRecord); ! 1147: else ! 1148: btRecordSize = sizeof(HFSExtentRecord); ! 1149: ! 1150: for ( j=0 ; j<i ; j++ ) ! 1151: { ! 1152: BTreeIterator tmpIterator; ! 1153: ! 1154: if (isHFSPlus) ! 1155: extentsBuffer[j].extentKey.hfsPlus.fileID = destFileID; // change only the id in the key to dest ID ! 1156: else ! 1157: extentsBuffer[j].extentKey.hfs.fileID = destFileID; // change only the id in the key to dest ID ! 1158: ! 1159: // get iterator and buffer descriptor ready... ! 1160: (void) BTInvalidateHint(&tmpIterator); ! 1161: BlockMoveData(&(extentsBuffer[j].extentKey), &tmpIterator.key, btKeySize); ! 1162: btRecord.bufferAddress = &(extentsBuffer[j].extentData); ! 1163: ! 1164: err = BTInsertRecord(fcb, &tmpIterator, &btRecord, btRecordSize); ! 1165: if ( err != noErr ) ! 1166: { // parse the error ! 1167: if ( err == btExists ) ! 1168: { ! 1169: if ( DEBUG_BUILD ) ! 1170: DebugStr("\pCan't insert record -- already exists"); ! 1171: return( cmBadNews ); ! 1172: } ! 1173: else ! 1174: return( err ); ! 1175: } ! 1176: } ! 1177: ! 1178: //-- okay, done with this buffered batch, go get the next set of extent records ! 1179: // If our buffer is not full, we must be done, or recieved an error ! 1180: ! 1181: if ( i != kNumExtentsToCache ) // if the buffer is not full, we must be done ! 1182: { ! 1183: err = DeleteExtents( vcb, srcFileID, isHFSPlus ); // Now delete all the extent entries with the sourceID ! 1184: if ( DEBUG_BUILD && err != noErr ) ! 1185: DebugStr("\pError from DeleteExtents"); ! 1186: break; // we're done! ! 1187: } ! 1188: } while ( true ); ! 1189: ! 1190: return( err ); ! 1191: } ! 1192: ! 1193: ! 1194: void CopyExtentInfo( ExtentKey *key, ExtentRecord *data, ExtentsRecBuffer *buffer, UInt16 bufferCount ) ! 1195: { ! 1196: BlockMoveData( key, &(buffer[bufferCount].extentKey), sizeof( ExtentKey ) ); ! 1197: BlockMoveData( data, &(buffer[bufferCount].extentData), sizeof( ExtentRecord ) ); ! 1198: } ! 1199: ! 1200: ! 1201: //-- Delete all extents in extent file that have the ID given. ! 1202: OSErr DeleteExtents( ExtendedVCB *vcb, UInt32 fileID, Boolean isHFSPlus ) ! 1203: { ! 1204: FCB * fcb; ! 1205: ExtentKey * extentKeyPtr; ! 1206: ExtentRecord extentData; ! 1207: BTreeIterator btIterator; ! 1208: FSBufferDescriptor btRecord; ! 1209: UInt16 btRecordSize; ! 1210: OSErr err; ! 1211: ! 1212: fcb = GetFileControlBlock(vcb->extentsRefNum); ! 1213: ! 1214: (void) BTInvalidateHint(&btIterator); ! 1215: extentKeyPtr = (ExtentKey*) &btIterator.key; ! 1216: btRecord.bufferAddress = &extentData; ! 1217: btRecord.itemCount = 1; ! 1218: ! 1219: // The algorithm is to position the BTree just before any extent records for fileID. ! 1220: // Then just keep getting successive records. If the record is still for fileID, ! 1221: // then delete it. ! 1222: ! 1223: if (isHFSPlus) { ! 1224: btRecord.itemSize = sizeof(HFSPlusExtentRecord); ! 1225: ! 1226: extentKeyPtr->hfsPlus.keyLength = kHFSPlusExtentKeyMaximumLength; ! 1227: extentKeyPtr->hfsPlus.forkType = 0; ! 1228: extentKeyPtr->hfsPlus.pad = 0; ! 1229: extentKeyPtr->hfsPlus.fileID = fileID; ! 1230: extentKeyPtr->hfsPlus.startBlock = 0; ! 1231: } ! 1232: else { ! 1233: btRecord.itemSize = sizeof(HFSExtentRecord); ! 1234: ! 1235: extentKeyPtr->hfs.keyLength = kHFSExtentKeyMaximumLength; ! 1236: extentKeyPtr->hfs.forkType = 0; ! 1237: extentKeyPtr->hfs.fileID = fileID; ! 1238: extentKeyPtr->hfs.startBlock = 0; ! 1239: } ! 1240: ! 1241: err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator); ! 1242: if ( err != btNotFound ) ! 1243: { ! 1244: if (err == noErr) { // Did we find a bogus extent record? ! 1245: err = cmBadNews; // Yes, so indicate things are messed up. ! 1246: } ! 1247: ! 1248: return err; // Got some unexpected error, so return it ! 1249: } ! 1250: ! 1251: do ! 1252: { ! 1253: BTreeIterator tmpIterator; ! 1254: HFSCatalogNodeID foundFileID; ! 1255: ! 1256: err = BTIterateRecord(fcb, kBTreeNextRecord, &btIterator, &btRecord, &btRecordSize); ! 1257: if ( err != noErr ) ! 1258: { ! 1259: if (err == btNotFound) // If we hit the end of the BTree ! 1260: err = noErr; // then it's OK ! 1261: ! 1262: break; // We're done now. ! 1263: } ! 1264: ! 1265: foundFileID = isHFSPlus ? extentKeyPtr->hfsPlus.fileID : extentKeyPtr->hfs.fileID; ! 1266: if ( foundFileID != fileID ) ! 1267: break; // numbers don't match, we must be done ! 1268: ! 1269: tmpIterator = btIterator; ! 1270: err = BTDeleteRecord( fcb, &tmpIterator ); ! 1271: if (err != noErr) ! 1272: break; ! 1273: } while ( true ); ! 1274: ! 1275: return( err ); ! 1276: } ! 1277: ! 1278: ! 1279: // Check if there are extents represented in the extents overflow file. ! 1280: UInt32 CheckExtents( void *extents, UInt32 totalBlocks, Boolean isHFSPlus ) ! 1281: { ! 1282: UInt32 extentAllocationBlocks; ! 1283: UInt16 i; ! 1284: ! 1285: ! 1286: if ( totalBlocks == 0 ) ! 1287: return( 0 ); ! 1288: ! 1289: extentAllocationBlocks = 0; ! 1290: ! 1291: if ( isHFSPlus ) ! 1292: { ! 1293: for ( i = 0 ; i < kHFSPlusExtentDensity ; i++ ) ! 1294: { ! 1295: extentAllocationBlocks += ((HFSPlusExtentDescriptor *)extents)[i].blockCount; ! 1296: if ( extentAllocationBlocks >= totalBlocks ) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump) ! 1297: return( 0 ); ! 1298: } ! 1299: } ! 1300: else ! 1301: { ! 1302: for ( i = 0 ; i < kHFSExtentDensity ; i++ ) ! 1303: { ! 1304: extentAllocationBlocks += ((HFSExtentDescriptor *)extents)[i].blockCount; ! 1305: if ( extentAllocationBlocks >= totalBlocks ) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump) ! 1306: return( 0 ); ! 1307: } ! 1308: } ! 1309: ! 1310: return( extentAllocationBlocks ); ! 1311: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.