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

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

unix.superglobalmegacorp.com

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