/*
Auto:		sc Move NOLINK NODEBUG OPT NOSTARTUP PARM=REGISTER NOSTACKCHECK DATA=NEAR CODE=NEAR STRINGMERGE
Auto:		slink FROM Move.o TO Move LIB LIB:sc.lib LIB:amiga.lib VERBOSE NODEBUG
*/

/* $Revision Header built automatically *************** (do not edit) ************
**
** © Copyright by GuntherSoft
**
** File             : SnakeSYS:CPrgs/Utils/Move.c
** Created on       : Wednesday, 11.08.93 15:01:14
** Created by       : Kai Iske
** Current revision : V1.6
**
**
** Purpose
** -------
**   - Small move utility which supports wildcards and doesn`t use
**     Rename() nor Copy() nor anything similar...
**
** Revision V1.6
** --------------
** created on Friday, 15.10.93 15:51:13  by  Kai Iske.   LogMessage :
**  -*-  changed on Saturday, 16.10.93 15:17:29  by  Kai Iske.   LogMessage :
**   - Move got screwed up, when attempting to move a
**     zero size file
**  -*-  changed on Friday, 15.10.93 16:03:35  by  Kai Iske.   LogMessage :
**   - Added Buffer Keyword to specify the maximum buffer
**     size for an inter device move. Normally Move would have used
**     the max amount of available free memory in order to
**     accomplish the move, or the size needed by the file...
**     (Suggested by : Christof Damian)
**  -*-  created on Friday, 15.10.93 15:51:13  by  Kai Iske.   LogMessage :
**   - One couldn`t rename a file using move, because the
**     "destination" file was removed before doing the rename,
**     ie. the source file was deleted.
**     (Reported by : Chris Conger)
**
** Revision V1.5
** --------------
** created on Tuesday, 05.10.93 01:42:53  by  Kai Iske.   LogMessage :
**  -*-  changed on Tuesday, 05.10.93 02:03:22  by  Kai Iske.   LogMessage :
**   - Freed the FileInfoBlock _BEFORE_ setting the Bits, Comment
**     etc. This lead to MungWall hits (of course it did)
**     (Reported by Nico Francois)
**  -*-  created on Tuesday, 05.10.93 01:42:53  by  Kai Iske.   LogMessage :
**   - Exidentially called one ExAll() without ED_SIZE
**     This lead to some calls to DoTheMove without the Size set ;)
**     (Reported by  Karsten Weiss)
**
** Revision V1.4
** --------------
** created on Friday, 01.10.93 16:55:15  by  Kai Iske.   LogMessage :
**  -*-  created on Friday, 01.10.93 16:55:15  by  Kai Iske.   LogMessage :
**   - Now uses Rename() when source and dest are on the same
**     device. This is faster ;) Why haven`t I thought of that
**     earlier ??? ;)
**
** Revision V1.3
** --------------
** created on Wednesday, 25.08.93 16:32:43  by  Kai Iske.   LogMessage :
**   - UnLock Problem solved when doing recursive Dir-Moves
**     This bug lead to "Object in use" error messages
**
** Revision V1.2
** --------------
** created on Tuesday, 17.08.93 22:48:38  by  Kai Iske.   LogMessage :
**   - Added CTRL-C checking
**   - Added FORCE Flag in order to move read/deleteprotected or
**     to overwrite a delete/writeprotected files
**
** Revision V1.1
** --------------
** created on Monday, 16.08.93 22:53:34  by  Kai Iske.   LogMessage :
**   - Added well known CLONE, DATES, COM, NOPRO,
**     QUIET and NOREQ options also used by e.g. Rename
**
** Revision V1.0
** --------------
** created on Wednesday, 11.08.93 15:01:14  by  Kai Iske.   LogMessage :
**     --- Initial release ---
**
*********************************************************************************/
#define REVISION "1.6"
#define REVDATE  "16.10.93"
#define REVTIME  "15:17:29"
#define AUTHOR   "Kai Iske"
#define VERNUM   1
#define REVNUM   6

#include	<string.h>
#include	<stdlib.h>
#include	<exec/types.h>
#include	<proto/exec.h>
#include	<proto/dos.h>
#include	<exec/memory.h>
#include	<exec/execbase.h>
#include	<dos/exall.h>
#include	<dos/dos.h>
#include	<dos/dosextens.h>





