1 /* $NetBSD: arch.c,v 1.222 2024/08/06 17:46:01 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.222 2024/08/06 17:46:01 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, 213 VARE_EVAL_DEFINED); 214 /* TODO: handle errors */ 215 isError = result.str == var_Error; 216 FStr_Done(&result); 217 if (isError) 218 return false; 219 220 expandLib = true; 221 cp += nested_p - cp; 222 } else 223 cp++; 224 } 225 226 spec[cp++ - spec] = '\0'; 227 if (expandLib) 228 Var_Expand(&lib, scope, VARE_EVAL_DEFINED); 229 230 for (;;) { 231 /* 232 * First skip to the start of the member's name, mark that 233 * place and skip to the end of it (either white-space or 234 * a close paren). 235 */ 236 bool doSubst = false; 237 238 cpp_skip_whitespace(&cp); 239 240 mem = FStr_InitRefer(cp); 241 while (*cp != '\0' && *cp != ')' && !ch_isspace(*cp)) { 242 if (*cp == '$') { 243 /* Expand nested expressions. */ 244 /* 245 * XXX: This code can probably be shortened. 246 */ 247 FStr result; 248 bool isError; 249 const char *nested_p = cp; 250 251 result = Var_Parse(&nested_p, scope, 252 VARE_EVAL_DEFINED); 253 /* TODO: handle errors */ 254 isError = result.str == var_Error; 255 FStr_Done(&result); 256 257 if (isError) 258 return false; 259 260 doSubst = true; 261 cp += nested_p - cp; 262 } else { 263 cp++; 264 } 265 } 266 267 if (*cp == '\0') { 268 Parse_Error(PARSE_FATAL, 269 "Missing ')' 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_EVAL_DEFINED); 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 void 773 Arch_TouchLib(GNode *gn MAKE_ATTR_UNUSED) 774 { 775 #ifdef RANLIBMAG 776 FILE *f; 777 struct ar_hdr arh; /* Header describing table of contents */ 778 struct utimbuf times; 779 780 f = ArchFindMember(gn->path, RANLIBMAG, &arh, "r+"); 781 if (f == NULL) 782 return; 783 784 snprintf(arh.ar_date, sizeof arh.ar_date, "%-ld", (unsigned long)now); 785 (void)fwrite(&arh, sizeof arh, 1, f); 786 fclose(f); /* TODO: handle errors */ 787 788 times.actime = times.modtime = now; 789 utime(gn->path, ×); /* TODO: handle errors */ 790 #endif 791 } 792 793 /* 794 * Update the mtime of the GNode with the mtime from the archive member on 795 * disk (or in the cache). 796 */ 797 void 798 Arch_UpdateMTime(GNode *gn) 799 { 800 struct ar_hdr *arh; 801 802 arh = ArchStatMember(GNode_VarArchive(gn), GNode_VarMember(gn), true); 803 if (arh != NULL) 804 gn->mtime = (time_t)strtol(arh->ar_date, NULL, 10); 805 else 806 gn->mtime = 0; 807 } 808 809 /* 810 * Given a nonexistent archive member's node, update gn->mtime from its 811 * archived form, if it exists. 812 */ 813 void 814 Arch_UpdateMemberMTime(GNode *gn) 815 { 816 GNodeListNode *ln; 817 818 for (ln = gn->parents.first; ln != NULL; ln = ln->next) { 819 GNode *pgn = ln->datum; 820 821 if (pgn->type & OP_ARCHV) { 822 /* 823 * If the parent is an archive specification and is 824 * being made and its member's name matches the name 825 * of the node we were given, record the modification 826 * time of the parent in the child. We keep searching 827 * its parents in case some other parent requires this 828 * child to exist. 829 */ 830 const char *nameStart = strchr(pgn->name, '(') + 1; 831 const char *nameEnd = strchr(nameStart, ')'); 832 size_t nameLen = (size_t)(nameEnd - nameStart); 833 834 if (pgn->flags.remake && 835 strncmp(nameStart, gn->name, nameLen) == 0) { 836 Arch_UpdateMTime(pgn); 837 gn->mtime = pgn->mtime; 838 } 839 } else if (pgn->flags.remake) { 840 /* 841 * Something which isn't a library depends on the 842 * existence of this target, so it needs to exist. 843 */ 844 gn->mtime = 0; 845 break; 846 } 847 } 848 } 849 850 /* 851 * Search for a library along the given search path. 852 * 853 * The node's 'path' field is set to the found path (including the 854 * actual file name, not -l...). If the system can handle the -L 855 * flag when linking (or we cannot find the library), we assume that 856 * the user has placed the .LIBS variable in the final linking 857 * command (or the linker will know where to find it) and set the 858 * TARGET variable for this node to be the node's name. Otherwise, 859 * we set the TARGET variable to be the full path of the library, 860 * as returned by Dir_FindFile. 861 */ 862 void 863 Arch_FindLib(GNode *gn, SearchPath *path) 864 { 865 char *libName = str_concat3("lib", gn->name + 2, ".a"); 866 gn->path = Dir_FindFile(libName, path); 867 free(libName); 868 869 Var_Set(gn, TARGET, gn->name); 870 } 871 872 static bool 873 RanlibOODate(const GNode *gn MAKE_ATTR_UNUSED) 874 { 875 #ifdef RANLIBMAG 876 struct ar_hdr *arh; /* Header for __.SYMDEF */ 877 int tocModTime; /* The table-of-contents' mod time */ 878 879 arh = ArchStatMember(gn->path, RANLIBMAG, false); 880 881 if (arh == NULL) { 882 /* A library without a table of contents is out-of-date. */ 883 if (DEBUG(ARCH) || DEBUG(MAKE)) 884 debug_printf("no toc..."); 885 return true; 886 } 887 888 tocModTime = (int)strtol(arh->ar_date, NULL, 10); 889 890 if (DEBUG(ARCH) || DEBUG(MAKE)) 891 debug_printf("%s modified %s...", 892 RANLIBMAG, Targ_FmtTime(tocModTime)); 893 return gn->youngestChild == NULL || 894 gn->youngestChild->mtime > tocModTime; 895 #else 896 return false; 897 #endif 898 } 899 900 /* 901 * Decide if a node with the OP_LIB attribute is out-of-date. 902 * The library is cached if it hasn't been already. 903 * 904 * There are several ways for a library to be out-of-date that are not 905 * available to ordinary files. In addition, there are ways that are open to 906 * regular files that are not available to libraries. 907 * 908 * A library that is only used as a source is never considered out-of-date by 909 * itself. This does not preclude the library's modification time from making 910 * its parent be out-of-date. A library will be considered out-of-date for 911 * any of these reasons, given that it is a target on a dependency line 912 * somewhere: 913 * 914 * Its modification time is less than that of one of its sources 915 * (gn->mtime < gn->youngestChild->mtime). 916 * 917 * Its modification time is greater than the time at which the make 918 * began (i.e. it's been modified in the course of the make, probably 919 * by archiving). 920 * 921 * The modification time of one of its sources is greater than the one 922 * of its RANLIBMAG member (i.e. its table of contents is out-of-date). 923 * We don't compare the archive time vs. TOC time because they can be 924 * too close. In my opinion we should not bother with the TOC at all 925 * since this is used by 'ar' rules that affect the data contents of the 926 * archive, not by ranlib rules, which affect the TOC. 927 */ 928 bool 929 Arch_LibOODate(GNode *gn) 930 { 931 932 if (gn->type & OP_PHONY) 933 return true; 934 if (!GNode_IsTarget(gn) && Lst_IsEmpty(&gn->children)) 935 return false; 936 if ((!Lst_IsEmpty(&gn->children) && gn->youngestChild == NULL) || 937 (gn->mtime > now) || 938 (gn->youngestChild != NULL && 939 gn->mtime < gn->youngestChild->mtime)) 940 return true; 941 return RanlibOODate(gn); 942 } 943 944 /* Initialize the archives module. */ 945 void 946 Arch_Init(void) 947 { 948 Lst_Init(&archives); 949 } 950 951 #ifdef CLEANUP 952 /* Clean up the archives module. */ 953 void 954 Arch_End(void) 955 { 956 ArchListNode *ln; 957 958 for (ln = archives.first; ln != NULL; ln = ln->next) 959 ArchFree(ln->datum); 960 Lst_Done(&archives); 961 } 962 #endif 963 964 bool 965 Arch_IsLib(GNode *gn) 966 { 967 char buf[8]; 968 int fd; 969 bool isLib; 970 971 if ((fd = open(gn->path, O_RDONLY)) == -1) 972 return false; 973 isLib = read(fd, buf, sizeof buf) == sizeof buf 974 && memcmp(buf, "!<arch>\n", sizeof buf) == 0; 975 (void)close(fd); 976 return isLib; 977 } 978