arch.c revision 1.218 1 /* $NetBSD: arch.c,v 1.218 2024/05/31 05:50:11 rillig Exp $ */
2
3 /*
4 * Copyright (c) 1988, 1989, 1990, 1993
5 * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 /*
36 * Copyright (c) 1989 by Berkeley Softworks
37 * All rights reserved.
38 *
39 * This code is derived from software contributed to Berkeley by
40 * Adam de Boor.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution.
50 * 3. All advertising materials mentioning features or use of this software
51 * must display the following acknowledgement:
52 * This product includes software developed by the University of
53 * California, Berkeley and its contributors.
54 * 4. Neither the name of the University nor the names of its contributors
55 * may be used to endorse or promote products derived from this software
56 * without specific prior written permission.
57 *
58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * SUCH DAMAGE.
69 */
70
71 /*
72 * Manipulate libraries, archives and their members.
73 *
74 * The first time an archive is referenced, all of its members' headers are
75 * read and cached and the archive closed again. All cached archives are kept
76 * on a list which is searched each time an archive member is referenced.
77 *
78 * The interface to this module is:
79 *
80 * Arch_Init Initialize this module.
81 *
82 * Arch_End Clean up this module.
83 *
84 * Arch_ParseArchive
85 * Parse an archive specification such as
86 * "archive.a(member1 member2)".
87 *
88 * Arch_Touch Alter the modification time of the archive
89 * member described by the given node to be
90 * the time when make was started.
91 *
92 * Arch_TouchLib Update the modification time of the library
93 * described by the given node. This is special
94 * because it also updates the modification time
95 * of the library's table of contents.
96 *
97 * Arch_UpdateMTime
98 * Find the modification time of a member of
99 * an archive *in the archive* and place it in the
100 * member's GNode.
101 *
102 * Arch_UpdateMemberMTime
103 * Find the modification time of a member of
104 * an archive. Called when the member doesn't
105 * already exist. Looks in the archive for the
106 * modification time. Returns the modification
107 * time.
108 *
109 * Arch_FindLib Search for a library along a path. The
110 * library name in the GNode should be in
111 * -l<name> format.
112 *
113 * Arch_LibOODate Decide if a library node is out-of-date.
114 */
115
116 #include <sys/types.h>
117 #include <sys/stat.h>
118 #include <sys/time.h>
119 #include <sys/param.h>
120
121 #include <ar.h>
122 #include <utime.h>
123
124 #include "make.h"
125 #include "dir.h"
126 #include "config.h"
127
128 /* "@(#)arch.c 8.2 (Berkeley) 1/2/94" */
129 MAKE_RCSID("$NetBSD: arch.c,v 1.218 2024/05/31 05:50:11 rillig Exp $");
130
131 typedef struct List ArchList;
132 typedef struct ListNode ArchListNode;
133
134 static ArchList archives; /* The archives we've already examined */
135
136 typedef struct Arch {
137 char *name;
138 HashTable members; /* All the members of the archive described
139 * by <name, struct ar_hdr *> key/value pairs */
140 char *fnametab; /* Extended name table strings */
141 size_t fnamesize; /* Size of the string table */
142 } Arch;
143
144 static FILE *ArchFindMember(const char *, const char *,
145 struct ar_hdr *, const char *);
146 #if defined(__svr4__) || defined(__SVR4) || defined(__ELF__)
147 #define SVR4ARCHIVES
148 static int ArchSVR4Entry(Arch *, char *, size_t, FILE *);
149 #endif
150
151
152 #ifdef CLEANUP
153 static void
154 ArchFree(Arch *a)
155 {
156 HashIter hi;
157
158 HashIter_Init(&hi, &a->members);
159 while (HashIter_Next(&hi))
160 free(hi.entry->value);
161
162 free(a->name);
163 free(a->fnametab);
164 HashTable_Done(&a->members);
165 free(a);
166 }
167 #endif
168
169 /* Return "archive(member)". */
170 MAKE_ATTR_NOINLINE static char *
171 FullName(const char *archive, const char *member)
172 {
173 Buffer buf;
174 Buf_Init(&buf);
175 Buf_AddStr(&buf, archive);
176 Buf_AddStr(&buf, "(");
177 Buf_AddStr(&buf, member);
178 Buf_AddStr(&buf, ")");
179 return Buf_DoneData(&buf);
180 }
181
182 /*
183 * Parse an archive specification such as "archive.a(member1 member2.${EXT})",
184 * adding nodes for the expanded members to gns. If successful, advance pp
185 * beyond the archive specification and any trailing whitespace.
186 */
187 bool
188 Arch_ParseArchive(char **pp, GNodeList *gns, GNode *scope)
189 {
190 char *spec; /* For modifying some bytes of *pp */
191 const char *cp; /* Pointer into line */
192 GNode *gn; /* New node */
193 FStr lib; /* Library-part of specification */
194 FStr mem; /* Member-part of specification */
195 char saveChar; /* Ending delimiter of member-name */
196 bool expandLib; /* Whether the parsed lib contains
197 * expressions that need to be expanded */
198
199 spec = *pp;
200 lib = FStr_InitRefer(spec);
201 expandLib = false;
202
203 for (cp = lib.str; *cp != '(' && *cp != '\0';) {
204 if (*cp == '$') {
205 /* Expand nested expressions. */
206 /* XXX: This code can probably be shortened. */
207 const char *nested_p = cp;
208 FStr result;
209 bool isError;
210
211 /* XXX: is expanded twice: once here and once below */
212 result = Var_Parse(&nested_p, scope, VARE_UNDEFERR);
213 /* TODO: handle errors */
214 isError = result.str == var_Error;
215 FStr_Done(&result);
216 if (isError)
217 return false;
218
219 expandLib = true;
220 cp += nested_p - cp;
221 } else
222 cp++;
223 }
224
225 spec[cp++ - spec] = '\0';
226 if (expandLib)
227 Var_Expand(&lib, scope, VARE_UNDEFERR);
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 bool doSubst = false;
236
237 cpp_skip_whitespace(&cp);
238
239 mem = FStr_InitRefer(cp);
240 while (*cp != '\0' && *cp != ')' && !ch_isspace(*cp)) {
241 if (*cp == '$') {
242 /* Expand nested expressions. */
243 /*
244 * XXX: This code can probably be shortened.
245 */
246 FStr result;
247 bool isError;
248 const char *nested_p = cp;
249
250 result = Var_Parse(&nested_p, scope,
251 VARE_UNDEFERR);
252 /* TODO: handle errors */
253 isError = result.str == var_Error;
254 FStr_Done(&result);
255
256 if (isError)
257 return false;
258
259 doSubst = true;
260 cp += nested_p - cp;
261 } else {
262 cp++;
263 }
264 }
265
266 if (*cp == '\0') {
267 Parse_Error(PARSE_FATAL,
268 "No closing parenthesis "
269 "in archive specification");
270 return false;
271 }
272
273 if (cp == mem.str)
274 break;
275
276 saveChar = *cp;
277 spec[cp - spec] = '\0';
278
279 /*
280 * XXX: This should be taken care of intelligently by
281 * SuffExpandChildren, both for the archive and the member
282 * portions.
283 */
284 /*
285 * If member contains variables, try and substitute for them.
286 * This slows down archive specs with dynamic sources, since
287 * they are (non-)substituted three times, but we need to do
288 * this since SuffExpandChildren calls us, otherwise we could
289 * assume the substitutions would be taken care of later.
290 */
291 if (doSubst) {
292 char *fullName;
293 char *p;
294 const char *unexpandedMem = mem.str;
295
296 Var_Expand(&mem, scope, VARE_UNDEFERR);
297
298 /*
299 * Now form an archive spec and recurse to deal with
300 * nested variables and multi-word variable values.
301 */
302 fullName = FullName(lib.str, mem.str);
303 p = fullName;
304
305 if (strcmp(mem.str, unexpandedMem) == 0) {
306 /*
307 * Must contain dynamic sources, so we can't
308 * deal with it now. Just create an ARCHV node
309 * and let SuffExpandChildren handle it.
310 */
311 gn = Targ_GetNode(fullName);
312 gn->type |= OP_ARCHV;
313 Lst_Append(gns, gn);
314
315 } else if (!Arch_ParseArchive(&p, gns, scope)) {
316 /* Error in nested call. */
317 free(fullName);
318 /* XXX: does unexpandedMemName leak? */
319 return false;
320 }
321 free(fullName);
322 /* XXX: does unexpandedMemName leak? */
323
324 } else if (Dir_HasWildcards(mem.str)) {
325 StringList members = LST_INIT;
326 SearchPath_Expand(&dirSearchPath, mem.str, &members);
327
328 while (!Lst_IsEmpty(&members)) {
329 char *member = Lst_Dequeue(&members);
330 char *fullname = FullName(lib.str, member);
331 free(member);
332
333 gn = Targ_GetNode(fullname);
334 free(fullname);
335
336 gn->type |= OP_ARCHV;
337 Lst_Append(gns, gn);
338 }
339 Lst_Done(&members);
340
341 } else {
342 char *fullname = FullName(lib.str, mem.str);
343 gn = Targ_GetNode(fullname);
344 free(fullname);
345
346 gn->type |= OP_ARCHV;
347 Lst_Append(gns, gn);
348 }
349 FStr_Done(&mem);
350
351 spec[cp - spec] = saveChar;
352 }
353
354 FStr_Done(&lib);
355
356 cp++; /* skip the ')' */
357 cpp_skip_whitespace(&cp);
358 *pp += cp - *pp;
359 return true;
360 }
361
362 /*
363 * Locate a member in an archive.
364 *
365 * See ArchFindMember for an almost identical copy of this code.
366 */
367 static struct ar_hdr *
368 ArchStatMember(const char *archive, const char *member, bool addToCache)
369 {
370 #define AR_MAX_NAME_LEN (sizeof arh.ar_name - 1)
371 FILE *arch;
372 size_t size; /* Size of archive member */
373 char magic[SARMAG];
374 ArchListNode *ln;
375 Arch *ar;
376 struct ar_hdr arh;
377 char memName[MAXPATHLEN + 1];
378 /* Current member name while hashing. */
379
380 member = str_basename(member);
381
382 for (ln = archives.first; ln != NULL; ln = ln->next) {
383 const Arch *a = ln->datum;
384 if (strcmp(a->name, archive) == 0)
385 break;
386 }
387
388 if (ln != NULL) {
389 struct ar_hdr *hdr;
390
391 ar = ln->datum;
392 hdr = HashTable_FindValue(&ar->members, member);
393 if (hdr != NULL)
394 return hdr;
395
396 {
397 /* Try truncated name */
398 char copy[AR_MAX_NAME_LEN + 1];
399 size_t len = strlen(member);
400
401 if (len > AR_MAX_NAME_LEN) {
402 snprintf(copy, sizeof copy, "%s", member);
403 hdr = HashTable_FindValue(&ar->members, copy);
404 }
405 return hdr;
406 }
407 }
408
409 if (!addToCache) {
410 /*
411 * Since the archive is not to be cached, assume there's no
412 * need to allocate the header, so just declare it static.
413 */
414 static struct ar_hdr sarh;
415
416 arch = ArchFindMember(archive, member, &sarh, "r");
417 if (arch == NULL)
418 return NULL;
419
420 fclose(arch);
421 return &sarh;
422 }
423
424 arch = fopen(archive, "r");
425 if (arch == NULL)
426 return NULL;
427
428 if (fread(magic, SARMAG, 1, arch) != 1 ||
429 strncmp(magic, ARMAG, SARMAG) != 0) {
430 (void)fclose(arch);
431 return NULL;
432 }
433
434 ar = bmake_malloc(sizeof *ar);
435 ar->name = bmake_strdup(archive);
436 ar->fnametab = NULL;
437 ar->fnamesize = 0;
438 HashTable_Init(&ar->members);
439 memName[AR_MAX_NAME_LEN] = '\0';
440
441 while (fread(&arh, sizeof arh, 1, arch) == 1) {
442 char *nameend;
443
444 if (strncmp(arh.ar_fmag, ARFMAG, sizeof arh.ar_fmag) != 0)
445 goto bad_archive;
446
447 arh.ar_size[sizeof arh.ar_size - 1] = '\0';
448 size = (size_t)strtol(arh.ar_size, NULL, 10);
449
450 memcpy(memName, arh.ar_name, sizeof arh.ar_name);
451 nameend = memName + AR_MAX_NAME_LEN;
452 while (nameend > memName && *nameend == ' ')
453 nameend--;
454 nameend[1] = '\0';
455
456 #ifdef SVR4ARCHIVES
457 /*
458 * svr4 names are slash-terminated.
459 * Also svr4 extended the AR format.
460 */
461 if (memName[0] == '/') {
462 /* svr4 magic mode; handle it */
463 switch (ArchSVR4Entry(ar, memName, size, arch)) {
464 case -1: /* Invalid data */
465 goto bad_archive;
466 case 0: /* List of files entry */
467 continue;
468 default: /* Got the entry */
469 break;
470 }
471 } else {
472 if (nameend[0] == '/')
473 nameend[0] = '\0';
474 }
475 #endif
476
477 #ifdef AR_EFMT1
478 /*
479 * BSD 4.4 extended AR format: #1/<namelen>, with name as the
480 * first <namelen> bytes of the file
481 */
482 if (strncmp(memName, AR_EFMT1, sizeof AR_EFMT1 - 1) == 0 &&
483 ch_isdigit(memName[sizeof AR_EFMT1 - 1])) {
484
485 size_t elen = (size_t)atoi(
486 memName + sizeof AR_EFMT1 - 1);
487
488 if (elen > MAXPATHLEN)
489 goto bad_archive;
490 if (fread(memName, elen, 1, arch) != 1)
491 goto bad_archive;
492 memName[elen] = '\0';
493 if (fseek(arch, -(long)elen, SEEK_CUR) != 0)
494 goto bad_archive;
495 if (DEBUG(ARCH) || DEBUG(MAKE))
496 debug_printf(
497 "ArchStatMember: "
498 "Extended format entry for %s\n",
499 memName);
500 }
501 #endif
502
503 {
504 struct ar_hdr *cached_hdr = bmake_malloc(
505 sizeof *cached_hdr);
506 memcpy(cached_hdr, &arh, sizeof arh);
507 HashTable_Set(&ar->members, memName, cached_hdr);
508 }
509
510 /* Files are padded with newlines to an even-byte boundary. */
511 if (fseek(arch, ((long)size + 1) & ~1, SEEK_CUR) != 0)
512 goto bad_archive;
513 }
514
515 fclose(arch);
516
517 Lst_Append(&archives, ar);
518
519 return HashTable_FindValue(&ar->members, member);
520
521 bad_archive:
522 fclose(arch);
523 HashTable_Done(&ar->members);
524 free(ar->fnametab);
525 free(ar);
526 return NULL;
527 }
528
529 #ifdef SVR4ARCHIVES
530 /*
531 * Parse an SVR4 style entry that begins with a slash.
532 * If it is "//", then load the table of filenames.
533 * If it is "/<offset>", then try to substitute the long file name
534 * from offset of a table previously read.
535 * If a table is read, the file pointer is moved to the next archive member.
536 *
537 * Results:
538 * -1: Bad data in archive
539 * 0: A table was loaded from the file
540 * 1: Name was successfully substituted from table
541 * 2: Name was not successfully substituted from table
542 */
543 static int
544 ArchSVR4Entry(Arch *ar, char *inout_name, size_t size, FILE *arch)
545 {
546 #define ARLONGNAMES1 "//"
547 #define ARLONGNAMES2 "/ARFILENAMES"
548 size_t entry;
549 char *ptr, *eptr;
550
551 if (strncmp(inout_name, ARLONGNAMES1, sizeof ARLONGNAMES1 - 1) == 0 ||
552 strncmp(inout_name, ARLONGNAMES2, sizeof ARLONGNAMES2 - 1) == 0) {
553
554 if (ar->fnametab != NULL) {
555 DEBUG0(ARCH,
556 "Attempted to redefine an SVR4 name table\n");
557 return -1;
558 }
559
560 /*
561 * This is a table of archive names, so we build one for
562 * ourselves
563 */
564 ar->fnametab = bmake_malloc(size);
565 ar->fnamesize = size;
566
567 if (fread(ar->fnametab, size, 1, arch) != 1) {
568 DEBUG0(ARCH, "Reading an SVR4 name table failed\n");
569 return -1;
570 }
571 eptr = ar->fnametab + size;
572 for (entry = 0, ptr = ar->fnametab; ptr < eptr; ptr++)
573 if (*ptr == '/') {
574 entry++;
575 *ptr = '\0';
576 }
577 DEBUG1(ARCH,
578 "Found svr4 archive name table with %lu entries\n",
579 (unsigned long)entry);
580 return 0;
581 }
582
583 if (inout_name[1] == ' ' || inout_name[1] == '\0')
584 return 2;
585
586 entry = (size_t)strtol(&inout_name[1], &eptr, 0);
587 if ((*eptr != ' ' && *eptr != '\0') || eptr == &inout_name[1]) {
588 DEBUG1(ARCH, "Could not parse SVR4 name %s\n", inout_name);
589 return 2;
590 }
591 if (entry >= ar->fnamesize) {
592 DEBUG2(ARCH, "SVR4 entry offset %s is greater than %lu\n",
593 inout_name, (unsigned long)ar->fnamesize);
594 return 2;
595 }
596
597 DEBUG2(ARCH, "Replaced %s with %s\n", inout_name, &ar->fnametab[entry]);
598
599 snprintf(inout_name, MAXPATHLEN + 1, "%s", &ar->fnametab[entry]);
600 return 1;
601 }
602 #endif
603
604
605 static bool
606 ArchiveMember_HasName(const struct ar_hdr *hdr,
607 const char *name, size_t namelen)
608 {
609 const size_t ar_name_len = sizeof hdr->ar_name;
610 const char *ar_name = hdr->ar_name;
611
612 if (strncmp(ar_name, name, namelen) != 0)
613 return false;
614
615 if (namelen >= ar_name_len)
616 return namelen == ar_name_len;
617
618 /* hdr->ar_name is space-padded to the right. */
619 if (ar_name[namelen] == ' ')
620 return true;
621
622 /*
623 * In archives created by GNU binutils 2.27, the member names end
624 * with a slash.
625 */
626 if (ar_name[namelen] == '/' && ar_name[namelen + 1] == ' ')
627 return true;
628
629 return false;
630 }
631
632 /*
633 * Load the header of an archive member. The mode is "r" for read-only
634 * access, "r+" for read-write access.
635 *
636 * Upon successful return, the archive file is positioned at the start of the
637 * member's struct ar_hdr. In case of a failure or if the member doesn't
638 * exist, return NULL.
639 *
640 * See ArchStatMember for an almost identical copy of this code.
641 */
642 static FILE *
643 ArchFindMember(const char *archive, const char *member,
644 struct ar_hdr *out_arh, const char *mode)
645 {
646 FILE *arch;
647 int size; /* Size of archive member */
648 char magic[SARMAG];
649 size_t len;
650
651 arch = fopen(archive, mode);
652 if (arch == NULL)
653 return NULL;
654
655 if (fread(magic, SARMAG, 1, arch) != 1 ||
656 strncmp(magic, ARMAG, SARMAG) != 0) {
657 fclose(arch);
658 return NULL;
659 }
660
661 /* Files are archived using their basename, not the entire path. */
662 member = str_basename(member);
663 len = strlen(member);
664
665 while (fread(out_arh, sizeof *out_arh, 1, arch) == 1) {
666
667 if (strncmp(out_arh->ar_fmag, ARFMAG,
668 sizeof out_arh->ar_fmag) != 0) {
669 fclose(arch);
670 return NULL;
671 }
672
673 DEBUG5(ARCH, "Reading archive %s member %.*s mtime %.*s\n",
674 archive,
675 (int)sizeof out_arh->ar_name, out_arh->ar_name,
676 (int)sizeof out_arh->ar_date, out_arh->ar_date);
677
678 if (ArchiveMember_HasName(out_arh, member, len)) {
679 if (fseek(arch, -(long)sizeof *out_arh, SEEK_CUR) !=
680 0) {
681 fclose(arch);
682 return NULL;
683 }
684 return arch;
685 }
686
687 #ifdef AR_EFMT1
688 /*
689 * BSD 4.4 extended AR format: #1/<namelen>, with name as the
690 * first <namelen> bytes of the file
691 */
692 if (strncmp(out_arh->ar_name, AR_EFMT1, sizeof AR_EFMT1 - 1) ==
693 0 &&
694 (ch_isdigit(out_arh->ar_name[sizeof AR_EFMT1 - 1]))) {
695 size_t elen = (size_t)atoi(
696 &out_arh->ar_name[sizeof AR_EFMT1 - 1]);
697 char ename[MAXPATHLEN + 1];
698
699 if (elen > MAXPATHLEN) {
700 fclose(arch);
701 return NULL;
702 }
703 if (fread(ename, elen, 1, arch) != 1) {
704 fclose(arch);
705 return NULL;
706 }
707 ename[elen] = '\0';
708 if (DEBUG(ARCH) || DEBUG(MAKE))
709 debug_printf(
710 "ArchFindMember: "
711 "Extended format entry for %s\n",
712 ename);
713 if (strncmp(ename, member, len) == 0) {
714 /* Found as extended name */
715 if (fseek(arch,
716 -(long)(sizeof(struct ar_hdr) - elen),
717 SEEK_CUR) != 0) {
718 fclose(arch);
719 return NULL;
720 }
721 return arch;
722 }
723 if (fseek(arch, -(long)elen, SEEK_CUR) != 0) {
724 fclose(arch);
725 return NULL;
726 }
727 }
728 #endif
729
730 /* Advance to the next member. */
731 out_arh->ar_size[sizeof out_arh->ar_size - 1] = '\0';
732 size = (int)strtol(out_arh->ar_size, NULL, 10);
733 /* Files are padded with newlines to an even-byte boundary. */
734 if (fseek(arch, (size + 1) & ~1L, SEEK_CUR) != 0) {
735 fclose(arch);
736 return NULL;
737 }
738 }
739
740 fclose(arch);
741 return NULL;
742 }
743
744 /*
745 * Update the ar_date of the member of an archive, on disk but not in the
746 * GNode. Update the st_mtime of the entire archive as well. For a library,
747 * it may be required to run ranlib after this.
748 */
749 void
750 Arch_Touch(GNode *gn)
751 {
752 FILE *f;
753 struct ar_hdr arh;
754
755 f = ArchFindMember(GNode_VarArchive(gn), GNode_VarMember(gn), &arh,
756 "r+");
757 if (f == NULL)
758 return;
759
760 snprintf(arh.ar_date, sizeof arh.ar_date, "%-ld", (unsigned long)now);
761 (void)fwrite(&arh, sizeof arh, 1, f);
762 fclose(f); /* TODO: handle errors */
763 }
764
765 /*
766 * Given a node which represents a library, touch the thing, making sure that
767 * the table of contents is also touched.
768 *
769 * Both the modification time of the library and of the RANLIBMAG member are
770 * set to 'now'.
771 */
772 /*ARGSUSED*/
773 void
774 Arch_TouchLib(GNode *gn MAKE_ATTR_UNUSED)
775 {
776 #ifdef RANLIBMAG
777 FILE *f;
778 struct ar_hdr arh; /* Header describing table of contents */
779 struct utimbuf times;
780
781 f = ArchFindMember(gn->path, RANLIBMAG, &arh, "r+");
782 if (f == NULL)
783 return;
784
785 snprintf(arh.ar_date, sizeof arh.ar_date, "%-ld", (unsigned long)now);
786 (void)fwrite(&arh, sizeof arh, 1, f);
787 fclose(f); /* TODO: handle errors */
788
789 times.actime = times.modtime = now;
790 utime(gn->path, ×); /* TODO: handle errors */
791 #endif
792 }
793
794 /*
795 * Update the mtime of the GNode with the mtime from the archive member on
796 * disk (or in the cache).
797 */
798 void
799 Arch_UpdateMTime(GNode *gn)
800 {
801 struct ar_hdr *arh;
802
803 arh = ArchStatMember(GNode_VarArchive(gn), GNode_VarMember(gn), true);
804 if (arh != NULL)
805 gn->mtime = (time_t)strtol(arh->ar_date, NULL, 10);
806 else
807 gn->mtime = 0;
808 }
809
810 /*
811 * Given a nonexistent archive member's node, update gn->mtime from its
812 * archived form, if it exists.
813 */
814 void
815 Arch_UpdateMemberMTime(GNode *gn)
816 {
817 GNodeListNode *ln;
818
819 for (ln = gn->parents.first; ln != NULL; ln = ln->next) {
820 GNode *pgn = ln->datum;
821
822 if (pgn->type & OP_ARCHV) {
823 /*
824 * If the parent is an archive specification and is
825 * being made and its member's name matches the name
826 * of the node we were given, record the modification
827 * time of the parent in the child. We keep searching
828 * its parents in case some other parent requires this
829 * child to exist.
830 */
831 const char *nameStart = strchr(pgn->name, '(') + 1;
832 const char *nameEnd = strchr(nameStart, ')');
833 size_t nameLen = (size_t)(nameEnd - nameStart);
834
835 if (pgn->flags.remake &&
836 strncmp(nameStart, gn->name, nameLen) == 0) {
837 Arch_UpdateMTime(pgn);
838 gn->mtime = pgn->mtime;
839 }
840 } else if (pgn->flags.remake) {
841 /*
842 * Something which isn't a library depends on the
843 * existence of this target, so it needs to exist.
844 */
845 gn->mtime = 0;
846 break;
847 }
848 }
849 }
850
851 /*
852 * Search for a library along the given search path.
853 *
854 * The node's 'path' field is set to the found path (including the
855 * actual file name, not -l...). If the system can handle the -L
856 * flag when linking (or we cannot find the library), we assume that
857 * the user has placed the .LIBS variable in the final linking
858 * command (or the linker will know where to find it) and set the
859 * TARGET variable for this node to be the node's name. Otherwise,
860 * we set the TARGET variable to be the full path of the library,
861 * as returned by Dir_FindFile.
862 */
863 void
864 Arch_FindLib(GNode *gn, SearchPath *path)
865 {
866 char *libName = str_concat3("lib", gn->name + 2, ".a");
867 gn->path = Dir_FindFile(libName, path);
868 free(libName);
869
870 Var_Set(gn, TARGET, gn->name);
871 }
872
873 /* ARGSUSED */
874 static bool
875 RanlibOODate(const GNode *gn MAKE_ATTR_UNUSED)
876 {
877 #ifdef RANLIBMAG
878 struct ar_hdr *arh; /* Header for __.SYMDEF */
879 int tocModTime; /* The table-of-contents' mod time */
880
881 arh = ArchStatMember(gn->path, RANLIBMAG, false);
882
883 if (arh == NULL) {
884 /* A library without a table of contents is out-of-date. */
885 if (DEBUG(ARCH) || DEBUG(MAKE))
886 debug_printf("no toc...");
887 return true;
888 }
889
890 tocModTime = (int)strtol(arh->ar_date, NULL, 10);
891
892 if (DEBUG(ARCH) || DEBUG(MAKE))
893 debug_printf("%s modified %s...",
894 RANLIBMAG, Targ_FmtTime(tocModTime));
895 return gn->youngestChild == NULL ||
896 gn->youngestChild->mtime > tocModTime;
897 #else
898 return false;
899 #endif
900 }
901
902 /*
903 * Decide if a node with the OP_LIB attribute is out-of-date.
904 * The library is cached if it hasn't been already.
905 *
906 * There are several ways for a library to be out-of-date that are not
907 * available to ordinary files. In addition, there are ways that are open to
908 * regular files that are not available to libraries.
909 *
910 * A library that is only used as a source is never considered out-of-date by
911 * itself. This does not preclude the library's modification time from making
912 * its parent be out-of-date. A library will be considered out-of-date for
913 * any of these reasons, given that it is a target on a dependency line
914 * somewhere:
915 *
916 * Its modification time is less than that of one of its sources
917 * (gn->mtime < gn->youngestChild->mtime).
918 *
919 * Its modification time is greater than the time at which the make
920 * began (i.e. it's been modified in the course of the make, probably
921 * by archiving).
922 *
923 * The modification time of one of its sources is greater than the one
924 * of its RANLIBMAG member (i.e. its table of contents is out-of-date).
925 * We don't compare the archive time vs. TOC time because they can be
926 * too close. In my opinion we should not bother with the TOC at all
927 * since this is used by 'ar' rules that affect the data contents of the
928 * archive, not by ranlib rules, which affect the TOC.
929 */
930 bool
931 Arch_LibOODate(GNode *gn)
932 {
933
934 if (gn->type & OP_PHONY)
935 return true;
936 if (!GNode_IsTarget(gn) && Lst_IsEmpty(&gn->children))
937 return false;
938 if ((!Lst_IsEmpty(&gn->children) && gn->youngestChild == NULL) ||
939 (gn->mtime > now) ||
940 (gn->youngestChild != NULL &&
941 gn->mtime < gn->youngestChild->mtime))
942 return true;
943 return RanlibOODate(gn);
944 }
945
946 /* Initialize the archives module. */
947 void
948 Arch_Init(void)
949 {
950 Lst_Init(&archives);
951 }
952
953 /* Clean up the archives module. */
954 void
955 Arch_End(void)
956 {
957 #ifdef CLEANUP
958 ArchListNode *ln;
959
960 for (ln = archives.first; ln != NULL; ln = ln->next)
961 ArchFree(ln->datum);
962 Lst_Done(&archives);
963 #endif
964 }
965
966 bool
967 Arch_IsLib(GNode *gn)
968 {
969 char buf[8];
970 int fd;
971 bool isLib;
972
973 if ((fd = open(gn->path, O_RDONLY)) == -1)
974 return false;
975 isLib = read(fd, buf, sizeof buf) == sizeof buf
976 && memcmp(buf, "!<arch>\n", sizeof buf) == 0;
977 (void)close(fd);
978 return isLib;
979 }
980