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