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