4         Contains:       A robust, general purpose directory copy routine. 
   8         Copyright:      © 1992-2001 by Apple Computer, Inc., all rights reserved. 
  10         You may incorporate this sample code into your applications without 
  11         restriction, though the sample code has been provided "AS IS" and the 
  12         responsibility for its operation is 100% yours.  However, what you are 
  13         not permitted to do is to redistribute the source as "DSC Sample Code" 
  14         after having made changes. If you're going to re-distribute the source, 
  15         we require that you make it clear in the source that the code was 
  16         descended from Apple Sample Code, but that you've made changes. 
  20                 DRI:                            Apple Macintosh Developer Technical Support 
  22                 Other Contact:          Apple Macintosh Developer Technical Support 
  23                                                         <http://developer.apple.com/bugreporter/> 
  25                 Technology:                     DTS Sample Code 
  31         Change History (most recent first): 
  33                  <2>      2/7/01        JL              Added standard header. Updated names of includes. 
  34                 <1>             12/06/99        JL              MoreFiles 1.5. 
  38 #include <MacErrors.h> 
  39 #include <MacMemory.h> 
  44 #define __COMPILINGMOREFILES 
  46 #include "MoreFiles.h" 
  47 #include "MoreFilesExtras.h" 
  48 #include "MoreDesktopMgr.h" 
  50 #include "DirectoryCopy.h" 
  52 /*****************************************************************************/ 
  58         dirCopyBigCopyBuffSize  
= 0x00004000, 
  59         dirCopyMinCopyBuffSize  
= 0x00000200 
  63 /*****************************************************************************/ 
  65 /* local data structures */ 
  67 /* The EnumerateGlobals structure is used to minimize the amount of 
  68 ** stack space used when recursively calling CopyLevel and to hold 
  69 ** global information that might be needed at any time. */ 
  71 #if PRAGMA_STRUCT_ALIGN 
  72 #pragma options align=mac68k 
  74 struct EnumerateGlobals
 
  76         Ptr                     copyBuffer
;                     /* pointer to buffer used for file copy operations */ 
  77         long            bufferSize
;                     /* the size of the copy buffer */ 
  78         CopyErrProcPtr errorHandler
;    /* pointer to error handling function */ 
  79         CopyFilterProcPtr copyFilterProc
; /* pointer to filter function */ 
  80         OSErr           error
;                          /* temporary holder of results - saves 2 bytes of stack each level */ 
  81         Boolean         bailout
;                        /* set to true to by error handling function if fatal error */ 
  82         short           destinationVRefNum
;     /* the destination vRefNum */ 
  83         Str63           itemName
;                       /* the name of the current item */ 
  84         CInfoPBRec      myCPB
;                          /* the parameter block used for PBGetCatInfo calls */ 
  86 #if PRAGMA_STRUCT_ALIGN 
  87 #pragma options align=reset 
  90 typedef struct EnumerateGlobals EnumerateGlobals
; 
  91 typedef EnumerateGlobals 
*EnumerateGlobalsPtr
; 
  94 /* The PreflightGlobals structure is used to minimize the amount of 
  95 ** stack space used when recursively calling GetLevelSize and to hold 
  96 ** global information that might be needed at any time. */ 
  98 #if PRAGMA_STRUCT_ALIGN 
  99 #pragma options align=mac68k 
 101 struct PreflightGlobals
 
 103         OSErr                   result
;                         /* temporary holder of results - saves 2 bytes of stack each level */ 
 104         Str63                   itemName
;                       /* the name of the current item */ 
 105         CInfoPBRec              myCPB
;                          /* the parameter block used for PBGetCatInfo calls */ 
 107         unsigned long   dstBlksPerAllocBlk
;     /* the number of 512 byte blocks per allocation block on destination */ 
 109         unsigned long   allocBlksNeeded
;        /* the total number of allocation blocks needed  */ 
 111         unsigned long   tempBlocks
;                     /* temporary storage for calculations (save some stack space)  */ 
 112         CopyFilterProcPtr copyFilterProc