/**********************************************************************/
/*                         Defines for Flags                          */
/**********************************************************************/
#define	CLONE		0x0001
#define	DATES		0x0002
#define	NOPRO		0x0004
#define	COM		0x0008
#define	QUIET		0x0010
#define	FORCE		0x0020

#define	WATCHSIGS	SIGBREAKF_CTRL_C



/**********************************************************************/
/*                      Static char definitions                       */
/**********************************************************************/
static	char	*Version	= "$VER: Move "REVISION" ("REVDATE")\0";
static	char	*Template	= "FROM/M,TO/A,CLONE/S,DATES/S,NOPRO/S,COM/S,QUIET/S,NOREQ/S,FORCE/S,BUFFER/N/K";
enum	{FROM_ARG, TO_ARG, CLONE_ARG, DATES_ARG, NOPRO_ARG, COM_ARG, QUIET_ARG, NOREQ_ARG, FORCE_ARG, BUFFER_ARG, LAST_ARG};



/**********************************************************************/
/*                             Prototypes                             */
/**********************************************************************/
int	__saveds DoMove(void);
BOOL	__stdargs DoTheMove(char *FromFile, char *ToPath, BOOL PatternFrom, BPTR OutHandle, struct DOSBase *DOSBase, LONG Type, ULONG Size, UWORD CopyFlags, LONG *HitMask, ULONG MaxBuffer);
BOOL	__stdargs DoMoveFile(char *FromFile, char *ToPath, char *Buffer, BPTR OutHandle, struct DOSBase *DOSBase, ULONG Size, UWORD CopyFlags, LONG *HitMask, ULONG MaxBuffer);


