arch.c revision 52109
1/* 2 * Copyright (c) 1988, 1989, 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 1989 by Berkeley Softworks 5 * 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. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39#ifndef lint 40#if 0 41static char sccsid[] = "@(#)arch.c 8.2 (Berkeley) 1/2/94"; 42#else 43static const char rcsid[] = 44 "$FreeBSD: head/usr.bin/make/arch.c 52109 1999-10-10 20:39:36Z julian $"; 45#endif 46#endif /* not lint */ 47 48/*- 49 * arch.c -- 50 * Functions to manipulate libraries, archives and their members. 51 * 52 * Once again, cacheing/hashing comes into play in the manipulation 53 * of archives. The first time an archive is referenced, all of its members' 54 * headers are read and hashed and the archive closed again. All hashed 55 * archives are kept on a list which is searched each time an archive member 56 * is referenced. 57 * 58 * The interface to this module is: 59 * Arch_ParseArchive Given an archive specification, return a list 60 * of GNode's, one for each member in the spec. 61 * FAILURE is returned if the specification is 62 * invalid for some reason. 63 * 64 * Arch_Touch Alter the modification time of the archive 65 * member described by the given node to be 66 * the current time. 67 * 68 * Arch_TouchLib Update the modification time of the library 69 * described by the given node. This is special 70 * because it also updates the modification time 71 * of the library's table of contents. 72 * 73 * Arch_MTime Find the modification time of a member of 74 * an archive *in the archive*. The time is also 75 * placed in the member's GNode. Returns the 76 * modification time. 77 * 78 * Arch_MemTime Find the modification time of a member of 79 * an archive. Called when the member doesn't 80 * already exist. Looks in the archive for the 81 * modification time. Returns the modification 82 * time. 83 * 84 * Arch_FindLib Search for a library along a path. The 85 * library name in the GNode should be in 86 * -l<name> format. 87 * 88 * Arch_LibOODate Special function to decide if a library node 89 * is out-of-date. 90 * 91 * Arch_Init Initialize this module. 92 * 93 * Arch_End Cleanup this module. 94 */ 95 96#include <sys/types.h> 97#include <sys/stat.h> 98#include <sys/time.h> 99#include <sys/param.h> 100#include <ctype.h> 101#include <ar.h> 102#include <utime.h> 103#include <stdio.h> 104#include <stdlib.h> 105#include "make.h" 106#include "hash.h" 107#include "dir.h" 108#include "config.h" 109 110static Lst archives; /* Lst of archives we've already examined */ 111 112typedef struct Arch { 113 char *name; /* Name of archive */ 114 Hash_Table members; /* All the members of the archive described 115 * by <name, struct ar_hdr *> key/value pairs */ 116 char *fnametab; /* Extended name table strings */ 117 size_t fnamesize; /* Size of the string table */ 118} Arch; 119 120static int ArchFindArchive __P((ClientData, ClientData)); 121static void ArchFree __P((ClientData)); 122static struct ar_hdr *ArchStatMember __P((char *, char *, Boolean)); 123static FILE *ArchFindMember __P((char *, char *, struct ar_hdr *, char *)); 124#if defined(__svr4__) || defined(__SVR4) || defined(__ELF__) 125#define SVR4ARCHIVES 126static int ArchSVR4Entry __P((Arch *, char *, size_t, FILE *)); 127#endif 128 129/*- 130 *----------------------------------------------------------------------- 131 * ArchFree -- 132 * Free memory used by an archive 133 * 134 * Results: 135 * None. 136 * 137 * Side Effects: 138 * None. 139 * 140 *----------------------------------------------------------------------- 141 */ 142static void 143ArchFree(ap) 144 ClientData ap; 145{ 146 Arch *a = (Arch *) ap; 147 Hash_Search search; 148 Hash_Entry *entry; 149 150 /* Free memory from hash entries */ 151 for (entry = Hash_EnumFirst(&a->members, &search); 152 entry != NULL; 153 entry = Hash_EnumNext(&search)) 154 free((Address) Hash_GetValue (entry)); 155 156 free(a->name); 157 efree(a->fnametab); 158 Hash_DeleteTable(&a->members); 159 free((Address) a); 160} 161 162 163 164/*- 165 *----------------------------------------------------------------------- 166 * Arch_ParseArchive -- 167 * Parse the archive specification in the given line and find/create 168 * the nodes for the specified archive members, placing their nodes 169 * on the given list. 170 * 171 * Results: 172 * SUCCESS if it was a valid specification. The linePtr is updated 173 * to point to the first non-space after the archive spec. The 174 * nodes for the members are placed on the given list. 175 * 176 * Side Effects: 177 * Some nodes may be created. The given list is extended. 178 * 179 *----------------------------------------------------------------------- 180 */ 181ReturnStatus 182Arch_ParseArchive (linePtr, nodeLst, ctxt) 183 char **linePtr; /* Pointer to start of specification */ 184 Lst nodeLst; /* Lst on which to place the nodes */ 185 GNode *ctxt; /* Context in which to expand variables */ 186{ 187 register char *cp; /* Pointer into line */ 188 GNode *gn; /* New node */ 189 char *libName; /* Library-part of specification */ 190 char *memName; /* Member-part of specification */ 191 char nameBuf[MAKE_BSIZE]; /* temporary place for node name */ 192 char saveChar; /* Ending delimiter of member-name */ 193 Boolean subLibName; /* TRUE if libName should have/had 194 * variable substitution performed on it */ 195 196 libName = *linePtr; 197 198 subLibName = FALSE; 199 200 for (cp = libName; *cp != '(' && *cp != '\0'; cp++) { 201 if (*cp == '$') { 202 /* 203 * Variable spec, so call the Var module to parse the puppy 204 * so we can safely advance beyond it... 205 */ 206 int length; 207 Boolean freeIt; 208 char *result; 209 210 result=Var_Parse(cp, ctxt, TRUE, &length, &freeIt); 211 if (result == var_Error) { 212 return(FAILURE); 213 } else { 214 subLibName = TRUE; 215 } 216 217 if (freeIt) { 218 free(result); 219 } 220 cp += length-1; 221 } 222 } 223 224 *cp++ = '\0'; 225 if (subLibName) { 226 libName = Var_Subst(NULL, libName, ctxt, TRUE); 227 } 228 229 230 for (;;) { 231 /* 232 * First skip to the start of the member's name, mark that 233 * place and skip to the end of it (either white-space or 234 * a close paren). 235 */ 236 Boolean doSubst = FALSE; /* TRUE if need to substitute in memName */ 237 238 while (*cp != '\0' && *cp != ')' && isspace (*cp)) { 239 cp++; 240 } 241 memName = cp; 242 while (*cp != '\0' && *cp != ')' && !isspace (*cp)) { 243 if (*cp == '$') { 244 /* 245 * Variable spec, so call the Var module to parse the puppy 246 * so we can safely advance beyond it... 247 */ 248 int length; 249 Boolean freeIt; 250 char *result; 251 252 result=Var_Parse(cp, ctxt, TRUE, &length, &freeIt); 253 if (result == var_Error) { 254 return(FAILURE); 255 } else { 256 doSubst = TRUE; 257 } 258 259 if (freeIt) { 260 free(result); 261 } 262 cp += length; 263 } else { 264 cp++; 265 } 266 } 267 268 /* 269 * If the specification ends without a closing parenthesis, 270 * chances are there's something wrong (like a missing backslash), 271 * so it's better to return failure than allow such things to happen 272 */ 273 if (*cp == '\0') { 274 printf("No closing parenthesis in archive specification\n"); 275 return (FAILURE); 276 } 277 278 /* 279 * If we didn't move anywhere, we must be done 280 */ 281 if (cp == memName) { 282 break; 283 } 284 285 saveChar = *cp; 286 *cp = '\0'; 287 288 /* 289 * XXX: This should be taken care of intelligently by 290 * SuffExpandChildren, both for the archive and the member portions. 291 */ 292 /* 293 * If member contains variables, try and substitute for them. 294 * This will slow down archive specs with dynamic sources, of course, 295 * since we'll be (non-)substituting them three times, but them's 296 * the breaks -- we need to do this since SuffExpandChildren calls 297 * us, otherwise we could assume the thing would be taken care of 298 * later. 299 */ 300 if (doSubst) { 301 char *buf; 302 char *sacrifice; 303 char *oldMemName = memName; 304 305 memName = Var_Subst(NULL, memName, ctxt, TRUE); 306 307 /* 308 * Now form an archive spec and recurse to deal with nested 309 * variables and multi-word variable values.... The results 310 * are just placed at the end of the nodeLst we're returning. 311 */ 312 buf = sacrifice = emalloc(strlen(memName)+strlen(libName)+3); 313 314 sprintf(buf, "%s(%s)", libName, memName); 315 316 if (strchr(memName, '$') && strcmp(memName, oldMemName) == 0) { 317 /* 318 * Must contain dynamic sources, so we can't deal with it now. 319 * Just create an ARCHV node for the thing and let 320 * SuffExpandChildren handle it... 321 */ 322 gn = Targ_FindNode(buf, TARG_CREATE); 323 324 if (gn == NILGNODE) { 325 free(buf); 326 return(FAILURE); 327 } else { 328 gn->type |= OP_ARCHV; 329 (void)Lst_AtEnd(nodeLst, (ClientData)gn); 330 } 331 } else if (Arch_ParseArchive(&sacrifice, nodeLst, ctxt)!=SUCCESS) { 332 /* 333 * Error in nested call -- free buffer and return FAILURE 334 * ourselves. 335 */ 336 free(buf); 337 return(FAILURE); 338 } 339 /* 340 * Free buffer and continue with our work. 341 */ 342 free(buf); 343 } else if (Dir_HasWildcards(memName)) { 344 Lst members = Lst_Init(FALSE); 345 char *member; 346 347 Dir_Expand(memName, dirSearchPath, members); 348 while (!Lst_IsEmpty(members)) { 349 member = (char *)Lst_DeQueue(members); 350 351 sprintf(nameBuf, "%s(%s)", libName, member); 352 free(member); 353 gn = Targ_FindNode (nameBuf, TARG_CREATE); 354 if (gn == NILGNODE) { 355 return (FAILURE); 356 } else { 357 /* 358 * We've found the node, but have to make sure the rest of 359 * the world knows it's an archive member, without having 360 * to constantly check for parentheses, so we type the 361 * thing with the OP_ARCHV bit before we place it on the 362 * end of the provided list. 363 */ 364 gn->type |= OP_ARCHV; 365 (void) Lst_AtEnd (nodeLst, (ClientData)gn); 366 } 367 } 368 Lst_Destroy(members, NOFREE); 369 } else { 370 sprintf(nameBuf, "%s(%s)", libName, memName); 371 gn = Targ_FindNode (nameBuf, TARG_CREATE); 372 if (gn == NILGNODE) { 373 return (FAILURE); 374 } else { 375 /* 376 * We've found the node, but have to make sure the rest of the 377 * world knows it's an archive member, without having to 378 * constantly check for parentheses, so we type the thing with 379 * the OP_ARCHV bit before we place it on the end of the 380 * provided list. 381 */ 382 gn->type |= OP_ARCHV; 383 (void) Lst_AtEnd (nodeLst, (ClientData)gn); 384 } 385 } 386 if (doSubst) { 387 free(memName); 388 } 389 390 *cp = saveChar; 391 } 392 393 /* 394 * If substituted libName, free it now, since we need it no longer. 395 */ 396 if (subLibName) { 397 free(libName); 398 } 399 400 /* 401 * We promised the pointer would be set up at the next non-space, so 402 * we must advance cp there before setting *linePtr... (note that on 403 * entrance to the loop, cp is guaranteed to point at a ')') 404 */ 405 do { 406 cp++; 407 } while (*cp != '\0' && isspace (*cp)); 408 409 *linePtr = cp; 410 return (SUCCESS); 411} 412 413/*- 414 *----------------------------------------------------------------------- 415 * ArchFindArchive -- 416 * See if the given archive is the one we are looking for. Called 417 * From ArchStatMember and ArchFindMember via Lst_Find. 418 * 419 * Results: 420 * 0 if it is, non-zero if it isn't. 421 * 422 * Side Effects: 423 * None. 424 * 425 *----------------------------------------------------------------------- 426 */ 427static int 428ArchFindArchive (ar, archName) 429 ClientData ar; /* Current list element */ 430 ClientData archName; /* Name we want */ 431{ 432 return (strcmp ((char *) archName, ((Arch *) ar)->name)); 433} 434 435/*- 436 *----------------------------------------------------------------------- 437 * ArchStatMember -- 438 * Locate a member of an archive, given the path of the archive and 439 * the path of the desired member. 440 * 441 * Results: 442 * A pointer to the current struct ar_hdr structure for the member. Note 443 * That no position is returned, so this is not useful for touching 444 * archive members. This is mostly because we have no assurances that 445 * The archive will remain constant after we read all the headers, so 446 * there's not much point in remembering the position... 447 * 448 * Side Effects: 449 * 450 *----------------------------------------------------------------------- 451 */ 452static struct ar_hdr * 453ArchStatMember (archive, member, hash) 454 char *archive; /* Path to the archive */ 455 char *member; /* Name of member. If it is a path, only the 456 * last component is used. */ 457 Boolean hash; /* TRUE if archive should be hashed if not 458 * already so. */ 459{ 460#define AR_MAX_NAME_LEN (sizeof(arh.ar_name)-1) 461 FILE * arch; /* Stream to archive */ 462 int size; /* Size of archive member */ 463 char *cp; /* Useful character pointer */ 464 char magic[SARMAG]; 465 LstNode ln; /* Lst member containing archive descriptor */ 466 Arch *ar; /* Archive descriptor */ 467 Hash_Entry *he; /* Entry containing member's description */ 468 struct ar_hdr arh; /* archive-member header for reading archive */ 469 char memName[MAXPATHLEN+1]; 470 /* Current member name while hashing. */ 471 472 /* 473 * Because of space constraints and similar things, files are archived 474 * using their final path components, not the entire thing, so we need 475 * to point 'member' to the final component, if there is one, to make 476 * the comparisons easier... 477 */ 478 cp = strrchr (member, '/'); 479 if ((cp != NULL) && (strcmp(member, RANLIBMAG) != 0)) 480 member = cp + 1; 481 482 ln = Lst_Find (archives, (ClientData) archive, ArchFindArchive); 483 if (ln != NILLNODE) { 484 ar = (Arch *) Lst_Datum (ln); 485 486 he = Hash_FindEntry (&ar->members, member); 487 488 if (he != NULL) { 489 return ((struct ar_hdr *) Hash_GetValue (he)); 490 } else { 491 /* Try truncated name */ 492 char copy[AR_MAX_NAME_LEN+1]; 493 int len = strlen (member); 494 495 if (len > AR_MAX_NAME_LEN) { 496 len = AR_MAX_NAME_LEN; 497 strncpy(copy, member, AR_MAX_NAME_LEN); 498 copy[AR_MAX_NAME_LEN] = '\0'; 499 } 500 if ((he = Hash_FindEntry (&ar->members, copy)) != NULL) 501 return ((struct ar_hdr *) Hash_GetValue (he)); 502 return (NULL); 503 } 504 } 505 506 if (!hash) { 507 /* 508 * Caller doesn't want the thing hashed, just use ArchFindMember 509 * to read the header for the member out and close down the stream 510 * again. Since the archive is not to be hashed, we assume there's 511 * no need to allocate extra room for the header we're returning, 512 * so just declare it static. 513 */ 514 static struct ar_hdr sarh; 515 516 arch = ArchFindMember(archive, member, &sarh, "r"); 517 518 if (arch == NULL) { 519 return (NULL); 520 } else { 521 fclose(arch); 522 return (&sarh); 523 } 524 } 525 526 /* 527 * We don't have this archive on the list yet, so we want to find out 528 * everything that's in it and cache it so we can get at it quickly. 529 */ 530 arch = fopen (archive, "r"); 531 if (arch == NULL) { 532 return (NULL); 533 } 534 535 /* 536 * We use the ARMAG string to make sure this is an archive we 537 * can handle... 538 */ 539 if ((fread (magic, SARMAG, 1, arch) != 1) || 540 (strncmp (magic, ARMAG, SARMAG) != 0)) { 541 fclose (arch); 542 return (NULL); 543 } 544 545 ar = (Arch *)emalloc (sizeof (Arch)); 546 ar->name = estrdup (archive); 547 ar->fnametab = NULL; 548 ar->fnamesize = 0; 549 Hash_InitTable (&ar->members, -1); 550 memName[AR_MAX_NAME_LEN] = '\0'; 551 552 while (fread ((char *)&arh, sizeof (struct ar_hdr), 1, arch) == 1) { 553 if (strncmp ( arh.ar_fmag, ARFMAG, sizeof (arh.ar_fmag)) != 0) { 554 /* 555 * The header is bogus, so the archive is bad 556 * and there's no way we can recover... 557 */ 558 goto badarch; 559 } else { 560 /* 561 * We need to advance the stream's pointer to the start of the 562 * next header. Files are padded with newlines to an even-byte 563 * boundary, so we need to extract the size of the file from the 564 * 'size' field of the header and round it up during the seek. 565 */ 566 arh.ar_size[sizeof(arh.ar_size)-1] = '\0'; 567 size = (int) strtol(arh.ar_size, NULL, 10); 568 569 (void) strncpy (memName, arh.ar_name, sizeof(arh.ar_name)); 570 for (cp = &memName[AR_MAX_NAME_LEN]; *cp == ' '; cp--) { 571 continue; 572 } 573 cp[1] = '\0'; 574 575#ifdef SVR4ARCHIVES 576 /* 577 * svr4 names are slash terminated. Also svr4 extended AR format. 578 */ 579 if (memName[0] == '/') { 580 /* 581 * svr4 magic mode; handle it 582 */ 583 switch (ArchSVR4Entry(ar, memName, size, arch)) { 584 case -1: /* Invalid data */ 585 goto badarch; 586 case 0: /* List of files entry */ 587 continue; 588 default: /* Got the entry */ 589 break; 590 } 591 } 592 else { 593 if (cp[0] == '/') 594 cp[0] = '\0'; 595 } 596#endif 597 598#ifdef AR_EFMT1 599 /* 600 * BSD 4.4 extended AR format: #1/<namelen>, with name as the 601 * first <namelen> bytes of the file 602 */ 603 if (strncmp(memName, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0 && 604 isdigit(memName[sizeof(AR_EFMT1) - 1])) { 605 606 unsigned int elen = atoi(&memName[sizeof(AR_EFMT1)-1]); 607 608 if (elen > MAXPATHLEN) 609 goto badarch; 610 if (fread (memName, elen, 1, arch) != 1) 611 goto badarch; 612 memName[elen] = '\0'; 613 fseek (arch, -elen, SEEK_CUR); 614 if (DEBUG(ARCH) || DEBUG(MAKE)) { 615 printf("ArchStat: Extended format entry for %s\n", memName); 616 } 617 } 618#endif 619 620 he = Hash_CreateEntry (&ar->members, memName, NULL); 621 Hash_SetValue (he, (ClientData)emalloc (sizeof (struct ar_hdr))); 622 memcpy ((Address)Hash_GetValue (he), (Address)&arh, 623 sizeof (struct ar_hdr)); 624 } 625 fseek (arch, (size + 1) & ~1, SEEK_CUR); 626 } 627 628 fclose (arch); 629 630 (void) Lst_AtEnd (archives, (ClientData) ar); 631 632 /* 633 * Now that the archive has been read and cached, we can look into 634 * the hash table to find the desired member's header. 635 */ 636 he = Hash_FindEntry (&ar->members, member); 637 638 if (he != NULL) { 639 return ((struct ar_hdr *) Hash_GetValue (he)); 640 } else { 641 return (NULL); 642 } 643 644badarch: 645 fclose (arch); 646 Hash_DeleteTable (&ar->members); 647 efree(ar->fnametab); 648 free ((Address)ar); 649 return (NULL); 650} 651 652#ifdef SVR4ARCHIVES 653/*- 654 *----------------------------------------------------------------------- 655 * ArchSVR4Entry -- 656 * Parse an SVR4 style entry that begins with a slash. 657 * If it is "//", then load the table of filenames 658 * If it is "/<offset>", then try to substitute the long file name 659 * from offset of a table previously read. 660 * 661 * Results: 662 * -1: Bad data in archive 663 * 0: A table was loaded from the file 664 * 1: Name was successfully substituted from table 665 * 2: Name was not successfully substituted from table 666 * 667 * Side Effects: 668 * If a table is read, the file pointer is moved to the next archive 669 * member 670 * 671 *----------------------------------------------------------------------- 672 */ 673static int 674ArchSVR4Entry(ar, name, size, arch) 675 Arch *ar; 676 char *name; 677 size_t size; 678 FILE *arch; 679{ 680#define ARLONGNAMES1 "//" 681#define ARLONGNAMES2 "/ARFILENAMES" 682 size_t entry; 683 char *ptr, *eptr; 684 685 if (strncmp(name, ARLONGNAMES1, sizeof(ARLONGNAMES1) - 1) == 0 || 686 strncmp(name, ARLONGNAMES2, sizeof(ARLONGNAMES2) - 1) == 0) { 687 688 if (ar->fnametab != NULL) { 689 if (DEBUG(ARCH)) { 690 printf("Attempted to redefine an SVR4 name table\n"); 691 } 692 return -1; 693 } 694 695 /* 696 * This is a table of archive names, so we build one for 697 * ourselves 698 */ 699 ar->fnametab = emalloc(size); 700 ar->fnamesize = size; 701 702 if (fread(ar->fnametab, size, 1, arch) != 1) { 703 if (DEBUG(ARCH)) { 704 printf("Reading an SVR4 name table failed\n"); 705 } 706 return -1; 707 } 708 eptr = ar->fnametab + size; 709 for (entry = 0, ptr = ar->fnametab; ptr < eptr; ptr++) 710 switch (*ptr) { 711 case '/': 712 entry++; 713 *ptr = '\0'; 714 break; 715 716 case '\n': 717 break; 718 719 default: 720 break; 721 } 722 if (DEBUG(ARCH)) { 723 printf("Found svr4 archive name table with %d entries\n", entry); 724 } 725 return 0; 726 } 727 728 if (name[1] == ' ' || name[1] == '\0') 729 return 2; 730 731 entry = (size_t) strtol(&name[1], &eptr, 0); 732 if ((*eptr != ' ' && *eptr != '\0') || eptr == &name[1]) { 733 if (DEBUG(ARCH)) { 734 printf("Could not parse SVR4 name %s\n", name); 735 } 736 return 2; 737 } 738 if (entry >= ar->fnamesize) { 739 if (DEBUG(ARCH)) { 740 printf("SVR4 entry offset %s is greater than %d\n", 741 name, ar->fnamesize); 742 } 743 return 2; 744 } 745 746 if (DEBUG(ARCH)) { 747 printf("Replaced %s with %s\n", name, &ar->fnametab[entry]); 748 } 749 750 (void) strncpy(name, &ar->fnametab[entry], MAXPATHLEN); 751 name[MAXPATHLEN] = '\0'; 752 return 1; 753} 754#endif 755 756 757/*- 758 *----------------------------------------------------------------------- 759 * ArchFindMember -- 760 * Locate a member of an archive, given the path of the archive and 761 * the path of the desired member. If the archive is to be modified, 762 * the mode should be "r+", if not, it should be "r". 763 * 764 * Results: 765 * An FILE *, opened for reading and writing, positioned at the 766 * start of the member's struct ar_hdr, or NULL if the member was 767 * nonexistent. The current struct ar_hdr for member. 768 * 769 * Side Effects: 770 * The passed struct ar_hdr structure is filled in. 771 * 772 *----------------------------------------------------------------------- 773 */ 774static FILE * 775ArchFindMember (archive, member, arhPtr, mode) 776 char *archive; /* Path to the archive */ 777 char *member; /* Name of member. If it is a path, only the 778 * last component is used. */ 779 struct ar_hdr *arhPtr; /* Pointer to header structure to be filled in */ 780 char *mode; /* The mode for opening the stream */ 781{ 782 FILE * arch; /* Stream to archive */ 783 int size; /* Size of archive member */ 784 char *cp; /* Useful character pointer */ 785 char magic[SARMAG]; 786 int len, tlen; 787 788 arch = fopen (archive, mode); 789 if (arch == NULL) { 790 return (NULL); 791 } 792 793 /* 794 * We use the ARMAG string to make sure this is an archive we 795 * can handle... 796 */ 797 if ((fread (magic, SARMAG, 1, arch) != 1) || 798 (strncmp (magic, ARMAG, SARMAG) != 0)) { 799 fclose (arch); 800 return (NULL); 801 } 802 803 /* 804 * Because of space constraints and similar things, files are archived 805 * using their final path components, not the entire thing, so we need 806 * to point 'member' to the final component, if there is one, to make 807 * the comparisons easier... 808 */ 809 cp = strrchr (member, '/'); 810 if ((cp != NULL) && (strcmp(member, RANLIBMAG) != 0)) { 811 member = cp + 1; 812 } 813 len = tlen = strlen (member); 814 if (len > sizeof (arhPtr->ar_name)) { 815 tlen = sizeof (arhPtr->ar_name); 816 } 817 818 while (fread ((char *)arhPtr, sizeof (struct ar_hdr), 1, arch) == 1) { 819 if (strncmp(arhPtr->ar_fmag, ARFMAG, sizeof (arhPtr->ar_fmag) ) != 0) { 820 /* 821 * The header is bogus, so the archive is bad 822 * and there's no way we can recover... 823 */ 824 fclose (arch); 825 return (NULL); 826 } else if (strncmp (member, arhPtr->ar_name, tlen) == 0) { 827 /* 828 * If the member's name doesn't take up the entire 'name' field, 829 * we have to be careful of matching prefixes. Names are space- 830 * padded to the right, so if the character in 'name' at the end 831 * of the matched string is anything but a space, this isn't the 832 * member we sought. 833 */ 834 if (tlen != sizeof(arhPtr->ar_name) && arhPtr->ar_name[tlen] != ' '){ 835 goto skip; 836 } else { 837 /* 838 * To make life easier, we reposition the file at the start 839 * of the header we just read before we return the stream. 840 * In a more general situation, it might be better to leave 841 * the file at the actual member, rather than its header, but 842 * not here... 843 */ 844 fseek (arch, -sizeof(struct ar_hdr), SEEK_CUR); 845 return (arch); 846 } 847 } else 848#ifdef AR_EFMT1 849 /* 850 * BSD 4.4 extended AR format: #1/<namelen>, with name as the 851 * first <namelen> bytes of the file 852 */ 853 if (strncmp(arhPtr->ar_name, AR_EFMT1, 854 sizeof(AR_EFMT1) - 1) == 0 && 855 isdigit(arhPtr->ar_name[sizeof(AR_EFMT1) - 1])) { 856 857 unsigned int elen = atoi(&arhPtr->ar_name[sizeof(AR_EFMT1)-1]); 858 char ename[MAXPATHLEN]; 859 860 if (elen > MAXPATHLEN) { 861 fclose (arch); 862 return NULL; 863 } 864 if (fread (ename, elen, 1, arch) != 1) { 865 fclose (arch); 866 return NULL; 867 } 868 ename[elen] = '\0'; 869 if (DEBUG(ARCH) || DEBUG(MAKE)) { 870 printf("ArchFind: Extended format entry for %s\n", ename); 871 } 872 if (strncmp(ename, member, len) == 0) { 873 /* Found as extended name */ 874 fseek (arch, -sizeof(struct ar_hdr) - elen, SEEK_CUR); 875 return (arch); 876 } 877 fseek (arch, -elen, SEEK_CUR); 878 goto skip; 879 } else 880#endif 881 { 882skip: 883 /* 884 * This isn't the member we're after, so we need to advance the 885 * stream's pointer to the start of the next header. Files are 886 * padded with newlines to an even-byte boundary, so we need to 887 * extract the size of the file from the 'size' field of the 888 * header and round it up during the seek. 889 */ 890 arhPtr->ar_size[sizeof(arhPtr->ar_size)-1] = '\0'; 891 size = (int) strtol(arhPtr->ar_size, NULL, 10); 892 fseek (arch, (size + 1) & ~1, SEEK_CUR); 893 } 894 } 895 896 /* 897 * We've looked everywhere, but the member is not to be found. Close the 898 * archive and return NULL -- an error. 899 */ 900 fclose (arch); 901 return (NULL); 902} 903 904/*- 905 *----------------------------------------------------------------------- 906 * Arch_Touch -- 907 * Touch a member of an archive. 908 * 909 * Results: 910 * The 'time' field of the member's header is updated. 911 * 912 * Side Effects: 913 * The modification time of the entire archive is also changed. 914 * For a library, this could necessitate the re-ranlib'ing of the 915 * whole thing. 916 * 917 *----------------------------------------------------------------------- 918 */ 919void 920Arch_Touch (gn) 921 GNode *gn; /* Node of member to touch */ 922{ 923 FILE * arch; /* Stream open to archive, positioned properly */ 924 struct ar_hdr arh; /* Current header describing member */ 925 char *p1, *p2; 926 927 arch = ArchFindMember(Var_Value (ARCHIVE, gn, &p1), 928 Var_Value (TARGET, gn, &p2), 929 &arh, "r+"); 930 efree(p1); 931 efree(p2); 932 sprintf(arh.ar_date, "%-12ld", (long) now); 933 934 if (arch != NULL) { 935 (void)fwrite ((char *)&arh, sizeof (struct ar_hdr), 1, arch); 936 fclose (arch); 937 } 938} 939 940/*- 941 *----------------------------------------------------------------------- 942 * Arch_TouchLib -- 943 * Given a node which represents a library, touch the thing, making 944 * sure that the table of contents also is touched. 945 * 946 * Results: 947 * None. 948 * 949 * Side Effects: 950 * Both the modification time of the library and of the RANLIBMAG 951 * member are set to 'now'. 952 * 953 *----------------------------------------------------------------------- 954 */ 955void 956Arch_TouchLib (gn) 957 GNode *gn; /* The node of the library to touch */ 958{ 959#ifdef RANLIBMAG 960 FILE * arch; /* Stream open to archive */ 961 struct ar_hdr arh; /* Header describing table of contents */ 962 struct utimbuf times; /* Times for utime() call */ 963 964 arch = ArchFindMember (gn->path, RANLIBMAG, &arh, "r+"); 965 sprintf(arh.ar_date, "%-12ld", (long) now); 966 967 if (arch != NULL) { 968 (void)fwrite ((char *)&arh, sizeof (struct ar_hdr), 1, arch); 969 fclose (arch); 970 971 times.actime = times.modtime = now; 972 utime(gn->path, ×); 973 } 974#endif 975} 976 977/*- 978 *----------------------------------------------------------------------- 979 * Arch_MTime -- 980 * Return the modification time of a member of an archive. 981 * 982 * Results: 983 * The modification time (seconds). 984 * 985 * Side Effects: 986 * The mtime field of the given node is filled in with the value 987 * returned by the function. 988 * 989 *----------------------------------------------------------------------- 990 */ 991int 992Arch_MTime (gn) 993 GNode *gn; /* Node describing archive member */ 994{ 995 struct ar_hdr *arhPtr; /* Header of desired member */ 996 int modTime; /* Modification time as an integer */ 997 char *p1, *p2; 998 999 arhPtr = ArchStatMember (Var_Value (ARCHIVE, gn, &p1), 1000 Var_Value (TARGET, gn, &p2), 1001 TRUE); 1002 efree(p1); 1003 efree(p2); 1004 1005 if (arhPtr != NULL) { 1006 modTime = (int) strtol(arhPtr->ar_date, NULL, 10); 1007 } else { 1008 modTime = 0; 1009 } 1010 1011 gn->mtime = modTime; 1012 return (modTime); 1013} 1014 1015/*- 1016 *----------------------------------------------------------------------- 1017 * Arch_MemMTime -- 1018 * Given a non-existent archive member's node, get its modification 1019 * time from its archived form, if it exists. 1020 * 1021 * Results: 1022 * The modification time. 1023 * 1024 * Side Effects: 1025 * The mtime field is filled in. 1026 * 1027 *----------------------------------------------------------------------- 1028 */ 1029int 1030Arch_MemMTime (gn) 1031 GNode *gn; 1032{ 1033 LstNode ln; 1034 GNode *pgn; 1035 char *nameStart, 1036 *nameEnd; 1037 1038 if (Lst_Open (gn->parents) != SUCCESS) { 1039 gn->mtime = 0; 1040 return (0); 1041 } 1042 while ((ln = Lst_Next (gn->parents)) != NILLNODE) { 1043 pgn = (GNode *) Lst_Datum (ln); 1044 1045 if (pgn->type & OP_ARCHV) { 1046 /* 1047 * If the parent is an archive specification and is being made 1048 * and its member's name matches the name of the node we were 1049 * given, record the modification time of the parent in the 1050 * child. We keep searching its parents in case some other 1051 * parent requires this child to exist... 1052 */ 1053 nameStart = strchr (pgn->name, '(') + 1; 1054 nameEnd = strchr (nameStart, ')'); 1055 1056 if (pgn->make && 1057 strncmp(nameStart, gn->name, nameEnd - nameStart) == 0) { 1058 gn->mtime = Arch_MTime(pgn); 1059 } 1060 } else if (pgn->make) { 1061 /* 1062 * Something which isn't a library depends on the existence of 1063 * this target, so it needs to exist. 1064 */ 1065 gn->mtime = 0; 1066 break; 1067 } 1068 } 1069 1070 Lst_Close (gn->parents); 1071 1072 return (gn->mtime); 1073} 1074 1075/*- 1076 *----------------------------------------------------------------------- 1077 * Arch_FindLib -- 1078 * Search for a library along the given search path. 1079 * 1080 * Results: 1081 * None. 1082 * 1083 * Side Effects: 1084 * The node's 'path' field is set to the found path (including the 1085 * actual file name, not -l...). If the system can handle the -L 1086 * flag when linking (or we cannot find the library), we assume that 1087 * the user has placed the .LIBRARIES variable in the final linking 1088 * command (or the linker will know where to find it) and set the 1089 * TARGET variable for this node to be the node's name. Otherwise, 1090 * we set the TARGET variable to be the full path of the library, 1091 * as returned by Dir_FindFile. 1092 * 1093 *----------------------------------------------------------------------- 1094 */ 1095void 1096Arch_FindLib (gn, path) 1097 GNode *gn; /* Node of library to find */ 1098 Lst path; /* Search path */ 1099{ 1100 char *libName; /* file name for archive */ 1101 1102 libName = (char *)emalloc (strlen (gn->name) + 6 - 2); 1103 sprintf(libName, "lib%s.a", &gn->name[2]); 1104 1105 gn->path = Dir_FindFile (libName, path); 1106 1107 free (libName); 1108 1109#ifdef LIBRARIES 1110 Var_Set (TARGET, gn->name, gn); 1111#else 1112 Var_Set (TARGET, gn->path == NULL ? gn->name : gn->path, gn); 1113#endif /* LIBRARIES */ 1114} 1115 1116/*- 1117 *----------------------------------------------------------------------- 1118 * Arch_LibOODate -- 1119 * Decide if a node with the OP_LIB attribute is out-of-date. Called 1120 * from Make_OODate to make its life easier. 1121 * 1122 * There are several ways for a library to be out-of-date that are 1123 * not available to ordinary files. In addition, there are ways 1124 * that are open to regular files that are not available to 1125 * libraries. A library that is only used as a source is never 1126 * considered out-of-date by itself. This does not preclude the 1127 * library's modification time from making its parent be out-of-date. 1128 * A library will be considered out-of-date for any of these reasons, 1129 * given that it is a target on a dependency line somewhere: 1130 * Its modification time is less than that of one of its 1131 * sources (gn->mtime < gn->cmtime). 1132 * Its modification time is greater than the time at which the 1133 * make began (i.e. it's been modified in the course 1134 * of the make, probably by archiving). 1135 * The modification time of one of its sources is greater than 1136 * the one of its RANLIBMAG member (i.e. its table of contents 1137 * is out-of-date). We don't compare of the archive time 1138 * vs. TOC time because they can be too close. In my 1139 * opinion we should not bother with the TOC at all since 1140 * this is used by 'ar' rules that affect the data contents 1141 * of the archive, not by ranlib rules, which affect the 1142 * TOC. 1143 * 1144 * Results: 1145 * TRUE if the library is out-of-date. FALSE otherwise. 1146 * 1147 * Side Effects: 1148 * The library will be hashed if it hasn't been already. 1149 * 1150 *----------------------------------------------------------------------- 1151 */ 1152Boolean 1153Arch_LibOODate (gn) 1154 GNode *gn; /* The library's graph node */ 1155{ 1156 Boolean oodate; 1157 1158 if (OP_NOP(gn->type) && Lst_IsEmpty(gn->children)) { 1159 oodate = FALSE; 1160 } else if ((gn->mtime > now) || (gn->mtime < gn->cmtime)) { 1161 oodate = TRUE; 1162 } else { 1163#ifdef RANLIBMAG 1164 struct ar_hdr *arhPtr; /* Header for __.SYMDEF */ 1165 int modTimeTOC; /* The table-of-contents's mod time */ 1166 1167 arhPtr = ArchStatMember (gn->path, RANLIBMAG, FALSE); 1168 1169 if (arhPtr != NULL) { 1170 modTimeTOC = (int) strtol(arhPtr->ar_date, NULL, 10); 1171 1172 if (DEBUG(ARCH) || DEBUG(MAKE)) { 1173 printf("%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC)); 1174 } 1175 oodate = (gn->cmtime > modTimeTOC); 1176 } else { 1177 /* 1178 * A library w/o a table of contents is out-of-date 1179 */ 1180 if (DEBUG(ARCH) || DEBUG(MAKE)) { 1181 printf("No t.o.c...."); 1182 } 1183 oodate = TRUE; 1184 } 1185#else 1186 oodate = (gn->mtime == 0); /* out-of-date if not present */ 1187#endif 1188 } 1189 return (oodate); 1190} 1191 1192/*- 1193 *----------------------------------------------------------------------- 1194 * Arch_Init -- 1195 * Initialize things for this module. 1196 * 1197 * Results: 1198 * None. 1199 * 1200 * Side Effects: 1201 * The 'archives' list is initialized. 1202 * 1203 *----------------------------------------------------------------------- 1204 */ 1205void 1206Arch_Init () 1207{ 1208 archives = Lst_Init (FALSE); 1209} 1210 1211 1212 1213/*- 1214 *----------------------------------------------------------------------- 1215 * Arch_End -- 1216 * Cleanup things for this module. 1217 * 1218 * Results: 1219 * None. 1220 * 1221 * Side Effects: 1222 * The 'archives' list is freed 1223 * 1224 *----------------------------------------------------------------------- 1225 */ 1226void 1227Arch_End () 1228{ 1229 Lst_Destroy(archives, ArchFree); 1230} 1231