Interdata732/usr/source/cmds/ar.c_old


/*
 *	Archiver:
 *
 *		A free translation of ar.s
 */

char usage[]	"Usage: ar -drtx archive [file ...]";
char noar[]	"No archive file";
char noup[]	"Archive file not updated";
char nocreat[]	"Can't create archive file";
char badform[]	"Bad archive format";
char readio[]	"Archive file read i/o error";
char inpio[]	"Input file i/o error";
char tmpio[]	"Temp file i/o error";

char tfname[]	"/tmp/arXXXXXXX";

int	magic	0177555;	/* magic word to identify archive format file */

struct {			/* archive file header */
	char fname[8];
	int  mtime[2];
	char uid;
	char mode;
	int  size;
} dir;

struct {			/* buffer for stat() */
	int	s_dev;
	int	s_ino;
	int	s_flags;
	char	s_nlinks;
	char	s_uid;
	char	s_gid;
	char	s_size0;
	int	s_size1;
	int	s_addr[8];
	int	s_atime[2];
	int	s_mtime[2];
} stbuf;


char **ffile, **lfile;		/* first & last file in arg list */
int  nfiles;			/* no. of files in arg list */
char *curname;			/* name of current file arg */
char *afname;			/* name of archive file */
int  afmode;			/* protect mode of archive file */
int  afdev;			/* device on which archive file resides */
int  afi, tfi;			/* fd for archive & temp files */
int  buff[128];
int  nerr;			/* count of errors */
int  vflag;			/* 'verbose'*/
int  zero;			/* zero for padding */

main(argc, argv)
char *argv[];
{
	extern dexit();
	register char *p;
	register opt;

	if (argc < 3)
		error(usage);

	/* get option & check verbose flag */
	if (*(p = argv[1]) == '-')
		p++;
	if ((opt = *p++) == 'v') {
		vflag++;
		opt = *p;
	} else
		if (*p == 'v')
			vflag++;

	/* set up list of file args */
	afname = argv[2];
	ffile = &argv[3];
	lfile = &argv[argc];
	nfiles = argc - 3;

	/* set up interrupt exit */
	if ((signal(2, 1)&01) == 0) {
		signal(1, &dexit);
		signal(2, &dexit);
	}
	/* call appropriate command routine */
	switch(opt) {

	case 'd':
		delete();	break;

	case 'r':
		replace();	break;

	case 't':
		table();	break;

	case 'x':
		extract();	break;

	default:
		error(usage);
	}
}

/*
 * Delete files from archive
 */
delete()
{
	mktemp();

	if (!getaf())
		error(noar);

	while (getdir())
		if (match()) {
			msg('d');
			skipfl();
		}
		else {
			msg('c');
			copyfl();
		}

	while (leftover())
		nfound();
	copyback();
}

/*
 * Replace or append files in the archive
 */
replace()
{
	mktemp();

	if (getaf())
		while (getdir())
			if (match()) {
				msg('r');
				skipfl();
				infl();
			} else {
				msg('c');
				copyfl();
			}

	while (leftover()) {
		msg('a');
		infl();
	}
	copyback();
}

/*
 * List table of contents
 */
table()
{
	if (!getaf())
		error(noar);

	while (getdir()) {
		if (all() || match())
			tabfl();
		skipfl();
	}

	while (leftover())
		nfound();
}

/*
 * Extract files from the archive
 */
extract()
{
	if (!getaf())
		error(noar);

	while (getdir())
		if (all() || match()) {
			msg('x');
			exfl();
		}
		else
			skipfl();

	while (leftover())
		nfound();
}
/*
 * Open archive file & check format
 */
getaf()
{
	if (stat(afname, &stbuf) < 0) {
		afmode = 0666;
		afi = -1;
		return(0);
	}
	if ((afi = open(afname, 0)) < 0)
		error("Can't open archive file");
	afmode = stbuf.s_flags & 0777;
	afdev = stbuf.s_dev;

	readaf(sizeof magic);
	if (buff[0] != magic)
		error(badform);
	return(1);
}

/*
 * Create temporary file
 */
mktemp()
{
	register pid;
	register char *p;

	/* use process id to create unique name in /tmp directory */
	for (p = tfname; *p; p++)
		;
	pid = getpid();
	while (*--p == 'X') {
		*p = (pid&7) + '0';
		pid =>> 3;
	}
	/*
	 * create file & reopen in input/output mode
	 */
	if ((tfi = creat(tfname, 0600)) < 0)
		error("Can't create temp file");
	close(tfi);
	if ((tfi = open(tfname, 2)) < 0)
		error("Can't open temp file???");
	/* write 'magic word' archive header */
	write(tfi, &magic, sizeof magic);
}

/*
 * Read from archive file, checking for i/o errors
 */
readaf(size)
{
	register len;

	if ((len = read(afi, buff, size)) == size)
		return;

	if (size < 0)			/* i/o error */
		error(readio);
	error(badform);			/* premature eof */
}


/*
 * Read next file header
 */
getdir()
{
	register len;

	if ((len = read(afi, &dir, sizeof dir)) == sizeof dir)
		return(1);
	if (len == 0)			/* end of file */
		return(0);
	if (len < 0)			/* i/o error */
		error(readio);
	error(badform);			/* premature eof */
}

/*
 * Test whether current header filename matches any argument file
 */
match()
{
	register char **fn;
	register i;

	for (fn = ffile; fn < lfile; fn++)
		if (*fn && cmp8(trim(*fn), dir.fname)) {
			curname = *fn;
			*fn = 0;
			return(1);
		}
	return(0);
}

/*
 * If no filename arguments, match all files in archive
 */
all()
{
	static char aname[12];

	if (nfiles)
		return(0);
	cpy8(dir.fname, aname);
	curname = aname;
	return(1);
}

