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