arch.c revision 143656
1141104Sharti/*-
21590Srgrimes * Copyright (c) 1988, 1989, 1990, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes * Copyright (c) 1989 by Berkeley Softworks
51590Srgrimes * All rights reserved.
61590Srgrimes *
71590Srgrimes * This code is derived from software contributed to Berkeley by
81590Srgrimes * Adam de Boor.
91590Srgrimes *
101590Srgrimes * Redistribution and use in source and binary forms, with or without
111590Srgrimes * modification, are permitted provided that the following conditions
121590Srgrimes * are met:
131590Srgrimes * 1. Redistributions of source code must retain the above copyright
141590Srgrimes *    notice, this list of conditions and the following disclaimer.
151590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161590Srgrimes *    notice, this list of conditions and the following disclaimer in the
171590Srgrimes *    documentation and/or other materials provided with the distribution.
181590Srgrimes * 3. All advertising materials mentioning features or use of this software
191590Srgrimes *    must display the following acknowledgement:
201590Srgrimes *	This product includes software developed by the University of
211590Srgrimes *	California, Berkeley and its contributors.
221590Srgrimes * 4. Neither the name of the University nor the names of its contributors
231590Srgrimes *    may be used to endorse or promote products derived from this software
241590Srgrimes *    without specific prior written permission.
251590Srgrimes *
261590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
271590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
281590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
291590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
301590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
311590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
321590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
331590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
341590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
351590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
361590Srgrimes * SUCH DAMAGE.
3762833Swsanchez *
3862833Swsanchez * @(#)arch.c	8.2 (Berkeley) 1/2/94
391590Srgrimes */
401590Srgrimes
4162833Swsanchez#include <sys/cdefs.h>
4294587Sobrien__FBSDID("$FreeBSD: head/usr.bin/make/arch.c 143656 2005-03-15 15:05:14Z harti $");
431590Srgrimes
441590Srgrimes/*-
451590Srgrimes * arch.c --
461590Srgrimes *	Functions to manipulate libraries, archives and their members.
471590Srgrimes *
481590Srgrimes *	Once again, cacheing/hashing comes into play in the manipulation
491590Srgrimes * of archives. The first time an archive is referenced, all of its members'
501590Srgrimes * headers are read and hashed and the archive closed again. All hashed
511590Srgrimes * archives are kept on a list which is searched each time an archive member
521590Srgrimes * is referenced.
531590Srgrimes *
541590Srgrimes * The interface to this module is:
55141270Sharti *	Arch_ParseArchive	Given an archive specification, return a list
56141270Sharti *				of GNode's, one for each member in the spec.
57141270Sharti *				FAILURE is returned if the specification is
58141270Sharti *				invalid for some reason.
591590Srgrimes *
60141270Sharti *	Arch_Touch		Alter the modification time of the archive
61141270Sharti *				member described by the given node to be
62141270Sharti *				the current time.
631590Srgrimes *
64141270Sharti *	Arch_TouchLib		Update the modification time of the library
65141270Sharti *				described by the given node. This is special
66141270Sharti *				because it also updates the modification time
67141270Sharti *				of the library's table of contents.
681590Srgrimes *
69141270Sharti *	Arch_MTime		Find the modification time of a member of
70141270Sharti *				an archive *in the archive*. The time is also
71141270Sharti *				placed in the member's GNode. Returns the
72141270Sharti *				modification time.
731590Srgrimes *
74141270Sharti *	Arch_MemTime		Find the modification time of a member of
75141270Sharti *				an archive. Called when the member doesn't
76141270Sharti *				already exist. Looks in the archive for the
77141270Sharti *				modification time. Returns the modification
78141270Sharti *				time.
791590Srgrimes *
80141270Sharti *	Arch_FindLib		Search for a library along a path. The
81141270Sharti *				library name in the GNode should be in
82141270Sharti *				-l<name> format.
831590Srgrimes *
84141270Sharti *	Arch_LibOODate		Special function to decide if a library node
85141270Sharti *				is out-of-date.
861590Srgrimes *
87141270Sharti *	Arch_Init		Initialize this module.
881590Srgrimes */
891590Srgrimes
90141104Sharti#include <sys/param.h>
91141104Sharti#include <sys/types.h>
92141104Sharti#include <ar.h>
93141104Sharti#include <ctype.h>
94143656Sharti#include <errno.h>
95143656Sharti#include <inttypes.h>
96141104Sharti#include <regex.h>
97141104Sharti#include <stdlib.h>
98141104Sharti#include <stdio.h>
99141104Sharti#include <string.h>
100141104Sharti#include <utime.h>
1011590Srgrimes
102141104Sharti#include "arch.h"
103142457Sharti#include "buf.h"
104141104Sharti#include "config.h"
105141104Sharti#include "dir.h"
106141104Sharti#include "globals.h"
107141104Sharti#include "GNode.h"
108141104Sharti#include "hash.h"
109141104Sharti#include "make.h"
110141104Sharti#include "targ.h"
111141104Sharti#include "util.h"
112141104Sharti#include "var.h"
113141104Sharti
114138916Sharti/* Lst of archives we've already examined */
115138916Shartistatic Lst archives = Lst_Initializer(archives);
1161590Srgrimes
1171590Srgrimestypedef struct Arch {
118142173Sharti	char		*name;		/* Name of archive */
119142173Sharti
120142173Sharti	/*
121142173Sharti	 * All the members of the archive described
122142173Sharti	 * by <name, struct ar_hdr *> key/value pairs
123142173Sharti	 */
124142173Sharti	Hash_Table	members;
1251590Srgrimes} Arch;
1261590Srgrimes
127143656Sharti/* size of the name field in the archive member header */
128143656Sharti#define	AR_NAMSIZ	sizeof(((struct ar_hdr *)0)->ar_name)
1291590Srgrimes
130143656Sharti/*
131143656Sharti * This structure is used while reading/writing an archive
132143656Sharti */
133143656Shartistruct arfile {
134143656Sharti	FILE		*fp;		/* archive file */
135143656Sharti	char		*fname;		/* name of the file */
136143656Sharti	struct ar_hdr	hdr;		/* current header */
137143656Sharti	char		sname[AR_NAMSIZ + 1]; /* short name */
138143656Sharti	char		*member;	/* (long) member name */
139143656Sharti	size_t		mlen;		/* size of the above */
140143656Sharti	char		*nametab;	/* name table */
141143656Sharti	size_t		nametablen;	/* size of the table */
142143656Sharti	int64_t		time;		/* from ar_date */
143143656Sharti	uint64_t	size;		/* from ar_size */
144143656Sharti	off_t		pos;		/* header pos of current entry */
145143656Sharti};
146143656Sharti
147143656Sharti/*
148143656Sharti * Name of the symbol table. The original BSD used "__.SYMDEF". Rumours go
149143656Sharti * that this name may have a slash appended sometimes. Actually FreeBSD
150143656Sharti * uses "/" which probably came from SVR4.
151143656Sharti */
152143656Sharti#define	SVR4_RANLIBMAG	"/"
153143656Sharti#define	BSD_RANLIBMAG	"__.SYMDEF"
154143656Sharti
155143656Sharti/*
156143656Sharti * Name of the filename table. The 4.4BSD ar format did not use this, but
157143656Sharti * puts long filenames directly between the member header and the object
158143656Sharti * file.
159143656Sharti */
160143656Sharti#define	SVR4_NAMEMAG	"//"
161143656Sharti#define	BSD_NAMEMAG	"ARFILENAMES/"
162143656Sharti
163143656Sharti/*
164143656Sharti * 44BSD long filename key. Use a local define here instead of relying
165143656Sharti * on ar.h because we want this to continue working even when the
166143656Sharti * definition is removed from ar.h.
167143656Sharti */
168143656Sharti#define	BSD_EXT1	"#1/"
169143656Sharti#define	BSD_EXT1LEN	3
170143656Sharti
1711590Srgrimes/*-
1721590Srgrimes *-----------------------------------------------------------------------
1731590Srgrimes * Arch_ParseArchive --
1741590Srgrimes *	Parse the archive specification in the given line and find/create
1751590Srgrimes *	the nodes for the specified archive members, placing their nodes
176104696Sjmallett *	on the given list, given the pointer to the start of the
177104696Sjmallett *	specification, a Lst on which to place the nodes, and a context
178104696Sjmallett *	in which to expand variables.
1791590Srgrimes *
1801590Srgrimes * Results:
1811590Srgrimes *	SUCCESS if it was a valid specification. The linePtr is updated
1821590Srgrimes *	to point to the first non-space after the archive spec. The
1831590Srgrimes *	nodes for the members are placed on the given list.
1841590Srgrimes *
1851590Srgrimes * Side Effects:
1861590Srgrimes *	Some nodes may be created. The given list is extended.
1871590Srgrimes *
1881590Srgrimes *-----------------------------------------------------------------------
1891590Srgrimes */
1901590SrgrimesReturnStatus
191138512ShartiArch_ParseArchive(char **linePtr, Lst *nodeLst, GNode *ctxt)
1921590Srgrimes{
193142173Sharti	char	*cp;		/* Pointer into line */
194142173Sharti	GNode	*gn;		/* New node */
195142173Sharti	char	*libName;	/* Library-part of specification */
196142173Sharti	char	*memName;	/* Member-part of specification */
197142173Sharti	char	*nameBuf;	/* temporary place for node name */
198142173Sharti	char	saveChar;	/* Ending delimiter of member-name */
199142173Sharti	Boolean	subLibName;	/* TRUE if libName should have/had
200141270Sharti				 * variable substitution performed on it */
2011590Srgrimes
202142173Sharti	libName = *linePtr;
2038874Srgrimes
204142173Sharti	subLibName = FALSE;
2051590Srgrimes
206142173Sharti	for (cp = libName; *cp != '(' && *cp != '\0'; cp++) {
207142173Sharti		if (*cp == '$') {
208142173Sharti			/*
209142173Sharti			 * Variable spec, so call the Var module to parse the
210142173Sharti			 * puppy so we can safely advance beyond it...
211142173Sharti			 */
212142937Sharti			size_t	length = 0;
213142173Sharti			Boolean	freeIt;
214142173Sharti			char	*result;
2158874Srgrimes
216142173Sharti			result = Var_Parse(cp, ctxt, TRUE, &length, &freeIt);
217142173Sharti			if (result == var_Error) {
218142173Sharti				return (FAILURE);
219142173Sharti			}
220142173Sharti			subLibName = TRUE;
2218874Srgrimes
222142173Sharti			if (freeIt) {
223142173Sharti				free(result);
224142173Sharti			}
225142173Sharti			cp += length - 1;
226142173Sharti		}
2271590Srgrimes	}
2281590Srgrimes
229142173Sharti	*cp++ = '\0';
230142173Sharti	if (subLibName) {
231143656Sharti		libName = Buf_Peel(Var_Subst(NULL, libName, ctxt, TRUE));
232142173Sharti	}
2331590Srgrimes
234142173Sharti	for (;;) {
235142173Sharti		/*
236142173Sharti		 * First skip to the start of the member's name, mark that
237142173Sharti		 * place and skip to the end of it (either white-space or
238142173Sharti		 * a close paren).
239142173Sharti		 */
2401590Srgrimes
2411590Srgrimes		/*
242142173Sharti		 * TRUE if need to substitute in memName
2431590Srgrimes		 */
244142173Sharti		Boolean	doSubst = FALSE;
2451590Srgrimes
246142173Sharti		while (*cp != '\0' && *cp != ')' &&
247142173Sharti		    isspace((unsigned char)*cp)) {
248143105Sharti			cp++;
2491590Srgrimes		}
2501590Srgrimes
251142173Sharti		memName = cp;
252142173Sharti		while (*cp != '\0' && *cp != ')' &&
253142173Sharti		    !isspace((unsigned char)*cp)) {
254142173Sharti			if (*cp == '$') {
255142173Sharti				/*
256142173Sharti				 * Variable spec, so call the Var module to
257142173Sharti				 * parse the puppy so we can safely advance
258142173Sharti				 * beyond it...
259142173Sharti				 */
260142937Sharti				size_t	length = 0;
261142173Sharti				Boolean	freeIt;
262142173Sharti				char	*result;
263142173Sharti
264142173Sharti				result = Var_Parse(cp, ctxt, TRUE,
265142173Sharti				    &length, &freeIt);
266142173Sharti				if (result == var_Error) {
267142173Sharti					return (FAILURE);
268142173Sharti				}
269142173Sharti				doSubst = TRUE;
270142173Sharti
271142173Sharti				if (freeIt) {
272142173Sharti					free(result);
273142173Sharti				}
274142173Sharti				cp += length;
275142173Sharti			} else {
276142173Sharti				cp++;
277142173Sharti			}
2781590Srgrimes		}
2791590Srgrimes
280142173Sharti		/*
281142173Sharti		 * If the specification ends without a closing parenthesis,
282142173Sharti		 * chances are there's something wrong (like a missing
283142173Sharti		 * backslash), so it's better to return failure than allow
284142173Sharti		 * such things to happen
285142173Sharti		 */
286142173Sharti		if (*cp == '\0') {
287142173Sharti			printf("No closing parenthesis in archive "
288142173Sharti			    "specification\n");
289142173Sharti			return (FAILURE);
290142173Sharti		}
2911590Srgrimes
292142173Sharti		/*
293142173Sharti		 * If we didn't move anywhere, we must be done
294142173Sharti		 */
295142173Sharti		if (cp == memName) {
296142173Sharti			break;
297142173Sharti		}
2981590Srgrimes
299142173Sharti		saveChar = *cp;
300142173Sharti		*cp = '\0';
3011590Srgrimes
302142173Sharti		/*
303142173Sharti		 * XXX: This should be taken care of intelligently by
304142173Sharti		 * SuffExpandChildren, both for the archive and the member
305142173Sharti		 * portions.
306142173Sharti		 */
307142173Sharti		/*
308142173Sharti		 * If member contains variables, try and substitute for them.
309142173Sharti		 * This will slow down archive specs with dynamic sources, of
310142173Sharti		 * course, since we'll be (non-)substituting them three times,
311142173Sharti		 * but them's the breaks -- we need to do this since
312142173Sharti		 * SuffExpandChildren calls us, otherwise we could assume the
313142173Sharti		 * thing would be taken care of later.
314142173Sharti		 */
315142173Sharti		if (doSubst) {
316142173Sharti			char	*buf;
317142173Sharti			char	*sacrifice;
318142173Sharti			char	*oldMemName = memName;
319142173Sharti			size_t	sz;
320142457Sharti			Buffer	*buf1;
3218874Srgrimes
322142173Sharti			/*
323142173Sharti			 * Now form an archive spec and recurse to deal with
324142173Sharti			 * nested variables and multi-word variable values....
325142173Sharti			 * The results are just placed at the end of the
326142173Sharti			 * nodeLst we're returning.
327142173Sharti			 */
328142457Sharti			buf1 = Var_Subst(NULL, memName, ctxt, TRUE);
329142457Sharti			memName = Buf_GetAll(buf1, NULL);
3301590Srgrimes
331142173Sharti			sz = strlen(memName) + strlen(libName) + 3;
332142457Sharti			buf = emalloc(sz);
3331590Srgrimes
334142173Sharti			snprintf(buf, sz, "%s(%s)", libName, memName);
33569390Swill
336142457Sharti			sacrifice = buf;
337142457Sharti
338142173Sharti			if (strchr(memName, '$') &&
339142173Sharti			    strcmp(memName, oldMemName) == 0) {
340142173Sharti				/*
341142173Sharti				 * Must contain dynamic sources, so we can't
342142173Sharti				 * deal with it now.
343142173Sharti				 * Just create an ARCHV node for the thing and
344142173Sharti				 * let SuffExpandChildren handle it...
345142173Sharti				 */
346142173Sharti				gn = Targ_FindNode(buf, TARG_CREATE);
3471590Srgrimes
348142173Sharti				if (gn == NULL) {
349142173Sharti					free(buf);
350142457Sharti					Buf_Destroy(buf1, FALSE);
351142173Sharti					return (FAILURE);
352142173Sharti				}
353142173Sharti				gn->type |= OP_ARCHV;
354142173Sharti				Lst_AtEnd(nodeLst, (void *)gn);
355142173Sharti			} else if (Arch_ParseArchive(&sacrifice, nodeLst,
356142173Sharti			    ctxt) != SUCCESS) {
357142173Sharti				/*
358142173Sharti				 * Error in nested call -- free buffer and
359142173Sharti				 * return FAILURE ourselves.
360142173Sharti				 */
361142173Sharti				free(buf);
362142457Sharti				Buf_Destroy(buf1, FALSE);
363142173Sharti				return (FAILURE);
364142173Sharti			}
365142457Sharti
366142457Sharti			/* Free buffer and continue with our work. */
367142173Sharti			free(buf);
368142457Sharti			Buf_Destroy(buf1, FALSE);
369142457Sharti
370142173Sharti		} else if (Dir_HasWildcards(memName)) {
371142173Sharti			Lst	members = Lst_Initializer(members);
372142173Sharti			char	*member;
373142173Sharti			size_t	sz = MAXPATHLEN;
374142173Sharti			size_t	nsz;
375138196Sharti
376142173Sharti			nameBuf = emalloc(sz);
3771590Srgrimes
378142173Sharti			Dir_Expand(memName, &dirSearchPath, &members);
379142173Sharti			while (!Lst_IsEmpty(&members)) {
380142173Sharti				member = Lst_DeQueue(&members);
381142173Sharti				nsz = strlen(libName) + strlen(member) + 3;
382142173Sharti				if (nsz > sz) {
383142173Sharti					sz = nsz * 2;
384142173Sharti					nameBuf = erealloc(nameBuf, sz);
385142173Sharti				}
3868874Srgrimes
387142173Sharti				snprintf(nameBuf, sz, "%s(%s)",
388142173Sharti				    libName, member);
389142173Sharti				free(member);
390142173Sharti				gn = Targ_FindNode(nameBuf, TARG_CREATE);
391142173Sharti				if (gn == NULL) {
392142173Sharti					free(nameBuf);
393142173Sharti					/* XXXHB Lst_Destroy(&members) */
394142173Sharti					return (FAILURE);
395142173Sharti				}
396142173Sharti				/*
397142173Sharti				 * We've found the node, but have to make sure
398142173Sharti				 * the rest of the world knows it's an archive
399142173Sharti				 * member, without having to constantly check
400142173Sharti				 * for parentheses, so we type the thing with
401142173Sharti				 * the OP_ARCHV bit before we place it on the
402142173Sharti				 * end of the provided list.
403142173Sharti				 */
404142173Sharti				gn->type |= OP_ARCHV;
405142173Sharti				Lst_AtEnd(nodeLst, gn);
406142173Sharti			}
407142173Sharti			free(nameBuf);
4081590Srgrimes		} else {
409142173Sharti			size_t	sz = strlen(libName) + strlen(memName) + 3;
410142173Sharti
411142173Sharti			nameBuf = emalloc(sz);
412142173Sharti			snprintf(nameBuf, sz, "%s(%s)", libName, memName);
413142173Sharti			gn = Targ_FindNode(nameBuf, TARG_CREATE);
414142173Sharti			free(nameBuf);
415142173Sharti			if (gn == NULL) {
416142173Sharti				return (FAILURE);
417142173Sharti			}
418142173Sharti			/*
419142173Sharti			 * We've found the node, but have to make sure the
420142173Sharti			 * rest of the world knows it's an archive member,
421142173Sharti			 * without having to constantly check for parentheses,
422142173Sharti			 * so we type the thing with the OP_ARCHV bit before
423142173Sharti			 * we place it on the end of the provided list.
424142173Sharti			 */
425142173Sharti			gn->type |= OP_ARCHV;
426142173Sharti			Lst_AtEnd(nodeLst, gn);
4271590Srgrimes		}
428142173Sharti		if (doSubst) {
429142173Sharti			free(memName);
430142173Sharti		}
431142173Sharti
432142173Sharti		*cp = saveChar;
4331590Srgrimes	}
434142173Sharti
435142173Sharti	/*
436142173Sharti	 * If substituted libName, free it now, since we need it no longer.
437142173Sharti	 */
438142173Sharti	if (subLibName) {
439142173Sharti		free(libName);
4401590Srgrimes	}
4418874Srgrimes
442142173Sharti	/*
443142173Sharti	 * We promised the pointer would be set up at the next non-space, so
444142173Sharti	 * we must advance cp there before setting *linePtr... (note that on
445142173Sharti	 * entrance to the loop, cp is guaranteed to point at a ')')
446142173Sharti	 */
447142173Sharti	do {
448142173Sharti		cp++;
449142173Sharti	} while (*cp != '\0' && isspace((unsigned char)*cp));
4501590Srgrimes
451142173Sharti	*linePtr = cp;
452142173Sharti	return (SUCCESS);
4531590Srgrimes}
4541590Srgrimes
455143656Sharti/*
456143656Sharti * Close an archive file an free all resources
4571590Srgrimes */
458143656Shartistatic void
459143656ShartiArchArchiveClose(struct arfile *ar)
4601590Srgrimes{
461138561Sharti
462143656Sharti	if (ar->nametab != NULL)
463143656Sharti		free(ar->nametab);
464143656Sharti	free(ar->member);
465143656Sharti	if (ar->fp != NULL) {
466143656Sharti		if (fclose(ar->fp) == EOF)
467143656Sharti			DEBUGM(ARCH, ("%s: close error", ar->fname));
468143656Sharti	}
469143656Sharti	free(ar->fname);
470143656Sharti	free(ar);
4711590Srgrimes}
4721590Srgrimes
473143656Sharti/*
474143656Sharti * Open an archive file.
4751590Srgrimes */
476143656Shartistatic struct arfile *
477143656ShartiArchArchiveOpen(const char *archive, const char *mode)
4781590Srgrimes{
479143656Sharti	struct arfile *ar;
480143656Sharti	char	magic[SARMAG];
4811590Srgrimes
482143656Sharti	ar = emalloc(sizeof(*ar));
483143656Sharti	ar->fname = estrdup(archive);
484143656Sharti	ar->mlen = 100;
485143656Sharti	ar->member = emalloc(ar->mlen);
486143656Sharti	ar->nametab = NULL;
487143656Sharti	ar->nametablen = 0;
488143656Sharti
489143656Sharti	if ((ar->fp = fopen(ar->fname, mode)) == NULL) {
490143656Sharti		DEBUGM(ARCH, ("%s", ar->fname));
491143656Sharti		ArchArchiveClose(ar);
492142173Sharti		return (NULL);
493142173Sharti	}
4941590Srgrimes
495143656Sharti	/* read MAGIC */
496143656Sharti	if (fread(magic, SARMAG, 1, ar->fp) != 1 ||
497143105Sharti	    strncmp(magic, ARMAG, SARMAG) != 0) {
498143656Sharti		DEBUGF(ARCH, ("%s: bad archive magic\n", ar->fname));
499143656Sharti		ArchArchiveClose(ar);
500142173Sharti		return (NULL);
501142165Sharti	}
5025814Sjkh
503143656Sharti	ar->pos = 0;
504143656Sharti	return (ar);
505143656Sharti}
506143656Sharti
507143656Sharti#define	MMAX(A, B)	((A) > (B) ? (A) : (B))
508143656Sharti
509143656Sharti/*
510143656Sharti * Read the next header from the archive. The return value will be +1 if
511143656Sharti * the header is read successfully, 0 on EOF and -1 if an error happend.
512143656Sharti * On a successful return sname contains the truncated member name and
513143656Sharti * member the full name. hdr contains the member header. For the symbol table
514143656Sharti * names of length 0 are returned. The entry for the file name table is never
515143656Sharti * returned.
516143656Sharti */
517143656Shartistatic int
518143656ShartiArchArchiveNext(struct arfile *ar)
519143656Sharti{
520143656Sharti	char	*end;
521143656Sharti	int	have_long_name;
522143656Sharti	u_long	offs;
523143656Sharti	char	*ptr;
524143656Sharti	size_t	ret;
525143656Sharti	char	buf[MMAX(sizeof(ar->hdr.ar_size), sizeof(ar->hdr.ar_date)) + 1];
526143656Sharti
527143656Sharti  next:
5281590Srgrimes	/*
529143656Sharti	 * Seek to the next header.
530142297Sharti	 */
531143656Sharti	if (ar->pos == 0) {
532143656Sharti		ar->pos = SARMAG;
533143656Sharti	} else {
534143656Sharti		ar->pos += sizeof(ar->hdr) + ar->size;
535143656Sharti		if (ar->size % 2 == 1)
536143656Sharti			ar->pos++;
5371590Srgrimes	}
538143656Sharti
539143656Sharti	if (fseeko(ar->fp, ar->pos, SEEK_SET) == -1) {
540143656Sharti		DEBUGM(ARCH, ("%s: cannot seek", ar->fname));
541143656Sharti		return (-1);
542142173Sharti	}
5431590Srgrimes
544143656Sharti	/*
545143656Sharti	 * Read next member header
546143656Sharti	 */
547143656Sharti	ret = fread(&ar->hdr, sizeof(ar->hdr), 1, ar->fp);
548143656Sharti	if (ret != 1) {
549143656Sharti		if (ferror(ar->fp)) {
550143656Sharti			DEBUGM(ARCH, ("%s", ar->fname));
551143656Sharti			return (-1);
552142173Sharti		}
553143656Sharti		return (0);
554143656Sharti	}
555143656Sharti	if (strncmp(ar->hdr.ar_fmag, ARFMAG, sizeof(ar->hdr.ar_fmag)) != 0) {
556143656Sharti		DEBUGF(ARCH, ("%s: bad entry magic\n", ar->fname));
557143656Sharti		return (-1);
558143656Sharti	}
5598874Srgrimes
560143656Sharti	/*
561143656Sharti	 * looks like a member - get name by stripping trailing spaces
562143656Sharti	 * and NUL terminating.
563143656Sharti	 */
564143656Sharti	strncpy(ar->sname, ar->hdr.ar_name, AR_NAMSIZ);
565143656Sharti	ar->sname[AR_NAMSIZ] = '\0';
566143656Sharti	for (ptr = ar->sname + AR_NAMSIZ; ptr > ar->sname; ptr--)
567143656Sharti		if (ptr[-1] != ' ')
568143656Sharti			break;
569143656Sharti
570143656Sharti	*ptr = '\0';
571143656Sharti
572143656Sharti	/*
573143656Sharti	 * Parse the size. All entries need to have a size. Be careful
574143656Sharti	 * to not allow buffer overruns.
575143656Sharti	 */
576143656Sharti	strncpy(buf, ar->hdr.ar_size, sizeof(ar->hdr.ar_size));
577143656Sharti	buf[sizeof(ar->hdr.ar_size)] = '\0';
578143656Sharti
579143656Sharti	errno = 0;
580143656Sharti	ar->size = strtoumax(buf, &end, 10);
581143656Sharti	if (errno != 0 || strspn(end, " ") != strlen(end)) {
582143656Sharti		DEBUGF(ARCH, ("bad size format in archive '%s'\n", buf));
583143656Sharti		return (-1);
584143656Sharti	}
585143656Sharti
586143656Sharti	/*
587143656Sharti	 * Look for the extended name table. Do this before parsing
588143656Sharti	 * the date because this table doesn't need a date.
589143656Sharti	 */
590143656Sharti	if (strcmp(ar->sname, BSD_NAMEMAG) == 0 ||
591143656Sharti	    strcmp(ar->sname, SVR4_NAMEMAG) == 0) {
592143656Sharti		/* filename table - read it in */
593143656Sharti		ar->nametablen = ar->size;
594143656Sharti		ar->nametab = emalloc(ar->nametablen);
595143656Sharti
596143656Sharti		ret = fread(ar->nametab, 1, ar->nametablen, ar->fp);
597143656Sharti		if (ret != ar->nametablen) {
598143656Sharti			DEBUGM(ARCH, ("%s: cannot read nametab", ar->fname));
599143656Sharti			return (-1);
600142173Sharti		}
601143656Sharti
60218730Ssteve		/*
603143656Sharti		 * NUL terminate the entries. Entries are \n terminated
604143656Sharti		 * and may have a trailing / or \.
60518730Ssteve		 */
606143656Sharti		ptr = ar->nametab;
607143656Sharti		while (ptr < ar->nametab + ar->nametablen) {
608143656Sharti			if (*ptr == '\n') {
609143656Sharti				if (ptr[-1] == '/' || ptr[-1] == '\\')
610143656Sharti					ptr[-1] = '\0';
611143656Sharti				*ptr = '\0';
612142173Sharti			}
613143656Sharti			ptr++;
61418730Ssteve		}
615143656Sharti
616143656Sharti		/* get next archive entry */
617143656Sharti		goto next;
6181590Srgrimes	}
6191590Srgrimes
620142173Sharti	/*
621143656Sharti	 * Now parse the modification date. Be careful to not overrun
622143656Sharti	 * buffers.
623142297Sharti	 */
624143656Sharti	strncpy(buf, ar->hdr.ar_date, sizeof(ar->hdr.ar_date));
625143656Sharti	buf[sizeof(ar->hdr.ar_date)] = '\0';
626143656Sharti
627143656Sharti	errno = 0;
628143656Sharti	ar->time = (int64_t)strtoll(buf, &end, 10);
629143656Sharti	if (errno != 0 || strspn(end, " ") != strlen(end)) {
630143656Sharti		DEBUGF(ARCH, ("bad date format in archive '%s'\n", buf));
631143656Sharti		return (-1);
632143656Sharti	}
633143656Sharti
634143656Sharti	/*
635143656Sharti	 * Now check for the symbol table. This should really be the first
636143656Sharti	 * entry, but we don't check this.
637143656Sharti	 */
638143656Sharti	if (strcmp(ar->sname, BSD_RANLIBMAG) == 0 ||
639143656Sharti	    strcmp(ar->sname, SVR4_RANLIBMAG) == 0) {
640143656Sharti		/* symbol table - return a zero length name */
641143656Sharti		ar->member[0] = '\0';
642143656Sharti		ar->sname[0] = '\0';
643143656Sharti		return (1);
644143656Sharti	}
645143656Sharti
646143656Sharti	have_long_name = 0;
647143656Sharti
648143656Sharti	/*
649143656Sharti	 * Look whether this is a long name. There are several variants
650143656Sharti	 * of long names:
651143656Sharti	 *	"#1/12           "	- 12 length of following filename
652143656Sharti	 *	"/17             "	- index into name table
653143656Sharti	 *	" 17             "	- index into name table
654143656Sharti	 * Note that in the last case we must also check that there is no
655143656Sharti	 * slash in the name because of filenames with leading spaces:
656143656Sharti	 *	" 777.o/           "	- filename 777.o
657143656Sharti	 */
658143656Sharti	if (ar->sname[0] == '/' || (ar->sname[0] == ' ' &&
659143656Sharti	    strchr(ar->sname, '/') == NULL)) {
660143656Sharti		/* SVR4 extended name */
661143656Sharti		errno = 0;
662143656Sharti		offs = strtoul(ar->sname + 1, &end, 10);
663143656Sharti		if (errno != 0 || *end != '\0' || offs >= ar->nametablen ||
664143656Sharti		    end == ar->sname + 1) {
665143656Sharti			DEBUGF(ARCH, ("bad extended name\n"));
666143656Sharti			return (-1);
667143656Sharti		}
668143656Sharti
669143656Sharti		/* fetch the name */
670143656Sharti		if (ar->mlen <= strlen(ar->nametab + offs)) {
671143656Sharti			ar->mlen = strlen(ar->nametab + offs) + 1;
672143656Sharti			ar->member = erealloc(ar->member, ar->mlen);
673143656Sharti		}
674143656Sharti		strcpy(ar->member, ar->nametab + offs);
675143656Sharti
676143656Sharti		have_long_name = 1;
677143656Sharti
678143656Sharti	} else if (strncmp(ar->sname, BSD_EXT1, BSD_EXT1LEN) == 0 &&
679143656Sharti	    isdigit(ar->sname[BSD_EXT1LEN])) {
680143656Sharti		/* BSD4.4 extended name */
681143656Sharti		errno = 0;
682143656Sharti		offs = strtoul(ar->sname + BSD_EXT1LEN, &end, 10);
683143656Sharti		if (errno != 0 || *end != '\0' ||
684143656Sharti		    end == ar->sname + BSD_EXT1LEN) {
685143656Sharti			DEBUGF(ARCH, ("%s: bad extended name\n", ar->fname));
686143656Sharti			return (-1);
687143656Sharti		}
688143656Sharti
689143656Sharti		/* read it from the archive */
690143656Sharti		if (ar->mlen <= offs) {
691143656Sharti			ar->mlen = offs + 1;
692143656Sharti			ar->member = erealloc(ar->member, ar->mlen);
693143656Sharti		}
694143656Sharti		ret = fread(ar->member, 1, offs, ar->fp);
695143656Sharti		if (ret != offs) {
696143656Sharti			DEBUGM(ARCH, ("%s: reading extended name", ar->fname));
697143656Sharti			return (-1);
698143656Sharti		}
699143656Sharti		ar->member[offs] = '\0';
700143656Sharti
701143656Sharti		have_long_name = 1;
702143656Sharti	}
703143656Sharti
704143656Sharti	/*
705143656Sharti	 * Now remove the trailing slash that Svr4 puts at
706143656Sharti	 * the end of the member name to support trailing spaces in names.
707143656Sharti	 */
708143656Sharti	if (ptr > ar->sname && ptr[-1] == '/')
709143656Sharti		*--ptr = '\0';
710143656Sharti
711143656Sharti	if (!have_long_name) {
712143656Sharti		if (strlen(ar->sname) >= ar->mlen) {
713143656Sharti			ar->mlen = strlen(ar->sname) + 1;
714143656Sharti			ar->member = erealloc(ar->member, ar->mlen);
715143656Sharti		}
716143656Sharti		strcpy(ar->member, ar->sname);
717143656Sharti	}
718143656Sharti
719143656Sharti	return (1);
7201590Srgrimes}
7211590Srgrimes
722143656Sharti/*
723143656Sharti * Touch the current archive member by writing a new header with an
724143656Sharti * updated timestamp. The return value is 0 for success and -1 for errors.
725143656Sharti */
726143656Shartistatic int
727143656ShartiArchArchiveTouch(struct arfile *ar, int64_t ts)
728143656Sharti{
729143656Sharti
730143656Sharti	/* seek to our header */
731143656Sharti	if (fseeko(ar->fp, ar->pos, SEEK_SET) == -1) {
732143656Sharti		DEBUGM(ARCH, ("%s: cannot seek", ar->fname));
733143656Sharti		return (-1);
734143656Sharti	}
735143656Sharti
736143656Sharti	/*
737143656Sharti	 * change timestamp, be sure to not NUL-terminated it, but
738143656Sharti	 * to fill with spaces.
739143656Sharti	 */
740143656Sharti	snprintf(ar->hdr.ar_date, sizeof(ar->hdr.ar_date), "%lld", ts);
741143656Sharti	memset(ar->hdr.ar_date + strlen(ar->hdr.ar_date),
742143656Sharti	    ' ', sizeof(ar->hdr.ar_date) - strlen(ar->hdr.ar_date));
743143656Sharti
744143656Sharti	if (fwrite(&ar->hdr, sizeof(ar->hdr), 1, ar->fp) != 1) {
745143656Sharti		DEBUGM(ARCH, ("%s: cannot touch", ar->fname));
746143656Sharti		return (-1);
747143656Sharti	}
748143656Sharti	return (0);
749143656Sharti}
750143656Sharti
7511590Srgrimes/*-
7521590Srgrimes *-----------------------------------------------------------------------
753143656Sharti * ArchFindMember --
754143656Sharti *	Locate a member of an archive, given the path of the archive and
755143656Sharti *	the path of the desired member. If the archive is to be modified,
756143656Sharti *	the mode should be "r+", if not, it should be "r".  The archive
757143656Sharti *	file is returned positioned at the correct header.
75818730Ssteve *
75918730Ssteve * Results:
760143656Sharti *	A struct arfile *, opened for reading and, possibly writing,
761143656Sharti *	positioned at the member's header, or NULL if the member was
762143656Sharti *	nonexistent.
76318730Ssteve *
76418730Ssteve *-----------------------------------------------------------------------
76518730Ssteve */
766143656Shartistatic struct arfile *
767143656ShartiArchFindMember(const char *archive, const char *member, const char *mode)
76818730Ssteve{
769143656Sharti	struct arfile	*ar;
770143656Sharti	const char	*cp;	/* Useful character pointer */
77118730Ssteve
772143656Sharti	if ((ar = ArchArchiveOpen(archive, mode)) == NULL)
773143656Sharti		return (NULL);
77418730Ssteve
775143656Sharti	/*
776143656Sharti	 * Because of space constraints and similar things, files are archived
777143656Sharti	 * using their final path components, not the entire thing, so we need
778143656Sharti	 * to point 'member' to the final component, if there is one, to make
779143656Sharti	 * the comparisons easier...
780143656Sharti	 */
781143656Sharti	if (member != NULL) {
782143656Sharti		cp = strrchr(member, '/');
783143656Sharti		if (cp != NULL) {
784143656Sharti			member = cp + 1;
785142173Sharti		}
786143656Sharti	}
78718730Ssteve
788143656Sharti	while (ArchArchiveNext(ar) > 0) {
789142173Sharti		/*
790143656Sharti		 * When comparing there are actually three cases:
791143656Sharti		 * (1) the name fits into the limit og af_name,
792143656Sharti		 * (2) the name is longer and the archive supports long names,
793143656Sharti		 * (3) the name is longer and the archive doesn't support long
794143656Sharti		 * names.
795143656Sharti		 * Because we don't know whether the archive supports long
796143656Sharti		 * names or not we need to be carefull.
797142297Sharti		 */
798143656Sharti		if (member == NULL) {
799143656Sharti			/* special case - symbol table */
800143656Sharti			if (ar->member[0] == '\0')
801143656Sharti				return (ar);
802143656Sharti		} else if (strlen(member) <= AR_NAMSIZ) {
803143656Sharti			/* case (1) */
804143656Sharti			if (strcmp(ar->member, member) == 0)
805143656Sharti				return (ar);
806143656Sharti		} else if (strcmp(ar->member, member) == 0) {
807143656Sharti			/* case (3) */
808143656Sharti			return (ar);
809143656Sharti		} else {
810143656Sharti			/* case (2) */
811143656Sharti			if (strlen(ar->member) == AR_NAMSIZ &&
812143656Sharti			    strncmp(member, ar->member, AR_NAMSIZ) == 0)
813143656Sharti				return (ar);
814142173Sharti		}
815142173Sharti	}
81618730Ssteve
817143656Sharti	/* not found */
818143656Sharti	ArchArchiveClose(ar);
819143656Sharti	return (NULL);
82018730Ssteve}
82118730Ssteve
82218730Ssteve/*-
82318730Ssteve *-----------------------------------------------------------------------
824142173Sharti * ArchStatMember --
8251590Srgrimes *	Locate a member of an archive, given the path of the archive and
826142173Sharti *	the path of the desired member, and a boolean representing whether
827142173Sharti *	or not the archive should be hashed (if not already hashed).
8281590Srgrimes *
8291590Srgrimes * Results:
830142173Sharti *	A pointer to the current struct ar_hdr structure for the member. Note
831142173Sharti *	That no position is returned, so this is not useful for touching
832142173Sharti *	archive members. This is mostly because we have no assurances that
833142173Sharti *	The archive will remain constant after we read all the headers, so
834142173Sharti *	there's not much point in remembering the position...
8351590Srgrimes *
8361590Srgrimes * Side Effects:
8371590Srgrimes *
8381590Srgrimes *-----------------------------------------------------------------------
8391590Srgrimes */
840143656Shartistatic int64_t
841142173ShartiArchStatMember(const char *archive, const char *member, Boolean hash)
8421590Srgrimes{
843143656Sharti	struct arfile	*arf;
844143656Sharti	int64_t		ret;
845143656Sharti	int		t;
846142173Sharti	char		*cp;	/* Useful character pointer */
847142173Sharti	LstNode		*ln;	/* Lst member containing archive descriptor */
848142173Sharti	Arch		*ar;	/* Archive descriptor */
849142173Sharti	Hash_Entry	*he;	/* Entry containing member's description */
850143656Sharti	char		copy[AR_NAMSIZ + 1];
8511590Srgrimes
852142173Sharti	/*
853142297Sharti	 * Because of space constraints and similar things, files are archived
854142297Sharti	 * using their final path components, not the entire thing, so we need
855142297Sharti	 * to point 'member' to the final component, if there is one, to make
856142297Sharti	 * the comparisons easier...
857142297Sharti	 */
858143656Sharti	if (member != NULL) {
859143656Sharti		cp = strrchr(member, '/');
860143656Sharti		if (cp != NULL)
861143656Sharti			member = cp + 1;
862143656Sharti	}
8638874Srgrimes
864143656Sharti	LST_FOREACH(ln, &archives) {
865143656Sharti		if (strcmp(archive, ((const Arch *)Lst_Datum(ln))->name) == 0)
866143656Sharti			break;
867143656Sharti	}
868142173Sharti	if (ln != NULL) {
869143656Sharti		/* found archive */
870142173Sharti		ar = Lst_Datum(ln);
8718874Srgrimes
872143656Sharti	} else {
873143656Sharti		if (!hash) {
874142173Sharti			/*
875143656Sharti			 * Caller doesn't want the thing hashed, just use
876143656Sharti			 * ArchFindMember to read the header for the member
877143656Sharti			 * out and close down the stream again.
878142173Sharti			 */
879143656Sharti			arf = ArchFindMember(archive, member, "r");
880143656Sharti			if (arf == NULL) {
881143656Sharti				return (INT64_MIN);
882143656Sharti			}
883143656Sharti			ret = arf->time;
884143656Sharti			ArchArchiveClose(arf);
885143656Sharti			return (ret);
886142173Sharti		}
887143656Sharti
8885814Sjkh		/*
889143656Sharti		 * We don't have this archive on the list yet, so we want to
890143656Sharti		 * find out everything that's in it and cache it so we can get
891143656Sharti		 * at it quickly.
8925814Sjkh		 */
893143656Sharti		arf = ArchArchiveOpen(archive, "r");
894143656Sharti		if (arf == NULL) {
895143656Sharti			return (INT64_MIN);
896142173Sharti		}
8975814Sjkh
898143656Sharti		/* create archive data structure */
899143656Sharti		ar = emalloc(sizeof(*ar));
900143656Sharti		ar->name = estrdup(archive);
901143656Sharti		Hash_InitTable(&ar->members, -1);
902142173Sharti
903143656Sharti		while ((t = ArchArchiveNext(arf)) > 0) {
904143656Sharti			he = Hash_CreateEntry(&ar->members, arf->member, NULL);
905143656Sharti			Hash_SetValue(he, emalloc(sizeof(int64_t)));
906143656Sharti			*(int64_t *)Hash_GetValue(he) = arf->time;
9075814Sjkh		}
908142173Sharti
909143656Sharti		ArchArchiveClose(arf);
910142173Sharti
911143656Sharti		if (t < 0) {
912143656Sharti			/* error happend - throw away everything */
913143656Sharti			Hash_DeleteTable(&ar->members);
914143656Sharti			free(ar->name);
915143656Sharti			free(ar);
916143656Sharti			return (INT64_MIN);
9175814Sjkh		}
918142173Sharti
919143656Sharti		Lst_AtEnd(&archives, ar);
9201590Srgrimes	}
9211590Srgrimes
922142173Sharti	/*
923142173Sharti	 * Now that the archive has been read and cached, we can look into
924142173Sharti	 * the hash table to find the desired member's header.
925142173Sharti	 */
926142173Sharti	he = Hash_FindEntry(&ar->members, member);
927143656Sharti	if (he != NULL)
928143656Sharti		return (*(int64_t *)Hash_GetValue (he));
929142173Sharti
930143656Sharti	if (member != NULL && strlen(member) > AR_NAMSIZ) {
931143656Sharti		/* Try truncated name */
932143656Sharti		strncpy(copy, member, AR_NAMSIZ);
933143656Sharti		copy[AR_NAMSIZ] = '\0';
934143656Sharti
935143656Sharti		if ((he = Hash_FindEntry(&ar->members, copy)) != NULL)
936143656Sharti			return (*(int64_t *)Hash_GetValue(he));
937142173Sharti	}
938142173Sharti
939143656Sharti	return (INT64_MIN);
9401590Srgrimes}
9411590Srgrimes
9421590Srgrimes/*-
9431590Srgrimes *-----------------------------------------------------------------------
9441590Srgrimes * Arch_Touch --
9451590Srgrimes *	Touch a member of an archive.
9461590Srgrimes *
9471590Srgrimes * Results:
9481590Srgrimes *	The 'time' field of the member's header is updated.
9491590Srgrimes *
9501590Srgrimes * Side Effects:
9511590Srgrimes *	The modification time of the entire archive is also changed.
9521590Srgrimes *	For a library, this could necessitate the re-ranlib'ing of the
9531590Srgrimes *	whole thing.
9541590Srgrimes *
9551590Srgrimes *-----------------------------------------------------------------------
9561590Srgrimes */
9571590Srgrimesvoid
958138232ShartiArch_Touch(GNode *gn)
9591590Srgrimes{
960143656Sharti	struct arfile	*ar;
961142173Sharti	char		*p1, *p2;
9621590Srgrimes
963143656Sharti	ar = ArchFindMember(Var_Value(ARCHIVE, gn, &p1),
964143656Sharti	    Var_Value(TARGET, gn, &p2), "r+");
965142173Sharti	free(p1);
966142173Sharti	free(p2);
9671590Srgrimes
968143656Sharti	if (ar != NULL) {
969143656Sharti		ArchArchiveTouch(ar, (int64_t)now);
970143656Sharti		ArchArchiveClose(ar);
971142173Sharti	}
9721590Srgrimes}
9731590Srgrimes
9741590Srgrimes/*-
9751590Srgrimes *-----------------------------------------------------------------------
9761590Srgrimes * Arch_TouchLib --
9771590Srgrimes *	Given a node which represents a library, touch the thing, making
9781590Srgrimes *	sure that the table of contents also is touched.
9791590Srgrimes *
9801590Srgrimes * Results:
9811590Srgrimes *	None.
9821590Srgrimes *
9831590Srgrimes * Side Effects:
9841590Srgrimes *	Both the modification time of the library and of the RANLIBMAG
9851590Srgrimes *	member are set to 'now'.
9861590Srgrimes *
9871590Srgrimes *-----------------------------------------------------------------------
9881590Srgrimes */
9891590Srgrimesvoid
990138232ShartiArch_TouchLib(GNode *gn)
9911590Srgrimes{
992143656Sharti	struct arfile	*ar;	/* Open archive */
993142173Sharti	struct utimbuf	times;	/* Times for utime() call */
9941590Srgrimes
995143656Sharti	ar = ArchFindMember(gn->path, NULL, "r+");
996143656Sharti	if (ar != NULL) {
997143656Sharti		ArchArchiveTouch(ar, (int64_t)now);
998143656Sharti		ArchArchiveClose(ar);
9991590Srgrimes
1000142173Sharti		times.actime = times.modtime = now;
1001142173Sharti		utime(gn->path, &times);
1002142173Sharti	}
10031590Srgrimes}
10041590Srgrimes
10051590Srgrimes/*-
10061590Srgrimes *-----------------------------------------------------------------------
10071590Srgrimes * Arch_MTime --
1008104696Sjmallett *	Return the modification time of a member of an archive, given its
1009104696Sjmallett *	name.
10101590Srgrimes *
10111590Srgrimes * Results:
1012138232Sharti *	The modification time(seconds).
1013142173Sharti *	XXXHB this should be a long.
10141590Srgrimes *
10151590Srgrimes * Side Effects:
10161590Srgrimes *	The mtime field of the given node is filled in with the value
10171590Srgrimes *	returned by the function.
10181590Srgrimes *
10191590Srgrimes *-----------------------------------------------------------------------
10201590Srgrimes */
10211590Srgrimesint
1022104696SjmallettArch_MTime(GNode *gn)
10231590Srgrimes{
1024143656Sharti	int64_t	mtime;
1025143656Sharti	char	*p1, *p2;
10261590Srgrimes
1027143656Sharti	mtime = ArchStatMember(Var_Value(ARCHIVE, gn, &p1),
1028142173Sharti	    Var_Value(TARGET, gn, &p2), TRUE);
1029142173Sharti	free(p1);
1030142173Sharti	free(p2);
10315814Sjkh
1032143656Sharti	if (mtime == INT_MIN) {
1033143656Sharti		mtime = 0;
1034142173Sharti	}
1035143656Sharti	gn->mtime = (int)mtime;			/* XXX */
1036143656Sharti	return (gn->mtime);
10371590Srgrimes}
10381590Srgrimes
10391590Srgrimes/*-
10401590Srgrimes *-----------------------------------------------------------------------
10411590Srgrimes * Arch_MemMTime --
10421590Srgrimes *	Given a non-existent archive member's node, get its modification
10431590Srgrimes *	time from its archived form, if it exists.
10441590Srgrimes *
10451590Srgrimes * Results:
10461590Srgrimes *	The modification time.
10471590Srgrimes *
10481590Srgrimes * Side Effects:
10491590Srgrimes *	The mtime field is filled in.
10501590Srgrimes *
10511590Srgrimes *-----------------------------------------------------------------------
10521590Srgrimes */
10531590Srgrimesint
1054138232ShartiArch_MemMTime(GNode *gn)
10551590Srgrimes{
1056142173Sharti	LstNode	*ln;
1057142173Sharti	GNode	*pgn;
1058142173Sharti	char	*nameStart;
1059142173Sharti	char	*nameEnd;
10601590Srgrimes
1061142173Sharti	for (ln = Lst_First(&gn->parents); ln != NULL; ln = Lst_Succ(ln)) {
1062142173Sharti		pgn = Lst_Datum(ln);
10631590Srgrimes
1064142173Sharti		if (pgn->type & OP_ARCHV) {
1065142173Sharti			/*
1066142173Sharti			 * If the parent is an archive specification and is
1067142173Sharti			 * being made and its member's name matches the name of
1068142173Sharti			 * the node we were given, record the modification time
1069142173Sharti			 * of the parent in the child. We keep searching its
1070142173Sharti			 * parents in case some other parent requires this
1071142173Sharti			 * child to exist...
1072142173Sharti			 */
1073142173Sharti			nameStart = strchr(pgn->name, '(') + 1;
1074142173Sharti			nameEnd = strchr(nameStart, ')');
10751590Srgrimes
1076142173Sharti			if (pgn->make && strncmp(nameStart, gn->name,
1077142173Sharti			    nameEnd - nameStart) == 0) {
1078142173Sharti				gn->mtime = Arch_MTime(pgn);
1079142173Sharti			}
1080142173Sharti		} else if (pgn->make) {
1081142173Sharti			/*
1082142173Sharti			 * Something which isn't a library depends on the
1083142173Sharti			 * existence of this target, so it needs to exist.
1084142173Sharti			 */
1085142173Sharti			gn->mtime = 0;
1086142173Sharti			break;
1087142173Sharti		}
10881590Srgrimes	}
1089142173Sharti	return (gn->mtime);
10901590Srgrimes}
10911590Srgrimes
10921590Srgrimes/*-
10931590Srgrimes *-----------------------------------------------------------------------
10941590Srgrimes * Arch_FindLib --
1095104696Sjmallett *	Search for a named library along the given search path.
10961590Srgrimes *
10971590Srgrimes * Results:
10981590Srgrimes *	None.
10991590Srgrimes *
11001590Srgrimes * Side Effects:
11011590Srgrimes *	The node's 'path' field is set to the found path (including the
11021590Srgrimes *	actual file name, not -l...). If the system can handle the -L
11031590Srgrimes *	flag when linking (or we cannot find the library), we assume that
11041590Srgrimes *	the user has placed the .LIBRARIES variable in the final linking
11051590Srgrimes *	command (or the linker will know where to find it) and set the
11061590Srgrimes *	TARGET variable for this node to be the node's name. Otherwise,
11071590Srgrimes *	we set the TARGET variable to be the full path of the library,
11081590Srgrimes *	as returned by Dir_FindFile.
11091590Srgrimes *
11101590Srgrimes *-----------------------------------------------------------------------
11111590Srgrimes */
11121590Srgrimesvoid
1113138512ShartiArch_FindLib(GNode *gn, Lst *path)
11141590Srgrimes{
1115142173Sharti	char	*libName;	/* file name for archive */
1116142173Sharti	size_t	sz;
11171590Srgrimes
1118142173Sharti	sz = strlen(gn->name) + 4;
1119142173Sharti	libName = emalloc(sz);
1120142173Sharti	snprintf(libName, sz, "lib%s.a", &gn->name[2]);
11211590Srgrimes
1122142173Sharti	gn->path = Dir_FindFile(libName, path);
11231590Srgrimes
1124142173Sharti	free(libName);
11251590Srgrimes
11261590Srgrimes#ifdef LIBRARIES
1127142173Sharti	Var_Set(TARGET, gn->name, gn);
11281590Srgrimes#else
1129142173Sharti	Var_Set(TARGET, gn->path == NULL ? gn->name : gn->path, gn);
113018730Ssteve#endif /* LIBRARIES */
11311590Srgrimes}
11321590Srgrimes
11331590Srgrimes/*-
11341590Srgrimes *-----------------------------------------------------------------------
11351590Srgrimes * Arch_LibOODate --
11361590Srgrimes *	Decide if a node with the OP_LIB attribute is out-of-date. Called
1137104696Sjmallett *	from Make_OODate to make its life easier, with the library's
1138104696Sjmallett *	graph node.
11391590Srgrimes *
11401590Srgrimes *	There are several ways for a library to be out-of-date that are
11411590Srgrimes *	not available to ordinary files. In addition, there are ways
11421590Srgrimes *	that are open to regular files that are not available to
11431590Srgrimes *	libraries. A library that is only used as a source is never
11441590Srgrimes *	considered out-of-date by itself. This does not preclude the
11451590Srgrimes *	library's modification time from making its parent be out-of-date.
11461590Srgrimes *	A library will be considered out-of-date for any of these reasons,
11471590Srgrimes *	given that it is a target on a dependency line somewhere:
11481590Srgrimes *	    Its modification time is less than that of one of its
1149141270Sharti *		  sources (gn->mtime < gn->cmtime).
11501590Srgrimes *	    Its modification time is greater than the time at which the
1151141270Sharti *		  make began (i.e. it's been modified in the course
1152141270Sharti *		  of the make, probably by archiving).
11535814Sjkh *	    The modification time of one of its sources is greater than
11545814Sjkh *		  the one of its RANLIBMAG member (i.e. its table of contents
1155141270Sharti *		  is out-of-date). We don't compare of the archive time
11565814Sjkh *		  vs. TOC time because they can be too close. In my
11575814Sjkh *		  opinion we should not bother with the TOC at all since
11585814Sjkh *		  this is used by 'ar' rules that affect the data contents
11595814Sjkh *		  of the archive, not by ranlib rules, which affect the
11608874Srgrimes *		  TOC.
11611590Srgrimes *
11621590Srgrimes * Results:
11631590Srgrimes *	TRUE if the library is out-of-date. FALSE otherwise.
11641590Srgrimes *
11651590Srgrimes * Side Effects:
11661590Srgrimes *	The library will be hashed if it hasn't been already.
11671590Srgrimes *
11681590Srgrimes *-----------------------------------------------------------------------
11691590Srgrimes */
11701590SrgrimesBoolean
1171138232ShartiArch_LibOODate(GNode *gn)
11721590Srgrimes{
1173143656Sharti	int64_t	mtime;	/* The table-of-contents's mod time */
11741590Srgrimes
1175142173Sharti	if (OP_NOP(gn->type) && Lst_IsEmpty(&gn->children)) {
1176142173Sharti		return (FALSE);
1177142173Sharti	}
1178143105Sharti	if (gn->mtime > now || gn->mtime < gn->cmtime) {
1179142173Sharti		return (TRUE);
1180142173Sharti	}
1181142173Sharti
1182143656Sharti	mtime = ArchStatMember(gn->path, NULL, FALSE);
1183143656Sharti	if (mtime == INT64_MIN) {
1184142173Sharti		/*
1185143656Sharti		 * Not found. A library w/o a table of contents is out-of-date
1186142173Sharti		 */
1187142173Sharti		if (DEBUG(ARCH) || DEBUG(MAKE)) {
1188143656Sharti			Debug("No TOC...");
1189142173Sharti		}
1190142173Sharti		return (TRUE);
11911590Srgrimes	}
1192143656Sharti
1193143656Sharti	/* XXX choose one. */
1194143656Sharti	if (DEBUG(ARCH) || DEBUG(MAKE)) {
1195143656Sharti		Debug("TOC modified %s...", Targ_FmtTime(mtime));
1196143656Sharti	}
1197143656Sharti	return (gn->cmtime > mtime);
11981590Srgrimes}
11991590Srgrimes
12001590Srgrimes/*-
12011590Srgrimes *-----------------------------------------------------------------------
12021590Srgrimes * Arch_Init --
12031590Srgrimes *	Initialize things for this module.
12041590Srgrimes *
12051590Srgrimes * Results:
12061590Srgrimes *	None.
12071590Srgrimes *
12081590Srgrimes *-----------------------------------------------------------------------
12091590Srgrimes */
12101590Srgrimesvoid
1211138232ShartiArch_Init(void)
12121590Srgrimes{
12131590Srgrimes}
1214