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$");
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.
57146338Sharti *				FALSE 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>
91144387Sharti#include <sys/queue.h>
92141104Sharti#include <sys/types.h>
93141104Sharti#include <ar.h>
94141104Sharti#include <ctype.h>
95144387Sharti#include <errno.h>
96144387Sharti#include <inttypes.h>
97176799Simp#include <limits.h>
98141104Sharti#include <regex.h>
99141104Sharti#include <stdlib.h>
100141104Sharti#include <stdio.h>
101141104Sharti#include <string.h>
102141104Sharti#include <utime.h>
1031590Srgrimes
104141104Sharti#include "arch.h"
105142457Sharti#include "buf.h"
106200630Sstas#include "config.h"
107141104Sharti#include "dir.h"
108141104Sharti#include "globals.h"
109141104Sharti#include "GNode.h"
110141104Sharti#include "hash.h"
111141104Sharti#include "make.h"
112146066Sharti#include "parse.h"
113141104Sharti#include "targ.h"
114141104Sharti#include "util.h"
115141104Sharti#include "var.h"
116141104Sharti
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;
125143657Sharti
126144387Sharti	TAILQ_ENTRY(Arch) link;		/* link all cached archives */
1271590Srgrimes} Arch;
1281590Srgrimes
129144387Sharti/* Lst of archives we've already examined */
130144387Shartistatic TAILQ_HEAD(, Arch) archives = TAILQ_HEAD_INITIALIZER(archives);
1311590Srgrimes
132144387Sharti
133144387Sharti/* size of the name field in the archive member header */
134144387Sharti#define	AR_NAMSIZ	sizeof(((struct ar_hdr *)0)->ar_name)
135144387Sharti
136144387Sharti/*
137144387Sharti * This structure is used while reading/writing an archive
138144387Sharti */
139144387Shartistruct arfile {
140144387Sharti	FILE		*fp;		/* archive file */
141144387Sharti	char		*fname;		/* name of the file */
142144387Sharti	struct ar_hdr	hdr;		/* current header */
143144387Sharti	char		sname[AR_NAMSIZ + 1]; /* short name */
144144387Sharti	char		*member;	/* (long) member name */
145144387Sharti	size_t		mlen;		/* size of the above */
146144387Sharti	char		*nametab;	/* name table */
147144387Sharti	size_t		nametablen;	/* size of the table */
148144387Sharti	int64_t		time;		/* from ar_date */
149144387Sharti	uint64_t	size;		/* from ar_size */
150144387Sharti	off_t		pos;		/* header pos of current entry */
151144387Sharti};
152144387Sharti
153144387Sharti/*
154144387Sharti * Name of the symbol table. The original BSD used "__.SYMDEF". Rumours go
155144387Sharti * that this name may have a slash appended sometimes. Actually FreeBSD
156144387Sharti * uses "/" which probably came from SVR4.
157144387Sharti */
158144387Sharti#define	SVR4_RANLIBMAG	"/"
159144387Sharti#define	BSD_RANLIBMAG	"__.SYMDEF"
160144387Sharti
161144387Sharti/*
162144387Sharti * Name of the filename table. The 4.4BSD ar format did not use this, but
163144387Sharti * puts long filenames directly between the member header and the object
164144387Sharti * file.
165144387Sharti */
166144387Sharti#define	SVR4_NAMEMAG	"//"
167144387Sharti#define	BSD_NAMEMAG	"ARFILENAMES/"
168144387Sharti
169144387Sharti/*
170144387Sharti * 44BSD long filename key. Use a local define here instead of relying
171144387Sharti * on ar.h because we want this to continue working even when the
172144387Sharti * definition is removed from ar.h.
173144387Sharti */
174144387Sharti#define	BSD_EXT1	"#1/"
175144387Sharti#define	BSD_EXT1LEN	3
176144387Sharti
177144387Sharti/* if this is TRUE make archive errors fatal */
178144387ShartiBoolean arch_fatal = TRUE;
179144387Sharti
180144387Sharti/**
181144387Sharti * ArchError
182144387Sharti *	An error happend while handling an archive. BSDmake traditionally
183144387Sharti *	ignored these errors. Now this is dependend on the global arch_fatal
184144387Sharti *	which, if true, makes these errors fatal and, if false, just emits an
185144387Sharti *	error message.
186144387Sharti */
187144387Sharti#define	ArchError(ARGS) do {					\
188144387Sharti	if (arch_fatal)						\
189144387Sharti		Fatal ARGS;					\
190144387Sharti	else							\
191144387Sharti		Error ARGS;					\
192144387Sharti    } while (0)
193144387Sharti
1941590Srgrimes/*-
1951590Srgrimes *-----------------------------------------------------------------------
1961590Srgrimes * Arch_ParseArchive --
1971590Srgrimes *	Parse the archive specification in the given line and find/create
1981590Srgrimes *	the nodes for the specified archive members, placing their nodes
199104696Sjmallett *	on the given list, given the pointer to the start of the
200104696Sjmallett *	specification, a Lst on which to place the nodes, and a context
201104696Sjmallett *	in which to expand variables.
2021590Srgrimes *
2031590Srgrimes * Results:
204146338Sharti *	TRUE if it was a valid specification. The linePtr is updated
2051590Srgrimes *	to point to the first non-space after the archive spec. The
2061590Srgrimes *	nodes for the members are placed on the given list.
2071590Srgrimes *
2081590Srgrimes * Side Effects:
2091590Srgrimes *	Some nodes may be created. The given list is extended.
2101590Srgrimes *
2111590Srgrimes *-----------------------------------------------------------------------
2121590Srgrimes */
213146338ShartiBoolean
214138512ShartiArch_ParseArchive(char **linePtr, Lst *nodeLst, GNode *ctxt)
2151590Srgrimes{
216142173Sharti	char	*cp;		/* Pointer into line */
217142173Sharti	GNode	*gn;		/* New node */
218142173Sharti	char	*libName;	/* Library-part of specification */
219142173Sharti	char	*memName;	/* Member-part of specification */
220142173Sharti	char	*nameBuf;	/* temporary place for node name */
221142173Sharti	char	saveChar;	/* Ending delimiter of member-name */
222142173Sharti	Boolean	subLibName;	/* TRUE if libName should have/had
223141270Sharti				 * variable substitution performed on it */
2241590Srgrimes
225142173Sharti	libName = *linePtr;
2268874Srgrimes
227142173Sharti	subLibName = FALSE;
2281590Srgrimes
229142173Sharti	for (cp = libName; *cp != '(' && *cp != '\0'; cp++) {
230142173Sharti		if (*cp == '$') {
231142173Sharti			/*
232142173Sharti			 * Variable spec, so call the Var module to parse the
233142173Sharti			 * puppy so we can safely advance beyond it...
234142173Sharti			 */
235142937Sharti			size_t	length = 0;
236142173Sharti			Boolean	freeIt;
237142173Sharti			char	*result;
2388874Srgrimes
239142173Sharti			result = Var_Parse(cp, ctxt, TRUE, &length, &freeIt);
240142173Sharti			if (result == var_Error) {
241146338Sharti				return (FALSE);
242142173Sharti			}
243142173Sharti			subLibName = TRUE;
2448874Srgrimes
245142173Sharti			if (freeIt) {
246142173Sharti				free(result);
247142173Sharti			}
248142173Sharti			cp += length - 1;
249142173Sharti		}
2501590Srgrimes	}
2511590Srgrimes
252142173Sharti	*cp++ = '\0';
253142173Sharti	if (subLibName) {
254146027Sharti		libName = Buf_Peel(Var_Subst(libName, ctxt, TRUE));
255142173Sharti	}
2561590Srgrimes
257142173Sharti	for (;;) {
258142173Sharti		/*
259142173Sharti		 * First skip to the start of the member's name, mark that
260142173Sharti		 * place and skip to the end of it (either white-space or
261142173Sharti		 * a close paren).
262142173Sharti		 */
2631590Srgrimes
2641590Srgrimes		/*
265142173Sharti		 * TRUE if need to substitute in memName
2661590Srgrimes		 */
267142173Sharti		Boolean	doSubst = FALSE;
2681590Srgrimes
269142173Sharti		while (*cp != '\0' && *cp != ')' &&
270142173Sharti		    isspace((unsigned char)*cp)) {
271143105Sharti			cp++;
2721590Srgrimes		}
2731590Srgrimes
274142173Sharti		memName = cp;
275142173Sharti		while (*cp != '\0' && *cp != ')' &&
276142173Sharti		    !isspace((unsigned char)*cp)) {
277142173Sharti			if (*cp == '$') {
278142173Sharti				/*
279142173Sharti				 * Variable spec, so call the Var module to
280142173Sharti				 * parse the puppy so we can safely advance
281142173Sharti				 * beyond it...
282142173Sharti				 */
283142937Sharti				size_t	length = 0;
284142173Sharti				Boolean	freeIt;
285142173Sharti				char	*result;
286142173Sharti
287142173Sharti				result = Var_Parse(cp, ctxt, TRUE,
288142173Sharti				    &length, &freeIt);
289142173Sharti				if (result == var_Error) {
290146338Sharti					return (FALSE);
291142173Sharti				}
292142173Sharti				doSubst = TRUE;
293142173Sharti
294142173Sharti				if (freeIt) {
295142173Sharti					free(result);
296142173Sharti				}
297142173Sharti				cp += length;
298142173Sharti			} else {
299142173Sharti				cp++;
300142173Sharti			}
3011590Srgrimes		}
3021590Srgrimes
303142173Sharti		/*
304142173Sharti		 * If the specification ends without a closing parenthesis,
305142173Sharti		 * chances are there's something wrong (like a missing
306142173Sharti		 * backslash), so it's better to return failure than allow
307142173Sharti		 * such things to happen
308142173Sharti		 */
309142173Sharti		if (*cp == '\0') {
310142173Sharti			printf("No closing parenthesis in archive "
311142173Sharti			    "specification\n");
312146338Sharti			return (FALSE);
313142173Sharti		}
3141590Srgrimes
315142173Sharti		/*
316142173Sharti		 * If we didn't move anywhere, we must be done
317142173Sharti		 */
318142173Sharti		if (cp == memName) {
319142173Sharti			break;
320142173Sharti		}
3211590Srgrimes
322142173Sharti		saveChar = *cp;
323142173Sharti		*cp = '\0';
3241590Srgrimes
325142173Sharti		/*
326142173Sharti		 * XXX: This should be taken care of intelligently by
327142173Sharti		 * SuffExpandChildren, both for the archive and the member
328142173Sharti		 * portions.
329142173Sharti		 */
330142173Sharti		/*
331142173Sharti		 * If member contains variables, try and substitute for them.
332142173Sharti		 * This will slow down archive specs with dynamic sources, of
333142173Sharti		 * course, since we'll be (non-)substituting them three times,
334142173Sharti		 * but them's the breaks -- we need to do this since
335142173Sharti		 * SuffExpandChildren calls us, otherwise we could assume the
336142173Sharti		 * thing would be taken care of later.
337142173Sharti		 */
338142173Sharti		if (doSubst) {
339142173Sharti			char	*buf;
340142173Sharti			char	*sacrifice;
341142173Sharti			char	*oldMemName = memName;
342142173Sharti			size_t	sz;
343142457Sharti			Buffer	*buf1;
3448874Srgrimes
345142173Sharti			/*
346142173Sharti			 * Now form an archive spec and recurse to deal with
347142173Sharti			 * nested variables and multi-word variable values....
348142173Sharti			 * The results are just placed at the end of the
349142173Sharti			 * nodeLst we're returning.
350142173Sharti			 */
351146027Sharti			buf1 = Var_Subst(memName, ctxt, TRUE);
352143959Sharti			memName = Buf_Data(buf1);
3531590Srgrimes
354142173Sharti			sz = strlen(memName) + strlen(libName) + 3;
355142457Sharti			buf = emalloc(sz);
3561590Srgrimes
357142173Sharti			snprintf(buf, sz, "%s(%s)", libName, memName);
35869390Swill
359142457Sharti			sacrifice = buf;
360142457Sharti
361142173Sharti			if (strchr(memName, '$') &&
362142173Sharti			    strcmp(memName, oldMemName) == 0) {
363142173Sharti				/*
364142173Sharti				 * Must contain dynamic sources, so we can't
365142173Sharti				 * deal with it now.
366142173Sharti				 * Just create an ARCHV node for the thing and
367142173Sharti				 * let SuffExpandChildren handle it...
368142173Sharti				 */
369142173Sharti				gn = Targ_FindNode(buf, TARG_CREATE);
3701590Srgrimes
371142173Sharti				if (gn == NULL) {
372142173Sharti					free(buf);
373142457Sharti					Buf_Destroy(buf1, FALSE);
374146338Sharti					return (FALSE);
375142173Sharti				}
376142173Sharti				gn->type |= OP_ARCHV;
377142173Sharti				Lst_AtEnd(nodeLst, (void *)gn);
378146338Sharti			} else if (!Arch_ParseArchive(&sacrifice, nodeLst,
379146338Sharti			    ctxt)) {
380142173Sharti				/*
381142173Sharti				 * Error in nested call -- free buffer and
382146338Sharti				 * return FALSE ourselves.
383142173Sharti				 */
384142173Sharti				free(buf);
385142457Sharti				Buf_Destroy(buf1, FALSE);
386146338Sharti				return (FALSE);
387142173Sharti			}
388142457Sharti
389142457Sharti			/* Free buffer and continue with our work. */
390142173Sharti			free(buf);
391142457Sharti			Buf_Destroy(buf1, FALSE);
392142457Sharti
393142173Sharti		} else if (Dir_HasWildcards(memName)) {
394142173Sharti			Lst	members = Lst_Initializer(members);
395142173Sharti			char	*member;
396142173Sharti			size_t	sz = MAXPATHLEN;
397142173Sharti			size_t	nsz;
398138196Sharti
399142173Sharti			nameBuf = emalloc(sz);
4001590Srgrimes
401144020Sharti			Path_Expand(memName, &dirSearchPath, &members);
402142173Sharti			while (!Lst_IsEmpty(&members)) {
403142173Sharti				member = Lst_DeQueue(&members);
404142173Sharti				nsz = strlen(libName) + strlen(member) + 3;
405142173Sharti				if (nsz > sz) {
406142173Sharti					sz = nsz * 2;
407142173Sharti					nameBuf = erealloc(nameBuf, sz);
408142173Sharti				}
4098874Srgrimes
410142173Sharti				snprintf(nameBuf, sz, "%s(%s)",
411142173Sharti				    libName, member);
412142173Sharti				free(member);
413142173Sharti				gn = Targ_FindNode(nameBuf, TARG_CREATE);
414142173Sharti				if (gn == NULL) {
415142173Sharti					free(nameBuf);
416142173Sharti					/* XXXHB Lst_Destroy(&members) */
417146338Sharti					return (FALSE);
418142173Sharti				}
419142173Sharti				/*
420142173Sharti				 * We've found the node, but have to make sure
421142173Sharti				 * the rest of the world knows it's an archive
422142173Sharti				 * member, without having to constantly check
423142173Sharti				 * for parentheses, so we type the thing with
424142173Sharti				 * the OP_ARCHV bit before we place it on the
425142173Sharti				 * end of the provided list.
426142173Sharti				 */
427142173Sharti				gn->type |= OP_ARCHV;
428142173Sharti				Lst_AtEnd(nodeLst, gn);
429142173Sharti			}
430142173Sharti			free(nameBuf);
4311590Srgrimes		} else {
432142173Sharti			size_t	sz = strlen(libName) + strlen(memName) + 3;
433142173Sharti
434142173Sharti			nameBuf = emalloc(sz);
435142173Sharti			snprintf(nameBuf, sz, "%s(%s)", libName, memName);
436142173Sharti			gn = Targ_FindNode(nameBuf, TARG_CREATE);
437142173Sharti			free(nameBuf);
438142173Sharti			if (gn == NULL) {
439146338Sharti				return (FALSE);
440142173Sharti			}
441142173Sharti			/*
442142173Sharti			 * We've found the node, but have to make sure the
443142173Sharti			 * rest of the world knows it's an archive member,
444142173Sharti			 * without having to constantly check for parentheses,
445142173Sharti			 * so we type the thing with the OP_ARCHV bit before
446142173Sharti			 * we place it on the end of the provided list.
447142173Sharti			 */
448142173Sharti			gn->type |= OP_ARCHV;
449142173Sharti			Lst_AtEnd(nodeLst, gn);
4501590Srgrimes		}
451142173Sharti		if (doSubst) {
452142173Sharti			free(memName);
453142173Sharti		}
454142173Sharti
455142173Sharti		*cp = saveChar;
4561590Srgrimes	}
457142173Sharti
458142173Sharti	/*
459142173Sharti	 * If substituted libName, free it now, since we need it no longer.
460142173Sharti	 */
461142173Sharti	if (subLibName) {
462142173Sharti		free(libName);
4631590Srgrimes	}
4648874Srgrimes
465142173Sharti	/*
466142173Sharti	 * We promised the pointer would be set up at the next non-space, so
467142173Sharti	 * we must advance cp there before setting *linePtr... (note that on
468142173Sharti	 * entrance to the loop, cp is guaranteed to point at a ')')
469142173Sharti	 */
470142173Sharti	do {
471142173Sharti		cp++;
472142173Sharti	} while (*cp != '\0' && isspace((unsigned char)*cp));
4731590Srgrimes
474142173Sharti	*linePtr = cp;
475146338Sharti	return (TRUE);
4761590Srgrimes}
4771590Srgrimes
478144387Sharti/*
479144387Sharti * Close an archive file an free all resources
4801590Srgrimes */
481144387Shartistatic void
482144387ShartiArchArchiveClose(struct arfile *ar)
4831590Srgrimes{
4841590Srgrimes
485144387Sharti	if (ar->nametab != NULL)
486144387Sharti		free(ar->nametab);
487144387Sharti	free(ar->member);
488144387Sharti	if (ar->fp != NULL) {
489144387Sharti		if (fclose(ar->fp) == EOF)
490144387Sharti			ArchError(("%s: close error", ar->fname));
491144387Sharti	}
492144387Sharti	free(ar->fname);
493144387Sharti	free(ar);
494144387Sharti}
495144387Sharti
496144387Sharti/*
497144387Sharti * Open an archive file.
498144387Sharti */
499144387Shartistatic struct arfile *
500144387ShartiArchArchiveOpen(const char *archive, const char *mode)
501144387Sharti{
502144387Sharti	struct arfile *ar;
503144387Sharti	char	magic[SARMAG];
504144387Sharti
505144387Sharti	ar = emalloc(sizeof(*ar));
506144387Sharti	ar->fname = estrdup(archive);
507144387Sharti	ar->mlen = 100;
508144387Sharti	ar->member = emalloc(ar->mlen);
509144387Sharti	ar->nametab = NULL;
510144387Sharti	ar->nametablen = 0;
511144387Sharti
512144387Sharti	if ((ar->fp = fopen(ar->fname, mode)) == NULL) {
513144387Sharti		DEBUGM(ARCH, ("%s", ar->fname));
514144387Sharti		ArchArchiveClose(ar);
515142173Sharti		return (NULL);
516142173Sharti	}
5171590Srgrimes
518144387Sharti	/* read MAGIC */
519144387Sharti	if (fread(magic, SARMAG, 1, ar->fp) != 1 ||
520143105Sharti	    strncmp(magic, ARMAG, SARMAG) != 0) {
521144387Sharti		ArchError(("%s: bad archive magic\n", ar->fname));
522144387Sharti		ArchArchiveClose(ar);
523142173Sharti		return (NULL);
524142165Sharti	}
5255814Sjkh
526144387Sharti	ar->pos = 0;
527144387Sharti	return (ar);
528144387Sharti}
529144387Sharti
530144387Sharti/*
531144387Sharti * Read the next header from the archive. The return value will be +1 if
532144387Sharti * the header is read successfully, 0 on EOF and -1 if an error happend.
533144387Sharti * On a successful return sname contains the truncated member name and
534144387Sharti * member the full name. hdr contains the member header. For the symbol table
535144387Sharti * names of length 0 are returned. The entry for the file name table is never
536144387Sharti * returned.
537144387Sharti */
538144387Shartistatic int
539144387ShartiArchArchiveNext(struct arfile *ar)
540144387Sharti{
541144387Sharti	char	*end;
542144387Sharti	int	have_long_name;
543144387Sharti	u_long	offs;
544144387Sharti	char	*ptr;
545144387Sharti	size_t	ret;
546144387Sharti	char	buf[MAX(sizeof(ar->hdr.ar_size), sizeof(ar->hdr.ar_date)) + 1];
547144387Sharti
548144387Sharti  next:
5491590Srgrimes	/*
550144387Sharti	 * Seek to the next header.
551142297Sharti	 */
552144387Sharti	if (ar->pos == 0) {
553144387Sharti		ar->pos = SARMAG;
554144387Sharti	} else {
555144387Sharti		ar->pos += sizeof(ar->hdr) + ar->size;
556144387Sharti		if (ar->size % 2 == 1)
557144387Sharti			ar->pos++;
5581590Srgrimes	}
559144387Sharti
560144387Sharti	if (fseeko(ar->fp, ar->pos, SEEK_SET) == -1) {
561144387Sharti		ArchError(("%s: cannot seek to %jd: %s", ar->fname,
562144387Sharti		    (intmax_t)ar->pos, strerror(errno)));
563144387Sharti		return (-1);
564142173Sharti	}
5651590Srgrimes
566144387Sharti	/*
567144387Sharti	 * Read next member header
568144387Sharti	 */
569144387Sharti	ret = fread(&ar->hdr, sizeof(ar->hdr), 1, ar->fp);
570144387Sharti	if (ret != 1) {
571144387Sharti		if (feof(ar->fp))
572144387Sharti			return (0);
573144387Sharti		ArchError(("%s: error reading member header: %s", ar->fname,
574144387Sharti		    strerror(errno)));
575144387Sharti		return (-1);
576144387Sharti	}
577144387Sharti	if (strncmp(ar->hdr.ar_fmag, ARFMAG, sizeof(ar->hdr.ar_fmag)) != 0) {
578144387Sharti		ArchError(("%s: bad entry magic", ar->fname));
579144387Sharti		return (-1);
580144387Sharti	}
5818874Srgrimes
582144387Sharti	/*
583144387Sharti	 * looks like a member - get name by stripping trailing spaces
584144387Sharti	 * and NUL terminating.
585144387Sharti	 */
586194797Sdelphij	strlcpy(ar->sname, ar->hdr.ar_name, AR_NAMSIZ + 1);
587144387Sharti	for (ptr = ar->sname + AR_NAMSIZ; ptr > ar->sname; ptr--)
588144387Sharti		if (ptr[-1] != ' ')
589144387Sharti			break;
590144387Sharti
591144387Sharti	*ptr = '\0';
592144387Sharti
593144387Sharti	/*
594144387Sharti	 * Parse the size. All entries need to have a size. Be careful
595144387Sharti	 * to not allow buffer overruns.
596144387Sharti	 */
597194797Sdelphij	strlcpy(buf, ar->hdr.ar_size, sizeof(ar->hdr.ar_size) + 1);
598144387Sharti
599144387Sharti	errno = 0;
600144387Sharti	ar->size = strtoumax(buf, &end, 10);
601144387Sharti	if (errno != 0 || strspn(end, " ") != strlen(end)) {
602144387Sharti		ArchError(("%s: bad size format in archive '%s'",
603144387Sharti		    ar->fname, buf));
604144387Sharti		return (-1);
605144387Sharti	}
606144387Sharti
607144387Sharti	/*
608144387Sharti	 * Look for the extended name table. Do this before parsing
609144387Sharti	 * the date because this table doesn't need a date.
610144387Sharti	 */
611144387Sharti	if (strcmp(ar->sname, BSD_NAMEMAG) == 0 ||
612144387Sharti	    strcmp(ar->sname, SVR4_NAMEMAG) == 0) {
613144387Sharti		/* filename table - read it in */
614144387Sharti		ar->nametablen = ar->size;
615144387Sharti		ar->nametab = emalloc(ar->nametablen);
616144387Sharti
617144387Sharti		ret = fread(ar->nametab, 1, ar->nametablen, ar->fp);
618144387Sharti		if (ret != ar->nametablen) {
619144387Sharti			if (ferror(ar->fp)) {
620144387Sharti				ArchError(("%s: cannot read nametab: %s",
621144387Sharti				    ar->fname, strerror(errno)));
622144387Sharti			} else {
623144387Sharti				ArchError(("%s: cannot read nametab: "
624144387Sharti				    "short read", ar->fname, strerror(errno)));
625143657Sharti			}
626144387Sharti			return (-1);
627142173Sharti		}
628144387Sharti
62918730Ssteve		/*
630144387Sharti		 * NUL terminate the entries. Entries are \n terminated
631144387Sharti		 * and may have a trailing / or \.
63218730Ssteve		 */
633144387Sharti		ptr = ar->nametab;
634144387Sharti		while (ptr < ar->nametab + ar->nametablen) {
635144387Sharti			if (*ptr == '\n') {
636144387Sharti				if (ptr[-1] == '/' || ptr[-1] == '\\')
637144387Sharti					ptr[-1] = '\0';
638144387Sharti				*ptr = '\0';
639144387Sharti			}
640144387Sharti			ptr++;
641144387Sharti		}
642143657Sharti
643144387Sharti		/* get next archive entry */
644144387Sharti		goto next;
645144387Sharti	}
646144387Sharti
647144387Sharti	/*
648144387Sharti	 * Now parse the modification date. Be careful to not overrun
649144387Sharti	 * buffers.
650144387Sharti	 */
651194797Sdelphij	strlcpy(buf, ar->hdr.ar_date, sizeof(ar->hdr.ar_date) + 1);
652144387Sharti
653144387Sharti	errno = 0;
654144387Sharti	ar->time = (int64_t)strtoll(buf, &end, 10);
655144387Sharti	if (errno != 0 || strspn(end, " ") != strlen(end)) {
656144387Sharti		ArchError(("%s: bad date format in archive '%s'",
657144387Sharti		    ar->fname, buf));
658144387Sharti		return (-1);
659144387Sharti	}
660144387Sharti
661144387Sharti	/*
662144387Sharti	 * Now check for the symbol table. This should really be the first
663144387Sharti	 * entry, but we don't check this.
664144387Sharti	 */
665144387Sharti	if (strcmp(ar->sname, BSD_RANLIBMAG) == 0 ||
666144387Sharti	    strcmp(ar->sname, SVR4_RANLIBMAG) == 0) {
667144387Sharti		/* symbol table - return a zero length name */
668144387Sharti		ar->member[0] = '\0';
669144387Sharti		ar->sname[0] = '\0';
670144387Sharti		return (1);
671144387Sharti	}
672144387Sharti
673144387Sharti	have_long_name = 0;
674144387Sharti
675144387Sharti	/*
676144387Sharti	 * Look whether this is a long name. There are several variants
677144387Sharti	 * of long names:
678144387Sharti	 *	"#1/12           "	- 12 length of following filename
679144387Sharti	 *	"/17             "	- index into name table
680144387Sharti	 *	" 17             "	- index into name table
681144387Sharti	 * Note that in the last case we must also check that there is no
682144387Sharti	 * slash in the name because of filenames with leading spaces:
683144387Sharti	 *	" 777.o/           "	- filename 777.o
684144387Sharti	 */
685144387Sharti	if (ar->sname[0] == '/' || (ar->sname[0] == ' ' &&
686144387Sharti	    strchr(ar->sname, '/') == NULL)) {
687144387Sharti		/* SVR4 extended name */
688144387Sharti		errno = 0;
689144387Sharti		offs = strtoul(ar->sname + 1, &end, 10);
690144387Sharti		if (errno != 0 || *end != '\0' || offs >= ar->nametablen ||
691144387Sharti		    end == ar->sname + 1) {
692144387Sharti			ArchError(("%s: bad extended name '%s'", ar->fname,
693144387Sharti			    ar->sname));
694144387Sharti			return (-1);
695144387Sharti		}
696144387Sharti
697144387Sharti		/* fetch the name */
698144387Sharti		if (ar->mlen <= strlen(ar->nametab + offs)) {
699144387Sharti			ar->mlen = strlen(ar->nametab + offs) + 1;
700144387Sharti			ar->member = erealloc(ar->member, ar->mlen);
701144387Sharti		}
702144387Sharti		strcpy(ar->member, ar->nametab + offs);
703144387Sharti
704144387Sharti		have_long_name = 1;
705144387Sharti
706144387Sharti	} else if (strncmp(ar->sname, BSD_EXT1, BSD_EXT1LEN) == 0 &&
707144387Sharti	    isdigit(ar->sname[BSD_EXT1LEN])) {
708144387Sharti		/* BSD4.4 extended name */
709144387Sharti		errno = 0;
710144387Sharti		offs = strtoul(ar->sname + BSD_EXT1LEN, &end, 10);
711144387Sharti		if (errno != 0 || *end != '\0' ||
712144387Sharti		    end == ar->sname + BSD_EXT1LEN) {
713144387Sharti			ArchError(("%s: bad extended name '%s'", ar->fname,
714144387Sharti			    ar->sname));
715144387Sharti			return (-1);
716144387Sharti		}
717144387Sharti
718144387Sharti		/* read it from the archive */
719144387Sharti		if (ar->mlen <= offs) {
720144387Sharti			ar->mlen = offs + 1;
721144387Sharti			ar->member = erealloc(ar->member, ar->mlen);
722144387Sharti		}
723144387Sharti		ret = fread(ar->member, 1, offs, ar->fp);
724144387Sharti		if (ret != offs) {
725144387Sharti			if (ferror(ar->fp)) {
726144387Sharti				ArchError(("%s: reading extended name: %s",
727144387Sharti				    ar->fname, strerror(errno)));
728144387Sharti			} else {
729144387Sharti				ArchError(("%s: reading extended name: "
730144387Sharti				    "short read", ar->fname));
731142173Sharti			}
732144387Sharti			return (-1);
73318730Ssteve		}
734144387Sharti		ar->member[offs] = '\0';
735144387Sharti
736144387Sharti		have_long_name = 1;
7371590Srgrimes	}
7381590Srgrimes
739142173Sharti	/*
740144387Sharti	 * Now remove the trailing slash that Svr4 puts at
741144387Sharti	 * the end of the member name to support trailing spaces in names.
742142297Sharti	 */
743144387Sharti	if (ptr > ar->sname && ptr[-1] == '/')
744144387Sharti		*--ptr = '\0';
745144387Sharti
746144387Sharti	if (!have_long_name) {
747144387Sharti		if (strlen(ar->sname) >= ar->mlen) {
748144387Sharti			ar->mlen = strlen(ar->sname) + 1;
749144387Sharti			ar->member = erealloc(ar->member, ar->mlen);
750144387Sharti		}
751144387Sharti		strcpy(ar->member, ar->sname);
752144387Sharti	}
753144387Sharti
754144387Sharti	return (1);
755143657Sharti}
756143656Sharti
757144387Sharti/*
758144387Sharti * Touch the current archive member by writing a new header with an
759144387Sharti * updated timestamp. The return value is 0 for success and -1 for errors.
760144387Sharti */
761144387Shartistatic int
762144387ShartiArchArchiveTouch(struct arfile *ar, int64_t ts)
763144387Sharti{
764144387Sharti
765144387Sharti	/* seek to our header */
766144387Sharti	if (fseeko(ar->fp, ar->pos, SEEK_SET) == -1) {
767144387Sharti		ArchError(("%s: cannot seek to %jd: %s", ar->fname,
768144387Sharti		    (intmax_t)ar->pos, strerror(errno)));
769144387Sharti		return (-1);
770144387Sharti	}
771144387Sharti
772144387Sharti	/*
773144387Sharti	 * change timestamp, be sure to not NUL-terminated it, but
774144387Sharti	 * to fill with spaces.
775144387Sharti	 */
776146577Sharti	snprintf(ar->hdr.ar_date, sizeof(ar->hdr.ar_date), "%jd",
777146577Sharti	    (intmax_t)ts);
778144387Sharti	memset(ar->hdr.ar_date + strlen(ar->hdr.ar_date),
779144387Sharti	    ' ', sizeof(ar->hdr.ar_date) - strlen(ar->hdr.ar_date));
780144387Sharti
781144387Sharti	if (fwrite(&ar->hdr, sizeof(ar->hdr), 1, ar->fp) != 1) {
782144387Sharti		ArchError(("%s: cannot touch: %s", ar->fname, strerror(errno)));
783144387Sharti		return (-1);
784144387Sharti	}
785144387Sharti	return (0);
786144387Sharti}
787144387Sharti
788143657Sharti/*-
789143657Sharti *-----------------------------------------------------------------------
790144387Sharti * ArchFindMember --
791144387Sharti *	Locate a member of an archive, given the path of the archive and
792144387Sharti *	the path of the desired member. If the archive is to be modified,
793144387Sharti *	the mode should be "r+", if not, it should be "r".  The archive
794144387Sharti *	file is returned positioned at the correct header.
795143657Sharti *
796143657Sharti * Results:
797144387Sharti *	A struct arfile *, opened for reading and, possibly writing,
798144387Sharti *	positioned at the member's header, or NULL if the member was
799144387Sharti *	nonexistent.
800143657Sharti *
801143657Sharti *-----------------------------------------------------------------------
802143657Sharti */
803144387Shartistatic struct arfile *
804144387ShartiArchFindMember(const char *archive, const char *member, const char *mode)
805143657Sharti{
806144387Sharti	struct arfile	*ar;
807144387Sharti	const char	*cp;	/* Useful character pointer */
808143656Sharti
809144387Sharti	if ((ar = ArchArchiveOpen(archive, mode)) == NULL)
810144387Sharti		return (NULL);
811143656Sharti
812144387Sharti	/*
813144387Sharti	 * Because of space constraints and similar things, files are archived
814144387Sharti	 * using their final path components, not the entire thing, so we need
815144387Sharti	 * to point 'member' to the final component, if there is one, to make
816144387Sharti	 * the comparisons easier...
817144387Sharti	 */
818144387Sharti	if (member != NULL) {
819144387Sharti		cp = strrchr(member, '/');
820144387Sharti		if (cp != NULL) {
821144387Sharti			member = cp + 1;
822143656Sharti		}
823144387Sharti	}
824143656Sharti
825144387Sharti	while (ArchArchiveNext(ar) > 0) {
826143657Sharti		/*
827144387Sharti		 * When comparing there are actually three cases:
828144387Sharti		 * (1) the name fits into the limit og af_name,
829144387Sharti		 * (2) the name is longer and the archive supports long names,
830144387Sharti		 * (3) the name is longer and the archive doesn't support long
831144387Sharti		 * names.
832144387Sharti		 * Because we don't know whether the archive supports long
833144387Sharti		 * names or not we need to be carefull.
834143657Sharti		 */
835144387Sharti		if (member == NULL) {
836144387Sharti			/* special case - symbol table */
837144387Sharti			if (ar->member[0] == '\0')
838144387Sharti				return (ar);
839144387Sharti		} else if (strlen(member) <= AR_NAMSIZ) {
840144387Sharti			/* case (1) */
841144387Sharti			if (strcmp(ar->member, member) == 0)
842144387Sharti				return (ar);
843144387Sharti		} else if (strcmp(ar->member, member) == 0) {
844144387Sharti			/* case (3) */
845144387Sharti			return (ar);
846144387Sharti		} else {
847144387Sharti			/* case (2) */
848144387Sharti			if (strlen(ar->member) == AR_NAMSIZ &&
849144387Sharti			    strncmp(member, ar->member, AR_NAMSIZ) == 0)
850144387Sharti				return (ar);
851143656Sharti		}
852143656Sharti	}
853143656Sharti
854144387Sharti	/* not found */
855144387Sharti	ArchArchiveClose(ar);
856144387Sharti	return (NULL);
85718730Ssteve}
85818730Ssteve
85918730Ssteve/*-
86018730Ssteve *-----------------------------------------------------------------------
861142173Sharti * ArchStatMember --
8621590Srgrimes *	Locate a member of an archive, given the path of the archive and
863142173Sharti *	the path of the desired member, and a boolean representing whether
864142173Sharti *	or not the archive should be hashed (if not already hashed).
8651590Srgrimes *
8661590Srgrimes * Results:
867142173Sharti *	A pointer to the current struct ar_hdr structure for the member. Note
868142173Sharti *	That no position is returned, so this is not useful for touching
869142173Sharti *	archive members. This is mostly because we have no assurances that
870142173Sharti *	The archive will remain constant after we read all the headers, so
871142173Sharti *	there's not much point in remembering the position...
8721590Srgrimes *
8731590Srgrimes * Side Effects:
8741590Srgrimes *
8751590Srgrimes *-----------------------------------------------------------------------
8761590Srgrimes */
877144387Shartistatic int64_t
878142173ShartiArchStatMember(const char *archive, const char *member, Boolean hash)
8791590Srgrimes{
880144387Sharti	struct arfile	*arf;
881144387Sharti	int64_t		ret;
882144387Sharti	int		t;
883142173Sharti	char		*cp;	/* Useful character pointer */
884142173Sharti	Arch		*ar;	/* Archive descriptor */
885142173Sharti	Hash_Entry	*he;	/* Entry containing member's description */
886144387Sharti	char		copy[AR_NAMSIZ + 1];
8871590Srgrimes
888142173Sharti	/*
889142297Sharti	 * Because of space constraints and similar things, files are archived
890142297Sharti	 * using their final path components, not the entire thing, so we need
891142297Sharti	 * to point 'member' to the final component, if there is one, to make
892142297Sharti	 * the comparisons easier...
893142297Sharti	 */
894144387Sharti	if (member != NULL) {
895144387Sharti		cp = strrchr(member, '/');
896144387Sharti		if (cp != NULL)
897144387Sharti			member = cp + 1;
898144387Sharti	}
8998874Srgrimes
900144387Sharti	TAILQ_FOREACH(ar, &archives, link) {
901144387Sharti		if (strcmp(archive, ar->name) == 0)
902143975Sharti			break;
903143975Sharti	}
904144387Sharti	if (ar == NULL) {
905144387Sharti		/* archive not found */
906144387Sharti		if (!hash) {
907142173Sharti			/*
908144387Sharti			 * Caller doesn't want the thing hashed, just use
909144387Sharti			 * ArchFindMember to read the header for the member
910144387Sharti			 * out and close down the stream again.
911142173Sharti			 */
912144387Sharti			arf = ArchFindMember(archive, member, "r");
913144387Sharti			if (arf == NULL) {
914144387Sharti				return (INT64_MIN);
915144387Sharti			}
916144387Sharti			ret = arf->time;
917144387Sharti			ArchArchiveClose(arf);
918144387Sharti			return (ret);
919142173Sharti		}
920144387Sharti
9215814Sjkh		/*
922144387Sharti		 * We don't have this archive on the list yet, so we want to
923144387Sharti		 * find out everything that's in it and cache it so we can get
924144387Sharti		 * at it quickly.
9255814Sjkh		 */
926144387Sharti		arf = ArchArchiveOpen(archive, "r");
927144387Sharti		if (arf == NULL) {
928144387Sharti			return (INT64_MIN);
929142173Sharti		}
9305814Sjkh
931144387Sharti		/* create archive data structure */
932144387Sharti		ar = emalloc(sizeof(*ar));
933144387Sharti		ar->name = estrdup(archive);
934144387Sharti		Hash_InitTable(&ar->members, -1);
935142173Sharti
936144387Sharti		while ((t = ArchArchiveNext(arf)) > 0) {
937144387Sharti			he = Hash_CreateEntry(&ar->members, arf->member, NULL);
938144387Sharti			Hash_SetValue(he, emalloc(sizeof(int64_t)));
939144387Sharti			*(int64_t *)Hash_GetValue(he) = arf->time;
9405814Sjkh		}
941142173Sharti
942144387Sharti		ArchArchiveClose(arf);
943142173Sharti
944144387Sharti		if (t < 0) {
945144387Sharti			/* error happend - throw away everything */
946144387Sharti			Hash_DeleteTable(&ar->members);
947144387Sharti			free(ar->name);
948144387Sharti			free(ar);
949144387Sharti			return (INT64_MIN);
9505814Sjkh		}
951142173Sharti
952144387Sharti		TAILQ_INSERT_TAIL(&archives, ar, link);
9531590Srgrimes	}
9541590Srgrimes
955142173Sharti	/*
956142173Sharti	 * Now that the archive has been read and cached, we can look into
957142173Sharti	 * the hash table to find the desired member's header.
958142173Sharti	 */
959142173Sharti	he = Hash_FindEntry(&ar->members, member);
960144387Sharti	if (he != NULL)
961144387Sharti		return (*(int64_t *)Hash_GetValue (he));
962142173Sharti
963144387Sharti	if (member != NULL && strlen(member) > AR_NAMSIZ) {
964144387Sharti		/* Try truncated name */
965194797Sdelphij		strlcpy(copy, member, AR_NAMSIZ + 1);
966144387Sharti
967144387Sharti		if ((he = Hash_FindEntry(&ar->members, copy)) != NULL)
968144387Sharti			return (*(int64_t *)Hash_GetValue(he));
969142173Sharti	}
970142173Sharti
971144387Sharti	return (INT64_MIN);
9721590Srgrimes}
9731590Srgrimes
9741590Srgrimes/*-
9751590Srgrimes *-----------------------------------------------------------------------
9761590Srgrimes * Arch_Touch --
9771590Srgrimes *	Touch a member of an archive.
9781590Srgrimes *
9791590Srgrimes * Results:
9801590Srgrimes *	The 'time' field of the member's header is updated.
9811590Srgrimes *
9821590Srgrimes * Side Effects:
9831590Srgrimes *	The modification time of the entire archive is also changed.
9841590Srgrimes *	For a library, this could necessitate the re-ranlib'ing of the
9851590Srgrimes *	whole thing.
9861590Srgrimes *
9871590Srgrimes *-----------------------------------------------------------------------
9881590Srgrimes */
9891590Srgrimesvoid
990138232ShartiArch_Touch(GNode *gn)
9911590Srgrimes{
992144387Sharti	struct arfile	*ar;
9931590Srgrimes
994146580Sharti	ar = ArchFindMember(Var_Value(ARCHIVE, gn),
995146580Sharti	    Var_Value(TARGET, gn), "r+");
9961590Srgrimes
997144387Sharti	if (ar != NULL) {
998144387Sharti		ArchArchiveTouch(ar, (int64_t)now);
999144387Sharti		ArchArchiveClose(ar);
1000142173Sharti	}
10011590Srgrimes}
10021590Srgrimes
10031590Srgrimes/*-
10041590Srgrimes *-----------------------------------------------------------------------
10051590Srgrimes * Arch_TouchLib --
10061590Srgrimes *	Given a node which represents a library, touch the thing, making
10071590Srgrimes *	sure that the table of contents also is touched.
10081590Srgrimes *
10091590Srgrimes * Results:
10101590Srgrimes *	None.
10111590Srgrimes *
10121590Srgrimes * Side Effects:
10131590Srgrimes *	Both the modification time of the library and of the RANLIBMAG
10141590Srgrimes *	member are set to 'now'.
10151590Srgrimes *
10161590Srgrimes *-----------------------------------------------------------------------
10171590Srgrimes */
10181590Srgrimesvoid
1019138232ShartiArch_TouchLib(GNode *gn)
10201590Srgrimes{
1021144387Sharti	struct arfile	*ar;	/* Open archive */
1022142173Sharti	struct utimbuf	times;	/* Times for utime() call */
10231590Srgrimes
1024144387Sharti	ar = ArchFindMember(gn->path, NULL, "r+");
1025144387Sharti	if (ar != NULL) {
1026144387Sharti		ArchArchiveTouch(ar, (int64_t)now);
1027144387Sharti		ArchArchiveClose(ar);
10281590Srgrimes
1029142173Sharti		times.actime = times.modtime = now;
1030142173Sharti		utime(gn->path, &times);
1031142173Sharti	}
10321590Srgrimes}
10331590Srgrimes
10341590Srgrimes/*-
10351590Srgrimes *-----------------------------------------------------------------------
10361590Srgrimes * Arch_MTime --
1037104696Sjmallett *	Return the modification time of a member of an archive, given its
1038104696Sjmallett *	name.
10391590Srgrimes *
10401590Srgrimes * Results:
1041138232Sharti *	The modification time(seconds).
1042142173Sharti *	XXXHB this should be a long.
10431590Srgrimes *
10441590Srgrimes * Side Effects:
10451590Srgrimes *	The mtime field of the given node is filled in with the value
10461590Srgrimes *	returned by the function.
10471590Srgrimes *
10481590Srgrimes *-----------------------------------------------------------------------
10491590Srgrimes */
10501590Srgrimesint
1051104696SjmallettArch_MTime(GNode *gn)
10521590Srgrimes{
1053144387Sharti	int64_t	mtime;
10541590Srgrimes
1055146580Sharti	mtime = ArchStatMember(Var_Value(ARCHIVE, gn),
1056146580Sharti	    Var_Value(TARGET, gn), TRUE);
10575814Sjkh
1058144387Sharti	if (mtime == INT_MIN) {
1059144387Sharti		mtime = 0;
1060142173Sharti	}
1061144387Sharti	gn->mtime = (int)mtime;			/* XXX */
1062144387Sharti	return (gn->mtime);
10631590Srgrimes}
10641590Srgrimes
10651590Srgrimes/*-
10661590Srgrimes *-----------------------------------------------------------------------
10671590Srgrimes * Arch_MemMTime --
10681590Srgrimes *	Given a non-existent archive member's node, get its modification
10691590Srgrimes *	time from its archived form, if it exists.
10701590Srgrimes *
10711590Srgrimes * Results:
10721590Srgrimes *	The modification time.
10731590Srgrimes *
10741590Srgrimes * Side Effects:
10751590Srgrimes *	The mtime field is filled in.
10761590Srgrimes *
10771590Srgrimes *-----------------------------------------------------------------------
10781590Srgrimes */
10791590Srgrimesint
1080138232ShartiArch_MemMTime(GNode *gn)
10811590Srgrimes{
1082142173Sharti	LstNode	*ln;
1083142173Sharti	GNode	*pgn;
1084142173Sharti	char	*nameStart;
1085142173Sharti	char	*nameEnd;
10861590Srgrimes
1087142173Sharti	for (ln = Lst_First(&gn->parents); ln != NULL; ln = Lst_Succ(ln)) {
1088142173Sharti		pgn = Lst_Datum(ln);
10891590Srgrimes
1090142173Sharti		if (pgn->type & OP_ARCHV) {
1091142173Sharti			/*
1092142173Sharti			 * If the parent is an archive specification and is
1093142173Sharti			 * being made and its member's name matches the name of
1094142173Sharti			 * the node we were given, record the modification time
1095142173Sharti			 * of the parent in the child. We keep searching its
1096142173Sharti			 * parents in case some other parent requires this
1097142173Sharti			 * child to exist...
1098142173Sharti			 */
1099142173Sharti			nameStart = strchr(pgn->name, '(') + 1;
1100142173Sharti			nameEnd = strchr(nameStart, ')');
11011590Srgrimes
1102142173Sharti			if (pgn->make && strncmp(nameStart, gn->name,
1103142173Sharti			    nameEnd - nameStart) == 0) {
1104142173Sharti				gn->mtime = Arch_MTime(pgn);
1105142173Sharti			}
1106142173Sharti		} else if (pgn->make) {
1107142173Sharti			/*
1108142173Sharti			 * Something which isn't a library depends on the
1109142173Sharti			 * existence of this target, so it needs to exist.
1110142173Sharti			 */
1111142173Sharti			gn->mtime = 0;
1112142173Sharti			break;
1113142173Sharti		}
11141590Srgrimes	}
1115142173Sharti	return (gn->mtime);
11161590Srgrimes}
11171590Srgrimes
11181590Srgrimes/*-
11191590Srgrimes *-----------------------------------------------------------------------
11201590Srgrimes * Arch_FindLib --
1121104696Sjmallett *	Search for a named library along the given search path.
11221590Srgrimes *
11231590Srgrimes * Results:
11241590Srgrimes *	None.
11251590Srgrimes *
11261590Srgrimes * Side Effects:
11271590Srgrimes *	The node's 'path' field is set to the found path (including the
11281590Srgrimes *	actual file name, not -l...). If the system can handle the -L
11291590Srgrimes *	flag when linking (or we cannot find the library), we assume that
11301590Srgrimes *	the user has placed the .LIBRARIES variable in the final linking
11311590Srgrimes *	command (or the linker will know where to find it) and set the
11321590Srgrimes *	TARGET variable for this node to be the node's name. Otherwise,
11331590Srgrimes *	we set the TARGET variable to be the full path of the library,
1134199419Sobrien *	as returned by Path_FindFile.
11351590Srgrimes *
11361590Srgrimes *-----------------------------------------------------------------------
11371590Srgrimes */
11381590Srgrimesvoid
1139144020ShartiArch_FindLib(GNode *gn, struct Path *path)
11401590Srgrimes{
1141142173Sharti	char	*libName;	/* file name for archive */
1142142173Sharti	size_t	sz;
11431590Srgrimes
1144142173Sharti	sz = strlen(gn->name) + 4;
1145142173Sharti	libName = emalloc(sz);
1146142173Sharti	snprintf(libName, sz, "lib%s.a", &gn->name[2]);
11471590Srgrimes
1148144020Sharti	gn->path = Path_FindFile(libName, path);
11491590Srgrimes
1150142173Sharti	free(libName);
11511590Srgrimes
11521590Srgrimes#ifdef LIBRARIES
1153142173Sharti	Var_Set(TARGET, gn->name, gn);
11541590Srgrimes#else
1155142173Sharti	Var_Set(TARGET, gn->path == NULL ? gn->name : gn->path, gn);
115618730Ssteve#endif /* LIBRARIES */
11571590Srgrimes}
11581590Srgrimes
11591590Srgrimes/*-
11601590Srgrimes *-----------------------------------------------------------------------
11611590Srgrimes * Arch_LibOODate --
11621590Srgrimes *	Decide if a node with the OP_LIB attribute is out-of-date. Called
1163104696Sjmallett *	from Make_OODate to make its life easier, with the library's
1164104696Sjmallett *	graph node.
11651590Srgrimes *
11661590Srgrimes *	There are several ways for a library to be out-of-date that are
11671590Srgrimes *	not available to ordinary files. In addition, there are ways
11681590Srgrimes *	that are open to regular files that are not available to
11691590Srgrimes *	libraries. A library that is only used as a source is never
11701590Srgrimes *	considered out-of-date by itself. This does not preclude the
11711590Srgrimes *	library's modification time from making its parent be out-of-date.
11721590Srgrimes *	A library will be considered out-of-date for any of these reasons,
11731590Srgrimes *	given that it is a target on a dependency line somewhere:
11741590Srgrimes *	    Its modification time is less than that of one of its
1175141270Sharti *		  sources (gn->mtime < gn->cmtime).
11761590Srgrimes *	    Its modification time is greater than the time at which the
1177141270Sharti *		  make began (i.e. it's been modified in the course
1178141270Sharti *		  of the make, probably by archiving).
11795814Sjkh *	    The modification time of one of its sources is greater than
11805814Sjkh *		  the one of its RANLIBMAG member (i.e. its table of contents
1181141270Sharti *		  is out-of-date). We don't compare of the archive time
11825814Sjkh *		  vs. TOC time because they can be too close. In my
11835814Sjkh *		  opinion we should not bother with the TOC at all since
11845814Sjkh *		  this is used by 'ar' rules that affect the data contents
11855814Sjkh *		  of the archive, not by ranlib rules, which affect the
11868874Srgrimes *		  TOC.
11871590Srgrimes *
11881590Srgrimes * Results:
11891590Srgrimes *	TRUE if the library is out-of-date. FALSE otherwise.
11901590Srgrimes *
11911590Srgrimes * Side Effects:
11921590Srgrimes *	The library will be hashed if it hasn't been already.
11931590Srgrimes *
11941590Srgrimes *-----------------------------------------------------------------------
11951590Srgrimes */
11961590SrgrimesBoolean
1197138232ShartiArch_LibOODate(GNode *gn)
11981590Srgrimes{
1199144387Sharti	int64_t	mtime;	/* The table-of-contents's mod time */
12001590Srgrimes
1201142173Sharti	if (OP_NOP(gn->type) && Lst_IsEmpty(&gn->children)) {
1202142173Sharti		return (FALSE);
1203142173Sharti	}
1204143105Sharti	if (gn->mtime > now || gn->mtime < gn->cmtime) {
1205142173Sharti		return (TRUE);
1206142173Sharti	}
1207142173Sharti
1208144387Sharti	mtime = ArchStatMember(gn->path, NULL, FALSE);
1209144387Sharti	if (mtime == INT64_MIN) {
1210142173Sharti		/*
1211144387Sharti		 * Not found. A library w/o a table of contents is out-of-date
1212142173Sharti		 */
1213142173Sharti		if (DEBUG(ARCH) || DEBUG(MAKE)) {
1214144387Sharti			Debug("No TOC...");
1215142173Sharti		}
1216142173Sharti		return (TRUE);
12171590Srgrimes	}
12181590Srgrimes
1219144387Sharti	/* XXX choose one. */
1220144387Sharti	if (DEBUG(ARCH) || DEBUG(MAKE)) {
1221144387Sharti		Debug("TOC modified %s...", Targ_FmtTime(mtime));
1222144387Sharti	}
1223144387Sharti	return (gn->cmtime > mtime);
12241590Srgrimes}
1225