/********************************************************************** * Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. * * All Rights Reserved. * * Reference "/usr/src/COPYRIGHT" for applicable restrictions. * **********************************************************************/ static char Sccsid[] = "@(#)files.c 3.0 4/22/86"; /* System 5 @(#)files.c 1.3 of 3/28/83 */ #include "defs" #include <sys/types.h> #include <sys/stat.h> #include <sys/dir.h> #include <pwd.h> #include <ar.h> /* UNIX DEPENDENT PROCEDURES */ #define equaln !strncmp /* * For 6.0, create a make which can understand all three archive * formats. This is kind of tricky, and <ar.h> isn't any help. * Note that there is no sgetl() and sputl() on the pdp11, so * make cannot handle anything but the one format there. */ char archmem[64]; /* archive file member name to search for */ char archname[64]; /* archive file to be opened */ int ar_type; /* to distiguish which archive format we have */ #define ARpdp 1 #define AR5 2 #define ARport 3 long first_ar_mem; /* where first archive member header is at */ long sym_begin; /* where the symbol lookup starts */ long num_symbols; /* the number of symbols available */ long sym_size; /* length of symbol directory file */ /* * Defines for all the different archive formats. See next comment * block for justification for not using <ar.h>'s versions. */ #define ARpdpMAG 0177545 /* old format (short) magic number */ #define AR5MAG "<ar>" /* 5.0 format magic string */ #define SAR5MAG 4 /* 5.0 format magic string length */ #define ARportMAG "!<arch>\n" /* Port. (6.0) magic string */ #define SARportMAG 8 /* Port. (6.0) magic string length */ #define ARFportMAG "`\n" /* Port. (6.0) end of header string */ /* * These are the archive file headers for the three formats. Note * that it really doesn't matter if these structures are defined * here. They are correct as of the respective archive format * releases. If the archive format is changed, then since backwards * compatability is the desired behavior, a new structure is added * to the list. */ struct /* pdp11 -- old archive format */ { char ar_name[14]; /* '\0' terminated */ long ar_date; /* native machine bit representation */ char ar_uid; /* " */ char ar_gid; /* " */ int ar_mode; /* " */ long ar_size; /* " */ } ar_pdp; struct /* pdp11 a.out header */ { short a_magic; unsigned a_text; unsigned a_data; unsigned a_bss; unsigned a_syms; /* length of symbol table */ unsigned a_entry; char a_unused; char a_hitext; char a_flag; char a_stamp; } arobj_pdp; struct /* pdp11 a.out symbol table entry */ { char n_name[8]; /* null-terminated name */ int n_type; unsigned n_value; } ars_pdp; struct /* UNIX 5.0 archive header format: vax family; 3b family */ { char ar_magic[SAR5MAG]; /* AR5MAG */ char ar_name[16]; /* ' ' terminated */ char ar_date[4]; /* sgetl() accessed */ char ar_syms[4]; /* sgetl() accessed */ } arh_5; struct /* UNIX 5.0 archive symbol format: vax family; 3b family */ { char sym_name[8]; /* ' ' terminated */ char sym_ptr[4]; /* sgetl() accessed */ } ars_5; struct /* UNIX 5.0 archive member format: vax family; 3b family */ { char arf_name[16]; /* ' ' terminated */ char arf_date[4]; /* sgetl() accessed */ char arf_uid[4]; /* " */ char arf_gid[4]; /* " */ char arf_mode[4]; /* " */ char arf_size[4]; /* " */ } arf_5; struct /* Portable (6.0) archive format: vax family; 3b family */ { char ar_name[16]; /* '/' terminated */ char ar_date[12]; /* left-adjusted; decimal ascii; blank filled */ char ar_uid[6]; /* " */ char ar_gid[6]; /* " */ char ar_mode[8]; /* left-adjusted; octal ascii; blank filled */ char ar_size[10]; /* left-adjusted; decimal ascii; blank filled */ char ar_fmag[2]; /* special end-of-header string (ARFportMAG) */ } ar_port; #if 0 /* no longer used! */ /* * New common object version of files.c */ char archmem[64]; char archname[64]; /* name of archive library */ struct ar_hdr head; /* archive file header */ struct ar_sym symbol; /* archive file symbol table entry */ struct arf_hdr fhead; /* archive file object file header */ #endif TIMETYPE afilescan(); TIMETYPE entryscan(); TIMETYPE pdpentrys(); FILE *arfd; char BADAR[] = "BAD ARCHIVE"; TIMETYPE exists(pname) NAMEBLOCK pname; { register CHARSTAR s; struct stat buf; TIMETYPE lookarch(); CHARSTAR filename; filename = pname->namep; if(any(filename, LPAREN)) return(lookarch(filename)); if(stat(filename,&buf) < 0) { s = findfl(filename); if(s != (CHARSTAR )-1) { pname->alias = copys(s); if(stat(pname->alias, &buf) == 0) return(buf.st_mtime); } return(0); } else return(buf.st_mtime); } TIMETYPE prestime() { TIMETYPE t; time(&t); return(t); } FSTATIC char n15[15]; FSTATIC CHARSTAR n15end = &n15[14]; DEPBLOCK srchdir(pat, mkchain, nextdbl) register CHARSTAR pat; /* pattern to be matched in directory */ int mkchain; /* nonzero if results to be remembered */ DEPBLOCK nextdbl; /* final value for chain */ { FILE * dirf; int i, nread; CHARSTAR dirname, dirpref, endir, filepat, p; char temp[100]; char fullname[100]; CHARSTAR p1, p2; NAMEBLOCK q; DEPBLOCK thisdbl; OPENDIR od; int dirofl = 0; static opendirs = 0; PATTERN patp; struct direct entry[32]; thisdbl = 0; if(mkchain == NO) for(patp=firstpat ; patp!=0 ; patp = patp->nextpattern) if(equal(pat,patp->patval)) return(0); patp = ALLOC(pattern); patp->nextpattern = firstpat; firstpat = patp; patp->patval = copys(pat); endir = 0; for(p=pat; *p!=CNULL; ++p) if(*p==SLASH) endir = p; if(endir==0) { dirname = "."; dirpref = ""; filepat = pat; } else { *endir = CNULL; dirpref = concat(pat, "/", temp); filepat = endir+1; dirname = temp; } dirf = NULL; for(od=firstod ; od!=0; od = od->nextopendir) if(equal(dirname, od->dirn)) { dirf = od->dirfc; fseek(dirf,0L,0); /* start over at the beginning */ break; } if(dirf == NULL) { dirf = fopen(dirname, "r"); if(++opendirs < MAXODIR) { od = ALLOC(opendir); od->nextopendir = firstod; firstod = od; od->dirfc = dirf; od->dirn = copys(dirname); } else dirofl = 1; } if(dirf == NULL) { fprintf(stderr, "Directory %s: ", dirname); fatal("Cannot open"); } else do { nread = fread(entry,sizeof(entry[0]),32,dirf) ; for(i=0; i<nread; ++i) if(entry[i].d_ino!= 0) { p1 = entry[i].d_name; p2 = n15; while( (p2<n15end) && (*p2++ = *p1++)!=CNULL ); if( amatch(n15,filepat) ) { concat(dirpref,n15,fullname); if( (q=srchname(fullname)) ==0) q = makename(copys(fullname)); if(mkchain) { thisdbl = ALLOC(depblock); thisdbl->nextdep = nextdbl; thisdbl->depname = q; nextdbl = thisdbl; } } } } while(nread==32); if(endir != 0) *endir = SLASH; if(dirofl) fclose(dirf); return(thisdbl); } /* stolen from glob through find */ amatch(s, p) CHARSTAR s, p; { register int cc, scc, k; int c, lc; scc = *s; lc = 077777; switch (c = *p) { case LSQUAR: k = 0; while (cc = *++p) { switch (cc) { case RSQUAR: if (k) return(amatch(++s, ++p)); else return(0); case MINUS: k |= lc <= scc & scc <= (cc=p[1]); } if(scc==(lc=cc)) k++; } return(0); case QUESTN: caseq: if(scc) return(amatch(++s, ++p)); return(0); case STAR: return(umatch(s, ++p)); case 0: return(!scc); } if(c==scc) goto caseq; return(0); } umatch(s, p) register CHARSTAR s, p; { if(*p==0) return(1); while(*s) if(amatch(s++,p)) return(1); return(0); } /* look inside archives for notations a(b) and a((b)) a(b) is file member b in archive a a((b)) is entry point b in object archive a */ TIMETYPE lookarch(filename) register CHARSTAR filename; { register int i; CHARSTAR p, q; char s[15]; int nc, objarch; TIMETYPE la(); for(p = filename; *p!= LPAREN ; ++p); i = p - filename; strncpy(archname, filename, i); archname[i] = CNULL; if(archname[0] == CNULL) fatal1("Null archive name `%s'", filename); p++; if(*p == LPAREN) { objarch = YES; ++p; if((q = strchr(p, RPAREN)) == NULL) q = p + strlen(p); strncpy(s,p,q-p); s[q-p] = CNULL; } else { objarch = NO; if((q = strchr(p, RPAREN)) == NULL) q = p + strlen(p); i = q - p; strncpy(archmem, p, i); archmem[i] = CNULL; nc = 14; if(archmem[0] == CNULL) fatal1("Null archive member name `%s'", filename); if(q = strrchr(archmem, SLASH)) ++q; else q = archmem; strncpy(s, q, nc); s[nc] = CNULL; } return(la(s, objarch)); } TIMETYPE la(am,flag) register char *am; register int flag; { TIMETYPE date = 0L; if(openarch(archname) == -1) return(0L); if(flag) date = entryscan(am); /* fatals if cannot find entry */ else date = afilescan(am); clarch(); return(date); } TIMETYPE afilescan(name) /* return date for named archive member file */ char *name; { int len = strlen(name); long ptr; if (fseek(arfd, first_ar_mem, 0) != 0) { seek_error:; fatal1("Seek error on archive file %s", archname); } /* * Hunt for the named file in each different type of * archive format. */ switch (ar_type) { case ARpdp: for (;;) { if (fread((char *)&ar_pdp, sizeof(ar_pdp), 1, arfd) != 1) { if (feof(arfd)) return (0L); break; } if (equaln(ar_pdp.ar_name, name, len)) return (ar_pdp.ar_date); ptr = ar_pdp.ar_size; ptr += (ptr & 01); if (fseek(arfd, ptr, 1) != 0) goto seek_error; } break; #ifndef pdp11 case AR5: for (;;) { if (fread((char *)&arf_5, sizeof(arf_5), 1, arfd) != 1) { if (feof(arfd)) return (0L); break; } if (equaln(arf_5.arf_name, name, len)) return (sgetl(arf_5.arf_date)); ptr = sgetl(arf_5.arf_size); ptr += (ptr & 01); if (fseek(arfd, ptr, 1) != 0) goto seek_error; } break; case ARport: for (;;) { if (fread((char *)&ar_port, sizeof(ar_port), 1, arfd) != 1 || !equaln(ar_port.ar_fmag, ARFportMAG, sizeof(ar_port.ar_fmag))) { if (feof(arfd)) return (0L); break; } if (equaln(ar_port.ar_name, name, len)) { long date; if (sscanf(ar_port.ar_date, "%ld", &date) != 1) { fatal1("Bad date field for %.14s in %s", name, archname); } return (date); } if (sscanf(ar_port.ar_size, "%ld", &ptr) != 1) { fatal1("Bad size field for %.14s in archive %s", name, archname); } ptr += (ptr & 01); if (fseek(arfd, ptr, 1) != 0) goto seek_error; } break; #endif } /* * Only here if fread() [or equaln()] failed and not at EOF */ fatal1("Read error on archive %s", archname); /*NOTREACHED*/ #if 0 long date; long nsyms; long ptr; nsyms = sgetl(head.ar_syms); if(fseek(arfd, (long)( nsyms*sizeof(symbol)+sizeof(head) ), 0) == -1) fatal("Seek error on archive file %s", archname); for(;;) { if(fread(&fhead, sizeof(fhead), 1, arfd) != 1) if(feof(arfd)) break; else fatal("Read error on archive %s", archname); if(equaln(fhead.arf_name, name, 14)) { date = sgetl(fhead.arf_date); return(date); } ptr = sgetl(fhead.arf_size); ptr = (ptr+1)&(~1); fseek(arfd, ptr, 1); } return( 0L ); #endif } TIMETYPE entryscan(name) /* return date of member containing global var named */ char *name; { /* * Hunt through each different archive format for the named * symbol. Note that the old archive format does not support * this convention since there is no symbol directory to * scan through for all defined global variables. */ if (ar_type == ARpdp) return (pdpentrys(name)); if (sym_begin == 0L || num_symbols == 0L) { no_such_sym:; fatal1("Cannot find symbol %s in archive %s", name, archname); } if (fseek(arfd, sym_begin, 0) != 0) { seek_error:; fatal1("Seek error on archive file %s", archname); } #ifndef pdp11 if (ar_type == AR5) { register int i; int len = strlen(name); if (len > 8) len = 8; for (i = 0; i < num_symbols; i++) { if (fread((char *)&ars_5, sizeof(ars_5), 1, arfd) != 1) { read_error:; fatal1("Read error on archive %s", archname); } if (equaln(ars_5.sym_name, name, len)) { if (fseek(arfd, sgetl(ars_5.sym_ptr), 0) != 0) goto seek_error; if (fread((char *)&arf_5, sizeof(arf_5), 1, arfd) != 1) { goto read_error; } return (sgetl(arf_5.arf_date)); } } } else /* ar_type == ARport */ { extern char *malloc(); int strtablen; register char *offs; /* offsets table */ register char *syms; /* string table */ register char *strend; /* end of string table */ char *strbeg; /* * Format of the symbol directory for this format is * as follows: [sputl()d number_of_symbols] * [sputl()d first_symbol_offset] * ... * [sputl()d number_of_symbols'_offset] * [null_terminated_string_table_of_symbols] */ if ((offs = malloc(num_symbols * sizeof(long))) == NULL) { fatal1("Cannot alloc offsets table for archive %s", archname); } if (fread(offs, sizeof(long), num_symbols, arfd) != num_symbols) goto read_error; strtablen = sym_size - ((num_symbols + 1) * sizeof(long)); if ((syms = malloc(strtablen)) == NULL) { fatal1("Cannot alloc string table for archive %s", archname); } if (fread(syms, sizeof(char), strtablen, arfd) != strtablen) goto read_error; strend = &syms[strtablen]; strbeg = syms; while (syms < strend) { if (equal(syms, name)) { long ptr, date; ptr = sgetl(offs); if (fseek(arfd, ptr, 0) != 0) goto seek_error; if (fread((char *)&ar_port, sizeof(ar_port), 1, arfd) != 1 || !equaln(ar_port.ar_fmag, ARFportMAG, sizeof(ar_port.ar_fmag))) { goto read_error; } if (sscanf(ar_port.ar_date, "%ld", &date) != 1) { fatal1("Bad date for %.14s, archive %s", ar_port.ar_name, archname); } free(strbeg); return (date); } syms += strlen(syms) + 1; offs += sizeof(long); } free(strbeg); } #endif goto no_such_sym; #if 0 register int i; long date; long ptr; long nsyms; nsyms = sgetl(head.ar_syms); for(i = 0; i < nsyms; i++) { if(fread(&symbol, sizeof(symbol), 1, arfd) != 1) badread: fatal("Read error on archive %s", archname); if(equaln(symbol.sym_name, name, 8)) { ptr = sgetl(symbol.sym_ptr); if(fseek(arfd, ptr, 0) == -1) fatal("Seek error on archive file %s",archname); if(fread(fhead, sizeof(fhead), 1, arfd) != 1) goto badread; date = sgetl(fhead.arf_date); return(date); } } fatal("Cannot find symbol %s in archive %s", name, archname); #endif } TIMETYPE pdpentrys(name) char *name; { long skip; long last; int len; register int i; #ifndef pdp11 fatal("Cannot do global variable search in pdp11 or old object file."); #endif len = strlen(name); if (len > 8) len = 8; /* * Look through archive, an object file entry at a time. For each * object file, jump to its symbol table and check each external * symbol for a match. If found, return the date of the module * containing the symbol. */ if (fseek(arfd, sizeof(short), 0) != 0) { seek_error:; fatal1("Cannot seek on archive file %s", archname); } while (fread((char *)&ar_pdp, sizeof(ar_pdp), 1, arfd) == 1) { last = ftell(arfd); if (ar_pdp.ar_size < sizeof(arobj_pdp) || fread((char *)&arobj_pdp, sizeof(arobj_pdp), 1, arfd) != 1 || (arobj_pdp.a_magic != 0401 && /* A_MAGIC0 */ arobj_pdp.a_magic != 0407 && /* A_MAGIC1 */ arobj_pdp.a_magic != 0410 && /* A_MAGIC2 */ arobj_pdp.a_magic != 0411 && /* A_MAGIC3 */ arobj_pdp.a_magic != 0405 && /* A_MAGIC4 */ arobj_pdp.a_magic != 0437)) /* A_MAGIC5 */ { fatal1("%s is not an object module", ar_pdp.ar_name); } skip = arobj_pdp.a_text + arobj_pdp.a_data; if (!arobj_pdp.a_flag) skip *= 2; if (skip >= ar_pdp.ar_size || fseek(arfd, skip, 1) != 0) goto seek_error; skip = ar_pdp.ar_size; skip += (skip & 01) + last; i = (arobj_pdp.a_syms / sizeof(ars_pdp)) + 1; while (--i > 0) /* look through symbol table */ { if (fread((char *)&ars_pdp, sizeof(ars_pdp), 1, arfd) != 1) { fatal1("Read error on archive %s", archname); } if ((ars_pdp.n_type & 040) /* N_EXT for pdp11 */ && equaln(ars_pdp.n_name, name, len)) { (void)strncpy(archmem, ar_pdp.ar_name, 14); archmem[14] = '\0'; return (ar_pdp.ar_date); } } if (fseek(arfd, skip, 0) != 0) goto seek_error; } return (0L); } openarch(f) register CHARSTAR f; { unsigned short mag_pdp; /* old archive format */ char mag_5[SAR5MAG]; /* 5.0 archive format */ char mag_port[SARportMAG]; /* port (6.0) archive format */ arfd = fopen(f, "r"); if(arfd == NULL) return(-1); /* * More code for three archive formats. Read in just enough to * distinguish the three types and set ar_type. Then if it is * one of the newer archive formats, gather more info. */ if (fread((char *)&mag_pdp, sizeof(mag_pdp), 1, arfd) != 1) return (-1); if (mag_pdp == (unsigned short)ARpdpMAG) { ar_type = ARpdp; first_ar_mem = ftell(arfd); sym_begin = num_symbols = sym_size = 0L; return (0); } if (fseek(arfd, 0L, 0) != 0 || fread(mag_5, SAR5MAG, 1, arfd) != 1) return (-1); if (equaln(mag_5, AR5MAG, SAR5MAG)) { ar_type = AR5; /* * Must read in header to set necessary info */ if (fseek(arfd, 0L, 0) != 0 || fread((char *)&arh_5, sizeof(arh_5), 1, arfd) != 1) { return (-1); } #ifdef pdp11 fatal1("Cannot handle 5.0 archive format for %s", archname); /*NOTREACHED*/ #else sym_begin = ftell(arfd); num_symbols = sgetl(arh_5.ar_syms); first_ar_mem = sym_begin + sizeof(ars_5) * num_symbols; sym_size = 0L; return (0); #endif } if (fseek(arfd, 0L, 0) != 0 || fread(mag_port, SARportMAG, 1, arfd) != 1) { return (-1); } if (equaln(mag_port, ARportMAG, SARportMAG)) { ar_type = ARport; /* * Must read in first member header to find out * if there is a symbol directory */ if (fread((char *)&ar_port, sizeof(ar_port), 1, arfd) != 1 || !equaln(ARFportMAG, ar_port.ar_fmag, sizeof(ar_port.ar_fmag))) { return (-1); } #ifdef pdp11 fatal1("Cannot handle portable archive format for %s", archname); /*NOTREACHED*/ #else if (ar_port.ar_name[0] == '/') { char s[4]; if (sscanf(ar_port.ar_size, "%ld", &sym_size) != 1) return (-1); sym_size += (sym_size & 01); /* round up */ if (fread(s, sizeof(s), 1, arfd) != 1) return (-1); num_symbols = sgetl(s); sym_begin = ftell(arfd); first_ar_mem = sym_begin + sym_size - sizeof(s); } else /* there is no symbol directory */ { sym_size = num_symbols = sym_begin = 0L; first_ar_mem = ftell(arfd) - sizeof(ar_port); } return (0); #endif } fatal1("%s is not an archive", f); /*NOTREACHED*/ #if 0 if(fread(&head, sizeof(head), 1, arfd) != 1) return(-1); if(!equaln(head.ar_magic, ARMAG, 4)) fatal1("%s is not an archive", f); return(0); #endif } clarch() { if(arfd != NULL) fclose(arfd); } /* * Used when unlinking files. If file cannot be stat'ed or it is * a directory, then do not remove it. */ isdir(p) char *p; { struct stat statbuf; if(stat(p, &statbuf) == -1) return(1); /* no stat, no remove */ if((statbuf.st_mode&S_IFMT) == S_IFDIR) return(1); return(0); }