home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Fish 3
/
goldfish_volume_3.bin
/
files
/
util
/
cli
/
move
/
move.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-01-13
|
33KB
|
1,338 lines
/*
Auto: sc <file>
Auto: Protect Move P ADD
*/
/* $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 : V37.11
**
**
** Purpose
** -------
** - Small move utility which supports wildcards and doesn`t use
** Rename() nor Copy() nor anything similar...
**
** Revision V37.11
** ---------------
** created on Monday, 30.05.94 09:20:04 by Kai Iske. LogMessage :
** -*- changed on Donnerstag, 12.01.95 13:26:43 by Kai Iske. LogMessage :
** - Changed version numbering to official scheme
** -*- changed on Mittwoch, 11.01.95 11:04:23 by Kai Iske. LogMessage :
** - One couldn`t move the entire contents of a directory
** to a dir within that directory (eg. Move #? Dummy)
** -*- changed on Mittwoch, 11.01.95 11:03:55 by Kai Iske. LogMessage :
** - One couldn`t move directories, if the destination dirs
** already existed (eg. Move Dummy1 Dummy2 t:; if Dummy1
** and Dummy2 both existed in t:)
** -*- changed on Montag, 05.09.94 23:16:13 by Kai Iske. LogMessage :
** - OldWindow and HitMask vars weren`t preset to 0
** (Reported by : Christian Buchner)
** -*- created on Monday, 30.05.94 09:20:04 by Kai Iske. LogMessage :
** - When one issued something like this "Move #? dummy/",
** Move stopped when trying to move dummy to itself ;) Fixed
**
** Revision V1.10
** --------------
** created on Sunday, 06.03.94 16:57:29 by Kai Iske. LogMessage :
** -*- created on Sunday, 06.03.94 16:57:29 by Kai Iske. LogMessage :
** - Move didn`t end up some operations with a "moved" string,
** thus leading to corrupted display
** (Reported by : Albert-Jan Brouwer)
** - One still couldn`t rename a directory
** (Reported by : Albert-Jan Brouwer)
**
** Revision V1.9
** --------------
** created on Saturday, 26.02.94 14:15:24 by Kai Iske. LogMessage :
** -*- changed on Saturday, 26.02.94 14:29:20 by Kai Iske. LogMessage :
** - On recursive moves, Move will indent the output according to
** recursion depth. This is for better readability
** -*- changed on Saturday, 26.02.94 14:19:22 by Kai Iske. LogMessage :
** - Move will refuse to move a dir to itself now.
** -*- created on Saturday, 26.02.94 14:15:24 by Kai Iske. LogMessage :
** - One couldn`t move a dir to another dir on the same device
**
** Revision V1.8
** --------------
** created on Sunday, 19.12.93 01:44:05 by Kai Iske. LogMessage :
** -*- changed on Sunday, 19.12.93 01:47:54 by Kai Iske. LogMessage :
** - Added PURE information to Doc, since Move really is pure
** (Suggested by : Albert-Jan Brouver)
** -*- changed on Sunday, 19.12.93 01:46:23 by Kai Iske. LogMessage :
** - Due to the move-renaming bug one couldn`t rename a dir
** an Assign was put on.
** (Reported by : Albert-Jan Brouver)
** -*- created on Sunday, 19.12.93 01:44:05 by Kai Iske. LogMessage :
** - Fixed move-renaming of directories.
** (Reported by : Albert-Jan Brouver)
** - Move had some severe problems recursively moving
** the contents of a directory
**
** Revision V1.7
** --------------
** created on Saturday, 04.12.93 23:19:03 by Kai Iske. LogMessage :
** -*- changed on Saturday, 04.12.93 23:26:25 by Kai Iske. LogMessage :
** - Error while moving to a "device full" disk
** (Reported by : Chris Conger)
** -*- created on Saturday, 04.12.93 23:19:03 by Kai Iske. LogMessage :
** - FileName length-bug fixed
** (Reported by : Juergen Lang)
** - Recompiled using SAS 6.50
** - Stack usage reduced
**
** 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 "37.11"
#define REVDATE "12.01.95"
#define REVTIME "13:26:43"
#define AUTHOR "Kai Iske"
#define VERNUM 37
#define REVNUM 11
#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 const char *Version = "$VER: Move "REVISION" ("REVDATE")\0";
static const 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);
static BOOL __stdargs DoTheMove(char *FromFile, char *ToPath, BOOL PatternFrom, BPTR OutHandle, LONG Type, ULONG Size, UWORD CopyFlags, LONG *HitMask, ULONG MaxBuffer, ULONG RecDepth);
static BOOL __stdargs DoMoveFile(char *FromFile, char *ToPath, char *Buffer, BPTR OutHandle, ULONG Size, UWORD CopyFlags, LONG *HitMask, ULONG MaxBuffer);
/**********************************************************************/
/* Library bases */
/**********************************************************************/
struct DosLibrary *DOSBase = NULL;
/**********************************************************************/
/* The main program */
/**********************************************************************/
int __saveds DoMove(void)
{
struct FileInfoBlock *FIB;
struct ExecBase *SysBase = *((struct ExecBase **)0x4L);
struct Process *MyProc = (struct Process *)SysBase->ThisTask;
struct RDArgs *RDArgs;
struct ExAllControl *EAC;
struct ExAllData *EAB, *EAD;
APTR *Args,
*OldWindow = NULL;
BPTR DirLock,
OutHandle;
char **FromPtr;
char *ToPtr;
char *Pattern;
char *PathName = NULL;
char *Buffer = NULL;
LONG HitMask = 0;
UWORD NumFrom = 0,
PatternType,
CopyFlags = 0;
ULONG MaxBuffer = 0;
BOOL PatternFrom,
GoOn = FALSE,
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(10);
}
// Do the wild thing
if((DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 37)))
{
// Allocate buffers
if((Pattern = AllocVec(1024, MEMF_CLEAR)) && (PathName = AllocVec(1024, MEMF_CLEAR)) && (Buffer = AllocVec(1024, MEMF_CLEAR)))
{
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((char *)Template, (LONG *)Args, NULL)))
{
// From and to really there ??
if(Args[FROM_ARG] && Args[TO_ARG])
{
// A O.K. so far
GoOn = TRUE;
// Get output handle
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, 1024);
// 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, 1024);
// 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, 1024);
// Move file
GoOn = DoTheMove(PathName, ToPtr, TRUE, OutHandle, EAD->ed_Type, EAD->ed_Size, CopyFlags, &HitMask, MaxBuffer, 1);
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);
GoOn = DoTheMove(*FromPtr, ToPtr, TRUE, OutHandle, FIB->fib_DirEntryType, FIB->fib_Size, CopyFlags, &HitMask, MaxBuffer, 1);
}
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 ");
}
else
PrintFault(ERROR_NO_FREE_STORE, "\nMove ");
// Free allocated buffers
if(Pattern)
FreeVec(Pattern);
if(PathName)
FreeVec(PathName);
if(Buffer)
FreeVec(Buffer);
// 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 */
/**********************************************************************/
static BOOL __stdargs DoTheMove(char *FromFile, char *ToPath, BOOL PatternFrom, BPTR OutHandle, LONG Type, ULONG Size, UWORD CopyFlags, LONG *HitMask, ULONG MaxBuffer, ULONG RecDepth)
{
struct ExAllControl *EAC;
struct ExAllData *EAB, *EAD;
char *NewDir;
char *Buffer = NULL;
char *ToDir = NULL;
char *DispBuff = NULL;
UWORD Len;
BPTR DirLock;
BOOL RetVal = TRUE,
Scanning,
DoRename = FALSE,
MoveDirToSame = FALSE,
Skipped = FALSE;
// Try to allocate buffers
if((NewDir = AllocVec(1024, MEMF_CLEAR)) && (Buffer = AllocVec(1024, MEMF_CLEAR)) && (ToDir = AllocVec(1024, MEMF_CLEAR)) && (DispBuff = AllocVec(1024, MEMF_CLEAR)))
{
// 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);
// Really got a from name ?!?
if(Len)
{
if(Buffer[Len - 1] == '/')
Buffer[Len - 1] = '\0';
// Copy dest name to buffer
strcpy(NewDir, ToPath);
// Check for dir moving to itself...
// ...and for renaming
if((DirLock = Lock(Buffer, ACCESS_READ)))
{
BPTR TestLock;
if((TestLock = Lock(NewDir, ACCESS_READ)))
{
// Working on same volume?
DoRename = (SameLock(DirLock, TestLock) == LOCK_SAME_VOLUME);
// Renaming a directory ???
MoveDirToSame = (SameLock(DirLock, TestLock) == LOCK_SAME);
UnLock(TestLock);
}
UnLock(DirLock);
}
// Ok, we are to move
// If a pattern is used print the name of the dir to be moved
if(PatternFrom && !(CopyFlags & QUIET))
{
int i;
// Prepend number of spaces according to recursion depth
for(i = 0; i < RecDepth; i++)
DispBuff[i] = ' ';
DispBuff[i] = '\0';
strcat(DispBuff, FromFile);
strcat(DispBuff, "...");
Write(OutHandle, " ", 1);
Write(OutHandle, DispBuff, strlen(DispBuff));
}
// Destination directory available ???
// If so, we are to move to that directory
// Otherwise, we`ll simply rename
if((DirLock = Lock(NewDir, ACCESS_READ)))
{
UnLock(DirLock);
// Add name of from directory
if(!MoveDirToSame)
AddPart(NewDir, FilePart(Buffer), 1024);
}
// Simple rename; no cross-device move ?!?
if(DoRename)
{
BOOL DoTheRename = TRUE;
// Trying to rename a directory?
// Only allowed when not in pattern or multimode
if(MoveDirToSame)
DoTheRename = !PatternFrom;
// Still rename the directory?
if(DoTheRename)
{
BPTR TestLock;
// Destination is already there?
// If so, only move contents
if((TestLock = Lock(NewDir, ACCESS_READ)))
{
DoRename = FALSE;
UnLock(TestLock);
}
else
{
// Do the rename
if(!Rename(Buffer, NewDir))
{
PrintFault(IoErr(), "\nMove ");
RetVal = FALSE;
}
}
}
else
Skipped = TRUE;
}
if(!DoRename)
{
// Clone directory name of source
strcpy(ToDir, Buffer);
// 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, 1024);
// And start recursion
RetVal = DoTheMove(Buffer, NewDir, FALSE, OutHandle, EAD->ed_Type, EAD->ed_Size, CopyFlags, HitMask, MaxBuffer, RecDepth + 1);
// 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;
}
}
// Ok, this dir was moved (no rename), so remove it
if(RetVal && !DoRename)
{
// With force mode set on,
// First make dir deletable
if(CopyFlags & FORCE)
SetProtection(ToDir, ~(FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_WRITE|FIBF_DELETE));
// Delete directory
if(!DeleteFile(ToDir))
{
PrintFault(IoErr(), "\nMove ");
RetVal = FALSE;
}
}
// Display "moved" message
if(PatternFrom && RetVal && !(CopyFlags & QUIET))
{
if(!Skipped)
FPuts(OutHandle, " moved\n");
else
FPuts(OutHandle, " skipped\n");
}
}
}
else
{
// Ok, we are to move
// If a pattern is used print the name of the file to be moved
if(PatternFrom && !(CopyFlags & QUIET))
{
int i;
// Prepend number of spaces according to recursion depth
for(i = 0; i < RecDepth; i++)
DispBuff[i] = ' ';
DispBuff[i] = '\0';
strcat(DispBuff, FromFile);
strcat(DispBuff, "...");
Write(OutHandle, " ", 1);
Write(OutHandle, DispBuff, strlen(DispBuff));
}
// On a plain file -> Simply move it
RetVal = DoMoveFile(FromFile, ToPath, Buffer, OutHandle, Size, CopyFlags, HitMask, MaxBuffer);
// If there was a pattern (or a single directory)
// end the Move string
if(PatternFrom && RetVal && !(CopyFlags & QUIET))
{
if(!Skipped)
FPuts(OutHandle, " moved\n");
else
FPuts(OutHandle, " skipped\n");
}
}
}
else
{
PrintFault(ERROR_NO_FREE_STORE, "\nMove ");
RetVal = FALSE;
}
// De-Allocate buffers
if(NewDir)
FreeVec(NewDir);
if(Buffer)
FreeVec(Buffer);
if(ToDir)
FreeVec(ToDir);
if(DispBuff)
FreeVec(DispBuff);
// Return Code
return(RetVal);
}
/**********************************************************************/
/* Physically move a file */
/**********************************************************************/
static BOOL __stdargs DoMoveFile(char *FromFile, char *ToPath, char *Buffer, BPTR OutHandle, ULONG Size, UWORD CopyFlags, LONG *HitMask, ULONG MaxBuffer)
{
struct FileInfoBlock *FIB;
BPTR InFile,
OutFile;
char *DestName;
APTR CopyBuffer;
ULONG ReadSize,
AvailSize;
LONG InKey = -1,
OutKey = -1;
BOOL RetVal = TRUE,
ErrCpy = FALSE,
LoopCpy = TRUE,
DoRename = FALSE,
RemoveFirst = FALSE;
// Allocate buffer for Destination name
if(!(DestName = AllocVec(1024, MEMF_CLEAR)))
{
PrintFault(ERROR_NO_FREE_STORE, "\nMove ");
return(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), 1024);
else
{
OutKey = ((struct FileLock *)BADDR(OutFile))->fl_Key;
RemoveFirst = TRUE;
}
}
else
{
// No examine -> Use source filename
AddPart(DestName, FilePart(FromFile), 1024);
}
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;
}
// Can we possibly simple rename the file?
if((InFile = Lock(FromFile, ACCESS_READ)))
{
if((OutFile = Lock(ToPath, ACCESS_READ)))
{
DoRename = (SameLock(InFile, OutFile) == LOCK_SAME_VOLUME);
UnLock(OutFile);
}
UnLock(InFile);
}
// 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) - 102400);
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;
}
FreeVec(CopyBuffer);
}
else
{
PrintFault(ERROR_NO_FREE_STORE, "\nMove ");
RetVal = FALSE;
ErrCpy = TRUE;
}
}
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)
{
FPuts(OutHandle, "\nMove : Error while moving; destination removed.\n");
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;
}
// Free buffer for destination name
FreeVec(DestName);
return(RetVal);
}