diff options
-rw-r--r-- | usr.bin/make/arch.c | 917 | ||||
-rw-r--r-- | usr.bin/make/arch.h | 4 | ||||
-rw-r--r-- | usr.bin/make/main.c | 10 |
3 files changed, 500 insertions, 431 deletions
diff --git a/usr.bin/make/arch.c b/usr.bin/make/arch.c index 9b993df..e9e9397 100644 --- a/usr.bin/make/arch.c +++ b/usr.bin/make/arch.c @@ -88,9 +88,12 @@ __FBSDID("$FreeBSD$"); */ #include <sys/param.h> +#include <sys/queue.h> #include <sys/types.h> #include <ar.h> #include <ctype.h> +#include <errno.h> +#include <inttypes.h> #include <regex.h> #include <stdlib.h> #include <stdio.h> @@ -109,9 +112,6 @@ __FBSDID("$FreeBSD$"); #include "util.h" #include "var.h" -/* Lst of archives we've already examined */ -static Lst archives = Lst_Initializer(archives); - typedef struct Arch { char *name; /* Name of archive */ @@ -121,13 +121,73 @@ typedef struct Arch { */ Hash_Table members; - char *fnametab; /* Extended name table strings */ - size_t fnamesize; /* Size of the string table */ + TAILQ_ENTRY(Arch) link; /* link all cached archives */ } Arch; -#if defined(__svr4__) || defined(__SVR4) || defined(__ELF__) -#define SVR4ARCHIVES -#endif +/* Lst of archives we've already examined */ +static TAILQ_HEAD(, Arch) archives = TAILQ_HEAD_INITIALIZER(archives); + + +/* size of the name field in the archive member header */ +#define AR_NAMSIZ sizeof(((struct ar_hdr *)0)->ar_name) + +/* + * This structure is used while reading/writing an archive + */ +struct arfile { + FILE *fp; /* archive file */ + char *fname; /* name of the file */ + struct ar_hdr hdr; /* current header */ + char sname[AR_NAMSIZ + 1]; /* short name */ + char *member; /* (long) member name */ + size_t mlen; /* size of the above */ + char *nametab; /* name table */ + size_t nametablen; /* size of the table */ + int64_t time; /* from ar_date */ + uint64_t size; /* from ar_size */ + off_t pos; /* header pos of current entry */ +}; + +/* + * Name of the symbol table. The original BSD used "__.SYMDEF". Rumours go + * that this name may have a slash appended sometimes. Actually FreeBSD + * uses "/" which probably came from SVR4. + */ +#define SVR4_RANLIBMAG "/" +#define BSD_RANLIBMAG "__.SYMDEF" + +/* + * Name of the filename table. The 4.4BSD ar format did not use this, but + * puts long filenames directly between the member header and the object + * file. + */ +#define SVR4_NAMEMAG "//" +#define BSD_NAMEMAG "ARFILENAMES/" + +/* + * 44BSD long filename key. Use a local define here instead of relying + * on ar.h because we want this to continue working even when the + * definition is removed from ar.h. + */ +#define BSD_EXT1 "#1/" +#define BSD_EXT1LEN 3 + +/* if this is TRUE make archive errors fatal */ +Boolean arch_fatal = TRUE; + +/** + * ArchError + * An error happend while handling an archive. BSDmake traditionally + * ignored these errors. Now this is dependend on the global arch_fatal + * which, if true, makes these errors fatal and, if false, just emits an + * error message. + */ +#define ArchError(ARGS) do { \ + if (arch_fatal) \ + Fatal ARGS; \ + else \ + Error ARGS; \ + } while (0) /*- *----------------------------------------------------------------------- @@ -413,251 +473,388 @@ Arch_ParseArchive(char **linePtr, Lst *nodeLst, GNode *ctxt) return (SUCCESS); } -/*- - *----------------------------------------------------------------------- - * ArchFindMember -- - * Locate a member of an archive, given the path of the archive and - * the path of the desired member. If the archive is to be modified, - * the mode should be "r+", if not, it should be "r". arhPtr is a - * poitner to the header structure to fill in. - * - * Results: - * An FILE *, opened for reading and writing, positioned at the - * start of the member's struct ar_hdr, or NULL if the member was - * nonexistent. The current struct ar_hdr for member. - * - * Side Effects: - * The passed struct ar_hdr structure is filled in. - * - *----------------------------------------------------------------------- +/* + * Close an archive file an free all resources */ -static FILE * -ArchFindMember(const char *archive, const char *member, struct ar_hdr *arhPtr, - const char *mode) +static void +ArchArchiveClose(struct arfile *ar) { - FILE *arch; /* Stream to archive */ - int size; /* Size of archive member */ - const char *cp; /* Useful character pointer */ - char magic[SARMAG]; - size_t len; - size_t tlen; - arch = fopen(archive, mode); - if (arch == NULL) { + if (ar->nametab != NULL) + free(ar->nametab); + free(ar->member); + if (ar->fp != NULL) { + if (fclose(ar->fp) == EOF) + ArchError(("%s: close error", ar->fname)); + } + free(ar->fname); + free(ar); +} + +/* + * Open an archive file. + */ +static struct arfile * +ArchArchiveOpen(const char *archive, const char *mode) +{ + struct arfile *ar; + char magic[SARMAG]; + + ar = emalloc(sizeof(*ar)); + ar->fname = estrdup(archive); + ar->mlen = 100; + ar->member = emalloc(ar->mlen); + ar->nametab = NULL; + ar->nametablen = 0; + + if ((ar->fp = fopen(ar->fname, mode)) == NULL) { + DEBUGM(ARCH, ("%s", ar->fname)); + ArchArchiveClose(ar); return (NULL); } - /* - * We use the ARMAG string to make sure this is an archive we - * can handle... - */ - if (fread(magic, SARMAG, 1, arch) != 1 || + /* read MAGIC */ + if (fread(magic, SARMAG, 1, ar->fp) != 1 || strncmp(magic, ARMAG, SARMAG) != 0) { - fclose(arch); + ArchError(("%s: bad archive magic\n", ar->fname)); + ArchArchiveClose(ar); return (NULL); } + ar->pos = 0; + return (ar); +} + +/* + * Read the next header from the archive. The return value will be +1 if + * the header is read successfully, 0 on EOF and -1 if an error happend. + * On a successful return sname contains the truncated member name and + * member the full name. hdr contains the member header. For the symbol table + * names of length 0 are returned. The entry for the file name table is never + * returned. + */ +static int +ArchArchiveNext(struct arfile *ar) +{ + char *end; + int have_long_name; + u_long offs; + char *ptr; + size_t ret; + char buf[MAX(sizeof(ar->hdr.ar_size), sizeof(ar->hdr.ar_date)) + 1]; + + next: /* - * Because of space constraints and similar things, files are archived - * using their final path components, not the entire thing, so we need - * to point 'member' to the final component, if there is one, to make - * the comparisons easier... + * Seek to the next header. */ - cp = strrchr(member, '/'); - if (cp != NULL && strcmp(member, RANLIBMAG) != 0) { - member = cp + 1; + if (ar->pos == 0) { + ar->pos = SARMAG; + } else { + ar->pos += sizeof(ar->hdr) + ar->size; + if (ar->size % 2 == 1) + ar->pos++; } - len = tlen = strlen(member); - if (len > sizeof(arhPtr->ar_name)) { - tlen = sizeof(arhPtr->ar_name); + + if (fseeko(ar->fp, ar->pos, SEEK_SET) == -1) { + ArchError(("%s: cannot seek to %jd: %s", ar->fname, + (intmax_t)ar->pos, strerror(errno))); + return (-1); } - while (fread(arhPtr, sizeof(struct ar_hdr), 1, arch) == 1) { - if (strncmp(arhPtr->ar_fmag, ARFMAG, - sizeof(arhPtr->ar_fmag)) != 0) { - /* - * The header is bogus, so the archive is bad - * and there's no way we can recover... - */ - fclose(arch); - return (NULL); - } + /* + * Read next member header + */ + ret = fread(&ar->hdr, sizeof(ar->hdr), 1, ar->fp); + if (ret != 1) { + if (feof(ar->fp)) + return (0); + ArchError(("%s: error reading member header: %s", ar->fname, + strerror(errno))); + return (-1); + } + if (strncmp(ar->hdr.ar_fmag, ARFMAG, sizeof(ar->hdr.ar_fmag)) != 0) { + ArchError(("%s: bad entry magic", ar->fname)); + return (-1); + } - if (strncmp(member, arhPtr->ar_name, tlen) == 0) { - /* - * If the member's name doesn't take up the entire - * 'name' field, we have to be careful of matching - * prefixes. Names are space-padded to the right, so if - * the character in 'name' at the end of the matched - * string is anything but a space, this isn't the - * member we sought. Additionally there may be a - * slash at the end of the name (System 5 style). - */ - if (tlen != sizeof(arhPtr->ar_name) && - arhPtr->ar_name[tlen] != ' ' && - arhPtr->ar_name[tlen] != '/') { - goto skip; + /* + * looks like a member - get name by stripping trailing spaces + * and NUL terminating. + */ + strncpy(ar->sname, ar->hdr.ar_name, AR_NAMSIZ); + ar->sname[AR_NAMSIZ] = '\0'; + for (ptr = ar->sname + AR_NAMSIZ; ptr > ar->sname; ptr--) + if (ptr[-1] != ' ') + break; + + *ptr = '\0'; + + /* + * Parse the size. All entries need to have a size. Be careful + * to not allow buffer overruns. + */ + strncpy(buf, ar->hdr.ar_size, sizeof(ar->hdr.ar_size)); + buf[sizeof(ar->hdr.ar_size)] = '\0'; + + errno = 0; + ar->size = strtoumax(buf, &end, 10); + if (errno != 0 || strspn(end, " ") != strlen(end)) { + ArchError(("%s: bad size format in archive '%s'", + ar->fname, buf)); + return (-1); + } + + /* + * Look for the extended name table. Do this before parsing + * the date because this table doesn't need a date. + */ + if (strcmp(ar->sname, BSD_NAMEMAG) == 0 || + strcmp(ar->sname, SVR4_NAMEMAG) == 0) { + /* filename table - read it in */ + ar->nametablen = ar->size; + ar->nametab = emalloc(ar->nametablen); + + ret = fread(ar->nametab, 1, ar->nametablen, ar->fp); + if (ret != ar->nametablen) { + if (ferror(ar->fp)) { + ArchError(("%s: cannot read nametab: %s", + ar->fname, strerror(errno))); + } else { + ArchError(("%s: cannot read nametab: " + "short read", ar->fname, strerror(errno))); } - /* - * To make life easier, we reposition the file at the - * start of the header we just read before we return the - * stream. In a more general situation, it might be - * better to leave the file at the actual member, rather - * than its header, but not here... - */ - fseek(arch, -sizeof(struct ar_hdr), SEEK_CUR); - return (arch); + return (-1); } -#ifdef AR_EFMT1 + /* - * BSD 4.4 extended AR format: #1/<namelen>, with name as the - * first <namelen> bytes of the file + * NUL terminate the entries. Entries are \n terminated + * and may have a trailing / or \. */ - if (strncmp(arhPtr->ar_name, AR_EFMT1, - sizeof(AR_EFMT1) - 1) == 0 && - isdigit(arhPtr->ar_name[sizeof(AR_EFMT1) - 1])) { - unsigned elen; - char ename[MAXPATHLEN]; - - elen = atoi(&arhPtr->ar_name[sizeof(AR_EFMT1) - 1]); - if (elen > MAXPATHLEN) { - fclose(arch); - return (NULL); - } - if (fread(ename, elen, 1, arch) != 1) { - fclose(arch); - return NULL; - } - ename[elen] = '\0'; - /* - * XXX choose one. - */ - if (DEBUG(ARCH) || DEBUG(MAKE)) { - printf("ArchFind: Extended format entry for " - "%s\n", ename); + ptr = ar->nametab; + while (ptr < ar->nametab + ar->nametablen) { + if (*ptr == '\n') { + if (ptr[-1] == '/' || ptr[-1] == '\\') + ptr[-1] = '\0'; + *ptr = '\0'; } - if (strncmp(ename, member, len) == 0) { - /* Found as extended name */ - fseek(arch, -sizeof(struct ar_hdr) - elen, - SEEK_CUR); - return (arch); + ptr++; + } + + /* get next archive entry */ + goto next; + } + + /* + * Now parse the modification date. Be careful to not overrun + * buffers. + */ + strncpy(buf, ar->hdr.ar_date, sizeof(ar->hdr.ar_date)); + buf[sizeof(ar->hdr.ar_date)] = '\0'; + + errno = 0; + ar->time = (int64_t)strtoll(buf, &end, 10); + if (errno != 0 || strspn(end, " ") != strlen(end)) { + ArchError(("%s: bad date format in archive '%s'", + ar->fname, buf)); + return (-1); + } + + /* + * Now check for the symbol table. This should really be the first + * entry, but we don't check this. + */ + if (strcmp(ar->sname, BSD_RANLIBMAG) == 0 || + strcmp(ar->sname, SVR4_RANLIBMAG) == 0) { + /* symbol table - return a zero length name */ + ar->member[0] = '\0'; + ar->sname[0] = '\0'; + return (1); + } + + have_long_name = 0; + + /* + * Look whether this is a long name. There are several variants + * of long names: + * "#1/12 " - 12 length of following filename + * "/17 " - index into name table + * " 17 " - index into name table + * Note that in the last case we must also check that there is no + * slash in the name because of filenames with leading spaces: + * " 777.o/ " - filename 777.o + */ + if (ar->sname[0] == '/' || (ar->sname[0] == ' ' && + strchr(ar->sname, '/') == NULL)) { + /* SVR4 extended name */ + errno = 0; + offs = strtoul(ar->sname + 1, &end, 10); + if (errno != 0 || *end != '\0' || offs >= ar->nametablen || + end == ar->sname + 1) { + ArchError(("%s: bad extended name '%s'", ar->fname, + ar->sname)); + return (-1); + } + + /* fetch the name */ + if (ar->mlen <= strlen(ar->nametab + offs)) { + ar->mlen = strlen(ar->nametab + offs) + 1; + ar->member = erealloc(ar->member, ar->mlen); + } + strcpy(ar->member, ar->nametab + offs); + + have_long_name = 1; + + } else if (strncmp(ar->sname, BSD_EXT1, BSD_EXT1LEN) == 0 && + isdigit(ar->sname[BSD_EXT1LEN])) { + /* BSD4.4 extended name */ + errno = 0; + offs = strtoul(ar->sname + BSD_EXT1LEN, &end, 10); + if (errno != 0 || *end != '\0' || + end == ar->sname + BSD_EXT1LEN) { + ArchError(("%s: bad extended name '%s'", ar->fname, + ar->sname)); + return (-1); + } + + /* read it from the archive */ + if (ar->mlen <= offs) { + ar->mlen = offs + 1; + ar->member = erealloc(ar->member, ar->mlen); + } + ret = fread(ar->member, 1, offs, ar->fp); + if (ret != offs) { + if (ferror(ar->fp)) { + ArchError(("%s: reading extended name: %s", + ar->fname, strerror(errno))); + } else { + ArchError(("%s: reading extended name: " + "short read", ar->fname)); } - fseek(arch, -elen, SEEK_CUR); - goto skip; + return (-1); } - #endif - skip: - /* - * This isn't the member we're after, so 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. - */ - arhPtr->ar_size[sizeof(arhPtr->ar_size) - 1] = '\0'; - size = (int)strtol(arhPtr->ar_size, NULL, 10); - fseek(arch, (size + 1) & ~1, SEEK_CUR); + ar->member[offs] = '\0'; + + have_long_name = 1; } /* - * We've looked everywhere, but the member is not to be found. Close the - * archive and return NULL -- an error. + * Now remove the trailing slash that Svr4 puts at + * the end of the member name to support trailing spaces in names. */ - fclose(arch); - return (NULL); + if (ptr > ar->sname && ptr[-1] == '/') + *--ptr = '\0'; + + if (!have_long_name) { + if (strlen(ar->sname) >= ar->mlen) { + ar->mlen = strlen(ar->sname) + 1; + ar->member = erealloc(ar->member, ar->mlen); + } + strcpy(ar->member, ar->sname); + } + + return (1); +} + +/* + * Touch the current archive member by writing a new header with an + * updated timestamp. The return value is 0 for success and -1 for errors. + */ +static int +ArchArchiveTouch(struct arfile *ar, int64_t ts) +{ + + /* seek to our header */ + if (fseeko(ar->fp, ar->pos, SEEK_SET) == -1) { + ArchError(("%s: cannot seek to %jd: %s", ar->fname, + (intmax_t)ar->pos, strerror(errno))); + return (-1); + } + + /* + * change timestamp, be sure to not NUL-terminated it, but + * to fill with spaces. + */ + snprintf(ar->hdr.ar_date, sizeof(ar->hdr.ar_date), "%lld", ts); + memset(ar->hdr.ar_date + strlen(ar->hdr.ar_date), + ' ', sizeof(ar->hdr.ar_date) - strlen(ar->hdr.ar_date)); + + if (fwrite(&ar->hdr, sizeof(ar->hdr), 1, ar->fp) != 1) { + ArchError(("%s: cannot touch: %s", ar->fname, strerror(errno))); + return (-1); + } + return (0); } -#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. + * ArchFindMember -- + * Locate a member of an archive, given the path of the archive and + * the path of the desired member. If the archive is to be modified, + * the mode should be "r+", if not, it should be "r". The archive + * file is returned positioned at the correct header. * * 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 + * A struct arfile *, opened for reading and, possibly writing, + * positioned at the member's header, or NULL if the member was + * nonexistent. * *----------------------------------------------------------------------- */ -static int -ArchSVR4Entry(Arch *ar, char *name, size_t size, FILE *arch) +static struct arfile * +ArchFindMember(const char *archive, const char *member, const char *mode) { -#define ARLONGNAMES1 "//" -#define ARLONGNAMES2 "/ARFILENAMES" - size_t entry; - char *ptr; - char *eptr; + struct arfile *ar; + const char *cp; /* Useful character pointer */ - if (strncmp(name, ARLONGNAMES1, sizeof(ARLONGNAMES1) - 1) == 0 || - strncmp(name, ARLONGNAMES2, sizeof(ARLONGNAMES2) - 1) == 0) { + if ((ar = ArchArchiveOpen(archive, mode)) == NULL) + return (NULL); - if (ar->fnametab != NULL) { - DEBUGF(ARCH, ("Attempted to redefine an SVR4 name " - "table\n")); - return (-1); + /* + * Because of space constraints and similar things, files are archived + * using their final path components, not the entire thing, so we need + * to point 'member' to the final component, if there is one, to make + * the comparisons easier... + */ + if (member != NULL) { + cp = strrchr(member, '/'); + if (cp != NULL) { + member = cp + 1; } + } + while (ArchArchiveNext(ar) > 0) { /* - * This is a table of archive names, so we build one for - * ourselves + * When comparing there are actually three cases: + * (1) the name fits into the limit og af_name, + * (2) the name is longer and the archive supports long names, + * (3) the name is longer and the archive doesn't support long + * names. + * Because we don't know whether the archive supports long + * names or not we need to be carefull. */ - ar->fnametab = emalloc(size); - ar->fnamesize = size; - - if (fread(ar->fnametab, size, 1, arch) != 1) { - DEBUGF(ARCH, ("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 (member == NULL) { + /* special case - symbol table */ + if (ar->member[0] == '\0') + return (ar); + } else if (strlen(member) <= AR_NAMSIZ) { + /* case (1) */ + if (strcmp(ar->member, member) == 0) + return (ar); + } else if (strcmp(ar->member, member) == 0) { + /* case (3) */ + return (ar); + } else { + /* case (2) */ + if (strlen(ar->member) == AR_NAMSIZ && + strncmp(member, ar->member, AR_NAMSIZ) == 0) + return (ar); } - DEBUGF(ARCH, ("Found svr4 archive name table with %zu " - "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]) { - DEBUGF(ARCH, ("Could not parse SVR4 name %s\n", name)); - return (2); } - if (entry >= ar->fnamesize) { - DEBUGF(ARCH, ("SVR4 entry offset %s is greater than %zu\n", - name, ar->fnamesize)); - return (2); - } - - DEBUGF(ARCH, ("Replaced %s with %s\n", name, &ar->fnametab[entry])); - strncpy(name, &ar->fnametab[entry], MAXPATHLEN); - name[MAXPATHLEN] = '\0'; - return (1); + /* not found */ + ArchArchiveClose(ar); + return (NULL); } -#endif /*- *----------------------------------------------------------------------- @@ -677,19 +874,16 @@ ArchSVR4Entry(Arch *ar, char *name, size_t size, FILE *arch) * *----------------------------------------------------------------------- */ -static struct ar_hdr * +static int64_t ArchStatMember(const char *archive, const char *member, Boolean hash) { -#define AR_MAX_NAME_LEN (sizeof(arh.ar_name) - 1) - FILE *arch; /* Stream to archive */ - int size; /* Size of archive member */ + struct arfile *arf; + int64_t ret; + int t; char *cp; /* Useful character pointer */ - char magic[SARMAG]; - LstNode *ln; /* Lst member containing archive descriptor */ Arch *ar; /* Archive descriptor */ Hash_Entry *he; /* Entry containing member's description */ - struct ar_hdr arh; /* archive-member header for reading archive */ - char memName[MAXPATHLEN + 1]; /* Current member name while hashing */ + char copy[AR_NAMSIZ + 1]; /* * Because of space constraints and similar things, files are archived @@ -697,179 +891,85 @@ ArchStatMember(const char *archive, const char *member, Boolean hash) * to point 'member' to the final component, if there is one, to make * the comparisons easier... */ - cp = strrchr(member, '/'); - if (cp != NULL && strcmp(member, RANLIBMAG) != 0) - member = cp + 1; - - LST_FOREACH(ln, &archives) { - if (strcmp(archive, ((const Arch *)Lst_Datum(ln))->name) == 0) - break; + if (member != NULL) { + cp = strrchr(member, '/'); + if (cp != NULL) + member = cp + 1; } - if (ln != NULL) { - char copy[AR_MAX_NAME_LEN + 1]; - - ar = Lst_Datum(ln); - - he = Hash_FindEntry(&ar->members, member); - if (he != NULL) { - return (Hash_GetValue(he)); - } - /* Try truncated name */ - strncpy(copy, member, AR_MAX_NAME_LEN); - copy[AR_MAX_NAME_LEN] = '\0'; - - if ((he = Hash_FindEntry(&ar->members, copy)) != NULL) - return (Hash_GetValue(he)); - return (NULL); - } - - if (!hash) { - /* - * Caller doesn't want the thing hashed, just use ArchFindMember - * to read the header for the member out and close down the - * stream again. Since the archive is not to be hashed, we - * assume there's no need to allocate extra room for the header - * we're returning, so just declare it static. - */ - static struct ar_hdr sarh; - - arch = ArchFindMember(archive, member, &sarh, "r"); - if (arch == NULL) { - return (NULL); - } - fclose(arch); - return (&sarh); - } - - /* - * We don't have this archive on the list yet, so we want to find out - * everything that's in it and cache it so we can get at it quickly. - */ - arch = fopen(archive, "r"); - if (arch == NULL) { - return (NULL); - } - - /* - * We use the ARMAG string to make sure this is an archive we - * can handle... - */ - if (fread(magic, SARMAG, 1, arch) != 1 || - strncmp(magic, ARMAG, SARMAG) != 0) { - fclose(arch); - return (NULL); + TAILQ_FOREACH(ar, &archives, link) { + if (strcmp(archive, ar->name) == 0) + break; } - - ar = emalloc(sizeof(Arch)); - ar->name = estrdup(archive); - ar->fnametab = NULL; - ar->fnamesize = 0; - Hash_InitTable(&ar->members, -1); - memName[AR_MAX_NAME_LEN] = '\0'; - - while (fread(&arh, sizeof(struct ar_hdr), 1, arch) == 1) { - if (strncmp(arh.ar_fmag, ARFMAG, sizeof(arh.ar_fmag)) != 0) { + if (ar == NULL) { + /* archive not found */ + if (!hash) { /* - * The header is bogus, so the archive is bad - * and there's no way we can recover... + * Caller doesn't want the thing hashed, just use + * ArchFindMember to read the header for the member + * out and close down the stream again. */ - goto badarch; - } - /* - * 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); - - strncpy(memName, arh.ar_name, sizeof(arh.ar_name)); - for (cp = &memName[AR_MAX_NAME_LEN]; *cp == ' '; cp--) { - ; + arf = ArchFindMember(archive, member, "r"); + if (arf == NULL) { + return (INT64_MIN); + } + ret = arf->time; + ArchArchiveClose(arf); + return (ret); } - cp[1] = '\0'; -#ifdef SVR4ARCHIVES /* - * svr4 names are slash terminated. Also svr4 extended AR - * format. + * We don't have this archive on the list yet, so we want to + * find out everything that's in it and cache it so we can get + * at it quickly. */ - if (memName[0] == '/') { - /* - * svr4 magic mode; handle it - */ - switch (ArchSVR4Entry(ar, memName, size, arch)) { + arf = ArchArchiveOpen(archive, "r"); + if (arf == NULL) { + return (INT64_MIN); + } - case -1: /* Invalid data */ - goto badarch; + /* create archive data structure */ + ar = emalloc(sizeof(*ar)); + ar->name = estrdup(archive); + Hash_InitTable(&ar->members, -1); - case 0: /* List of files entry */ - continue; - default: /* Got the entry */ - break; - } - } else { - if (cp[0] == '/') - cp[0] = '\0'; + while ((t = ArchArchiveNext(arf)) > 0) { + he = Hash_CreateEntry(&ar->members, arf->member, NULL); + Hash_SetValue(he, emalloc(sizeof(int64_t))); + *(int64_t *)Hash_GetValue(he) = arf->time; } -#endif -#ifdef AR_EFMT1 - /* - * BSD 4.4 extended AR format: #1/<namelen>, with name as the - * first <namelen> bytes of the file - */ - if (strncmp(memName, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0 && - isdigit(memName[sizeof(AR_EFMT1) - 1])) { - unsigned elen = atoi(&memName[sizeof(AR_EFMT1) - 1]); - - if (elen > MAXPATHLEN) - goto badarch; - if (fread(memName, elen, 1, arch) != 1) - goto badarch; - memName[elen] = '\0'; - fseek(arch, -elen, SEEK_CUR); - /* - * XXX Multiple levels may be asked for, make this - * conditional on one, and use DEBUGF. - */ - if (DEBUG(ARCH) || DEBUG(MAKE)) { - fprintf(stderr, "ArchStat: Extended format " - "entry for %s\n", memName); - } + ArchArchiveClose(arf); + + if (t < 0) { + /* error happend - throw away everything */ + Hash_DeleteTable(&ar->members); + free(ar->name); + free(ar); + return (INT64_MIN); } -#endif - he = Hash_CreateEntry(&ar->members, memName, NULL); - Hash_SetValue(he, emalloc(sizeof(struct ar_hdr))); - memcpy(Hash_GetValue(he), &arh, sizeof(struct ar_hdr)); - fseek(arch, (size + 1) & ~1, SEEK_CUR); + TAILQ_INSERT_TAIL(&archives, ar, link); } - fclose(arch); - - Lst_AtEnd(&archives, ar); - /* * Now that the archive has been read and cached, we can look into * the hash table to find the desired member's header. */ he = Hash_FindEntry(&ar->members, member); + if (he != NULL) + return (*(int64_t *)Hash_GetValue (he)); - if (he != NULL) { - return (Hash_GetValue (he)); - } else { - return (NULL); + if (member != NULL && strlen(member) > AR_NAMSIZ) { + /* Try truncated name */ + strncpy(copy, member, AR_NAMSIZ); + copy[AR_NAMSIZ] = '\0'; + + if ((he = Hash_FindEntry(&ar->members, copy)) != NULL) + return (*(int64_t *)Hash_GetValue(he)); } - badarch: - fclose(arch); - Hash_DeleteTable(&ar->members); - free(ar->fnametab); - free(ar); - return (NULL); + return (INT64_MIN); } /*- @@ -890,19 +990,17 @@ ArchStatMember(const char *archive, const char *member, Boolean hash) void Arch_Touch(GNode *gn) { - FILE *arch; /* Archive stream, positioned properly */ - struct ar_hdr arh; /* Current header describing member */ + struct arfile *ar; char *p1, *p2; - arch = ArchFindMember(Var_Value(ARCHIVE, gn, &p1), - Var_Value(TARGET, gn, &p2), &arh, "r+"); + ar = ArchFindMember(Var_Value(ARCHIVE, gn, &p1), + Var_Value(TARGET, gn, &p2), "r+"); free(p1); free(p2); - if (arch != NULL) { - snprintf(arh.ar_date, sizeof(arh.ar_date), "%-12ld", (long)now); - fwrite(&arh, sizeof(struct ar_hdr), 1, arch); - fclose(arch); + if (ar != NULL) { + ArchArchiveTouch(ar, (int64_t)now); + ArchArchiveClose(ar); } } @@ -924,22 +1022,17 @@ Arch_Touch(GNode *gn) void Arch_TouchLib(GNode *gn) { -#ifdef RANLIBMAG - FILE *arch; /* Stream open to archive */ - struct ar_hdr arh; /* Header describing table of contents */ + struct arfile *ar; /* Open archive */ struct utimbuf times; /* Times for utime() call */ - arch = ArchFindMember(gn->path, RANLIBMAG, &arh, "r+"); - if (arch != NULL) { - snprintf(arh.ar_date, sizeof(arh.ar_date), - "%-12ld", (long) now); - fwrite(&arh, sizeof(struct ar_hdr), 1, arch); - fclose(arch); + ar = ArchFindMember(gn->path, NULL, "r+"); + if (ar != NULL) { + ArchArchiveTouch(ar, (int64_t)now); + ArchArchiveClose(ar); times.actime = times.modtime = now; utime(gn->path, ×); } -#endif } /*- @@ -961,23 +1054,19 @@ Arch_TouchLib(GNode *gn) int Arch_MTime(GNode *gn) { - struct ar_hdr *arhPtr; /* Header of desired member */ - int modTime; /* Modification time as an integer */ - char *p1, *p2; + int64_t mtime; + char *p1, *p2; - arhPtr = ArchStatMember(Var_Value(ARCHIVE, gn, &p1), + mtime = ArchStatMember(Var_Value(ARCHIVE, gn, &p1), Var_Value(TARGET, gn, &p2), TRUE); free(p1); free(p2); - if (arhPtr != NULL) { - modTime = (int)strtol(arhPtr->ar_date, NULL, 10); - } else { - modTime = 0; + if (mtime == INT_MIN) { + mtime = 0; } - - gn->mtime = modTime; - return (modTime); + gn->mtime = (int)mtime; /* XXX */ + return (gn->mtime); } /*- @@ -1114,10 +1203,7 @@ Arch_FindLib(GNode *gn, struct Path *path) Boolean Arch_LibOODate(GNode *gn) { -#ifdef RANLIBMAG - struct ar_hdr *arhPtr; /* Header for __.SYMDEF */ - int modTimeTOC; /* The table-of-contents's mod time */ -#endif + int64_t mtime; /* The table-of-contents's mod time */ if (OP_NOP(gn->type) && Lst_IsEmpty(&gn->children)) { return (FALSE); @@ -1126,43 +1212,20 @@ Arch_LibOODate(GNode *gn) return (TRUE); } -#ifdef RANLIBMAG - arhPtr = ArchStatMember(gn->path, RANLIBMAG, FALSE); - - if (arhPtr != NULL) { - modTimeTOC = (int)strtol(arhPtr->ar_date, NULL, 10); - - /* XXX choose one. */ - if (DEBUG(ARCH) || DEBUG(MAKE)) { - printf("%s modified %s...", RANLIBMAG, - Targ_FmtTime(modTimeTOC)); - } - return (gn->cmtime > modTimeTOC); - } else { + mtime = ArchStatMember(gn->path, NULL, FALSE); + if (mtime == INT64_MIN) { /* - * A library w/o a table of contents is out-of-date + * Not found. A library w/o a table of contents is out-of-date */ if (DEBUG(ARCH) || DEBUG(MAKE)) { - printf("No t.o.c...."); + Debug("No TOC..."); } return (TRUE); } -#else - return (gn->mtime == 0); /* out-of-date if not present */ -#endif -} -/*- - *----------------------------------------------------------------------- - * Arch_Init -- - * Initialize things for this module. - * - * Results: - * None. - * - *----------------------------------------------------------------------- - */ -void -Arch_Init(void) -{ + /* XXX choose one. */ + if (DEBUG(ARCH) || DEBUG(MAKE)) { + Debug("TOC modified %s...", Targ_FmtTime(mtime)); + } + return (gn->cmtime > mtime); } diff --git a/usr.bin/make/arch.h b/usr.bin/make/arch.h index d3f4ba9..5b2542f 100644 --- a/usr.bin/make/arch.h +++ b/usr.bin/make/arch.h @@ -47,6 +47,9 @@ struct GNode; struct Lst; struct Path; +/* archive errors are fatal */ +extern Boolean arch_fatal; + ReturnStatus Arch_ParseArchive(char **, struct Lst *, struct GNode *); void Arch_Touch(struct GNode *); void Arch_TouchLib(struct GNode *); @@ -54,6 +57,5 @@ int Arch_MTime(struct GNode *); int Arch_MemMTime(struct GNode *); void Arch_FindLib(struct GNode *, struct Path *); Boolean Arch_LibOODate(struct GNode *); -void Arch_Init(void); #endif /* arch_h_488adf7a */ diff --git a/usr.bin/make/main.c b/usr.bin/make/main.c index b2c3379..6e0ac8c 100644 --- a/usr.bin/make/main.c +++ b/usr.bin/make/main.c @@ -188,9 +188,14 @@ MainParseArgs(int argc, char **argv) int c; optind = 1; /* since we're called more than once */ -#define OPTFLAGS "BC:D:E:I:PSV:Xd:ef:ij:km:nqrstv" +#define OPTFLAGS "ABC:D:E:I:PSV:Xd:ef:ij:km:nqrstv" rearg: while((c = getopt(argc, argv, OPTFLAGS)) != -1) { switch(c) { + + case 'A': + arch_fatal = FALSE; + MFLAGS_append("-A", NULL); + break; case 'C': if (chdir(optarg) == -1) err(1, "chdir %s", optarg); @@ -718,10 +723,9 @@ main(int argc, char **argv) compatMake = TRUE; /* - * Initialize archive, target and suffix modules in preparation for + * Initialize target and suffix modules in preparation for * parsing the makefile(s) */ - Arch_Init(); Targ_Init(); Suff_Init(); |