]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/morefile/DirectoryCopy.c
better implementation from VZ
[wxWidgets.git] / src / mac / carbon / morefile / DirectoryCopy.c
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
56 enum
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
74 struct 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
90 typedef struct EnumerateGlobals EnumerateGlobals;
91 typedef 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
101 struct 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
118 typedef struct PreflightGlobals PreflightGlobals;
119 typedef PreflightGlobals *PreflightGlobalsPtr;
120
121 /*****************************************************************************/
122
123 /* static prototypes */
124
125 static void GetLevelSize(long currentDirID,
126 PreflightGlobals *theGlobals);
127
128 static OSErr PreflightDirectoryCopySpace(short srcVRefNum,
129 long srcDirID,
130 short dstVRefNum,
131 CopyFilterProcPtr copyFilterProc,
132 Boolean *spaceOK);
133
134 static void CopyLevel(long sourceDirID,
135 long dstDirID,
136 EnumerateGlobals *theGlobals);
137
138 /*****************************************************************************/
139
140 static 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
217 static 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
259 static 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
417 pascal 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
618 ErrorExit:
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
630 pascal 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
651 pascal 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
669 pascal 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