diff options
Diffstat (limited to 'usr.bin/make/arch.c')
-rw-r--r-- | usr.bin/make/arch.c | 213 |
1 files changed, 177 insertions, 36 deletions
diff --git a/usr.bin/make/arch.c b/usr.bin/make/arch.c index a015eab..8a21380 100644 --- a/usr.bin/make/arch.c +++ b/usr.bin/make/arch.c @@ -94,7 +94,7 @@ static char sccsid[] = "@(#)arch.c 8.2 (Berkeley) 1/2/94"; #include <sys/param.h> #include <ctype.h> #include <ar.h> -#include <ranlib.h> +#include <utime.h> #include <stdio.h> #include <stdlib.h> #include "make.h" @@ -108,12 +108,18 @@ typedef struct Arch { char *name; /* Name of archive */ Hash_Table members; /* All the members of the archive described * by <name, struct ar_hdr *> key/value pairs */ + char *fnametab; /* Extended name table strings */ + size_t fnamesize; /* Size of the string table */ } Arch; static int ArchFindArchive __P((ClientData, ClientData)); static void ArchFree __P((ClientData)); static struct ar_hdr *ArchStatMember __P((char *, char *, Boolean)); static FILE *ArchFindMember __P((char *, char *, struct ar_hdr *, char *)); +#if defined(__svr4__) || defined(__SVR4) +#define SVR4ARCHIVES +static int ArchSVR4Entry __P((Arch *, char *, size_t, FILE *)); +#endif /*- *----------------------------------------------------------------------- @@ -143,6 +149,8 @@ ArchFree(ap) free((Address) Hash_GetValue (entry)); free(a->name); + if (a->fnametab) + free(a->fnametab); Hash_DeleteTable(&a->members); free((Address) a); } @@ -486,7 +494,7 @@ ArchStatMember (archive, member, hash) strncpy(copy, member, AR_MAX_NAME_LEN); copy[AR_MAX_NAME_LEN] = '\0'; } - if ( (he = Hash_FindEntry (&ar->members, copy)) ) + if ((he = Hash_FindEntry (&ar->members, copy)) != NULL) return ((struct ar_hdr *) Hash_GetValue (he)); return ((struct ar_hdr *) NULL); } @@ -532,27 +540,58 @@ ArchStatMember (archive, member, hash) } ar = (Arch *)emalloc (sizeof (Arch)); - ar->name = strdup (archive); + ar->name = estrdup (archive); + ar->fnametab = NULL; + ar->fnamesize = 0; Hash_InitTable (&ar->members, -1); memName[AR_MAX_NAME_LEN] = '\0'; while (fread ((char *)&arh, sizeof (struct ar_hdr), 1, arch) == 1) { if (strncmp ( arh.ar_fmag, ARFMAG, sizeof (arh.ar_fmag)) != 0) { - /* - * The header is bogus, so the archive is bad - * and there's no way we can recover... - */ - fclose (arch); - Hash_DeleteTable (&ar->members); - free ((Address)ar); - return ((struct ar_hdr *) NULL); + /* + * The header is bogus, so the archive is bad + * and there's no way we can recover... + */ + goto badarch; } else { + /* + * We need to advance the stream's pointer to the start of the + * next header. Files are padded with newlines to an even-byte + * boundary, so we need to extract the size of the file from the + * 'size' field of the header and round it up during the seek. + */ + arh.ar_size[sizeof(arh.ar_size)-1] = '\0'; + size = (int) strtol(arh.ar_size, NULL, 10); + (void) strncpy (memName, arh.ar_name, sizeof(arh.ar_name)); for (cp = &memName[AR_MAX_NAME_LEN]; *cp == ' '; cp--) { continue; } cp[1] = '\0'; +#ifdef SVR4ARCHIVES + /* + * svr4 names are slash terminated. Also svr4 extended AR format. + */ + if (memName[0] == '/') { + /* + * svr4 magic mode; handle it + */ + switch (ArchSVR4Entry(ar, memName, size, arch)) { + case -1: /* Invalid data */ + goto badarch; + case 0: /* List of files entry */ + continue; + default: /* Got the entry */ + break; + } + } + else { + if (cp[0] == '/') + cp[0] = '\0'; + } +#endif + #ifdef AR_EFMT1 /* * BSD 4.4 extended AR format: #1/<namelen>, with name as the @@ -563,18 +602,10 @@ ArchStatMember (archive, member, hash) unsigned int elen = atoi(&memName[sizeof(AR_EFMT1)-1]); - if (elen > MAXPATHLEN) { - fclose (arch); - Hash_DeleteTable (&ar->members); - free ((Address)ar); - return ((struct ar_hdr *) NULL); - } - if (fread (memName, elen, 1, arch) != 1) { - fclose (arch); - Hash_DeleteTable (&ar->members); - free ((Address)ar); - return ((struct ar_hdr *) NULL); - } + if (elen > MAXPATHLEN) + goto badarch; + if (fread (memName, elen, 1, arch) != 1) + goto badarch; memName[elen] = '\0'; fseek (arch, -elen, 1); if (DEBUG(ARCH) || DEBUG(MAKE)) { @@ -588,14 +619,6 @@ ArchStatMember (archive, member, hash) memcpy ((Address)Hash_GetValue (he), (Address)&arh, sizeof (struct ar_hdr)); } - /* - * We need to advance the stream's pointer to the start of the - * next header. Files are padded with newlines to an even-byte - * boundary, so we need to extract the size of the file from the - * 'size' field of the header and round it up during the seek. - */ - arh.ar_size[sizeof(arh.ar_size)-1] = '\0'; - size = (int) strtol(arh.ar_size, NULL, 10); fseek (arch, (size + 1) & ~1, 1); } @@ -614,8 +637,121 @@ ArchStatMember (archive, member, hash) } else { return ((struct ar_hdr *) NULL); } + +badarch: + fclose (arch); + Hash_DeleteTable (&ar->members); + if (ar->fnametab) + free(ar->fnametab); + free ((Address)ar); + return ((struct ar_hdr *) NULL); } +#ifdef SVR4ARCHIVES +/*- + *----------------------------------------------------------------------- + * ArchSVR4Entry -- + * Parse an SVR4 style entry that begins with a slash. + * If it is "//", then load the table of filenames + * If it is "/<offset>", then try to substitute the long file name + * from offset of a table previously read. + * + * Results: + * -1: Bad data in archive + * 0: A table was loaded from the file + * 1: Name was successfully substituted from table + * 2: Name was not successfully substituted from table + * + * Side Effects: + * If a table is read, the file pointer is moved to the next archive + * member + * + *----------------------------------------------------------------------- + */ +static int +ArchSVR4Entry(ar, name, size, arch) + Arch *ar; + char *name; + size_t size; + FILE *arch; +{ +#define ARLONGNAMES1 "//" +#define ARLONGNAMES2 "/ARFILENAMES" + size_t entry; + char *ptr, *eptr; + + if (strncmp(name, ARLONGNAMES1, sizeof(ARLONGNAMES1) - 1) == 0 || + strncmp(name, ARLONGNAMES2, sizeof(ARLONGNAMES2) - 1) == 0) { + + if (ar->fnametab != NULL) { + if (DEBUG(ARCH)) { + printf("Attempted to redefine an SVR4 name table\n"); + } + return -1; + } + + /* + * This is a table of archive names, so we build one for + * ourselves + */ + ar->fnametab = emalloc(size); + ar->fnamesize = size; + + if (fread(ar->fnametab, size, 1, arch) != 1) { + if (DEBUG(ARCH)) { + printf("Reading an SVR4 name table failed\n"); + } + return -1; + } + eptr = ar->fnametab + size; + for (entry = 0, ptr = ar->fnametab; ptr < eptr; ptr++) + switch (*ptr) { + case '/': + entry++; + *ptr = '\0'; + break; + + case '\n': + break; + + default: + break; + } + if (DEBUG(ARCH)) { + printf("Found svr4 archive name table with %d entries\n", entry); + } + return 0; + } + + if (name[1] == ' ' || name[1] == '\0') + return 2; + + entry = (size_t) strtol(&name[1], &eptr, 0); + if ((*eptr != ' ' && *eptr != '\0') || eptr == &name[1]) { + if (DEBUG(ARCH)) { + printf("Could not parse SVR4 name %s\n", name); + } + return 2; + } + if (entry >= ar->fnamesize) { + if (DEBUG(ARCH)) { + printf("SVR4 entry offset %s is greater than %d\n", + name, ar->fnamesize); + } + return 2; + } + + if (DEBUG(ARCH)) { + printf("Replaced %s with %s\n", name, &ar->fnametab[entry]); + } + + (void) strncpy(name, &ar->fnametab[entry], MAXPATHLEN); + name[MAXPATHLEN] = '\0'; + return 1; +} +#endif + + /*- *----------------------------------------------------------------------- * ArchFindMember -- @@ -820,9 +956,10 @@ void Arch_TouchLib (gn) GNode *gn; /* The node of the library to touch */ { +#ifdef RANLIBMAG FILE * arch; /* Stream open to archive */ struct ar_hdr arh; /* Header describing table of contents */ - struct timeval times[2]; /* Times for utimes() call */ + struct utimbuf times; /* Times for utime() call */ arch = ArchFindMember (gn->path, RANLIBMAG, &arh, "r+"); sprintf(arh.ar_date, "%-12ld", (long) now); @@ -831,10 +968,10 @@ Arch_TouchLib (gn) (void)fwrite ((char *)&arh, sizeof (struct ar_hdr), 1, arch); fclose (arch); - times[0].tv_sec = times[1].tv_sec = now; - times[0].tv_usec = times[1].tv_usec = 0; - utimes(gn->path, times); + times.actime = times.modtime = now; + utime(gn->path, ×); } +#endif } /*- @@ -975,7 +1112,7 @@ Arch_FindLib (gn, path) Var_Set (TARGET, gn->name, gn); #else Var_Set (TARGET, gn->path == (char *) NULL ? gn->name : gn->path, gn); -#endif LIBRARIES +#endif /* LIBRARIES */ } /*- @@ -1025,6 +1162,7 @@ Arch_LibOODate (gn) } else if ((gn->mtime > now) || (gn->mtime < gn->cmtime)) { oodate = TRUE; } else { +#ifdef RANLIBMAG struct ar_hdr *arhPtr; /* Header for __.SYMDEF */ int modTimeTOC; /* The table-of-contents's mod time */ @@ -1046,6 +1184,9 @@ Arch_LibOODate (gn) } oodate = TRUE; } +#else + oodate = FALSE; +#endif } return (oodate); } |