AUSAM/source/S/copy.c
#
#include <local-system>
/* the copy command
copy [-a] [-ad] [-l] [-n] [-o] [-r] [-v] [-m] sources destination
written by Keith Davis Feb 13, 1976
Ian Johnstone added -m july 18, 1977
Ian Johnstone added -s novemeber 30, 1977
*/
unsigned par_uid; /* the parent process id for the mkdir forks */
/* the device type */
struct
{
int dev;
int inumber;/* the inode number */
int flags; /* the flags */
#ifndef AUSAM
char nlinks; /* number of links to the file */
char uid; /* the uid of the file */
char gid; /* the group id of the file */
#else AUSAM
unsigned uid; /* 16-bit uid */
char nlinks; /* no. of links */
#endif AUSAM
char size0; /* high byte of the 24 bit size */
int size1; /* low word of the 24 bit size */
int addr[8];/* first address */
long actime; /* time of last access */
long modtime;/* time of last modifiction */
}
stat1, stat2;
int type1, type2;
char name1[256],name2[272]; /* buffers for source and destination names */
char *name1l, *name2l; /* points to the last char '\0' in name1 and name2 */
int direntry[9]; /* buffer for directory entries */
int askflag; /* ask before doing anything */
int askdirflag; /* ask before doing anything to directories */
int linkflag; /* if on then links are used where possible */
int newonlyflag; /* if on then override will not be done */
int ownerflag; /* if on and super user then will change owner on created files etc */
int recursiveflag; /* if on then will branch down directory structure */
int verboseflag; /* prints lots of information */
int suflag; /* 0 if super user otherwise 1 */
int moveflag; /* if on then remove file after copy */
int smdatflag; /* set modify date on destination files
to preserve inc dump information */
main(argc, argv)
int argc;
char **argv;
{
extern int fout;
register int i;
register char *s, *t;
char *name2ptr; /* remembers loc of last arg */
int k = 0;
fout = 2;
#ifndef AUSAM
suflag = getuid()&0377; /* set suflag id */
#else AUSAM
suflag = getuid(); /* set suflag=0 if super-user */
#endif AUSAM
for(i=3;i<16;i++) close(i); /* close unneeded files */
for(i=1;i<argc;i++)
{
if(argv[i][0] == '-') switch(argv[i][1])
{
case 'a': if (argv[i][2] == 'd') askdirflag = 1;
else askflag = askdirflag = 1;
break;
case 'l': linkflag = 1; break;
case 'm': moveflag = 1; linkflag = 1; break;
case 's': if (suflag == 0) smdatflag = 1;
else printf("only super user may set -s flag\n");
break;
case 'n': newonlyflag = 1; break;
case 'o': if (suflag == 0) ownerflag = 1;
else printf("only super user may set -o flag\n");
break;
case 'r': recursiveflag = 1; break;
case 'v': verboseflag = 1; break;
}
else name2ptr = argv[k++] = argv[i]; /* copy the arg */
}
if(--k < 1) /* k now is the number of sources */
{
if (k)
{
printf("Error: arg count\n");
exit(0);
}
k++; /* if only one source, use working directory */
name2ptr = ".";
}
for(i=0;i<k;i++) /* this code solves the multiple sources problem */
{
/* get a source */
s = name1; t = argv[i];
while(*s++ = *t++);
name1l = --s; /* point to the '\0' in char string */
while (*--s == '/') /* extra / */
{
*s = 0; name1l = s;
}
/* get the destination */
s = name2; t = name2ptr; /* always the same file */
while(*s++ = *t++);
name2l = --s;
while (*--s == '/') /* extra / */
{
*s = 0; name2l = s;
}
getstat();
/* only do directories if they are the only argument or '-r' given */
if (type1 == 2 && type2 != 0 && (recursiveflag || k == 1)) cd();
else /* do the cp command */
/* make entry in the direntry for the cp command */
{
s = &direntry[1]; t = name1;
while (*s = *t++) if(*s++ == '/') s = &direntry[1];
cp(); /* do the cp command */
}
}
}
#ifndef AUSAM
getstat() /* gets the status on the two files */
{
if (stat(name1,&stat1) == -1) type1 = 4;
else type1 = ((stat1.flags)>>13)&3;
if (stat(name2,&stat2) == -1) type2 = 4;
else type2 = ((stat2.flags)>>13)&3;
}
#else AUSAM
getstat() /* gets the status on the two files */
{
if (newstat(name1,&stat1) == -1) type1 = 4;
else type1 = ((stat1.flags)>>13)&3;
if (newstat(name2,&stat2) == -1) type2 = 4;
else type2 = ((stat2.flags)>>13)&3;
}
#endif AUSAM
cd() /* copy a directory */
{
/* source-directory file descriptor */
register int dirfd;
int pid,status,mode,modeflags,name1s,name2s;
long savedmodtime;
mode = type2; modeflags = stat1.flags; /* save for later use */
savedmodtime = stat1.modtime; /* save for later use */
if (type2 == 4) /* does not exist so create the directory */
{
do if((pid=fork()) == 0)
{
execl("/bin/mkdir","mkdir",name2,0);
perror( "/bin/mkdir" );
kill(9,par_uid);
exit(0);
} while(pid == -1);
while(pid != waitx(&status));
getstat();
}
if (type2 != 2) /* if two then directory otherwise error */
{
if (type2 == 4) printf("Error: could not mkdir %s\n",name2);
else printf("Error: %s is not a directory\n",name2);
return;
}
if ((dirfd = open(name1,0)) == -1)
{
perror( name1 );
return;
}
name1s = name1l; name2s = name2l; /* save pointers */
getentry(dirfd); /* skip first two entries */
getentry(dirfd); /* because they are the "." & ".." entries */
while(getentry(dirfd)) /* get an entry */
{
/* and push it onto the name1 & name2 */
push_name();
getstat();
switch (type1)
{
/* just a file */
case 0:
if (ask(askflag,"copy file",name1)) cp();
break;
case 1: /* character-type special file */
case 3: /* block-type special file */
if (ask(askdirflag,"copy special file",name1)) sf();
break;
case 2: /* directory */
if (recursiveflag) /* ignore if not */
if (ask(askdirflag,"examine directory",name1))
cd(); /* copy the directory */
break;
default:/* error */
printf("Error: %s does not exist",name1);
return;
}
name1l = name1s; *name1l = 0; /* pop name1 */
name2l = name2s; *name2l = 0; /* pop name2 */
}
close(dirfd); /* close the file source-directory */
if (mode == 4) /* if directory was created then change */
{
chmod(name2,modeflags);
#ifndef AUSAM
if (ownerflag) chown(name2,(stat1.gid<<8)|(stat1.uid));
#else AUSAM
if ( ownerflag )
chown( name2, stat1.uid );
#endif AUSAM
if (smdatflag) smdate(name2,savedmodtime);
}
if (moveflag)
{
if( !fork() )
{
execl("/bin/rmdir","rmdir",name1,0);
perror( "/bin/rmdir" );
exit(1);
}
waitx( &status );
}
return;
}
sf() /* copy a special file */
{
if (suflag)
{
printf("Error: Only super user can copy special files.\n");
return;
}
mknod(name2,stat1.flags,stat1.addr[0]); /* make the node */
#ifndef AUSAM
if (ownerflag) chown(name2,(stat1.gid<<8)|stat1.uid);
#else AUSAM
if ( ownerflag )
chown( name2, stat1.uid );
#endif AUSAM
if (smdatflag) smdate(name2,stat1.modtime);
getstat();
if(type1 != type2 ||
stat1.flags != stat2.flags ||
stat1.addr[0] != stat2.addr[0] )
{
printf("Error: could not create special file %s\n",name2);
unlink(name2);
}
else if (moveflag) unlink(name1);
}
getentry(df)
int df; /* the directory file descriptor */
{
do
{
if(read(df,direntry,16) != 16) return(0);
} while (direntry[0] == 0);
return(1);
}
push_name()
{
register char *s, *t;
/* add entry onto name1 */
if (name1l+17 > &name1[256])
{
printf("Error file name too long %s\n",name1);
exit(1);
}
s = name1l; t = &direntry[1]; *s++ = '/';
while (*s++ = *t++);
name1l = --s;
/* add entry onto name2 */
if (name2l+17 > &name2[256])
{
printf("Error file name too long %s\n",name2);
exit(1);
}
s = name2l; t = &direntry[1]; *s++ = '/';
while (*s++ = *t++);
name2l = --s;
}
cp() /* works just like the cp command */
{
int errflag;
static int buf[256];
int fold, fnew;
register int n;
register char *s, *t;
/* is target a directory? */
if (type2 == 2) /* if so then pad name2 with direntry */
{
/* set to last char in destination name */
s = name2l;
*s++ = '/'; /* push a '/' */
t = &direntry[1]; /* points to begin of source string */
while(*s++ = *t++);/* add last part of name2 */
getstat();
}
if (type2 != 4)
{
/* cannot process if flag is on and old */
if (newonlyflag)
{
printf("Error: cannot overwrite %s\n",name2);
return;
}
if (stat1.dev==stat2.dev)
/* done if same device and inode */
{
if (stat1.inumber==stat2.inumber)
return;
if (linkflag && unlink(name2) == -1)
{
printf("Error: cannot remove %s\n",name2);
return;
}
}
}
errflag = 0;
if (linkflag == 0 || link(name1,name2) == -1)
{
if((fold = open(name1,0)) == -1)
{
perror( name1 );
errflag=1;
return;
}
if ((fnew = creat(name2,stat1.flags)) == -1)
{
perror( name2 );
errflag=1;
close(fold); return;
}
if (ownerflag && type2 == 4)
#ifndef AUSAM
chown(name2,(stat1.gid<<8)|(stat1.uid));
#else AUSAM
chown( name2 , stat1.uid );
#endif AUSAM
while(n = read(fold,buf,512))
{
if(n == -1)
{
perror( name1 );
errflag=1;
unlink(name2); break;
}
else if(write(fnew, buf, n) != n)
{
perror( name2 );
errflag=1;
unlink(name2); break;
}
}
close(fold);
close(fnew);
}
if( (moveflag) && (!errflag) ) unlink(name1);
if( (smdatflag) && (!errflag) ) smdate(name2,stat1.modtime);
return;
}
ask(f,s,t) int f;
{
char ch;
register flg;
if (f) /* if flag true then ask question */
{
printf("%s %s? ",s,t);
if (read(0,&ch,1) != 1) return(0);
flg = ch == 'y';
while (ch != '\n' && read(0,&ch,1) == 1) ;
return(flg);
}
else if (verboseflag) printf("%s %s\n",s,t);
return(1);
}