/**********************************************************************/
/*                          The main program                          */
/**********************************************************************/
int __saveds DoMove(void)
{
	struct	FileInfoBlock	*FIB;
	struct	ExecBase	*SysBase = *((struct ExecBase **)0x4L);
	struct	DOSBase		*DOSBase;
	struct	Process		*MyProc = (struct Process *)SysBase->ThisTask;
	struct	RDArgs		*RDArgs;
	struct	ExAllControl	*EAC;
	struct	ExAllData	*EAB, *EAD;
	APTR	*Args,
		*OldWindow;
	BPTR	DirLock,
		OutHandle;
	char	**FromPtr;
	char	*ToPtr;
	char	Pattern[256];
	char	PathName[256];
	char	Buffer[256];
	LONG	HitMask;
	UWORD	NumFrom = 0, PatternType, CopyFlags = 0;
	ULONG	MaxBuffer = 0;
	BOOL	PatternFrom, GoOn = TRUE, Scanning;

		// Ignore startup from WB

	if(!(MyProc->pr_CLI))
	{
		struct	Message	*MyMsg;

		WaitPort(&MyProc->pr_MsgPort);
		MyMsg = GetMsg(&MyProc->pr_MsgPort);
		Disable();
		ReplyMsg(MyMsg);
		return(0);
	}

		// Do the wild thing

	if((DOSBase = (struct DOSBase *)OpenLibrary("dos.library", 37)))
	{
		if((FIB = AllocVec(sizeof(struct FileInfoBlock), MEMF_CLEAR)))
		{
				// Get buffer for ReadArgs()

			if((Args = AllocVec((LAST_ARG * sizeof(ULONG)), MEMF_CLEAR)))
			{
					// Get structure for ExAll()

				if((EAC = AllocDosObject(DOS_EXALLCONTROL, NULL)))
				{
						// Get buffer for ExAll()

					if((EAB = AllocVec((sizeof(struct ExAllData)*20), MEMF_CLEAR)))
					{
							// Parse commandline

						if((RDArgs = ReadArgs(Template, (ULONG *)Args, NULL)))
						{
								// From and to really there ??

							if(Args[FROM_ARG] && Args[TO_ARG])
							{
								OutHandle	= Output();

									// Get Flags

								if(Args[CLONE_ARG])
									CopyFlags	|=	CLONE;
								if(Args[DATES_ARG])
									CopyFlags	|=	DATES;
								if(Args[NOPRO_ARG])
									CopyFlags	|=	NOPRO;
								if(Args[COM_ARG])
									CopyFlags	|=	COM;
								if(Args[QUIET_ARG])
									CopyFlags	|=	QUIET;
								if(Args[FORCE_ARG])
									CopyFlags	|=	FORCE;
								if(Args[BUFFER_ARG])
									MaxBuffer	=	*((ULONG *)Args[BUFFER_ARG]) * 1024;

									// Check for NOREQ Option

								if(Args[NOREQ_ARG])
								{
									OldWindow		= MyProc->pr_WindowPtr;
									MyProc->pr_WindowPtr	= (void *)(-1L);
								}

									// Get pointers to Files

								FromPtr	= (char **)Args[FROM_ARG];
								ToPtr	= (char *)Args[TO_ARG];

									// Count FROM entries

								while(*FromPtr++)
									NumFrom++;

									// Restore FromPtr

								FromPtr	= (char **)Args[FROM_ARG];

									// Set pattern if there are more than 1
									// FROM files or if the only FROM file
									// is a pattern

								if(NumFrom > 1)
									PatternFrom = TRUE;
								else
									PatternFrom = ParsePatternNoCase(*FromPtr, Pattern, 256);

									// If a pattern is used, check
									// whether the dest really is a dir

								if(PatternFrom)
								{
										// Try to obtain a lock

									if((DirLock = Lock(ToPtr, ACCESS_READ)))
									{
											// Check file

										if(Examine(DirLock, FIB))
										{
												// Get type of destination entry

											GoOn = (FIB->fib_DirEntryType > 0);

												// If it`s not a directory (multiple files are to be moved)
												// issue an error

											if(!GoOn)
												FPuts(OutHandle, "\nMove : Multiple files may not be moved to a single file\n");
										}
										else
										{
												// Examine() failed -> Abort

											GoOn = FALSE;
											PrintFault(IoErr(), "\nMove ");
										}

											// Unlock CheckDir

										UnLock(DirLock);
									}
									else
									{
											// If lock failed issue an error

										PrintFault(IoErr(), "\nMove ");
										GoOn = FALSE;
									}
								}



									// Loop for all source files

								while(NumFrom && GoOn)
								{
										// Check for CTRL-C

									if(GoOn)
										HitMask	= CheckSignal(WATCHSIGS);

									if(!HitMask && GoOn)
									{
											// Check if this source is a pattern

										strcpy(Buffer, FilePart(*FromPtr));
										strupr(Buffer);
										PatternType = ParsePatternNoCase(Buffer, Pattern, 256);

											// It is a pattern

										if(PatternType == 1)
										{
												// Create name of source

											strcpy(Buffer, *FromPtr);
											*PathPart(Buffer)	= '\0';

												// Get Lock for Source - Directory

											if((DirLock = Lock(Buffer, ACCESS_READ)))
											{
													// Setup ExAllControl-Structure

												EAC->eac_LastKey	= 0L;
												EAC->eac_MatchString	= Pattern;
												EAC->eac_MatchFunc	= NULL;

												do
												{
														// Check for CTRL-C

													if(GoOn)
														HitMask = CheckSignal(WATCHSIGS);

													if(HitMask)
														GoOn = FALSE;

														// Scan directory

													Scanning = ExAll(DirLock, EAB, (20*sizeof(struct ExAllData)), ED_SIZE, EAC);

														// Issue Error

													if(GoOn && (!Scanning) && (IoErr() != ERROR_NO_MORE_ENTRIES))
													{
														PrintFault(IoErr(), "\nMove ");
														GoOn = FALSE;
													}

														// End of Dir reached

													if(EAC->eac_Entries == 0)
														Scanning = FALSE;
													else if(GoOn)
													{
														EAD	= EAB;

														do
														{
																// Check for CTRL-C

															if(GoOn)
																HitMask = CheckSignal(WATCHSIGS);

															if(!HitMask && GoOn)
															{
																	// Create filename for this file to be moved

																strcpy(PathName, *FromPtr);
																*PathPart(PathName)	= '\0';
																AddPart(PathName, EAD->ed_Name, 256);

																	// Move file

																if((GoOn = DoTheMove(PathName, ToPtr, TRUE, OutHandle, DOSBase, EAD->ed_Type, EAD->ed_Size, CopyFlags, &HitMask, MaxBuffer)) && (EAD->ed_Type > 0))
																{
																		// Delete directory after a succesful move

																	if(!(GoOn = DeleteFile(PathName)))
																		PrintFault(IoErr(), "\nMove ");
																}

																EAD	= EAD->ed_Next;
															}
															else
																GoOn = FALSE;

														} while(EAD && GoOn);
													}
												} while(Scanning);

													// Unlock source directory

												UnLock(DirLock);
											}
											else
											{
													// Issue error, if dir could not be locked

												PrintFault(IoErr(), "\nMove ");
												GoOn	= FALSE;
											}
										}
											// No pattern

										else if(PatternType == 0)
										{
												// Try to lock source file/dir

											if((DirLock = Lock(*FromPtr, ACCESS_READ)))
											{
													// Examine this lock

												if(Examine(DirLock, FIB))
												{
														// Unlock directory and do the move

													UnLock(DirLock);
													if((GoOn = DoTheMove(*FromPtr, ToPtr, TRUE, OutHandle, DOSBase, FIB->fib_DirEntryType, FIB->fib_Size, CopyFlags, &HitMask, MaxBuffer)) && (FIB->fib_DirEntryType > 0))
													{
															// Delete dir after a succesfull move

														if(!(GoOn = DeleteFile(*FromPtr)))
															PrintFault(IoErr(), "\nMove ");
													}
												}
												else
												{
														// Issue error on failed Examine()

													PrintFault(IoErr(), "\nMove ");
													GoOn = FALSE;
													UnLock(DirLock);
												}
											}
											else
											{
													// No Lock() no more moves

												PrintFault(IoErr(), "\nMove ");
												GoOn = FALSE;
											}
										}

											// Error condition

										else
										{
											PrintFault(IoErr(), "\nMove ");
											GoOn = FALSE;
										}

										NumFrom--;
										FromPtr++;
									}
									else
										GoOn	= FALSE;
								}
							}

								// Free ReadArgs

							FreeArgs(RDArgs);
						}
						else
							PrintFault(IoErr(), "\nMove ");

							// Free ExAll-Buffer

						FreeVec(EAB);
					}
					else
						PrintFault(ERROR_NO_FREE_STORE, "\nMove ");

						// Free ExAllControl Structure

					FreeDosObject(DOS_EXALLCONTROL, (void *)EAC);
				}
				else
					PrintFault(IoErr(), "\nMove ");

					// Free Argument Buffer

				FreeVec(Args);
			}
			else
				PrintFault(ERROR_NO_FREE_STORE, "\nMove ");

			FreeVec(FIB);
		}
		else
			PrintFault(ERROR_NO_FREE_STORE, "\nMove ");

			// Check for Abort-Signals

		if(HitMask && !(CopyFlags & QUIET))
		{
				// Display appropriate message

			if(HitMask & SIGBREAKF_CTRL_C)
				FPuts(OutHandle, "\nMove ^C...\n");
		}

			// Close DOSLibrary

		CloseLibrary((struct Library *)DOSBase);
	}

		// Restore old window pointer (if any)

	if(OldWindow)
		MyProc->pr_WindowPtr	= OldWindow;


		// Depending on this flag return appropriate return code

	if(GoOn)
		return(0);
	else
		return(10);
}




