Annotation of XNU/bsd/hfs/hfscommon/Catalog/FileIDsServices.c, revision 1.1.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.