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 
= 0 ; 
 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                                                 /* note that currentSrcDirID has not been initialised when entering this execution path */ 
 329                                                 if ( theGlobals
->errorHandler 
!= NULL 
) 
 331                                                         theGlobals
->bailout 
= CallCopyErrProc(theGlobals
->errorHandler
, theGlobals
->error
, dirCreateOp
, 
 332                                                                                                                 theGlobals
->myCPB
.dirInfo
.ioVRefNum
, currentSrcDirID
, NULL
, 
 333                                                                                                                 theGlobals
->destinationVRefNum
, dstDirID
, theGlobals
->itemName
); 
 337                                                         /* If you don't handle the errors with an error handler, */ 
 338                                                         /* then the copy stops here. */ 
 339                                                         theGlobals
->bailout 
= true; 
 343                                         if ( !theGlobals
->bailout 
) 
 345                                                 /* clear error return on way back if we aren't bailing out */ 
 346                                                 theGlobals
->error 
= noErr
; 
 351                                         /* We have a file, so copy it */ 
 353                                         theGlobals
->error 
= FileCopy(theGlobals
->myCPB
.hFileInfo
.ioVRefNum
, 
 354                                                                                                  theGlobals
->myCPB
.hFileInfo
.ioFlParID
, 
 355                                                                                                  theGlobals
->itemName
, 
 356                                                                                                  theGlobals
->destinationVRefNum
, 
 360                                                                                                  theGlobals
->copyBuffer
, 
 361                                                                                                  theGlobals
->bufferSize
, 
 364                                         /* handle any errors from FileCopy */ 
 365                                         if ( theGlobals
->error 
!= noErr 
) 
 367                                                 if ( theGlobals
->errorHandler 
!= NULL 
) 
 369                                                         theGlobals
->bailout 
= CallCopyErrProc(theGlobals
->errorHandler
, theGlobals
->error
, fileCopyOp
, 
 370                                                                                                         theGlobals
->myCPB
.hFileInfo
.ioVRefNum
, theGlobals
->myCPB
.hFileInfo
.ioFlParID
, theGlobals
->itemName
, 
 371                                                                                                         theGlobals
->destinationVRefNum
, dstDirID
, NULL
); 
 372                                                         if ( !theGlobals
->bailout 
) 
 374                                                                 /* If the CopyErrProc handled the problem, clear the error here */ 
 375                                                                 theGlobals
->error 
= noErr
; 
 380                                                         /* If you don't handle the errors with an error handler, */ 
 381                                                         /* then the copy stops here. */ 
 382                                                         theGlobals
->bailout 
= true; 
 389                 {       /* error handling for PBGetCatInfo */ 
 390                         /* it's normal to get a fnfErr when indexing; that only means you've hit the end of the directory */ 
 391                         if ( theGlobals
->error 
!= fnfErr 
) 
 393                                 if ( theGlobals
->errorHandler 
!= NULL 
) 
 395                                         theGlobals
->bailout 
= CallCopyErrProc(theGlobals
->errorHandler
, theGlobals
->error
, getNextItemOp
, 
 396                                                                                         theGlobals
->myCPB
.dirInfo
.ioVRefNum
, sourceDirID
, NULL
, 0, 0, NULL
); 
 397                                         if ( !theGlobals
->bailout 
) 
 399                                                 /* If the CopyErrProc handled the problem, clear the error here */ 
 400                                                 theGlobals
->error 
= noErr
; 
 405                                         /* If you don't handle the errors with an error handler, */ 
 406                                         /* then the copy stops here. */ 
 407                                         theGlobals
->bailout 
= true; 
 411                 ++index
; /* prepare to get next item */ 
 412         } while ( (theGlobals
->error 
== noErr
) && (!theGlobals
->bailout
) ); /* time to fall back a level? */ 
 415 /*****************************************************************************/ 
 417 pascal  OSErr   
FilteredDirectoryCopy(short srcVRefNum
, 
 419                                                                           ConstStr255Param srcName
, 
 422                                                                           ConstStr255Param dstName
, 
 423                                                                           ConstStr255Param copyName
, 
 427                                                                           CopyErrProcPtr copyErrHandler
, 
 428                                                                           CopyFilterProcPtr copyFilterProc
) 
 430         EnumerateGlobals theGlobals
; 
 433         Boolean ourCopyBuffer 
= false; 
 434         Str63   srcDirName
, oldDiskName
; 
 437         /* Make sure a copy buffer is allocated. */ 
 438         if ( copyBufferPtr 
== NULL 
) 
 440                 /* The caller didn't supply a copy buffer so grab one from the application heap. 
 441                 ** Try to get a big copy buffer, if we can't, try for a 512-byte buffer. 
 442                 ** If 512 bytes aren't available, we're in trouble. */ 
 443                 copyBufferSize 
= dirCopyBigCopyBuffSize
; 
 444                 copyBufferPtr 
= NewPtr(copyBufferSize
); 
 445                 if ( copyBufferPtr 
== NULL 
) 
 447                         copyBufferSize 
= dirCopyMinCopyBuffSize
; 
 448                         copyBufferPtr 
= NewPtr(copyBufferSize
); 
 449                         if ( copyBufferPtr 
== NULL 
) 
 451                                 return ( memFullErr 
); 
 454                 ourCopyBuffer 
= true; 
 457         /* Get the real dirID where we're copying from and make sure it is a directory. */ 
 458         error 
= GetDirectoryID(srcVRefNum
, srcDirID
, srcName
, &srcDirID
, &isDirectory
); 
 459         if ( error 
!= noErr 
) 
 469         /* Special case destination if it is the root parent directory. */ 
 470         /* Since you can't create the root directory, this is needed if */ 
 471         /* you want to copy a directory's content to a disk's root directory. */ 
 472         if ( (dstDirID 
== fsRtParID
) && (dstName 
== NULL
) ) 
 474                 dstDirID 
= fsRtParID
; 
 480                 /*  Get the real dirID where we're going to put the copy and make sure it is a directory. */ 
 481                 error 
= GetDirectoryID(dstVRefNum
, dstDirID
, dstName
, &dstDirID
, &isDirectory
); 
 482                 if ( error 
!= noErr 
) 
 493         /* Get the real vRefNum of both the source and destination */ 
 494         error 
= DetermineVRefNum(srcName
, srcVRefNum
, &srcVRefNum
); 
 495         if ( error 
!= noErr 
) 
 499         error 
= DetermineVRefNum(dstName
, dstVRefNum
, &dstVRefNum
); 
 500         if ( error 
!= noErr 
) 
 507                 error 
= PreflightDirectoryCopySpace(srcVRefNum
, srcDirID
, dstVRefNum
, copyFilterProc
, &spaceOK
); 
 508                 if ( error 
!= noErr 
) 
 514                         error 
= dskFulErr
; /* not enough room on destination */ 
 519         /* Create the new directory in the destination directory with the */ 
 520         /* same name as the source directory. */ 
 521         error 
= GetDirName(srcVRefNum
, srcDirID
, srcDirName
); 
 522         if ( error 
!= noErr 
) 
 527         /* Again, special case destination if the destination is the */ 
 528         /* root parent directory. This time, we'll rename the disk to */ 
 529         /* the source directory name. */ 
 530         if ( dstDirID 
== fsRtParID 
) 
 532                 /* Get the current name of the destination disk */ 
 533                 error 
= GetDirName(dstVRefNum
, fsRtDirID
, oldDiskName
); 
 534                 if ( error 
== noErr 
)    
 536                         /* use the copyName as srcDirName if supplied */ 
 537                         if ( copyName 
!= NULL 
) 
 539                                 /* make a copy since copyName is a const input */ 
 540                                 BlockMoveData(copyName
, srcDirName
, sizeof(Str31
)); 
 542                         /* Shorten the name if it's too long to be the volume name */ 
 543                         TruncPString(srcDirName
, srcDirName
, 27); 
 545                         /* Rename the disk */ 
 546                         error 
= HRename(dstVRefNum
, fsRtParID
, oldDiskName
, srcDirName
); 
 548                         /* and copy to the root directory */ 
 549                         dstDirID 
= fsRtDirID
; 
 554                 /* use the copyName as srcDirName if supplied */ 
 555                 error 
= DirCreate(dstVRefNum
, dstDirID
, ((copyName 
!= NULL
) ? copyName 
: srcDirName
), &dstDirID
); 
 557         if ( error 
!= noErr 
) 
 559                 /* handle any errors from DirCreate */ 
 560                 if ( copyErrHandler 
!= NULL 
) 
 562                         if ( CallCopyErrProc(copyErrHandler
, error
, dirCreateOp
, 
 563                                                                                                         srcVRefNum
, srcDirID
, NULL
, 
 564                                                                                                         dstVRefNum
, dstDirID
, srcDirName
) ) 
 570                                 /* If the CopyErrProc handled the problem, clear the error here */ 
 577                         /* If you don't handle the errors with an error handler, */ 
 578                         /* then the copy stops here. */ 
 583         /* dstDirID is now the newly created directory! */ 
 585         /* Set up the globals we need to access from the recursive routine. */ 
 586         theGlobals
.copyBuffer 
= (Ptr
)copyBufferPtr
; 
 587         theGlobals
.bufferSize 
= copyBufferSize
; 
 588         theGlobals
.destinationVRefNum 
= dstVRefNum
; /* so we can get to it always */ 
 589         theGlobals
.myCPB
.hFileInfo
.ioNamePtr 
= (StringPtr
)&theGlobals
.itemName
; 
 590         theGlobals
.myCPB
.hFileInfo
.ioVRefNum 
= srcVRefNum
; 
 591         theGlobals
.errorHandler 
= copyErrHandler
; 
 592         theGlobals
.bailout 
= false; 
 593         theGlobals
.copyFilterProc 
=  copyFilterProc
; 
 595         /* Here we go into recursion land... */ 
 596         CopyLevel(srcDirID
, dstDirID
, &theGlobals
); 
 597         error 
= theGlobals
.error
;       /* get the result */ 
 599         if ( !theGlobals
.bailout 
) 
 601                 /* Copy comment from source to destination directory. */ 
 602                 /* Ignore the result because we really don't care if it worked or not. */ 
 603                 (void) DTCopyComment(srcVRefNum
, srcDirID
, NULL
, dstVRefNum
, dstDirID
, NULL
); 
 605                 /* Copy the File Manager attributes */ 
 606                 error 
= CopyFileMgrAttributes(srcVRefNum
, srcDirID
, NULL
, 
 607                                         dstVRefNum
, dstDirID
, NULL
, true); 
 609                 /* handle any errors from CopyFileMgrAttributes */ 
 610                 if ( (error 
!= noErr
) && (copyErrHandler 
!= NULL
) ) 
 612                         theGlobals
.bailout 
= CallCopyErrProc(copyErrHandler
, error
, copyDirFMAttributesOp
, 
 613                                                                                                 srcVRefNum
, srcDirID
, NULL
, 
 614                                                                                                 dstVRefNum
, dstDirID
, NULL
); 
 619         /* Get rid of the copy buffer if we allocated it. */ 
 622                 DisposePtr((Ptr
)copyBufferPtr
); 
 628 /*****************************************************************************/ 
 630 pascal  OSErr   
DirectoryCopy(short srcVRefNum
, 
 632                                                           ConstStr255Param srcName
, 
 635                                                           ConstStr255Param dstName
, 
 636                                                           ConstStr255Param copyName
, 
 640                                                           CopyErrProcPtr copyErrHandler
) 
 642         return ( FilteredDirectoryCopy(srcVRefNum
, srcDirID
, srcName
, 
 643                                                                    dstVRefNum
, dstDirID
, dstName
, 
 645                                                                    copyBufferPtr
, copyBufferSize
, preflight
, 
 646                                                                    copyErrHandler
, NULL
) ); 
 649 /*****************************************************************************/ 
 651 pascal  OSErr   
FSpFilteredDirectoryCopy(const FSSpec 
*srcSpec
, 
 652                                                                                  const FSSpec 
*dstSpec
, 
 653                                                                                  ConstStr255Param copyName
, 
 657                                                                                  CopyErrProcPtr copyErrHandler
, 
 658                                                                                  CopyFilterProcPtr copyFilterProc
) 
 660         return ( FilteredDirectoryCopy(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
, 
 661                                                                    dstSpec
->vRefNum
, dstSpec
->parID
, dstSpec
->name
, 
 663                                                                    copyBufferPtr
, copyBufferSize
, preflight
, 
 664                                                                    copyErrHandler
, copyFilterProc
) ); 
 667 /*****************************************************************************/ 
 669 pascal  OSErr   
FSpDirectoryCopy(const FSSpec 
*srcSpec
, 
 670                                                                  const FSSpec 
*dstSpec
, 
 671                                                                  ConstStr255Param copyName
, 
 675                                                                  CopyErrProcPtr copyErrHandler
) 
 677         return ( FilteredDirectoryCopy(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
, 
 678                                                                    dstSpec
->vRefNum
, dstSpec
->parID
, dstSpec
->name
, 
 680                                                                    copyBufferPtr
, copyBufferSize
, preflight
, 
 681                                                                    copyErrHandler
, NULL
) ); 
 684 /*****************************************************************************/