;       /* pointer to filter function */ 
 114 #if PRAGMA_STRUCT_ALIGN 
 115 #pragma options align=reset 
 118 typedef struct PreflightGlobals PreflightGlobals
; 
 119 typedef PreflightGlobals 
*PreflightGlobalsPtr
; 
 121 /*****************************************************************************/ 
 123 /* static prototypes */ 
 125 static  void    GetLevelSize(long currentDirID
, 
 126                                                          PreflightGlobals 
*theGlobals
); 
 128 static  OSErr   
PreflightDirectoryCopySpace(short srcVRefNum
, 
 131                                                                                         CopyFilterProcPtr copyFilterProc
, 
 134 static  void    CopyLevel(long sourceDirID
, 
 136                                                   EnumerateGlobals 
*theGlobals
); 
 138 /*****************************************************************************/ 
 140 static  void    GetLevelSize(long currentDirID
, 
 141                                                          PreflightGlobals 
*theGlobals
) 
 147                 theGlobals
->myCPB
.dirInfo
.ioFDirIndex 
= index
; 
 148                 theGlobals
->myCPB
.dirInfo
.ioDrDirID 
= currentDirID
;     /* we need to do this every time */ 
 149                                                                                                                         /* through, since GetCatInfo  */ 
 150                                                                                                                         /* returns ioFlNum in this field */ 
 151                 theGlobals
->result 
= PBGetCatInfoSync(&theGlobals
->myCPB
); 
 152                 if ( theGlobals
->result 
== noErr 
) 
 154                         if ( (theGlobals
->copyFilterProc 
== NULL
) || 
 155                                  CallCopyFilterProc(theGlobals
->copyFilterProc
, &theGlobals
->myCPB
) ) /* filter if filter proc was supplied */ 
 157                                 /* Either there's no filter proc OR the filter proc says to use this item */ 
 158                                 if ( (theGlobals
->myCPB
.dirInfo
.ioFlAttrib 
& kioFlAttribDirMask
) != 0 ) 
 160                                         /* we have a directory */ 
 162                                         GetLevelSize(theGlobals
->myCPB
.dirInfo
.ioDrDirID
, theGlobals
); /* recurse */ 
 163                                         theGlobals
->result 
= noErr
; /* clear error return on way back */ 
 167                                         /* We have a file - add its allocation blocks to allocBlksNeeded. */ 
 168                                         /* Since space on Mac OS disks is always allocated in allocation blocks, */ 
 169                                         /* this takes into account rounding up to the end of an allocation block. */ 
 171                                         /* get number of 512-byte blocks needed for data fork */ 
 172                                         if ( ((unsigned long)theGlobals
->myCPB
.hFileInfo
.ioFlLgLen 
& 0x000001ff) != 0 ) 
 174                                                 theGlobals
->tempBlocks 
= ((unsigned long)theGlobals
->myCPB
.hFileInfo
.ioFlLgLen 
>> 9) + 1; 
 178                                                 theGlobals
->tempBlocks 
= (unsigned long)theGlobals
->myCPB
.hFileInfo
.ioFlLgLen 
>> 9; 
 180                                         /* now, calculate number of new allocation blocks needed for the data fork and add it to the total */ 
 181                                         if ( theGlobals
->tempBlocks 
% theGlobals
->dstBlksPerAllocBlk 
) 
 183                                                 theGlobals
->allocBlksNeeded 
+= (theGlobals
->tempBlocks 
/ theGlobals
->dstBlksPerAllocBlk
) + 1; 
 187                                                 theGlobals
->allocBlksNeeded 
+= theGlobals
->tempBlocks 
/ theGlobals
->dstBlksPerAllocBlk
; 
 190                                         /* get number of 512-byte blocks needed for resource fork */ 
 191                                         if ( ((unsigned long)theGlobals
->myCPB
.hFileInfo
.ioFlRLgLen 
& 0x000001ff) != 0 ) 
 193                                                 theGlobals
->tempBlocks 
= ((unsigned long)theGlobals
->myCPB
.hFileInfo
.ioFlRLgLen 
>> 9) + 1; 
 197                                                 theGlobals
->tempBlocks 
= (unsigned long)theGlobals
->myCPB
.hFileInfo
.ioFlRLgLen 
>> 9; 
 199                                         /* now, calculate number of new allocation blocks needed for the resource  fork and add it to the total */ 
 200                                         if ( theGlobals
->tempBlocks 
% theGlobals
->dstBlksPerAllocBlk 
) 
 202                                                 theGlobals
->allocBlksNeeded 
+= (theGlobals
->tempBlocks 
/ theGlobals
->dstBlksPerAllocBlk
) + 1; 
 206                                                 theGlobals
->allocBlksNeeded 
+= theGlobals
->tempBlocks 
/ theGlobals
->dstBlksPerAllocBlk
; 
 212         } while ( theGlobals
->result 
== noErr 
); 
 215 /*****************************************************************************/ 
 217 static  OSErr   
