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

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

unix.superglobalmegacorp.com

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