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 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 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 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 * 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 * 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 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 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 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 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 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 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 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 1062 Arch_End () 1063 { 1064 Lst_Destroy(archives, ArchFree); 1065 } 1066