PreflightDirectoryCopySpace(short srcVRefNum
, 
 220                                                                                         CopyFilterProcPtr copyFilterProc
, 
 225         unsigned long dstFreeBlocks
; 
 226         PreflightGlobals theGlobals
; 
 228         error 
= XGetVolumeInfoNoName(NULL
, dstVRefNum
, &pb
); 
 229         if ( error 
== noErr 
) 
 231                 /* Convert freeBytes to free disk blocks (512-byte blocks) */ 
 232                 dstFreeBlocks 
= U32SetU(U64ShiftRight(pb
.ioVFreeBytes
, 9)); 
 234                 /* get allocation block size (always multiple of 512) and divide by 512 
 235                   to get number of 512-byte blocks per allocation block */ 
 236                 theGlobals
.dstBlksPerAllocBlk 
= ((unsigned long)pb
.ioVAlBlkSiz 
>> 9); 
 238                 theGlobals
.allocBlksNeeded 
= 0; 
 240                 theGlobals
.myCPB
.dirInfo
.ioNamePtr 
= theGlobals
.itemName
; 
 241                 theGlobals
.myCPB
.dirInfo
.ioVRefNum 
= srcVRefNum
; 
 243                 theGlobals
.copyFilterProc 
= copyFilterProc
; 
 245                 GetLevelSize(srcDirID
, &theGlobals
); 
 247                 /* Is there enough room on the destination volume for the source file?                                  */ 
 248                 /* Note:        This will work because the largest number of disk blocks supported                      */ 
 249                 /*                      on a 2TB volume is 0xffffffff and (allocBlksNeeded * dstBlksPerAllocBlk)        */ 
 250                 /*                      will always be less than 0xffffffff.                                                                            */ 
 251                 *spaceOK 
= ((theGlobals
.allocBlksNeeded 
* theGlobals
.dstBlksPerAllocBlk
) <= dstFreeBlocks
); 
 257 /*****************************************************************************/ 
 259 static  void    CopyLevel(long sourceDirID
, 
 261                                                   EnumerateGlobals 
*theGlobals
) 
 263         long currentSrcDirID
; 
 269                 /* Get next source item at the current directory level */ 
 271                 theGlobals
->myCPB
.dirInfo
.ioFDirIndex 
= index
; 
 272                 theGlobals
->myCPB
.dirInfo
.ioDrDirID 
= sourceDirID
; 
 273                 theGlobals
->error 
= PBGetCatInfoSync(&theGlobals
->myCPB
);                
 275                 if ( theGlobals
->error 
== noErr 
) 
 277                         if ( (theGlobals
->copyFilterProc 
== NULL
) || 
 278                                  CallCopyFilterProc(theGlobals
->copyFilterProc
, &theGlobals
->myCPB
) ) /* filter if filter proc was supplied */ 
 280                                 /* Either there's no filter proc OR the filter proc says to use this item */ 
 282                                 /* We have an item.  Is it a file or directory? */ 
 283                                 if ( (theGlobals
->myCPB
.hFileInfo
.ioFlAttrib 
& kioFlAttribDirMask
) != 0 ) 
 285                                         /* We have a directory */ 
 287                                         /* Create a new directory at the destination. No errors allowed! */ 
 288                                         theGlobals
->error 
= DirCreate(theGlobals
->destinationVRefNum
, dstDirID
, theGlobals
->itemName
, &newDirID
); 
 289                                         if ( theGlobals
->error 
== noErr 
) 
 291                                                 /* Save the current source directory ID where we can get it when we come back 
 292                                                 ** from recursion land. */ 
 293                                                 currentSrcDirID 
= theGlobals
->myCPB
.dirInfo
.ioDrDirID
; 
 295                                                 /* Dive again (copy the directory level we just found below this one) */ 
 296                                                 CopyLevel(theGlobals
->myCPB
.dirInfo
.ioDrDirID
, newDirID
, theGlobals
); 
 298                                                 if ( !theGlobals
->bailout 
) 
 300                                                         /* Copy comment from old to new directory. */ 
 301                                                         /* Ignore the result because we really don't care if it worked or not. */ 
 302                                                         (void) DTCopyComment(theGlobals
->myCPB
.dirInfo
.ioVRefNum
, currentSrcDirID
, NULL
, theGlobals
->destinationVRefNum
, newDirID
, NULL
); 
 304                                                         /* Copy directory attributes (dates, etc.) to newDirID. */ 
 305                                                         /* No errors allowed */ 
 306                                                         theGlobals
->error 
= CopyFileMgrAttributes(theGlobals
->myCPB
.dirInfo
.ioVRefNum
, currentSrcDirID
, NULL
, theGlobals
->destinationVRefNum
, newDirID
, NULL
, true); 
 308                                                         /* handle any errors from CopyFileMgrAttributes */ 
 309                                                         if ( theGlobals
->error 
!= noErr 
) 
 311                                                                 if ( theGlobals
->errorHandler 
!= NULL 
) 
 313                                                                         theGlobals
->bailout 
=  CallCopyErrProc(theGlobals
->errorHandler
, theGlobals
->error
, copyDirFMAttributesOp
, 
 314                                                                                                                         theGlobals
->myCPB
.dirInfo
.ioVRefNum
, currentSrcDirID
, NULL
, 
 315                                                                                                                         theGlobals
->destinationVRefNum
, newDirID
, NULL
); 
 319                                                                         /* If you don't handle the errors with an error handler, */ 
 320                                                                         /* then the copy stops here. */ 
 321                                                                         theGlobals
->bailout 
= true; 
 326                                         else    /* error handling for DirCreate */ 
 328                                                 if ( theGlobals
->errorHandler 
!= NULL 
) 
 330                                                         theGlobals
->bailout 
= CallCopyErrProc(theGlobals
->errorHandler
, theGlobals
->error
, dirCreateOp
, 
 331                                                                                                                 theGlobals
->myCPB
.dirInfo
.ioVRefNum
, currentSrcDirID
, NULL
, 
 332                                                                                                                 theGlobals
->destinationVRefNum
, dstDirID
, theGlobals
->itemName
); 
 336                                                         /* If you don't handle the errors with an error handler, */ 
 337                                                         /* then the copy stops here. */ 
 338                                                         theGlobals
->bailout 
= true; 
 342                                         if ( !theGlobals
->bailout 
) 
 344                                                 /* clear error return on way back if we aren't bailing out */ 
 345                                                 theGlobals
->error 
= noErr
; 
 350                                         /* We have a file, so copy it */ 
 352                                         theGlobals
->error 
= FileCopy(theGlobals
->myCPB
.hFileInfo
.ioVRefNum
, 
 353                                                                                                  theGlobals
->myCPB
.hFileInfo
.ioFlParID
, 
 354                                                                                                  theGlobals
->itemName
, 
 355                                                                                                  theGlobals
->destinationVRefNum
, 
 359                                                                                                  theGlobals
->copyBuffer
, 
 360                                                                                                  theGlobals
->bufferSize
, 
 363                                         /* handle any errors from FileCopy */ 
 364                                         if ( theGlobals
->error 
!= noErr 
) 
 366                                                 if ( theGlobals
->errorHandler 
!= NULL 
) 
 368                                                         theGlobals
->bailout 
= CallCopyErrProc(theGlobals
->errorHandler
, theGlobals
->error
, fileCopyOp
, 
 369                                                                                                         theGlobals
->myCPB
.hFileInfo
.ioVRefNum
, theGlobals
->myCPB
.hFileInfo
.ioFlParID
, theGlobals
->itemName
, 
 370                                                                                                         theGlobals
->destinationVRefNum
, dstDirID
, NULL
); 
 371                                                         if ( !theGlobals
->bailout 
) 
 373                                                                 /* If the CopyErrProc handled the problem, clear the error here */ 
 374                                                                 theGlobals
->error 
= noErr
; 
 379                                                         /* If you don't handle the errors with an error handler, */ 
 380                                                         /* then the copy stops here. */ 
 381                                                         theGlobals
->bailout 
= true; 
 388                 {       /* error handling for PBGetCatInfo */ 
 389                         /* it's normal to get a fnfErr when indexing; that only means you've hit the end of the directory */ 
 390                         if ( theGlobals
->error 
!= fnfErr 
) 
 392                                 if ( theGlobals
->errorHandler 
!= NULL 
) 
 394                                         theGlobals
->bailout 
= CallCopyErrProc(theGlobals
->errorHandler
, theGlobals
->error
, getNextItemOp
, 
 395                                                                                         theGlobals
->myCPB
.dirInfo
.ioVRefNum
, sourceDirID
, NULL
, 0, 0, NULL
); 
 396                                         if ( !theGlobals
->bailout 
) 
 398                                                 /* If the CopyErrProc handled the problem, clear the error here */ 
 399                                                 theGlobals
->error 
= noErr
; 
 404                                         /* If you don't handle the errors with an error handler, */ 
 405                                         /* then the copy stops here. */ 
 406                                         theGlobals
->bailout 
= true; 
 410                 ++index
; /* prepare to get next item */ 
 411         } while ( (theGlobals
->error 
== noErr
) && (!theGlobals
->bailout
) ); /* time to fall back a level? */ 
 414 /*****************************************************************************/ 
 416 pascal  OSErr   
FilteredDirectoryCopy(short srcVRefNum
, 
 418                                                                           ConstStr255Param srcName
, 
 421                                                                           ConstStr255Param dstName
, 
 422                                                                           ConstStr255Param copyName
, 
 426                                                                           CopyErrProcPtr copyErrHandler
, 
 427                                                                           CopyFilterProcPtr copyFilterProc
) 
 429         EnumerateGlobals theGlobals
; 
 432         Boolean ourCopyBuffer 
= false; 
 433         Str63   srcDirName
, oldDiskName
; 
 436         /* Make sure a copy buffer is allocated. */ 
 437         if ( copyBufferPtr 
== NULL 
) 
 439                 /* The caller didn't supply a copy buffer so grab one from the application heap. 
 440                 ** Try to get a big copy buffer, if we can't, try for a 512-byte buffer. 
 441                 ** If 512 bytes aren't available, we're in trouble. */ 
 442                 copyBufferSize 
= dirCopyBigCopyBuffSize
; 
 443                 copyBufferPtr 
= NewPtr(copyBufferSize
); 
 444                 if ( copyBufferPtr 
== NULL 
) 
 446                         copyBufferSize 
= dirCopyMinCopyBuffSize
; 
 447                         copyBufferPtr 
= NewPtr(copyBufferSize
); 
 448                         if ( copyBufferPtr 
== NULL 
) 
 450                                 return ( memFullErr 
); 
 453                 ourCopyBuffer 
= true; 
 456         /* Get the real dirID where we're copying from and make sure it is a directory. */ 
 457         error 
= GetDirectoryID(srcVRefNum
, srcDirID
, srcName
, &srcDirID
, &isDirectory
); 
 458         if ( error 
!= noErr 
) 
 468         /* Special case destination if it is the root parent directory. */ 
 469         /* Since you can't create the root directory, this is needed if */ 
 470         /* you want to copy a directory's content to a disk's root directory. */ 
 471         if ( (dstDirID 
== fsRtParID
) && (dstName 
== NULL
) ) 
 473                 dstDirID 
= fsRtParID
; 
 479                 /*  Get the real dirID where we're going to put the copy and make sure it is a directory. */ 
 480                 error 
= GetDirectoryID(dstVRefNum
, dstDirID
, dstName
, &dstDirID
, &isDirectory
); 
 481                 if ( error 
!= noErr 
) 
 492         /* Get the real vRefNum of both the source and destination */ 
 493         error 
= DetermineVRefNum(srcName
, srcVRefNum
, &srcVRefNum
); 
 494         if ( error 
!= noErr 
) 
 498         error 
= DetermineVRefNum(dstName
, dstVRefNum
, &dstVRefNum
); 
 499         if ( error 
!= noErr 
) 
 506                 error 
= PreflightDirectoryCopySpace(srcVRefNum
, srcDirID
, dstVRefNum
, copyFilterProc
, &spaceOK
); 
 507                 if ( error 
!= noErr 
) 
 513                         error 
= dskFulErr
; /* not enough room on destination */ 
 518         /* Create the new directory in the destination directory with the */ 
 519         /* same name as the source directory. */ 
 520         error 
= GetDirName(srcVRefNum
, srcDirID
, srcDirName
); 
 521         if ( error 
!= noErr 
) 
 526         /* Again, special case destination if the destination is the */ 
 527         /* root parent directory. This time, we'll rename the disk to */ 
 528         /* the source directory name. */ 
 529         if ( dstDirID 
== fsRtParID 
) 
 531                 /* Get the current name of the destination disk */ 
 532                 error 
= GetDirName(dstVRefNum
, fsRtDirID
, oldDiskName
); 
 533                 if ( error 
== noErr 
)    
 535                         /* use the copyName as srcDirName if supplied */ 
 536                         if ( copyName 
!= NULL 
) 
 538                                 /* make a copy since copyName is a const input */ 
 539                                 BlockMoveData(copyName
, srcDirName
, sizeof(Str31
)); 
 541                         /* Shorten the name if it's too long to be the volume name */ 
 542                         TruncPString(srcDirName
, srcDirName
, 27); 
 544                         /* Rename the disk */ 
 545                         error 
= HRename(dstVRefNum
, fsRtParID
, oldDiskName
, srcDirName
); 
 547                         /* and copy to the root directory */ 
 548                         dstDirID 
= fsRtDirID
; 
 553                 /* use the copyName as srcDirName if supplied */ 
 554                 error 
= DirCreate(dstVRefNum
, dstDirID
, ((copyName 
!= NULL
) ? copyName 
: srcDirName
), &dstDirID
); 
 556         if ( error 
!= noErr 
) 
 558                 /* handle any errors from DirCreate */ 
 559                 if ( copyErrHandler 
!= NULL 
) 
 561                         if ( CallCopyErrProc(copyErrHandler
, error
, dirCreateOp
, 
 562                                                                                                         srcVRefNum
, srcDirID
, NULL
, 
 563                                                                                                         dstVRefNum
, dstDirID
, srcDirName
) ) 
 569                                 /* If the CopyErrProc handled the problem, clear the error here */ 
 576                         /* If you don't handle the errors with an error handler, */ 
 577                         /* then the copy stops here. */ 
 582         /* dstDirID is now the newly created directory! */ 
 584         /* Set up the globals we need to access from the recursive routine. */ 
 585         theGlobals
.copyBuffer 
= (Ptr
)copyBufferPtr
; 
 586         theGlobals
.bufferSize 
= copyBufferSize
; 
 587         theGlobals
.destinationVRefNum 
= dstVRefNum
; /* so we can get to it always */ 
 588         theGlobals
.myCPB
.hFileInfo
.ioNamePtr 
= (StringPtr
)&theGlobals
.itemName
; 
 589         theGlobals
.myCPB
.hFileInfo
.ioVRefNum 
= srcVRefNum
; 
 590         theGlobals
.errorHandler 
= copyErrHandler
; 
 591         theGlobals
.bailout 
= false; 
 592         theGlobals
.copyFilterProc 
=  copyFilterProc
; 
 594         /* Here we go into recursion land... */ 
 595         CopyLevel(srcDirID
, dstDirID
, &theGlobals
); 
 596         error 
= theGlobals
.error
;       /* get the result */ 
 598         if ( !theGlobals
.bailout 
) 
 600                 /* Copy comment from source to destination directory. */ 
 601                 /* Ignore the result because we really don't care if it worked or not. */ 
 602                 (void) DTCopyComment(srcVRefNum
, srcDirID
, NULL
, dstVRefNum
, dstDirID
, NULL
); 
 604                 /* Copy the File Manager attributes */ 
 605                 error 
= CopyFileMgrAttributes(srcVRefNum
, srcDirID
, NULL
, 
 606                                         dstVRefNum
, dstDirID
, NULL
, true); 
 608                 /* handle any errors from CopyFileMgrAttributes */ 
 609                 if ( (error 
!= noErr
) && (copyErrHandler 
!= NULL
) ) 
 611                         theGlobals
.bailout 
= CallCopyErrProc(copyErrHandler
, error
, copyDirFMAttributesOp
, 
 612                                                                                                 srcVRefNum
, srcDirID
, NULL
, 
 613                                                                                                 dstVRefNum
, dstDirID
, NULL
); 
 618         /* Get rid of the copy buffer if we allocated it. */ 
 621                 DisposePtr((Ptr
)copyBufferPtr
); 
 627 /*****************************************************************************/ 
 629 pascal  OSErr   
DirectoryCopy(short srcVRefNum
, 
 631                                                           ConstStr255Param srcName
, 
 634                                                           ConstStr255Param dstName
, 
 635                                                           ConstStr255Param copyName
, 
 639                                                           CopyErrProcPtr copyErrHandler
) 
 641         return ( FilteredDirectoryCopy(srcVRefNum
, srcDirID
, srcName
, 
 642                                                                    dstVRefNum
, dstDirID
, dstName
, 
 644                                                                    copyBufferPtr
, copyBufferSize
, preflight
, 
 645                                                                    copyErrHandler
, NULL
) ); 
 648 /*****************************************************************************/ 
 650 pascal  OSErr   
FSpFilteredDirectoryCopy(const FSSpec 
*srcSpec
, 
 651                                                                                  const FSSpec 
*dstSpec
, 
 652                                                                                  ConstStr255Param copyName
, 
 656                                                                                  CopyErrProcPtr copyErrHandler
, 
 657                                                                                  CopyFilterProcPtr copyFilterProc
) 
 659         return ( FilteredDirectoryCopy(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
, 
 660                                                                    dstSpec
->vRefNum
, dstSpec
->parID
, dstSpec
->name
, 
 662                                                                    copyBufferPtr
, copyBufferSize
, preflight
, 
 663                                                                    copyErrHandler
, copyFilterProc
) ); 
 666 /*****************************************************************************/ 
 668 pascal  OSErr   
FSpDirectoryCopy(const FSSpec 
*srcSpec
, 
 669                                                                  const FSSpec 
*dstSpec
, 
 670                                                                  ConstStr255Param copyName
, 
 674                                                                  CopyErrProcPtr copyErrHandler
) 
 676         return ( FilteredDirectoryCopy(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
, 
 677                                                                    dstSpec
->vRefNum
, dstSpec
->parID
, dstSpec
->name
, 
 679                                                                    copyBufferPtr
, copyBufferSize
, preflight
, 
 680                                                                    copyErrHandler
, NULL
) ); 
 683 /*****************************************************************************/