1 /* $NetBSD: arch.c,v 1.211 2022/09/27 17:46:58 rillig Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1989, 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Adam de Boor. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 /* 36 * Copyright (c) 1989 by Berkeley Softworks 37 * All rights reserved. 38 * 39 * This code is derived from software contributed to Berkeley by 40 * Adam de Boor. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. All advertising materials mentioning features or use of this software 51 * must display the following acknowledgement: 52 * This product includes software developed by the University of 53 * California, Berkeley and its contributors. 54 * 4. Neither the name of the University nor the names of its contributors 55 * may be used to endorse or promote products derived from this software 56 * without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * SUCH DAMAGE. 69 */ 70 71 /* 72 * Manipulate libraries, archives and their members. 73 * 74 * The first time an archive is referenced, all of its members' headers are 75 * read and cached and the archive closed again. All cached archives are kept 76 * on a list which is searched each time an archive member is referenced. 77 * 78 * The interface to this module is: 79 * 80 * Arch_Init Initialize this module. 81 * 82 * Arch_End Clean up this module. 83 * 84 * Arch_ParseArchive 85 * Parse an archive specification such as 86 * "archive.a(member1 member2)". 87 * 88 * Arch_Touch Alter the modification time of the archive 89 * member described by the given node to be 90 * the time when make was started. 91 * 92 * Arch_TouchLib Update the modification time of the library 93 * described by the given node. This is special 94 * because it also updates the modification time 95 * of the library's table of contents. 96 * 97 * Arch_UpdateMTime 98 * Find the modification time of a member of 99 * an archive *in the archive* and place it in the 100 * member's GNode. 101 * 102 * Arch_UpdateMemberMTime 103 * Find the modification time of a member of 104 * an archive. Called when the member doesn't 105 * already exist. Looks in the archive for the 106 * modification time. Returns the modification 107 * time. 108 * 109 * Arch_FindLib Search for a library along a path. The 110 * library name in the GNode should be in 111 * -l<name> format. 112 * 113 * Arch_LibOODate Decide if a library node is out-of-date. 114 */ 115 116 #include <sys/types.h> 117 #include <sys/stat.h> 118 #include <sys/time.h> 119 #include <sys/param.h> 120 121 #include <ar.h> 122 #include <utime.h> 123 124 #include "make.h" 125 #include "dir.h" 126 #include "config.h" 127 128 /* "@(#)arch.c 8.2 (Berkeley) 1/2/94" */ 129 MAKE_RCSID("$NetBSD: arch.c,v 1.211 2022/09/27 17:46:58 rillig Exp $"); 130 131 typedef struct List ArchList; 132 typedef struct ListNode ArchListNode; 133 134 static ArchList archives; /* The archives we've already examined */ 135 136 typedef struct Arch { 137 char *name; /* Name of archive */ 138 HashTable members; /* All the members of the archive described 139 * by <name, struct ar_hdr *> key/value pairs */ 140 char *fnametab; /* Extended name table strings */ 141 size_t fnamesize; /* Size of the string table */ 142 } Arch; 143 144 static FILE *ArchFindMember(const char *, const char *, 145 struct ar_hdr *, const char *); 146 #if defined(__svr4__) || defined(__SVR4) || defined(__ELF__) 147 #define SVR4ARCHIVES 148 static int ArchSVR4Entry(Arch *, char *, size_t, FILE *); 149 #endif 150 151 152 #ifdef CLEANUP 153 static void 154 ArchFree(void *ap) 155 { 156 Arch *a = ap; 157 HashIter hi; 158 159 /* Free memory from hash entries */ 160 HashIter_Init(&hi, &a->members); 161 while (HashIter_Next(&hi) != NULL) 162 free(hi.entry->value); 163 164 free(a->name); 165 free(a->fnametab); 166 HashTable_Done(&a->members); 167 free(a); 168 } 169 #endif 170 171 /* Return "archive(member)". */ 172 static char * 173 FullName(const char *archive, const char *member) 174 { 175 size_t len1 = strlen(archive); 176 size_t len3 = strlen(member); 177 char *result = bmake_malloc(len1 + 1 + len3 + 1 + 1); 178 memcpy(result, archive, len1); 179 memcpy(result + len1, "(", 1); 180 memcpy(result + len1 + 1, member, len3); 181 memcpy(result + len1 + 1 + len3, ")", 1 + 1); 182 return result; 183 } 184 185 /* 186 * Parse an archive specification such as "archive.a(member1 member2.${EXT})", 187 * adding nodes for the expanded members to gns. Nodes are created as 188 * necessary. 189 * 190 * Input: 191 * pp The start of the specification. 192 * gns The list on which to place the nodes. 193 * scope The scope in which to expand variables. 194 * 195 * Output: 196 * return True if it was a valid specification. 197 * *pp Points to the first non-space after the archive spec. 198 */ 199 bool 200 Arch_ParseArchive(char **pp, GNodeList *gns, GNode *scope) 201 { 202 char *spec; /* For modifying some bytes of *pp */ 203 const char *cp; /* Pointer into line */ 204 GNode *gn; /* New node */ 205 FStr lib; /* Library-part of specification */ 206 FStr mem; /* Member-part of specification */ 207 char saveChar; /* Ending delimiter of member-name */ 208 bool expandLib; /* Whether the parsed lib contains variable 209 * expressions that need to be expanded */ 210 211 spec = *pp; 212 lib = FStr_InitRefer(spec); 213 expandLib = false; 214 215 for (cp = lib.str; *cp != '(' && *cp != '\0';) { 216 if (*cp == '$') { 217 /* Expand nested variable expressions. */ 218 /* XXX: This code can probably be shortened. */ 219 const char *nested_p = cp; 220 FStr result; 221 bool isError; 222 223 /* XXX: is expanded twice: once here and once below */ 224 (void)Var_Parse(&nested_p, scope, 225 VARE_UNDEFERR, &result); 226 /* TODO: handle errors */ 227 isError = result.str == var_Error; 228 FStr_Done(&result); 229 if (isError) 230 return false; 231 232 expandLib = true; 233 cp += nested_p - cp; 234 } else 235 cp++; 236 } 237 238 spec[cp++ - spec] = '\0'; 239 if (expandLib) 240 Var_Expand(&lib, scope, VARE_UNDEFERR); 241 242 for (;;) { 243 /* 244 * First skip to the start of the member's name, mark that 245 * place and skip to the end of it (either white-space or 246 * a close paren). 247 */ 248 bool doSubst = false; 249 250 cpp_skip_whitespace(&cp); 251 252 mem = FStr_InitRefer(cp); 253 while (*cp != '\0' && *cp != ')' && !ch_isspace(*cp)) { 254 if (*cp == '$') { 255 /* Expand nested variable expressions. */ 256 /* 257 * XXX: This code can probably be shortened. 258 */ 259 FStr result; 260 bool isError; 261 const char *nested_p = cp; 262 263 (void)Var_Parse(&nested_p, scope, 264 VARE_UNDEFERR, &result); 265 /* TODO: handle errors */ 266 isError = result.str == var_Error; 267 FStr_Done(&result); 268 269 if (isError) 270 return false; 271 272 doSubst = true; 273 cp += nested_p - cp; 274 } else { 275 cp++; 276 } 277 } 278 279 /* 280 * If the specification ends without a closing parenthesis, 281 * chances are there's something wrong (like a missing 282 * backslash), so it's better to return failure than allow 283 * such things to happen 284 */ 285 if (*cp == '\0') { 286 Parse_Error(PARSE_FATAL, 287 "No closing parenthesis " 288 "in archive specification"); 289 return false; 290 } 291 292 /* 293 * If we didn't move anywhere, we must be done 294 */ 295 if (cp == mem.str) 296 break; 297 298 saveChar = *cp; 299 spec[cp - spec] = '\0'; 300 301 /* 302 * XXX: This should be taken care of intelligently by 303 * SuffExpandChildren, both for the archive and the member 304 * portions. 305 */ 306 /* 307 * If member contains variables, try and substitute for them. 308 * This will slow down archive specs with dynamic sources, of 309 * course, since we'll be (non-)substituting them three 310 * times, but them's the breaks -- we need to do this since 311 * SuffExpandChildren calls us, otherwise we could assume the 312 * thing would be taken care of later. 313 */ 314 if (doSubst) { 315 char *fullName; 316 char *p; 317 const char *unexpandedMem = mem.str; 318 319 Var_Expand(&mem, scope, VARE_UNDEFERR); 320 321 /* 322 * Now form an archive spec and recurse to deal with 323 * nested variables and multi-word variable values. 324 */ 325 fullName = FullName(lib.str, mem.str); 326 p = fullName; 327 328 if (strcmp(mem.str, unexpandedMem) == 0) { 329 /* 330 * Must contain dynamic sources, so we can't 331 * deal with it now. Just create an ARCHV node 332 * for the thing and let SuffExpandChildren 333 * handle it. 334 */ 335 gn = Targ_GetNode(fullName); 336 gn->type |= OP_ARCHV; 337 Lst_Append(gns, gn); 338 339 } else if (!Arch_ParseArchive(&p, gns, scope)) { 340 /* Error in nested call. */ 341 free(fullName); 342 /* XXX: does unexpandedMemName leak? */ 343 return false; 344 } 345 free(fullName); 346 /* XXX: does unexpandedMemName leak? */ 347 348 } else if (Dir_HasWildcards(mem.str)) { 349 StringList members = LST_INIT; 350 SearchPath_Expand(&dirSearchPath, mem.str, &members); 351 352 while (!Lst_IsEmpty(&members)) { 353 char *member = Lst_Dequeue(&members); 354 char *fullname = FullName(lib.str, member); 355 free(member); 356 357 gn = Targ_GetNode(fullname); 358 free(fullname); 359 360 gn->type |= OP_ARCHV; 361 Lst_Append(gns, gn); 362 } 363 Lst_Done(&members); 364 365 } else { 366 char *fullname = FullName(lib.str, mem.str); 367 gn = Targ_GetNode(fullname); 368 free(fullname); 369 370 /* 371 * We've found the node, but have to make sure the 372 * rest of the world knows it's an archive member, 373 * without having to constantly check for parentheses, 374 * so we type the thing with the OP_ARCHV bit before 375 * we place it on the end of the provided list. 376 */ 377 gn->type |= OP_ARCHV; 378 Lst_Append(gns, gn); 379 } 380 FStr_Done(&mem); 381 382 spec[cp - spec] = saveChar; 383 } 384 385 FStr_Done(&lib); 386 387 cp++; /* skip the ')' */ 388 /* We promised that pp would be set up at the next non-space. */ 389 cpp_skip_whitespace(&cp); 390 *pp += cp - *pp; 391 return true; 392 } 393 394 /* 395 * Locate a member of an archive, given the path of the archive and the path 396 * of the desired member. 397 * 398 * Input: 399 * archive Path to the archive 400 * member Name of member; only its basename is used. 401 * addToCache True if archive should be cached if not already so. 402 * 403 * Results: 404 * The ar_hdr for the member, or NULL. 405 * 406 * See ArchFindMember for an almost identical copy of this code. 407 */ 408 static struct ar_hdr * 409 ArchStatMember(const char *archive, const char *member, bool addToCache) 410 { 411 #define AR_MAX_NAME_LEN (sizeof arh.ar_name - 1) 412 FILE *arch; 413 size_t size; /* Size of archive member */ 414 char magic[SARMAG]; 415 ArchListNode *ln; 416 Arch *ar; /* Archive descriptor */ 417 struct ar_hdr arh; /* archive-member header for reading archive */ 418 char memName[MAXPATHLEN + 1]; 419 /* Current member name while hashing. */ 420 421 /* 422 * Because of space constraints and similar things, files are archived 423 * using their basename, not the entire path. 424 */ 425 member = str_basename(member); 426 427 for (ln = archives.first; ln != NULL; ln = ln->next) { 428 const Arch *a = ln->datum; 429 if (strcmp(a->name, archive) == 0) 430 break; 431 } 432 433 if (ln != NULL) { 434 struct ar_hdr *hdr; 435 436 ar = ln->datum; 437 hdr = HashTable_FindValue(&ar->members, member); 438 if (hdr != NULL) 439 return hdr; 440 441 { 442 /* Try truncated name */ 443 char copy[AR_MAX_NAME_LEN + 1]; 444 size_t len = strlen(member); 445 446 if (len > AR_MAX_NAME_LEN) { 447 snprintf(copy, sizeof copy, "%s", member); 448 hdr = HashTable_FindValue(&ar->members, copy); 449 } 450 return hdr; 451 } 452 } 453 454 if (!addToCache) { 455 /* 456 * Caller doesn't want the thing cached, just use 457 * ArchFindMember to read the header for the member out and 458 * close down the stream again. Since the archive is not to be 459 * cached, we assume there's no need to allocate extra room 460 * for the header we're returning, 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 /* 473 * We don't have this archive on the list yet, so we want to find out 474 * everything that's in it and cache it so we can get at it quickly. 475 */ 476 arch = fopen(archive, "r"); 477 if (arch == NULL) 478 return NULL; 479 480 /* 481 * We use the ARMAG string to make sure this is an archive we 482 * can handle... 483 */ 484 if (fread(magic, SARMAG, 1, arch) != 1 || 485 strncmp(magic, ARMAG, SARMAG) != 0) { 486 (void)fclose(arch); 487 return NULL; 488 } 489 490 ar = bmake_malloc(sizeof *ar); 491 ar->name = bmake_strdup(archive); 492 ar->fnametab = NULL; 493 ar->fnamesize = 0; 494 HashTable_Init(&ar->members); 495 memName[AR_MAX_NAME_LEN] = '\0'; 496 497 while (fread(&arh, sizeof arh, 1, arch) == 1) { 498 char *nameend; 499 500 /* If the header is bogus, there's no way we can recover. */ 501 if (strncmp(arh.ar_fmag, ARFMAG, sizeof arh.ar_fmag) != 0) 502 goto badarch; 503 504 /* 505 * We need to advance the stream's pointer to the start of the 506 * next header. Files are padded with newlines to an even-byte 507 * boundary, so we need to extract the size of the file from 508 * the 'size' field of the header and round it up during the 509 * seek. 510 */ 511 arh.ar_size[sizeof arh.ar_size - 1] = '\0'; 512 size = (size_t)strtol(arh.ar_size, NULL, 10); 513 514 memcpy(memName, arh.ar_name, sizeof arh.ar_name); 515 nameend = memName + AR_MAX_NAME_LEN; 516 while (nameend > memName && *nameend == ' ') 517 nameend--; 518 nameend[1] = '\0'; 519 520 #ifdef SVR4ARCHIVES 521 /* 522 * svr4 names are slash-terminated. 523 * Also svr4 extended the AR format. 524 */ 525 if (memName[0] == '/') { 526 /* svr4 magic mode; handle it */ 527 switch (ArchSVR4Entry(ar, memName, size, arch)) { 528 case -1: /* Invalid data */ 529 goto badarch; 530 case 0: /* List of files entry */ 531 continue; 532 default: /* Got the entry */ 533 break; 534 } 535 } else { 536 if (nameend[0] == '/') 537 nameend[0] = '\0'; 538 } 539 #endif 540 541 #ifdef AR_EFMT1 542 /* 543 * BSD 4.4 extended AR format: #1/<namelen>, with name as the 544 * first <namelen> bytes of the file 545 */ 546 if (strncmp(memName, AR_EFMT1, sizeof AR_EFMT1 - 1) == 0 && 547 ch_isdigit(memName[sizeof AR_EFMT1 - 1])) { 548 549 size_t elen = (size_t)atoi( 550 memName + sizeof AR_EFMT1 - 1); 551 552 if (elen > MAXPATHLEN) 553 goto badarch; 554 if (fread(memName, elen, 1, arch) != 1) 555 goto badarch; 556 memName[elen] = '\0'; 557 if (fseek(arch, -(long)elen, SEEK_CUR) != 0) 558 goto badarch; 559 if (DEBUG(ARCH) || DEBUG(MAKE)) 560 debug_printf( 561 "ArchStatMember: " 562 "Extended format entry for %s\n", 563 memName); 564 } 565 #endif 566 567 { 568 struct ar_hdr *cached_hdr = bmake_malloc( 569 sizeof *cached_hdr); 570 memcpy(cached_hdr, &arh, sizeof arh); 571 HashTable_Set(&ar->members, memName, cached_hdr); 572 } 573 574 if (fseek(arch, ((long)size + 1) & ~1, SEEK_CUR) != 0) 575 goto badarch; 576 } 577 578 fclose(arch); 579 580 Lst_Append(&archives, ar); 581 582 /* 583 * Now that the archive has been read and cached, we can look into 584 * the addToCache table to find the desired member's header. 585 */ 586 return HashTable_FindValue(&ar->members, member); 587 588 badarch: 589 fclose(arch); 590 HashTable_Done(&ar->members); 591 free(ar->fnametab); 592 free(ar); 593 return NULL; 594 } 595 596 #ifdef SVR4ARCHIVES 597 /* 598 * Parse an SVR4 style entry that begins with a slash. 599 * If it is "//", then load the table of filenames. 600 * If it is "/<offset>", then try to substitute the long file name 601 * from offset of a table previously read. 602 * If a table is read, the file pointer is moved to the next archive member. 603 * 604 * Results: 605 * -1: Bad data in archive 606 * 0: A table was loaded from the file 607 * 1: Name was successfully substituted from table 608 * 2: Name was not successfully substituted from table 609 */ 610 static int 611 ArchSVR4Entry(Arch *ar, char *inout_name, size_t size, FILE *arch) 612 { 613 #define ARLONGNAMES1 "//" 614 #define ARLONGNAMES2 "/ARFILENAMES" 615 size_t entry; 616 char *ptr, *eptr; 617 618 if (strncmp(inout_name, ARLONGNAMES1, sizeof ARLONGNAMES1 - 1) == 0 || 619 strncmp(inout_name, ARLONGNAMES2, sizeof ARLONGNAMES2 - 1) == 0) { 620 621 if (ar->fnametab != NULL) { 622 DEBUG0(ARCH, 623 "Attempted to redefine an SVR4 name table\n"); 624 return -1; 625 } 626 627 /* 628 * This is a table of archive names, so we build one for 629 * ourselves 630 */ 631 ar->fnametab = bmake_malloc(size); 632 ar->fnamesize = size; 633 634 if (fread(ar->fnametab, size, 1, arch) != 1) { 635 DEBUG0(ARCH, "Reading an SVR4 name table failed\n"); 636 return -1; 637 } 638 eptr = ar->fnametab + size; 639 for (entry = 0, ptr = ar->fnametab; ptr < eptr; ptr++) 640 if (*ptr == '/') { 641 entry++; 642 *ptr = '\0'; 643 } 644 DEBUG1(ARCH, 645 "Found svr4 archive name table with %lu entries\n", 646 (unsigned long)entry); 647 return 0; 648 } 649 650 if (inout_name[1] == ' ' || inout_name[1] == '\0') 651 return 2; 652 653 entry = (size_t)strtol(&inout_name[1], &eptr, 0); 654 if ((*eptr != ' ' && *eptr != '\0') || eptr == &inout_name[1]) { 655 DEBUG1(ARCH, "Could not parse SVR4 name %s\n", inout_name); 656 return 2; 657 } 658 if (entry >= ar->fnamesize) { 659 DEBUG2(ARCH, "SVR4 entry offset %s is greater than %lu\n", 660 inout_name, (unsigned long)ar->fnamesize); 661 return 2; 662 } 663 664 DEBUG2(ARCH, "Replaced %s with %s\n", inout_name, &ar->fnametab[entry]); 665 666 snprintf(inout_name, MAXPATHLEN + 1, "%s", &ar->fnametab[entry]); 667 return 1; 668 } 669 #endif 670 671 672 static bool 673 ArchiveMember_HasName(const struct ar_hdr *hdr, 674 const char *name, size_t namelen) 675 { 676 const size_t ar_name_len = sizeof hdr->ar_name; 677 const char *ar_name = hdr->ar_name; 678 679 if (strncmp(ar_name, name, namelen) != 0) 680 return false; 681 682 if (namelen >= ar_name_len) 683 return namelen == ar_name_len; 684 685 /* hdr->ar_name is space-padded to the right. */ 686 if (ar_name[namelen] == ' ') 687 return true; 688 689 /* 690 * In archives created by GNU binutils 2.27, the member names end 691 * with a slash. 692 */ 693 if (ar_name[namelen] == '/' && 694 (namelen == ar_name_len || ar_name[namelen + 1] == ' ')) 695 return true; 696 697 return false; 698 } 699 700 /* 701 * Locate a member of an archive, given the path of the archive and the path 702 * of the desired member. 703 * 704 * Input: 705 * archive Path to the archive 706 * member Name of member. If it is a path, only the last 707 * component is used. 708 * out_arh Archive header to be filled in 709 * mode "r" for read-only access, "r+" for read-write access 710 * 711 * Output: 712 * return The archive file, positioned at the start of the 713 * member's struct ar_hdr, or NULL if the member doesn't 714 * exist. 715 * *out_arh The current struct ar_hdr for member. 716 * 717 * See ArchStatMember for an almost identical copy of this code. 718 */ 719 static FILE * 720 ArchFindMember(const char *archive, const char *member, struct ar_hdr *out_arh, 721 const char *mode) 722 { 723 FILE *arch; /* Stream to archive */ 724 int size; /* Size of archive member */ 725 char magic[SARMAG]; 726 size_t len; 727 728 arch = fopen(archive, mode); 729 if (arch == NULL) 730 return NULL; 731 732 /* 733 * We use the ARMAG string to make sure this is an archive we 734 * can handle... 735 */ 736 if (fread(magic, SARMAG, 1, arch) != 1 || 737 strncmp(magic, ARMAG, SARMAG) != 0) { 738 fclose(arch); 739 return NULL; 740 } 741 742 /* 743 * Because of space constraints and similar things, files are archived 744 * using their basename, not the entire path. 745 */ 746 member = str_basename(member); 747 748 len = strlen(member); 749 750 while (fread(out_arh, sizeof *out_arh, 1, arch) == 1) { 751 752 if (strncmp(out_arh->ar_fmag, ARFMAG, 753 sizeof out_arh->ar_fmag) != 0) { 754 /* 755 * The header is bogus, so the archive is bad 756 * and there's no way we can recover... 757 */ 758 fclose(arch); 759 return NULL; 760 } 761 762 DEBUG5(ARCH, "Reading archive %s member %.*s mtime %.*s\n", 763 archive, 764 (int)sizeof out_arh->ar_name, out_arh->ar_name, 765 (int)sizeof out_arh->ar_date, out_arh->ar_date); 766 767 if (ArchiveMember_HasName(out_arh, member, len)) { 768 /* 769 * To make life easier for callers that want to update 770 * the archive, we reposition the file at the start of 771 * the header we just read before we return the 772 * stream. In a more general situation, it might be 773 * better to leave the file at the actual member, 774 * rather than its header, but not here. 775 */ 776 if (fseek(arch, -(long)sizeof *out_arh, SEEK_CUR) != 777 0) { 778 fclose(arch); 779 return NULL; 780 } 781 return arch; 782 } 783 784 #ifdef AR_EFMT1 785 /* 786 * BSD 4.4 extended AR format: #1/<namelen>, with name as the 787 * first <namelen> bytes of the file 788 */ 789 if (strncmp(out_arh->ar_name, AR_EFMT1, sizeof AR_EFMT1 - 1) == 790 0 && 791 (ch_isdigit(out_arh->ar_name[sizeof AR_EFMT1 - 1]))) { 792 size_t elen = (size_t)atoi( 793 &out_arh->ar_name[sizeof AR_EFMT1 - 1]); 794 char ename[MAXPATHLEN + 1]; 795 796 if (elen > MAXPATHLEN) { 797 fclose(arch); 798 return NULL; 799 } 800 if (fread(ename, elen, 1, arch) != 1) { 801 fclose(arch); 802 return NULL; 803 } 804 ename[elen] = '\0'; 805 if (DEBUG(ARCH) || DEBUG(MAKE)) 806 debug_printf( 807 "ArchFindMember: " 808 "Extended format entry for %s\n", 809 ename); 810 if (strncmp(ename, member, len) == 0) { 811 /* Found as extended name */ 812 if (fseek(arch, 813 -(long)(sizeof(struct ar_hdr) - elen), 814 SEEK_CUR) != 0) { 815 fclose(arch); 816 return NULL; 817 } 818 return arch; 819 } 820 if (fseek(arch, -(long)elen, SEEK_CUR) != 0) { 821 fclose(arch); 822 return NULL; 823 } 824 } 825 #endif 826 827 /* 828 * This isn't the member we're after, so we need to advance the 829 * stream's pointer to the start of the next header. Files are 830 * padded with newlines to an even-byte boundary, so we need to 831 * extract the size of the file from the 'size' field of the 832 * header and round it up during the seek. 833 */ 834 out_arh->ar_size[sizeof out_arh->ar_size - 1] = '\0'; 835 size = (int)strtol(out_arh->ar_size, NULL, 10); 836 if (fseek(arch, (size + 1) & ~1L, SEEK_CUR) != 0) { 837 fclose(arch); 838 return NULL; 839 } 840 } 841 842 fclose(arch); 843 return NULL; 844 } 845 846 /* 847 * Touch a member of an archive, on disk. 848 * The GNode's modification time is left as-is. 849 * 850 * The st_mtime of the entire archive is also changed. 851 * For a library, it may be required to run ranlib after this. 852 * 853 * Input: 854 * gn Node of member to touch 855 * 856 * Results: 857 * The 'time' field of the member's header is updated. 858 */ 859 void 860 Arch_Touch(GNode *gn) 861 { 862 FILE *f; 863 struct ar_hdr arh; 864 865 f = ArchFindMember(GNode_VarArchive(gn), GNode_VarMember(gn), &arh, 866 "r+"); 867 if (f == NULL) 868 return; 869 870 snprintf(arh.ar_date, sizeof arh.ar_date, "%-ld", (unsigned long)now); 871 (void)fwrite(&arh, sizeof arh, 1, f); 872 fclose(f); /* TODO: handle errors */ 873 } 874 875 /* 876 * Given a node which represents a library, touch the thing, making sure that 877 * the table of contents is also touched. 878 * 879 * Both the modification time of the library and of the RANLIBMAG member are 880 * set to 'now'. 881 */ 882 /*ARGSUSED*/ 883 void 884 Arch_TouchLib(GNode *gn MAKE_ATTR_UNUSED) 885 { 886 #ifdef RANLIBMAG 887 FILE *f; 888 struct ar_hdr arh; /* Header describing table of contents */ 889 struct utimbuf times; 890 891 f = ArchFindMember(gn->path, RANLIBMAG, &arh, "r+"); 892 if (f == NULL) 893 return; 894 895 snprintf(arh.ar_date, sizeof arh.ar_date, "%-ld", (unsigned long)now); 896 (void)fwrite(&arh, sizeof arh, 1, f); 897 fclose(f); /* TODO: handle errors */ 898 899 times.actime = times.modtime = now; 900 utime(gn->path, ×); /* TODO: handle errors */ 901 #endif 902 } 903 904 /* 905 * Update the mtime of the GNode with the mtime from the archive member on 906 * disk (or in the cache). 907 */ 908 void 909 Arch_UpdateMTime(GNode *gn) 910 { 911 struct ar_hdr *arh; 912 913 arh = ArchStatMember(GNode_VarArchive(gn), GNode_VarMember(gn), true); 914 if (arh != NULL) 915 gn->mtime = (time_t)strtol(arh->ar_date, NULL, 10); 916 else 917 gn->mtime = 0; 918 } 919 920 /* 921 * Given a nonexistent archive member's node, update gn->mtime from its 922 * archived form, if it exists. 923 */ 924 void 925 Arch_UpdateMemberMTime(GNode *gn) 926 { 927 GNodeListNode *ln; 928 929 for (ln = gn->parents.first; ln != NULL; ln = ln->next) { 930 GNode *pgn = ln->datum; 931 932 if (pgn->type & OP_ARCHV) { 933 /* 934 * If the parent is an archive specification and is 935 * being made and its member's name matches the name 936 * of the node we were given, record the modification 937 * time of the parent in the child. We keep searching 938 * its parents in case some other parent requires this 939 * child to exist. 940 */ 941 const char *nameStart = strchr(pgn->name, '(') + 1; 942 const char *nameEnd = strchr(nameStart, ')'); 943 size_t nameLen = (size_t)(nameEnd - nameStart); 944 945 if (pgn->flags.remake && 946 strncmp(nameStart, gn->name, nameLen) == 0) { 947 Arch_UpdateMTime(pgn); 948 gn->mtime = pgn->mtime; 949 } 950 } else if (pgn->flags.remake) { 951 /* 952 * Something which isn't a library depends on the 953 * existence of this target, so it needs to exist. 954 */ 955 gn->mtime = 0; 956 break; 957 } 958 } 959 } 960 961 /* 962 * Search for a library along the given search path. 963 * 964 * The node's 'path' field is set to the found path (including the 965 * actual file name, not -l...). If the system can handle the -L 966 * flag when linking (or we cannot find the library), we assume that 967 * the user has placed the .LIBS variable in the final linking 968 * command (or the linker will know where to find it) and set the 969 * TARGET variable for this node to be the node's name. Otherwise, 970 * we set the TARGET variable to be the full path of the library, 971 * as returned by Dir_FindFile. 972 * 973 * Input: 974 * gn Node of library to find 975 */ 976 void 977 Arch_FindLib(GNode *gn, SearchPath *path) 978 { 979 char *libName = str_concat3("lib", gn->name + 2, ".a"); 980 gn->path = Dir_FindFile(libName, path); 981 free(libName); 982 983 #ifdef LIBRARIES 984 Var_Set(gn, TARGET, gn->name); 985 #else 986 Var_Set(gn, TARGET, GNode_Path(gn)); 987 #endif 988 } 989 990 /* ARGSUSED */ 991 static bool 992 RanlibOODate(const GNode *gn MAKE_ATTR_UNUSED) 993 { 994 #ifdef RANLIBMAG 995 struct ar_hdr *arh; /* Header for __.SYMDEF */ 996 int tocModTime; /* The table-of-contents' mod time */ 997 998 arh = ArchStatMember(gn->path, RANLIBMAG, false); 999 1000 if (arh == NULL) { 1001 /* A library without a table of contents is out-of-date. */ 1002 if (DEBUG(ARCH) || DEBUG(MAKE)) 1003 debug_printf("no toc..."); 1004 return true; 1005 } 1006 1007 tocModTime = (int)strtol(arh->ar_date, NULL, 10); 1008 1009 if (DEBUG(ARCH) || DEBUG(MAKE)) 1010 debug_printf("%s modified %s...", 1011 RANLIBMAG, Targ_FmtTime(tocModTime)); 1012 return gn->youngestChild == NULL || 1013 gn->youngestChild->mtime > tocModTime; 1014 #else 1015 return false; 1016 #endif 1017 } 1018 1019 /* 1020 * Decide if a node with the OP_LIB attribute is out-of-date. Called from 1021 * GNode_IsOODate to make its life easier. 1022 * The library is cached if it hasn't been already. 1023 * 1024 * There are several ways for a library to be out-of-date that are 1025 * not available to ordinary files. In addition, there are ways 1026 * that are open to regular files that are not available to 1027 * libraries. 1028 * 1029 * A library that is only used as a source is never 1030 * considered out-of-date by itself. This does not preclude the 1031 * library's modification time from making its parent be out-of-date. 1032 * A library will be considered out-of-date for any of these reasons, 1033 * given that it is a target on a dependency line somewhere: 1034 * 1035 * Its modification time is less than that of one of its sources 1036 * (gn->mtime < gn->youngestChild->mtime). 1037 * 1038 * Its modification time is greater than the time at which the make 1039 * began (i.e. it's been modified in the course of the make, probably 1040 * by archiving). 1041 * 1042 * The modification time of one of its sources is greater than the one 1043 * of its RANLIBMAG member (i.e. its table of contents is out-of-date). 1044 * We don't compare the archive time vs. TOC time because they can be 1045 * too close. In my opinion we should not bother with the TOC at all 1046 * since this is used by 'ar' rules that affect the data contents of the 1047 * archive, not by ranlib rules, which affect the TOC. 1048 */ 1049 bool 1050 Arch_LibOODate(GNode *gn) 1051 { 1052 1053 if (gn->type & OP_PHONY) { 1054 return true; 1055 } else if (!GNode_IsTarget(gn) && Lst_IsEmpty(&gn->children)) { 1056 return false; 1057 } else if ((!Lst_IsEmpty(&gn->children) && gn->youngestChild == NULL) || 1058 (gn->mtime > now) || 1059 (gn->youngestChild != NULL && 1060 gn->mtime < gn->youngestChild->mtime)) { 1061 return true; 1062 } else { 1063 return RanlibOODate(gn); 1064 } 1065 } 1066 1067 /* Initialize the archives module. */ 1068 void 1069 Arch_Init(void) 1070 { 1071 Lst_Init(&archives); 1072 } 1073 1074 /* Clean up the archives module. */ 1075 void 1076 Arch_End(void) 1077 { 1078 #ifdef CLEANUP 1079 Lst_DoneCall(&archives, ArchFree); 1080 #endif 1081 } 1082 1083 bool 1084 Arch_IsLib(GNode *gn) 1085 { 1086 static const char armag[] = "!<arch>\n"; 1087 char buf[sizeof armag - 1]; 1088 int fd; 1089 1090 if ((fd = open(gn->path, O_RDONLY)) == -1) 1091 return false; 1092 1093 if (read(fd, buf, sizeof buf) != sizeof buf) { 1094 (void)close(fd); 1095 return false; 1096 } 1097 1098 (void)close(fd); 1099 1100 return memcmp(buf, armag, sizeof buf) == 0; 1101 } 1102