/* Copyright 1983 Alcyon Corporation 8716 Production Ave. San Diego, Ca. 92121 */ char *SCCSID = "@(#) ar68 - July 1, 1983"; #include #ifndef PDP11 # define SEEKTYPE long # include # include # ifdef VAX11 # include # else # include # endif #else # include # define SEEKTYPE int long mklong(); #endif #ifdef VAX11 # define int short #endif #define USAGE "usage: %s [rdxtpvabi] [pos] archive file [file ...]\n" #define DEFMODE 0666 char buff[BUFSIZ]; struct stat astat, tstat; /* 11 apr 83, struct stat */ #define READ 0 #define WRITE 1 /* flags for cp1file */ #define IEVEN 1 #define OEVEN 2 #define WHDR 4 #define ROWN 0400 /* file protection flags */ #define WOWN 0200 #define XOWN 0100 #define RGRP 040 #define WGRP 020 #define XGRP 010 #define ROTH 04 #define WOTH 02 #define XOTH 01 struct libhdr libhd; struct libhdr *lp = { &libhd }; int libmagic = LIBMAGIC; int rflg, dflg, xflg, tflg, vflg; int uflg; int pflg; int areof; FILE *arfp; FILE *tempfd; int aflg, bflg; int psflg; int matchflg; char *psname; char *arname,*tempname; FILE *openar(); char *mktemp(); char *ctime(); char *fnonly(); int (*docom)(); int endit(); int replace(); int delete(); int extract(); int tell(); int print(); #ifdef VAX11 struct { short loword; short hiword; }; #else struct { int hiword; int loword; }; #endif char fname[15]; main(argc,argv) char **argv; { register char *p1, *p2; register char **ap; register int i; int j,docopy; char *myname; myname = *argv; if( argc < 3 ) { usage: printf(USAGE,myname); endit(); } signal(1,endit); signal(2,endit); ap = &argv[1]; p1 = *ap++; i = argc-3; while(*p1) { switch(*p1++) { case 'r': rflg++; docom = replace; break; case 'a': aflg++; psname = *ap++; i--; break; case 'b': case 'i': bflg++; i--; psname = *ap++; break; case 'd': dflg++; docom = delete; break; case 'x': xflg++; docom = extract; break; case 't': tflg++; docom = tell; break; case 'p': pflg++; docom = print; break; case 'v': vflg++; break; case '-': break; default: printf("invalid option flag: %c\n",*--p1); endit(); } } uflg = rflg+dflg; if( (uflg+xflg+tflg+pflg) != 1 ) { printf("At least one and only one of 'rdxt' flags required\n"); endit(); } psflg = aflg+bflg; if( psflg > 1 ) { printf("only one of 'abi' flags allowed\n"); endit(); } if( psflg && (rflg != 1) ) { printf("'abi' flags can only be used with 'r' flag\n"); endit(); } arname = *ap++; arfp = openar(arname,rflg); if( i == 0 && tflg ) { listall(); endit(); } if( i == 0 && xflg ) { exall(); endit(); } if( i <= 0 ) goto usage; tempname = mktemp("/tmp/_~ar?????"); if( (tempfd = fopen(tempname,"w")) == NULL ) { printf("can't create %s\n",tempname); endit(); } if( lputw(&libmagic,tempfd) != 0 ) perror("ar: write error on magic number"); /* read archive, executing appropriate commands */ while( matchflg == 0 && nextar() ) { docopy = 1; if( !psflg ) { for (j = 0; j < i; j++) { if( streq( fnonly(ap[j]), &lp->lfname[0]) ) { docopy = 0; (*docom)(ap[j]); i--; while( j < i ) { ap[j] = ap[j+1]; j++; } } } } else if( streq(psname,&lp->lfname[0]) ) { docopy = 0; for (j = 0; j < i; j++) (*docom)(ap[j]); i = 0; psflg = 0; } if( docopy ) skcopy(uflg); } /* deal with the leftovers */ if( i > 0 ) { for (j = 0; j < i; j++) { if( rflg ) (*docom)(ap[j]); else printf("%s not found\n",ap[j]); } } (*docom)(0L); /* make temp file the archive file */ if( stat(tempname,&tstat) < 0 ) { printf("can't find %s\n",tempname); endit(); } if( arfp != NULL ) { if( stat(arname,&astat) < 0 ) { printf("can't find %s\n",arname); endit(); } if( (astat.st_nlink != 1) || (astat.st_dev != tstat.st_dev) ) { fclose(arfp); tmp2ar(); } else if( (unlink(arname) == -1) ) { printf("can't unlink old archive\nnew archive left in %s\n", tempname); tempname = 0; /* keeps endit from removing the archive */ } else if( link(tempname,arname) < 0 ) { if( copy(tempname,arname) < 0 ) { printf("can't link to %s\nnew archive left in %s\n", arname,tempname); tempname = 0; } } } else { if( (arfp = fopen(arname,"w")) == NULL ) { printf("can't create %s\narchive left in %s\n",arname,tempname); tempname = 0; /* keeps endit from removing the archive */ endit(); } if( stat(arname,&astat) < 0 ) { printf("can't find %s\n",arname); endit(); } fclose(arfp); if( astat.st_dev != tstat.st_dev ) tmp2ar(); else if( (unlink(arname) < 0) || (link(tempname,arname) < 0) ) { printf("can't link to %s\n",arname); printf("new archive left in %s\n",tempname); tempname = 0; /* keeps endit from removing the archive */ } } endit(); } FILE * openar(arp,crfl) char *arp; { register FILE *i; unsigned int ib; if( (i = fopen(arp,"r")) == NULL ) { /* does not exist */ areof = 1; return(NULL); } if( lgetw(&ib,i) != 0 || ib != LIBMAGIC ) { notar: printf("not archive format: %s %o\n",arp,ib); endit(); } return(i); } /* execute one command -- call with filename or 0 */ int tell(ap) char *ap; { register char *p; register i; register char *p1; if( ckafile(ap) ) return; if( vflg ) { /* long list */ pmode(lp->lfimode); printf(" %d/%d ",lp->luserid,lp->lgid); #ifdef PDP11 plong("%6ld",lp->lfsize); #else printf("%6ld",lp->lfsize); #endif p1 = ctime(&lp->lmodti); p1[24] = '\0'; p1 += 4; printf(" %s ",p1); } pfname(); skcopy(0); } pfname() { register char *p; register i; p = &lp->lfname[0]; i = LIBNSIZE; while( *p && i ) { putchar(*p++); i--; } putchar('\n'); } int replace(name) char *name; { register int i; register FILE *ifd; register struct stat *stp; /* 11 apr 83, struct stat */ struct stat stbuf; #ifdef PDP11 long l; #endif stp = &stbuf; if( name == 0 ) { if( bflg && areof == 0 ) { if( fseek(arfp,-(SEEKTYPE)LIBHDSIZE,1) == -1 ) printf("fseek error\n"); } cprest(); return; } if( stat(name,stp) < 0 ) { printf("can't find %s\n",name); endit(); } if( (ifd = fopen(name,"r")) == NULL ) { printf("can't open %s\n",name); endit(); } if( areof && psflg ) { printf("%s not in library\n",psname); endit(); } if( (bflg|aflg) && matchflg == 0 ) { /* copy archive before appending */ if( aflg ) skcopy(1); matchflg++; } copystr(name,&lp->lfname[0],LIBNSIZE); if( areof|aflg ) inform('a'); else if( bflg ) inform('i'); else { inform('r'); skcopy(0); /* skip old copy */ } lp->luserid = stp->st_uid; lp->lgid = stp->st_gid; lp->lfimode = stp->st_mode; #ifdef PDP11 l = mklong(stp->st_mtime[0],stp->st_mtime[1]); lp->lmodti = l; l = mklong(stp->st_size0,stp->st_size1); lp->lfsize = l; #else lp->lmodti = stp->st_mtime; lp->lfsize = stp->st_size; #endif cp1file(ifd,tempfd,WHDR+OEVEN,name,tempname); fclose(ifd); } int delete(ap) char *ap; { if( ap == 0 ) { cprest(); return; } inform('d'); skcopy(0); } int extract(ap) char *ap; { register FILE *ofd; register i; if( ckafile(ap) ) return; if( (i = creat(ap,lp->lfimode)) < 0 ) { printf("can't create %s\n",ap); endit(); } ofd = fdopen(i,"w"); inform('x'); cp1file(arfp,ofd,IEVEN,arname,ap); fclose(ofd); } int print(ap) char *ap; { if( ckafile(ap) ) return; cp1file(arfp,1,IEVEN,arname,"std output"); } int endit() { if( tempname ) unlink(tempname); exit(0); } /* list all file in the library */ listall() { while( nextar() ) tell((char *) -1); } /* read next ar file header into libhd */ nextar() { if( areof || getarhd(arfp,&libhd) == EOF || libhd.lfname[0] == 0 ) { areof++; return(0); } return(1); } /* call with cpflag = 0 for skip, cpflag = 1 for copy */ skcopy(cpflag) int cpflag; { register SEEKTYPE l; register int i; if( areof ) return; l = lp->lfsize; if( l&1 ) l++; if( cpflag ) { inform('c'); cp1file(arfp,tempfd,WHDR+OEVEN+IEVEN,arname,tempname); } else { if( fseek(arfp,l,1) == -1 ) { printf("seek error on library\n"); endit(); } } } char *mktemp(ap) char *ap; { register char *p; register i,j; i = getpid(); /* process id */ p = ap; while( *p ) p++; for( j = 0; j < 5; j++ ) { *--p = ((i&7) + '0'); i >>= 3; } return(ap); } streq(s1, s2) char *s1, *s2; { register char *p1, *p2; p1 = s1; p2 = s2; while( *p1++ == *p2 ) if( *p2++ == 0 ) return(1); return(0); } int m1[] = { 1, ROWN, 'r', '-' }; int m2[] = { 1, WOWN, 'w', '-' }; int m3[] = { 1, XOWN, 'x', '-' }; int m4[] = { 1, RGRP, 'r', '-' }; int m5[] = { 1, WGRP, 'w', '-' }; int m6[] = { 1, XGRP, 'x', '-' }; int m7[] = { 1, ROTH, 'r', '-' }; int m8[] = { 1, WOTH, 'w', '-' }; int m9[] = { 1, XOTH, 'x', '-' }; int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; pmode(aflg1) { register int **mp; for( mp = &m[0]; mp < &m[9]; ) select(*mp++,aflg1); } select(pairp,flg) int *pairp; int flg; { register int n, *ap, f; ap = pairp; f = flg; n = *ap++; while( --n >= 0 && (f&*ap++) == 0 ) ap++; putchar(*ap); } inform(cc) char cc; { if( vflg ) { putchar(cc); putchar(' '); pfname(); } } copystr(ap1,ap2,alen) char *ap1, *ap2; { register char *p1, *p2; register len; p2 = 0; p1 = ap1; while( *p1 ) if( *p1++ == '/' ) p2 = p1; /* point to char after last '/' in name */ if( p2 ) p1 = p2; else p1 = ap1; p2 = ap2; len = alen; while( len ) { if( ! (*p2++ = *p1++) ) break; len--; } while( --len > 0 ) *p2++ = '\0'; } #ifdef PDP11 long mklong(ai1,ai2) { long l; l.hiword = ai1; l.loword = ai2; return(l); } plong(num) long num; { } #endif cprest() { while( nextar() ) skcopy(1); /* copy rest of library */ } cp1file(ifd,ofd,aflags,iname,oname) FILE *ifd, *ofd; int aflags; char *iname, *oname; { register i; register long l; register int flags, sz; char str[50]; flags = aflags; if( flags&WHDR ) { if( putarhd(ofd,&libhd) != 0 ) { iwrerr: sprintf(str,"ar: write error on %s",oname); perror(str); endit(); } } l = lp->lfsize; while( l ) { if( l < BUFSIZ ) sz = l; else sz = BUFSIZ; if( (i = fread(buff,sizeof (char),sz,ifd)) == NULL ) { perror("ar: read error"); endit(); } if( fwrite(buff,sizeof (char),i,ofd) == NULL ) goto iwrerr; l -= i; } if( flags&OEVEN ) { if( lp->lfsize&1 ) fwrite("",sizeof (char),1,ofd); } if( flags&IEVEN ) if( lp->lfsize&1 ) fread(buff,sizeof (char),1,ifd); } ckafile(ap) char *ap; { if( ap == 0 ) endit(); if( areof ) { printf("%s not in archive file\n",ap); return(1); } return(0); } exall() { while( nextar() ) extract(lp->lfname); } tmp2ar() { register int n,ifd,ofd; if( (ofd = creat(arname,DEFMODE)) < 0 ) { printf("can't create %s\n",arname); printf("archive left in %s\n",tempname); tempname = 0; /* keeps endit from removing the archive */ return; } fclose(tempfd); if( (ifd = open(tempname,0)) < 0 ) { printf("failed to open %s\n",tempname); return; } while( (n = read(ifd,buff,BUFSIZ)) > 0 ) write(ofd,buff,n); tempfd = fdopen(ifd,"r"); } char * fnonly(s) char *s; { register char *p, *r; r = s; strcpy(fname,r); p = 0; while( *r ) { if(*r == '/' ) p = r; r++; } if( p ) { ++p; if( *p == 0 ) p = fname; } else p = fname; return(p); } /* this is a copy routine for the cross device archive creation */ copy(from,to) char *from, *to; { register int ifd, ofd, len; if( (ofd = open(to,WRITE)) == -1 ) { if( (ofd = creat(to,DEFMODE)) == -1 ) return(-1); } if( (ifd = open(from,READ)) == -1 ) { close(ofd); unlink(to); return(-1); } while( (len = read(ifd,buff,sizeof buff)) > 0 ) write(ofd,buff,len); close(ifd); close(ofd); }