/**********************************************************************/
/*                            Do the move                             */
/**********************************************************************/
BOOL __stdargs DoTheMove(char *FromFile, char *ToPath, BOOL PatternFrom, BPTR OutHandle, struct DOSBase *DOSBase, LONG Type, ULONG Size, UWORD CopyFlags, LONG *HitMask, ULONG MaxBuffer)
{
	struct	ExAllControl	*EAC;
	struct	ExAllData	*EAB, *EAD;
	char	NewDir[256];
	char	Buffer[256];
	UWORD	Len;
	BPTR	DirLock;
	BOOL	RetVal = TRUE, Scanning;

		// If a pattern is used print the name of the file to be moved

	if(PatternFrom && !(CopyFlags & QUIET))
	{
		strcpy(Buffer, FromFile);
		strcat(Buffer, "...");
		Write(OutHandle, " ", 1);
		Write(OutHandle, Buffer, strlen(Buffer));
	}

		// Is it a directory ???
		// If yes, recursively loop for all entries within dir

	if(Type > 0)
	{
		strcpy(Buffer, FromFile);

			// Get length of from name

		Len	= strlen(Buffer);
		if(Len)
		{
			if(Buffer[Len - 1] == '/')
				Buffer[Len - 1] = '\0';

				// Copy dest name to buffer

			strcpy(NewDir, ToPath);

				// Add name of from directory

			AddPart(NewDir, FilePart(Buffer), 256);

				// Try to lock directory or
				// create it, if not existent

			if(!(DirLock = Lock(NewDir, ACCESS_READ)))
			{
				if((DirLock = CreateDir(NewDir)) && PatternFrom && !(CopyFlags & QUIET))
					Write(OutHandle, " [created]...", 13);
			}

				// Got the destination directory ???

			if(DirLock)
			{
					// Unlock Directory

				UnLock(DirLock);

					// Lock sourcedirectory

				if((DirLock = Lock(Buffer, ACCESS_READ)))
				{
						// Get ExAll Control for recursive directory search

					if((EAC = AllocDosObject(DOS_EXALLCONTROL, NULL)))
					{
							// Allocate buffer for move

						if((EAB = AllocVec((20*sizeof(struct ExAllData)), MEMF_CLEAR)))
						{
							EAC->eac_LastKey	= 0L;
							EAC->eac_MatchString	= NULL;
							EAC->eac_MatchFunc	= NULL;

							do
							{
									// Check for CTRL-C

								if(RetVal)
									(*HitMask) = CheckSignal(WATCHSIGS);

								if((*HitMask))
									RetVal = FALSE;

									// Scan directory for entries

								Scanning = ExAll(DirLock, EAB, (20*sizeof(struct ExAllData)), ED_SIZE, EAC);

									// Check for an error

								if(RetVal && (!Scanning) && (IoErr() != ERROR_NO_MORE_ENTRIES))
								{
									PrintFault(IoErr(), "\nMove ");
									RetVal = FALSE;
								}

									// End of Dir reached

								if(EAC->eac_Entries == 0)
									Scanning = FALSE;
								else if(RetVal)
								{
									EAD = EAB;

									do
									{
											// Check for CTRL-C

										if(RetVal)
											(*HitMask) = CheckSignal(WATCHSIGS);

										if(!(*HitMask) && RetVal)
										{
												// Create filename of source

											strcpy(Buffer, FromFile);
											AddPart(Buffer, EAD->ed_Name, 256);

												// And start recursion

											if((RetVal = DoTheMove(Buffer, NewDir, FALSE, OutHandle, DOSBase, EAD->ed_Type, EAD->ed_Size, CopyFlags, HitMask, MaxBuffer)) && (EAD->ed_Type > 0))
											{
													// if file moved was a dir, delete it

												if(!(RetVal = DeleteFile(Buffer)))
													PrintFault(IoErr(), "\nMove ");
											}

												// Loop for all entries

											EAD = EAD->ed_Next;
										}
										else
											RetVal = FALSE;

									} while(EAD && RetVal);
								}
							} while(Scanning);

								// Free ExAll Buffer

							FreeVec(EAB);
						}
						else
						{
							PrintFault(ERROR_NO_FREE_STORE, "\nMove ");
							RetVal = FALSE;
						}

							// Free ExAllControl Structure

						FreeDosObject(DOS_EXALLCONTROL, EAC);
					}
					else
					{
						PrintFault(IoErr(), "\nMove ");
						RetVal = FALSE;
					}

					UnLock(DirLock);
				}
				else
				{
					PrintFault(IoErr(), "\nMove ");
					RetVal = FALSE;
				}
			}
			else
			{
				PrintFault(IoErr(), "\nMove ");
				RetVal = FALSE;
			}
		}
	}
	else
	{
			// On a plain file -> Simply move it

		RetVal = DoMoveFile(FromFile, ToPath, Buffer, OutHandle, DOSBase, Size, CopyFlags, HitMask, MaxBuffer);
	}

		// If there was a pattern (or a single directory)
		// end the Move string

	if(PatternFrom && RetVal && !(CopyFlags & QUIET))
		FPuts(OutHandle, " moved\n");

		// Return Code

	return(RetVal);
}





