home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Amiga / Workbench / Patches / CopyReplace.lha / Source / Copy.c next >
C/C++ Source or Header  |  1998-05-08  |  33KB  |  1,215 lines

  1. #define NAME         "Copy"
  2. #define REVISION     "15"
  3. #define DISTRIBUTION "(Freeware) "
  4. //#define DEBUG
  5.  
  6. /* Programmheader
  7.  
  8.         Name:           Copy
  9.         Author:         SDI
  10.         Distribution:   Freeware
  11.         Description:    copies, moves, deletes and links files
  12.         Compileropts:   -
  13.         Linkeropts:     -gsi -l amiga
  14.  
  15.  1.0   02.08.97 : first version, only raw source
  16.  1.1   06.08.97 : added more stuff
  17.  1.2   08.08.97 : completed option description, added new code
  18.  1.3   09.08.97 : and more stuff done and SILENT option
  19.  1.4   11.08.97 : fixed problem with DELETE and ExNext function
  20.  1.5   14.08.97 : fixed DoWork, added new stuff
  21.  1.6   17.08.97 : added more functions, program is near completion
  22.  1.7   24.08.97 : bug fixes in DoWork function
  23.  1.8   25.09.97 : included missing functions, started debugging
  24.  1.9   26.09.97 : debugging, source cleanup
  25.  1.10  28.09.97 : and still debugging
  26.  1.11  30.09.97 : fixed some errors
  27.  1.12  04.10.97 : Added FORCE Option
  28.  1.13  19.12.97 : added DIRECT option
  29.  1.14  20.04.98 : with DIRECT now all softlinks can be deleted (Thanks to
  30.     Magnus Holmgren for reporting this)
  31.  1.15  06.05.98 : added automatic DIRECT detection with IsFileSystem
  32. */
  33.  
  34. #include <proto/dos.h>
  35. #include <proto/exec.h>
  36. #include <exec/memory.h>
  37. #include "SDI_defines.h"
  38. #define SDI_TO_ANSI
  39. #include "SDI_ASM_STD_protos.h"
  40.  
  41. #define PARAM   "FROM/M,TO,PAT=PATTERN/K,BUF=BUFFER/K/N,ALL/S,"         \
  42.                 "DIRECT/S,CLONE/S,DATES/S,NOPRO/S,COM=COMMENT/S,"       \
  43.                 "QUIET/S,SILENT/S,NOREQ/S,ERRWARN/S,MAKEDIR/S,"         \
  44.                 "MOVE/S,DELETE/S,HARD=HARDLINK/S,SOFT=SOFTLINK/S,"      \
  45.                 "FOLNK=FORCELINK/S,FODEL=FORCEDELETE/S,"                \
  46.                 "FOOVR=FORCEOVERWRITE/S,DONTOVR=DONTOVERWRITE/S,"    \
  47.                 "FORCE/S"
  48.  
  49. #define COPYFLAG_ALL            (1<<0)
  50. #define COPYFLAG_DATES          (1<<1)
  51. #define COPYFLAG_NOPRO          (1<<2)
  52. #define COPYFLAG_COMMENT        (1<<3)
  53. #define COPYFLAG_FORCELINK      (1<<4)
  54. #define COPYFLAG_FORCEDELETE    (1<<5)
  55. #define COPYFLAG_FORCEOVERWRITE (1<<6)
  56. #define COPYFLAG_DONTOVERWRITE  (1<<7)
  57. #define COPYFLAG_QUIET          (1<<8)
  58. #define COPYFLAG_SILENT         (1<<9)
  59. #define COPYFLAG_ERRWARN    (1<<10)
  60.  
  61. #define COPYFLAG_SOFTLINK       (1<<20) /* produce softlinks */
  62. #define COPYFLAG_DEST_FILE      (1<<21) /* one file mode */
  63. #define COPYFLAG_DONE           (1<<22) /* did something in DoWork */
  64. #define COPYFLAG_ENTERSECOND    (1<<23) /* entered directory second time */
  65.  
  66. #define COPYFLAG_SRCNOFILESYS    (1<<24) /* source is no filesystem */
  67. #define COPYFLAG_DESNOFILESYS    (1<<25) /* destination is no filesystem */
  68.  
  69. #define COPYMODE_COPY           0
  70. #define COPYMODE_MOVE           1
  71. #define COPYMODE_DELETE         2
  72. #define COPYMODE_MAKEDIR    3
  73. #define COPYMODE_LINK           4
  74.  
  75. #define PRINTOUT_SIZE           50      /* maximum size of name printout */
  76. #define PRINTOUT_SPACES         10      /* maximum number of spaces      */
  77.  
  78. #define FILEPATH_SIZE           300     /* maximum size of filepaths     */
  79.  
  80. /* return values */
  81. #define TESTDEST_DIR_OK         2       /* directory exists, go in */
  82. #define TESTDEST_DELETED        1       /* file or empty directory deleted */
  83. #define TESTDEST_NONE           0       /* nothing existed */
  84. #define TESTDEST_ERROR          -1      /* an error occured */
  85. #define TESTDEST_CANTDELETE     -2      /* deletion not allowed (DONTOV) */
  86.  
  87. struct Args {
  88.   STRPTR *      from;
  89.   STRPTR        to;
  90.   STRPTR        pattern;
  91.   LONG *        buffer;
  92.   LONG          all;
  93.   LONG        direct;
  94.   LONG          clone;
  95.   LONG          dates;
  96.   LONG          nopro;
  97.   LONG          comment;
  98.   LONG          quiet;
  99.   LONG          silent;
  100.   LONG          noreq;
  101.   LONG        errwarn;
  102.   LONG        makedir;
  103.   LONG          move_mode;
  104.   LONG          delete_mode;
  105.   LONG          hardlink;
  106.   LONG          softlink;
  107.   LONG          forcelink;
  108.   LONG          forcedelete;
  109.   LONG          forceoverwrite;
  110.   LONG          dontoverwrite;
  111.   LONG        force;
  112. };
  113.  
  114. struct CopyData {
  115.   ULONG         Flags;
  116.   ULONG         BufferSize;
  117.   STRPTR        Pattern;
  118.   ULONG         Destination;
  119.   ULONG         CurDest;  /* Current Destination */
  120.   ULONG        DestPathSize;
  121.   struct FileInfoBlock *Fib;
  122.   UBYTE         Mode;
  123.   UBYTE         RetVal;         /* when set, error output is already done */
  124.   UBYTE         RetVal2;        /* when set, error output must be done */
  125.   UBYTE         Deep;
  126.   UBYTE        FileName[FILEPATH_SIZE];
  127.   UBYTE        DestName[FILEPATH_SIZE];
  128. };
  129.  
  130. #define TEXT_READ        texts[0]
  131. #define TEXT_COPIED             texts[1]
  132. #define TEXT_MOVED              texts[2]
  133. #define TEXT_DELETED            texts[3]
  134. #define TEXT_LINKED             texts[4]
  135. #define TEXT_RENAMED            texts[5]
  136. #define TEXT_CREATED            texts[6]
  137. #define TEXT_ENTERED            texts[7]
  138. #define TEXT_OPENED_FOR_OUTPUT  texts[8]
  139. #define TEXTNUM_MODE            9
  140. #define TEXT_DIRECTORY          texts[15]
  141. #define TEXT_NOT_DONE           texts[16]
  142. #define TEXT_NOTHING_DONE       texts[17]
  143. #define TEXT_ERR_FORCELINK      texts[18]
  144. #define TEXT_ERR_DELETE_DEVICE  texts[19]
  145. #define TEXT_ERR_DEST_DIR       texts[20]
  146. #define TEXT_ERR_INFINITE_LOOP  texts[21]
  147. #define TEXT_ERR_WILDCARD_DEST  texts[22]
  148.  
  149. STRPTR texts[] =
  150. {
  151. "read",
  152. "copied",
  153. "moved",
  154. "deleted",
  155. "linked",
  156. "renamed",
  157. "created",
  158. "entered",
  159. "opened for output",
  160. "COPY mode\n",
  161. "MOVE mode\n",
  162. "DELETE mode\n",
  163. "MAKEDIR mode\n",
  164. "HARDLINK mode\n",
  165. "SOFTLINK mode\n",
  166. "%s <Dir>",                /* output of directories */
  167. "not %s: ",
  168. "No file was processed.\n",
  169. "FORCELINK keyword required.\n",
  170. "A device cannot be deleted.",
  171. "Destination must be a directory.\n",
  172. "Infinite loop not allowed.\n",
  173. "Wildcard destination invalid.\n",
  174. };
  175.  
  176. LONG  CopyFile(ULONG, ULONG, ULONG);
  177. void  DoWork(STRPTR, struct CopyData *);
  178. LONG  IsPattern(STRPTR); /* return 0 -> NOPATTERN, return -1 --> ERROR */
  179. LONG  KillFile(STRPTR, ULONG);
  180. LONG  LinkFile(ULONG, STRPTR, ULONG);
  181. ULONG OpenDestDir(STRPTR, struct CopyData *);
  182. void  PatCopy(STRPTR, struct CopyData *);
  183. void  PrintName(STRPTR, ULONG, ULONG, ULONG);
  184. void  PrintNotDone(STRPTR, STRPTR, ULONG, ULONG);
  185. ULONG TestFileSys(STRPTR); /* returns value, when is a filesystem */
  186. void  SetData(STRPTR, struct CopyData *);
  187. LONG  TestDest(STRPTR, ULONG, struct CopyData *);
  188. ULONG TestLoop(ULONG, ULONG);
  189.  
  190. struct DosLibrary *DOSBase;
  191.  
  192. ULONG start(void)
  193. {
  194.   struct Process *task;
  195.   struct DosLibrary *dosbase;
  196.   struct CopyData cd;
  197.  
  198.   /* test for WB and reply startup-message */
  199.   if(!(task = (struct Process *) FindTask(0))->pr_CLI)
  200.   {
  201.     WaitPort(&task->pr_MsgPort);
  202.     Forbid();
  203.     ReplyMsg(GetMsg(&task->pr_MsgPort));
  204.     return RETURN_FAIL;
  205.   }
  206.  
  207.   memset(&cd, 0, sizeof(struct CopyData));
  208.   cd.BufferSize = 102400;
  209.   cd.Mode = COPYMODE_COPY;
  210.   cd.RetVal2 = RETURN_FAIL;
  211.   cd.Deep = 1;
  212.  
  213.   if((dosbase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
  214.   {
  215.     STRPTR a[2] = {"", 0};
  216.     struct RDArgs *rda;
  217.     struct Args args;
  218.  
  219.     DOSBase = dosbase;
  220.  
  221.     memset(&args, 0, sizeof(struct Args));
  222.  
  223.     if((rda = (struct RDArgs *) AllocDosObject(DOS_RDARGS, 0)))
  224.     {
  225.       rda->RDA_ExtHelp =
  226.       "FROM     multiple input files\n"
  227.       "TO       destination file or directory\n"
  228.       "PATTERN  a pattern the filenames must match\n"
  229.       "BUFFER   buffersize for copy buffer (default 200 [100K])\n"
  230.       "ALL      deep scan into sub directories\n"
  231.       "DIRECT   copy/delete only: work without any tests or options\n"
  232.       "CLONE    copy comment, protection bits and date as well\n"
  233.       "DATES    copy dates\n"
  234.       "NOPRO    do not copy protection bits\n"
  235.       "COMMENT  copy filecomment\n"
  236.       "QUIET    suppress all output and requesters\n"
  237.       "SILENT   suppress output, but not errors and requesters\n"
  238.       "NOREQ    suppress requesters\n"
  239.       "ERRWARN  do not proceed, when one file failed\n"
  240.       "MAKEDIR  produce directories\n"
  241.       "MOVE     delete source files after copying successful\n"
  242.       "DELETE   do not copy, but delete the source files\n"
  243.       "HARDLINK make a hardlink to source instead of copying\n"
  244.       "SOFTLINK make a softlink to source instead of copying\n"
  245.       "FOLNK    also makes links to directories\n"
  246.       "FODEL    delete protected files also\n"
  247.       "FOOVR    also overwrite protected files\n"
  248.       "DONTOVR  do never overwrite destination\n"
  249.       "FORCE    DO NOT USE. Call compatibility only.\n";
  250.  
  251.       if(ReadArgs(PARAM, (LONG *) &args, rda))
  252.       {
  253.         ULONG patbufsize = 0;
  254.         LONG i = 0;
  255.         APTR win = task->pr_WindowPtr;
  256.  
  257.         if(args.quiet) /* when QUIET, SILENT and NOREQ are also true! */
  258.           args.silent = args.noreq = 1;
  259.  
  260.         if(args.buffer && *args.buffer > 0) /* minimum buffer size */
  261.           cd.BufferSize = *args.buffer * 512;
  262.  
  263.         if(args.quiet)          cd.Flags |= COPYFLAG_QUIET;
  264.         if(args.silent)         cd.Flags |= COPYFLAG_SILENT;
  265.         if(args.all)            cd.Flags |= COPYFLAG_ALL;
  266.         if(args.clone)          cd.Flags |= COPYFLAG_DATES|COPYFLAG_COMMENT;
  267.         if(args.dates)          cd.Flags |= COPYFLAG_DATES;
  268.         if(args.comment)        cd.Flags |= COPYFLAG_COMMENT;
  269.         if(args.nopro)          cd.Flags |= COPYFLAG_NOPRO;
  270.         if(args.forcelink)      cd.Flags |= COPYFLAG_FORCELINK;
  271.         if(args.forcedelete)    cd.Flags |= COPYFLAG_FORCEDELETE;
  272.         if(args.forceoverwrite) cd.Flags |= COPYFLAG_FORCEOVERWRITE;
  273.         if(args.dontoverwrite)  cd.Flags |= COPYFLAG_DONTOVERWRITE;
  274.     if(args.errwarn)    cd.Flags |= COPYFLAG_ERRWARN;
  275.  
  276.     if(args.force) /* support OS Delete and MakeLink command options */
  277.     {
  278.       if(args.delete_mode)
  279.         cd.Flags |= COPYFLAG_FORCEDELETE;
  280.       if(args.hardlink || args.softlink)
  281.         cd.Flags |= COPYFLAG_FORCELINK;
  282.     }
  283.  
  284.         if(!args.from)  /* no args.from means currentdir */
  285.           args.from = a;
  286.  
  287.         if(args.noreq) /* no dos.library requests allowed */
  288.           task->pr_WindowPtr = (APTR) -1;
  289.  
  290.         if(args.delete_mode)    { ++i; cd.Mode = COPYMODE_DELETE; }
  291.         if(args.move_mode)      { ++i; cd.Mode = COPYMODE_MOVE; }
  292.     if(args.makedir)    { ++i; cd.Mode = COPYMODE_MAKEDIR; }
  293.         if(args.hardlink)       { ++i; cd.Mode = COPYMODE_LINK; }
  294.         if(args.softlink)
  295.         {
  296.           ++i;
  297.           cd.Mode = COPYMODE_LINK;
  298.           cd.Flags |= COPYFLAG_SOFTLINK|COPYFLAG_FORCELINK;
  299.         }
  300.  
  301.         if(cd.Mode != COPYMODE_DELETE && cd.Mode != COPYMODE_MAKEDIR &&
  302.         !args.to)
  303.         {
  304.           if(*(args.from+1)) /* when no TO is specified, the arg is last */
  305.           {                  /* one of from. Copy this argument into */
  306.             STRPTR *a;       /* args.to */
  307.  
  308.             a = args.from;
  309.             while(*(++a))
  310.               ;
  311.             args.to = *(--a); *a = 0;
  312.           }
  313.         }
  314.  
  315.         /* test if more than one of the above four or any other wrong
  316.            arguments */
  317.  
  318.     if(i > 1 ||
  319.     (args.from == a && cd.Mode == COPYMODE_MAKEDIR) ||
  320.     (args.direct && (args.from == a || !*args.from || cd.Pattern ||
  321.         (cd.Flags & ~(COPYFLAG_QUIET|COPYFLAG_SILENT|COPYFLAG_ERRWARN)) ||
  322.         (cd.Mode != COPYMODE_DELETE && (cd.Mode != COPYMODE_COPY ||
  323.         !args.to || args.from[1])))) ||
  324.     (args.dontoverwrite && args.forceoverwrite) ||
  325.     (args.nopro && args.clone) ||
  326.     (args.softlink && args.all) ||
  327.     (!args.to && cd.Mode != COPYMODE_DELETE && cd.Mode != COPYMODE_MAKEDIR))
  328.           SetIoErr(ERROR_TOO_MANY_ARGS);
  329.     else if(cd.Mode == COPYMODE_MAKEDIR)
  330.     {
  331.       ULONG i;
  332.       cd.RetVal2 = RETURN_OK;
  333.  
  334.           if(!args.silent)
  335.             Printf(texts[TEXTNUM_MODE+COPYMODE_MAKEDIR]);
  336.  
  337.       while(!cd.RetVal && !cd.RetVal2 && *args.from)
  338.       {
  339.             if((i = IsPattern(*args.from)))
  340.             {
  341.               if(i != -1)
  342.               {
  343.                 cd.RetVal = RETURN_ERROR;
  344.                 if(!args.quiet)
  345.                   Printf(TEXT_ERR_WILDCARD_DEST);
  346.               }
  347.               else
  348.                 cd.RetVal2 = RETURN_FAIL;
  349.             }
  350.         if((i = OpenDestDir(*args.from, &cd)))
  351.         {
  352.           UnLock(i);
  353.           cd.Flags |= COPYFLAG_DONE;
  354.         }
  355.         ++args.from;
  356.       }
  357.     } /* cd.Mode == COPYMODE_MAKEDIR */
  358.     else if(args.direct)
  359.     {
  360.       if(cd.Mode == COPYMODE_COPY)
  361.       {
  362.         ULONG in, out;
  363.  
  364.         if((in = Open(*args.from, MODE_OLDFILE)))
  365.         {
  366.           if((out = Open(args.to, MODE_NEWFILE)))
  367.           {
  368.             cd.RetVal2 = CopyFile(in, out, cd.BufferSize);
  369.             Close(out);
  370.           }
  371.           Close(in);
  372.         }
  373.       }
  374.       else /* COPYMODE_DELETE */
  375.       {
  376.         while(*args.from)
  377.               KillFile(*(args.from++), cd.Flags & COPYFLAG_FORCEDELETE);
  378.             cd.RetVal2 = RETURN_OK;
  379.       }
  380.     }
  381.         else
  382.         {
  383.           if(args.pattern && *args.pattern)
  384.           {
  385.             patbufsize = (SDI_strlen(args.pattern)<<1) + 1;
  386.             if((cd.Pattern = (STRPTR) AllocMem(patbufsize, MEMF_PUBLIC)))
  387.             {
  388.               if(ParsePattern(args.pattern, cd.Pattern, patbufsize) < 0)
  389.               {
  390.                 FreeMem(cd.Pattern, patbufsize); cd.Pattern = 0;
  391.               }
  392.             }
  393.           }
  394.  
  395.           if((cd.Fib = (struct FileInfoBlock *) AllocDosObject(DOS_FIB, 0)))
  396.           {
  397.             if(!args.silent)
  398.               Printf(texts[TEXTNUM_MODE+cd.Mode+
  399.               (cd.Flags & COPYFLAG_SOFTLINK ? 1 : 0)]);
  400.  
  401.             if(args.pattern && !cd.Pattern)
  402.             {
  403.               if(!*args.pattern)
  404.                 SetIoErr(ERROR_BAD_TEMPLATE);
  405.             }
  406.             else if(cd.Mode == COPYMODE_DELETE)
  407.             {
  408.               cd.RetVal2 = RETURN_OK;
  409.  
  410.               while(cd.RetVal <= (args.errwarn ? RETURN_OK : RETURN_WARN)
  411.               && *args.from)
  412.                 PatCopy(*(args.from++), &cd);
  413.  
  414.             }
  415.             else if((i = IsPattern(args.to)))
  416.             {
  417.               if(i != -1)
  418.               {
  419.                 cd.RetVal = RETURN_ERROR;
  420.                 if(!args.quiet)
  421.                   Printf(TEXT_ERR_WILDCARD_DEST);
  422.               }
  423.             }
  424.             else
  425.             {
  426.               STRPTR path;
  427.  
  428.               if(*(path = PathPart(args.to)) == '/')
  429.                 ++path; /* is destination a path description ? */
  430.  
  431.               if(*path && !*(args.from+1) && !(i = IsPattern(*args.from)))
  432.               {
  433.                 ULONG lock;
  434.  
  435.                 /* is destination an existing directory */
  436.                 if((lock = Lock(args.to, SHARED_LOCK)))
  437.                 {
  438.                   if(Examine(lock, cd.Fib))
  439.                   {
  440.                     if(cd.Fib->fib_DirEntryType > 0)
  441.                       cd.RetVal2 = RETURN_OK;
  442.                     /* indicate dir-mode for next if */
  443.                   }
  444.                   else
  445.                     i = 1;
  446.                   UnLock(lock);
  447.                 }
  448.  
  449.                 /* is source a directory */
  450.                 if(!i && cd.RetVal2 && (lock = Lock(*args.from, SHARED_LOCK)))
  451.                 {
  452.                   if(Examine(lock, cd.Fib))
  453.                   {
  454.                     cd.RetVal2 = RETURN_OK;
  455.                     if(cd.Mode != COPYMODE_COPY ||
  456.                     cd.Fib->fib_DirEntryType < 0)
  457.                     {
  458.                       UBYTE sep;
  459.  
  460.                       cd.Flags |= COPYFLAG_DEST_FILE;
  461.                       /* produce missing destination directories */
  462.                       sep = *path; *path = 0;
  463.                       if((cd.CurDest = OpenDestDir(args.to, &cd)))
  464.                       {
  465.                         *path = sep;
  466.                         /* do the job */
  467.             UnLock(lock); lock = 0;
  468.             CopyMem(*args.from, cd.FileName, 1+strlen(*args.from));
  469.                         DoWork(FilePart(args.to), &cd); /* on file call */
  470.             UnLock(cd.CurDest);
  471.                       }
  472.                     }
  473.                   }
  474.                   if(lock)
  475.                     UnLock(lock);
  476.                 }
  477.                 else if(cd.Mode == COPYMODE_COPY && !TestFileSys(*args.from))
  478.                 {
  479.                   UBYTE sep;
  480.                   cd.Flags |= COPYFLAG_DEST_FILE|COPYFLAG_SRCNOFILESYS;
  481.                   cd.RetVal2 = RETURN_OK;
  482.                   /* produce missing destination directories */
  483.                   sep = *path; *path = 0;
  484.                   if((cd.CurDest = OpenDestDir(args.to, &cd)))
  485.                   {
  486.                     *path = sep;
  487.                     /* do the job */
  488.             CopyMem(*args.from, cd.FileName, 1+strlen(*args.from));
  489.                     DoWork(FilePart(args.to), &cd); /* on file call */
  490.             UnLock(cd.CurDest);
  491.                   }
  492.                 }
  493.               }
  494.               else if(i != -1)
  495.                 cd.RetVal2 = RETURN_OK;
  496.  
  497.               if(!cd.RetVal && !cd.RetVal2 && !(cd.Flags &
  498.               COPYFLAG_DEST_FILE) && (cd.Destination =
  499.               OpenDestDir(args.to, &cd)))
  500.               {
  501.                 while(cd.RetVal <= (args.errwarn ? RETURN_OK : RETURN_WARN)
  502.                 && *args.from && !CTRL_C)
  503.                   PatCopy(*(args.from++), &cd);
  504.  
  505.                 UnLock(cd.Destination);
  506.               }
  507.             } /* else */
  508.  
  509.             if(!(cd.Flags & COPYFLAG_DONE) && !args.silent && !cd.RetVal
  510.             && !cd.RetVal2)
  511.               Printf(TEXT_NOTHING_DONE);
  512.  
  513.             FreeDosObject(DOS_FIB, cd.Fib);
  514.           } /* if((cd.Fib = ... )) */
  515.  
  516.           if(cd.Pattern)
  517.             FreeMem(cd.Pattern, patbufsize);
  518.         } /* else */
  519.  
  520.     task->pr_WindowPtr = win;
  521.  
  522.         FreeArgs(rda);
  523.       } /* ReadArgs */
  524.       FreeDosObject(DOS_RDARGS, rda);
  525.     } /* AllocDosObject */
  526.  
  527.     if(!cd.RetVal2 && CTRL_C)
  528.     {
  529.       SetIoErr(ERROR_BREAK);
  530.       cd.RetVal2 = RETURN_WARN;
  531.     }
  532.  
  533.     if(cd.RetVal2 && !args.quiet && !cd.RetVal)
  534.       PrintFault(IoErr(),0);
  535.  
  536.     if(cd.RetVal)
  537.       cd.RetVal2 = cd.RetVal;
  538.  
  539.     CloseLibrary((struct Library *) dosbase);
  540.  
  541.     if(args.errwarn && cd.RetVal2 == RETURN_WARN)
  542.       cd.RetVal2 = RETURN_ERROR;
  543.   }
  544.  
  545.   return cd.RetVal2;
  546. }
  547.  
  548. void PatCopy(STRPTR name, struct CopyData *cd)
  549. {
  550.   struct AnchorPath *APath;
  551.   ULONG retval, doit = 0, deep = 0, failval = RETURN_WARN, first = 0;
  552.  
  553. #ifdef DEBUG
  554.   Printf("PatCopy(%s, .)\n", name);
  555. #endif
  556.  
  557.   if((cd->Mode == COPYMODE_COPY || (cd->Flags & COPYFLAG_ALL)) &&
  558.   !IsPattern(name))
  559.     first = 1; /* enter first directory (support of old copy style) */
  560.  
  561.   if(cd->Flags & COPYFLAG_ERRWARN)
  562.     failval = RETURN_OK;
  563.  
  564.   cd->CurDest = cd->Destination;
  565.   cd->DestPathSize = 0;
  566.  
  567.   if(cd->Mode == COPYMODE_COPY && !TestFileSys(name))
  568.   {
  569.     cd->Flags |= COPYFLAG_SRCNOFILESYS;
  570.     CopyMem(name, cd->FileName, 1+strlen(name));
  571.     DoWork(FilePart(name), cd);
  572.     cd->Flags &= ~COPYFLAG_SRCNOFILESYS;
  573.     return;
  574.   }
  575.  
  576.   if((APath = (struct AnchorPath *) AllocMem(sizeof(struct AnchorPath) + FILEPATH_SIZE,
  577.   MEMF_PUBLIC|MEMF_CLEAR)))
  578.   {
  579.     APath->ap_BreakBits = SIGBREAKF_CTRL_C;
  580.     APath->ap_Strlen = FILEPATH_SIZE;
  581.  
  582.     for(retval = MatchFirst(name, APath); !retval && cd->RetVal <=
  583.     failval && !cd->RetVal2; retval = MatchNext(APath))
  584.     {
  585.       if(doit)
  586.       {
  587.         DoWork(cd->Fib->fib_FileName, cd); doit = 0;
  588.       }
  589.  
  590.       if(deep)         /* used for Deep checking */
  591.       {
  592.         ++cd->Deep; deep = 0;
  593.       }
  594.  
  595.       cd->Flags &= ~COPYFLAG_ENTERSECOND;
  596.  
  597.       CopyMem(APath->ap_Buf, cd->FileName, FILEPATH_SIZE);
  598.       CopyMem(&APath->ap_Info, cd->Fib, sizeof(struct FileInfoBlock));
  599.  
  600.       if(first && APath->ap_Info.fib_DirEntryType > 0)
  601.         APath->ap_Flags |= APF_DODIR;
  602.       else if(APath->ap_Flags & APF_DIDDIR)
  603.       {
  604.     ULONG i;
  605.         cd->Flags |= COPYFLAG_ENTERSECOND;
  606.         APath->ap_Flags &= ~APF_DIDDIR;
  607.         --cd->Deep;
  608.         if(cd->Mode == COPYMODE_DELETE || cd->Mode == COPYMODE_MOVE)
  609.       doit = 1;
  610.     if((i = cd->CurDest))
  611.     {
  612.           cd->CurDest = ParentDir(i);
  613.       cd->DestPathSize = 0;
  614.       if(i != cd->Destination)
  615.             UnLock(i);
  616.           if(!cd->CurDest)
  617.             break;
  618.         }
  619.       }
  620.       else if(APath->ap_Info.fib_DirEntryType > 0)
  621.       {
  622.     doit = 1;
  623.         if(cd->Flags & COPYFLAG_ALL)
  624.         {
  625.           APath->ap_Flags |= APF_DODIR;
  626.           deep = 1;
  627.         }
  628.       }
  629.       else if(!cd->Pattern || MatchPatternNoCase(cd->Pattern,
  630.       APath->ap_Info.fib_FileName))
  631.         doit = 1;
  632.       first = 0;
  633.     }
  634.     MatchEnd(APath);
  635.  
  636.     if(retval != ERROR_NO_MORE_ENTRIES)
  637.       cd->RetVal2 = RETURN_FAIL;
  638.  
  639.     if(doit)
  640.       DoWork(cd->Fib->fib_FileName, cd);
  641.  
  642. /* No need to clear the flags here, as they are cleared on next PatJoin
  643.    call (DoWork is not called first round, as lock is zero!). */
  644.  
  645.     FreeMem(APath, sizeof(struct AnchorPath) + FILEPATH_SIZE);
  646.   }
  647.   else
  648.   {
  649.     cd->RetVal = RETURN_FAIL;
  650.     if(!cd->Flags & COPYFLAG_QUIET)
  651.       PrintFault(ERROR_NO_FREE_STORE, 0);
  652.   }
  653.  
  654.   if(cd->CurDest && cd->CurDest != cd->Destination)
  655.     UnLock(cd->CurDest);
  656. }
  657.  
  658. LONG IsPattern(STRPTR name)
  659. {
  660.   LONG a, ret = -1;
  661.   STRPTR buffer;
  662.  
  663.   a = (strlen(name)<<1) + 10;
  664.  
  665.   if((buffer = (STRPTR) AllocMem(a, MEMF_ANY)))
  666.   {
  667.     ret = ParsePattern(name, buffer, a);
  668.     FreeMem(buffer, a);
  669.   }
  670.  
  671.   if(ret == -1)
  672.     SetIoErr(ERROR_NO_FREE_STORE);
  673.  
  674.   return ret;
  675. }
  676.  
  677. LONG KillFile(STRPTR name, ULONG doit)
  678. {
  679.   if(doit)
  680.     SetProtection(name, 0);
  681.   return DeleteFile(name);
  682. }
  683.  
  684. ULONG OpenDestDir(STRPTR name, struct CopyData *cd)
  685. {
  686.   LONG a, err = 0, cr = 0;
  687.   STRPTR ptr = name;
  688.   UBYTE as;
  689.  
  690.   if((cd->Mode == COPYMODE_COPY || cd->Mode == COPYMODE_MOVE) &&
  691.   !TestFileSys(name))
  692.   {
  693.     cd->Flags |= COPYFLAG_DESNOFILESYS;
  694.     CopyMem(name, cd->DestName, 1+strlen(name));
  695.     return (ULONG) Lock("", SHARED_LOCK);
  696.   }
  697.  
  698.   while(!err && *ptr != 0)
  699.   {
  700.     while(*ptr && *ptr != '/')
  701.       ++ptr;
  702.     as = *ptr;
  703.     *ptr = 0;
  704.  
  705.     if((a = TestDest(name, 1, cd)) == TESTDEST_CANTDELETE)
  706.     {
  707.       if(!(cd->Flags & COPYFLAG_QUIET))
  708.         Printf(TEXT_ERR_DEST_DIR);
  709.       err = 2;
  710.     }
  711.     else if(a < 0)
  712.       err = 1;
  713.     else if(a != TESTDEST_DIR_OK)
  714.     {
  715.       if((a = CreateDir(name)))
  716.       {
  717.     ++cr;
  718.         if(!(cd->Flags & COPYFLAG_SILENT))
  719.         {
  720.           PrintName(name, 1, 1, 1);
  721.           Printf("%s\n", TEXT_CREATED);
  722.         }
  723.         UnLock(a);
  724.       }
  725.       else
  726.       {
  727.         if(!(cd->Flags & COPYFLAG_QUIET))
  728.           PrintNotDone(name, TEXT_CREATED, 1, 1);
  729.         err = 2;
  730.       }
  731.     }
  732.     
  733.     *(ptr++) = as;
  734.   }
  735.  
  736.   if(err)
  737.   {
  738.     cd->RetVal = RETURN_ERROR;
  739.  
  740.     if(!(cd->Flags & COPYFLAG_QUIET) && err == 1)
  741.       PrintNotDone(name, TEXT_OPENED_FOR_OUTPUT, 1, 1);
  742.     return 0;
  743.   }
  744.  
  745.   if(cd->Mode == COPYMODE_MAKEDIR && !cr && !(cd->Flags & COPYFLAG_QUIET))
  746.   {
  747.     SetIoErr(ERROR_OBJECT_EXISTS);
  748.     PrintNotDone(name, TEXT_CREATED, 1, 1);
  749.   }
  750.  
  751.   return (ULONG) Lock(name, SHARED_LOCK);
  752. }
  753.  
  754. void PrintName(STRPTR name, ULONG deep, ULONG dir, ULONG txt)
  755. {
  756.   deep %= PRINTOUT_SPACES; /* reduce number of spaces */
  757.   /* This produces an error with MaxonC++ */
  758.  
  759.   while(deep--)
  760.     Printf(" ");
  761.  
  762.   if((deep = strlen(name)) > PRINTOUT_SIZE) /* reduce name size */
  763.   {
  764.     name += deep-PRINTOUT_SIZE;
  765.     Printf("...");
  766.   }
  767.  
  768.   Printf((dir ? TEXT_DIRECTORY : "%s"), name);
  769.   if(txt)
  770.     Printf(" ..");
  771.   Flush(Output());
  772. }
  773.  
  774. void PrintNotDone(STRPTR name, STRPTR txt, ULONG deep, ULONG dir)
  775. {
  776.   if(name)
  777.     PrintName(name, deep, dir, 1);
  778.   Printf(TEXT_NOT_DONE, txt);
  779.   PrintFault(IoErr(),0);
  780. }
  781.  
  782. /* returns value, when it seems to be a filesystem */
  783. ULONG TestFileSys(STRPTR name)
  784. {
  785.   STRPTR n = name;
  786.   ULONG ret = 1;
  787.  
  788.   while(*n && *n != ':')
  789.    ++n;
  790.  
  791.   if(*(n++) == ':')
  792.   {
  793.     UBYTE a;
  794.  
  795.     a = *n; *n = 0;
  796.     ret = IsFileSystem(name);
  797.     *n = a;
  798.   }  
  799.   return ret;
  800. }
  801.  
  802. void DoWork(STRPTR name, struct CopyData *cd)
  803. {
  804.   ULONG pdir, lock = 0;
  805.   STRPTR printerr = 0, printok = "";
  806.  
  807. #ifdef DEBUG
  808.   Printf("DoWork(%s, .)\n", name);
  809. #endif
  810.  
  811.   if(cd->RetVal > (cd->Flags & COPYFLAG_ERRWARN ? RETURN_OK : RETURN_WARN)
  812.   || cd->RetVal2)
  813.     return;
  814.  
  815.   if(cd->Mode != COPYMODE_DELETE && !(cd->Flags & COPYFLAG_DESNOFILESYS))
  816.   {
  817.     if(!cd->DestPathSize)
  818.     {
  819.       if(!NameFromLock(cd->CurDest, cd->DestName, FILEPATH_SIZE))
  820.       {
  821.         cd->RetVal2 = RETURN_FAIL;
  822.         UnLock(lock);
  823.         return;
  824.       }
  825.       cd->DestPathSize = strlen(cd->DestName);
  826.     }
  827.     cd->DestName[cd->DestPathSize] = 0;
  828.     AddPart(cd->DestName, name, FILEPATH_SIZE);
  829.   }
  830.  
  831.   if(cd->Flags & (COPYFLAG_SRCNOFILESYS|COPYFLAG_DESNOFILESYS))
  832.   {
  833.     ULONG in, out, res = 0, kill = 1;
  834.     STRPTR txt = TEXT_OPENED_FOR_OUTPUT;
  835.  
  836. #ifdef DEBUG
  837.     Printf("Partly DIRECT mode active now (%s - %s)\n", cd->FileName,
  838.     cd->DestName);
  839. #endif
  840.  
  841.     if((out = Open(cd->DestName, MODE_NEWFILE)))
  842.     {
  843.       txt = cd->Mode == COPYMODE_MOVE ? TEXT_MOVED : TEXT_COPIED;
  844.       if((in = Open(cd->FileName, MODE_OLDFILE)))
  845.       {
  846.         ULONG h;
  847.  
  848.     h = CopyFile(in, out, cd->BufferSize);
  849.     Close(in);
  850.     if(!h)
  851.     {
  852.       kill = 0;
  853.       if(cd->Mode == COPYMODE_MOVE)
  854.       {
  855.         if(KillFile(cd->FileName, cd->Flags & COPYFLAG_FORCEDELETE))
  856.               res = 1;
  857.       }
  858.       else
  859.         res = 1;
  860.     }
  861.       }
  862.       Close(out);
  863.  
  864.       if(kill)
  865.     KillFile(cd->DestName, 0);
  866.     }
  867.     if(!res && !(cd->Flags & COPYFLAG_QUIET))
  868.     PrintNotDone(cd->Flags & COPYFLAG_SILENT ? name : 0,
  869.     txt, cd->Deep, cd->Fib->fib_DirEntryType > 0);
  870.     else
  871.     {
  872.       cd->Flags |= COPYFLAG_DONE;
  873.       if(!(cd->Flags & COPYFLAG_SILENT))
  874.         Printf("%s\n", txt);
  875.     }
  876.     return;
  877.   }
  878.  
  879.   if(!(lock = Lock(cd->FileName, SHARED_LOCK)))
  880.   {
  881.     cd->RetVal = RETURN_WARN;
  882.     if(!(cd->Flags & COPYFLAG_QUIET))
  883.     {
  884.       PrintNotDone(cd->Fib->fib_FileName, TEXT_READ, cd->Deep,
  885.       cd->Fib->fib_DirEntryType > 0);
  886.     }
  887.     return;
  888.   }
  889.  
  890.   if(!(pdir = ParentDir(lock)))
  891.   {
  892.     cd->RetVal = RETURN_ERROR;
  893.     if(cd->Mode == COPYMODE_DELETE)
  894.     {
  895.       if(!(cd->Flags & COPYFLAG_QUIET))
  896.       {
  897.         Printf(" %s ", cd->FileName);
  898.         Printf(TEXT_NOT_DONE, TEXT_DELETED);
  899.         Printf("%s\n", TEXT_ERR_DELETE_DEVICE);
  900.       }
  901.     }
  902.     UnLock(lock);
  903.     return;
  904.   }
  905.   UnLock(pdir);
  906.  
  907.   if(!(cd->Flags & COPYFLAG_SILENT))
  908.     PrintName(name, cd->Deep, cd->Fib->fib_DirEntryType > 0,
  909.     cd->Fib->fib_DirEntryType < 0 || (cd->Flags & COPYFLAG_ALL ?
  910.     cd->Mode != COPYMODE_DELETE : cd->Mode != COPYMODE_COPY) ||
  911.     cd->Flags & COPYFLAG_ENTERSECOND);
  912.  
  913.   if((cd->Flags & COPYFLAG_ENTERSECOND) || (cd->Mode == COPYMODE_DELETE
  914.   && (!(cd->Flags & COPYFLAG_ALL) || cd->Fib->fib_DirEntryType < 0)))
  915.   {
  916.     UnLock(lock); lock = 0;
  917.  
  918.     if(KillFile(cd->FileName, cd->Flags & COPYFLAG_FORCEDELETE))
  919.       printok = TEXT_DELETED;
  920.     else
  921.     {
  922.       cd->RetVal = RETURN_WARN;
  923.       printerr = TEXT_DELETED;
  924.     }
  925.   }
  926.   else if(cd->Mode == COPYMODE_DELETE)
  927.     ;
  928.   else if(cd->Fib->fib_DirEntryType > 0)
  929.   {
  930.     ULONG a;
  931.  
  932.     if((cd->Flags & COPYFLAG_ALL || cd->Mode == COPYMODE_LINK ||
  933.     cd->Mode == COPYMODE_MOVE) && TestLoop(lock, cd->CurDest))
  934.     {
  935.       printok = 0;
  936.       cd->RetVal = RETURN_ERROR;
  937.       if(!(cd->Flags & COPYFLAG_QUIET))
  938.       {
  939.         if(cd->Flags & COPYFLAG_SILENT)
  940.           PrintName(name, cd->Deep, 1, 1);
  941.         Printf(TEXT_NOT_DONE, TEXT_ENTERED);
  942.         Printf(TEXT_ERR_INFINITE_LOOP);
  943.       }
  944.     }
  945.     else if((a = TestDest(cd->DestName, 1, cd)) < 0)
  946.     {
  947.       printerr = TEXT_CREATED; cd->RetVal = RETURN_ERROR;
  948.     }
  949.     else if(cd->Flags & COPYFLAG_ALL)
  950.     {
  951.       ULONG i;
  952.  
  953.       i = cd->CurDest;
  954.       cd->DestPathSize = 0;
  955.  
  956.       if(a == TESTDEST_DIR_OK)
  957.       {
  958.         if(!(cd->CurDest = Lock(cd->DestName, SHARED_LOCK)))
  959.         {
  960.           printerr = TEXT_ENTERED; cd->RetVal = RETURN_ERROR;
  961.         }
  962.         else
  963.           printok  = TEXT_ENTERED;
  964.       }
  965.       else if((cd->CurDest = CreateDir(cd->DestName)))
  966.       {
  967.         UnLock(cd->CurDest);
  968.         if((cd->CurDest = Lock(cd->DestName, SHARED_LOCK)))
  969.           printok = TEXT_CREATED;
  970.         else
  971.         {
  972.           printerr = TEXT_ENTERED; cd->RetVal = RETURN_ERROR;
  973.         }
  974.       }
  975.       else
  976.       {
  977.         printerr = TEXT_CREATED; cd->RetVal = RETURN_ERROR;
  978.       }
  979.       if(!cd->CurDest)
  980.         cd->CurDest = i;
  981.       else if(i != cd->Destination)
  982.         UnLock(i);
  983.     }
  984.     else if(cd->Mode == COPYMODE_MOVE)
  985.     {
  986.       if(Rename(cd->FileName, cd->DestName))
  987.         printok = TEXT_RENAMED;
  988.       else
  989.       {
  990.         printerr = TEXT_RENAMED; cd->RetVal = RETURN_WARN;
  991.       }
  992.     }
  993.     else if(cd->Mode == COPYMODE_LINK)
  994.     {
  995.       if(!(cd->Flags & COPYFLAG_FORCELINK))
  996.       {
  997.         printok = 0;
  998.         cd->RetVal = RETURN_WARN;
  999.         if(!(cd->Flags & COPYFLAG_QUIET))
  1000.         {
  1001.           if(cd->Flags & COPYFLAG_SILENT)
  1002.             PrintName(name, cd->Deep, 1, 1);
  1003.           Printf(TEXT_NOT_DONE, TEXT_LINKED);
  1004.           Printf(TEXT_ERR_FORCELINK);
  1005.         }
  1006.       }
  1007.       else if(LinkFile(lock, cd->DestName, cd->Flags & COPYFLAG_SOFTLINK))
  1008.         printok = TEXT_LINKED;
  1009.       else
  1010.       {
  1011.         printerr = TEXT_LINKED; cd->RetVal = RETURN_WARN;
  1012.       }
  1013.     }
  1014.     else /* COPY mode only displays directories, when not ALL */
  1015.     {
  1016.       printok = 0;
  1017.       if(!(cd->Flags & COPYFLAG_SILENT))
  1018.         Printf("\n");
  1019.     }
  1020.   }
  1021.   else
  1022.   {
  1023.     /* test for existing destination file */
  1024.     if(TestDest(cd->DestName, 0, cd) < 0)
  1025.       printerr = TEXT_OPENED_FOR_OUTPUT;
  1026.     else if(cd->Mode == COPYMODE_MOVE && Rename(cd->FileName, cd->DestName))
  1027.       printok = TEXT_RENAMED;
  1028.     else if(cd->Mode == COPYMODE_LINK)
  1029.     {
  1030.       if(!(cd->Flags & COPYFLAG_SOFTLINK) && LinkFile(lock, cd->DestName, 0))
  1031.         printok = TEXT_LINKED;
  1032.       else
  1033.       {
  1034.         printerr = TEXT_LINKED; cd->RetVal = RETURN_WARN;
  1035.         if(cd->Flags & COPYFLAG_SOFTLINK)
  1036.           SetIoErr(ERROR_OBJECT_WRONG_TYPE);
  1037.       }
  1038.     }
  1039.     else
  1040.     {
  1041.       ULONG in, out, res = 0, h;
  1042.       STRPTR txt = TEXT_OPENED_FOR_OUTPUT;
  1043.  
  1044.       if((out = Open(cd->DestName, MODE_NEWFILE)))
  1045.       {
  1046.         ULONG kill = 1;
  1047.  
  1048.     txt = cd->Mode == COPYMODE_MOVE ? TEXT_MOVED : TEXT_COPIED;
  1049.     UnLock(lock); lock = 0;
  1050.     if((in = Open(cd->FileName, MODE_OLDFILE)))
  1051.     {
  1052.       h = CopyFile(in, out, cd->BufferSize);
  1053.       Close(in);
  1054.       if(!h)
  1055.       {
  1056.         kill = 0;
  1057.         if(cd->Mode == COPYMODE_MOVE)
  1058.         {
  1059.           if(KillFile(cd->FileName, cd->Flags & COPYFLAG_FORCEDELETE))
  1060.                 res = 1;
  1061.         }
  1062.         else
  1063.           res = 1;
  1064.       }
  1065.         }
  1066.     Close(out);
  1067.  
  1068.     if(kill)
  1069.       KillFile(cd->DestName, 0);
  1070.       }
  1071.       if(!res)
  1072.       {
  1073.     printerr = txt; cd->RetVal = RETURN_WARN;
  1074.       }
  1075.       else
  1076.     printok = txt;
  1077.     }
  1078.   }
  1079.       
  1080.   if(printerr && !(cd->Flags & COPYFLAG_QUIET))
  1081.     PrintNotDone(cd->Flags & COPYFLAG_SILENT ? name : 0,
  1082.     printerr, cd->Deep, cd->Fib->fib_DirEntryType > 0);
  1083.   else if(printok)
  1084.   {
  1085.     cd->Flags |= COPYFLAG_DONE;
  1086.     if(!(cd->Flags & COPYFLAG_SILENT))
  1087.       Printf("%s\n", printok);
  1088.     SetData(cd->DestName, cd);
  1089.   }
  1090.  
  1091.   if(lock)
  1092.     UnLock(lock);
  1093. }
  1094.  
  1095. LONG CopyFile(ULONG from, ULONG to, ULONG bufsize)
  1096. {
  1097.   STRPTR buffer;
  1098.   LONG s, err = 0;
  1099.  
  1100.   if((buffer = (STRPTR) AllocMem(bufsize, MEMF_ANY)))
  1101.   {
  1102.     do
  1103.     {
  1104.       if((s = Read(from, buffer, bufsize)) == -1 ||
  1105.       Write(to, buffer, s) == -1)
  1106.         err = RETURN_FAIL;
  1107.     } while(s == bufsize && !err);
  1108.     FreeMem(buffer, bufsize);
  1109.   }
  1110.   else
  1111.     err = RETURN_FAIL;
  1112.  
  1113.   return err;
  1114. }
  1115.  
  1116. /* Softlink's path starts always with device name! f.e. "Ram Disk:T/..." */
  1117. LONG LinkFile(ULONG from, STRPTR to, ULONG soft)
  1118. {
  1119.   if(soft)
  1120.   {
  1121.     UBYTE name[FILEPATH_SIZE];
  1122.     NameFromLock(from, name, FILEPATH_SIZE);
  1123.     return MakeLink(to, (ULONG) name, LINK_SOFT);
  1124.   }
  1125.   else
  1126.     return MakeLink(to, from, LINK_HARD);
  1127. }
  1128.  
  1129. /* return 0 means no loop, return != 0 means loop found */
  1130. ULONG TestLoop(ULONG srcdir, ULONG destdir)
  1131. {
  1132.   ULONG par, lock, loop = 0;
  1133.  
  1134.   lock = destdir;
  1135.  
  1136.   if(SameDevice(srcdir, destdir))
  1137.   {
  1138.     do
  1139.     {
  1140.       if(!SameLock(srcdir, lock))
  1141.         loop = 1;
  1142.       else
  1143.       {
  1144.         par = ParentDir(lock);
  1145.         if(lock != destdir)
  1146.           UnLock(lock);
  1147.         lock = par;
  1148.       }
  1149.     } while(!loop && lock);
  1150.   }
  1151.  
  1152.   if(lock != destdir)
  1153.     UnLock(lock);
  1154.  
  1155.   return loop;
  1156. }
  1157.  
  1158. void SetData(STRPTR name, struct CopyData *cd)
  1159. {
  1160.   if(cd->Flags & COPYFLAG_NOPRO)
  1161.     SetProtection(name, 0);
  1162.   else
  1163.     SetProtection(name, cd->Fib->fib_Protection);
  1164.   if(cd->Flags & COPYFLAG_DATES)
  1165.     SetFileDate(name, &cd->Fib->fib_Date);
  1166.   if(cd->Flags & COPYFLAG_COMMENT)
  1167.     SetComment(name, cd->Fib->fib_Comment);
  1168. }
  1169.  
  1170. LONG TestDest(STRPTR name, ULONG type, struct CopyData *cd)
  1171. {
  1172.   LONG ret = TESTDEST_ERROR;
  1173.   ULONG lock;
  1174.  
  1175.   if((lock = Lock(name, SHARED_LOCK)))
  1176.   {
  1177.     struct FileInfoBlock *fib;
  1178.  
  1179.     if((fib = (struct FileInfoBlock *) AllocDosObject(DOS_FIB, 0)))
  1180.     {
  1181.       if(Examine(lock, fib))
  1182.       {
  1183.         UnLock(lock); lock = 0;
  1184.         if(type)
  1185.         {
  1186.           if(fib->fib_DirEntryType > 0)
  1187.             ret = TESTDEST_DIR_OK;
  1188.           else if(!(cd->Flags & COPYFLAG_DONTOVERWRITE))
  1189.           {
  1190.             if(KillFile(name, cd->Flags & COPYFLAG_FORCEOVERWRITE))
  1191.               ret = TESTDEST_DELETED;
  1192.           }
  1193.           else
  1194.             ret = TESTDEST_CANTDELETE;
  1195.         }
  1196.         else if(cd->Flags & COPYFLAG_DONTOVERWRITE)
  1197.           ret = TESTDEST_CANTDELETE;
  1198.         else if(KillFile(name, cd->Flags & COPYFLAG_FORCEOVERWRITE))
  1199.           ret = TESTDEST_DELETED;
  1200.       }
  1201.       FreeDosObject(DOS_FIB, fib);
  1202.     }
  1203.     if(lock)
  1204.       UnLock(lock);
  1205.   }
  1206.   else
  1207.     ret = TESTDEST_NONE;
  1208.  
  1209.   if(ret == TESTDEST_CANTDELETE)
  1210.     SetIoErr(ERROR_OBJECT_EXISTS);
  1211.  
  1212.   return ret;
  1213. }
  1214.  
  1215.