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