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