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