/*
 * Compare two 8-char strings
 */
cmp8(s1, s2)
char *s1, *s2;
{
	register char *p, *q;
	register i;

	p = s1; q = s2;
	for (i=0; i<8; i++) {
		if (p[i] != q[i])
			return(0);
		if (p[i] == '\0')
			break;
	}
	return(1);
}

/*
 * Copy 8 chars of a filename
 */
cpy8(s1, s2)
char *s1, *s2;
{
	register char *p, *q;
	register i;

	p = s1; q = s2;

	for (i=0; i < 8; i++)
		if ((q[i] = p[i]) == '\0')
			break;
	while (i < 8)
		q[i++] = '\0';
}


/*
 * Given a pathname, return the last component
 */
trim(fn)
char *fn;
{
	register char *fp, *p;
	register c;

	p = fp = fn;
	while (c = *fp++)
		if (c == '/')
			p = fp;
	return(p);
}

/*
 * Return any file as yet unmatched in arg list
 */
leftover()
{
	register char **fn;

	for (fn = ffile; fn < lfile; fn++)
		if (*fn) {
			curname = *fn;
			*fn = 0;
			cpy8(trim(curname), dir.fname);
			return(1);
		}
	return(0);
}

/*
 * Print one table of contents entry
 */
tabfl()
{
	extern char *ctime();
	register char *p;

	printf("%-8.8s", dir.fname);
	if (vflag) {
		printf("%8d", dir.size);
		p = ctime(dir.mtime);
		printf("  %-12.12s", &p[4]);
	}
	putchar('\n');
}

/*
 * Extract a file from the archive
 */
exfl()
{
	register ofi, len, size;

	/* create new file with mode & owner of archived file */
	if ((ofi = creat(curname, dir.mode|0400)) < 0) {
		printf("-- %s: can't create\n", dir.fname);
		nerr++;
		skipfl();
		return;
	}
	/* copy file */
	for (size = dir.size; size >= 512; size =- 512) {
		readaf(512);
		write(ofi, buff, 512);
	}
	if (size) {
		readaf(size);
		write(ofi, buff, size);
	}
	close(ofi);
	/* pad to halfword if necessary */
	if (size & 01)
		seek(afi, 1, 1);
}

/*
 * Copy a file into the (temporary) archive
 */
infl()
{
	register size, ifi;

	if (stat(curname, &stbuf) < 0 || (ifi = open(curname, 0)) < 0) {
		printf("-- %s: can't open\n", curname);
		nerr++;
		return;
	}
	/* make header */
	cpy8(trim(curname), dir.fname);
	dir.mtime[0] = stbuf.s_mtime[0];
	dir.mtime[1] = stbuf.s_mtime[1];
	dir.uid = stbuf.s_uid;
	dir.mode = stbuf.s_flags & 0377;
	dir.size = stbuf.s_size1;
	write(tfi, &dir, sizeof dir);

	/* copy file */
	for (size = dir.size; size >= 512; size =- 512) {
		if (read(ifi, buff, 512) != 512)
			error(inpio);
		write(tfi, buff, 512);
	}
	if (size) {
		if (read(ifi, buff, size) != size)
			error(inpio);
		write(tfi, buff, size);
	}
	close(ifi);
	/* pad to halfword if necessary */
	if (size & 01)
		write(tfi, &zero, 1);
}

/*
 * Copy a file from the archive to the temporary file
 */
copyfl()
{
	register size;

	/* copy the header */
	write(tfi, &dir, sizeof dir);

	/* copy the file */
	for (size = dir.size; size >= 512; size =- 512) {
		readaf(512);
		write(tfi, buff, 512);
	}
	if (size) {
		readaf(size);
		write(tfi, buff, size);
	}
	/* pad to halfword if necessary */
	if (size & 01) {
		seek(afi, 1, 1);
		write(tfi, &zero, 1);
	}
}

/*
 * Skip to the next file in the archive
 */
skipfl()
{
	register s;

	s = (dir.size+1) & ~01;
	seek(afi, s, 1);
}

/*
 * Verbose option -- running commentary
 */
msg(ch)
{
	if (vflag)
		printf("%c %.8s\n", ch, dir.fname);
}

/*
 * Error message for missing file
 */
nfound()
{
	printf("-- %.8s not found\n", trim(curname));

	/* record error so archive will not be updated */
	nerr++;
}

/*
 * All finished -- replace archive with new temporary file
 */
copyback()
{
	register fd, len;

	/* if any errors have occured, don't update the archive */
	if (nerr)
		error(noup);

	/* create archive file if it didn't exist before */
	if (afi < 0) {
		if ((fd = creat(afname, afmode)) < 0)
			error(nocreat);
		fstat(fd, &stbuf);
		afdev = stbuf.s_dev;
		close(fd);
	}
	else
		close(afi);

	/* prevent interrupts while moving back */
	signal(1, 1);
	signal(2, 1);

	/* if temp & archive files on same device, just do a mv */
	stat(tfname, &stbuf);
	if (stbuf.s_dev == afdev) {
		unlink(afname);
		if (link(tfname, afname) < 0)
			error(nocreat);
		unlink(tfname);
		chmod(afname, afmode);
		return;
	}

	/* copy temp file to archive file */
	if ((fd = creat(afname, afmode)) < 0)
		error(nocreat);
	seek(tfi, 0, 0);
	while ((len = read(tfi, buff, 512)) > 0)
		write(fd, buff, len);
	if (len < 0)
		error(tmpio);
	unlink(tfname);
}

/*
 * Error exit
 */
error(s)
{
	printf("%s\n", s);
	dexit();
}

/*
 * Delete temp file & exit
 */
dexit()
{
	if (tfi)
		unlink(tfname);
	exit(1);
}