Interdata_v6/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);
}