home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Dream 52
/
Amiga_Dream_52.iso
/
Amiga
/
Workbench
/
Patches
/
CopyReplace.lha
/
Source
/
Copy.c
next >
Wrap
C/C++ Source or Header
|
1998-05-08
|
33KB
|
1,215 lines
#define NAME "Copy"
#define REVISION "15"
#define DISTRIBUTION "(Freeware) "
//#define DEBUG
/* Programmheader
Name: Copy
Author: SDI
Distribution: Freeware
Description: copies, moves, deletes and links files
Compileropts: -
Linkeropts: -gsi -l amiga
1.0 02.08.97 : first version, only raw source
1.1 06.08.97 : added more stuff
1.2 08.08.97 : completed option description, added new code
1.3 09.08.97 : and more stuff done and SILENT option
1.4 11.08.97 : fixed problem with DELETE and ExNext function
1.5 14.08.97 : fixed DoWork, added new stuff
1.6 17.08.97 : added more functions, program is near completion
1.7 24.08.97 : bug fixes in DoWork function
1.8 25.09.97 : included missing functions, started debugging
1.9 26.09.97 : debugging, source cleanup
1.10 28.09.97 : and still debugging
1.11 30.09.97 : fixed some errors
1.12 04.10.97 : Added FORCE Option
1.13 19.12.97 : added DIRECT option
1.14 20.04.98 : with DIRECT now all softlinks can be deleted (Thanks to
Magnus Holmgren for reporting this)
1.15 06.05.98 : added automatic DIRECT detection with IsFileSystem
*/
#include <proto/dos.h>
#include <proto/exec.h>
#include <exec/memory.h>
#include "SDI_defines.h"
#define SDI_TO_ANSI
#include "SDI_ASM_STD_protos.h"
#define PARAM "FROM/M,TO,PAT=PATTERN/K,BUF=BUFFER/K/N,ALL/S," \
"DIRECT/S,CLONE/S,DATES/S,NOPRO/S,COM=COMMENT/S," \
"QUIET/S,SILENT/S,NOREQ/S,ERRWARN/S,MAKEDIR/S," \
"MOVE/S,DELETE/S,HARD=HARDLINK/S,SOFT=SOFTLINK/S," \
"FOLNK=FORCELINK/S,FODEL=FORCEDELETE/S," \
"FOOVR=FORCEOVERWRITE/S,DONTOVR=DONTOVERWRITE/S," \
"FORCE/S"
#define COPYFLAG_ALL (1<<0)
#define COPYFLAG_DATES (1<<1)
#define COPYFLAG_NOPRO (1<<2)
#define COPYFLAG_COMMENT (1<<3)
#define COPYFLAG_FORCELINK (1<<4)
#define COPYFLAG_FORCEDELETE (1<<5)
#define COPYFLAG_FORCEOVERWRITE (1<<6)
#define COPYFLAG_DONTOVERWRITE (1<<7)
#define COPYFLAG_QUIET (1<<8)
#define COPYFLAG_SILENT (1<<9)
#define COPYFLAG_ERRWARN (1<<10)
#define COPYFLAG_SOFTLINK (1<<20) /* produce softlinks */
#define COPYFLAG_DEST_FILE (1<<21) /* one file mode */
#define COPYFLAG_DONE (1<<22) /* did something in DoWork */
#define COPYFLAG_ENTERSECOND (1<<23) /* entered directory second time */
#define COPYFLAG_SRCNOFILESYS (1<<24) /* source is no filesystem */
#define COPYFLAG_DESNOFILESYS (1<<25) /* destination is no filesystem */
#define COPYMODE_COPY 0
#define COPYMODE_MOVE 1
#define COPYMODE_DELETE 2
#define COPYMODE_MAKEDIR 3
#define COPYMODE_LINK 4
#define PRINTOUT_SIZE 50 /* maximum size of name printout */
#define PRINTOUT_SPACES 10 /* maximum number of spaces */
#define FILEPATH_SIZE 300 /* maximum size of filepaths */
/* return values */
#define TESTDEST_DIR_OK 2 /* directory exists, go in */
#define TESTDEST_DELETED 1 /* file or empty directory deleted */
#define TESTDEST_NONE 0 /* nothing existed */
#define TESTDEST_ERROR -1 /* an error occured */
#define TESTDEST_CANTDELETE -2 /* deletion not allowed (DONTOV) */
struct Args {
STRPTR * from;
STRPTR to;
STRPTR pattern;
LONG * buffer;
LONG all;
LONG direct;
LONG clone;
LONG dates;
LONG nopro;
LONG comment;
LONG quiet;
LONG silent;
LONG noreq;
LONG errwarn;
LONG makedir;
LONG move_mode;
LONG delete_mode;
LONG hardlink;
LONG softlink;
LONG forcelink;
LONG forcedelete;
LONG forceoverwrite;
LONG dontoverwrite;
LONG force;
};
struct CopyData {
ULONG Flags;
ULONG BufferSize;
STRPTR Pattern;
ULONG Destination;
ULONG CurDest; /* Current Destination */
ULONG DestPathSize;
struct FileInfoBlock *Fib;
UBYTE Mode;
UBYTE RetVal; /* when set, error output is already done */
UBYTE RetVal2; /* when set, error output must be done */
UBYTE Deep;
UBYTE FileName[FILEPATH_SIZE];
UBYTE DestName[FILEPATH_SIZE];
};
#define TEXT_READ texts[0]
#define TEXT_COPIED texts[1]
#define TEXT_MOVED texts[2]
#define TEXT_DELETED texts[3]
#define TEXT_LINKED texts[4]
#define TEXT_RENAMED texts[5]
#define TEXT_CREATED texts[6]
#define TEXT_ENTERED texts[7]
#define TEXT_OPENED_FOR_OUTPUT texts[8]
#define TEXTNUM_MODE 9
#define TEXT_DIRECTORY texts[15]
#define TEXT_NOT_DONE texts[16]
#define TEXT_NOTHING_DONE texts[17]
#define TEXT_ERR_FORCELINK texts[18]
#define TEXT_ERR_DELETE_DEVICE texts[19]
#define TEXT_ERR_DEST_DIR texts[20]
#define TEXT_ERR_INFINITE_LOOP texts[21]
#define TEXT_ERR_WILDCARD_DEST texts[22]
STRPTR texts[] =
{
"read",
"copied",
"moved",
"deleted",
"linked",
"renamed",
"created",
"entered",
"opened for output",
"COPY mode\n",
"MOVE mode\n",
"DELETE mode\n",
"MAKEDIR mode\n",
"HARDLINK mode\n",
"SOFTLINK mode\n",
"%s <Dir>", /* output of directories */
"not %s: ",
"No file was processed.\n",
"FORCELINK keyword required.\n",
"A device cannot be deleted.",
"Destination must be a directory.\n",
"Infinite loop not allowed.\n",
"Wildcard destination invalid.\n",
};
LONG CopyFile(ULONG, ULONG, ULONG);
void DoWork(STRPTR, struct CopyData *);
LONG IsPattern(STRPTR); /* return 0 -> NOPATTERN, return -1 --> ERROR */
LONG KillFile(STRPTR, ULONG);
LONG LinkFile(ULONG, STRPTR, ULONG);
ULONG OpenDestDir(STRPTR, struct CopyData *);
void PatCopy(STRPTR, struct CopyData *);
void PrintName(STRPTR, ULONG, ULONG, ULONG);
void PrintNotDone(STRPTR, STRPTR, ULONG, ULONG);
ULONG TestFileSys(STRPTR); /* returns value, when is a filesystem */
void SetData(STRPTR, struct CopyData *);
LONG TestDest(STRPTR, ULONG, struct CopyData *);
ULONG TestLoop(ULONG, ULONG);
struct DosLibrary *DOSBase;
ULONG start(void)
{
struct Process *task;
struct DosLibrary *dosbase;
struct CopyData cd;
/* test for WB and reply startup-message */
if(!(task = (struct Process *) FindTask(0))->pr_CLI)
{
WaitPort(&task->pr_MsgPort);
Forbid();
ReplyMsg(GetMsg(&task->pr_MsgPort));
return RETURN_FAIL;
}
memset(&cd, 0, sizeof(struct CopyData));
cd.BufferSize = 102400;
cd.Mode = COPYMODE_COPY;
cd.RetVal2 = RETURN_FAIL;
cd.Deep = 1;
if((dosbase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
{
STRPTR a[2] = {"", 0};
struct RDArgs *rda;
struct Args args;
DOSBase = dosbase;
memset(&args, 0, sizeof(struct Args));
if((rda = (struct RDArgs *) AllocDosObject(DOS_RDARGS, 0)))
{
rda->RDA_ExtHelp =
"FROM multiple input files\n"
"TO destination file or directory\n"
"PATTERN a pattern the filenames must match\n"
"BUFFER buffersize for copy buffer (default 200 [100K])\n"
"ALL deep scan into sub directories\n"
"DIRECT copy/delete only: work without any tests or options\n"
"CLONE copy comment, protection bits and date as well\n"
"DATES copy dates\n"
"NOPRO do not copy protection bits\n"
"COMMENT copy filecomment\n"
"QUIET suppress all output and requesters\n"
"SILENT suppress output, but not errors and requesters\n"
"NOREQ suppress requesters\n"
"ERRWARN do not proceed, when one file failed\n"
"MAKEDIR produce directories\n"
"MOVE delete source files after copying successful\n"
"DELETE do not copy, but delete the source files\n"
"HARDLINK make a hardlink to source instead of copying\n"
"SOFTLINK make a softlink to source instead of copying\n"
"FOLNK also makes links to directories\n"
"FODEL delete protected files also\n"
"FOOVR also overwrite protected files\n"
"DONTOVR do never overwrite destination\n"
"FORCE DO NOT USE. Call compatibility only.\n";
if(ReadArgs(PARAM, (LONG *) &args, rda))
{
ULONG patbufsize = 0;
LONG i = 0;
APTR win = task->pr_WindowPtr;
if(args.quiet) /* when QUIET, SILENT and NOREQ are also true! */
args.silent = args.noreq = 1;
if(args.buffer && *args.buffer > 0) /* minimum buffer size */
cd.BufferSize = *args.buffer * 512;
if(args.quiet) cd.Flags |= COPYFLAG_QUIET;
if(args.silent) cd.Flags |= COPYFLAG_SILENT;
if(args.all) cd.Flags |= COPYFLAG_ALL;
if(args.clone) cd.Flags |= COPYFLAG_DATES|COPYFLAG_COMMENT;
if(args.dates) cd.Flags |= COPYFLAG_DATES;
if(args.comment) cd.Flags |= COPYFLAG_COMMENT;
if(args.nopro) cd.Flags |= COPYFLAG_NOPRO;
if(args.forcelink) cd.Flags |= COPYFLAG_FORCELINK;
if(args.forcedelete) cd.Flags |= COPYFLAG_FORCEDELETE;
if(args.forceoverwrite) cd.Flags |= COPYFLAG_FORCEOVERWRITE;
if(args.dontoverwrite) cd.Flags |= COPYFLAG_DONTOVERWRITE;
if(args.errwarn) cd.Flags |= COPYFLAG_ERRWARN;
if(args.force) /* support OS Delete and MakeLink command options */
{
if(args.delete_mode)
cd.Flags |= COPYFLAG_FORCEDELETE;
if(args.hardlink || args.softlink)
cd.Flags |= COPYFLAG_FORCELINK;
}
if(!args.from) /* no args.from means currentdir */
args.from = a;
if(args.noreq) /* no dos.library requests allowed */
task->pr_WindowPtr = (APTR) -1;
if(args.delete_mode) { ++i; cd.Mode = COPYMODE_DELETE; }
if(args.move_mode) { ++i; cd.Mode = COPYMODE_MOVE; }
if(args.makedir) { ++i; cd.Mode = COPYMODE_MAKEDIR; }
if(args.hardlink) { ++i; cd.Mode = COPYMODE_LINK; }
if(args.softlink)
{
++i;
cd.Mode = COPYMODE_LINK;
cd.Flags |= COPYFLAG_SOFTLINK|COPYFLAG_FORCELINK;
}
if(cd.Mode != COPYMODE_DELETE && cd.Mode != COPYMODE_MAKEDIR &&
!args.to)
{
if(*(args.from+1)) /* when no TO is specified, the arg is last */
{ /* one of from. Copy this argument into */
STRPTR *a; /* args.to */
a = args.from;
while(*(++a))
;
args.to = *(--a); *a = 0;
}
}
/* test if more than one of the above four or any other wrong
arguments */
if(i > 1 ||
(args.from == a && cd.Mode == COPYMODE_MAKEDIR) ||
(args.direct && (args.from == a || !*args.from || cd.Pattern ||
(cd.Flags & ~(COPYFLAG_QUIET|COPYFLAG_SILENT|COPYFLAG_ERRWARN)) ||
(cd.Mode != COPYMODE_DELETE && (cd.Mode != COPYMODE_COPY ||
!args.to || args.from[1])))) ||
(args.dontoverwrite && args.forceoverwrite) ||
(args.nopro && args.clone) ||
(args.softlink && args.all) ||
(!args.to && cd.Mode != COPYMODE_DELETE && cd.Mode != COPYMODE_MAKEDIR))
SetIoErr(ERROR_TOO_MANY_ARGS);
else if(cd.Mode == COPYMODE_MAKEDIR)
{
ULONG i;
cd.RetVal2 = RETURN_OK;
if(!args.silent)
Printf(texts[TEXTNUM_MODE+COPYMODE_MAKEDIR]);
while(!cd.RetVal && !cd.RetVal2 && *args.from)
{
if((i = IsPattern(*args.from)))
{
if(i != -1)
{
cd.RetVal = RETURN_ERROR;
if(!args.quiet)
Printf(TEXT_ERR_WILDCARD_DEST);
}
else
cd.RetVal2 = RETURN_FAIL;
}
if((i = OpenDestDir(*args.from, &cd)))
{
UnLock(i);
cd.Flags |= COPYFLAG_DONE;
}
++args.from;
}
} /* cd.Mode == COPYMODE_MAKEDIR */
else if(args.direct)
{
if(cd.Mode == COPYMODE_COPY)
{
ULONG in, out;
if((in = Open(*args.from, MODE_OLDFILE)))
{
if((out = Open(args.to, MODE_NEWFILE)))
{
cd.RetVal2 = CopyFile(in, out, cd.BufferSize);
Close(out);
}
Close(in);
}
}
else /* COPYMODE_DELETE */
{
while(*args.from)
KillFile(*(args.from++), cd.Flags & COPYFLAG_FORCEDELETE);
cd.RetVal2 = RETURN_OK;
}
}
else
{
if(args.pattern && *args.pattern)
{
patbufsize = (SDI_strlen(args.pattern)<<1) + 1;
if((cd.Pattern = (STRPTR) AllocMem(patbufsize, MEMF_PUBLIC)))
{
if(ParsePattern(args.pattern, cd.Pattern, patbufsize) < 0)
{
FreeMem(cd.Pattern, patbufsize); cd.Pattern = 0;
}
}
}
if((cd.Fib = (struct FileInfoBlock *) AllocDosObject(DOS_FIB, 0)))
{
if(!args.silent)
Printf(texts[TEXTNUM_MODE+cd.Mode+
(cd.Flags & COPYFLAG_SOFTLINK ? 1 : 0)]);
if(args.pattern && !cd.Pattern)
{
if(!*args.pattern)
SetIoErr(ERROR_BAD_TEMPLATE);
}
else if(cd.Mode == COPYMODE_DELETE)
{
cd.RetVal2 = RETURN_OK;
while(cd.RetVal <= (args.errwarn ? RETURN_OK : RETURN_WARN)
&& *args.from)
PatCopy(*(args.from++), &cd);
}
else if((i = IsPattern(args.to)))
{
if(i != -1)
{
cd.RetVal = RETURN_ERROR;
if(!args.quiet)
Printf(TEXT_ERR_WILDCARD_DEST);
}
}
else
{
STRPTR path;
if(*(path = PathPart(args.to)) == '/')
++path; /* is destination a path description ? */
if(*path && !*(args.from+1) && !(i = IsPattern(*args.from)))
{
ULONG lock;
/* is destination an existing directory */
if((lock = Lock(args.to, SHARED_LOCK)))
{
if(Examine(lock, cd.Fib))
{
if(cd.Fib->fib_DirEntryType > 0)
cd.RetVal2 = RETURN_OK;
/* indicate dir-mode for next if */
}
else
i = 1;
UnLock(lock);
}
/* is source a directory */
if(!i && cd.RetVal2 && (lock = Lock(*args.from, SHARED_LOCK)))
{
if(Examine(lock, cd.Fib))
{
cd.RetVal2 = RETURN_OK;
if(cd.Mode != COPYMODE_COPY ||
cd.Fib->fib_DirEntryType < 0)
{
UBYTE sep;
cd.Flags |= COPYFLAG_DEST_FILE;
/* produce missing destination directories */
sep = *path; *path = 0;
if((cd.CurDest = OpenDestDir(args.to, &cd)))
{
*path = sep;
/* do the job */
UnLock(lock); lock = 0;
CopyMem(*args.from, cd.FileName, 1+strlen(*args.from));
DoWork(FilePart(args.to), &cd); /* on file call */
UnLock(cd.CurDest);
}
}
}
if(lock)
UnLock(lock);
}
else if(cd.Mode == COPYMODE_COPY && !TestFileSys(*args.from))
{
UBYTE sep;
cd.Flags |= COPYFLAG_DEST_FILE|COPYFLAG_SRCNOFILESYS;
cd.RetVal2 = RETURN_OK;
/* produce missing destination directories */
sep = *path; *path = 0;
if((cd.CurDest = OpenDestDir(args.to, &cd)))
{
*path = sep;
/* do the job */
CopyMem(*args.from, cd.FileName, 1+strlen(*args.from));
DoWork(FilePart(args.to), &cd); /* on file call */
UnLock(cd.CurDest);
}
}
}
else if(i != -1)
cd.RetVal2 = RETURN_OK;
if(!cd.RetVal && !cd.RetVal2 && !(cd.Flags &
COPYFLAG_DEST_FILE) && (cd.Destination =
OpenDestDir(args.to, &cd)))
{
while(cd.RetVal <= (args.errwarn ? RETURN_OK : RETURN_WARN)
&& *args.from && !CTRL_C)
PatCopy(*(args.from++), &cd);
UnLock(cd.Destination);
}
} /* else */
if(!(cd.Flags & COPYFLAG_DONE) && !args.silent && !cd.RetVal
&& !cd.RetVal2)
Printf(TEXT_NOTHING_DONE);
FreeDosObject(DOS_FIB, cd.Fib);
} /* if((cd.Fib = ... )) */
if(cd.Pattern)
FreeMem(cd.Pattern, patbufsize);
} /* else */
task->pr_WindowPtr = win;
FreeArgs(rda);
} /* ReadArgs */
FreeDosObject(DOS_RDARGS, rda);
} /* AllocDosObject */
if(!cd.RetVal2 && CTRL_C)
{
SetIoErr(ERROR_BREAK);
cd.RetVal2 = RETURN_WARN;
}
if(cd.RetVal2 && !args.quiet && !cd.RetVal)
PrintFault(IoErr(),0);
if(cd.RetVal)
cd.RetVal2 = cd.RetVal;
CloseLibrary((struct Library *) dosbase);
if(args.errwarn && cd.RetVal2 == RETURN_WARN)
cd.RetVal2 = RETURN_ERROR;
}
return cd.RetVal2;
}
void PatCopy(STRPTR name, struct CopyData *cd)
{
struct AnchorPath *APath;
ULONG retval, doit = 0, deep = 0, failval = RETURN_WARN, first = 0;
#ifdef DEBUG
Printf("PatCopy(%s, .)\n", name);
#endif
if((cd->Mode == COPYMODE_COPY || (cd->Flags & COPYFLAG_ALL)) &&
!IsPattern(name))
first = 1; /* enter first directory (support of old copy style) */
if(cd->Flags & COPYFLAG_ERRWARN)
failval = RETURN_OK;
cd->CurDest = cd->Destination;
cd->DestPathSize = 0;
if(cd->Mode == COPYMODE_COPY && !TestFileSys(name))
{
cd->Flags |= COPYFLAG_SRCNOFILESYS;
CopyMem(name, cd->FileName, 1+strlen(name));
DoWork(FilePart(name), cd);
cd->Flags &= ~COPYFLAG_SRCNOFILESYS;
return;
}
if((APath = (struct AnchorPath *) AllocMem(sizeof(struct AnchorPath) + FILEPATH_SIZE,
MEMF_PUBLIC|MEMF_CLEAR)))
{
APath->ap_BreakBits = SIGBREAKF_CTRL_C;
APath->ap_Strlen = FILEPATH_SIZE;
for(retval = MatchFirst(name, APath); !retval && cd->RetVal <=
failval && !cd->RetVal2; retval = MatchNext(APath))
{
if(doit)
{
DoWork(cd->Fib->fib_FileName, cd); doit = 0;
}
if(deep) /* used for Deep checking */
{
++cd->Deep; deep = 0;
}
cd->Flags &= ~COPYFLAG_ENTERSECOND;
CopyMem(APath->ap_Buf, cd->FileName, FILEPATH_SIZE);
CopyMem(&APath->ap_Info, cd->Fib, sizeof(struct FileInfoBlock));
if(first && APath->ap_Info.fib_DirEntryType > 0)
APath->ap_Flags |= APF_DODIR;
else if(APath->ap_Flags & APF_DIDDIR)
{
ULONG i;
cd->Flags |= COPYFLAG_ENTERSECOND;
APath->ap_Flags &= ~APF_DIDDIR;
--cd->Deep;
if(cd->Mode == COPYMODE_DELETE || cd->Mode == COPYMODE_MOVE)
doit = 1;
if((i = cd->CurDest))
{
cd->CurDest = ParentDir(i);
cd->DestPathSize = 0;
if(i != cd->Destination)
UnLock(i);
if(!cd->CurDest)
break;
}
}
else if(APath->ap_Info.fib_DirEntryType > 0)
{
doit = 1;
if(cd->Flags & COPYFLAG_ALL)
{
APath->ap_Flags |= APF_DODIR;
deep = 1;
}
}
else if(!cd->Pattern || MatchPatternNoCase(cd->Pattern,
APath->ap_Info.fib_FileName))
doit = 1;
first = 0;
}
MatchEnd(APath);
if(retval != ERROR_NO_MORE_ENTRIES)
cd->RetVal2 = RETURN_FAIL;
if(doit)
DoWork(cd->Fib->fib_FileName, cd);
/* No need to clear the flags here, as they are cleared on next PatJoin
call (DoWork is not called first round, as lock is zero!). */
FreeMem(APath, sizeof(struct AnchorPath) + FILEPATH_SIZE);
}
else
{
cd->RetVal = RETURN_FAIL;
if(!cd->Flags & COPYFLAG_QUIET)
PrintFault(ERROR_NO_FREE_STORE, 0);
}
if(cd->CurDest && cd->CurDest != cd->Destination)
UnLock(cd->CurDest);
}
LONG IsPattern(STRPTR name)
{
LONG a, ret = -1;
STRPTR buffer;
a = (strlen(name)<<1) + 10;
if((buffer = (STRPTR) AllocMem(a, MEMF_ANY)))
{
ret = ParsePattern(name, buffer, a);
FreeMem(buffer, a);
}
if(ret == -1)
SetIoErr(ERROR_NO_FREE_STORE);
return ret;
}
LONG KillFile(STRPTR name, ULONG doit)
{
if(doit)
SetProtection(name, 0);
return DeleteFile(name);
}
ULONG OpenDestDir(STRPTR name, struct CopyData *cd)
{
LONG a, err = 0, cr = 0;
STRPTR ptr = name;
UBYTE as;
if((cd->Mode == COPYMODE_COPY || cd->Mode == COPYMODE_MOVE) &&
!TestFileSys(name))
{
cd->Flags |= COPYFLAG_DESNOFILESYS;
CopyMem(name, cd->DestName, 1+strlen(name));
return (ULONG) Lock("", SHARED_LOCK);
}
while(!err && *ptr != 0)
{
while(*ptr && *ptr != '/')
++ptr;
as = *ptr;
*ptr = 0;
if((a = TestDest(name, 1, cd)) == TESTDEST_CANTDELETE)
{
if(!(cd->Flags & COPYFLAG_QUIET))
Printf(TEXT_ERR_DEST_DIR);
err = 2;
}
else if(a < 0)
err = 1;
else if(a != TESTDEST_DIR_OK)
{
if((a = CreateDir(name)))
{
++cr;
if(!(cd->Flags & COPYFLAG_SILENT))
{
PrintName(name, 1, 1, 1);
Printf("%s\n", TEXT_CREATED);
}
UnLock(a);
}
else
{
if(!(cd->Flags & COPYFLAG_QUIET))
PrintNotDone(name, TEXT_CREATED, 1, 1);
err = 2;
}
}
*(ptr++) = as;
}
if(err)
{
cd->RetVal = RETURN_ERROR;
if(!(cd->Flags & COPYFLAG_QUIET) && err == 1)
PrintNotDone(name, TEXT_OPENED_FOR_OUTPUT, 1, 1);
return 0;
}
if(cd->Mode == COPYMODE_MAKEDIR && !cr && !(cd->Flags & COPYFLAG_QUIET))
{
SetIoErr(ERROR_OBJECT_EXISTS);
PrintNotDone(name, TEXT_CREATED, 1, 1);
}
return (ULONG) Lock(name, SHARED_LOCK);
}
void PrintName(STRPTR name, ULONG deep, ULONG dir, ULONG txt)
{
deep %= PRINTOUT_SPACES; /* reduce number of spaces */
/* This produces an error with MaxonC++ */
while(deep--)
Printf(" ");
if((deep = strlen(name)) > PRINTOUT_SIZE) /* reduce name size */
{
name += deep-PRINTOUT_SIZE;
Printf("...");
}
Printf((dir ? TEXT_DIRECTORY : "%s"), name);
if(txt)
Printf(" ..");
Flush(Output());
}
void PrintNotDone(STRPTR name, STRPTR txt, ULONG deep, ULONG dir)
{
if(name)
PrintName(name, deep, dir, 1);
Printf(TEXT_NOT_DONE, txt);
PrintFault(IoErr(),0);
}
/* returns value, when it seems to be a filesystem */
ULONG TestFileSys(STRPTR name)
{
STRPTR n = name;
ULONG ret = 1;
while(*n && *n != ':')
++n;
if(*(n++) == ':')
{
UBYTE a;
a = *n; *n = 0;
ret = IsFileSystem(name);
*n = a;
}
return ret;
}
void DoWork(STRPTR name, struct CopyData *cd)
{
ULONG pdir, lock = 0;
STRPTR printerr = 0, printok = "";
#ifdef DEBUG
Printf("DoWork(%s, .)\n", name);
#endif
if(cd->RetVal > (cd->Flags & COPYFLAG_ERRWARN ? RETURN_OK : RETURN_WARN)
|| cd->RetVal2)
return;
if(cd->Mode != COPYMODE_DELETE && !(cd->Flags & COPYFLAG_DESNOFILESYS))
{
if(!cd->DestPathSize)
{
if(!NameFromLock(cd->CurDest, cd->DestName, FILEPATH_SIZE))
{
cd->RetVal2 = RETURN_FAIL;
UnLock(lock);
return;
}
cd->DestPathSize = strlen(cd->DestName);
}
cd->DestName[cd->DestPathSize] = 0;
AddPart(cd->DestName, name, FILEPATH_SIZE);
}
if(cd->Flags & (COPYFLAG_SRCNOFILESYS|COPYFLAG_DESNOFILESYS))
{
ULONG in, out, res = 0, kill = 1;
STRPTR txt = TEXT_OPENED_FOR_OUTPUT;
#ifdef DEBUG
Printf("Partly DIRECT mode active now (%s - %s)\n", cd->FileName,
cd->DestName);
#endif
if((out = Open(cd->DestName, MODE_NEWFILE)))
{
txt = cd->Mode == COPYMODE_MOVE ? TEXT_MOVED : TEXT_COPIED;
if((in = Open(cd->FileName, MODE_OLDFILE)))
{
ULONG h;
h = CopyFile(in, out, cd->BufferSize);
Close(in);
if(!h)
{
kill = 0;
if(cd->Mode == COPYMODE_MOVE)
{
if(KillFile(cd->FileName, cd->Flags & COPYFLAG_FORCEDELETE))
res = 1;
}
else
res = 1;
}
}
Close(out);
if(kill)
KillFile(cd->DestName, 0);
}
if(!res && !(cd->Flags & COPYFLAG_QUIET))
PrintNotDone(cd->Flags & COPYFLAG_SILENT ? name : 0,
txt, cd->Deep, cd->Fib->fib_DirEntryType > 0);
else
{
cd->Flags |= COPYFLAG_DONE;
if(!(cd->Flags & COPYFLAG_SILENT))
Printf("%s\n", txt);
}
return;
}
if(!(lock = Lock(cd->FileName, SHARED_LOCK)))
{
cd->RetVal = RETURN_WARN;
if(!(cd->Flags & COPYFLAG_QUIET))
{
PrintNotDone(cd->Fib->fib_FileName, TEXT_READ, cd->Deep,
cd->Fib->fib_DirEntryType > 0);
}
return;
}
if(!(pdir = ParentDir(lock)))
{
cd->RetVal = RETURN_ERROR;
if(cd->Mode == COPYMODE_DELETE)
{
if(!(cd->Flags & COPYFLAG_QUIET))
{
Printf(" %s ", cd->FileName);
Printf(TEXT_NOT_DONE, TEXT_DELETED);
Printf("%s\n", TEXT_ERR_DELETE_DEVICE);
}
}
UnLock(lock);
return;
}
UnLock(pdir);
if(!(cd->Flags & COPYFLAG_SILENT))
PrintName(name, cd->Deep, cd->Fib->fib_DirEntryType > 0,
cd->Fib->fib_DirEntryType < 0 || (cd->Flags & COPYFLAG_ALL ?
cd->Mode != COPYMODE_DELETE : cd->Mode != COPYMODE_COPY) ||
cd->Flags & COPYFLAG_ENTERSECOND);
if((cd->Flags & COPYFLAG_ENTERSECOND) || (cd->Mode == COPYMODE_DELETE
&& (!(cd->Flags & COPYFLAG_ALL) || cd->Fib->fib_DirEntryType < 0)))
{
UnLock(lock); lock = 0;
if(KillFile(cd->FileName, cd->Flags & COPYFLAG_FORCEDELETE))
printok = TEXT_DELETED;
else
{
cd->RetVal = RETURN_WARN;
printerr = TEXT_DELETED;
}
}
else if(cd->Mode == COPYMODE_DELETE)
;
else if(cd->Fib->fib_DirEntryType > 0)
{
ULONG a;
if((cd->Flags & COPYFLAG_ALL || cd->Mode == COPYMODE_LINK ||
cd->Mode == COPYMODE_MOVE) && TestLoop(lock, cd->CurDest))
{
printok = 0;
cd->RetVal = RETURN_ERROR;
if(!(cd->Flags & COPYFLAG_QUIET))
{
if(cd->Flags & COPYFLAG_SILENT)
PrintName(name, cd->Deep, 1, 1);
Printf(TEXT_NOT_DONE, TEXT_ENTERED);
Printf(TEXT_ERR_INFINITE_LOOP);
}
}
else if((a = TestDest(cd->DestName, 1, cd)) < 0)
{
printerr = TEXT_CREATED; cd->RetVal = RETURN_ERROR;
}
else if(cd->Flags & COPYFLAG_ALL)
{
ULONG i;
i = cd->CurDest;
cd->DestPathSize = 0;
if(a == TESTDEST_DIR_OK)
{
if(!(cd->CurDest = Lock(cd->DestName, SHARED_LOCK)))
{
printerr = TEXT_ENTERED; cd->RetVal = RETURN_ERROR;
}
else
printok = TEXT_ENTERED;
}
else if((cd->CurDest = CreateDir(cd->DestName)))
{
UnLock(cd->CurDest);
if((cd->CurDest = Lock(cd->DestName, SHARED_LOCK)))
printok = TEXT_CREATED;
else
{
printerr = TEXT_ENTERED; cd->RetVal = RETURN_ERROR;
}
}
else
{
printerr = TEXT_CREATED; cd->RetVal = RETURN_ERROR;
}
if(!cd->CurDest)
cd->CurDest = i;
else if(i != cd->Destination)
UnLock(i);
}
else if(cd->Mode == COPYMODE_MOVE)
{
if(Rename(cd->FileName, cd->DestName))
printok = TEXT_RENAMED;
else
{
printerr = TEXT_RENAMED; cd->RetVal = RETURN_WARN;
}
}
else if(cd->Mode == COPYMODE_LINK)
{
if(!(cd->Flags & COPYFLAG_FORCELINK))
{
printok = 0;
cd->RetVal = RETURN_WARN;
if(!(cd->Flags & COPYFLAG_QUIET))
{
if(cd->Flags & COPYFLAG_SILENT)
PrintName(name, cd->Deep, 1, 1);
Printf(TEXT_NOT_DONE, TEXT_LINKED);
Printf(TEXT_ERR_FORCELINK);
}
}
else if(LinkFile(lock, cd->DestName, cd->Flags & COPYFLAG_SOFTLINK))
printok = TEXT_LINKED;
else
{
printerr = TEXT_LINKED; cd->RetVal = RETURN_WARN;
}
}
else /* COPY mode only displays directories, when not ALL */
{
printok = 0;
if(!(cd->Flags & COPYFLAG_SILENT))
Printf("\n");
}
}
else
{
/* test for existing destination file */
if(TestDest(cd->DestName, 0, cd) < 0)
printerr = TEXT_OPENED_FOR_OUTPUT;
else if(cd->Mode == COPYMODE_MOVE && Rename(cd->FileName, cd->DestName))
printok = TEXT_RENAMED;
else if(cd->Mode == COPYMODE_LINK)
{
if(!(cd->Flags & COPYFLAG_SOFTLINK) && LinkFile(lock, cd->DestName, 0))
printok = TEXT_LINKED;
else
{
printerr = TEXT_LINKED; cd->RetVal = RETURN_WARN;
if(cd->Flags & COPYFLAG_SOFTLINK)
SetIoErr(ERROR_OBJECT_WRONG_TYPE);
}
}
else
{
ULONG in, out, res = 0, h;
STRPTR txt = TEXT_OPENED_FOR_OUTPUT;
if((out = Open(cd->DestName, MODE_NEWFILE)))
{
ULONG kill = 1;
txt = cd->Mode == COPYMODE_MOVE ? TEXT_MOVED : TEXT_COPIED;
UnLock(lock); lock = 0;
if((in = Open(cd->FileName, MODE_OLDFILE)))
{
h = CopyFile(in, out, cd->BufferSize);
Close(in);
if(!h)
{
kill = 0;
if(cd->Mode == COPYMODE_MOVE)
{
if(KillFile(cd->FileName, cd->Flags & COPYFLAG_FORCEDELETE))
res = 1;
}
else
res = 1;
}
}
Close(out);
if(kill)
KillFile(cd->DestName, 0);
}
if(!res)
{
printerr = txt; cd->RetVal = RETURN_WARN;
}
else
printok = txt;
}
}
if(printerr && !(cd->Flags & COPYFLAG_QUIET))
PrintNotDone(cd->Flags & COPYFLAG_SILENT ? name : 0,
printerr, cd->Deep, cd->Fib->fib_DirEntryType > 0);
else if(printok)
{
cd->Flags |= COPYFLAG_DONE;
if(!(cd->Flags & COPYFLAG_SILENT))
Printf("%s\n", printok);
SetData(cd->DestName, cd);
}
if(lock)
UnLock(lock);
}
LONG CopyFile(ULONG from, ULONG to, ULONG bufsize)
{
STRPTR buffer;
LONG s, err = 0;
if((buffer = (STRPTR) AllocMem(bufsize, MEMF_ANY)))
{
do
{
if((s = Read(from, buffer, bufsize)) == -1 ||
Write(to, buffer, s) == -1)
err = RETURN_FAIL;
} while(s == bufsize && !err);
FreeMem(buffer, bufsize);
}
else
err = RETURN_FAIL;
return err;
}
/* Softlink's path starts always with device name! f.e. "Ram Disk:T/..." */
LONG LinkFile(ULONG from, STRPTR to, ULONG soft)
{
if(soft)
{
UBYTE name[FILEPATH_SIZE];
NameFromLock(from, name, FILEPATH_SIZE);
return MakeLink(to, (ULONG) name, LINK_SOFT);
}
else
return MakeLink(to, from, LINK_HARD);
}
/* return 0 means no loop, return != 0 means loop found */
ULONG TestLoop(ULONG srcdir, ULONG destdir)
{
ULONG par, lock, loop = 0;
lock = destdir;
if(SameDevice(srcdir, destdir))
{
do
{
if(!SameLock(srcdir, lock))
loop = 1;
else
{
par = ParentDir(lock);
if(lock != destdir)
UnLock(lock);
lock = par;
}
} while(!loop && lock);
}
if(lock != destdir)
UnLock(lock);
return loop;
}
void SetData(STRPTR name, struct CopyData *cd)
{
if(cd->Flags & COPYFLAG_NOPRO)
SetProtection(name, 0);
else
SetProtection(name, cd->Fib->fib_Protection);
if(cd->Flags & COPYFLAG_DATES)
SetFileDate(name, &cd->Fib->fib_Date);
if(cd->Flags & COPYFLAG_COMMENT)
SetComment(name, cd->Fib->fib_Comment);
}
LONG TestDest(STRPTR name, ULONG type, struct CopyData *cd)
{
LONG ret = TESTDEST_ERROR;
ULONG lock;
if((lock = Lock(name, SHARED_LOCK)))
{
struct FileInfoBlock *fib;
if((fib = (struct FileInfoBlock *) AllocDosObject(DOS_FIB, 0)))
{
if(Examine(lock, fib))
{
UnLock(lock); lock = 0;
if(type)
{
if(fib->fib_DirEntryType > 0)
ret = TESTDEST_DIR_OK;
else if(!(cd->Flags & COPYFLAG_DONTOVERWRITE))
{
if(KillFile(name, cd->Flags & COPYFLAG_FORCEOVERWRITE))
ret = TESTDEST_DELETED;
}
else
ret = TESTDEST_CANTDELETE;
}
else if(cd->Flags & COPYFLAG_DONTOVERWRITE)
ret = TESTDEST_CANTDELETE;
else if(KillFile(name, cd->Flags & COPYFLAG_FORCEOVERWRITE))
ret = TESTDEST_DELETED;
}
FreeDosObject(DOS_FIB, fib);
}
if(lock)
UnLock(lock);
}
else
ret = TESTDEST_NONE;
if(ret == TESTDEST_CANTDELETE)
SetIoErr(ERROR_OBJECT_EXISTS);
return ret;
}