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