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