1/* 2 File: DirectoryCopy.c 3 4 Contains: A robust, general purpose directory copy routine. 5 6 Version: MoreFiles 7 8 Copyright: � 1992-2001 by Apple Computer, Inc., all rights reserved. 9 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. 17 18 File Ownership: 19 20 DRI: Apple Macintosh Developer Technical Support 21 22 Other Contact: Apple Macintosh Developer Technical Support 23 <http://developer.apple.com/bugreporter/> 24 25 Technology: DTS Sample Code 26 27 Writers: 28 29 (JL) Jim Luther 30 31 Change History (most recent first): 32 33 <2> 2/7/01 JL Added standard header. Updated names of includes. 34 <1> 12/06/99 JL MoreFiles 1.5. 35*/ 36 37#include <MacTypes.h> 38#include <MacErrors.h> 39#include <MacMemory.h> 40#include <Files.h> 41#include <Script.h> 42#include <Math64.h> 43 44#define __COMPILINGMOREFILES 45 46#include "MoreFiles.h" 47#include "MoreFilesExtras.h" 48#include "MoreDesktopMgr.h" 49#include "FileCopy.h" 50#include "DirectoryCopy.h" 51 52/*****************************************************************************/ 53 54/* local constants */ 55 56enum 57{ 58 dirCopyBigCopyBuffSize = 0x00004000, 59 dirCopyMinCopyBuffSize = 0x00000200 60}; 61 62 63/*****************************************************************************/ 64 65/* local data structures */ 66 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. */ 70 71#if PRAGMA_STRUCT_ALIGN 72#pragma options align=mac68k 73#endif 74struct EnumerateGlobals 75{ 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 */ 85}; 86#if PRAGMA_STRUCT_ALIGN 87#pragma options align=reset 88#endif 89 90typedef struct EnumerateGlobals EnumerateGlobals; 91typedef EnumerateGlobals *EnumerateGlobalsPtr; 92 93 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. */ 97 98#if PRAGMA_STRUCT_ALIGN 99#pragma options align=mac68k 100#endif 101struct PreflightGlobals 102{ 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 */ 106 107 unsigned long dstBlksPerAllocBlk; /* the number of 512 byte blocks per allocation block on destination */ 108 109 unsigned long allocBlksNeeded; /* the total number of allocation blocks needed */ 110 111 unsigned long tempBlocks; /* temporary storage for calculations (save some stack space) */ 112 CopyFilterProcPtr copyFilterProc; /* pointer to filter function */ 113}; 114#if PRAGMA_STRUCT_ALIGN 115#pragma options align=reset 116#endif 117 118typedef struct PreflightGlobals PreflightGlobals; 119typedef PreflightGlobals *PreflightGlobalsPtr; 120 121/*****************************************************************************/ 122 123/* static prototypes */ 124 125static void GetLevelSize(long currentDirID, 126 PreflightGlobals *theGlobals); 127 128static OSErr PreflightDirectoryCopySpace(short srcVRefNum, 129 long srcDirID, 130 short dstVRefNum, 131 CopyFilterProcPtr copyFilterProc, 132 Boolean *spaceOK); 133 134static void CopyLevel(long sourceDirID, 135 long dstDirID, 136 EnumerateGlobals *theGlobals); 137 138/*****************************************************************************/ 139 140static void GetLevelSize(long currentDirID, 141 PreflightGlobals *theGlobals) 142{ 143 short index = 1; 144 145 do 146 { 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 ) 153 { 154 if ( (theGlobals->copyFilterProc == NULL) || 155 CallCopyFilterProc(theGlobals->copyFilterProc, &theGlobals->myCPB) ) /* filter if filter proc was supplied */ 156 { 157 /* Either there's no filter proc OR the filter proc says to use this item */ 158 if ( (theGlobals->myCPB.dirInfo.ioFlAttrib & kioFlAttribDirMask) != 0 ) 159 { 160 /* we have a directory */ 161 162 GetLevelSize(theGlobals->myCPB.dirInfo.ioDrDirID, theGlobals); /* recurse */ 163 theGlobals->result = noErr; /* clear error return on way back */ 164 } 165 else 166 { 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. */ 170 171 /* get number of 512-byte blocks needed for data fork */ 172 if ( ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlLgLen & 0x000001ff) != 0 ) 173 { 174 theGlobals->tempBlocks = ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlLgLen >> 9) + 1; 175 } 176 else 177 { 178 theGlobals->tempBlocks = (unsigned long)theGlobals->myCPB.hFileInfo.ioFlLgLen >> 9; 179 } 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 ) 182 { 183 theGlobals->allocBlksNeeded += (theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk) + 1; 184 } 185 else 186 { 187 theGlobals->allocBlksNeeded += theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk; 188 } 189 190 /* get number of 512-byte blocks needed for resource fork */ 191 if ( ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlRLgLen & 0x000001ff) != 0 ) 192 { 193 theGlobals->tempBlocks = ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlRLgLen >> 9) + 1; 194 } 195 else 196 { 197 theGlobals->tempBlocks = (unsigned long)theGlobals->myCPB.hFileInfo.ioFlRLgLen >> 9; 198 } 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 ) 201 { 202 theGlobals->allocBlksNeeded += (theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk) + 1; 203 } 204 else 205 { 206 theGlobals->allocBlksNeeded += theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk; 207 } 208 } 209 } 210 } 211 ++index; 212 } while ( theGlobals->result == noErr ); 213} 214 215/*****************************************************************************/ 216 217static OSErr PreflightDirectoryCopySpace(short srcVRefNum, 218 long srcDirID, 219 short dstVRefNum, 220 CopyFilterProcPtr copyFilterProc, 221 Boolean *spaceOK) 222{ 223 XVolumeParam pb; 224 OSErr error; 225 unsigned long dstFreeBlocks; 226 PreflightGlobals theGlobals; 227 228 error = XGetVolumeInfoNoName(NULL, dstVRefNum, &pb); 229 if ( error == noErr ) 230 { 231 /* Convert freeBytes to free disk blocks (512-byte blocks) */ 232 dstFreeBlocks = U32SetU(U64ShiftRight(pb.ioVFreeBytes, 9)); 233 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); 237 238 theGlobals.allocBlksNeeded = 0; 239 240 theGlobals.myCPB.dirInfo.ioNamePtr = theGlobals.itemName; 241 theGlobals.myCPB.dirInfo.ioVRefNum = srcVRefNum; 242 243 theGlobals.copyFilterProc = copyFilterProc; 244 245 GetLevelSize(srcDirID, &theGlobals); 246 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); 252 } 253 254 return ( error ); 255} 256 257/*****************************************************************************/ 258 259static void CopyLevel(long sourceDirID, 260 long dstDirID, 261 EnumerateGlobals *theGlobals) 262{ 263 long currentSrcDirID = 0 ; 264 long newDirID; 265 short index = 1; 266 267 do 268 { 269 /* Get next source item at the current directory level */ 270 271 theGlobals->myCPB.dirInfo.ioFDirIndex = index; 272 theGlobals->myCPB.dirInfo.ioDrDirID = sourceDirID; 273 theGlobals->error = PBGetCatInfoSync(&theGlobals->myCPB); 274 275 if ( theGlobals->error == noErr ) 276 { 277 if ( (theGlobals->copyFilterProc == NULL) || 278 CallCopyFilterProc(theGlobals->copyFilterProc, &theGlobals->myCPB) ) /* filter if filter proc was supplied */ 279 { 280 /* Either there's no filter proc OR the filter proc says to use this item */ 281 282 /* We have an item. Is it a file or directory? */ 283 if ( (theGlobals->myCPB.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0 ) 284 { 285 /* We have a directory */ 286 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 ) 290 { 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; 294 295 /* Dive again (copy the directory level we just found below this one) */ 296 CopyLevel(theGlobals->myCPB.dirInfo.ioDrDirID, newDirID, theGlobals); 297 298 if ( !theGlobals->bailout ) 299 { 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); 303 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); 307 308 /* handle any errors from CopyFileMgrAttributes */ 309 if ( theGlobals->error != noErr ) 310 { 311 if ( theGlobals->errorHandler != NULL ) 312 { 313 theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, copyDirFMAttributesOp, 314 theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL, 315 theGlobals->destinationVRefNum, newDirID, NULL); 316 } 317 else 318 { 319 /* If you don't handle the errors with an error handler, */ 320 /* then the copy stops here. */ 321 theGlobals->bailout = true; 322 } 323 } 324 } 325 } 326 else /* error handling for DirCreate */ 327 { 328 /* note that currentSrcDirID has not been initialised when entering this execution path */ 329 if ( theGlobals->errorHandler != NULL ) 330 { 331 theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, dirCreateOp, 332 theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL, 333 theGlobals->destinationVRefNum, dstDirID, theGlobals->itemName); 334 } 335 else 336 { 337 /* If you don't handle the errors with an error handler, */ 338 /* then the copy stops here. */ 339 theGlobals->bailout = true; 340 } 341 } 342 343 if ( !theGlobals->bailout ) 344 { 345 /* clear error return on way back if we aren't bailing out */ 346 theGlobals->error = noErr; 347 } 348 } 349 else 350 { 351 /* We have a file, so copy it */ 352 353 theGlobals->error = FileCopy(theGlobals->myCPB.hFileInfo.ioVRefNum, 354 theGlobals->myCPB.hFileInfo.ioFlParID, 355 theGlobals->itemName, 356 theGlobals->destinationVRefNum, 357 dstDirID, 358 NULL, 359 NULL, 360 theGlobals->copyBuffer, 361 theGlobals->bufferSize, 362 false); 363 364 /* handle any errors from FileCopy */ 365 if ( theGlobals->error != noErr ) 366 { 367 if ( theGlobals->errorHandler != NULL ) 368 { 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 ) 373 { 374 /* If the CopyErrProc handled the problem, clear the error here */ 375 theGlobals->error = noErr; 376 } 377 } 378 else 379 { 380 /* If you don't handle the errors with an error handler, */ 381 /* then the copy stops here. */ 382 theGlobals->bailout = true; 383 } 384 } 385 } 386 } 387 } 388 else 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 ) 392 { 393 if ( theGlobals->errorHandler != NULL ) 394 { 395 theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, getNextItemOp, 396 theGlobals->myCPB.dirInfo.ioVRefNum, sourceDirID, NULL, 0, 0, NULL); 397 if ( !theGlobals->bailout ) 398 { 399 /* If the CopyErrProc handled the problem, clear the error here */ 400 theGlobals->error = noErr; 401 } 402 } 403 else 404 { 405 /* If you don't handle the errors with an error handler, */ 406 /* then the copy stops here. */ 407 theGlobals->bailout = true; 408 } 409 } 410 } 411 ++index; /* prepare to get next item */ 412 } while ( (theGlobals->error == noErr) && (!theGlobals->bailout) ); /* time to fall back a level? */ 413} 414 415/*****************************************************************************/ 416 417pascal OSErr FilteredDirectoryCopy(short srcVRefNum, 418 long srcDirID, 419 ConstStr255Param srcName, 420 short dstVRefNum, 421 long dstDirID, 422 ConstStr255Param dstName, 423 ConstStr255Param copyName, 424 void *copyBufferPtr, 425 long copyBufferSize, 426 Boolean preflight, 427 CopyErrProcPtr copyErrHandler, 428 CopyFilterProcPtr copyFilterProc) 429{ 430 EnumerateGlobals theGlobals; 431 Boolean isDirectory; 432 OSErr error; 433 Boolean ourCopyBuffer = false; 434 Str63 srcDirName, oldDiskName; 435 Boolean spaceOK; 436 437 /* Make sure a copy buffer is allocated. */ 438 if ( copyBufferPtr == NULL ) 439 { 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 ) 446 { 447 copyBufferSize = dirCopyMinCopyBuffSize; 448 copyBufferPtr = NewPtr(copyBufferSize); 449 if ( copyBufferPtr == NULL ) 450 { 451 return ( memFullErr ); 452 } 453 } 454 ourCopyBuffer = true; 455 } 456 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 ) 460 { 461 goto ErrorExit; 462 } 463 if ( !isDirectory ) 464 { 465 error = dirNFErr; 466 goto ErrorExit; 467 } 468 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) ) 473 { 474 dstDirID = fsRtParID; 475 isDirectory = true; 476 error = noErr; 477 } 478 else 479 { 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 ) 483 { 484 goto ErrorExit; 485 } 486 if ( !isDirectory ) 487 { 488 error = dirNFErr; 489 goto ErrorExit; 490 } 491 } 492 493 /* Get the real vRefNum of both the source and destination */ 494 error = DetermineVRefNum(srcName, srcVRefNum, &srcVRefNum); 495 if ( error != noErr ) 496 { 497 goto ErrorExit; 498 } 499 error = DetermineVRefNum(dstName, dstVRefNum, &dstVRefNum); 500 if ( error != noErr ) 501 { 502 goto ErrorExit; 503 } 504 505 if ( preflight ) 506 { 507 error = PreflightDirectoryCopySpace(srcVRefNum, srcDirID, dstVRefNum, copyFilterProc, &spaceOK); 508 if ( error != noErr ) 509 { 510 goto ErrorExit; 511 } 512 if ( !spaceOK ) 513 { 514 error = dskFulErr; /* not enough room on destination */ 515 goto ErrorExit; 516 } 517 } 518 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 ) 523 { 524 goto ErrorExit; 525 } 526 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 ) 531 { 532 /* Get the current name of the destination disk */ 533 error = GetDirName(dstVRefNum, fsRtDirID, oldDiskName); 534 if ( error == noErr ) 535 { 536 /* use the copyName as srcDirName if supplied */ 537 if ( copyName != NULL ) 538 { 539 /* make a copy since copyName is a const input */ 540 BlockMoveData(copyName, srcDirName, sizeof(Str31)); 541 } 542 /* Shorten the name if it's too long to be the volume name */ 543 TruncPString(srcDirName, srcDirName, 27); 544 545 /* Rename the disk */ 546 error = HRename(dstVRefNum, fsRtParID, oldDiskName, srcDirName); 547 548 /* and copy to the root directory */ 549 dstDirID = fsRtDirID; 550 } 551 } 552 else 553 { 554 /* use the copyName as srcDirName if supplied */ 555 error = DirCreate(dstVRefNum, dstDirID, ((copyName != NULL) ? copyName : srcDirName), &dstDirID); 556 } 557 if ( error != noErr ) 558 { 559 /* handle any errors from DirCreate */ 560 if ( copyErrHandler != NULL ) 561 { 562 if ( CallCopyErrProc(copyErrHandler, error, dirCreateOp, 563 srcVRefNum, srcDirID, NULL, 564 dstVRefNum, dstDirID, srcDirName) ) 565 { 566 goto ErrorExit; 567 } 568 else 569 { 570 /* If the CopyErrProc handled the problem, clear the error here */ 571 /* and continue */ 572 error = noErr; 573 } 574 } 575 else 576 { 577 /* If you don't handle the errors with an error handler, */ 578 /* then the copy stops here. */ 579 goto ErrorExit; 580 } 581 } 582 583 /* dstDirID is now the newly created directory! */ 584 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; 594 595 /* Here we go into recursion land... */ 596 CopyLevel(srcDirID, dstDirID, &theGlobals); 597 error = theGlobals.error; /* get the result */ 598 599 if ( !theGlobals.bailout ) 600 { 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); 604 605 /* Copy the File Manager attributes */ 606 error = CopyFileMgrAttributes(srcVRefNum, srcDirID, NULL, 607 dstVRefNum, dstDirID, NULL, true); 608 609 /* handle any errors from CopyFileMgrAttributes */ 610 if ( (error != noErr) && (copyErrHandler != NULL) ) 611 { 612 theGlobals.bailout = CallCopyErrProc(copyErrHandler, error, copyDirFMAttributesOp, 613 srcVRefNum, srcDirID, NULL, 614 dstVRefNum, dstDirID, NULL); 615 } 616 } 617 618ErrorExit: 619 /* Get rid of the copy buffer if we allocated it. */ 620 if ( ourCopyBuffer ) 621 { 622 DisposePtr((Ptr)copyBufferPtr); 623 } 624 625 return ( error ); 626} 627 628/*****************************************************************************/ 629 630pascal OSErr DirectoryCopy(short srcVRefNum, 631 long srcDirID, 632 ConstStr255Param srcName, 633 short dstVRefNum, 634 long dstDirID, 635 ConstStr255Param dstName, 636 ConstStr255Param copyName, 637 void *copyBufferPtr, 638 long copyBufferSize, 639 Boolean preflight, 640 CopyErrProcPtr copyErrHandler) 641{ 642 return ( FilteredDirectoryCopy(srcVRefNum, srcDirID, srcName, 643 dstVRefNum, dstDirID, dstName, 644 copyName, 645 copyBufferPtr, copyBufferSize, preflight, 646 copyErrHandler, NULL) ); 647} 648 649/*****************************************************************************/ 650 651pascal OSErr FSpFilteredDirectoryCopy(const FSSpec *srcSpec, 652 const FSSpec *dstSpec, 653 ConstStr255Param copyName, 654 void *copyBufferPtr, 655 long copyBufferSize, 656 Boolean preflight, 657 CopyErrProcPtr copyErrHandler, 658 CopyFilterProcPtr copyFilterProc) 659{ 660 return ( FilteredDirectoryCopy(srcSpec->vRefNum, srcSpec->parID, srcSpec->name, 661 dstSpec->vRefNum, dstSpec->parID, dstSpec->name, 662 copyName, 663 copyBufferPtr, copyBufferSize, preflight, 664 copyErrHandler, copyFilterProc) ); 665} 666 667/*****************************************************************************/ 668 669pascal OSErr FSpDirectoryCopy(const FSSpec *srcSpec, 670 const FSSpec *dstSpec, 671 ConstStr255Param copyName, 672 void *copyBufferPtr, 673 long copyBufferSize, 674 Boolean preflight, 675 CopyErrProcPtr copyErrHandler) 676{ 677 return ( FilteredDirectoryCopy(srcSpec->vRefNum, srcSpec->parID, srcSpec->name, 678 dstSpec->vRefNum, dstSpec->parID, dstSpec->name, 679 copyName, 680 copyBufferPtr, copyBufferSize, preflight, 681 copyErrHandler, NULL) ); 682} 683 684/*****************************************************************************/ 685 686