Annotation of kernel/bsd/hfs/hfscommon/Catalog/FileIDsServices.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.