New bitmap method SetRGBConversionFunction which can be used to
[tangerine.git] / workbench / c / Copy.c
blobfb79923e81c994fc2b6bdc97bf6636bc1714e8f2
1 /* copy t:AmiTCP.#? big: buf=2000000 verbose
2 (C) 2001 AROS - The Amiga Research OS
3 $Id$
5 Desc: Copy CLI command
6 Lang: English
7 */
9 /*****************************************************************************
11 NAME
13 Copy
15 SYNOPSIS
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,
23 FORCE/S
25 LOCATION
27 Workbench:C
29 FUNCTION
31 Creates identical copies of one or more files.
33 INPUTS
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
42 DATES -- copy dates
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:
65 FROM:
66 Source file(s). For directories, all contained files are source files. May
67 have standard patterns.
69 TO:
70 Destination file or for multiple sources destination directory. Destination
71 directories are created (including all needed parent directories).
73 ALL:
74 Scan directories recursively
76 QUIET:
77 Copy is completely silent here. Really no output is given, also no requests
78 for missing disks or other problems!
80 BUF=BUFFER:
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.
84 PAT=PATTERN:
85 PATTERN allows to specify a standard dos pattern, all file have to match.
86 This is useful with ALL option.
88 Example:
89 When you want to delete all .info files in a directory tree, you need
90 this option: Copy DELETE #? ALL PAT #?.info
92 CLONE:
93 The filecomment, date and protection bits of the source files are copied to
94 destination file or directory.
96 DATES:
97 The date information of source is copied to destination.
99 NOPRO:
100 The protection bits of sources are NOT copied. So the destination gets
101 default bits [rwed].
103 COM=COMMENT:
104 The filecomment is copied to destination.
106 NOREQ:
107 No standard DOS requests are displayed, when an error occurs.
110 DIRECT:
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
117 file.
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
122 needed sometimes.
124 VERBOSE:
125 Copy gives additional output.
127 ERRWARN:
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.
138 MAKEDIR:
139 All names specified in FROM field are taken as directories, which must be
140 created.
142 MOVE:
143 The files are not copied, but moved (or renamed). This means that after
144 move operation the source does no longer exist.
146 DELETE:
147 This does not copy anything, but delete the source files!
149 HARD=HARDLINK:
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.
155 SOFT=SOFTLINK:
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
159 set to true.
160 NOTE: Softlinks are not official supported by OS and may be dangerous.
161 I suggest not to use this option! See description below.
163 FOLNK=FORCELINK:
164 When linking of directories should be possible, this option is needed. See
165 section "About links" for possible problems.
167 FODEL=FORCEDELETE:
168 When this option is enabled, files are deleted also, when they are delete
169 protected.
171 FOOVR=FORCEOVERWRITE:
172 When this option is enabled, files are overwritten also, when they are
173 protected.
175 DONTOVR=DONTOVERWRITE:
176 This option prevents overwriting of destination files.
179 RESULT
181 NOTES
183 EXAMPLE
185 BUGS
187 SEE ALSO
189 Delete, Rename, MakeDir, MakeLink
191 INTERNALS
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
220 possible.
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
242 About links:
244 HARDLINKS:
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).
252 SOFTLINKS:
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
257 you!
259 PROBLEMS:
260 Links to directories may cause infinite directory loops!
262 Example: Having following directory tree:
264 DEV:
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
277 loop.
280 HISTORY
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)
297 #define DEBUG 0
299 #ifdef __AROS__
300 #warning "FIXME: Not trusting softlinks in AROS DOS!"
301 #define USE_SOFTLINKCHECK 0
302 #else
303 #define USE_SOFTLINKCHECK 1
304 #endif
306 #define USE_ALWAYSVERBOSE 1
307 #define USE_BOGUSEOFWORKAROUND 0
309 #include <exec/devices.h>
310 #include <exec/io.h>
311 #include <exec/memory.h>
312 #include <exec/semaphores.h>
313 #include <exec/types.h>
314 #include <dos/exall.h>
316 #ifdef __SASC
317 typedef ULONG IPTR;
318 #else /* __SASC */
319 #include <aros/debug.h>
320 #endif /* __SASC */
322 #include <proto/dos.h>
323 #include <proto/exec.h>
325 #include <string.h>
326 #include <stdio.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,"
332 "QUIET/S,"
333 #if !USE_ALWAYSVERBOSE
334 "VERBOSE/S,"
335 #endif
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,"
340 "FORCE/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 */
374 /* return values */
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) */
381 struct IptrArgs
383 IPTR from;
384 IPTR to;
385 IPTR pattern;
386 IPTR buffer;
387 IPTR all;
388 IPTR direct;
389 IPTR clone;
390 IPTR dates;
391 IPTR nopro;
392 IPTR comment;
393 IPTR quiet;
394 #if !USE_ALWAYSVERBOSE
395 IPTR verbose;
396 #endif
397 IPTR noreq;
398 IPTR errwarn;
399 IPTR makedir;
400 IPTR move_mode;
401 IPTR delete_mode;
402 IPTR hardlink;
403 IPTR softlink;
404 IPTR forcelink;
405 IPTR forcedelete;
406 IPTR forceoverwrite;
407 IPTR dontoverwrite;
408 IPTR force;
412 struct Args
414 STRPTR *from;
415 STRPTR to;
416 STRPTR pattern;
417 LONG *buffer;
418 LONG all;
419 LONG direct;
420 LONG clone;
421 LONG dates;
422 LONG nopro;
423 LONG comment;
424 LONG quiet;
425 LONG verbose;
426 LONG noreq;
427 LONG errwarn;
428 LONG makedir;
429 LONG move_mode;
430 LONG delete_mode;
431 LONG hardlink;
432 LONG softlink;
433 LONG forcelink;
434 LONG forcedelete;
435 LONG forceoverwrite;
436 LONG dontoverwrite;
437 LONG force;
441 struct CopyData
443 struct ExecBase *SysBase;
444 struct DosLibrary *DOSBase;
446 ULONG Flags;
447 ULONG BufferSize;
448 STRPTR Pattern;
449 BPTR Destination;
450 BPTR CurDest; /* Current Destination */
451 ULONG DestPathSize;
452 struct FileInfoBlock Fib;
453 UBYTE Mode;
454 UBYTE RetVal; /* when set, error output is already done */
455 UBYTE RetVal2; /* when set, error output must be done */
456 UBYTE Deep;
457 UBYTE FileName[FILEPATH_SIZE];
458 UBYTE DestName[FILEPATH_SIZE];
460 STRPTR CopyBuf;
461 ULONG CopyBufLen;
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[] =
485 "read.",
486 "copied.",
487 "moved.",
488 "deleted.",
489 "linked.",
490 "renamed.",
491 " [created]",
492 "entered",
493 "opened for output",
494 "COPY mode\n",
495 "MOVE mode\n",
496 "DELETE mode\n",
497 "MAKEDIR mode\n",
498 "HARDLINK mode\n",
499 "SOFTLINK mode\n",
500 "%s (Dir)", /* output of directories */
501 " not %s: ",
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 *);
526 int main(void)
528 #ifndef __AROS__
529 struct ExecBase *SysBase;
530 struct DosLibrary *DOSBase;
531 #endif
532 struct Process *task;
533 struct CopyData *cd;
534 int retval = RETURN_FAIL;
536 #ifndef __AROS__
537 SysBase=*((struct ExecBase**) 4);
538 #endif
540 /* test for WB and reply startup-message */
541 if (!(task = (struct Process *)FindTask(NULL))->pr_CLI)
543 WaitPort(&task->pr_MsgPort);
544 Forbid();
545 ReplyMsg(GetMsg(&task->pr_MsgPort));
547 return RETURN_FAIL;
550 #ifndef __AROS__
551 DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 37);
552 #endif
553 cd = AllocMem(sizeof(*cd), MEMF_PUBLIC | MEMF_CLEAR);
555 if (DOSBase && cd)
557 STRPTR a[2] = { "", 0 };
558 struct RDArgs *rda;
559 struct IptrArgs iArgs;
560 struct Args args;
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;
570 cd->Deep = 1;
572 memset(&iArgs, 0, sizeof(struct IptrArgs));
574 rda = (struct RDArgs *)AllocDosObject(DOS_RDARGS, NULL);
575 if (rda)
577 rda->RDA_ExtHelp =
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"
585 "DATES copy dates\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"
591 #endif
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;
608 LONG i = 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;
624 #else
625 args.verbose = (LONG)iArgs.verbose;
626 #endif
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
641 true! */
643 /* Original doesn't hide requesters with QUIET */
644 /*args.noreq = 1;*/
645 args.verbose = FALSE;
648 if (args.buffer && *args.buffer > 0) /* minimum buffer size */
650 cd->BufferSize = *args.buffer * 512;
653 if (args.quiet)
655 cd->Flags |= COPYFLAG_QUIET;
658 #if !USE_ALWAYSVERBOSE
659 if (args.verbose)
661 cd->Flags |= COPYFLAG_VERBOSE;
663 #endif
664 if (args.all)
666 cd->Flags |= COPYFLAG_ALL;
669 /* 12-jul-03 bugfix: always copy protection flags! -Piru */
670 cd->Flags |= COPYFLAG_PROTECTION;
671 if (args.clone)
673 cd->Flags |= COPYFLAG_DATES | COPYFLAG_COMMENT | COPYFLAG_PROTECTION;
676 if (args.dates)
678 cd->Flags |= COPYFLAG_DATES;
681 if (args.comment)
683 cd->Flags |= COPYFLAG_COMMENT;
686 if (args.nopro)
688 cd->Flags |= COPYFLAG_NOPRO;
691 if (args.forcelink)
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;
711 if (args.errwarn)
713 cd->Flags |= COPYFLAG_ERRWARN;
716 if (args.force) /* support OS Delete and MakeLink command
717 options */
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 */
732 args.from = a;
735 if (args.noreq) /* no dos.library requests allowed */
737 task->pr_WindowPtr = (APTR)-1;
740 if (args.delete_mode)
742 ++i;
743 cd->Mode = COPYMODE_DELETE;
746 if (args.move_mode)
748 ++i;
749 cd->Mode = COPYMODE_MOVE;
752 if (args.makedir)
754 ++i;
755 cd->Mode = COPYMODE_MAKEDIR;
758 if (args.hardlink)
760 ++i;
761 cd->Mode = COPYMODE_LINK;
764 if (args.softlink)
766 ++i;
767 cd->Mode = COPYMODE_LINK;
768 cd->Flags |= COPYFLAG_SOFTLINK | COPYFLAG_FORCELINK;
771 #ifdef __AROS__
772 #warning "CHECKME: Is this still needed?"
773 if (*args.from == NULL)
775 PutStr("No arguments specified\n");
776 FreeArgs(rda);
777 FreeDosObject(DOS_RDARGS, rda);
778 return RETURN_ERROR;
780 #endif
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
786 is last */
787 { /* one of from. Copy this argument into */
788 STRPTR *a; /* args.to */
790 a = args.from;
792 while(*(++a))
795 args.to = *(--a);
796 *a = 0;
799 #if USE_ALWAYSVERBOSE
801 /* Only do this if quiet isn't set - bigfoot */
802 if (!args.quiet)
804 /* If more than two args, be verbose... - Piru */
805 if (args.from[0] && args.from[1])
807 args.verbose = TRUE;
808 cd->Flags |= COPYFLAG_VERBOSE;
811 /* If any of the sources is a pattern, be verbose... - Piru */
813 STRPTR *a;
815 for (a = args.from; *a; a++)
817 if (IsMatchPattern(*a, cd) != 0)
819 args.verbose = TRUE;
820 cd->Flags |= COPYFLAG_VERBOSE;
825 #endif
827 /* test if more than one of the above four or any other wrong
828 arguments */
830 if (i > 1 ||
831 (args.from == a && cd->Mode == COPYMODE_MAKEDIR) ||
832 (args.direct && (args.from == a || !*args.from ||
833 args.pattern ||
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)
846 LONG i;
847 BPTR dir;
848 cd->RetVal2 = RETURN_OK;
850 #if !USE_ALWAYSVERBOSE
851 if (args.verbose)
853 PutStr(texts[TEXTNUM_MODE + COPYMODE_MAKEDIR]);
855 #endif
857 while (!cd->RetVal && !cd->RetVal2 && *args.from)
859 if ((i = IsPattern(*args.from, cd)))
861 if (i != -1)
863 cd->RetVal = RETURN_ERROR;
865 if (!args.quiet)
867 PutStr(TEXT_ERR_WILDCARD_DEST);
870 else
872 cd->RetVal2 = RETURN_FAIL;
876 if ((dir = OpenDestDir(*args.from, cd)))
878 UnLock(dir);
879 cd->Flags |= COPYFLAG_DONE;
882 ++args.from;
884 } /* cd->Mode == COPYMODE_MAKEDIR */
885 else if (args.direct)
887 if (cd->Mode == COPYMODE_COPY)
889 BPTR in, out;
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);
896 Close(out);
899 Close(in);
902 else /* COPYMODE_DELETE */
904 while (*args.from)
906 KillFile(*(args.from++), cd->Flags & COPYFLAG_FORCEDELETE, cd);
909 cd->RetVal2 = RETURN_OK;
912 else
914 if (args.pattern && *args.pattern)
916 patbufsize = (strlen(args.pattern) << 1) + 3;
918 if ((cd->Pattern = (STRPTR)AllocMem(patbufsize,
919 MEMF_ANY)))
921 if (ParsePatternNoCase(args.pattern, cd->Pattern,
922 patbufsize) < 0)
924 FreeMem(cd->Pattern, patbufsize);
925 cd->Pattern = 0;
930 if (1) // (cd->Fib = (struct FileInfoBlock *)AllocDosObject(DOS_FIB, NULL)))
932 #if !USE_ALWAYSVERBOSE
933 if (args.verbose)
935 PutStr(texts[TEXTNUM_MODE + cd->Mode +
936 (cd->Flags & COPYFLAG_SOFTLINK ? 1 : 0)]);
938 #endif
939 if (args.pattern && !cd->Pattern)
941 if (!*args.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)
951 && *args.from)
953 PatCopy(*(args.from++), cd);
956 else if ((i = IsPattern(args.to, cd)))
958 if (i != -1)
960 cd->RetVal = RETURN_ERROR;
962 if (!args.quiet)
964 PutStr(TEXT_ERR_WILDCARD_DEST);
968 else
970 STRPTR path;
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)))
980 BPTR lock;
981 LONG lockioerr;
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 */
995 else
997 i = 1;
1000 UnLock(lock);
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
1006 #if 1
1007 if (!i && cd->RetVal2 && !IsMatchPattern(*args.from, cd))
1009 ULONG len;
1010 STRPTR pat;
1012 //Printf("pattern check <%s>\n", *args.from);
1014 len = (strlen(*args.from) << 1) + 3;
1016 if ((pat = (STRPTR)AllocMem(len,
1017 MEMF_ANY)))
1019 if (ParsePattern(*args.from, pat, len) > -1 &&
1020 strlen(pat) <= strlen(*args.from))
1022 lock = Lock(pat, SHARED_LOCK);
1023 if (lock)
1025 UnLock(lock);
1027 strcpy(*args.from, pat);
1031 FreeMem(pat, len);
1034 #endif
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)
1046 UBYTE sep;
1048 cd->Flags |= COPYFLAG_DEST_FILE;
1050 /* produce missing destination directories */
1051 sep = *path;
1052 *path = 0;
1054 if ((cd->CurDest = OpenDestDir(args.to, cd)))
1056 *path = sep;
1058 /* do the job */
1059 UnLock(lock);
1060 lock = 0;
1061 CopyMem(*args.from, cd->FileName,
1062 1 + strlen(*args.from));
1063 DoWork(FilePart(args.to), cd); /* on file call */
1064 UnLock(cd->CurDest);
1069 if (lock)
1071 UnLock(lock);
1075 lockioerr = IoErr(); /* We save ioerr here, because TestFileSys changes it */
1077 if (lock == 0 && cd->Mode == COPYMODE_COPY && !TestFileSys(*args.from, cd))
1079 UBYTE sep;
1080 cd->Flags |= COPYFLAG_DEST_FILE | COPYFLAG_SRCNOFILESYS;
1081 cd->RetVal2 = RETURN_OK;
1083 /* produce missing destination directories */
1084 sep = *path;
1085 *path = 0;
1087 if ((cd->CurDest = OpenDestDir(args.to, cd)))
1089 *path = sep;
1091 /* do the job */
1092 CopyMem(*args.from, cd->FileName, 1 + strlen(*args.from));
1093 DoWork(FilePart(args.to), cd); /* on file call */
1094 UnLock(cd->CurDest);
1097 else
1098 SetIoErr(lockioerr);
1100 else if (i != -1)
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);
1116 } /* else */
1118 if (!(cd->Flags & COPYFLAG_DONE) && args.verbose &&
1119 !cd->RetVal && !cd->RetVal2)
1121 PutStr(TEXT_NOTHING_DONE);
1124 } /* if (1) */
1126 if (cd->Pattern)
1128 FreeMem(cd->Pattern, patbufsize);
1130 } /* else */
1132 task->pr_WindowPtr = win;
1134 FreeArgs(rda);
1135 } /* ReadArgs */
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);
1151 if (cd->RetVal)
1153 cd->RetVal2 = cd->RetVal;
1156 if (args.errwarn && cd->RetVal2 == RETURN_WARN)
1158 cd->RetVal2 = RETURN_ERROR;
1161 if (cd->CopyBuf)
1163 FreeMem(cd->CopyBuf, cd->CopyBufLen);
1166 #undef SysBase
1167 #undef DOSBase
1169 if (cd)
1171 retval = cd->RetVal2;
1172 FreeMem(cd, sizeof(*cd));
1174 else if (DOSBase)
1176 PrintFault(IoErr(), NULL);
1178 #ifndef __AROS__
1179 if (DOSBase)
1181 CloseLibrary((struct Library *)DOSBase);
1183 #endif
1184 return retval;
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;
1195 #if DEBUG
1196 Printf("PatCopy(%s, .)\n", name);
1197 #endif
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;
1219 return;
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)
1235 if (parentdirerr)
1237 //Printf("ParentDir() fuxored last round! Would copy next files to SYS: !\n");
1238 retval = IoErr();
1239 if (!retval)
1240 SetIoErr(retval = ERROR_INVALID_LOCK);
1241 break;
1244 if (doit)
1246 DoWork(cd->Fib.fib_FileName, cd);
1247 doit = 0;
1250 if (deep) /* used for Deep checking */
1252 ++cd->Deep;
1253 deep = 0;
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;
1266 #endif
1267 APath->ap_Flags |= APF_DODIR;
1269 else if (APath->ap_Flags & APF_DIDDIR)
1271 BPTR i;
1273 cd->Flags |= COPYFLAG_ENTERSECOND;
1274 APath->ap_Flags &= ~APF_DIDDIR;
1275 --cd->Deep;
1277 if (cd->Mode == COPYMODE_DELETE || cd->Mode == COPYMODE_MOVE)
1279 doit = 1;
1282 if ((i = cd->CurDest))
1284 cd->CurDest = ParentDir(i);
1285 cd->DestPathSize = 0;
1287 if (i != cd->Destination)
1289 UnLock(i);
1292 if (!cd->CurDest)
1294 parentdirerr = 1;
1295 continue;
1299 else if (APath->ap_Info.fib_DirEntryType > 0)
1301 doit = 1;
1303 if (cd->Flags & COPYFLAG_ALL)
1305 #if USE_SOFTLINKCHECK
1307 BOOL enter = TRUE;
1308 BPTR dirlock, lock;
1310 dirlock = CurrentDir(APath->ap_Current->an_Lock);
1311 lock = Lock(APath->ap_Info.fib_FileName, ACCESS_READ);
1312 if (lock)
1313 UnLock(lock);
1314 else
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);
1325 if (buffer)
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);
1337 enter = FALSE;
1340 FreeMem(buffer, BUFFERSIZE);
1343 FreeDeviceProc(dvp);
1346 SetIoErr(ioerr);
1348 CurrentDir(dirlock);
1350 if (enter)
1352 APath->ap_Flags |= APF_DODIR;
1353 deep = 1;
1356 #else /* USE_SOFTLINKCHECK */
1358 APath->ap_Flags |= APF_DODIR;
1359 deep = 1;
1361 #endif /* USE_SOFTLINKCHECK */
1364 else if (!cd->Pattern || MatchPatternNoCase(cd->Pattern, APath->ap_Info.fib_FileName))
1366 doit = 1;
1369 first = 0;
1372 MatchEnd(APath);
1374 if (retval && retval != ERROR_NO_MORE_ENTRIES)
1376 LONG ioerr = IoErr();
1377 #if USE_ALWAYSVERBOSE
1378 cd->Flags |= COPYFLAG_VERBOSE;
1379 #endif
1380 Printf("%s - ", name);
1381 PrintFault(ioerr, NULL);
1382 SetIoErr(ioerr);
1384 cd->RetVal2 = RETURN_FAIL;
1387 if (doit)
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);
1397 else
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)
1416 LONG a, ret = -1;
1417 STRPTR buffer;
1419 a = (strlen(name) << 1) + 3;
1421 if ((buffer = (STRPTR)AllocMem(a, MEMF_ANY)))
1423 ret = ParsePattern(name, buffer, a);
1424 FreeMem(buffer, a);
1427 if (ret == -1)
1429 SetIoErr(ERROR_NO_FREE_STORE);
1432 return ret;
1436 LONG IsMatchPattern(STRPTR name, struct CopyData *cd)
1438 struct AnchorPath ap;
1439 LONG ret = -1;
1441 ap.ap_BreakBits = 0;
1442 ap.ap_Flags = APF_DOWILD;
1443 ap.ap_Strlen = 0;
1445 if (MatchFirst(name, &ap) == 0)
1447 ret = (ap.ap_Flags & APF_ITSWILD) ? TRUE : FALSE;
1449 MatchEnd(&ap);
1452 return ret;
1456 LONG KillFile(STRPTR name, ULONG doit, struct CopyData *cd)
1458 if (doit)
1460 SetProtection(name, 0);
1463 return DeleteFile(name);
1467 LONG KillFileKeepErr(STRPTR name, ULONG doit, struct CopyData *cd)
1469 LONG ret, ioerr;
1471 ioerr = IoErr();
1472 ret = KillFile(name, doit, cd);
1473 SetIoErr(ioerr);
1475 return ret;
1479 BPTR OpenDestDir(STRPTR name, struct CopyData *cd)
1481 LONG a, err = 0, cr = 0;
1482 BPTR dir;
1483 STRPTR ptr = name;
1484 UBYTE as;
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 != '/')
1498 ++ptr;
1501 as = *ptr;
1502 *ptr = 0;
1504 if ((a = TestDest(name, 1, cd)) == TESTDEST_CANTDELETE)
1506 if (!(cd->Flags & COPYFLAG_QUIET))
1508 PutStr(TEXT_ERR_DEST_DIR);
1511 err = 2;
1513 else if (a < 0)
1515 err = 1;
1517 else if (a != TESTDEST_DIR_OK)
1519 if ((dir = CreateDir(name)))
1521 ++cr;
1523 if ((cd->Flags & COPYFLAG_VERBOSE))
1525 PrintName(name, 1, 1, 1, cd);
1526 Printf("%s\n", TEXT_CREATED);
1529 UnLock(dir);
1531 else
1533 if (!(cd->Flags & COPYFLAG_QUIET))
1535 PrintNotDone(name, TEXT_CREATED, 1, 1, cd);
1538 err = 2;
1542 *ptr = as;
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
1546 * string. - Piru
1548 if (as)
1550 ptr++;
1554 if (err)
1556 cd->RetVal = RETURN_ERROR;
1558 if (!(cd->Flags & COPYFLAG_QUIET) && err == 1)
1560 PrintNotDone(name, TEXT_OPENED_FOR_OUTPUT, 1, 1, cd);
1563 return 0;
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)
1578 #if 0
1579 deep %= PRINTOUT_SPACES; /* reduce number of spaces */
1580 /* This produces an error with MaxonC++ */
1581 #endif
1583 PutStr(" ");
1584 if (deep)
1586 while (--deep)
1588 PutStr(" ");
1592 if (dir)
1594 PutStr(" ");
1597 #if 0
1598 if ((deep = strlen(name)) > PRINTOUT_SIZE) /* reduce name size */
1600 name += deep-PRINTOUT_SIZE;
1601 PutStr("...");
1603 #endif
1605 Printf((dir ? TEXT_DIRECTORY : (STRPTR) "%s"), name);
1607 if (!dir && txt)
1609 PutStr("..");
1612 Flush(Output());
1616 void PrintNotDone(CONST_STRPTR name, CONST_STRPTR txt, ULONG deep, ULONG dir, struct CopyData *cd)
1618 #if !USE_ALWAYSVERBOSE
1619 if (name)
1621 PrintName(name, deep, dir, 1, cd);
1623 #endif
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)
1633 STRPTR n = name;
1634 ULONG ret = 1;
1636 while (*n && *n != ':')
1638 ++n;
1641 if (*(n++) == ':')
1643 UBYTE a;
1645 a = *n;
1646 *n = 0;
1647 ret = IsFileSystem(name);
1648 *n = a;
1651 return ret;
1655 void DoWork(STRPTR name, struct CopyData *cd)
1657 BPTR pdir, lock = 0;
1658 CONST_STRPTR printerr = NULL, printok = "";
1660 #if DEBUG
1661 Printf("DoWork(%s, .)\n", name);
1662 #endif
1664 if (cd->RetVal > (cd->Flags & COPYFLAG_ERRWARN ? RETURN_OK : RETURN_WARN) || cd->RetVal2)
1666 #if DEBUG
1667 Printf("DoWork(RetVal %ld)\n", cd->RetVal);
1668 #endif
1669 return;
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;
1679 UnLock(lock);
1681 #if DEBUG
1682 Printf("DoWork(NameFromLock RetVal %ld)\n", cd->RetVal);
1683 #endif
1685 return;
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;
1698 BPTR in, out;
1699 CONST_STRPTR txt = TEXT_OPENED_FOR_OUTPUT;
1701 #if DEBUG
1702 Printf("Partly DIRECT mode active now (%s - %s)\n", cd->FileName,
1703 cd->DestName);
1704 #endif
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)))
1712 ULONG h;
1714 h = CopyFile(in, out, cd->BufferSize, cd);
1715 Close(out); out = NULL;
1716 Close(in);
1718 if (!h)
1720 kill = 0;
1722 if (cd->Mode == COPYMODE_MOVE)
1724 if (KillFile(cd->FileName, cd->Flags & COPYFLAG_FORCEDELETE, cd))
1726 res = 1;
1729 else
1731 res = 1;
1736 if (out)
1738 Close(out);
1741 if (kill)
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);
1752 else
1754 cd->Flags |= COPYFLAG_DONE;
1756 if ((cd->Flags & COPYFLAG_VERBOSE))
1758 Printf("%s\n", txt);
1762 #if DEBUG
1763 PutStr("DoWork(done)\n");
1764 #endif
1765 return;
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);
1778 #if DEBUG
1779 Printf("DoWork(Lock RetVal %ld)\n", cd->RetVal);
1780 #endif
1781 return;
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);
1798 UnLock(lock);
1800 #if DEBUG
1801 Printf("DoWork(ParentDir %ld)\n", cd->RetVal);
1802 #endif
1803 return;
1806 UnLock(pdir);
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)))
1821 UnLock(lock);
1822 lock = 0;
1824 if (KillFile(cd->FileName, cd->Flags & COPYFLAG_FORCEDELETE, cd))
1826 printok = TEXT_DELETED;
1828 else
1830 cd->RetVal = RETURN_WARN;
1831 printerr = TEXT_DELETED;
1834 else if (cd->Mode == COPYMODE_DELETE)
1838 else if (cd->Fib.fib_DirEntryType > 0)
1840 ULONG a;
1842 if ((cd->Flags & COPYFLAG_ALL || cd->Mode == COPYMODE_LINK ||
1843 cd->Mode == COPYMODE_MOVE) && TestLoop(lock, cd->CurDest, cd))
1845 printok = 0;
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)
1866 BPTR i;
1868 i = cd->CurDest;
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;
1878 else
1880 #if USE_ALWAYSVERBOSE
1881 printok = "";
1882 #else
1883 printok = TEXT_ENTERED;
1884 #endif
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;
1895 else
1897 printerr = TEXT_ENTERED;
1898 cd->RetVal = RETURN_ERROR;
1901 else
1903 printerr = TEXT_CREATED;
1904 cd->RetVal = RETURN_ERROR;
1907 if (!cd->CurDest)
1909 cd->CurDest = i;
1911 else if (i != cd->Destination)
1913 UnLock(i);
1916 else if (cd->Mode == COPYMODE_MOVE)
1918 if (Rename(cd->FileName, cd->DestName))
1920 printok = TEXT_RENAMED;
1922 else
1924 printerr = TEXT_RENAMED;
1925 cd->RetVal = RETURN_WARN;
1928 else if (cd->Mode == COPYMODE_LINK)
1930 if (!(cd->Flags & COPYFLAG_FORCELINK))
1932 printok = 0;
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;
1950 else
1952 printerr = TEXT_LINKED;
1953 cd->RetVal = RETURN_WARN;
1956 else /* COPY mode only displays directories, when not ALL */
1958 printok = 0;
1960 if (!(cd->Flags & COPYFLAG_QUIET))
1962 if (cd->Flags & COPYFLAG_VERBOSE)
1964 PutStr("\n");
1969 else
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;
1986 else
1988 printerr = TEXT_LINKED;
1989 cd->RetVal = RETURN_WARN;
1991 if (cd->Flags & COPYFLAG_SOFTLINK)
1993 SetIoErr(ERROR_OBJECT_WRONG_TYPE);
1997 else
1999 ULONG res = 0, h;
2000 BPTR in, out;
2001 CONST_STRPTR txt = TEXT_OPENED_FOR_OUTPUT;
2003 if ((out = Open(cd->DestName, MODE_NEWFILE)))
2005 ULONG kill = 1;
2007 txt = cd->Mode == COPYMODE_MOVE ? TEXT_MOVED : TEXT_COPIED;
2008 UnLock(lock);
2009 lock = 0;
2011 if ((in = Open(cd->FileName, MODE_OLDFILE)))
2013 h = CopyFile(in, out, cd->BufferSize, cd);
2014 Close(out); out = NULL;
2015 Close(in);
2017 if (!h)
2019 kill = 0;
2021 if (cd->Mode == COPYMODE_MOVE)
2023 if (KillFile(cd->FileName, cd->Flags & COPYFLAG_FORCEDELETE, cd))
2025 res = 1;
2028 else
2030 res = 1;
2035 if (out)
2037 Close(out);
2040 if (kill)
2042 KillFileKeepErr(cd->DestName, 0, cd);
2046 if (!res)
2048 printerr = txt;
2049 cd->RetVal = RETURN_WARN;
2051 else
2053 printok = txt;
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);
2063 else if (printok)
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);
2078 if (lock)
2080 UnLock(lock);
2085 LONG CopyFile(BPTR from, BPTR to, ULONG bufsize, struct CopyData *cd)
2087 STRPTR buffer;
2088 LONG s, err = 0;
2090 if (cd->CopyBuf)
2092 buffer = cd->CopyBuf;
2093 bufsize = cd->CopyBufLen;
2095 else
2099 buffer = (STRPTR)AllocMem(bufsize, MEMF_PUBLIC);
2100 if (buffer)
2102 cd->CopyBuf = buffer;
2103 cd->CopyBufLen = bufsize;
2104 break;
2107 bufsize >>= 1;
2109 } while (bufsize >= 512);
2112 if (buffer)
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);*/
2126 ULONG brk = CTRL_C;
2127 if (brk || (s = Read(from, buffer, bufsize)) == -1 || Write(to, buffer, s) != s)
2129 if (brk)
2131 SetIoErr(ERROR_BREAK);
2133 err = RETURN_FAIL;
2134 break;
2136 else if (s == 0 && copied < filesize)
2138 /* premature EOF with buggy fs */
2139 err = RETURN_FAIL;
2140 break;
2143 copied += s;
2145 } while (copied < filesize);
2147 /*{ LONG ioerr = IoErr();
2148 Printf("copied %lu/%lu\n", copied, filesize);
2149 SetIoErr(ioerr);}*/
2151 else
2152 #endif /* USE_BOGUSEOFWORKAROUND */
2154 /* Stream or so, copy until EOF or error */
2157 ULONG brk = CTRL_C;
2158 if (brk || (s = Read(from, buffer, bufsize)) == -1 || Write(to, buffer, s) != s)
2160 if (brk)
2162 SetIoErr(ERROR_BREAK);
2164 err = RETURN_FAIL;
2165 break;
2167 } while (s == bufsize);
2170 /* Freed at exit to avoid fragmentation */
2171 /*FreeMem(buffer, bufsize);*/
2173 else
2175 err = RETURN_FAIL;
2178 return err;
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)
2185 if (soft)
2187 LONG ret = FALSE;
2188 UBYTE *name;
2190 name = AllocMem(FILEPATH_SIZE, MEMF_ANY);
2191 if (name)
2193 if (NameFromLock(from, name, FILEPATH_SIZE))
2195 ret = MakeLink(to, name, LINK_SOFT);
2198 FreeMem(name, FILEPATH_SIZE);
2201 return ret;
2203 else
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)
2213 ULONG loop = 0;
2214 BPTR par, lock;
2216 lock = destdir;
2218 if (SameDevice(srcdir, destdir))
2222 if (!SameLock(srcdir, lock))
2224 loop = 1;
2226 else
2228 par = ParentDir(lock);
2230 if (lock != destdir)
2232 UnLock(lock);
2235 lock = par;
2238 while(!loop && lock);
2241 if (lock != destdir)
2243 UnLock(lock);
2246 return loop;
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;
2277 BPTR lock;
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))
2287 UnLock(lock);
2288 lock = 0;
2290 if (type)
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;
2303 else
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);
2321 if (lock)
2323 UnLock(lock);
2326 else
2328 ret = TESTDEST_NONE;
2331 if (ret == TESTDEST_CANTDELETE)
2333 SetIoErr(ERROR_OBJECT_EXISTS);
2336 return ret;