]> git.saurik.com Git - wxWidgets.git/blob - src/mac/morefile/DirectoryCopy.c
Fixed yet another error in my wxCmdLineParser mdifications.
[wxWidgets.git] / src / mac / 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;
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 if ( theGlobals->errorHandler != NULL )
329 {
330 theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, dirCreateOp,
331 theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL,
332 theGlobals->destinationVRefNum, dstDirID, theGlobals->itemName);
333 }
334 else
335 {
336 /* If you don't handle the errors with an error handler, */
337 /* then the copy stops here. */
338 theGlobals->bailout = true;
339 }
340 }
341
342 if ( !theGlobals->bailout )
343 {
344 /* clear error return on way back if we aren't bailing out */
345 theGlobals->error = noErr;
346 }
347 }
348 else
349 {
350 /* We have a file, so copy it */
351
352 theGlobals->error = FileCopy(theGlobals->myCPB.hFileInfo.ioVRefNum,
353 theGlobals->myCPB.hFileInfo.ioFlParID,
354 theGlobals->itemName,
355 theGlobals->destinationVRefNum,
356 dstDirID,
357 NULL,
358 NULL,
359 theGlobals->copyBuffer,
360 theGlobals->bufferSize,
361 false);
362
363 /* handle any errors from FileCopy */
364 if ( theGlobals->error != noErr )
365 {
366 if ( theGlobals->errorHandler != NULL )
367 {
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 )
372 {
373 /* If the CopyErrProc handled the problem, clear the error here */
374 theGlobals->error = noErr;
375 }
376 }
377 else
378 {
379 /* If you don't handle the errors with an error handler, */
380 /* then the copy stops here. */
381 theGlobals->bailout = true;
382 }
383 }
384 }
385 }
386 }
387 else
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 )
391 {
392 if ( theGlobals->errorHandler != NULL )
393 {
394 theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, getNextItemOp,
395 theGlobals->myCPB.dirInfo.ioVRefNum, sourceDirID, NULL, 0, 0, NULL);
396 if ( !theGlobals->bailout )
397 {
398 /* If the CopyErrProc handled the problem, clear the error here */
399 theGlobals->error = noErr;
400 }
401 }
402 else
403 {
404 /* If you don't handle the errors with an error handler, */
405 /* then the copy stops here. */
406 theGlobals->bailout = true;
407 }
408 }
409 }
410 ++index; /* prepare to get next item */
411 } while ( (theGlobals->error == noErr) && (!theGlobals->bailout) ); /* time to fall back a level? */
412 }
413
414 /*****************************************************************************/
415
416 pascal OSErr FilteredDirectoryCopy(short srcVRefNum,
417 long srcDirID,
418 ConstStr255Param srcName,
419 short dstVRefNum,
420 long dstDirID,
421 ConstStr255Param dstName,
422 ConstStr255Param copyName,
423 void *copyBufferPtr,
424 long copyBufferSize,
425 Boolean preflight,
426 CopyErrProcPtr copyErrHandler,
427 CopyFilterProcPtr copyFilterProc)
428 {
429 EnumerateGlobals theGlobals;
430 Boolean isDirectory;
431 OSErr error;
432 Boolean ourCopyBuffer = false;
433 Str63 srcDirName, oldDiskName;
434 Boolean spaceOK;
435
436 /* Make sure a copy buffer is allocated. */
437 if ( copyBufferPtr == NULL )
438 {
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 )
445 {
446 copyBufferSize = dirCopyMinCopyBuffSize;
447 copyBufferPtr = NewPtr(copyBufferSize);
448 if ( copyBufferPtr == NULL )
449 {
450 return ( memFullErr );
451 }
452 }
453 ourCopyBuffer = true;
454 }
455
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 )
459 {
460 goto ErrorExit;
461 }
462 if ( !isDirectory )
463 {
464 error = dirNFErr;
465 goto ErrorExit;
466 }
467
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) )
472 {
473 dstDirID = fsRtParID;
474 isDirectory = true;
475 error = noErr;
476 }
477 else
478 {
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 )
482 {
483 goto ErrorExit;
484 }
485 if ( !isDirectory )
486 {
487 error = dirNFErr;
488 goto ErrorExit;
489 }
490 }
491
492 /* Get the real vRefNum of both the source and destination */
493 error = DetermineVRefNum(srcName, srcVRefNum, &srcVRefNum);
494 if ( error != noErr )
495 {
496 goto ErrorExit;
497 }
498 error = DetermineVRefNum(dstName, dstVRefNum, &dstVRefNum);
499 if ( error != noErr )
500 {
501 goto ErrorExit;
502 }
503
504 if ( preflight )
505 {
506 error = PreflightDirectoryCopySpace(srcVRefNum, srcDirID, dstVRefNum, copyFilterProc, &spaceOK);
507 if ( error != noErr )
508 {
509 goto ErrorExit;
510 }
511 if ( !spaceOK )
512 {
513 error = dskFulErr; /* not enough room on destination */
514 goto ErrorExit;
515 }
516 }
517
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 )
522 {
523 goto ErrorExit;
524 }
525
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 )
530 {
531 /* Get the current name of the destination disk */
532 error = GetDirName(dstVRefNum, fsRtDirID, oldDiskName);
533 if ( error == noErr )
534 {
535 /* use the copyName as srcDirName if supplied */
536 if ( copyName != NULL )
537 {
538 /* make a copy since copyName is a const input */
539 BlockMoveData(copyName, srcDirName, sizeof(Str31));
540 }
541 /* Shorten the name if it's too long to be the volume name */
542 TruncPString(srcDirName, srcDirName, 27);
543
544 /* Rename the disk */
545 error = HRename(dstVRefNum, fsRtParID, oldDiskName, srcDirName);
546
547 /* and copy to the root directory */
548 dstDirID = fsRtDirID;
549 }
550 }
551 else
552 {
553 /* use the copyName as srcDirName if supplied */
554 error = DirCreate(dstVRefNum, dstDirID, ((copyName != NULL) ? copyName : srcDirName), &dstDirID);
555 }
556 if ( error != noErr )
557 {
558 /* handle any errors from DirCreate */
559 if ( copyErrHandler != NULL )
560 {
561 if ( CallCopyErrProc(copyErrHandler, error, dirCreateOp,
562 srcVRefNum, srcDirID, NULL,
563 dstVRefNum, dstDirID, srcDirName) )
564 {
565 goto ErrorExit;
566 }
567 else
568 {
569 /* If the CopyErrProc handled the problem, clear the error here */
570 /* and continue */
571 error = noErr;
572 }
573 }
574 else
575 {
576 /* If you don't handle the errors with an error handler, */
577 /* then the copy stops here. */
578 goto ErrorExit;
579 }
580 }
581
582 /* dstDirID is now the newly created directory! */
583
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;
593
594 /* Here we go into recursion land... */
595 CopyLevel(srcDirID, dstDirID, &theGlobals);
596 error = theGlobals.error; /* get the result */
597
598 if ( !theGlobals.bailout )
599 {
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);
603
604 /* Copy the File Manager attributes */
605 error = CopyFileMgrAttributes(srcVRefNum, srcDirID, NULL,
606 dstVRefNum, dstDirID, NULL, true);
607
608 /* handle any errors from CopyFileMgrAttributes */
609 if ( (error != noErr) && (copyErrHandler != NULL) )
610 {
611 theGlobals.bailout = CallCopyErrProc(copyErrHandler, error, copyDirFMAttributesOp,
612 srcVRefNum, srcDirID, NULL,
613 dstVRefNum, dstDirID, NULL);
614 }
615 }
616
617 ErrorExit:
618 /* Get rid of the copy buffer if we allocated it. */
619 if ( ourCopyBuffer )
620 {
621 DisposePtr((Ptr)copyBufferPtr);
622 }
623
624 return ( error );
625 }
626
627 /*****************************************************************************/
628
629 pascal OSErr DirectoryCopy(short srcVRefNum,
630 long srcDirID,
631 ConstStr255Param srcName,
632 short dstVRefNum,
633 long dstDirID,
634 ConstStr255Param dstName,
635 ConstStr255Param copyName,
636 void *copyBufferPtr,
637 long copyBufferSize,
638 Boolean preflight,
639 CopyErrProcPtr copyErrHandler)
640 {
641 return ( FilteredDirectoryCopy(srcVRefNum, srcDirID, srcName,
642 dstVRefNum, dstDirID, dstName,
643 copyName,
644 copyBufferPtr, copyBufferSize, preflight,
645 copyErrHandler, NULL) );
646 }
647
648 /*****************************************************************************/
649
650 pascal OSErr FSpFilteredDirectoryCopy(const FSSpec *srcSpec,
651 const FSSpec *dstSpec,
652 ConstStr255Param copyName,
653 void *copyBufferPtr,
654 long copyBufferSize,
655 Boolean preflight,
656 CopyErrProcPtr copyErrHandler,
657 CopyFilterProcPtr copyFilterProc)
658 {
659 return ( FilteredDirectoryCopy(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
660 dstSpec->vRefNum, dstSpec->parID, dstSpec->name,
661 copyName,
662 copyBufferPtr, copyBufferSize, preflight,
663 copyErrHandler, copyFilterProc) );
664 }
665
666 /*****************************************************************************/
667
668 pascal OSErr FSpDirectoryCopy(const FSSpec *srcSpec,
669 const FSSpec *dstSpec,
670 ConstStr255Param copyName,
671 void *copyBufferPtr,
672 long copyBufferSize,
673 Boolean preflight,
674 CopyErrProcPtr copyErrHandler)
675 {
676 return ( FilteredDirectoryCopy(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
677 dstSpec->vRefNum, dstSpec->parID, dstSpec->name,
678 copyName,
679 copyBufferPtr, copyBufferSize, preflight,
680 copyErrHandler, NULL) );
681 }
682
683 /*****************************************************************************/
684