857 lines
20 KiB
C
857 lines
20 KiB
C
/* Copyright (c) 1993 UNIX System Laboratories, Inc. */
|
|
/* All Rights Reserved */
|
|
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
|
|
/* UNIX System Laboratories, Inc. */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
/* Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
|
|
/* Copyright (c) 1988, 1990 AT&T */
|
|
/* All Rights Reserved */
|
|
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
|
|
/* UNIX System Laboratories, Inc. */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
#ident "@(#)make:files.c 1.21.1.2"
|
|
|
|
#include "defs"
|
|
#include <ar.h>
|
|
#include <pwd.h>
|
|
#include <sys/stat.h>
|
|
#include <ctype.h>
|
|
#include <pfmt.h>
|
|
#include <locale.h>
|
|
|
|
#define STREQN !strncmp
|
|
|
|
extern PATTERN firstpat; /* main.c */
|
|
|
|
|
|
/* UNIX VERSION DEPENDENT PROCEDURES */
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
char archmem[NAME_MAX]; /* archive file member name to search for */
|
|
|
|
int ar_type; /* to distiguish which archive format we have */
|
|
#define ARold 1
|
|
#define AR5 2
|
|
#define ARport 3
|
|
|
|
long first_ar_mem, /* where first archive member header is at */
|
|
sym_begin, /* where the symbol lookup starts */
|
|
num_symbols, /* the number of symbols available */
|
|
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 ARoldMAG 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 { /* 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_old;
|
|
|
|
struct { /* old 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_old;
|
|
|
|
struct { /* old a.out symbol table entry */
|
|
char n_name[8]; /* null-terminated name */
|
|
int n_type;
|
|
unsigned n_value;
|
|
} ars_old;
|
|
|
|
struct { /* UNIX 5.0 archive header format: 3b */
|
|
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: 3b */
|
|
char sym_name[8]; /* ' ' terminated */
|
|
char sym_ptr[4]; /* sgetl() accessed */
|
|
} ars_5;
|
|
|
|
struct { /* UNIX 5.0 archive member format: 3b */
|
|
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: 3b */
|
|
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;
|
|
|
|
|
|
|
|
FILE *arfd;
|
|
|
|
int nopen = 0;
|
|
|
|
/*
|
|
** Declare local functions and make LINT happy.
|
|
*/
|
|
|
|
static DEPBLOCK dodir();
|
|
static int umatch();
|
|
static time_t afilescan();
|
|
static time_t entryscan();
|
|
static time_t oldentrys();
|
|
static int openarch();
|
|
static DIR * getfid();
|
|
static time_t lookarch();
|
|
|
|
static char *name_table = NULL;
|
|
static size_t length = 0;
|
|
|
|
|
|
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 */
|
|
{
|
|
register PATTERN patp;
|
|
DIR *dirf;
|
|
CHARSTAR dirname, dirpref, filepat, dname(), sname();
|
|
char temp[MAXPATHLEN], temp2[MAXPATHLEN];
|
|
char pattemp[MAXPATHLEN], dirtemp[MAXPATHLEN];
|
|
|
|
if ( !mkchain )
|
|
for (patp = firstpat; patp; patp = patp->nextpattern)
|
|
if (STREQ(pat, patp->patval))
|
|
return(0);
|
|
|
|
patp = ALLOC(pattern);
|
|
patp->nextpattern = firstpat;
|
|
firstpat = patp;
|
|
patp->patval = copys(pat);
|
|
|
|
(void)copstr(pattemp, pat);
|
|
(void)copstr(dirtemp, pat);
|
|
(void)dname(dirtemp);
|
|
if (STREQ(dirtemp, ".")) {
|
|
dirpref = "";
|
|
dirname = "";
|
|
} else {
|
|
dirpref = concat(dirtemp, "/", temp);
|
|
dirname = concat("/", dirtemp, temp2);
|
|
}
|
|
|
|
filepat = sname(pattemp);
|
|
if (*pat == '/') {
|
|
if ( !(dirf = getfid(dirname)) )
|
|
return(nextdbl);
|
|
else if (dirf != (DIR *) -1)
|
|
nextdbl = dodir(dirf, filepat, dirpref, nextdbl, mkchain);
|
|
} else{
|
|
/*
|
|
* ATT has this as cur_wd - this means:
|
|
* 1) lots more pathname lookups
|
|
* 2) make doesn't work if getcwd fails!
|
|
*/
|
|
(void)concat(".", dirname, dirtemp);
|
|
#ifdef MKDEBUG
|
|
if (IS_ON(DBUG))
|
|
printf("looking in [%s]\n", dirtemp);
|
|
#endif
|
|
if ( dirf = getfid(dirtemp))
|
|
if (dirf != (DIR *) - 1)
|
|
nextdbl = dodir(dirf, filepat, dirpref, nextdbl, mkchain);
|
|
}
|
|
return(nextdbl);
|
|
}
|
|
|
|
|
|
FSTATIC char file_name[MAXNAMLEN];
|
|
|
|
|
|
static DEPBLOCK
|
|
dodir(dirf, filepat, dirpref, nextdbl, mkchain)
|
|
DIR *dirf;
|
|
register CHARSTAR filepat;
|
|
CHARSTAR dirpref;
|
|
DEPBLOCK nextdbl;
|
|
int mkchain;
|
|
{
|
|
register CHARSTAR p1, p2;
|
|
DEPBLOCK thisdbl;
|
|
register dirent_t * entry;
|
|
char fullname[MAXPATHLEN];
|
|
int amatch();
|
|
NAMEBLOCK q;
|
|
|
|
while((entry = readdir(dirf)) != NULL) {
|
|
p1 = entry->d_name;
|
|
p2 = file_name;
|
|
|
|
while ( (*p2++ = *p1++) != CNULL ) ;
|
|
|
|
if ( amatch(file_name, filepat) ) {
|
|
(void)concat(dirpref, file_name, fullname);
|
|
if ( !(q = SRCHNAME(fullname)) )
|
|
q = makename(copys(fullname));
|
|
|
|
if (mkchain) {
|
|
thisdbl = ALLOC(depblock);
|
|
thisdbl->nextdep = nextdbl;
|
|
thisdbl->depname = q;
|
|
nextdbl = thisdbl;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (nextdbl);
|
|
}
|
|
|
|
|
|
amatch(s, p) /* stolen from glob through find */
|
|
register CHARSTAR p;
|
|
CHARSTAR s;
|
|
{
|
|
register int cc, scc = *s, k;
|
|
int c, lc = LRGINT;
|
|
|
|
switch (c = *p) {
|
|
|
|
case LSQUAR:
|
|
k = 0;
|
|
while (cc = *++p) {
|
|
switch (cc) {
|
|
|
|
case RSQUAR:
|
|
if (k)
|
|
return(amatch(++s, ++p));
|
|
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);
|
|
}
|
|
|
|
|
|
static int
|
|
umatch(s, p)
|
|
register CHARSTAR s, p;
|
|
{
|
|
if ( !(*p) )
|
|
return(1);
|
|
while (*s)
|
|
if (amatch(s++, p))
|
|
return(1);
|
|
return(0);
|
|
}
|
|
|
|
|
|
time_t
|
|
la(archive, member, flag)
|
|
char *archive, *member;
|
|
int flag;
|
|
{
|
|
time_t date;
|
|
int aropen = openarch(archive);
|
|
|
|
if ((aropen < 0) && arfd)
|
|
(void)fclose( arfd );
|
|
|
|
if (aropen == -1) /* can't open archive */
|
|
return(0L);
|
|
|
|
/*
|
|
* Openarch returns -1 if the archive is not able to be opened.
|
|
* Openarch has been modified to allow distinction between archive
|
|
* open problems (-1) and symbol table problems for 6.0 archives(-2).
|
|
*/
|
|
if (aropen == -2) /* NULL archive */
|
|
return(1L);
|
|
|
|
if (flag)
|
|
date = entryscan(archive, member);
|
|
else
|
|
date = afilescan(archive, member);
|
|
|
|
/* close the archive file */
|
|
(void)fclose( arfd );
|
|
|
|
return(date);
|
|
}
|
|
|
|
|
|
static time_t
|
|
afilescan(an, name) /* return date for named archive member file */
|
|
char *an, *name;
|
|
{
|
|
long sgetl();
|
|
long ptr;
|
|
size_t len = strlen(name);
|
|
|
|
if (fseek(arfd, first_ar_mem, 0))
|
|
seek_error: fatal1(":87:seek error on archive %s", an);
|
|
|
|
if (name_table) {
|
|
free(name_table);
|
|
name_table = NULL;
|
|
}
|
|
/*
|
|
* Hunt for the named file in each different type of
|
|
* archive format.
|
|
*/
|
|
switch (ar_type) {
|
|
case ARold:
|
|
for (; ; ) {
|
|
if (fread((char *) &ar_old,
|
|
sizeof(ar_old), 1, arfd) != 1) {
|
|
if (feof(arfd))
|
|
return (1L);
|
|
break;
|
|
}
|
|
if (STREQN(ar_old.ar_name, name, len))
|
|
return (ar_old.ar_date);
|
|
ptr = ar_old.ar_size;
|
|
ptr += (ptr & 01);
|
|
if (fseek(arfd, ptr, 1))
|
|
goto seek_error;
|
|
}
|
|
break;
|
|
case AR5:
|
|
for (; ; ) {
|
|
if (fread((char *) &arf_5,
|
|
sizeof(arf_5), 1, arfd) != 1) {
|
|
if (feof(arfd))
|
|
return (1L);
|
|
break;
|
|
}
|
|
if (STREQN(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))
|
|
goto seek_error;
|
|
}
|
|
break;
|
|
case ARport:
|
|
for (;;) {
|
|
if ((fread((char *) &ar_port,
|
|
sizeof(ar_port), 1, arfd) != 1) ||
|
|
!(STREQN(ar_port.ar_fmag, ARFportMAG,
|
|
sizeof(ar_port.ar_fmag)))) {
|
|
if (feof(arfd))
|
|
return (1L);
|
|
break;
|
|
}
|
|
if (ar_port.ar_name[0] == '/') {
|
|
if (ar_port.ar_name[1] == '/') {
|
|
/* a name starting with a // indicates that there
|
|
* is a table strings containing archive member
|
|
* names that are longer than 16 characters
|
|
*/
|
|
if(!name_table) {
|
|
off_t whence;
|
|
|
|
/* have to read in the string table
|
|
* for the first time
|
|
*/
|
|
whence = ftell(arfd);
|
|
sscanf(ar_port.ar_size, "%ld", &length);
|
|
name_table = (char *)malloc(length);
|
|
if(fread(name_table, length, 1, arfd) != 1) {
|
|
if (feof(arfd))
|
|
return (1L);
|
|
break;
|
|
}
|
|
fseek(arfd, whence, SEEK_SET);
|
|
}
|
|
} else if (isdigit(ar_port.ar_name[1])) {
|
|
/* look for name in string table */
|
|
int offset;
|
|
|
|
if (!name_table) {
|
|
fatal1(_SGI_MMX_make_arnostr
|
|
":Missing string table in %s",
|
|
an);
|
|
}
|
|
sscanf(&(ar_port.ar_name[1]), "%d", &offset);
|
|
if (STREQN(&(name_table[offset]), name, len)) {
|
|
long date;
|
|
|
|
if (sscanf(ar_port.ar_date, "%ld",
|
|
&date) != 1)
|
|
fatal1(_SGI_MMX_make_badardate
|
|
":Bad date field for %s in %s",
|
|
name, an);
|
|
return (date);
|
|
}
|
|
} else {
|
|
/*
|
|
* begins with '/' but nothing special
|
|
* ignore ...
|
|
*/
|
|
}
|
|
} else if (STREQN(ar_port.ar_name, name, len) &&
|
|
(len == sizeof ar_port.ar_name ||
|
|
ar_port.ar_name[len] == '/' ||
|
|
ar_port.ar_name[len] == ' ' ||
|
|
ar_port.ar_name[len] == CNULL )) {
|
|
long date;
|
|
|
|
if (sscanf(ar_port.ar_date, "%ld", &date) != 1)
|
|
fatal1(_SGI_MMX_make_badardate
|
|
":Bad date field for %s in %s",
|
|
name, an);
|
|
|
|
return (date);
|
|
}
|
|
|
|
/* skip over entry */
|
|
if (sscanf(ar_port.ar_size, "%ld", &ptr) != 1)
|
|
fatal1(":89:Bad size field for %.14s in archive %s",
|
|
name, an);
|
|
|
|
ptr += (ptr & 01);
|
|
if (fseek(arfd, ptr, 1))
|
|
goto seek_error;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* Only here if fread() [or STREQN()] failed and not at EOF */
|
|
|
|
fatal1(":90:read error on archive %s", an);
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
|
|
static time_t
|
|
entryscan(an, name) /* return date of member containing global var named */
|
|
char *an, *name;
|
|
{
|
|
long sgetl();
|
|
|
|
/*
|
|
* 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 == ARold)
|
|
return (oldentrys(an, name));
|
|
if (sym_begin == 0L || num_symbols == 0L)
|
|
goto no_such_sym;
|
|
|
|
if (fseek(arfd, sym_begin, 0))
|
|
goto seek_error;
|
|
|
|
if (ar_type == AR5) {
|
|
register int i;
|
|
unsigned 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)
|
|
goto read_error;
|
|
if (STREQN(ars_5.sym_name, name, len)) {
|
|
if (fseek(arfd, sgetl(ars_5.sym_ptr), 0))
|
|
goto seek_error;
|
|
if (fread((char *)&arf_5,
|
|
sizeof(arf_5), 1, arfd) != 1)
|
|
goto read_error;
|
|
|
|
/* replace symbol name w/ member name */
|
|
(void)strncpy(archmem, arf_5.arf_name,
|
|
sizeof(arf_5.arf_name));
|
|
|
|
return (sgetl(arf_5.arf_date));
|
|
}
|
|
}
|
|
} else { /* ar_type == ARport */
|
|
register CHARSTAR offs, /* offsets table */
|
|
syms, /* string table */
|
|
strend; /* end of string table */
|
|
void free();
|
|
int strtablen;
|
|
CHARSTAR 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 = (char *) malloc( (unsigned) (num_symbols * sizeof(long)))) )
|
|
fatal1(":92:cannot alloc offsets table for archive %s",
|
|
an);
|
|
|
|
if (fread(offs, sizeof(long), (int) num_symbols, arfd) != num_symbols)
|
|
goto read_error;
|
|
|
|
strtablen = sym_size - ((num_symbols + 1L) * sizeof(long));
|
|
if ( !(syms = (char *) malloc((unsigned) strtablen)) )
|
|
fatal1(":93:cannot alloc string table for archive %s",
|
|
an);
|
|
|
|
if (fread(syms, sizeof(char), strtablen, arfd) != strtablen)
|
|
goto read_error;
|
|
strbeg = syms;
|
|
strend = &syms[strtablen];
|
|
/* while less than end of string table */
|
|
while (syms < strend) {
|
|
if (STREQ(syms, name)) {
|
|
long date;
|
|
register char *ap, *hp;
|
|
|
|
if (fseek(arfd, sgetl(offs), 0))
|
|
goto seek_error;
|
|
if ((fread((char *) &ar_port,
|
|
sizeof(ar_port), 1, arfd) != 1) ||
|
|
!(STREQN(ar_port.ar_fmag,
|
|
ARFportMAG,
|
|
sizeof(ar_port.ar_fmag))))
|
|
goto read_error;
|
|
|
|
if (sscanf(ar_port.ar_date, "%ld", &date) != 1)
|
|
fatal1(_SGI_MMX_make_badardate
|
|
":Bad date field for %s in %s",
|
|
ar_port.ar_name, an);
|
|
|
|
/* replace symbol name w/ member name */
|
|
ap = archmem;
|
|
hp = ar_port.ar_name;
|
|
while (*hp && *hp != '/' &&
|
|
(ap < archmem + sizeof(archmem)))
|
|
*ap++ = *hp++;
|
|
|
|
free(strbeg);
|
|
return (date);
|
|
}
|
|
syms += strlen(syms) + 1;
|
|
offs += sizeof(long);
|
|
}
|
|
free(strbeg);
|
|
}
|
|
|
|
no_such_sym:
|
|
fatal1(":91:cannot find symbol %s in archive %s", name, an);
|
|
/* NOTREACHED */
|
|
|
|
read_error:
|
|
fatal1(":90:read error on archive %s", an);
|
|
/* NOTREACHED */
|
|
|
|
seek_error:
|
|
fatal1(":87:seek error on archive %s", an);
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
|
|
static time_t
|
|
oldentrys(an, name)
|
|
char *an, *name;
|
|
{
|
|
register int i;
|
|
long ftell(), skip, last, len = strlen(name);
|
|
|
|
fatal(":95:Cannot do global variable search old object file.");
|
|
if (len > 8L)
|
|
len = 8L;
|
|
/*
|
|
* 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))
|
|
seek_error: fatal1(":87:seek error on archive %s", an);
|
|
|
|
while (fread((char *) & ar_old, sizeof(ar_old), 1, arfd) == 1) {
|
|
last = ftell(arfd);
|
|
if (ar_old.ar_size < sizeof(arobj_old) ||
|
|
fread((char *) & arobj_old, sizeof(arobj_old),
|
|
1, arfd) != 1 ||
|
|
(arobj_old.a_magic != 0401 && /* A_MAGIC0 */
|
|
arobj_old.a_magic != 0407 && /* A_MAGIC1 */
|
|
arobj_old.a_magic != 0410 && /* A_MAGIC2 */
|
|
arobj_old.a_magic != 0411 && /* A_MAGIC3 */
|
|
arobj_old.a_magic != 0405 && /* A_MAGIC4 */
|
|
arobj_old.a_magic != 0437)) /* A_MAGIC5 */
|
|
fatal1(":96:%s is not an object module (bu42)",
|
|
ar_old.ar_name);
|
|
|
|
skip = arobj_old.a_text + arobj_old.a_data;
|
|
if (!arobj_old.a_flag)
|
|
skip *= 2L;
|
|
if (skip >= ar_old.ar_size || fseek(arfd, skip, 1))
|
|
goto seek_error;
|
|
skip = ar_old.ar_size;
|
|
skip += (skip & 01) + last;
|
|
i = (arobj_old.a_syms / sizeof(ars_old)) + 1;
|
|
while ( --i ) { /* look through symbol table */
|
|
if (fread((char *) &ars_old, sizeof(ars_old), 1, arfd) != 1)
|
|
fatal1(":90:read error on archive %s",
|
|
an);
|
|
|
|
if ((ars_old.n_type & 040) /* N_EXT for old type */
|
|
&& STREQN(ars_old.n_name, name, (int) len)) {
|
|
(void)strncpy(archmem, ar_old.ar_name, (size_t)14);
|
|
archmem[14] = CNULL;
|
|
return (ar_old.ar_date);
|
|
}
|
|
}
|
|
if (fseek(arfd, skip, 0))
|
|
goto seek_error;
|
|
}
|
|
return (0L);
|
|
}
|
|
|
|
|
|
static int
|
|
openarch(f)
|
|
register CHARSTAR f;
|
|
{
|
|
long sgetl(), ftell();
|
|
extern int errno;
|
|
unsigned short mag_old; /* old archive format */
|
|
char mag_5[SAR5MAG], /* 5.0 archive format */
|
|
mag_port[SARportMAG]; /* port (6.0) archive format */
|
|
|
|
|
|
if ( !(arfd = fopen(f, "r")) ){
|
|
if(errno == ENOENT )
|
|
return(-1);
|
|
else
|
|
fatal1(_SGI_MMX_make_noread ":cannot open %s for reading", f);
|
|
}
|
|
/*
|
|
* 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_old, sizeof(mag_old), 1, arfd) != 1)
|
|
fatal1(_SGI_MMX_make_notarch ":%s is not an archive", f);
|
|
if (mag_old == (unsigned short)ARoldMAG) {
|
|
ar_type = ARold;
|
|
first_ar_mem = ftell(arfd);
|
|
sym_begin = num_symbols = sym_size = 0L;
|
|
return (0);
|
|
}
|
|
if (fseek(arfd, 0L, 0) || fread(mag_5, SAR5MAG, 1, arfd) != 1)
|
|
fatal1(_SGI_MMX_make_notarch ":%s is not an archive", f);
|
|
if (STREQN(mag_5, AR5MAG, SAR5MAG)) {
|
|
ar_type = AR5;
|
|
|
|
/* Must read in header to set necessary info */
|
|
|
|
if (fseek(arfd, 0L, 0) ||
|
|
fread((char *) & arh_5, sizeof(arh_5), 1, arfd) != 1)
|
|
return (-1);
|
|
|
|
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);
|
|
}
|
|
if (fseek(arfd, 0L, 0) ||
|
|
fread(mag_port, SARportMAG, 1, arfd) != 1)
|
|
fatal1(_SGI_MMX_make_notarch ":%s is not an archive", f);
|
|
|
|
if (STREQN(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 ||
|
|
!STREQN(ARFportMAG, ar_port.ar_fmag,
|
|
sizeof(ar_port.ar_fmag)))
|
|
return (-2);
|
|
|
|
if (ar_port.ar_name[0] == '/' && ar_port.ar_name[1] == ' ') {
|
|
char s[4];
|
|
|
|
if (sscanf(ar_port.ar_size, "%ld", &sym_size) != 1)
|
|
return (-2);
|
|
sym_size += (sym_size & 01); /* round up */
|
|
if (fread(s, sizeof(s), 1, arfd) != 1)
|
|
return (-2);
|
|
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);
|
|
}
|
|
fatal1(_SGI_MMX_make_unkarch ":%s is unknown archive", f);
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
|
|
static DIR *
|
|
getfid(dirname)
|
|
char *dirname;
|
|
{
|
|
char temp[MAXPATHLEN];
|
|
register DIR * dirf;
|
|
register OPENDIR fod, od = firstod;
|
|
OPENDIR cod, odpred = NULL;
|
|
static maxodirs = -1;
|
|
|
|
cat(temp, dirname, 0);
|
|
(void) compath(temp);
|
|
|
|
if (maxodirs < 0)
|
|
maxodirs = getdtablesize() - 20;
|
|
|
|
while ( od ) {
|
|
if (STREQ(temp, od->dirn)) {
|
|
if ( !(dirf = od->dirfc) ) {
|
|
if (nopen >= maxodirs) {
|
|
for (fod = firstod; fod; fod = fod->nextopendir)
|
|
if ( fod->dirfc )
|
|
cod = fod;
|
|
(void)closedir (cod->dirfc);
|
|
cod->dirfc = NULL;
|
|
nopen--;
|
|
}
|
|
if ( !(dirf = opendir(od->dirn)) )
|
|
return((DIR * ) -1);
|
|
else {
|
|
od->dirfc = dirf;
|
|
nopen++;
|
|
}
|
|
} else /* start over at the beginning */
|
|
(void)rewinddir(dirf);
|
|
|
|
if (odpred) {
|
|
odpred->nextopendir = od->nextopendir;
|
|
od->nextopendir = firstod;
|
|
firstod = od;
|
|
}
|
|
return(dirf);
|
|
}
|
|
|
|
odpred = od;
|
|
od = od->nextopendir;
|
|
}
|
|
|
|
od = ALLOC(s_opendir);
|
|
od->nextopendir = firstod;
|
|
firstod = od;
|
|
od->dirn = copys(temp);
|
|
if (nopen >= maxodirs) {
|
|
for (fod = firstod; fod; fod = fod->nextopendir)
|
|
if ( fod->dirfc )
|
|
cod = fod;
|
|
(void)closedir(cod->dirfc);
|
|
cod->dirfc = NULL;
|
|
nopen--;
|
|
}
|
|
|
|
if ( dirf = opendir(temp) )
|
|
nopen++;
|
|
|
|
od->dirfc = dirf;
|
|
|
|
return(dirf);
|
|
}
|
|
|
|
/*
|
|
* The intent here is to provide a means to make the value of
|
|
* bytes in an io-buffer correspond to the value of a long
|
|
* in the memory while doing the io a `long' at a time.
|
|
* Files written and read in this way are machine-independent.
|
|
*
|
|
*/
|
|
#ifdef __STDC__
|
|
# include <limits.h>
|
|
#else
|
|
# include <values.h>
|
|
# define CHAR_BIT BITSPERBYTE
|
|
# define const
|
|
#endif
|
|
|
|
long
|
|
sgetl(buffer)
|
|
register const char *buffer;
|
|
{
|
|
register long w = 0;
|
|
register int i = CHAR_BIT * sizeof(long);
|
|
|
|
while ((i -= CHAR_BIT) >= 0)
|
|
w |= (long) ((unsigned char) *buffer++) << i;
|
|
return (w);
|
|
}
|