/* * 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 #include #include #ifdef ARP #include #include #endif #include #include #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 #include 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) ); }