1 /* $OpenPackages$ */ 2 /* $OpenBSD: arch.c,v 1.75 2007/11/17 16:39:45 espie Exp $ */ 3 /* $NetBSD: arch.c,v 1.17 1996/11/06 17:58:59 christos Exp $ */ 4 5 /* 6 * Copyright (c) 1999,2000 Marc Espie. 7 * 8 * Extensive code changes for the OpenBSD project. 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD 23 * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 /* 32 * Copyright (c) 1988, 1989, 1990, 1993 33 * The Regents of the University of California. All rights reserved. 34 * Copyright (c) 1989 by Berkeley Softworks 35 * All rights reserved. 36 * 37 * This code is derived from software contributed to Berkeley by 38 * Adam de Boor. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 3. Neither the name of the University nor the names of its contributors 49 * may be used to endorse or promote products derived from this software 50 * without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 */ 64 65 /* 66 * Once again, cacheing/hashing comes into play in the manipulation 67 * of archives. The first time an archive is referenced, all of its members' 68 * headers are read and hashed and the archive closed again. All hashed 69 * archives are kept in a hash (archives) which is searched each time 70 * an archive member is referenced. 71 * 72 */ 73 74 #include <sys/param.h> 75 #include <ar.h> 76 #include <assert.h> 77 #include <ctype.h> 78 #include <fcntl.h> 79 #include <limits.h> 80 #include <stddef.h> 81 #include <stdio.h> 82 #include <stdint.h> 83 #include <stdlib.h> 84 #include <string.h> 85 #include <unistd.h> 86 #include "ohash.h" 87 #include "config.h" 88 #include "defines.h" 89 #include "buf.h" 90 #include "dir.h" 91 #include "direxpand.h" 92 #include "arch.h" 93 #include "var.h" 94 #include "targ.h" 95 #include "memory.h" 96 #include "gnode.h" 97 #include "timestamp.h" 98 #include "lst.h" 99 100 #ifndef PATH_MAX 101 # ifdef MAXPATHLEN 102 # define PATH_MAX (MAXPATHLEN+1) 103 # else 104 # define PATH_MAX 1024 105 # endif 106 #endif 107 108 #ifdef TARGET_MACHINE 109 #undef MACHINE 110 #define MACHINE TARGET_MACHINE 111 #endif 112 #ifdef TARGET_MACHINE_ARCH 113 #undef MACHINE_ARCH 114 #define MACHINE_ARCH TARGET_MACHINE_ARCH 115 #endif 116 117 static struct ohash archives; /* Archives we've already examined. */ 118 119 typedef struct Arch_ { 120 struct ohash members; /* All the members of this archive, as 121 * struct arch_member entries. */ 122 char name[1]; /* Archive name. */ 123 } Arch; 124 125 /* Used to get to ar's field sizes. */ 126 static struct ar_hdr *dummy; 127 #define AR_NAME_SIZE (sizeof(dummy->ar_name)) 128 #define AR_DATE_SIZE (sizeof(dummy->ar_date)) 129 130 /* Each archive member is tied to an arch_member structure, 131 * suitable for hashing. */ 132 struct arch_member { 133 TIMESTAMP mtime; /* Member modification date. */ 134 char date[AR_DATE_SIZE+1]; /* Same, before conversion to numeric 135 * value. */ 136 char name[1]; /* Member name. */ 137 }; 138 139 static struct ohash_info members_info = { 140 offsetof(struct arch_member, name), NULL, 141 hash_alloc, hash_free, element_alloc 142 }; 143 144 static struct ohash_info arch_info = { 145 offsetof(Arch, name), NULL, hash_alloc, hash_free, element_alloc 146 }; 147 148 149 150 static struct arch_member *new_arch_member(struct ar_hdr *, const char *); 151 static TIMESTAMP mtime_of_member(struct arch_member *); 152 static long field2long(const char *, size_t); 153 static Arch *read_archive(const char *, const char *); 154 155 #ifdef CLEANUP 156 static void ArchFree(Arch *); 157 #endif 158 static TIMESTAMP ArchMTimeMember(const char *, const char *, bool); 159 static FILE *ArchFindMember(const char *, const char *, struct ar_hdr *, const char *); 160 static void ArchTouch(const char *, const char *); 161 #if defined(__svr4__) || defined(__SVR4) || \ 162 (defined(__OpenBSD__) && defined(__ELF__)) 163 #define SVR4ARCHIVES 164 #endif 165 static bool parse_archive(Buffer, const char **, Lst, SymTable *); 166 static void add_archive_node(Lst, const char *); 167 168 struct SVR4namelist { 169 char *fnametab; /* Extended name table strings */ 170 size_t fnamesize; /* Size of the string table */ 171 }; 172 173 #ifdef SVR4ARCHIVES 174 static const char *svr4list = "Archive list"; 175 176 static char *ArchSVR4Entry(struct SVR4namelist *, const char *, size_t, FILE *); 177 #endif 178 179 static struct arch_member * 180 new_arch_member(struct ar_hdr *hdr, const char *name) 181 { 182 const char *end = NULL; 183 struct arch_member *n; 184 185 n = ohash_create_entry(&members_info, name, &end); 186 /* XXX ar entries are NOT null terminated. */ 187 memcpy(n->date, &(hdr->ar_date), AR_DATE_SIZE); 188 n->date[AR_DATE_SIZE] = '\0'; 189 /* Don't compute mtime before it is needed. */ 190 ts_set_out_of_date(n->mtime); 191 return n; 192 } 193 194 static TIMESTAMP 195 mtime_of_member(struct arch_member *m) 196 { 197 if (is_out_of_date(m->mtime)) 198 ts_set_from_time_t((time_t) strtol(m->date, NULL, 10), 199 m->mtime); 200 return m->mtime; 201 } 202 203 #ifdef CLEANUP 204 static void 205 ArchFree(Arch *a) 206 { 207 /* Free memory from hash entries */ 208 free_hash(&a->members); 209 free(a); 210 } 211 #endif 212 213 bool 214 Arch_ParseArchive(const char **line, Lst nodes, SymTable *ctxt) 215 { 216 bool result; 217 BUFFER expand; 218 219 Buf_Init(&expand, MAKE_BSIZE); 220 result = parse_archive(&expand, line, nodes, ctxt); 221 Buf_Destroy(&expand); 222 return result; 223 } 224 225 static void 226 add_archive_node(Lst nodes, const char *name) 227 { 228 GNode *gn; 229 230 gn = Targ_FindNode(name, TARG_CREATE); 231 gn->type |= OP_ARCHV; 232 Lst_AtEnd(nodes, gn); 233 } 234 235 static bool 236 parse_archive(Buffer expand, const char **linePtr, Lst nodeLst, SymTable *ctxt) 237 { 238 const char *cp; /* Pointer into line */ 239 const char *lib; /* Library-part of specification */ 240 const char *elib; 241 const char *member; /* Member-part of specification */ 242 const char *emember; 243 bool subst_lib; 244 245 /* figure out the library name part */ 246 lib = *linePtr; 247 subst_lib = false; 248 249 for (cp = lib; *cp != '(' && *cp != '\0';) { 250 if (*cp == '$') { 251 if (!Var_ParseSkip(&cp, ctxt)) 252 return false; 253 subst_lib = true; 254 } else 255 cp++; 256 } 257 258 elib = cp; 259 if (subst_lib) { 260 lib = Var_Substi(lib, elib, ctxt, true); 261 elib = lib + strlen(lib); 262 } 263 264 cp++; 265 /* iterate on members, that may be separated by spaces */ 266 for (;;) { 267 /* First skip to the start of the member's name, mark that 268 * place and skip to the end of it (either white-space or 269 * a close paren). */ 270 bool subst_member = false; 271 272 while (isspace(*cp)) 273 cp++; 274 member = cp; 275 while (*cp != '\0' && *cp != ')' && !isspace(*cp)) { 276 if (*cp == '$') { 277 if (!Var_ParseSkip(&cp, ctxt)) 278 return false; 279 subst_member = true; 280 } else 281 cp++; 282 } 283 284 /* If the specification ends without a closing parenthesis, 285 * chances are there's something wrong (like a missing 286 * backslash), so it's better to return failure than allow such 287 * things to happen. */ 288 if (*cp == '\0') { 289 printf("No closing parenthesis in archive specification\n"); 290 return false; 291 } 292 293 /* If we didn't move anywhere, we must be done. */ 294 if (cp == member) 295 break; 296 297 emember = cp; 298 299 /* XXX: This should be taken care of intelligently by 300 * SuffExpandChildren, both for the archive and the member 301 * portions. */ 302 303 /* If member contains variables, try and substitute for them. 304 * This will slow down archive specs with dynamic sources, of 305 * course, since we'll be (non-)substituting them three times, 306 * but them's the breaks -- we need to do this since 307 * SuffExpandChildren calls us, otherwise we could assume the 308 * thing would be taken care of later. */ 309 if (subst_member) { 310 const char *oldMemberName = member; 311 const char *result; 312 313 member = Var_Substi(member, emember, ctxt, true); 314 315 /* Now form an archive spec and recurse to deal with 316 * nested variables and multi-word variable values.... 317 * The results are just placed at the end of the 318 * nodeLst we're returning. */ 319 Buf_Addi(expand, lib, elib); 320 Buf_AddChar(expand, '('); 321 Buf_AddString(expand, member); 322 Buf_AddChar(expand, ')'); 323 result = Buf_Retrieve(expand); 324 325 if (strchr(member, '$') && 326 memcmp(member, oldMemberName, 327 emember - oldMemberName) == 0) { 328 /* Must contain dynamic sources, so we can't 329 * deal with it now. let SuffExpandChildren 330 * handle it later */ 331 add_archive_node(nodeLst, result); 332 } else if (!Arch_ParseArchive(&result, nodeLst, ctxt)) 333 return false; 334 Buf_Reset(expand); 335 } else if (Dir_HasWildcardsi(member, emember)) { 336 LIST members; 337 char *m; 338 339 Lst_Init(&members); 340 341 Dir_Expandi(member, emember, defaultPath, &members); 342 while ((m = (char *)Lst_DeQueue(&members)) != NULL) { 343 Buf_Addi(expand, lib, elib); 344 Buf_AddChar(expand, '('); 345 Buf_AddString(expand, m); 346 Buf_AddChar(expand, ')'); 347 free(m); 348 add_archive_node(nodeLst, Buf_Retrieve(expand)); 349 Buf_Reset(expand); 350 } 351 } else { 352 Buf_Addi(expand, lib, elib); 353 Buf_AddChar(expand, '('); 354 Buf_Addi(expand, member, emember); 355 Buf_AddChar(expand, ')'); 356 add_archive_node(nodeLst, Buf_Retrieve(expand)); 357 Buf_Reset(expand); 358 } 359 if (subst_member) 360 free((char *)member); 361 362 } 363 364 if (subst_lib) 365 free((char *)lib); 366 367 /* We promised the pointer would be set up at the next non-space, so 368 * we must advance cp there before setting *linePtr... (note that on 369 * entrance to the loop, cp is guaranteed to point at a ')') */ 370 do { 371 cp++; 372 } while (isspace(*cp)); 373 374 *linePtr = cp; 375 return true; 376 } 377 378 /* Helper function: ar fields are not null terminated. */ 379 static long 380 field2long(const char *field, size_t length) 381 { 382 static char enough[32]; 383 384 assert(length < sizeof(enough)); 385 memcpy(enough, field, length); 386 enough[length] = '\0'; 387 return strtol(enough, NULL, 10); 388 } 389 390 static Arch * 391 read_archive(const char *archive, const char *earchive) 392 { 393 FILE *arch; /* Stream to archive */ 394 char magic[SARMAG]; 395 Arch *ar; 396 struct SVR4namelist list; 397 398 list.fnametab = NULL; 399 400 /* When we encounter an archive for the first time, we read its 401 * whole contents, to place it in the cache. */ 402 arch = fopen(archive, "r"); 403 if (arch == NULL) 404 return NULL; 405 406 /* Make sure this is an archive we can handle. */ 407 if ((fread(magic, SARMAG, 1, arch) != 1) || 408 (strncmp(magic, ARMAG, SARMAG) != 0)) { 409 fclose(arch); 410 return NULL; 411 } 412 413 ar = ohash_create_entry(&arch_info, archive, &earchive); 414 ohash_init(&ar->members, 8, &members_info); 415 416 for (;;) { 417 size_t n; 418 struct ar_hdr arHeader; /* Archive-member header */ 419 off_t size; /* Size of archive member */ 420 char buffer[PATH_MAX]; 421 char *memberName; /* Current member name while hashing. */ 422 char *cp; 423 424 memberName = buffer; 425 n = fread(&arHeader, 1, sizeof(struct ar_hdr), arch); 426 427 /* Whole archive read ok. */ 428 if (n == 0 && feof(arch)) { 429 efree(list.fnametab); 430 fclose(arch); 431 return ar; 432 } 433 if (n < sizeof(struct ar_hdr)) 434 break; 435 436 if (memcmp(arHeader.ar_fmag, ARFMAG, sizeof(arHeader.ar_fmag)) 437 != 0) { 438 /* header is bogus. */ 439 break; 440 } else { 441 /* We need to advance the stream's pointer to the start 442 * of the next header. Records are padded with 443 * newlines to an even-byte boundary, so we need to 444 * extract the size of the record and round it up 445 * during the seek. */ 446 size = (off_t) field2long(arHeader.ar_size, 447 sizeof(arHeader.ar_size)); 448 449 (void)memcpy(memberName, arHeader.ar_name, 450 AR_NAME_SIZE); 451 /* Find real end of name (strip extranous ' ') */ 452 for (cp = memberName + AR_NAME_SIZE - 1; *cp == ' ';) 453 cp--; 454 cp[1] = '\0'; 455 456 #ifdef SVR4ARCHIVES 457 /* SVR4 names are slash terminated. Also svr4 extended 458 * AR format. 459 */ 460 if (memberName[0] == '/') { 461 /* SVR4 magic mode. */ 462 memberName = ArchSVR4Entry(&list, memberName, 463 size, arch); 464 if (memberName == NULL) 465 /* Invalid data */ 466 break; 467 else if (memberName == svr4list) 468 /* List of files entry */ 469 continue; 470 /* Got the entry. */ 471 /* XXX this assumes further processing, such as 472 * AR_EFMT1, also applies to SVR4ARCHIVES. */ 473 } 474 else { 475 if (cp[0] == '/') 476 cp[0] = '\0'; 477 } 478 #endif 479 480 #ifdef AR_EFMT1 481 /* BSD 4.4 extended AR format: #1/<namelen>, with name 482 * as the first <namelen> bytes of the file. */ 483 if (memcmp(memberName, AR_EFMT1, sizeof(AR_EFMT1) - 1) 484 == 0 && isdigit(memberName[sizeof(AR_EFMT1) - 1])) { 485 486 int elen = atoi(memberName + 487 sizeof(AR_EFMT1)-1); 488 489 if (elen <= 0 || elen >= PATH_MAX) 490 break; 491 memberName = buffer; 492 if (fread(memberName, elen, 1, arch) != 1) 493 break; 494 memberName[elen] = '\0'; 495 if (fseek(arch, -elen, SEEK_CUR) != 0) 496 break; 497 if (DEBUG(ARCH) || DEBUG(MAKE)) 498 printf("ArchStat: Extended format entry for %s\n", 499 memberName); 500 } 501 #endif 502 503 ohash_insert(&ar->members, 504 ohash_qlookup(&ar->members, memberName), 505 new_arch_member(&arHeader, memberName)); 506 } 507 if (fseek(arch, (size + 1) & ~1, SEEK_CUR) != 0) 508 break; 509 } 510 511 fclose(arch); 512 ohash_delete(&ar->members); 513 efree(list.fnametab); 514 free(ar); 515 return NULL; 516 } 517 518 /*- 519 *----------------------------------------------------------------------- 520 * ArchMTimeMember -- 521 * Find the modification time of an archive's member, given the 522 * path to the archive and the path to the desired member. 523 * 524 * Results: 525 * The archive member's modification time, or OUT_OF_DATE if member 526 * was not found (convenient, so that missing members are always 527 * out of date). 528 * 529 * Side Effects: 530 * Cache the whole archive contents if hash is true. 531 *----------------------------------------------------------------------- 532 */ 533 static TIMESTAMP 534 ArchMTimeMember( 535 const char *archive, /* Path to the archive */ 536 const char *member, /* Name of member. If it is a path, only the 537 * last component is used. */ 538 bool hash) /* true if archive should be hashed if not 539 * already so. */ 540 { 541 FILE *arch; /* Stream to archive */ 542 Arch *ar; /* Archive descriptor */ 543 unsigned int slot; /* Place of archive in the archives hash */ 544 const char *end = NULL; 545 const char *cp; 546 TIMESTAMP result; 547 548 ts_set_out_of_date(result); 549 /* Because of space constraints and similar things, files are archived 550 * using their final path components, not the entire thing, so we need 551 * to point 'member' to the final component, if there is one, to make 552 * the comparisons easier... */ 553 cp = strrchr(member, '/'); 554 if (cp != NULL) 555 member = cp + 1; 556 557 /* Try to find archive in cache. */ 558 slot = ohash_qlookupi(&archives, archive, &end); 559 ar = ohash_find(&archives, slot); 560 561 /* If not found, get it now. */ 562 if (ar == NULL) { 563 if (!hash) { 564 /* Quick path: no need to hash the whole archive, just 565 * use ArchFindMember to get the member's header and 566 * close the stream again. */ 567 struct ar_hdr arHeader; 568 569 arch = ArchFindMember(archive, member, &arHeader, "r"); 570 571 if (arch != NULL) { 572 fclose(arch); 573 ts_set_from_time_t( 574 (time_t)strtol(arHeader.ar_date, NULL, 10), 575 result); 576 } 577 return result; 578 } 579 ar = read_archive(archive, end); 580 if (ar != NULL) 581 ohash_insert(&archives, slot, ar); 582 } 583 584 /* If archive was found, get entry we seek. */ 585 if (ar != NULL) { 586 struct arch_member *he; 587 end = NULL; 588 589 he = ohash_find(&ar->members, ohash_qlookupi(&ar->members, 590 member, &end)); 591 if (he != NULL) 592 return mtime_of_member(he); 593 else { 594 if ((size_t)(end - member) > AR_NAME_SIZE) { 595 /* Try truncated name. */ 596 end = member + AR_NAME_SIZE; 597 he = ohash_find(&ar->members, 598 ohash_qlookupi(&ar->members, member, &end)); 599 if (he != NULL) 600 return mtime_of_member(he); 601 } 602 } 603 } 604 return result; 605 } 606 607 #ifdef SVR4ARCHIVES 608 /*- 609 *----------------------------------------------------------------------- 610 * ArchSVR4Entry -- 611 * Parse an SVR4 style entry that begins with a slash. 612 * If it is "//", then load the table of filenames 613 * If it is "/<offset>", then try to substitute the long file name 614 * from offset of a table previously read. 615 * 616 * Results: 617 * svr4list: just read a list of names 618 * NULL: error occurred 619 * extended name 620 * 621 * Side-effect: 622 * For a list of names, store the list in l. 623 *----------------------------------------------------------------------- 624 */ 625 626 static char * 627 ArchSVR4Entry(struct SVR4namelist *l, const char *name, size_t size, FILE *arch) 628 { 629 #define ARLONGNAMES1 "/" 630 #define ARLONGNAMES2 "ARFILENAMES" 631 size_t entry; 632 char *ptr, *eptr; 633 634 assert(name[0] == '/'); 635 name++; 636 /* First comes a table of archive names, to be used by subsequent 637 * calls. */ 638 if (memcmp(name, ARLONGNAMES1, sizeof(ARLONGNAMES1) - 1) == 0 || 639 memcmp(name, ARLONGNAMES2, sizeof(ARLONGNAMES2) - 1) == 0) { 640 641 if (l->fnametab != NULL) { 642 if (DEBUG(ARCH)) 643 printf("Attempted to redefine an SVR4 name table\n"); 644 return NULL; 645 } 646 647 l->fnametab = emalloc(size); 648 l->fnamesize = size; 649 650 if (fread(l->fnametab, size, 1, arch) != 1) { 651 if (DEBUG(ARCH)) 652 printf("Reading an SVR4 name table failed\n"); 653 return NULL; 654 } 655 656 eptr = l->fnametab + size; 657 for (entry = 0, ptr = l->fnametab; ptr < eptr; ptr++) 658 switch (*ptr) { 659 case '/': 660 entry++; 661 *ptr = '\0'; 662 break; 663 664 case '\n': 665 break; 666 667 default: 668 break; 669 } 670 if (DEBUG(ARCH)) 671 printf("Found svr4 archive name table with %lu entries\n", 672 (u_long)entry); 673 return (char *)svr4list; 674 } 675 /* Then the names themselves are given as offsets in this table. */ 676 if (*name == ' ' || *name == '\0') 677 return NULL; 678 679 entry = (size_t) strtol(name, &eptr, 0); 680 if ((*eptr != ' ' && *eptr != '\0') || eptr == name) { 681 if (DEBUG(ARCH)) 682 printf("Could not parse SVR4 name /%s\n", name); 683 return NULL; 684 } 685 if (entry >= l->fnamesize) { 686 if (DEBUG(ARCH)) 687 printf("SVR4 entry offset /%s is greater than %lu\n", 688 name, (u_long)l->fnamesize); 689 return NULL; 690 } 691 692 if (DEBUG(ARCH)) 693 printf("Replaced /%s with %s\n", name, l->fnametab + entry); 694 695 return l->fnametab + entry; 696 } 697 #endif 698 699 700 /*- 701 *----------------------------------------------------------------------- 702 * ArchFindMember -- 703 * Locate a member of an archive, given the path of the archive and 704 * the path of the desired member. If the archive is to be modified, 705 * the mode should be "r+", if not, it should be "r". 706 * 707 * Results: 708 * A FILE *, opened for reading and writing, positioned right after 709 * the member's header, or NULL if the member was nonexistent. 710 * 711 * Side Effects: 712 * Fill the struct ar_hdr pointed by arHeaderPtr. 713 *----------------------------------------------------------------------- 714 */ 715 static FILE * 716 ArchFindMember( 717 const char *archive, /* Path to the archive */ 718 const char *member, /* Name of member. If it is a path, only the 719 * last component is used. */ 720 struct ar_hdr *arHeaderPtr,/* Pointer to header structure to be filled in */ 721 const char *mode) /* mode for opening the stream */ 722 { 723 FILE * arch; /* Stream to archive */ 724 char *cp; 725 char magic[SARMAG]; 726 size_t length; 727 struct SVR4namelist list; 728 729 list.fnametab = NULL; 730 731 arch = fopen(archive, mode); 732 if (arch == NULL) 733 return NULL; 734 735 /* Make sure this is an archive we can handle. */ 736 if (fread(magic, SARMAG, 1, arch) != 1 || 737 strncmp(magic, ARMAG, SARMAG) != 0) { 738 fclose(arch); 739 return NULL; 740 } 741 742 /* Because of space constraints and similar things, files are archived 743 * using their final path components, not the entire thing, so we need 744 * to point 'member' to the final component, if there is one, to make 745 * the comparisons easier... */ 746 cp = strrchr(member, '/'); 747 if (cp != NULL) 748 member = cp + 1; 749 750 length = strlen(member); 751 if (length >= AR_NAME_SIZE) 752 length = AR_NAME_SIZE; 753 754 /* Error handling is simpler than for read_archive, since we just 755 * look for a given member. */ 756 while (fread(arHeaderPtr, sizeof(struct ar_hdr), 1, arch) == 1) { 757 off_t size; /* Size of archive member */ 758 char *memberName; 759 760 if (memcmp(arHeaderPtr->ar_fmag, ARFMAG, 761 sizeof(arHeaderPtr->ar_fmag) ) != 0) 762 /* The header is bogus, so the archive is bad. */ 763 break; 764 765 memberName = arHeaderPtr->ar_name; 766 if (memcmp(member, memberName, length) == 0) { 767 /* If the member's name doesn't take up the entire 768 * 'name' field, we have to be careful of matching 769 * prefixes. Names are space- padded to the right, so 770 * if the character in 'name' at the end of the matched 771 * string is anything but a space, this isn't the 772 * member we sought. */ 773 #ifdef SVR4ARCHIVES 774 if (length < sizeof(arHeaderPtr->ar_name) && 775 memberName[length] == '/') 776 length++; 777 #endif 778 if (length == sizeof(arHeaderPtr->ar_name) || 779 memberName[length] == ' ') { 780 efree(list.fnametab); 781 return arch; 782 } 783 } 784 785 size = (off_t) field2long(arHeaderPtr->ar_size, 786 sizeof(arHeaderPtr->ar_size)); 787 788 #ifdef SVR4ARCHIVES 789 /* svr4 names are slash terminated. Also svr4 extended AR 790 * format. 791 */ 792 if (memberName[0] == '/') { 793 /* svr4 magic mode. */ 794 memberName = ArchSVR4Entry(&list, arHeaderPtr->ar_name, 795 size, arch); 796 if (memberName == NULL) 797 /* Invalid data */ 798 break; 799 else if (memberName == svr4list) 800 /* List of files entry */ 801 continue; 802 /* Got the entry. */ 803 if (strcmp(memberName, member) == 0) { 804 efree(list.fnametab); 805 return arch; 806 } 807 } 808 #endif 809 810 #ifdef AR_EFMT1 811 /* BSD 4.4 extended AR format: #1/<namelen>, with name as the 812 * first <namelen> bytes of the file. */ 813 if (memcmp(memberName, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0 && 814 isdigit(memberName[sizeof(AR_EFMT1) - 1])) { 815 char ename[PATH_MAX]; 816 817 int elength = atoi(memberName + sizeof(AR_EFMT1)-1); 818 819 if (elength <= 0 || elength >= PATH_MAX) 820 break; 821 if (fread(ename, elength, 1, arch) != 1) 822 break; 823 if (fseek(arch, -elength, SEEK_CUR) != 0) 824 break; 825 ename[elength] = '\0'; 826 if (DEBUG(ARCH) || DEBUG(MAKE)) 827 printf("ArchFind: Extended format entry for %s\n", ename); 828 /* Found as extended name. */ 829 if (strcmp(ename, member) == 0) { 830 efree(list.fnametab); 831 return arch; 832 } 833 } 834 #endif 835 /* This isn't the member we're after, so we need to advance the 836 * stream's pointer to the start of the next header. */ 837 if (fseek(arch, (size + 1) & ~1, SEEK_CUR) != 0) 838 break; 839 } 840 841 /* We did not find the member, or we ran into an error while reading 842 * the archive. */ 843 #ifdef SVRARCHIVES 844 efree(list.fnametab); 845 #endif 846 fclose(arch); 847 return NULL; 848 } 849 850 static void 851 ArchTouch(const char *archive, const char *member) 852 { 853 FILE *arch; 854 struct ar_hdr arHeader; 855 856 arch = ArchFindMember(archive, member, &arHeader, "r+"); 857 if (arch != NULL) { 858 snprintf(arHeader.ar_date, sizeof(arHeader.ar_date), 859 "%-12ld", (long) timestamp2time_t(now)); 860 if (fseek(arch, -sizeof(struct ar_hdr), SEEK_CUR) == 0) 861 (void)fwrite(&arHeader, sizeof(struct ar_hdr), 1, arch); 862 fclose(arch); 863 } 864 } 865 866 /* 867 * Side Effects: 868 * The modification time of the entire archive is also changed. 869 * For a library, this could necessitate the re-ranlib'ing of the 870 * whole thing. 871 */ 872 void 873 Arch_Touch(GNode *gn) 874 { 875 ArchTouch(Var(ARCHIVE_INDEX, gn), Var(MEMBER_INDEX, gn)); 876 } 877 878 /*ARGSUSED*/ 879 void 880 Arch_TouchLib(GNode *gn UNUSED) 881 /* ^ Non RANLIBMAG does nothing with it */ 882 { 883 #ifdef RANLIBMAG 884 if (gn->path != NULL) { 885 ArchTouch(gn->path, RANLIBMAG); 886 set_times(gn->path); 887 } 888 #endif 889 } 890 891 TIMESTAMP 892 Arch_MTime(GNode *gn) 893 { 894 gn->mtime = ArchMTimeMember(Var(ARCHIVE_INDEX, gn), 895 Var(MEMBER_INDEX, gn), true); 896 897 return gn->mtime; 898 } 899 900 TIMESTAMP 901 Arch_MemMTime(GNode *gn) 902 { 903 LstNode ln; 904 905 for (ln = Lst_First(&gn->parents); ln != NULL; ln = Lst_Adv(ln)) { 906 GNode *pgn; 907 char *nameStart; 908 char *nameEnd; 909 910 pgn = (GNode *)Lst_Datum(ln); 911 912 if (pgn->type & OP_ARCHV) { 913 /* If the parent is an archive specification and is 914 * being made and its member's name matches the name of 915 * the node we were given, record the modification time 916 * of the parent in the child. We keep searching its 917 * parents in case some other parent requires this 918 * child to exist... */ 919 if ((nameStart = strchr(pgn->name, '(') ) != NULL) { 920 nameStart++; 921 nameEnd = strchr(nameStart, ')'); 922 } else 923 nameEnd = NULL; 924 925 if (pgn->must_make && nameEnd != NULL && 926 strncmp(nameStart, gn->name, nameEnd - nameStart) 927 == 0 && gn->name[nameEnd-nameStart] == '\0') 928 gn->mtime = Arch_MTime(pgn); 929 } else if (pgn->must_make) { 930 /* Something which isn't a library depends on the 931 * existence of this target, so it needs to exist. */ 932 ts_set_out_of_date(gn->mtime); 933 break; 934 } 935 } 936 return gn->mtime; 937 } 938 939 /* we assume the system knows how to find libraries */ 940 void 941 Arch_FindLib(GNode *gn, Lst path UNUSED) 942 { 943 Var(TARGET_INDEX, gn) = gn->name; 944 } 945 946 /*- 947 *----------------------------------------------------------------------- 948 * Arch_LibOODate -- 949 * Decide if a node with the OP_LIB attribute is out-of-date. Called 950 * from Make_OODate to make its life easier. 951 * 952 * There are several ways for a library to be out-of-date that are 953 * not available to ordinary files. In addition, there are ways 954 * that are open to regular files that are not available to 955 * libraries. A library that is only used as a source is never 956 * considered out-of-date by itself. This does not preclude the 957 * library's modification time from making its parent be out-of-date. 958 * A library will be considered out-of-date for any of these reasons, 959 * given that it is a target on a dependency line somewhere: 960 * Its modification time is less than that of one of its 961 * sources (gn->mtime < gn->cmtime). 962 * Its modification time is greater than the time at which the 963 * make began (i.e. it's been modified in the course 964 * of the make, probably by archiving). 965 * The modification time of one of its sources is greater than 966 * the one of its RANLIBMAG member (i.e. its table of contents 967 * is out-of-date). We don't compare of the archive time 968 * vs. TOC time because they can be too close. In my 969 * opinion we should not bother with the TOC at all since 970 * this is used by 'ar' rules that affect the data contents 971 * of the archive, not by ranlib rules, which affect the 972 * TOC. 973 * 974 * Results: 975 * true if the library is out-of-date. false otherwise. 976 * 977 * Side Effects: 978 * The library will be hashed if it hasn't been already. 979 *----------------------------------------------------------------------- 980 */ 981 bool 982 Arch_LibOODate(GNode *gn) 983 { 984 #ifdef RANLIBMAG 985 TIMESTAMP modTimeTOC; /* mod time of __.SYMDEF */ 986 #endif 987 988 if (OP_NOP(gn->type) && Lst_IsEmpty(&gn->children)) 989 return false; 990 if (is_strictly_before(now, gn->mtime) || 991 is_strictly_before(gn->mtime, gn->cmtime) || 992 is_out_of_date(gn->mtime)) 993 return true; 994 #ifdef RANLIBMAG 995 /* non existent libraries are always out-of-date. */ 996 if (gn->path == NULL) 997 return true; 998 modTimeTOC = ArchMTimeMember(gn->path, RANLIBMAG, false); 999 1000 if (!is_out_of_date(modTimeTOC)) { 1001 if (DEBUG(ARCH) || DEBUG(MAKE)) 1002 printf("%s modified %s...", RANLIBMAG, 1003 time_to_string(modTimeTOC)); 1004 return is_strictly_before(modTimeTOC, gn->cmtime); 1005 } 1006 /* A library w/o a table of contents is out-of-date. */ 1007 if (DEBUG(ARCH) || DEBUG(MAKE)) 1008 printf("No t.o.c...."); 1009 return true; 1010 #else 1011 return false; 1012 #endif 1013 } 1014 1015 void 1016 Arch_Init(void) 1017 { 1018 ohash_init(&archives, 4, &arch_info); 1019 } 1020 1021 #ifdef CLEANUP 1022 void 1023 Arch_End(void) 1024 { 1025 Arch *e; 1026 unsigned int i; 1027 1028 for (e = ohash_first(&archives, &i); e != NULL; 1029 e = ohash_next(&archives, &i)) 1030 ArchFree(e); 1031 ohash_delete(&archives); 1032 } 1033 #endif 1034 1035 bool 1036 Arch_IsLib(GNode *gn) 1037 { 1038 char buf[SARMAG]; 1039 int fd; 1040 1041 if (gn->path == NULL || (fd = open(gn->path, O_RDONLY)) == -1) 1042 return false; 1043 1044 if (read(fd, buf, SARMAG) != SARMAG) { 1045 (void)close(fd); 1046 return false; 1047 } 1048 1049 (void)close(fd); 1050 1051 return memcmp(buf, ARMAG, SARMAG) == 0; 1052 } 1053