1 /* copy t:AmiTCP.#? big: buf=2000000 verbose
2 (C) 2001 AROS - The Amiga Research OS
9 /*****************************************************************************
17 FROM/M, TO, ALL/S, QUIET/S, BUF=BUFFER/K/N, CLONE/S, DATES/S, NOPRO/S,
18 COM=COMMENT/S, NOREQ/S,
20 PAT=PATTERN/K, DIRECT/S,SILENT/S, ERRWARN/S, MAKEDIR/S, MOVE/S,
21 DELETE/S, HARD=HARDLINK/S, SOFT=SOFTLINK/S, FOLNK=FORCELINK/S,
22 FODEL=FORCEDELETE/S, FOOVR=FORCEOVERWRITE/S, DONTOVR=DONTOVERWRITE/S,
31 Creates identical copies of one or more files.
35 FROM -- multiple input files
36 TO -- destination file or directory
37 ALL -- deep scan into sub directories
38 QUIET -- suppress all output and requesters
39 BUFFER -- buffer size for copy buffer in 512 byte blocks
40 (default 1024 (= 512K))
41 CLONE -- copy comment, protection bits and date as well
43 NOPRO -- do not copy protection bits
44 COMMENT -- copy filecomment
45 NOREQ -- suppress requesters
47 PATTERN -- a pattern the filenames must match
48 DIRECT -- copy mode only: copy file without any tests or options
49 VERBOSE -- gives more output
50 ERRWARN -- do not proceed, when one file failed
51 MAKEDIR -- produce directories
52 MOVE -- delete source files after copying successful
53 DELETE -- do not copy, but delete the source files
54 HARDLINK -- make a hardlink to source instead of copying
55 SOFTLINK -- make a softlink to source instead of copying
56 FOLNK -- also makes links to directories
57 FODEL -- delete protected files also
58 FOOVR -- also overwrite protected files
59 DONTOVR -- do never overwrite destination
60 FORCE -- DO NOT USE. Call compatibility only.
63 More detailed descriptions:
66 Source file(s). For directories, all contained files are source files. May
67 have standard patterns.
70 Destination file or for multiple sources destination directory. Destination
71 directories are created (including all needed parent directories).
74 Scan directories recursively
77 Copy is completely silent here. Really no output is given, also no requests
78 for missing disks or other problems!
81 Specify the number of 512 byte buffers for copying. Default are 200 buffers
82 [100KB memory]. One buffer is minimum size, but should never be used.
85 PATTERN allows to specify a standard dos pattern, all file have to match.
86 This is useful with ALL option.
89 When you want to delete all .info files in a directory tree, you need
90 this option: Copy DELETE #? ALL PAT #?.info
93 The filecomment, date and protection bits of the source files are copied to
94 destination file or directory.
97 The date information of source is copied to destination.
100 The protection bits of sources are NOT copied. So the destination gets
104 The filecomment is copied to destination.
107 No standard DOS requests are displayed, when an error occurs.
111 Certain devices do not allow some of the used DOS packet request types.
112 This option is a really easy copy command, which only opens source and
113 destination directly without any tests and checks.
114 Options ALL, PAT, CLONE, DATES, NOPRO, COM, MAKEDIR, MOVE, DELETE, HARD,
115 SOFT, FOLNK, FODEL, FOOVR, DONTOVR and multiple input files cannot be
116 specified together with DIRECT. This options needs one input and one output
118 When you want to delete a softlink, which does no longer point to a valid
119 file, you need this option as well.
120 Example use: 'Copy DIRECT text PRT:' to print a file called text.
121 - Copy manages a lot of such cases automatically, but maybe this option is
125 Copy gives additional output.
128 Copy knows and returns the 3 types of dos.library errors:
129 5 WARN The processing of one file failed, Copy skips this file
130 and proceeds the next.
131 10 ERROR The creation of a directory or any other bad error happend.
132 Copy quits after that.
133 20 FAIL A really hard error happend (No memory, Examine failed, ...)
134 Copy quits after that.
135 When option ERRWARN is used, the result 5 (WARN) gets result 10 (ERROR). So
136 Copy aborts everytime an error occured.
139 All names specified in FROM field are taken as directories, which must be
143 The files are not copied, but moved (or renamed). This means that after
144 move operation the source does no longer exist.
147 This does not copy anything, but delete the source files!
150 Instead of copying the files, a hard link is created. This only works,
151 when destination is on same device as source.
152 When ALL option is specified, the directories are scanned recursively, else
153 Copy produces links to the directories.
156 Instead of copying directories, a soft link is created. These links are
157 useable between different devices also. Soft links are only created for
158 directories. Files are skipped here. Option FORCELINK is therefor always
160 NOTE: Softlinks are not official supported by OS and may be dangerous.
161 I suggest not to use this option! See description below.
164 When linking of directories should be possible, this option is needed. See
165 section "About links" for possible problems.
168 When this option is enabled, files are deleted also, when they are delete
171 FOOVR=FORCEOVERWRITE:
172 When this option is enabled, files are overwritten also, when they are
175 DONTOVR=DONTOVERWRITE:
176 This option prevents overwriting of destination files.
189 Delete, Rename, MakeDir, MakeLink
193 The separation of the different switches above is according to
194 what the AmigaDOS Copy command had, and the extensions respectively.
196 Some comments on how the program does it's job:
198 The program has 6 working modes: COPY, MOVE, SOFTLINK, HARDLINK,
199 DELETE and MAKEDIR. Only one of these can be used at same time!
201 Move option renames the files, when on same device, else the file
202 is copied and the source deleted after that.
203 When a directory is processed and on the same device it is
204 renamed! This means MOVE option copies complete directories also
205 without ALL option (when on same device).
207 In Copy mode you may use f.e. "Copy C: RAM:K" instead of
208 "Copy C:#? RAM:K". For the other modes this does not work!
210 Destination files are always overwritten, except DONTOVERWRITE is
211 turned on, or they are protected.
213 When the destination directory does not exists, it is created.
214 Existing files with same name are overwritten. When some parent
215 directories do not exist, they are also created. This is also done,
216 when only one file is copied.
218 The program does a loop detection, so that copying/moving/linking
219 with a sub directory of source as destination and ALL option is not
222 Example: Copy RAM:S RAM:S/C ALL
225 Useful aliases you may add to S:User-StartUp:
227 Alias Delete Copy [] DELETE VERBOSE
228 Alias MakeDir Copy [] MAKEDIR
229 Alias MakeLink Copy TO [] HARDLINK
230 Alias Move Copy [] MOVE CLONE VERBOSE
231 Alias Rename Copy [] MOVE CLONE
233 Some programs do want the files to be in C: directory. For these
234 you may additionally use following lines:
236 Alias C:Delete Copy [] DELETE VERBOSE
237 Alias C:MakeDir Copy [] MAKEDIR
238 Alias C:MakeLink Copy TO [] HARDLINK
239 Alias C:Rename Copy [] MOVE CLONE
245 When copying one file to annother place on same disk, the file
246 afterwards uses double space. Links are a method to resolve that
247 problem. When using a link, the file is not copied, but only a new
248 entry to the same data as created. This saves space and allows to
249 have copies of files always up-to-date (as when on link is updated,
250 all the others are new as well).
253 This is a link method, which is NOT official supported by the OS.
254 Soft links do not need to be on the same partition. The may be used
255 for references between different partitions. NOTE: Using this links
256 may cause lots of problems. You may test for yourself if it works for
260 Links to directories may cause infinite directory loops!
262 Example: Having following directory tree:
268 Some loops are detected, for example when trying to do:
269 MakeLink DEV:A/C DEV:A FORCE
270 Here you get an error message, that loops are not allowed.
272 Some more complicated links cannot be detected:
273 MakeLink DEV:A/C DEV:B FORCE
275 MakeLink DEV:B/C DEV:A FORCE
276 Till now no error message is possible, so the result is an infinite
282 Copy was done by Dirk Stoecker (stoecker@amigaworld.com), donated
283 to AROS in March 2001
285 3.3.2001 -- AROSified by Johan 'S.Duvan' Alfredsson
286 29.7.2002 -- Fixed silly IoErr trashing bug, bumped to 50.1 - Piru
287 7.11.2002 -- Fixed even silier bug where it would put out a bogus
288 errormessage when the copy destination was a volume
289 root. bumped to 50.2 - Piru
291 ******************************************************************************/
293 static const char version
[] = "\0$VER: Copy 50.14 (27.11.2004) © AROS";
295 #define CTRL_C (SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
300 #warning "FIXME: Not trusting softlinks in AROS DOS!"
301 #define USE_SOFTLINKCHECK 0
303 #define USE_SOFTLINKCHECK 1
306 #define USE_ALWAYSVERBOSE 1
307 #define USE_BOGUSEOFWORKAROUND 0
309 #include <exec/devices.h>
311 #include <exec/memory.h>
312 #include <exec/semaphores.h>
313 #include <exec/types.h>
314 #include <dos/exall.h>
319 #include <aros/debug.h>
322 #include <proto/dos.h>
323 #include <proto/exec.h>
329 static const UBYTE
*PARAM
=
330 "FROM/M,TO,PAT=PATTERN/K,BUF=BUFFER/K/N,ALL/S,"
331 "DIRECT/S,CLONE/S,DATES/S,NOPRO/S,COM=COMMENT/S,"
333 #if !USE_ALWAYSVERBOSE
336 "NOREQ/S,ERRWARN/S,MAKEDIR/S,"
337 "MOVE/S,DELETE/S,HARD=HARDLINK/S,SOFT=SOFTLINK/S,"
338 "FOLNK=FORCELINK/S,FODEL=FORCEDELETE/S,"
339 "FOOVR=FORCEOVERWRITE/S,DONTOVR=DONTOVERWRITE/S,"
342 #define COPYFLAG_ALL (1<<0)
343 #define COPYFLAG_DATES (1<<1)
344 #define COPYFLAG_NOPRO (1<<2)
345 #define COPYFLAG_COMMENT (1<<3)
346 #define COPYFLAG_FORCELINK (1<<4)
347 #define COPYFLAG_FORCEDELETE (1<<5)
348 #define COPYFLAG_FORCEOVERWRITE (1<<6)
349 #define COPYFLAG_DONTOVERWRITE (1<<7)
350 #define COPYFLAG_QUIET (1<<8)
351 #define COPYFLAG_VERBOSE (1<<9)
352 #define COPYFLAG_ERRWARN (1<<10)
353 #define COPYFLAG_PROTECTION (1<<11)
355 #define COPYFLAG_SOFTLINK (1<<20) /* produce softlinks */
356 #define COPYFLAG_DEST_FILE (1<<21) /* one file mode */
357 #define COPYFLAG_DONE (1<<22) /* did something in DoWork */
358 #define COPYFLAG_ENTERSECOND (1<<23) /* entered directory second time */
360 #define COPYFLAG_SRCNOFILESYS (1<<24) /* source is no filesystem */
361 #define COPYFLAG_DESNOFILESYS (1<<25) /* destination is no filesystem */
363 #define COPYMODE_COPY 0
364 #define COPYMODE_MOVE 1
365 #define COPYMODE_DELETE 2
366 #define COPYMODE_MAKEDIR 3
367 #define COPYMODE_LINK 4
369 #define PRINTOUT_SIZE 50 /* maximum size of name printout */
370 #define PRINTOUT_SPACES 10 /* maximum number of spaces */
372 #define FILEPATH_SIZE 2048 /* maximum size of filepaths */
375 #define TESTDEST_DIR_OK 2 /* directory exists, go in */
376 #define TESTDEST_DELETED 1 /* file or empty directory deleted */
377 #define TESTDEST_NONE 0 /* nothing existed */
378 #define TESTDEST_ERROR -1 /* an error occured */
379 #define TESTDEST_CANTDELETE -2 /* deletion not allowed (DONTOV) */
394 #if !USE_ALWAYSVERBOSE
443 struct ExecBase
*SysBase
;
444 struct DosLibrary
*DOSBase
;
450 BPTR CurDest
; /* Current Destination */
452 struct FileInfoBlock Fib
;
454 UBYTE RetVal
; /* when set, error output is already done */
455 UBYTE RetVal2
; /* when set, error output must be done */
457 UBYTE FileName
[FILEPATH_SIZE
];
458 UBYTE DestName
[FILEPATH_SIZE
];
464 #define TEXT_READ texts[0]
465 #define TEXT_COPIED texts[1]
466 #define TEXT_MOVED texts[2]
467 #define TEXT_DELETED texts[3]
468 #define TEXT_LINKED texts[4]
469 #define TEXT_RENAMED texts[5]
470 #define TEXT_CREATED texts[6]
471 #define TEXT_ENTERED texts[7]
472 #define TEXT_OPENED_FOR_OUTPUT texts[8]
473 #define TEXTNUM_MODE 9
474 #define TEXT_DIRECTORY texts[15]
475 #define TEXT_NOT_DONE texts[16]
476 #define TEXT_NOTHING_DONE texts[17]
477 #define TEXT_ERR_FORCELINK texts[18]
478 #define TEXT_ERR_DELETE_DEVICE texts[19]
479 #define TEXT_ERR_DEST_DIR texts[20]
480 #define TEXT_ERR_INFINITE_LOOP texts[21]
481 #define TEXT_ERR_WILDCARD_DEST texts[22]
483 const CONST_STRPTR texts
[] =
500 "%s (Dir)", /* output of directories */
502 "No file was processed.\n",
503 "FORCELINK keyword required.\n",
504 "A device cannot be deleted.",
505 "Destination must be a directory.\n",
506 "Infinite loop not allowed.\n",
507 "Wildcard destination invalid.\n",
510 LONG
CopyFile(BPTR
, BPTR
, ULONG
, struct CopyData
*);
511 void DoWork(STRPTR
, struct CopyData
*);
512 LONG
IsMatchPattern(STRPTR name
, struct CopyData
*cd
);
513 LONG
IsPattern(STRPTR
, struct CopyData
*); /* return 0 -> NOPATTERN, return -1 --> ERROR */
514 LONG
KillFile(STRPTR
, ULONG
, struct CopyData
*);
515 LONG
KillFileKeepErr(STRPTR name
, ULONG doit
, struct CopyData
*);
516 LONG
LinkFile(BPTR
, STRPTR
, ULONG
, struct CopyData
*);
517 BPTR
OpenDestDir(STRPTR
, struct CopyData
*);
518 void PatCopy(STRPTR
, struct CopyData
*);
519 void PrintName(CONST_STRPTR
, ULONG
, ULONG
, ULONG
, struct CopyData
*);
520 void PrintNotDone(CONST_STRPTR
, CONST_STRPTR
, ULONG
, ULONG
, struct CopyData
*);
521 ULONG
TestFileSys(STRPTR
, struct CopyData
*); /* returns value, when is a filesystem */
522 void SetData(STRPTR
, struct CopyData
*);
523 LONG
TestDest(STRPTR
, ULONG
, struct CopyData
*);
524 ULONG
TestLoop(BPTR
, BPTR
, struct CopyData
*);
529 struct ExecBase
*SysBase
;
530 struct DosLibrary
*DOSBase
;
532 struct Process
*task
;
534 int retval
= RETURN_FAIL
;
537 SysBase
=*((struct ExecBase
**) 4);
540 /* test for WB and reply startup-message */
541 if (!(task
= (struct Process
*)FindTask(NULL
))->pr_CLI
)
543 WaitPort(&task
->pr_MsgPort
);
545 ReplyMsg(GetMsg(&task
->pr_MsgPort
));
551 DOSBase
= (struct DosLibrary
*)OpenLibrary("dos.library", 37);
553 cd
= AllocMem(sizeof(*cd
), MEMF_PUBLIC
| MEMF_CLEAR
);
557 STRPTR a
[2] = { "", 0 };
559 struct IptrArgs iArgs
;
562 cd
->SysBase
= SysBase
;
563 cd
->DOSBase
= DOSBase
;
564 #define SysBase cd->SysBase
565 #define DOSBase cd->DOSBase
567 cd
->BufferSize
= 512*1024;
568 cd
->Mode
= COPYMODE_COPY
;
569 cd
->RetVal2
= RETURN_FAIL
;
572 memset(&iArgs
, 0, sizeof(struct IptrArgs
));
574 rda
= (struct RDArgs
*)AllocDosObject(DOS_RDARGS
, NULL
);
578 "FROM multiple input files\n"
579 "TO destination file or directory\n"
580 "PATTERN a pattern the filenames must match\n"
581 "BUFFER buffersize for copy buffer (default 200 [100K])\n"
582 "ALL deep scan into sub directories\n"
583 "DIRECT copy/delete only: work without any tests or options\n"
584 "CLONE copy comment, protection bits and date as well\n"
586 "NOPRO do not copy protection bits\n"
587 "COMMENT copy filecomment\n"
588 "QUIET suppress all output and requesters\n"
589 #if !USE_ALWAYSVERBOSE
590 "VERBOSE give additional output\n"
592 "NOREQ suppress requesters\n"
593 "ERRWARN do not proceed, when one file failed\n"
594 "MAKEDIR produce directories\n"
595 "MOVE delete source files after copying successful\n"
596 "DELETE do not copy, but delete the source files\n"
597 "HARDLINK make a hardlink to source instead of copying\n"
598 "SOFTLINK make a softlink to source instead of copying\n"
599 "FOLNK also makes links to directories\n"
600 "FODEL delete protected files also\n"
601 "FOOVR also overwrite protected files\n"
602 "DONTOVR do never overwrite destination\n"
603 "FORCE DO NOT USE. Call compatibility only.\n";
605 if (ReadArgs(PARAM
, (IPTR
*)&iArgs
, rda
))
607 ULONG patbufsize
= 0;
609 APTR win
= task
->pr_WindowPtr
;
611 args
.from
= (STRPTR
*)iArgs
.from
;
612 args
.to
= (STRPTR
)iArgs
.to
;
613 args
.pattern
= (STRPTR
)iArgs
.pattern
;
614 args
.buffer
= (LONG
*)iArgs
.buffer
;
615 args
.all
= (LONG
)iArgs
.all
;
616 args
.direct
= (LONG
)iArgs
.direct
;
617 args
.clone
= (LONG
)iArgs
.clone
;
618 args
.dates
= (LONG
)iArgs
.dates
;
619 args
.nopro
= (LONG
)iArgs
.nopro
;
620 args
.comment
= (LONG
)iArgs
.comment
;
621 args
.quiet
= (LONG
)iArgs
.quiet
;
622 #if USE_ALWAYSVERBOSE
623 args
.verbose
= FALSE
;
625 args
.verbose
= (LONG
)iArgs
.verbose
;
627 args
.noreq
= (LONG
)iArgs
.noreq
;
628 args
.errwarn
= (LONG
)iArgs
.errwarn
;
629 args
.makedir
= (LONG
)iArgs
.makedir
;
630 args
.move_mode
= (LONG
)iArgs
.move_mode
;
631 args
.delete_mode
= (LONG
)iArgs
.delete_mode
;
632 args
.hardlink
= (LONG
)iArgs
.hardlink
;
633 args
.softlink
= (LONG
)iArgs
.softlink
;
634 args
.forcelink
= (LONG
)iArgs
.forcelink
;
635 args
.forcedelete
= (LONG
)iArgs
.forcedelete
;
636 args
.forceoverwrite
= (LONG
)iArgs
.forceoverwrite
;
637 args
.dontoverwrite
= (LONG
)iArgs
.dontoverwrite
;
638 args
.force
= (LONG
)iArgs
.force
;
640 if (args
.quiet
) /* when QUIET, SILENT and NOREQ are also
643 /* Original doesn't hide requesters with QUIET */
645 args
.verbose
= FALSE
;
648 if (args
.buffer
&& *args
.buffer
> 0) /* minimum buffer size */
650 cd
->BufferSize
= *args
.buffer
* 512;
655 cd
->Flags
|= COPYFLAG_QUIET
;
658 #if !USE_ALWAYSVERBOSE
661 cd
->Flags
|= COPYFLAG_VERBOSE
;
666 cd
->Flags
|= COPYFLAG_ALL
;
669 /* 12-jul-03 bugfix: always copy protection flags! -Piru */
670 cd
->Flags
|= COPYFLAG_PROTECTION
;
673 cd
->Flags
|= COPYFLAG_DATES
| COPYFLAG_COMMENT
| COPYFLAG_PROTECTION
;
678 cd
->Flags
|= COPYFLAG_DATES
;
683 cd
->Flags
|= COPYFLAG_COMMENT
;
688 cd
->Flags
|= COPYFLAG_NOPRO
;
693 cd
->Flags
|= COPYFLAG_FORCELINK
;
696 if (args
.forcedelete
)
698 cd
->Flags
|= COPYFLAG_FORCEDELETE
;
701 if (args
.forceoverwrite
)
703 cd
->Flags
|= COPYFLAG_FORCEOVERWRITE
;
706 if (args
.dontoverwrite
)
708 cd
->Flags
|= COPYFLAG_DONTOVERWRITE
;
713 cd
->Flags
|= COPYFLAG_ERRWARN
;
716 if (args
.force
) /* support OS Delete and MakeLink command
719 if (args
.delete_mode
)
721 cd
->Flags
|= COPYFLAG_FORCEDELETE
;
724 if (args
.hardlink
|| args
.softlink
)
726 cd
->Flags
|= COPYFLAG_FORCELINK
;
730 if (!args
.from
) /* no args.from means currentdir */
735 if (args
.noreq
) /* no dos.library requests allowed */
737 task
->pr_WindowPtr
= (APTR
)-1;
740 if (args
.delete_mode
)
743 cd
->Mode
= COPYMODE_DELETE
;
749 cd
->Mode
= COPYMODE_MOVE
;
755 cd
->Mode
= COPYMODE_MAKEDIR
;
761 cd
->Mode
= COPYMODE_LINK
;
767 cd
->Mode
= COPYMODE_LINK
;
768 cd
->Flags
|= COPYFLAG_SOFTLINK
| COPYFLAG_FORCELINK
;
772 #warning "CHECKME: Is this still needed?"
773 if (*args
.from
== NULL
)
775 PutStr("No arguments specified\n");
777 FreeDosObject(DOS_RDARGS
, rda
);
782 if (cd
->Mode
!= COPYMODE_DELETE
&&
783 cd
->Mode
!= COPYMODE_MAKEDIR
&& !args
.to
)
785 if (*(args
.from
+ 1)) /* when no TO is specified, the arg
787 { /* one of from. Copy this argument into */
788 STRPTR
*a
; /* args.to */
799 #if USE_ALWAYSVERBOSE
801 /* Only do this if quiet isn't set - bigfoot */
804 /* If more than two args, be verbose... - Piru */
805 if (args
.from
[0] && args
.from
[1])
808 cd
->Flags
|= COPYFLAG_VERBOSE
;
811 /* If any of the sources is a pattern, be verbose... - Piru */
815 for (a
= args
.from
; *a
; a
++)
817 if (IsMatchPattern(*a
, cd
) != 0)
820 cd
->Flags
|= COPYFLAG_VERBOSE
;
827 /* test if more than one of the above four or any other wrong
831 (args
.from
== a
&& cd
->Mode
== COPYMODE_MAKEDIR
) ||
832 (args
.direct
&& (args
.from
== a
|| !*args
.from
||
834 (cd
->Flags
& ~(COPYFLAG_QUIET
| COPYFLAG_VERBOSE
| COPYFLAG_ERRWARN
)) ||
835 (cd
->Mode
!= COPYMODE_DELETE
&& (cd
->Mode
!= COPYMODE_COPY
||
836 !args
.to
|| args
.from
[1])))) ||
837 (args
.dontoverwrite
&& args
.forceoverwrite
) ||
838 /* (args.nopro && args.clone) ||*/ /* Ignore, like original - Piru */
839 (args
.softlink
&& args
.all
) ||
840 (!args
.to
&& cd
->Mode
!= COPYMODE_DELETE
&& cd
->Mode
!= COPYMODE_MAKEDIR
))
842 SetIoErr(ERROR_TOO_MANY_ARGS
);
844 else if (cd
->Mode
== COPYMODE_MAKEDIR
)
848 cd
->RetVal2
= RETURN_OK
;
850 #if !USE_ALWAYSVERBOSE
853 PutStr(texts
[TEXTNUM_MODE
+ COPYMODE_MAKEDIR
]);
857 while (!cd
->RetVal
&& !cd
->RetVal2
&& *args
.from
)
859 if ((i
= IsPattern(*args
.from
, cd
)))
863 cd
->RetVal
= RETURN_ERROR
;
867 PutStr(TEXT_ERR_WILDCARD_DEST
);
872 cd
->RetVal2
= RETURN_FAIL
;
876 if ((dir
= OpenDestDir(*args
.from
, cd
)))
879 cd
->Flags
|= COPYFLAG_DONE
;
884 } /* cd->Mode == COPYMODE_MAKEDIR */
885 else if (args
.direct
)
887 if (cd
->Mode
== COPYMODE_COPY
)
891 if ((in
= Open(*args
.from
, MODE_OLDFILE
)))
893 if ((out
= Open(args
.to
, MODE_NEWFILE
)))
895 cd
->RetVal2
= CopyFile(in
, out
, cd
->BufferSize
, cd
);
902 else /* COPYMODE_DELETE */
906 KillFile(*(args
.from
++), cd
->Flags
& COPYFLAG_FORCEDELETE
, cd
);
909 cd
->RetVal2
= RETURN_OK
;
914 if (args
.pattern
&& *args
.pattern
)
916 patbufsize
= (strlen(args
.pattern
) << 1) + 3;
918 if ((cd
->Pattern
= (STRPTR
)AllocMem(patbufsize
,
921 if (ParsePatternNoCase(args
.pattern
, cd
->Pattern
,
924 FreeMem(cd
->Pattern
, patbufsize
);
930 if (1) // (cd->Fib = (struct FileInfoBlock *)AllocDosObject(DOS_FIB, NULL)))
932 #if !USE_ALWAYSVERBOSE
935 PutStr(texts
[TEXTNUM_MODE
+ cd
->Mode
+
936 (cd
->Flags
& COPYFLAG_SOFTLINK
? 1 : 0)]);
939 if (args
.pattern
&& !cd
->Pattern
)
943 SetIoErr(ERROR_BAD_TEMPLATE
);
946 else if (cd
->Mode
== COPYMODE_DELETE
)
948 cd
->RetVal2
= RETURN_OK
;
950 while (cd
->RetVal
<= (args
.errwarn
? RETURN_OK
: RETURN_WARN
)
953 PatCopy(*(args
.from
++), cd
);
956 else if ((i
= IsPattern(args
.to
, cd
)))
960 cd
->RetVal
= RETURN_ERROR
;
964 PutStr(TEXT_ERR_WILDCARD_DEST
);
972 if (*(path
= PathPart(args
.to
)) == '/')
974 ++path
; /* is destination a path description ? */
977 if (*path
&& !*(args
.from
+1) &&
978 !(i
= IsMatchPattern(*args
.from
, cd
)))
983 /* is destination an existing directory */
984 if ((lock
= Lock(args
.to
, SHARED_LOCK
)))
986 if (Examine(lock
, &cd
->Fib
))
988 if (cd
->Fib
.fib_DirEntryType
> 0)
990 cd
->RetVal2
= RETURN_OK
;
993 /* indicate dir-mode for next if */
1003 /* Some magic to handle tick quoted pattern object names. Quite crude way to
1004 * handle it, but I couldn't think of anything better. - Piru
1007 if (!i
&& cd
->RetVal2
&& !IsMatchPattern(*args
.from
, cd
))
1012 //Printf("pattern check <%s>\n", *args.from);
1014 len
= (strlen(*args
.from
) << 1) + 3;
1016 if ((pat
= (STRPTR
)AllocMem(len
,
1019 if (ParsePattern(*args
.from
, pat
, len
) > -1 &&
1020 strlen(pat
) <= strlen(*args
.from
))
1022 lock
= Lock(pat
, SHARED_LOCK
);
1027 strcpy(*args
.from
, pat
);
1036 /* is source a directory */
1037 if (!i
&& cd
->RetVal2
&&
1038 (lock
= Lock(*args
.from
, SHARED_LOCK
)))
1040 if (Examine(lock
, &cd
->Fib
))
1042 cd
->RetVal2
= RETURN_OK
;
1043 if (cd
->Mode
!= COPYMODE_COPY
||
1044 cd
->Fib
.fib_DirEntryType
< 0)
1048 cd
->Flags
|= COPYFLAG_DEST_FILE
;
1050 /* produce missing destination directories */
1054 if ((cd
->CurDest
= OpenDestDir(args
.to
, cd
)))
1061 CopyMem(*args
.from
, cd
->FileName
,
1062 1 + strlen(*args
.from
));
1063 DoWork(FilePart(args
.to
), cd
); /* on file call */
1064 UnLock(cd
->CurDest
);
1075 lockioerr
= IoErr(); /* We save ioerr here, because TestFileSys changes it */
1077 if (lock
== 0 && cd
->Mode
== COPYMODE_COPY
&& !TestFileSys(*args
.from
, cd
))
1080 cd
->Flags
|= COPYFLAG_DEST_FILE
| COPYFLAG_SRCNOFILESYS
;
1081 cd
->RetVal2
= RETURN_OK
;
1083 /* produce missing destination directories */
1087 if ((cd
->CurDest
= OpenDestDir(args
.to
, cd
)))
1092 CopyMem(*args
.from
, cd
->FileName
, 1 + strlen(*args
.from
));
1093 DoWork(FilePart(args
.to
), cd
); /* on file call */
1094 UnLock(cd
->CurDest
);
1098 SetIoErr(lockioerr
);
1102 cd
->RetVal2
= RETURN_OK
;
1105 if (!cd
->RetVal
&& !cd
->RetVal2
&& !(cd
->Flags
& COPYFLAG_DEST_FILE
) &&
1106 (cd
->Destination
= OpenDestDir(args
.to
, cd
)))
1108 while (cd
->RetVal
<= (args
.errwarn
? RETURN_OK
: RETURN_WARN
)
1109 && *args
.from
&& !CTRL_C
)
1111 PatCopy(*(args
.from
++), cd
);
1114 UnLock(cd
->Destination
);
1118 if (!(cd
->Flags
& COPYFLAG_DONE
) && args
.verbose
&&
1119 !cd
->RetVal
&& !cd
->RetVal2
)
1121 PutStr(TEXT_NOTHING_DONE
);
1128 FreeMem(cd
->Pattern
, patbufsize
);
1132 task
->pr_WindowPtr
= win
;
1137 FreeDosObject(DOS_RDARGS
, rda
);
1138 } /* AllocDosObject */
1140 if (!cd
->RetVal2
&& CTRL_C
)
1142 SetIoErr(ERROR_BREAK
);
1143 cd
->RetVal2
= RETURN_WARN
;
1146 if (cd
->RetVal2
&& !args
.quiet
&& !cd
->RetVal
)
1148 PrintFault(IoErr(), NULL
);
1153 cd
->RetVal2
= cd
->RetVal
;
1156 if (args
.errwarn
&& cd
->RetVal2
== RETURN_WARN
)
1158 cd
->RetVal2
= RETURN_ERROR
;
1163 FreeMem(cd
->CopyBuf
, cd
->CopyBufLen
);
1171 retval
= cd
->RetVal2
;
1172 FreeMem(cd
, sizeof(*cd
));
1176 PrintFault(IoErr(), NULL
);
1181 CloseLibrary((struct Library
*)DOSBase
);
1187 #define SysBase cd->SysBase
1188 #define DOSBase cd->DOSBase
1190 void PatCopy(STRPTR name
, struct CopyData
*cd
)
1192 struct AnchorPath
*APath
;
1193 ULONG retval
, doit
= 0, deep
= 0, failval
= RETURN_WARN
, first
= 0;
1196 Printf("PatCopy(%s, .)\n", name
);
1199 if ((cd
->Mode
== COPYMODE_COPY
|| (cd
->Flags
& COPYFLAG_ALL
)) && !IsMatchPattern(name
, cd
))
1201 first
= 1; /* enter first directory (support of old copy style) */
1204 if (cd
->Flags
& COPYFLAG_ERRWARN
)
1206 failval
= RETURN_OK
;
1209 cd
->CurDest
= cd
->Destination
;
1210 cd
->DestPathSize
= 0;
1212 if (cd
->Mode
== COPYMODE_COPY
&& !TestFileSys(name
, cd
))
1214 cd
->Flags
|= COPYFLAG_SRCNOFILESYS
;
1215 CopyMem(name
, cd
->FileName
, 1 + strlen(name
));
1216 DoWork(FilePart(name
), cd
);
1217 cd
->Flags
&= ~COPYFLAG_SRCNOFILESYS
;
1222 if ((APath
= (struct AnchorPath
*)AllocMem(sizeof(struct AnchorPath
) + FILEPATH_SIZE
,
1223 MEMF_PUBLIC
| MEMF_CLEAR
)))
1225 int parentdirerr
= 0;
1227 APath
->ap_BreakBits
= SIGBREAKF_CTRL_C
;
1228 APath
->ap_Strlen
= FILEPATH_SIZE
;
1230 for (retval
= MatchFirst(name
, APath
);
1231 !retval
&& cd
->RetVal
<= failval
&& !cd
->RetVal2
;
1232 retval
= MatchNext(APath
)
1237 //Printf("ParentDir() fuxored last round! Would copy next files to SYS: !\n");
1240 SetIoErr(retval
= ERROR_INVALID_LOCK
);
1246 DoWork(cd
->Fib
.fib_FileName
, cd
);
1250 if (deep
) /* used for Deep checking */
1256 cd
->Flags
&= ~COPYFLAG_ENTERSECOND
;
1258 CopyMem(APath
->ap_Buf
, cd
->FileName
, FILEPATH_SIZE
);
1259 CopyMem(&APath
->ap_Info
, &cd
->Fib
, sizeof(struct FileInfoBlock
));
1261 if (first
&& APath
->ap_Info
.fib_DirEntryType
> 0)
1263 #if USE_ALWAYSVERBOSE
1264 /* If the source is a directory, be verbose - Piru */
1265 cd
->Flags
|= COPYFLAG_VERBOSE
;
1267 APath
->ap_Flags
|= APF_DODIR
;
1269 else if (APath
->ap_Flags
& APF_DIDDIR
)
1273 cd
->Flags
|= COPYFLAG_ENTERSECOND
;
1274 APath
->ap_Flags
&= ~APF_DIDDIR
;
1277 if (cd
->Mode
== COPYMODE_DELETE
|| cd
->Mode
== COPYMODE_MOVE
)
1282 if ((i
= cd
->CurDest
))
1284 cd
->CurDest
= ParentDir(i
);
1285 cd
->DestPathSize
= 0;
1287 if (i
!= cd
->Destination
)
1299 else if (APath
->ap_Info
.fib_DirEntryType
> 0)
1303 if (cd
->Flags
& COPYFLAG_ALL
)
1305 #if USE_SOFTLINKCHECK
1310 dirlock
= CurrentDir(APath
->ap_Current
->an_Lock
);
1311 lock
= Lock(APath
->ap_Info
.fib_FileName
, ACCESS_READ
);
1316 struct DevProc
*dvp
;
1317 LONG ioerr
= IoErr();
1319 if (ioerr
== ERROR_OBJECT_NOT_FOUND
&&
1320 (dvp
= GetDeviceProc("", NULL
)))
1322 #define BUFFERSIZE 512
1323 UBYTE
*buffer
= AllocMem(BUFFERSIZE
, MEMF_PUBLIC
);
1327 if (ReadLink(dvp
->dvp_Port
, dvp
->dvp_Lock
, APath
->ap_Info
.fib_FileName
, buffer
, BUFFERSIZE
- 1) > 0)
1329 if (!(cd
->Flags
& COPYFLAG_QUIET
))
1331 buffer
[BUFFERSIZE
- 1] = '\0';
1333 Printf("Warning: Skipping dangling softlink %s -> %s\n",
1334 APath
->ap_Info
.fib_FileName
, buffer
);
1340 FreeMem(buffer
, BUFFERSIZE
);
1343 FreeDeviceProc(dvp
);
1348 CurrentDir(dirlock
);
1352 APath
->ap_Flags
|= APF_DODIR
;
1356 #else /* USE_SOFTLINKCHECK */
1358 APath
->ap_Flags
|= APF_DODIR
;
1361 #endif /* USE_SOFTLINKCHECK */
1364 else if (!cd
->Pattern
|| MatchPatternNoCase(cd
->Pattern
, APath
->ap_Info
.fib_FileName
))
1374 if (retval
&& retval
!= ERROR_NO_MORE_ENTRIES
)
1376 LONG ioerr
= IoErr();
1377 #if USE_ALWAYSVERBOSE
1378 cd
->Flags
|= COPYFLAG_VERBOSE
;
1380 Printf("%s - ", name
);
1381 PrintFault(ioerr
, NULL
);
1384 cd
->RetVal2
= RETURN_FAIL
;
1389 DoWork(cd
->Fib
.fib_FileName
, cd
);
1392 /* No need to clear the flags here, as they are cleared on next PatJoin
1393 call (DoWork is not called first round, as lock is zero!). */
1395 FreeMem(APath
, sizeof(struct AnchorPath
) + FILEPATH_SIZE
);
1399 cd
->RetVal
= RETURN_FAIL
;
1401 if (!cd
->Flags
& COPYFLAG_QUIET
)
1403 PrintFault(ERROR_NO_FREE_STORE
, NULL
);
1407 if (cd
->CurDest
&& cd
->CurDest
!= cd
->Destination
)
1409 UnLock(cd
->CurDest
);
1414 LONG
IsPattern(STRPTR name
, struct CopyData
*cd
)
1419 a
= (strlen(name
) << 1) + 3;
1421 if ((buffer
= (STRPTR
)AllocMem(a
, MEMF_ANY
)))
1423 ret
= ParsePattern(name
, buffer
, a
);
1429 SetIoErr(ERROR_NO_FREE_STORE
);
1436 LONG
IsMatchPattern(STRPTR name
, struct CopyData
*cd
)
1438 struct AnchorPath ap
;
1441 ap
.ap_BreakBits
= 0;
1442 ap
.ap_Flags
= APF_DOWILD
;
1445 if (MatchFirst(name
, &ap
) == 0)
1447 ret
= (ap
.ap_Flags
& APF_ITSWILD
) ? TRUE
: FALSE
;
1456 LONG
KillFile(STRPTR name
, ULONG doit
, struct CopyData
*cd
)
1460 SetProtection(name
, 0);
1463 return DeleteFile(name
);
1467 LONG
KillFileKeepErr(STRPTR name
, ULONG doit
, struct CopyData
*cd
)
1472 ret
= KillFile(name
, doit
, cd
);
1479 BPTR
OpenDestDir(STRPTR name
, struct CopyData
*cd
)
1481 LONG a
, err
= 0, cr
= 0;
1486 if ((cd
->Mode
== COPYMODE_COPY
|| cd
->Mode
== COPYMODE_MOVE
) && !TestFileSys(name
, cd
))
1488 cd
->Flags
|= COPYFLAG_DESNOFILESYS
;
1489 CopyMem(name
, cd
->DestName
, 1 + strlen(name
));
1491 return Lock("", SHARED_LOCK
);
1494 while (!err
&& *ptr
!= 0)
1496 while (*ptr
&& *ptr
!= '/')
1504 if ((a
= TestDest(name
, 1, cd
)) == TESTDEST_CANTDELETE
)
1506 if (!(cd
->Flags
& COPYFLAG_QUIET
))
1508 PutStr(TEXT_ERR_DEST_DIR
);
1517 else if (a
!= TESTDEST_DIR_OK
)
1519 if ((dir
= CreateDir(name
)))
1523 if ((cd
->Flags
& COPYFLAG_VERBOSE
))
1525 PrintName(name
, 1, 1, 1, cd
);
1526 Printf("%s\n", TEXT_CREATED
);
1533 if (!(cd
->Flags
& COPYFLAG_QUIET
))
1535 PrintNotDone(name
, TEXT_CREATED
, 1, 1, cd
);
1544 /* 26-Oct-2003 bugfix: Don't scan past end of the string.
1545 * as is the old char, if '\0' we've reached the end of the
1556 cd
->RetVal
= RETURN_ERROR
;
1558 if (!(cd
->Flags
& COPYFLAG_QUIET
) && err
== 1)
1560 PrintNotDone(name
, TEXT_OPENED_FOR_OUTPUT
, 1, 1, cd
);
1566 if (cd
->Mode
== COPYMODE_MAKEDIR
&& !cr
&& !(cd
->Flags
& COPYFLAG_QUIET
))
1568 SetIoErr(ERROR_OBJECT_EXISTS
);
1569 PrintNotDone(name
, TEXT_CREATED
, 1, 1, cd
);
1572 return Lock(name
, SHARED_LOCK
);
1576 void PrintName(CONST_STRPTR name
, ULONG deep
, ULONG dir
, ULONG txt
, struct CopyData
*cd
)
1579 deep
%= PRINTOUT_SPACES
; /* reduce number of spaces */
1580 /* This produces an error with MaxonC++ */
1598 if ((deep
= strlen(name
)) > PRINTOUT_SIZE
) /* reduce name size */
1600 name
+= deep
-PRINTOUT_SIZE
;
1605 Printf((dir
? TEXT_DIRECTORY
: (STRPTR
) "%s"), name
);
1616 void PrintNotDone(CONST_STRPTR name
, CONST_STRPTR txt
, ULONG deep
, ULONG dir
, struct CopyData
*cd
)
1618 #if !USE_ALWAYSVERBOSE
1621 PrintName(name
, deep
, dir
, 1, cd
);
1625 Printf(TEXT_NOT_DONE
, txt
);
1626 PrintFault(IoErr(), NULL
);
1630 /* returns value, when it seems to be a filesystem */
1631 ULONG
TestFileSys(STRPTR name
, struct CopyData
*cd
)
1636 while (*n
&& *n
!= ':')
1647 ret
= IsFileSystem(name
);
1655 void DoWork(STRPTR name
, struct CopyData
*cd
)
1657 BPTR pdir
, lock
= 0;
1658 CONST_STRPTR printerr
= NULL
, printok
= "";
1661 Printf("DoWork(%s, .)\n", name
);
1664 if (cd
->RetVal
> (cd
->Flags
& COPYFLAG_ERRWARN
? RETURN_OK
: RETURN_WARN
) || cd
->RetVal2
)
1667 Printf("DoWork(RetVal %ld)\n", cd
->RetVal
);
1672 if (cd
->Mode
!= COPYMODE_DELETE
&& !(cd
->Flags
& COPYFLAG_DESNOFILESYS
))
1674 if (!cd
->DestPathSize
)
1676 if (!NameFromLock(cd
->CurDest
, cd
->DestName
, FILEPATH_SIZE
))
1678 cd
->RetVal2
= RETURN_FAIL
;
1682 Printf("DoWork(NameFromLock RetVal %ld)\n", cd
->RetVal
);
1688 cd
->DestPathSize
= strlen(cd
->DestName
);
1691 cd
->DestName
[cd
->DestPathSize
] = 0;
1692 AddPart(cd
->DestName
, name
, FILEPATH_SIZE
);
1695 if (cd
->Flags
& (COPYFLAG_SRCNOFILESYS
|COPYFLAG_DESNOFILESYS
))
1697 ULONG res
= 0, kill
= 1;
1699 CONST_STRPTR txt
= TEXT_OPENED_FOR_OUTPUT
;
1702 Printf("Partly DIRECT mode active now (%s - %s)\n", cd
->FileName
,
1706 if ((out
= Open(cd
->DestName
, MODE_NEWFILE
)))
1708 txt
= cd
->Mode
== COPYMODE_MOVE
? TEXT_MOVED
: TEXT_COPIED
;
1710 if ((in
= Open(cd
->FileName
, MODE_OLDFILE
)))
1714 h
= CopyFile(in
, out
, cd
->BufferSize
, cd
);
1715 Close(out
); out
= NULL
;
1722 if (cd
->Mode
== COPYMODE_MOVE
)
1724 if (KillFile(cd
->FileName
, cd
->Flags
& COPYFLAG_FORCEDELETE
, cd
))
1743 KillFileKeepErr(cd
->DestName
, 0, cd
);
1747 if (!res
&& !(cd
->Flags
& COPYFLAG_QUIET
))
1749 PrintNotDone(cd
->Flags
& COPYFLAG_VERBOSE
? name
: 0,
1750 txt
, cd
->Deep
, cd
->Fib
.fib_DirEntryType
> 0, cd
);
1754 cd
->Flags
|= COPYFLAG_DONE
;
1756 if ((cd
->Flags
& COPYFLAG_VERBOSE
))
1758 Printf("%s\n", txt
);
1763 PutStr("DoWork(done)\n");
1768 if (!(lock
= Lock(cd
->FileName
, SHARED_LOCK
)))
1770 cd
->RetVal
= RETURN_WARN
;
1772 if (!(cd
->Flags
& COPYFLAG_QUIET
))
1774 PrintNotDone(cd
->Fib
.fib_FileName
, TEXT_READ
, cd
->Deep
,
1775 cd
->Fib
.fib_DirEntryType
> 0, cd
);
1779 Printf("DoWork(Lock RetVal %ld)\n", cd
->RetVal
);
1784 if (!(pdir
= ParentDir(lock
)))
1786 cd
->RetVal
= RETURN_ERROR
;
1788 if (cd
->Mode
== COPYMODE_DELETE
)
1790 if (!(cd
->Flags
& COPYFLAG_QUIET
))
1792 Printf(" %s ", cd
->FileName
);
1793 Printf(TEXT_NOT_DONE
, TEXT_DELETED
);
1794 Printf("%s\n", TEXT_ERR_DELETE_DEVICE
);
1801 Printf("DoWork(ParentDir %ld)\n", cd
->RetVal
);
1808 if (!(cd
->Flags
& COPYFLAG_QUIET
))
1810 if ((cd
->Flags
& COPYFLAG_VERBOSE
))
1812 PrintName(name
, cd
->Deep
, cd
->Fib
.fib_DirEntryType
> 0, cd
->Fib
.fib_DirEntryType
< 0 ||
1813 (cd
->Flags
& COPYFLAG_ALL
? cd
->Mode
!= COPYMODE_DELETE
: cd
->Mode
!= COPYMODE_COPY
) ||
1814 cd
->Flags
& COPYFLAG_ENTERSECOND
, cd
);
1818 if ((cd
->Flags
& COPYFLAG_ENTERSECOND
) || (cd
->Mode
== COPYMODE_DELETE
&&
1819 (!(cd
->Flags
& COPYFLAG_ALL
) || cd
->Fib
.fib_DirEntryType
< 0)))
1824 if (KillFile(cd
->FileName
, cd
->Flags
& COPYFLAG_FORCEDELETE
, cd
))
1826 printok
= TEXT_DELETED
;
1830 cd
->RetVal
= RETURN_WARN
;
1831 printerr
= TEXT_DELETED
;
1834 else if (cd
->Mode
== COPYMODE_DELETE
)
1838 else if (cd
->Fib
.fib_DirEntryType
> 0)
1842 if ((cd
->Flags
& COPYFLAG_ALL
|| cd
->Mode
== COPYMODE_LINK
||
1843 cd
->Mode
== COPYMODE_MOVE
) && TestLoop(lock
, cd
->CurDest
, cd
))
1846 cd
->RetVal
= RETURN_ERROR
;
1848 if (!(cd
->Flags
& COPYFLAG_QUIET
))
1850 if (!(cd
->Flags
& COPYFLAG_VERBOSE
))
1852 PrintName(name
, cd
->Deep
, 1, 1, cd
);
1855 Printf(TEXT_NOT_DONE
, TEXT_ENTERED
);
1856 PutStr(TEXT_ERR_INFINITE_LOOP
);
1859 else if ((a
= TestDest(cd
->DestName
, 1, cd
)) < 0)
1861 printerr
= TEXT_CREATED
;
1862 cd
->RetVal
= RETURN_ERROR
;
1864 else if (cd
->Flags
& COPYFLAG_ALL
)
1869 cd
->DestPathSize
= 0;
1871 if (a
== TESTDEST_DIR_OK
)
1873 if (!(cd
->CurDest
= Lock(cd
->DestName
, SHARED_LOCK
)))
1875 printerr
= TEXT_ENTERED
;
1876 cd
->RetVal
= RETURN_ERROR
;
1880 #if USE_ALWAYSVERBOSE
1883 printok
= TEXT_ENTERED
;
1887 else if ((cd
->CurDest
= CreateDir(cd
->DestName
)))
1889 UnLock(cd
->CurDest
);
1891 if ((cd
->CurDest
= Lock(cd
->DestName
, SHARED_LOCK
)))
1893 printok
= TEXT_CREATED
;
1897 printerr
= TEXT_ENTERED
;
1898 cd
->RetVal
= RETURN_ERROR
;
1903 printerr
= TEXT_CREATED
;
1904 cd
->RetVal
= RETURN_ERROR
;
1911 else if (i
!= cd
->Destination
)
1916 else if (cd
->Mode
== COPYMODE_MOVE
)
1918 if (Rename(cd
->FileName
, cd
->DestName
))
1920 printok
= TEXT_RENAMED
;
1924 printerr
= TEXT_RENAMED
;
1925 cd
->RetVal
= RETURN_WARN
;
1928 else if (cd
->Mode
== COPYMODE_LINK
)
1930 if (!(cd
->Flags
& COPYFLAG_FORCELINK
))
1933 cd
->RetVal
= RETURN_WARN
;
1935 if (!(cd
->Flags
& COPYFLAG_QUIET
))
1937 if (!(cd
->Flags
& COPYFLAG_VERBOSE
))
1939 PrintName(name
, cd
->Deep
, 1, 1, cd
);
1942 Printf(TEXT_NOT_DONE
, TEXT_LINKED
);
1943 PutStr(TEXT_ERR_FORCELINK
);
1946 else if (LinkFile(lock
, cd
->DestName
, cd
->Flags
& COPYFLAG_SOFTLINK
, cd
))
1948 printok
= TEXT_LINKED
;
1952 printerr
= TEXT_LINKED
;
1953 cd
->RetVal
= RETURN_WARN
;
1956 else /* COPY mode only displays directories, when not ALL */
1960 if (!(cd
->Flags
& COPYFLAG_QUIET
))
1962 if (cd
->Flags
& COPYFLAG_VERBOSE
)
1971 /* test for existing destination file */
1972 if (TestDest(cd
->DestName
, 0, cd
) < 0)
1974 printerr
= TEXT_OPENED_FOR_OUTPUT
;
1976 else if (cd
->Mode
== COPYMODE_MOVE
&& Rename(cd
->FileName
, cd
->DestName
))
1978 printok
= TEXT_RENAMED
;
1980 else if (cd
->Mode
== COPYMODE_LINK
)
1982 if (!(cd
->Flags
& COPYFLAG_SOFTLINK
) && LinkFile(lock
, cd
->DestName
, 0, cd
))
1984 printok
= TEXT_LINKED
;
1988 printerr
= TEXT_LINKED
;
1989 cd
->RetVal
= RETURN_WARN
;
1991 if (cd
->Flags
& COPYFLAG_SOFTLINK
)
1993 SetIoErr(ERROR_OBJECT_WRONG_TYPE
);
2001 CONST_STRPTR txt
= TEXT_OPENED_FOR_OUTPUT
;
2003 if ((out
= Open(cd
->DestName
, MODE_NEWFILE
)))
2007 txt
= cd
->Mode
== COPYMODE_MOVE
? TEXT_MOVED
: TEXT_COPIED
;
2011 if ((in
= Open(cd
->FileName
, MODE_OLDFILE
)))
2013 h
= CopyFile(in
, out
, cd
->BufferSize
, cd
);
2014 Close(out
); out
= NULL
;
2021 if (cd
->Mode
== COPYMODE_MOVE
)
2023 if (KillFile(cd
->FileName
, cd
->Flags
& COPYFLAG_FORCEDELETE
, cd
))
2042 KillFileKeepErr(cd
->DestName
, 0, cd
);
2049 cd
->RetVal
= RETURN_WARN
;
2058 if (printerr
&& !(cd
->Flags
& COPYFLAG_QUIET
))
2060 PrintNotDone(cd
->Flags
& COPYFLAG_VERBOSE
? name
: 0,
2061 printerr
, cd
->Deep
, cd
->Fib
.fib_DirEntryType
> 0, cd
);
2065 cd
->Flags
|= COPYFLAG_DONE
;
2067 if (!(cd
->Flags
& COPYFLAG_QUIET
))
2069 if ((cd
->Flags
& COPYFLAG_VERBOSE
))
2071 Printf("%s\n", printok
);
2075 SetData(cd
->DestName
, cd
);
2085 LONG
CopyFile(BPTR from
, BPTR to
, ULONG bufsize
, struct CopyData
*cd
)
2092 buffer
= cd
->CopyBuf
;
2093 bufsize
= cd
->CopyBufLen
;
2099 buffer
= (STRPTR
)AllocMem(bufsize
, MEMF_PUBLIC
);
2102 cd
->CopyBuf
= buffer
;
2103 cd
->CopyBufLen
= bufsize
;
2109 } while (bufsize
>= 512);
2114 #if USE_BOGUSEOFWORKAROUND
2115 struct FileInfoBlock
*fib
= (struct FileInfoBlock
*) buffer
; /* NOTE: bufsize is min 512 bytes */
2117 if (ExamineFH(from
, fib
))
2119 #warning "****** WARNING: No largefile support! ******"
2120 ULONG filesize
= fib
->fib_Size
, copied
= 0;
2122 /*Printf("filesize: %lu\n", filesize);*/
2127 if (brk
|| (s
= Read(from
, buffer
, bufsize
)) == -1 || Write(to
, buffer
, s
) != s
)
2131 SetIoErr(ERROR_BREAK
);
2136 else if (s
== 0 && copied
< filesize
)
2138 /* premature EOF with buggy fs */
2145 } while (copied
< filesize
);
2147 /*{ LONG ioerr = IoErr();
2148 Printf("copied %lu/%lu\n", copied, filesize);
2152 #endif /* USE_BOGUSEOFWORKAROUND */
2154 /* Stream or so, copy until EOF or error */
2158 if (brk
|| (s
= Read(from
, buffer
, bufsize
)) == -1 || Write(to
, buffer
, s
) != s
)
2162 SetIoErr(ERROR_BREAK
);
2167 } while (s
== bufsize
);
2170 /* Freed at exit to avoid fragmentation */
2171 /*FreeMem(buffer, bufsize);*/
2182 /* Softlink's path starts always with device name! f.e. "Ram Disk:T/..." */
2183 LONG
LinkFile(BPTR from
, STRPTR to
, ULONG soft
, struct CopyData
*cd
)
2190 name
= AllocMem(FILEPATH_SIZE
, MEMF_ANY
);
2193 if (NameFromLock(from
, name
, FILEPATH_SIZE
))
2195 ret
= MakeLink(to
, name
, LINK_SOFT
);
2198 FreeMem(name
, FILEPATH_SIZE
);
2205 return MakeLink(to
, from
, LINK_HARD
);
2210 /* return 0 means no loop, return != 0 means loop found */
2211 ULONG
TestLoop(BPTR srcdir
, BPTR destdir
, struct CopyData
*cd
)
2218 if (SameDevice(srcdir
, destdir
))
2222 if (!SameLock(srcdir
, lock
))
2228 par
= ParentDir(lock
);
2230 if (lock
!= destdir
)
2238 while(!loop
&& lock
);
2241 if (lock
!= destdir
)
2250 void SetData(STRPTR name
, struct CopyData
*cd
)
2252 if (cd
->Flags
& COPYFLAG_NOPRO
)
2254 /* Is already set! - Piru */
2255 //SetProtection(name, 0);
2257 else if (cd
->Flags
& COPYFLAG_PROTECTION
)
2259 SetProtection(name
, cd
->Fib
.fib_Protection
& (ULONG
) ~FIBF_ARCHIVE
);
2262 if (cd
->Flags
& COPYFLAG_DATES
)
2264 SetFileDate(name
, &cd
->Fib
.fib_Date
);
2267 if (cd
->Flags
& COPYFLAG_COMMENT
)
2269 SetComment(name
, cd
->Fib
.fib_Comment
);
2274 LONG
TestDest(STRPTR name
, ULONG type
, struct CopyData
*cd
)
2276 LONG ret
= TESTDEST_ERROR
;
2279 if ((lock
= Lock(name
, SHARED_LOCK
)))
2281 struct FileInfoBlock
*fib
;
2283 if ((fib
= (struct FileInfoBlock
*)AllocDosObject(DOS_FIB
, NULL
)))
2285 if (Examine(lock
, fib
))
2292 if (fib
->fib_DirEntryType
> 0)
2294 ret
= TESTDEST_DIR_OK
;
2296 else if (!(cd
->Flags
& COPYFLAG_DONTOVERWRITE
))
2298 if (KillFile(name
, cd
->Flags
& COPYFLAG_FORCEOVERWRITE
, cd
))
2300 ret
= TESTDEST_DELETED
;
2305 ret
= TESTDEST_CANTDELETE
;
2308 else if (cd
->Flags
& COPYFLAG_DONTOVERWRITE
)
2310 ret
= TESTDEST_CANTDELETE
;
2312 else if (KillFile(name
, cd
->Flags
& COPYFLAG_FORCEOVERWRITE
, cd
))
2314 ret
= TESTDEST_DELETED
;
2318 FreeDosObject(DOS_FIB
, fib
);
2328 ret
= TESTDEST_NONE
;
2331 if (ret
== TESTDEST_CANTDELETE
)
2333 SetIoErr(ERROR_OBJECT_EXISTS
);