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