source: trunk/src/kmk/arch.c@ 25

Last change on this file since 25 was 25, checked in by bird, 23 years ago

This commit was generated by cvs2svn to compensate for changes in r24,
which included commits to RCS files with non-trunk default branches.

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