AUSAM/source/S/copy.c

Compare this file to the similar file:
Show the results in this format:

#
#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);
}