/**********************************************************************/
/*                      Ein File wirklich moven                       */
/**********************************************************************/
BOOL __stdargs DoMoveFile(char *FromFile, char *ToPath, char *Buffer, BPTR OutHandle, struct DOSBase *DOSBase, ULONG Size, UWORD CopyFlags, LONG *HitMask, ULONG MaxBuffer)
{
	struct	FileInfoBlock	*FIB;
	struct	DevProc		*FromDev, *ToDev;
	BPTR	InFile, OutFile;
	APTR	CopyBuffer;
	char	DestName[256];
	LONG	AvailSize, ReadSize, InKey = -1, OutKey = -1;
	BOOL	RetVal = TRUE, ErrCpy = FALSE, LoopCpy = TRUE, DoRename = FALSE, RemoveFirst = FALSE;

	if((FIB = AllocVec(sizeof(struct FileInfoBlock), MEMF_CLEAR)))
	{

		strcpy(DestName, ToPath);

			// Check, if destfile already exists
			// If so, check if it`s a dir.
			// Yes -> Copy with sourcename
			// No -> Copy with given name

		if((OutFile = Lock(DestName, ACCESS_READ)))
		{
			if(Examine(OutFile, FIB))
			{
					// If dest is a directory move with source name

				if(FIB->fib_DirEntryType > 0)
					AddPart(DestName, FilePart(FromFile), 256);
				else
				{
					OutKey		= ((struct FileLock *)BADDR(OutFile))->fl_Key;
					RemoveFirst	= TRUE;
				}
			}
			else
			{
					// No examine -> Use source filename

				AddPart(DestName, FilePart(FromFile), 256);
			}

			UnLock(OutFile);
		}

			// Try to lock input file

		if((InFile = Lock(FromFile, ACCESS_READ)))
		{
				// Get DiskBlock for inputfile

			InKey	= ((struct FileLock *)BADDR(InFile))->fl_Key;

				// Get old protection bits, comment and filedate

			if(Examine(InFile, FIB))
			{
					// In Force mode -> Force read and delete permissons
					// for input file

				if(CopyFlags & FORCE)
					SetProtection(FromFile, ~(FIBF_OTR_READ|FIBF_OTR_DELETE|FIBF_READ|FIBF_DELETE));
			}
			else
			{
				PrintFault(IoErr(), "\nMove ");
				RetVal = FALSE;
			}

				// If so, unlock

			UnLock(InFile);
		}
		else
		{
			PrintFault(IoErr(), "\nMove ");
			RetVal = FALSE;
		}


			// Check whether to use a Rename() or a real Copy-Mode

		FromDev	= GetDeviceProc(FromFile, NULL);
		ToDev	= GetDeviceProc(DestName, NULL);

			// If the same device is used -> Do the rename

		if(FromDev && ToDev && (FromDev->dvp_Port == ToDev->dvp_Port))
			DoRename = TRUE;

		if(FromDev)
			FreeDeviceProc(FromDev);

		if(ToDev)
			FreeDeviceProc(ToDev);


			// No Rename -> Do the right move ;)

		if(!DoRename)
		{
				// Open Input file

			if(RetVal && (InFile = Open(FromFile, MODE_OLDFILE)))
			{
					// Outfile already there ??? and in force mode ???

				if((CopyFlags & FORCE) && ((OutFile = Lock(DestName, ACCESS_READ))))
				{
						// Force delete and write permissons

					UnLock(OutFile);
					SetProtection(DestName, ~(FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_WRITE|FIBF_DELETE));
				}

					// Open Output file

				if((OutFile = Open(DestName, MODE_NEWFILE)))
				{
						// Is there any data within the file ???

					if(Size)
					{
							// Get available size of memory
							// or take the user`s buffer size into account

						AvailSize	= (MaxBuffer != 0) ? MaxBuffer : AvailMem(MEMF_LARGEST);
						Size		= (Size > AvailSize) ? AvailSize : Size;

							// Loop till we get a buffer

						while(Size && !(CopyBuffer = AllocVec(Size, MEMF_CLEAR)))
							Size	-= 1024;

						if(CopyBuffer)
						{
								// Loop for portions of the source file

							while(RetVal && LoopCpy)
							{
									// Check for CTRL-C

								if(RetVal)
									(*HitMask) = CheckSignal(WATCHSIGS);

								if(!(*HitMask) && RetVal)
								{
										// Read part of file

									if((ReadSize = Read(InFile, CopyBuffer, Size)) > 0)
									{
											// And write it back

										if(Write(OutFile, CopyBuffer, ReadSize) == -1)
										{
											PrintFault(IoErr(), "\nMove ");
											RetVal	= FALSE;
											ErrCpy	= TRUE;
										}
									}
									else
									{
											// EOF ??? -> End copy

										if(ReadSize == 0)
											LoopCpy	= FALSE;
										else
										{
												// Otherwise issue error

											PrintFault(IoErr(), "\nMove ");
											RetVal	= FALSE;
											ErrCpy	= TRUE;
										}
									}
								}
								else
									RetVal = FALSE;
							}

								// Free Copy buffer

							FreeVec(CopyBuffer);
						}
						else
						{
								// Issue error

							PrintFault(ERROR_NO_FREE_STORE, "\nMove ");
							RetVal	= FALSE;
							ErrCpy	= TRUE;
						}

							// Close outfile
					}

					Close(OutFile);
				}
				else
				{
						// Issue error

					PrintFault(IoErr(), "\nMove ");
					RetVal = FALSE;
				}
					// Close InFile

				Close(InFile);
			}
			else
			{
					// Issue error

				PrintFault(IoErr(), "\nMove ");
				RetVal = FALSE;
			}
		}
		else
		{
				// If RemoveFirst is not set, check again ;)

			if(!RemoveFirst)
			{
				if((OutFile = Lock(DestName, ACCESS_READ)))
				{
					if(Examine(OutFile, FIB))
					{
						// If dest is a file, delete first

						if(FIB->fib_DirEntryType < 0)
						{
								// Get Disk block of dest file

							OutKey	= ((struct FileLock *)BADDR(OutFile))->fl_Key;
							RemoveFirst = TRUE;
						}
					}
					UnLock(OutFile);
				}
			}

				// Check if only a rename should be accomplished

			if(InKey != -1 && OutKey != -1)
			{
				if(InKey == OutKey)
					RemoveFirst = FALSE;
			}

				// In Rename() mode, the destination has to be removed first

			if(RemoveFirst)
			{
					// If dest file is protected check for FORCE flag

				if(CopyFlags & FORCE)
					SetProtection(DestName, ~(FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_WRITE|FIBF_DELETE));

				if(!DeleteFile(DestName))
				{
					PrintFault(IoErr(), "\nMove ");
					RetVal = FALSE;
				}
			}

			if(RetVal)
			{
					// Now try to "rename" the file

				if(!Rename(FromFile, DestName))
				{
					PrintFault(IoErr(), "\nMove ");
					RetVal = FALSE;
				}
			}
		}

			// Error while copying ?? -> Remove Dest file

		if(ErrCpy)
			DeleteFile(DestName);

			// No Error -> Remove Source file

		if(RetVal && !ErrCpy)
		{
			if(!DoRename && !(RetVal = DeleteFile(FromFile)))
				PrintFault(IoErr(), "\nMove ");
			else
			{
					// Set bits etc. as requested

				if((CopyFlags & CLONE) || (CopyFlags & DATES))
					SetFileDate(DestName, &FIB->fib_Date);

				if((CopyFlags & CLONE) || (CopyFlags & COM))
					SetComment(DestName, FIB->fib_Comment);

				if(((CopyFlags & CLONE) && !(CopyFlags & NOPRO)) || (!(CopyFlags & CLONE) && !(CopyFlags & NOPRO)))
					SetProtection(DestName, FIB->fib_Protection);
			}
		}

			// Free FileInfo Block

		FreeVec(FIB);
	}
	else
	{
		PrintFault(ERROR_NO_FREE_STORE, "\nMove ");
		RetVal = FALSE;
	}

	return(RetVal);
}
