home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
200-299
/
ff219.lzh
/
Mv
/
mv.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-06-04
|
39KB
|
1,880 lines
/*
* mv v1.0 - Unix-like move file utility
*
* Copyright 1989 Edwin Hoogerbeets
*
* This code may be freely redistributed as long as no charges other than
* reasonable copying fees are levied for it.
*
* Manx version by Edwin Hoogerbeets
* usenet: edwin@watcsc.waterloo.edu
* CIS: 72647,3675
*
* Works mostly like the Unix move.
*
* Usage: mv [-cfix] [-] file1 file2
* mv [-cfix] [-] path1 [path2 ...] dir
* cp [-fimnx] [-] file1 file2
* cp [-fimnxrR] [-] path1 [path2 ...] dir
* rm [-cdfimrR] [-] path [path ...]
*
* Where path is either a file or a directory.
*
* -c act like cp instead (as in "mv -c" means do a cp instead of mv)
* -d remove directories only if they are empty (as in AmigaDOS Delete)
* -f force quiet mode, overwriting destination files if necessary.
* -i force interactive mode
* -m act like mv instead
* -n do not copy file dates, comments and protections (use "n"ew dates..)
* -R same as -r
* -r recursively do directories as well (mv is always recursive)
* -x act like rm instead
* - end of options (useful to remove a file whose name starts with
* a dash eg. "-d")
*
* Moves, etc. across devices are supported.
*
*/
#include <fcntl.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#ifdef ARP
#include <libraries/arpbase.h>
#include <libraries/arpfunc.h>
#endif
#include <exec/memory.h>
#include <ctype.h>
#define FIBSIZE (long)sizeof(struct FileInfoBlock)
#define BUFSIZE 256
typedef struct fl {
char name[BUFSIZE];
struct fl *next;
} filenode;
#define FNSIZE (long)sizeof(filenode)
struct FileLock *lock;
struct FileInfoBlock *fib;
int mvflag = 0, /* is this a move command? */
cpflag = 0, /* is this a copy command? */
rmflag = 0, /* is this a remove command? */
rflag = 0, /* is this command recursive? */
fflag = 0, /* don't ask if it should overwrite, just do it */
iflag = 0, /* do interactive mode */
nflag = 1, /* copy file dates, comments and protections */
dflag = 0; /* delete directories only if they are empty */
char commandname[32] = "";
long ofile; /* output file handle */
long ifile; /* input file handle */
#ifdef ARP
typedef struct BAP {
struct AnchorPath bap_ap;
char padding[BUFSIZE];
} BigAnchorPath;
#define APSIZE (long)sizeof(BigAnchorPath)
int arpflag = 0;
#endif
/* these are so Manx won't complain about ptr/int conversions, etc. */
extern struct FileLock *ParentDir();
extern struct FileLock *CreateDir();
extern struct FileLock *Lock();
extern struct FileLock *CurrentDir();
extern int Examine();
extern char *AllocMem();
extern struct FileHandle *Open();
extern struct MsgPort *DeviceProc();
extern struct Library *OpenLibrary();
extern struct _dev *_devtab;
#ifdef ARP
struct ArpBase *ArpBase;
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
#endif
#include <exec/alerts.h>
#include <workbench/startup.h>
extern long _savsp, _stkbase;
extern int errno;
extern int Enable_Abort;
extern int _argc, _arg_len;
extern char **_argv, *_arg_lin;
_main(alen, aptr)
long alen;
char *aptr;
{
struct Process *pp, *FindTask();
_stkbase = _savsp - *((long *)_savsp+1) + 8;
*(long *)_stkbase = 0x4d414e58L;
pp = FindTask(0L);
_cli_parse(pp, alen, aptr);
Enable_Abort = 1;
exit(main(_argc, _argv));
}
/*
* The following few routines were taken from my edlib1.1 source. They
* are included here so that anyone can recompile this source without
* the library. (I'll be happy to send you edlib if you want it.)
*/
char *strrpbrk(str, charset)
register char *str, *charset;
{
register char *temp;
extern char *index();
temp = str + strlen(str) - 1;
while ( temp != (str - 1) && !index(charset, *temp) )
--temp;
return( (temp != (str - 1)) ? temp : NULL);
}
int stricmp(str1,str2)
register char *str1,*str2;
{
register int index = 0;
while ( str1[index] && str2[index] &&
tolower(str1[index]) == tolower(str2[index]) )
++index;
return( (tolower(str1[index]) < tolower(str2[index])) ? -1 :
( (tolower(str1[index]) > tolower(str2[index])) ? 1 : 0) );
}
/* return a pointer to the first character of a file name in a path name */
char *basename(buf)
register char *buf;
{
register char *foo = strrpbrk(buf,":/");
return( foo ? (foo + 1) : buf );
}
/* end of edlib routines */
/* write out a string */
int emit(file,str)
long file;
char *str;
{
Write(file,str,strlen(str));
}
/*
* return the length of the largest piece of memory that is possibly
* contiguous
*/
long mem()
{
long chip, fast;
extern long AvailMem();
Forbid();
chip = AvailMem(MEMF_CHIP);
fast = AvailMem(MEMF_FAST);
Permit();
return(chip>fast ? chip : fast);
}
/* make a new file info block and return a pointer to it */
struct FileInfoBlock *newfib()
{
struct FileInfoBlock *fib;
fib = (struct FileInfoBlock *) AllocMem(FIBSIZE, MEMF_CLEAR);
if ( !fib ) {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": Out of memory!\n");
}
return(NULL);
}
return(fib);
}
/* get rid of a used file info block */
int freefib(fib)
{
if ( fib )
FreeMem(fib,FIBSIZE);
}
/* make a new buffer and return a pointer to it */
char *newbuf()
{
register char *temp = AllocMem(BUFSIZE,MEMF_CLEAR|MEMF_PUBLIC);
if ( !temp ) {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": Out of memory!\n");
}
return(NULL);
}
return(temp);
}
/* free a buffer previously allocated with newbuf() */
int freebuf(buf)
char *buf;
{
if ( buf ) {
FreeMem(buf,BUFSIZE);
}
}
/* make a new filenode structure and return a pointer to it */
filenode *newfilenode()
{
filenode *new = (filenode *)
AllocMem(FNSIZE,MEMF_PUBLIC|MEMF_CLEAR);
if ( new ) {
new->name[0] = '\0';
new->next = NULL;
}
return(new);
}
/* free a list of filenode structures */
int freefilenodes(file)
filenode *file;
{
if ( file ) {
freefilenodes(file->next);
FreeMem(file,FNSIZE);
}
}
/* return a pointer to the last element of a filenode list */
filenode *end(file)
filenode *file;
{
if ( file ) {
if ( file->next ) {
return(end(file->next));
} else {
return(file);
}
} else {
return(NULL);
}
}
/* return the length of a list of filenodes */
int arglength(file)
filenode *file;
{
if ( file->next ) {
return(arglength(file->next)+1);
} else {
return(1);
}
}
/* Does the input string contain a wildcard? */
int haswild(name)
char *name;
{
register int foo = 0;
while ( name[foo] && name[foo] != '*' && name[foo] != '?' &&
name[foo] != '#' )
++foo;
return ( name[foo] );
}
/*
* This routine takes a string with possibly a wildcard in it and expands
* it to a list of filenode structures. If arp isn't opened or if it
* wasn't compiled with arp, then it creates a list of 1 filenode containing
* the argument it was passed. The pointer to nomem is where it puts the
* error code for "low on available memory" errors.
*/
filenode *expand(name,nomem)
char *name;
int *nomem;
{
filenode *file;
# ifdef ARP
if ( arpflag && haswild(name) ) {
filenode *temp;
int error;
BigAnchorPath *anchor;
*nomem = 0;
anchor = (BigAnchorPath *)
AllocMem(APSIZE,MEMF_CLEAR|MEMF_PUBLIC);
anchor->bap_ap.ap_Length = BUFSIZE;
if ( FindFirst(name,anchor) ) {
FreeAnchorChain(anchor);
return(NULL);
}
if ( file = newfilenode() ) {
strcat(file->name,anchor->bap_ap.ap_Buf);
} else {
*nomem = 1;
FreeAnchorChain(anchor);
return(NULL);
}
# ifdef DEBUG
printf("First matched file: %s\n",file->name);
# endif
temp = file;
while ( !(error = FindNext(anchor)) ) {
if ( !(temp->next = newfilenode()) ) {
*nomem = 1;
FreeAnchorChain(anchor);
freefilenodes(file);
return(NULL);
}
temp = temp->next;
strcat(temp->name,anchor->bap_ap.ap_Buf);
# ifdef DEBUG
printf("Next matched file: %s\n",temp->name);
# endif
}
FreeAnchorChain(anchor);
} else {
# endif
file = newfilenode();
if ( file ) {
*nomem = 0;
strcat(file->name,name);
} else {
*nomem = 1;
return(NULL);
}
# ifdef ARP
}
# endif
return(file);
}
/* well, I guess this is a pro-choice program. ;-) */
_abort()
{
if ( lock )
UnLock(lock);
exit(-1);
}
/*
* make a string containing the path part of a full AmigaDOS path name.
* return a pointer to this string.
*/
char *parent(name)
char *name;
{
register char *foo;
char *temp = AllocMem((long)strlen(name)+1,MEMF_CLEAR);
strcat(temp,name);
/* get a pointer to the filename part */
foo = basename(temp);
/*
* lop off the file name part -- the length of the whole original
* string must still be freed when freeing what temp points to.
*/
*foo = '\0';
return(temp);
}
/* are the two files on the same volume? If you can't tell, guess */
int samedev(src,dst)
char *src, *dst;
{
char srcbuf[40], dstbuf[40], *temp;
struct FileLock *lock;
/* Simultaneous get a lock and convert BPTR to a C pointer */
lock = (struct FileLock *)BADDR(Lock(src,ACCESS_READ));
if (lock == NULL) {
return(-1);
}
temp = (char *)
BADDR(((struct DeviceList *)BADDR(lock->fl_Volume))->dl_Name);
strncpy(srcbuf,&temp[1],temp[0]+1);
srcbuf[temp[0]+2] = '\0';
UnLock(((long)lock) >> 2); /* You must UnLock or the GURU visits */
temp = parent(dst);
lock = (struct FileLock *)BADDR(Lock(temp,ACCESS_READ));
FreeMem(temp,strlen(dst)+1);
if (lock == NULL) {
return(-1);
}
temp = (char *)
BADDR(((struct DeviceList *)BADDR(lock->fl_Volume))->dl_Name);
strncpy(dstbuf,&temp[1],temp[0]+1);
dstbuf[temp[0]+2] = '\0';
UnLock(((long)lock) >> 2); /* You must UnLock or the GURU visits */
# ifdef DEBUG
printf("%s and %s are %son the same volume\n",src,dst,
(!stricmp(srcbuf,dstbuf))?"":"not ");
# endif
return( !stricmp(srcbuf,dstbuf) );
}
/*
* Is the named file a directory? Get a File Info Block and point fib to
* it and return the results.
*
* return 0 for not a dir (ie. file)
* return 1 for a dir
* return 2 for no access to file
* return 3 for not being able to examine file
*
*/
int isdir(path,fib)
char *path;
struct FileInfoBlock **fib;
{
struct FileLock *lock;
register int result;
/* allocate a word aligned memory block to hold our info */
*fib = newfib();
if ( !(lock = Lock(path,ACCESS_READ)) ) {
return(2);
}
if ( *fib ) {
if ( Examine(lock,*fib) ) {
/* if the source is not a directory .. */
result = (*fib)->fib_DirEntryType > 0 ? 1 : 0;
} else {
/* 3 for could not examine */
result = 3;
}
} else {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": Out of memory!\n");
}
UnLock(lock);
return(-1);
}
UnLock(lock);
return(result);
}
#ifdef ARP
void closethings()
{
if ( ArpBase ) {
CloseLibrary(ArpBase);
}
if ( IntuitionBase ) {
CloseLibrary(IntuitionBase);
}
if ( GfxBase ) {
CloseLibrary(GfxBase);
}
}
#endif
void usage()
{
if ( !fflag ) {
emit(ofile,"Usage: mv [-cfix] [-] file1 file2\n");
emit(ofile," mv [-cfix] [-] path1 [path2 ...] dir\n");
emit(ofile," cp [-fimnx] [-] file1 file2\n");
emit(ofile," cp [-fimnxrR] [-] path1 [path2 ...] dir\n");
emit(ofile," rm [-cdfimrR] [-] path [path ...]\n");
emit(ofile,"\nWhere path is either a file or a directory.\n");
}
# ifdef ARP
closethings();
# endif
exit(1);
}
/* the following is a mess. brace yourself. */
main(argc,argv)
int argc;
char *argv[];
{
register int index, c;
struct FileInfoBlock *startfib = NULL, *endfib = NULL;
filenode *start = NULL, *temp = NULL, *endnode = NULL;
int args, result, nomem;
ofile = (long) Open("*",MODE_NEWFILE); /* open new file for stderr */
ifile = Input();
# ifdef ARP
ArpBase = (struct ArpBase *) OpenLibrary(ArpName,0L);
if ( ArpBase ) {
# ifdef DEBUG
printf("opened arp.library okay\n");
# endif
if ( !(IntuitionBase = (struct IntuitionBase *)
OpenLibrary("intuition.library",0L)) ) {
emit(ofile,"Could not open intuition.library\n");
# ifdef ARP
closethings();
# endif
exit(-1);
}
if ( !(GfxBase = (struct GfxBase *)
OpenLibrary("graphics.library",0L)) ) {
emit(ofile,"Could not open graphics.library\n");
# ifdef ARP
closethings();
# endif
exit(-1);
}
arpflag = 1;
} else {
# ifdef DEBUG
printf("Arp.library not opened.\n");
# endif
arpflag = 0;
}
# endif
if ( !stricmp(basename(argv[0]),MVNAME) ) {
++mvflag;
++rflag;
} else if ( !stricmp(basename(argv[0]),RMNAME) ) {
++rmflag;
} else {
/*
* default to the copy command so that if the user renames the
* executable to something we don't understand, we don't do
* anything really destructive.
*/
++cpflag;
}
index = 1;
/* simplistic argument processing */
while ( argv[index][0] == '-' ) {
c = 1;
/* - option was specified to end other options */
if ( !argv[index][c] ) {
++index;
break;
}
while ( argv[index][c] ) {
switch ( argv[index][c] ) {
case 'c':
cpflag = 1;
rflag = mvflag = rmflag = 0;
break;
case 'd':
dflag = 1;
break;
case 'f':
fflag = 1;
iflag = 0;
break;
case 'i':
fflag = 0;
iflag = 1;
break;
case 'm':
rflag = mvflag = 1;
cpflag = rmflag = 0;
break;
case 'n':
nflag = 0;
break;
case 'R':
case 'r':
rflag = 1;
break;
case 'x':
rmflag = 1;
rflag = mvflag = cpflag = 0;
break;
default:
emit(ofile,"invalid option ");
Write(ofile,&argv[index][c],1);
emit(ofile,"\n");
usage();
}
c++;
}
++index;
}
/* if there are no file names left after the options were processed ... */
if ( (argc - index) < (rmflag ? 1 : 2) ) {
usage();
}
if ( mvflag ) {
strcat(commandname,MVNAME);
# ifdef DEBUG
printf("mv command executing\n");
# endif
} else if ( rmflag ) {
strcat(commandname,RMNAME);
# ifdef DEBUG
printf("rm command executing\n");
# endif
} else {
strcat(commandname,CPNAME);
# ifdef DEBUG
printf("cp command executing\n");
# endif
}
/*
* expand the first argument. index contains the number of the first
* file name argument at this point, because it is updated by the options
* parsing piece of code above.
*/
start = expand(argv[index++],&nomem);
if ( nomem ) {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": Out of memory!\n");
}
# ifdef ARP
closethings();
# endif
exit(-1);
}
temp = end(start);
for ( ;index < argc; index++) {
/*
* it is possible that previous arguments had a wildcard and didn't
* match anything, so temp would be NULL at this point, otherwise
* attach the new file list from expand onto the end of the list.
*/
if ( temp ) {
temp->next = expand(argv[index],&nomem);
} else {
temp = expand(argv[index],&nomem);
start = temp;
}
if ( nomem ) {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": Out of memory!\n");
}
# ifdef ARP
closethings();
# endif
freefilenodes(start);
exit(-1);
}
temp = end(temp);
}
endnode = end(start);
args = arglength(start);
# ifdef DEBUG
printf("argc: %d\n",argc);
for ( temp = start; temp; temp = temp->next ) {
printf("argument \"%s\"\n", temp->name );
}
# endif
if ( !rmflag ) {
/*
* main case statement for the program to find out what to do with
* its life. (You gotta fight, for your right,
* to PPPPPAAAAAAARRRRRRRRIIIIIIIITTTTTTTYYYYYY!!!!!!
*/
/*
* check last argument (ie. the destination file) to make sure it
* is a directory
*/
switch ( isdir(endnode->name,&endfib) ) {
/*
* destination is a file, check that there are only 2 arguments
* and that the first one is also a file, or inform the user
* of his (or her) silliness.
*/
case 0:
if ( args == 2 ) {
if ( isdir(start->name,&startfib) ) {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": cannot move a directory onto a file\n");
}
freefib(startfib);
freefib(endfib);
freefilenodes(start);
usage();
} else {
result = mv2f(start->name,startfib,endnode->name,endfib);
if ( result == 2 && mvflag ) {
rm(start->name,fflag,iflag);
}
freefib(startfib);
freefib(endfib);
freefilenodes(start);
exit(0);
}
} else {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": cannot move a directory onto a file\n");
}
freefib(endfib);
freefilenodes(start);
usage();
}
break;
/* destination is a directory */
case 1:
freefib(endfib);
break;
/* destination doesn't exist */
case 2:
if ( args == 2 && !isdir(start->name,&startfib) ) {
/*
* move file specified in start->name to a new
* file in endnode->name
*/
result = mv2f(start->name,startfib,endnode->name,NULL);
if ( result == 2 && mvflag ) {
rm(start->name,fflag,iflag);
}
freefib(endfib);
freefib(startfib);
freefilenodes(start);
exit(0);
} else {
if ( args > 2 ) {
struct FileLock *lock;
char *buf = newbuf();
freefib(startfib);
freefib(endfib);
if ( !buf ) {
freefilenodes(start);
exit(-1);
}
if ( iflag ) {
buf[0] = '\0';
emit(ofile,commandname);
emit(ofile,": create directory ");
emit(ofile,endnode->name);
Read(ifile,buf,BUFSIZE);
if ( buf[0] != 'y' && buf[0] != 'Y' ) {
break;
}
}
if ( !(lock = CreateDir(endnode->name)) ) {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": unable to create directory ");
emit(ofile,endnode->name);
emit(ofile,"\n");
}
# ifdef ARP
closethings();
# endif
freefilenodes(start);
freebuf(buf);
exit(-1);
} else {
UnLock(lock);
}
freebuf(buf);
}
}
break;
case 3:
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": could not examine file ");
emit(ofile,endnode->name);
emit(ofile,"\n");
}
freefilenodes(start);
freefib(endfib);
exit(3);
break;
}
# ifdef DEBUG
printf("Move or copy files to directory %s\n",endnode->name);
# endif
}
/*
* For each source argument, move it to the correct directory.
*/
for ( temp = start; temp; temp = temp->next ) {
Chk_Abort();
if ( (temp != endnode) && (mvflag || cpflag) ) {
result = mv(temp->name,endnode->name);
switch ( result ) {
/* if there was an error, get out now */
case -1:
# ifdef ARP
closethings();
# endif
freefilenodes(start);
exit(-1);
/* if there was a successful copy, then remove the source */
case 2:
if ( !cpflag )
rm(temp->name,fflag,iflag);
break;
/*
* if there was a successful move, then do nothing, 'cause the
* source is gone already.
*/
default:
break;
}
} else if ( rmflag ) {
rm(temp->name,fflag,iflag);
}
}
# ifdef ARP
closethings();
# endif
freefilenodes(start);
exit(0);
}
int rm_file(file,fflag,iflag)
char *file;
int fflag, iflag;
{
register int result;
char *buf = newbuf();
if ( !buf ) {
return(-1);
}
# ifdef DEBUG
printf("Deleting file %s\n",file);
# endif
switch ( isdeletable(file) ) {
case 2:
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": could not find file ");
emit(ofile,file);
emit(ofile,"\n");
}
result = -1;
break;
case 1:
if ( iflag ) {
buf[0] = '\0';
emit(ofile,commandname);
emit(ofile,": remove ");
emit(ofile,file);
emit(ofile,"? ");
Read(ifile,buf,BUFSIZE);
if ( buf[0] != 'y' && buf[0] != 'Y' ) {
result = -1;
break;
}
}
SetProtection(file,0);
if ( !DeleteFile(file) ) {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": could not remove ");
emit(ofile,file);
emit(ofile,"\n");
}
result = -1;
} else {
result = 1;
}
break;
case 0:
if ( !fflag ) {
buf[0] = '\0';
emit(ofile,commandname);
emit(ofile,": overide delete protection for file ");
emit(ofile,file);
emit(ofile,"? ");
Read(ifile,buf,BUFSIZE);
if ( buf[0] == 'y' || buf[0] == 'Y' ) {
SetProtection(file,0);
if ( !DeleteFile(file) ) {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": could not remove ");
emit(ofile,file);
emit(ofile,"\n");
}
result = -1;
} else {
result = 1;
}
} else {
result = -1;
}
} else {
SetProtection(file,0);
if ( !DeleteFile(file) ) {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": could not remove ");
emit(ofile,file);
emit(ofile,"\n");
}
result = -1;
} else {
result = 1;
}
}
break;
}
freebuf(buf);
return(result);
}
/* recursively remove a directory or a remove a file */
int rm_dir(name,fflag,iflag)
char *name;
int fflag, iflag;
{
register struct FileLock *lock, *cwd;
register struct FileInfoBlock *fib;
register char *buf;
register int result = 1;
# ifdef DEBUG
printf("Recursively deleting directory %s\n",name);
# endif
buf = newbuf();
fib = (struct FileInfoBlock *)AllocMem(FIBSIZE,MEMF_CLEAR);
if (lock = Lock(name, ACCESS_READ)) {
cwd = CurrentDir(lock);
if (Examine(lock, fib)) {
buf[0] = '\0';
while (result && ExNext(lock, fib)) {
if ( fib->fib_DirEntryType > 0 )
result = rm_dir(fib->fib_FileName,fflag,iflag);
if (buf[0]) {
rm_file(buf,fflag,iflag);
}
strcpy(buf, fib->fib_FileName);
}
if ( buf[0] ) {
rm_file(buf,fflag,iflag);
}
}
UnLock(CurrentDir(cwd));
} else {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": could not get a lock on ");
emit(ofile,name);
emit(ofile,"\n");
}
result = -1;
}
FreeMem(fib, FIBSIZE);
freebuf(buf);
return(result);
}
rm(name,fflag,iflag)
char *name;
int fflag,iflag;
{
int result;
struct FileInfoBlock *fib;
switch ( isdir(name,&fib) ) {
case 0:
result = rm_file(name,fflag,iflag);
break;
case 1:
if ( rflag ) {
/* recursively delete the directory */
result = rm_dir(name,fflag,iflag);
if ( result ) {
rm_file(name,fflag,iflag);
}
} else if ( dflag ) {
/* only deletes directory if it is empty, as in AmigaDOS Delete */
result = rm_file(name,fflag,iflag);
} else {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": ");
emit(ofile,name);
emit(ofile," is a directory (not removed)\n");
}
result = -1;
}
break;
case 2:
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": could not access file ");
emit(ofile,name);
emit(ofile,"\n");
}
break;
case 3:
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": could not examine file ");
emit(ofile,name);
emit(ofile,"\n");
}
break;
}
if ( fib )
freefib(fib);
return(result);
}
/* mv a file or directory _to_a_directory_ */
int mv(src,dst)
char *src, *dst;
{
register int result = 0;
struct FileInfoBlock *srcfib;
switch ( isdir(src,&srcfib) ) {
/* source is a file */
case 0:
result = mvfile(src,srcfib,dst);
break;
/* source is a directory */
case 1:
result = mvdir(src,srcfib,dst);
break;
/* no access to source */
case 2:
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": could not access file ");
emit(ofile,src);
emit(ofile,"\n");
}
result = 0;
break;
/* not able to examine source */
case 3:
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": could not examine file ");
emit(ofile,src);
emit(ofile,"\n");
}
result = 0;
break;
}
freefib(srcfib);
return(result);
}
/* mv to a destination dir _from_ a directory source */
int mvdir(src,srcfib,dst)
char *src, *dst;
struct FileInfoBlock *srcfib;
{
register int result = 1, temp, onsame;
struct FileInfoBlock *dstfib;
if ( (onsame = samedev(src,dst)) == -1 )
return(0);
temp = isdir(dst,&dstfib);
/* if they are on the same device, treat the src dir as a file */
if ( onsame && mvflag ) {
/* if the destination dir doesn't exist, then move onto it... */
if ( temp == 2 ) {
result = mv2f(src,srcfib,dst,NULL);
} else {
/* ...else move into it */
result = mv2d(src,srcfib,dst);
}
} else if ( mvflag || (cpflag && rflag) ) {
/* ugh. We have to copy the source dir to the destination dir */
register int success, len;
register char c;
register struct FileLock *oldlock, *newlock, *dstlock;
char *buf = newbuf();
char *dstbuf = newbuf();
register struct FileInfoBlock *fib = newfib();
if ( !fib || !buf || !dstbuf ) {
result = -1;
} else {
dstbuf[0] = '\0';
strcat(dstbuf,dst);
if ( temp != 2 ) {
/*
* build the name of the destination from the directory name and
* later, the file name
*/
len = strlen(dstbuf);
/*
* only append a slash if the file name is not the current directory,
* (ie. "") the last character is not null, and the last character
* is neither of ':' or '/'. This part is so much easier under Unix
* path naming conventions, but hey, Amigoids gotta be different!
*/
if ( len && (c = dstbuf[len - 1] ) && c != ':' && c != '/' )
strcat(dstbuf,"/");
/*
* add only the file name onto the destination directory to
* build the name of the file we want to move to
*/
strcat(dstbuf,basename(src));
}
/* see if the directory exists */
if ( !(dstlock = Lock(dstbuf,ACCESS_READ)) ) {
struct DateStamp ds;
/* if no lock, try creating it */
if ( iflag ) {
buf[0] = '\0';
emit(ofile,commandname);
emit(ofile,": create directory ");
emit(ofile,dstbuf);
emit(ofile,"? ");
Read(ifile,buf,BUFSIZE);
if ( buf[0] != 'y' && buf[0] != 'Y' ) {
freefib(fib);
freefib(dstfib);
return(0);
}
}
if ( !(dstlock = CreateDir(dstbuf)) ) {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": unable to create directory ");
emit(ofile,dstbuf);
emit(ofile,"\n");
}
return(0);
}
# ifdef DEBUG
printf("Created directory %s\n",dstbuf);
# endif
setdate(&srcfib->fib_Date,dstbuf);
}
UnLock(dstlock);
/*
* get a lock on the source directory, since we have to copy it
* recursively
*/
newlock = Lock(src,ACCESS_READ);
/* Take a look at the directory */
success = Examine(newlock,fib);
/*
* while the examination of the source directory worked and the
* last move worked...
*/
while ( ExNext(newlock,fib) && result > 0 ) {
/* build the source file name */
buf[0] = '\0';
strcat(buf,src);
len = strlen(buf);
if ( len && (c = buf[len - 1] ) && c != ':' && c != '/' )
strcat(buf,"/");
strcat(buf,&fib->fib_FileName[0]);
result = mv(buf,dstbuf);
}
UnLock(newlock);
}
freefib(fib);
freebuf(buf);
freebuf(dstbuf);
} else {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": ");
emit(ofile,src);
emit(ofile," is a directory (not copied)\n");
}
}
freefib(dstfib);
return(result);
}
/* mv to a destination file or directory _from_ a file */
int mvfile(src,srcfib,dst)
char *src, *dst;
struct FileInfoBlock *srcfib;
{
register int result = 0;
struct FileInfoBlock *dstfib;
char *buf = newbuf();
if ( !buf ) {
return(-1);
}
switch ( isdir(dst,&dstfib) ) {
/* destination is a file */
case 0:
result = mv2f(src,srcfib,dst,dstfib);
break;
/* destination is a directory */
case 1:
result = mv2d(src,srcfib,dst);
break;
case 2:
if ( iflag ) {
buf[0] = '\0';
emit(ofile,commandname);
emit(ofile,": create directory ");
emit(ofile,dst);
emit(ofile,"? ");
Read(ifile,buf,BUFSIZE);
if ( buf[0] != 'y' && buf[0] != 'Y' ) {
result = 0;
break;
}
}
# ifdef DEBUG
printf("Creating dir %s\n",dst);
# endif
lock = CreateDir(dst);
if ( !lock ) {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": could not create destination directory ");
emit(ofile,dst);
emit(ofile,"\n");
}
result = 0;
} else {
UnLock(lock);
result = mv2d(src,srcfib,dst);
}
break;
case 3:
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": could not examine directory ");
emit(ofile,dst);
emit(ofile,"\n");
}
result = 0;
break;
}
freefib(dstfib);
freebuf(buf);
return(result);
}
/* mv a file _to_ a directory dst */
int mv2d(src,srcfib,dst)
char *src, *dst;
struct FileInfoBlock *srcfib;
{
char *buf = newbuf();
register char c;
register int result = 0;
register int len = strlen(dst);
struct FileInfoBlock *dstfib;
if ( !buf ) {
return(-1);
}
buf[0] = '\0';
/* build the file name in the destination directory */
strcat(buf,dst);
if ( len && (c = buf[len - 1] ) && c != ':' && c != '/' )
strcat(buf,"/");
strcat(buf,basename(src));
switch ( isdir(buf,&dstfib) ) {
case 0:
result = mv2f(src,srcfib,buf,dstfib);
break;
case 1:
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": could not move file ");
emit(ofile,src);
emit(ofile," onto directory ");
emit(ofile,buf);
emit(ofile,"\n");
}
result = 0;
break;
case 2:
result = mv2f(src,srcfib,buf,NULL);
break;
case 3:
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": something is awry with file ");
emit(ofile,buf);
emit(ofile,"\n");
}
result = 0;
break;
}
freefib(dstfib);
freebuf(buf);
return(result);
}
/* mv a file _to_ a file */
int mv2f(src,srcfib,dst,dstfib)
char *src, *dst;
struct FileInfoBlock *srcfib, *dstfib;
{
register int result = 0, cleanup = 0;
char *inputbuf;
register int onsame;
/* are they on the same volume? */
if ( (onsame = samedev(src,dst)) == -1) {
freebuf(inputbuf);
return(0);
}
if ( !(inputbuf = newbuf()) ) {
return(-1);
}
if ( dstfib ) {
if ( onsame && srcfib->fib_DiskKey == dstfib->fib_DiskKey ) {
if ( !mvflag ) {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": cannot copy ");
emit(ofile,src);
emit(ofile," to itself!\n");
}
freebuf(inputbuf);
return(1);
}
} else {
if ( iflag ) {
inputbuf[0] = '\0';
emit(ofile,commandname);
emit(ofile,": overwrite ");
emit(ofile,dst);
emit(ofile,"? ");
Read(ifile,inputbuf,BUFSIZE);
if ( inputbuf[0] != 'y' && inputbuf[0] != 'Y' ) {
freebuf(inputbuf);
return(1);
}
/* if remove unsuccessful, return an error */
if ( rm_file(dst,1,0) == -1 ) {
freebuf(inputbuf);
return(0);
}
} else {
/* if remove unsuccessful, return an error */
if ( rm_file(dst,fflag,0) == -1 ) {
freebuf(inputbuf);
return(0);
}
}
}
}
result = (onsame && mvflag) ? move(src,dst) : cp(src,srcfib,dst);
freebuf(inputbuf);
return(result);
}
/* copy a source file to a destination file */
int cp(src,srcfib,dst)
char *src, *dst;
struct FileInfoBlock *srcfib;
{
register int num;
register long size;
register char *buf;
struct FileHandle *srchandle, *dsthandle;
# ifdef DEBUG
printf("copy file %s to %s\n",src,dst);
# endif
size = mem() - 4;
if ( size < 128 ) {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": Out of memory!\n");
}
return(-1);
}
/*
* allocate a maximum of "size" continous bytes, else source file
* size worth of bytes. This allows one read and one write if there
* is enough memory for it. The 8 is added in case there is a
* zero size file we want to copy and we still want to allocate
* a buffer anyways.
*/
size = ( srcfib->fib_Size + 8 > size ) ? size : srcfib->fib_Size + 8;
# ifdef DEBUG
printf("Allocating %d bytes for the copy\n",size);
# endif
if ( !(buf = AllocMem(size,MEMF_CLEAR|MEMF_PUBLIC)) ) {
/* didn't work, try again with a smaller size */
size = size / 4;
if ( !(buf = AllocMem(size,MEMF_CLEAR|MEMF_PUBLIC)) ) {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": Out of memory!\n");
}
return(-1);
}
}
/* if we can't open the file, return an error */
if ( !(dsthandle = Open(dst,MODE_NEWFILE)) ) {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": cannot Open file ");
emit(ofile,dst);
emit(ofile,"\n");
}
FreeMem(buf,size);
/* returning 0 indicates an error to the above routines */
return(0);
}
if ( !(srchandle = Open(src,MODE_OLDFILE)) ) {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": cannot Open file ");
emit(ofile,src);
emit(ofile,"\n");
}
Close(dsthandle);
FreeMem(buf,size);
return(0);
}
/* copy bytes back and forth. Read returns -1 for a read error */
while ( (num = Read(srchandle,buf,size)) > 0 ) {
if ( Write(dsthandle,buf,num) == -1 ) {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": error writing to file ");
emit(ofile,dst);
emit(ofile,". Disk may be full.\n");
}
Close(srchandle);
Close(dsthandle);
FreeMem(buf,size);
return(-1);
}
}
Close(srchandle);
Close(dsthandle);
if ( num == -1 ) {
if ( !fflag ) {
emit(ofile,commandname);
emit(ofile,": error reading from file ");
emit(ofile,src);
emit(ofile,"\n");
}
FreeMem(buf,size);
return(0);
}
if ( nflag ) {
/*
* copy the protection bits, the comment and the datestamp to the
* new file if the n flag is set (ie. -n was NOT specified in the
* commandline)
*/
SetProtection(dst,srcfib->fib_Protection);
SetComment(dst,srcfib->fib_Comment);
setdate(&srcfib->fib_Date,dst);
FreeMem(buf,size);
}
/* return 2 for successful copy (not 1, because 1 is a move) */
return(2);
}
/* rename a source file to a destination file */
int move(src,dst)
char *src, *dst;
{
register int foo;
# ifdef DEBUG
printf("move file %s to %s\n",src,dst);
# endif
/* return 1 for successful move */
foo = Rename(src,dst) ? 1 : 0;
if ( !foo && !fflag ) {
emit(ofile,commandname);
emit(ofile,": could not move file ");
emit(ofile,src);
emit(ofile," to ");
emit(ofile,dst);
emit(ofile,"\n");
}
return(foo);
}
int setdate(date,name)
struct DateStamp *date;
char *name;
{
register UBYTE *ptr;
struct MsgPort *task;
register struct FileLock *lock, *parent;
register struct FileInfoBlock *fib;
int stat, result, dos_packet();
if ( !(task = DeviceProc(name)) ) {
return(0);
}
if ( !(lock = Lock(name,ACCESS_READ)) ) {
return(0);
}
fib = newfib();
/*
* thanks to Matt Dillon for this routine. I really don't know how
* it does what it does, but it works, so no comments here.
*/
/*
* Well, I mean other than these comments...
*/
/*
* Oh, forget it.
*/
if ( fib ) {
if ( Examine(lock,fib) ) {
parent = ParentDir(lock);
UnLock(lock);
ptr = (UBYTE *) AllocMem(256L,MEMF_CLEAR|MEMF_PUBLIC);
strcpy((ptr + 1),fib->fib_FileName);
*ptr = (UBYTE) strlen(fib->fib_FileName);
result = dos_packet(task,34L,NULL,parent,(ULONG)&ptr[0] >> 2L,date);
FreeMem(ptr,256L);
UnLock(parent);
}
freefib(fib);
} else {
UnLock(lock);
}
}
/* is a file delete protected? */
int isdeletable(file)
char *file;
{
register struct FileLock *lock;
register struct FileInfoBlock *fib;
register int result = 0;
if ( !(lock = Lock(file,ACCESS_READ)) ) {
return(0);
}
/* allocate a word aligned memory block to hold our info */
fib = newfib();
if ( fib ) {
if ( Examine(lock,fib) ) {
result = fib->fib_Protection;
freefib(fib);
} else {
freefib(fib);
return(2);
}
}
UnLock(lock);
return( !(result & FIBF_DELETE) );
}