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