Annotation of src/usr.bin/make/arch.c, Revision 1.4
1.4 ! niklas 1: /* $OpenBSD$ */
! 2: /* $NetBSD: arch.c,v 1.14 1996/03/12 18:04:27 christos Exp $ */
1.1 deraadt 3:
4: /*
5: * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
6: * Copyright (c) 1988, 1989 by Adam de Boor
7: * Copyright (c) 1989 by Berkeley Softworks
8: * All rights reserved.
9: *
10: * This code is derived from software contributed to Berkeley by
11: * Adam de Boor.
12: *
13: * Redistribution and use in source and binary forms, with or without
14: * modification, are permitted provided that the following conditions
15: * are met:
16: * 1. Redistributions of source code must retain the above copyright
17: * notice, this list of conditions and the following disclaimer.
18: * 2. Redistributions in binary form must reproduce the above copyright
19: * notice, this list of conditions and the following disclaimer in the
20: * documentation and/or other materials provided with the distribution.
21: * 3. All advertising materials mentioning features or use of this software
22: * must display the following acknowledgement:
23: * This product includes software developed by the University of
24: * California, Berkeley and its contributors.
25: * 4. Neither the name of the University nor the names of its contributors
26: * may be used to endorse or promote products derived from this software
27: * without specific prior written permission.
28: *
29: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39: * SUCH DAMAGE.
40: */
41:
42: #ifndef lint
43: #if 0
44: static char sccsid[] = "@(#)arch.c 5.7 (Berkeley) 12/28/90";
1.4 ! niklas 45: static char rcsid[] = "$NetBSD: arch.c,v 1.14 1996/03/12 18:04:27 christos Exp $";
1.1 deraadt 46: #else
1.4 ! niklas 47: static char rcsid[] = "$OpenBSD$";
1.1 deraadt 48: #endif
49: #endif /* not lint */
50:
51: /*-
52: * arch.c --
53: * Functions to manipulate libraries, archives and their members.
54: *
55: * Once again, cacheing/hashing comes into play in the manipulation
56: * of archives. The first time an archive is referenced, all of its members'
57: * headers are read and hashed and the archive closed again. All hashed
58: * archives are kept on a list which is searched each time an archive member
59: * is referenced.
60: *
61: * The interface to this module is:
62: * Arch_ParseArchive Given an archive specification, return a list
63: * of GNode's, one for each member in the spec.
64: * FAILURE is returned if the specification is
65: * invalid for some reason.
66: *
67: * Arch_Touch Alter the modification time of the archive
68: * member described by the given node to be
69: * the current time.
70: *
71: * Arch_TouchLib Update the modification time of the library
72: * described by the given node. This is special
73: * because it also updates the modification time
74: * of the library's table of contents.
75: *
76: * Arch_MTime Find the modification time of a member of
77: * an archive *in the archive*. The time is also
78: * placed in the member's GNode. Returns the
79: * modification time.
80: *
81: * Arch_MemTime Find the modification time of a member of
82: * an archive. Called when the member doesn't
83: * already exist. Looks in the archive for the
84: * modification time. Returns the modification
85: * time.
86: *
87: * Arch_FindLib Search for a library along a path. The
88: * library name in the GNode should be in
89: * -l<name> format.
90: *
91: * Arch_LibOODate Special function to decide if a library node
92: * is out-of-date.
93: *
94: * Arch_Init Initialize this module.
95: *
96: * Arch_End Cleanup this module.
97: */
98:
99: #include <sys/types.h>
100: #include <sys/stat.h>
101: #include <sys/time.h>
102: #include <sys/param.h>
103: #include <ctype.h>
104: #include <ar.h>
1.3 niklas 105: #if !defined(__svr4__) && !defined(__SVR4)
1.1 deraadt 106: #include <ranlib.h>
1.2 deraadt 107: #endif
1.3 niklas 108: #include <utime.h>
1.1 deraadt 109: #include <stdio.h>
110: #include <stdlib.h>
111: #include "make.h"
112: #include "hash.h"
113: #include "dir.h"
114: #include "config.h"
115:
116: static Lst archives; /* Lst of archives we've already examined */
117:
118: typedef struct Arch {
119: char *name; /* Name of archive */
120: Hash_Table members; /* All the members of the archive described
121: * by <name, struct ar_hdr *> key/value pairs */
122: } Arch;
123:
124: static int ArchFindArchive __P((ClientData, ClientData));
125: static void ArchFree __P((ClientData));
126: static struct ar_hdr *ArchStatMember __P((char *, char *, Boolean));
127: static FILE *ArchFindMember __P((char *, char *, struct ar_hdr *, char *));
128:
129: /*-
130: *-----------------------------------------------------------------------
131: * ArchFree --
132: * Free memory used by an archive
133: *
134: * Results:
135: * None.
136: *
137: * Side Effects:
138: * None.
139: *
140: *-----------------------------------------------------------------------
141: */
142: static void
143: ArchFree(ap)
144: ClientData ap;
145: {
146: Arch *a = (Arch *) ap;
147: Hash_Search search;
148: Hash_Entry *entry;
149:
150: /* Free memory from hash entries */
151: for (entry = Hash_EnumFirst(&a->members, &search);
152: entry != (Hash_Entry *)NULL;
153: entry = Hash_EnumNext(&search))
154: free((Address) Hash_GetValue (entry));
155:
156: free(a->name);
157: Hash_DeleteTable(&a->members);
158: free((Address) a);
159: }
160:
161:
162:
163: /*-
164: *-----------------------------------------------------------------------
165: * Arch_ParseArchive --
166: * Parse the archive specification in the given line and find/create
167: * the nodes for the specified archive members, placing their nodes
168: * on the given list.
169: *
170: * Results:
171: * SUCCESS if it was a valid specification. The linePtr is updated
172: * to point to the first non-space after the archive spec. The
173: * nodes for the members are placed on the given list.
174: *
175: * Side Effects:
176: * Some nodes may be created. The given list is extended.
177: *
178: *-----------------------------------------------------------------------
179: */
180: ReturnStatus
181: Arch_ParseArchive (linePtr, nodeLst, ctxt)
182: char **linePtr; /* Pointer to start of specification */
183: Lst nodeLst; /* Lst on which to place the nodes */
184: GNode *ctxt; /* Context in which to expand variables */
185: {
186: register char *cp; /* Pointer into line */
187: GNode *gn; /* New node */
188: char *libName; /* Library-part of specification */
189: char *memName; /* Member-part of specification */
190: char nameBuf[MAKE_BSIZE]; /* temporary place for node name */
191: char saveChar; /* Ending delimiter of member-name */
192: Boolean subLibName; /* TRUE if libName should have/had
193: * variable substitution performed on it */
194:
195: libName = *linePtr;
196:
197: subLibName = FALSE;
198:
199: for (cp = libName; *cp != '(' && *cp != '\0'; cp++) {
200: if (*cp == '$') {
201: /*
202: * Variable spec, so call the Var module to parse the puppy
203: * so we can safely advance beyond it...
204: */
205: int length;
206: Boolean freeIt;
207: char *result;
208:
209: result=Var_Parse(cp, ctxt, TRUE, &length, &freeIt);
210: if (result == var_Error) {
211: return(FAILURE);
212: } else {
213: subLibName = TRUE;
214: }
215:
216: if (freeIt) {
217: free(result);
218: }
219: cp += length-1;
220: }
221: }
222:
223: *cp++ = '\0';
224: if (subLibName) {
225: libName = Var_Subst(NULL, libName, ctxt, TRUE);
226: }
227:
228:
229: for (;;) {
230: /*
231: * First skip to the start of the member's name, mark that
232: * place and skip to the end of it (either white-space or
233: * a close paren).
234: */
235: Boolean doSubst = FALSE; /* TRUE if need to substitute in memName */
236:
237: while (*cp != '\0' && *cp != ')' && isspace (*cp)) {
238: cp++;
239: }
240: memName = cp;
241: while (*cp != '\0' && *cp != ')' && !isspace (*cp)) {
242: if (*cp == '$') {
243: /*
244: * Variable spec, so call the Var module to parse the puppy
245: * so we can safely advance beyond it...
246: */
247: int length;
248: Boolean freeIt;
249: char *result;
250:
251: result=Var_Parse(cp, ctxt, TRUE, &length, &freeIt);
252: if (result == var_Error) {
253: return(FAILURE);
254: } else {
255: doSubst = TRUE;
256: }
257:
258: if (freeIt) {
259: free(result);
260: }
261: cp += length;
262: } else {
263: cp++;
264: }
265: }
266:
267: /*
268: * If the specification ends without a closing parenthesis,
269: * chances are there's something wrong (like a missing backslash),
270: * so it's better to return failure than allow such things to happen
271: */
272: if (*cp == '\0') {
273: printf("No closing parenthesis in archive specification\n");
274: return (FAILURE);
275: }
276:
277: /*
278: * If we didn't move anywhere, we must be done
279: */
280: if (cp == memName) {
281: break;
282: }
283:
284: saveChar = *cp;
285: *cp = '\0';
286:
287: /*
288: * XXX: This should be taken care of intelligently by
289: * SuffExpandChildren, both for the archive and the member portions.
290: */
291: /*
292: * If member contains variables, try and substitute for them.
293: * This will slow down archive specs with dynamic sources, of course,
294: * since we'll be (non-)substituting them three times, but them's
295: * the breaks -- we need to do this since SuffExpandChildren calls
296: * us, otherwise we could assume the thing would be taken care of
297: * later.
298: */
299: if (doSubst) {
300: char *buf;
301: char *sacrifice;
302: char *oldMemName = memName;
303:
304: memName = Var_Subst(NULL, memName, ctxt, TRUE);
305:
306: /*
307: * Now form an archive spec and recurse to deal with nested
308: * variables and multi-word variable values.... The results
309: * are just placed at the end of the nodeLst we're returning.
310: */
311: buf = sacrifice = emalloc(strlen(memName)+strlen(libName)+3);
312:
313: sprintf(buf, "%s(%s)", libName, memName);
314:
315: if (strchr(memName, '$') && strcmp(memName, oldMemName) == 0) {
316: /*
317: * Must contain dynamic sources, so we can't deal with it now.
318: * Just create an ARCHV node for the thing and let
319: * SuffExpandChildren handle it...
320: */
321: gn = Targ_FindNode(buf, TARG_CREATE);
322:
323: if (gn == NILGNODE) {
324: free(buf);
325: return(FAILURE);
326: } else {
327: gn->type |= OP_ARCHV;
328: (void)Lst_AtEnd(nodeLst, (ClientData)gn);
329: }
330: } else if (Arch_ParseArchive(&sacrifice, nodeLst, ctxt)!=SUCCESS) {
331: /*
332: * Error in nested call -- free buffer and return FAILURE
333: * ourselves.
334: */
335: free(buf);
336: return(FAILURE);
337: }
338: /*
339: * Free buffer and continue with our work.
340: */
341: free(buf);
342: } else if (Dir_HasWildcards(memName)) {
343: Lst members = Lst_Init(FALSE);
344: char *member;
345:
346: Dir_Expand(memName, dirSearchPath, members);
347: while (!Lst_IsEmpty(members)) {
348: member = (char *)Lst_DeQueue(members);
349:
350: sprintf(nameBuf, "%s(%s)", libName, member);
351: free(member);
352: gn = Targ_FindNode (nameBuf, TARG_CREATE);
353: if (gn == NILGNODE) {
354: return (FAILURE);
355: } else {
356: /*
357: * We've found the node, but have to make sure the rest of
358: * the world knows it's an archive member, without having
359: * to constantly check for parentheses, so we type the
360: * thing with the OP_ARCHV bit before we place it on the
361: * end of the provided list.
362: */
363: gn->type |= OP_ARCHV;
364: (void) Lst_AtEnd (nodeLst, (ClientData)gn);
365: }
366: }
367: Lst_Destroy(members, NOFREE);
368: } else {
369: sprintf(nameBuf, "%s(%s)", libName, memName);
370: gn = Targ_FindNode (nameBuf, TARG_CREATE);
371: if (gn == NILGNODE) {
372: return (FAILURE);
373: } else {
374: /*
375: * We've found the node, but have to make sure the rest of the
376: * world knows it's an archive member, without having to
377: * constantly check for parentheses, so we type the thing with
378: * the OP_ARCHV bit before we place it on the end of the
379: * provided list.
380: */
381: gn->type |= OP_ARCHV;
382: (void) Lst_AtEnd (nodeLst, (ClientData)gn);
383: }
384: }
385: if (doSubst) {
386: free(memName);
387: }
388:
389: *cp = saveChar;
390: }
391:
392: /*
393: * If substituted libName, free it now, since we need it no longer.
394: */
395: if (subLibName) {
396: free(libName);
397: }
398:
399: /*
400: * We promised the pointer would be set up at the next non-space, so
401: * we must advance cp there before setting *linePtr... (note that on
402: * entrance to the loop, cp is guaranteed to point at a ')')
403: */
404: do {
405: cp++;
406: } while (*cp != '\0' && isspace (*cp));
407:
408: *linePtr = cp;
409: return (SUCCESS);
410: }
411:
412: /*-
413: *-----------------------------------------------------------------------
414: * ArchFindArchive --
415: * See if the given archive is the one we are looking for. Called
416: * From ArchStatMember and ArchFindMember via Lst_Find.
417: *
418: * Results:
419: * 0 if it is, non-zero if it isn't.
420: *
421: * Side Effects:
422: * None.
423: *
424: *-----------------------------------------------------------------------
425: */
426: static int
427: ArchFindArchive (ar, archName)
428: ClientData ar; /* Current list element */
429: ClientData archName; /* Name we want */
430: {
431: return (strcmp ((char *) archName, ((Arch *) ar)->name));
432: }
433:
434: /*-
435: *-----------------------------------------------------------------------
436: * ArchStatMember --
437: * Locate a member of an archive, given the path of the archive and
438: * the path of the desired member.
439: *
440: * Results:
441: * A pointer to the current struct ar_hdr structure for the member. Note
442: * That no position is returned, so this is not useful for touching
443: * archive members. This is mostly because we have no assurances that
444: * The archive will remain constant after we read all the headers, so
445: * there's not much point in remembering the position...
446: *
447: * Side Effects:
448: *
449: *-----------------------------------------------------------------------
450: */
451: static struct ar_hdr *
452: ArchStatMember (archive, member, hash)
453: char *archive; /* Path to the archive */
454: char *member; /* Name of member. If it is a path, only the
455: * last component is used. */
456: Boolean hash; /* TRUE if archive should be hashed if not
457: * already so. */
458: {
459: #define AR_MAX_NAME_LEN (sizeof(arh.ar_name)-1)
460: FILE * arch; /* Stream to archive */
461: int size; /* Size of archive member */
462: char *cp; /* Useful character pointer */
463: char magic[SARMAG];
464: LstNode ln; /* Lst member containing archive descriptor */
465: Arch *ar; /* Archive descriptor */
466: Hash_Entry *he; /* Entry containing member's description */
467: struct ar_hdr arh; /* archive-member header for reading archive */
468: char memName[MAXPATHLEN+1];
469: /* Current member name while hashing. */
470:
471: /*
472: * Because of space constraints and similar things, files are archived
473: * using their final path components, not the entire thing, so we need
474: * to point 'member' to the final component, if there is one, to make
475: * the comparisons easier...
476: */
477: cp = strrchr (member, '/');
478: if (cp != (char *) NULL) {
479: member = cp + 1;
480: }
481:
482: ln = Lst_Find (archives, (ClientData) archive, ArchFindArchive);
483: if (ln != NILLNODE) {
484: ar = (Arch *) Lst_Datum (ln);
485:
486: he = Hash_FindEntry (&ar->members, member);
487:
488: if (he != (Hash_Entry *) NULL) {
489: return ((struct ar_hdr *) Hash_GetValue (he));
490: } else {
491: /* Try truncated name */
492: char copy[AR_MAX_NAME_LEN+1];
493: int len = strlen (member);
494:
495: if (len > AR_MAX_NAME_LEN) {
496: len = AR_MAX_NAME_LEN;
497: strncpy(copy, member, AR_MAX_NAME_LEN);
498: copy[AR_MAX_NAME_LEN] = '\0';
499: }
1.2 deraadt 500: if ((he = Hash_FindEntry (&ar->members, copy)) != NULL)
1.1 deraadt 501: return ((struct ar_hdr *) Hash_GetValue (he));
502: return ((struct ar_hdr *) NULL);
503: }
504: }
505:
506: if (!hash) {
507: /*
508: * Caller doesn't want the thing hashed, just use ArchFindMember
509: * to read the header for the member out and close down the stream
510: * again. Since the archive is not to be hashed, we assume there's
511: * no need to allocate extra room for the header we're returning,
512: * so just declare it static.
513: */
514: static struct ar_hdr sarh;
515:
516: arch = ArchFindMember(archive, member, &sarh, "r");
517:
518: if (arch == (FILE *)NULL) {
519: return ((struct ar_hdr *)NULL);
520: } else {
521: fclose(arch);
522: return (&sarh);
523: }
524: }
525:
526: /*
527: * We don't have this archive on the list yet, so we want to find out
528: * everything that's in it and cache it so we can get at it quickly.
529: */
530: arch = fopen (archive, "r");
531: if (arch == (FILE *) NULL) {
532: return ((struct ar_hdr *) NULL);
533: }
534:
535: /*
536: * We use the ARMAG string to make sure this is an archive we
537: * can handle...
538: */
539: if ((fread (magic, SARMAG, 1, arch) != 1) ||
540: (strncmp (magic, ARMAG, SARMAG) != 0)) {
541: fclose (arch);
542: return ((struct ar_hdr *) NULL);
543: }
544:
545: ar = (Arch *)emalloc (sizeof (Arch));
546: ar->name = strdup (archive);
547: Hash_InitTable (&ar->members, -1);
548: memName[AR_MAX_NAME_LEN] = '\0';
549:
550: while (fread ((char *)&arh, sizeof (struct ar_hdr), 1, arch) == 1) {
551: if (strncmp ( arh.ar_fmag, ARFMAG, sizeof (arh.ar_fmag)) != 0) {
552: /*
553: * The header is bogus, so the archive is bad
554: * and there's no way we can recover...
555: */
556: fclose (arch);
557: Hash_DeleteTable (&ar->members);
558: free ((Address)ar);
559: return ((struct ar_hdr *) NULL);
560: } else {
561: (void) strncpy (memName, arh.ar_name, sizeof(arh.ar_name));
562: for (cp = &memName[AR_MAX_NAME_LEN]; *cp == ' '; cp--) {
563: continue;
564: }
565: cp[1] = '\0';
566:
1.3 niklas 567: #if defined(__svr4__) || defined(__SVR4)
568: /* svr4 names are slash terminated */
569: if (cp[0] == '/')
570: cp[0] = '\0';
571: #endif
572:
1.1 deraadt 573: #ifdef AR_EFMT1
574: /*
575: * BSD 4.4 extended AR format: #1/<namelen>, with name as the
576: * first <namelen> bytes of the file
577: */
578: if (strncmp(memName, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0 &&
579: isdigit(memName[sizeof(AR_EFMT1) - 1])) {
580:
581: unsigned int elen = atoi(&memName[sizeof(AR_EFMT1)-1]);
582:
583: if (elen > MAXPATHLEN) {
584: fclose (arch);
585: Hash_DeleteTable (&ar->members);
586: free ((Address)ar);
587: return ((struct ar_hdr *) NULL);
588: }
589: if (fread (memName, elen, 1, arch) != 1) {
590: fclose (arch);
591: Hash_DeleteTable (&ar->members);
592: free ((Address)ar);
593: return ((struct ar_hdr *) NULL);
594: }
595: memName[elen] = '\0';
596: fseek (arch, -elen, 1);
597: if (DEBUG(ARCH) || DEBUG(MAKE)) {
598: printf("ArchStat: Extended format entry for %s\n", memName);
599: }
600: }
601: #endif
602:
603: he = Hash_CreateEntry (&ar->members, memName, (Boolean *)NULL);
604: Hash_SetValue (he, (ClientData)emalloc (sizeof (struct ar_hdr)));
605: memcpy ((Address)Hash_GetValue (he), (Address)&arh,
606: sizeof (struct ar_hdr));
607: }
608: /*
609: * We need to advance the stream's pointer to the start of the
610: * next header. Files are padded with newlines to an even-byte
611: * boundary, so we need to extract the size of the file from the
612: * 'size' field of the header and round it up during the seek.
613: */
614: arh.ar_size[sizeof(arh.ar_size)-1] = '\0';
615: size = (int) strtol(arh.ar_size, NULL, 10);
616: fseek (arch, (size + 1) & ~1, 1);
617: }
618:
619: fclose (arch);
620:
621: (void) Lst_AtEnd (archives, (ClientData) ar);
622:
623: /*
624: * Now that the archive has been read and cached, we can look into
625: * the hash table to find the desired member's header.
626: */
627: he = Hash_FindEntry (&ar->members, member);
628:
629: if (he != (Hash_Entry *) NULL) {
630: return ((struct ar_hdr *) Hash_GetValue (he));
631: } else {
632: return ((struct ar_hdr *) NULL);
633: }
634: }
635:
636: /*-
637: *-----------------------------------------------------------------------
638: * ArchFindMember --
639: * Locate a member of an archive, given the path of the archive and
640: * the path of the desired member. If the archive is to be modified,
641: * the mode should be "r+", if not, it should be "r".
642: *
643: * Results:
644: * An FILE *, opened for reading and writing, positioned at the
645: * start of the member's struct ar_hdr, or NULL if the member was
646: * nonexistent. The current struct ar_hdr for member.
647: *
648: * Side Effects:
649: * The passed struct ar_hdr structure is filled in.
650: *
651: *-----------------------------------------------------------------------
652: */
653: static FILE *
654: ArchFindMember (archive, member, arhPtr, mode)
655: char *archive; /* Path to the archive */
656: char *member; /* Name of member. If it is a path, only the
657: * last component is used. */
658: struct ar_hdr *arhPtr; /* Pointer to header structure to be filled in */
659: char *mode; /* The mode for opening the stream */
660: {
661: FILE * arch; /* Stream to archive */
662: int size; /* Size of archive member */
663: char *cp; /* Useful character pointer */
664: char magic[SARMAG];
665: int len, tlen;
666:
667: arch = fopen (archive, mode);
668: if (arch == (FILE *) NULL) {
669: return ((FILE *) NULL);
670: }
671:
672: /*
673: * We use the ARMAG string to make sure this is an archive we
674: * can handle...
675: */
676: if ((fread (magic, SARMAG, 1, arch) != 1) ||
677: (strncmp (magic, ARMAG, SARMAG) != 0)) {
678: fclose (arch);
679: return ((FILE *) NULL);
680: }
681:
682: /*
683: * Because of space constraints and similar things, files are archived
684: * using their final path components, not the entire thing, so we need
685: * to point 'member' to the final component, if there is one, to make
686: * the comparisons easier...
687: */
688: cp = strrchr (member, '/');
689: if (cp != (char *) NULL) {
690: member = cp + 1;
691: }
692: len = tlen = strlen (member);
693: if (len > sizeof (arhPtr->ar_name)) {
694: tlen = sizeof (arhPtr->ar_name);
695: }
696:
697: while (fread ((char *)arhPtr, sizeof (struct ar_hdr), 1, arch) == 1) {
698: if (strncmp(arhPtr->ar_fmag, ARFMAG, sizeof (arhPtr->ar_fmag) ) != 0) {
699: /*
700: * The header is bogus, so the archive is bad
701: * and there's no way we can recover...
702: */
703: fclose (arch);
704: return ((FILE *) NULL);
705: } else if (strncmp (member, arhPtr->ar_name, tlen) == 0) {
706: /*
707: * If the member's name doesn't take up the entire 'name' field,
708: * we have to be careful of matching prefixes. Names are space-
709: * padded to the right, so if the character in 'name' at the end
710: * of the matched string is anything but a space, this isn't the
711: * member we sought.
712: */
713: if (tlen != sizeof(arhPtr->ar_name) && arhPtr->ar_name[tlen] != ' '){
714: goto skip;
715: } else {
716: /*
717: * To make life easier, we reposition the file at the start
718: * of the header we just read before we return the stream.
719: * In a more general situation, it might be better to leave
720: * the file at the actual member, rather than its header, but
721: * not here...
722: */
723: fseek (arch, -sizeof(struct ar_hdr), 1);
724: return (arch);
725: }
726: } else
727: #ifdef AR_EFMT1
728: /*
729: * BSD 4.4 extended AR format: #1/<namelen>, with name as the
730: * first <namelen> bytes of the file
731: */
732: if (strncmp(arhPtr->ar_name, AR_EFMT1,
733: sizeof(AR_EFMT1) - 1) == 0 &&
734: isdigit(arhPtr->ar_name[sizeof(AR_EFMT1) - 1])) {
735:
736: unsigned int elen = atoi(&arhPtr->ar_name[sizeof(AR_EFMT1)-1]);
737: char ename[MAXPATHLEN];
738:
739: if (elen > MAXPATHLEN) {
740: fclose (arch);
741: return NULL;
742: }
743: if (fread (ename, elen, 1, arch) != 1) {
744: fclose (arch);
745: return NULL;
746: }
747: ename[elen] = '\0';
748: if (DEBUG(ARCH) || DEBUG(MAKE)) {
749: printf("ArchFind: Extended format entry for %s\n", ename);
750: }
751: if (strncmp(ename, member, len) == 0) {
752: /* Found as extended name */
753: fseek (arch, -sizeof(struct ar_hdr) - elen, 1);
754: return (arch);
755: }
756: fseek (arch, -elen, 1);
757: goto skip;
758: } else
759: #endif
760: {
761: skip:
762: /*
763: * This isn't the member we're after, so we need to advance the
764: * stream's pointer to the start of the next header. Files are
765: * padded with newlines to an even-byte boundary, so we need to
766: * extract the size of the file from the 'size' field of the
767: * header and round it up during the seek.
768: */
769: arhPtr->ar_size[sizeof(arhPtr->ar_size)-1] = '\0';
770: size = (int) strtol(arhPtr->ar_size, NULL, 10);
771: fseek (arch, (size + 1) & ~1, 1);
772: }
773: }
774:
775: /*
776: * We've looked everywhere, but the member is not to be found. Close the
777: * archive and return NULL -- an error.
778: */
779: fclose (arch);
780: return ((FILE *) NULL);
781: }
782:
783: /*-
784: *-----------------------------------------------------------------------
785: * Arch_Touch --
786: * Touch a member of an archive.
787: *
788: * Results:
789: * The 'time' field of the member's header is updated.
790: *
791: * Side Effects:
792: * The modification time of the entire archive is also changed.
793: * For a library, this could necessitate the re-ranlib'ing of the
794: * whole thing.
795: *
796: *-----------------------------------------------------------------------
797: */
798: void
799: Arch_Touch (gn)
800: GNode *gn; /* Node of member to touch */
801: {
802: FILE * arch; /* Stream open to archive, positioned properly */
803: struct ar_hdr arh; /* Current header describing member */
804: char *p1, *p2;
805:
806: arch = ArchFindMember(Var_Value (ARCHIVE, gn, &p1),
807: Var_Value (TARGET, gn, &p2),
808: &arh, "r+");
809: if (p1)
810: free(p1);
811: if (p2)
812: free(p2);
813: sprintf(arh.ar_date, "%-12ld", (long) now);
814:
815: if (arch != (FILE *) NULL) {
816: (void)fwrite ((char *)&arh, sizeof (struct ar_hdr), 1, arch);
817: fclose (arch);
818: }
819: }
820:
821: /*-
822: *-----------------------------------------------------------------------
823: * Arch_TouchLib --
824: * Given a node which represents a library, touch the thing, making
825: * sure that the table of contents also is touched.
826: *
827: * Results:
828: * None.
829: *
830: * Side Effects:
831: * Both the modification time of the library and of the RANLIBMAG
832: * member are set to 'now'.
833: *
834: *-----------------------------------------------------------------------
835: */
836: void
837: Arch_TouchLib (gn)
838: GNode *gn; /* The node of the library to touch */
839: {
1.3 niklas 840: #ifdef RANLIBMAG
1.1 deraadt 841: FILE * arch; /* Stream open to archive */
842: struct ar_hdr arh; /* Header describing table of contents */
1.3 niklas 843: struct utimbuf times; /* Times for utime() call */
1.1 deraadt 844:
845: arch = ArchFindMember (gn->path, RANLIBMAG, &arh, "r+");
846: sprintf(arh.ar_date, "%-12ld", (long) now);
847:
848: if (arch != (FILE *) NULL) {
849: (void)fwrite ((char *)&arh, sizeof (struct ar_hdr), 1, arch);
850: fclose (arch);
851:
1.3 niklas 852: times.actime = times.modtime = now;
853: utime(gn->path, ×);
1.1 deraadt 854: }
1.3 niklas 855: #endif
1.1 deraadt 856: }
857:
858: /*-
859: *-----------------------------------------------------------------------
860: * Arch_MTime --
861: * Return the modification time of a member of an archive.
862: *
863: * Results:
864: * The modification time (seconds).
865: *
866: * Side Effects:
867: * The mtime field of the given node is filled in with the value
868: * returned by the function.
869: *
870: *-----------------------------------------------------------------------
871: */
872: int
873: Arch_MTime (gn)
874: GNode *gn; /* Node describing archive member */
875: {
876: struct ar_hdr *arhPtr; /* Header of desired member */
877: int modTime; /* Modification time as an integer */
878: char *p1, *p2;
879:
880: arhPtr = ArchStatMember (Var_Value (ARCHIVE, gn, &p1),
881: Var_Value (TARGET, gn, &p2),
882: TRUE);
883: if (p1)
884: free(p1);
885: if (p2)
886: free(p2);
887:
888: if (arhPtr != (struct ar_hdr *) NULL) {
889: modTime = (int) strtol(arhPtr->ar_date, NULL, 10);
890: } else {
891: modTime = 0;
892: }
893:
894: gn->mtime = modTime;
895: return (modTime);
896: }
897:
898: /*-
899: *-----------------------------------------------------------------------
900: * Arch_MemMTime --
901: * Given a non-existent archive member's node, get its modification
902: * time from its archived form, if it exists.
903: *
904: * Results:
905: * The modification time.
906: *
907: * Side Effects:
908: * The mtime field is filled in.
909: *
910: *-----------------------------------------------------------------------
911: */
912: int
913: Arch_MemMTime (gn)
914: GNode *gn;
915: {
916: LstNode ln;
917: GNode *pgn;
918: char *nameStart,
919: *nameEnd;
920:
921: if (Lst_Open (gn->parents) != SUCCESS) {
922: gn->mtime = 0;
923: return (0);
924: }
925: while ((ln = Lst_Next (gn->parents)) != NILLNODE) {
926: pgn = (GNode *) Lst_Datum (ln);
927:
928: if (pgn->type & OP_ARCHV) {
929: /*
930: * If the parent is an archive specification and is being made
931: * and its member's name matches the name of the node we were
932: * given, record the modification time of the parent in the
933: * child. We keep searching its parents in case some other
934: * parent requires this child to exist...
935: */
936: nameStart = strchr (pgn->name, '(') + 1;
937: nameEnd = strchr (nameStart, ')');
938:
939: if (pgn->make &&
940: strncmp(nameStart, gn->name, nameEnd - nameStart) == 0) {
941: gn->mtime = Arch_MTime(pgn);
942: }
943: } else if (pgn->make) {
944: /*
945: * Something which isn't a library depends on the existence of
946: * this target, so it needs to exist.
947: */
948: gn->mtime = 0;
949: break;
950: }
951: }
952:
953: Lst_Close (gn->parents);
954:
955: return (gn->mtime);
956: }
957:
958: /*-
959: *-----------------------------------------------------------------------
960: * Arch_FindLib --
961: * Search for a library along the given search path.
962: *
963: * Results:
964: * None.
965: *
966: * Side Effects:
967: * The node's 'path' field is set to the found path (including the
968: * actual file name, not -l...). If the system can handle the -L
969: * flag when linking (or we cannot find the library), we assume that
970: * the user has placed the .LIBRARIES variable in the final linking
971: * command (or the linker will know where to find it) and set the
972: * TARGET variable for this node to be the node's name. Otherwise,
973: * we set the TARGET variable to be the full path of the library,
974: * as returned by Dir_FindFile.
975: *
976: *-----------------------------------------------------------------------
977: */
978: void
979: Arch_FindLib (gn, path)
980: GNode *gn; /* Node of library to find */
981: Lst path; /* Search path */
982: {
983: char *libName; /* file name for archive */
984:
985: libName = (char *)emalloc (strlen (gn->name) + 6 - 2);
986: sprintf(libName, "lib%s.a", &gn->name[2]);
987:
988: gn->path = Dir_FindFile (libName, path);
989:
990: free (libName);
991:
992: #ifdef LIBRARIES
993: Var_Set (TARGET, gn->name, gn);
994: #else
995: Var_Set (TARGET, gn->path == (char *) NULL ? gn->name : gn->path, gn);
1.3 niklas 996: #endif /* LIBRARIES */
1.1 deraadt 997: }
998:
999: /*-
1000: *-----------------------------------------------------------------------
1001: * Arch_LibOODate --
1002: * Decide if a node with the OP_LIB attribute is out-of-date. Called
1003: * from Make_OODate to make its life easier.
1004: *
1005: * There are several ways for a library to be out-of-date that are
1006: * not available to ordinary files. In addition, there are ways
1007: * that are open to regular files that are not available to
1008: * libraries. A library that is only used as a source is never
1009: * considered out-of-date by itself. This does not preclude the
1010: * library's modification time from making its parent be out-of-date.
1011: * A library will be considered out-of-date for any of these reasons,
1012: * given that it is a target on a dependency line somewhere:
1013: * Its modification time is less than that of one of its
1014: * sources (gn->mtime < gn->cmtime).
1015: * Its modification time is greater than the time at which the
1016: * make began (i.e. it's been modified in the course
1017: * of the make, probably by archiving).
1018: * The modification time of one of its sources is greater than
1019: * the one of its RANLIBMAG member (i.e. its table of contents
1020: * is out-of-date). We don't compare of the archive time
1021: * vs. TOC time because they can be too close. In my
1022: * opinion we should not bother with the TOC at all since
1023: * this is used by 'ar' rules that affect the data contents
1024: * of the archive, not by ranlib rules, which affect the
1025: * TOC.
1026: *
1027: * Results:
1028: * TRUE if the library is out-of-date. FALSE otherwise.
1029: *
1030: * Side Effects:
1031: * The library will be hashed if it hasn't been already.
1032: *
1033: *-----------------------------------------------------------------------
1034: */
1035: Boolean
1036: Arch_LibOODate (gn)
1037: GNode *gn; /* The library's graph node */
1038: {
1039: Boolean oodate;
1040:
1041: if (OP_NOP(gn->type) && Lst_IsEmpty(gn->children)) {
1042: oodate = FALSE;
1043: } else if ((gn->mtime > now) || (gn->mtime < gn->cmtime)) {
1044: oodate = TRUE;
1045: } else {
1.2 deraadt 1046: #ifdef RANLIBMAG
1.1 deraadt 1047: struct ar_hdr *arhPtr; /* Header for __.SYMDEF */
1048: int modTimeTOC; /* The table-of-contents's mod time */
1049:
1050: arhPtr = ArchStatMember (gn->path, RANLIBMAG, FALSE);
1051:
1052: if (arhPtr != (struct ar_hdr *)NULL) {
1053: modTimeTOC = (int) strtol(arhPtr->ar_date, NULL, 10);
1054:
1055: if (DEBUG(ARCH) || DEBUG(MAKE)) {
1056: printf("%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC));
1057: }
1058: oodate = (gn->cmtime > modTimeTOC);
1059: } else {
1060: /*
1061: * A library w/o a table of contents is out-of-date
1062: */
1063: if (DEBUG(ARCH) || DEBUG(MAKE)) {
1064: printf("No t.o.c....");
1065: }
1066: oodate = TRUE;
1067: }
1.2 deraadt 1068: #else
1.4 ! niklas 1069: oodate = FALSE;
1.2 deraadt 1070: #endif
1.1 deraadt 1071: }
1072: return (oodate);
1073: }
1074:
1075: /*-
1076: *-----------------------------------------------------------------------
1077: * Arch_Init --
1078: * Initialize things for this module.
1079: *
1080: * Results:
1081: * None.
1082: *
1083: * Side Effects:
1084: * The 'archives' list is initialized.
1085: *
1086: *-----------------------------------------------------------------------
1087: */
1088: void
1089: Arch_Init ()
1090: {
1091: archives = Lst_Init (FALSE);
1092: }
1093:
1094:
1095:
1096: /*-
1097: *-----------------------------------------------------------------------
1098: * Arch_End --
1099: * Cleanup things for this module.
1100: *
1101: * Results:
1102: * None.
1103: *
1104: * Side Effects:
1105: * The 'archives' list is freed
1106: *
1107: *-----------------------------------------------------------------------
1108: */
1109: void
1110: Arch_End ()
1111: {
1112: Lst_Destroy(archives, ArchFree);
1113: }