arch.c revision 138916
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1988, 1989, 1990, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * Copyright (c) 1989 by Berkeley Softworks 51590Srgrimes * All rights reserved. 61590Srgrimes * 71590Srgrimes * This code is derived from software contributed to Berkeley by 81590Srgrimes * Adam de Boor. 91590Srgrimes * 101590Srgrimes * Redistribution and use in source and binary forms, with or without 111590Srgrimes * modification, are permitted provided that the following conditions 121590Srgrimes * are met: 131590Srgrimes * 1. Redistributions of source code must retain the above copyright 141590Srgrimes * notice, this list of conditions and the following disclaimer. 151590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161590Srgrimes * notice, this list of conditions and the following disclaimer in the 171590Srgrimes * documentation and/or other materials provided with the distribution. 181590Srgrimes * 3. All advertising materials mentioning features or use of this software 191590Srgrimes * must display the following acknowledgement: 201590Srgrimes * This product includes software developed by the University of 211590Srgrimes * California, Berkeley and its contributors. 221590Srgrimes * 4. Neither the name of the University nor the names of its contributors 231590Srgrimes * may be used to endorse or promote products derived from this software 241590Srgrimes * without specific prior written permission. 251590Srgrimes * 261590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 271590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 281590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 291590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 301590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 311590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 321590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 331590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 341590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 351590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 361590Srgrimes * SUCH DAMAGE. 3762833Swsanchez * 3862833Swsanchez * @(#)arch.c 8.2 (Berkeley) 1/2/94 391590Srgrimes */ 401590Srgrimes 4162833Swsanchez#include <sys/cdefs.h> 4294587Sobrien__FBSDID("$FreeBSD: head/usr.bin/make/arch.c 138916 2004-12-16 16:14:16Z harti $"); 431590Srgrimes 441590Srgrimes/*- 451590Srgrimes * arch.c -- 461590Srgrimes * Functions to manipulate libraries, archives and their members. 471590Srgrimes * 481590Srgrimes * Once again, cacheing/hashing comes into play in the manipulation 491590Srgrimes * of archives. The first time an archive is referenced, all of its members' 501590Srgrimes * headers are read and hashed and the archive closed again. All hashed 511590Srgrimes * archives are kept on a list which is searched each time an archive member 521590Srgrimes * is referenced. 531590Srgrimes * 541590Srgrimes * The interface to this module is: 551590Srgrimes * Arch_ParseArchive Given an archive specification, return a list 561590Srgrimes * of GNode's, one for each member in the spec. 571590Srgrimes * FAILURE is returned if the specification is 581590Srgrimes * invalid for some reason. 591590Srgrimes * 601590Srgrimes * Arch_Touch Alter the modification time of the archive 611590Srgrimes * member described by the given node to be 621590Srgrimes * the current time. 631590Srgrimes * 641590Srgrimes * Arch_TouchLib Update the modification time of the library 651590Srgrimes * described by the given node. This is special 661590Srgrimes * because it also updates the modification time 671590Srgrimes * of the library's table of contents. 681590Srgrimes * 691590Srgrimes * Arch_MTime Find the modification time of a member of 701590Srgrimes * an archive *in the archive*. The time is also 711590Srgrimes * placed in the member's GNode. Returns the 721590Srgrimes * modification time. 731590Srgrimes * 741590Srgrimes * Arch_MemTime Find the modification time of a member of 751590Srgrimes * an archive. Called when the member doesn't 761590Srgrimes * already exist. Looks in the archive for the 771590Srgrimes * modification time. Returns the modification 781590Srgrimes * time. 791590Srgrimes * 801590Srgrimes * Arch_FindLib Search for a library along a path. The 811590Srgrimes * library name in the GNode should be in 821590Srgrimes * -l<name> format. 831590Srgrimes * 841590Srgrimes * Arch_LibOODate Special function to decide if a library node 851590Srgrimes * is out-of-date. 861590Srgrimes * 871590Srgrimes * Arch_Init Initialize this module. 885814Sjkh * 895814Sjkh * Arch_End Cleanup this module. 901590Srgrimes */ 911590Srgrimes 921590Srgrimes#include <sys/types.h> 931590Srgrimes#include <sys/stat.h> 941590Srgrimes#include <sys/time.h> 955814Sjkh#include <sys/param.h> 961590Srgrimes#include <ctype.h> 971590Srgrimes#include <ar.h> 9818730Ssteve#include <utime.h> 991590Srgrimes#include <stdio.h> 1005814Sjkh#include <stdlib.h> 1011590Srgrimes#include "make.h" 1021590Srgrimes#include "hash.h" 1031590Srgrimes#include "dir.h" 1041590Srgrimes#include "config.h" 1051590Srgrimes 106138916Sharti/* Lst of archives we've already examined */ 107138916Shartistatic Lst archives = Lst_Initializer(archives); 1081590Srgrimes 1091590Srgrimestypedef struct Arch { 1101590Srgrimes char *name; /* Name of archive */ 1111590Srgrimes Hash_Table members; /* All the members of the archive described 1121590Srgrimes * by <name, struct ar_hdr *> key/value pairs */ 11318730Ssteve char *fnametab; /* Extended name table strings */ 11418730Ssteve size_t fnamesize; /* Size of the string table */ 1151590Srgrimes} Arch; 1161590Srgrimes 11792921Simpstatic void ArchFree(void *); 11892921Simpstatic struct ar_hdr *ArchStatMember(char *, char *, Boolean); 11992921Simpstatic FILE *ArchFindMember(char *, char *, struct ar_hdr *, char *); 12051132Sjulian#if defined(__svr4__) || defined(__SVR4) || defined(__ELF__) 121103503Sjmallett#define SVR4ARCHIVES 12292921Simpstatic int ArchSVR4Entry(Arch *, char *, size_t, FILE *); 12318730Ssteve#endif 1241590Srgrimes 1251590Srgrimes/*- 1261590Srgrimes *----------------------------------------------------------------------- 1275814Sjkh * ArchFree -- 1285814Sjkh * Free memory used by an archive 1295814Sjkh * 1305814Sjkh * Results: 1315814Sjkh * None. 1325814Sjkh * 1335814Sjkh * Side Effects: 1345814Sjkh * None. 1355814Sjkh * 1365814Sjkh *----------------------------------------------------------------------- 1375814Sjkh */ 1385814Sjkhstatic void 139104696SjmallettArchFree(void *ap) 1405814Sjkh{ 141138264Sharti Arch *a = ap; 1425814Sjkh Hash_Search search; 1435814Sjkh Hash_Entry *entry; 1448874Srgrimes 1458874Srgrimes /* Free memory from hash entries */ 1465814Sjkh for (entry = Hash_EnumFirst(&a->members, &search); 14749938Shoek entry != NULL; 1485814Sjkh entry = Hash_EnumNext(&search)) 14969531Swill free(Hash_GetValue(entry)); 1505814Sjkh 1515814Sjkh free(a->name); 152105826Sjmallett free(a->fnametab); 1535814Sjkh Hash_DeleteTable(&a->members); 15469531Swill free(a); 1555814Sjkh} 1565814Sjkh 1575814Sjkh/*- 1585814Sjkh *----------------------------------------------------------------------- 1591590Srgrimes * Arch_ParseArchive -- 1601590Srgrimes * Parse the archive specification in the given line and find/create 1611590Srgrimes * the nodes for the specified archive members, placing their nodes 162104696Sjmallett * on the given list, given the pointer to the start of the 163104696Sjmallett * specification, a Lst on which to place the nodes, and a context 164104696Sjmallett * in which to expand variables. 1651590Srgrimes * 1661590Srgrimes * Results: 1671590Srgrimes * SUCCESS if it was a valid specification. The linePtr is updated 1681590Srgrimes * to point to the first non-space after the archive spec. The 1691590Srgrimes * nodes for the members are placed on the given list. 1701590Srgrimes * 1711590Srgrimes * Side Effects: 1721590Srgrimes * Some nodes may be created. The given list is extended. 1731590Srgrimes * 1741590Srgrimes *----------------------------------------------------------------------- 1751590Srgrimes */ 1761590SrgrimesReturnStatus 177138512ShartiArch_ParseArchive(char **linePtr, Lst *nodeLst, GNode *ctxt) 1781590Srgrimes{ 17994584Sobrien char *cp; /* Pointer into line */ 1801590Srgrimes GNode *gn; /* New node */ 1811590Srgrimes char *libName; /* Library-part of specification */ 1821590Srgrimes char *memName; /* Member-part of specification */ 18369390Swill char *nameBuf; /* temporary place for node name */ 1841590Srgrimes char saveChar; /* Ending delimiter of member-name */ 1851590Srgrimes Boolean subLibName; /* TRUE if libName should have/had 1861590Srgrimes * variable substitution performed on it */ 1871590Srgrimes 1881590Srgrimes libName = *linePtr; 1898874Srgrimes 1901590Srgrimes subLibName = FALSE; 1911590Srgrimes 1921590Srgrimes for (cp = libName; *cp != '(' && *cp != '\0'; cp++) { 1931590Srgrimes if (*cp == '$') { 1941590Srgrimes /* 1951590Srgrimes * Variable spec, so call the Var module to parse the puppy 1961590Srgrimes * so we can safely advance beyond it... 1971590Srgrimes */ 198138346Sharti size_t length; 1991590Srgrimes Boolean freeIt; 2001590Srgrimes char *result; 2018874Srgrimes 202138232Sharti result = Var_Parse(cp, ctxt, TRUE, &length, &freeIt); 2031590Srgrimes if (result == var_Error) { 204138232Sharti return (FAILURE); 2051590Srgrimes } else { 2061590Srgrimes subLibName = TRUE; 2071590Srgrimes } 2088874Srgrimes 2091590Srgrimes if (freeIt) { 2101590Srgrimes free(result); 2111590Srgrimes } 212138232Sharti cp += length - 1; 2131590Srgrimes } 2141590Srgrimes } 2151590Srgrimes 2161590Srgrimes *cp++ = '\0'; 2171590Srgrimes if (subLibName) { 2181590Srgrimes libName = Var_Subst(NULL, libName, ctxt, TRUE); 2191590Srgrimes } 2201590Srgrimes 2218874Srgrimes 2221590Srgrimes for (;;) { 2231590Srgrimes /* 2241590Srgrimes * First skip to the start of the member's name, mark that 2251590Srgrimes * place and skip to the end of it (either white-space or 2261590Srgrimes * a close paren). 2271590Srgrimes */ 2281590Srgrimes Boolean doSubst = FALSE; /* TRUE if need to substitute in memName */ 2291590Srgrimes 230138232Sharti while (*cp != '\0' && *cp != ')' && isspace((unsigned char)*cp)) { 2311590Srgrimes cp++; 2321590Srgrimes } 2331590Srgrimes memName = cp; 234138232Sharti while (*cp != '\0' && *cp != ')' && !isspace((unsigned char)*cp)) { 2351590Srgrimes if (*cp == '$') { 2361590Srgrimes /* 2371590Srgrimes * Variable spec, so call the Var module to parse the puppy 2381590Srgrimes * so we can safely advance beyond it... 2391590Srgrimes */ 240138346Sharti size_t length; 2411590Srgrimes Boolean freeIt; 2421590Srgrimes char *result; 2431590Srgrimes 244138346Sharti result = Var_Parse(cp, ctxt, TRUE, &length, &freeIt); 2451590Srgrimes if (result == var_Error) { 246138232Sharti return (FAILURE); 2471590Srgrimes } else { 2481590Srgrimes doSubst = TRUE; 2491590Srgrimes } 2501590Srgrimes 2511590Srgrimes if (freeIt) { 2521590Srgrimes free(result); 2531590Srgrimes } 2541590Srgrimes cp += length; 2551590Srgrimes } else { 2561590Srgrimes cp++; 2571590Srgrimes } 2581590Srgrimes } 2591590Srgrimes 2601590Srgrimes /* 2611590Srgrimes * If the specification ends without a closing parenthesis, 2621590Srgrimes * chances are there's something wrong (like a missing backslash), 2631590Srgrimes * so it's better to return failure than allow such things to happen 2641590Srgrimes */ 2651590Srgrimes if (*cp == '\0') { 2661590Srgrimes printf("No closing parenthesis in archive specification\n"); 2671590Srgrimes return (FAILURE); 2681590Srgrimes } 2691590Srgrimes 2701590Srgrimes /* 2711590Srgrimes * If we didn't move anywhere, we must be done 2721590Srgrimes */ 2731590Srgrimes if (cp == memName) { 2741590Srgrimes break; 2751590Srgrimes } 2761590Srgrimes 2771590Srgrimes saveChar = *cp; 2781590Srgrimes *cp = '\0'; 2791590Srgrimes 2801590Srgrimes /* 2811590Srgrimes * XXX: This should be taken care of intelligently by 2821590Srgrimes * SuffExpandChildren, both for the archive and the member portions. 2831590Srgrimes */ 2841590Srgrimes /* 2851590Srgrimes * If member contains variables, try and substitute for them. 2861590Srgrimes * This will slow down archive specs with dynamic sources, of course, 2871590Srgrimes * since we'll be (non-)substituting them three times, but them's 2881590Srgrimes * the breaks -- we need to do this since SuffExpandChildren calls 2891590Srgrimes * us, otherwise we could assume the thing would be taken care of 2901590Srgrimes * later. 2911590Srgrimes */ 2921590Srgrimes if (doSubst) { 2931590Srgrimes char *buf; 2941590Srgrimes char *sacrifice; 2951590Srgrimes char *oldMemName = memName; 29669390Swill size_t sz; 2978874Srgrimes 2981590Srgrimes memName = Var_Subst(NULL, memName, ctxt, TRUE); 2991590Srgrimes 3001590Srgrimes /* 3011590Srgrimes * Now form an archive spec and recurse to deal with nested 3021590Srgrimes * variables and multi-word variable values.... The results 3031590Srgrimes * are just placed at the end of the nodeLst we're returning. 3041590Srgrimes */ 3051590Srgrimes 30669390Swill sz = strlen(memName) + strlen(libName) + 3; 30769390Swill buf = sacrifice = emalloc(sz); 3081590Srgrimes 30969390Swill snprintf(buf, sz, "%s(%s)", libName, memName); 31069390Swill 3111590Srgrimes if (strchr(memName, '$') && strcmp(memName, oldMemName) == 0) { 3121590Srgrimes /* 3131590Srgrimes * Must contain dynamic sources, so we can't deal with it now. 3141590Srgrimes * Just create an ARCHV node for the thing and let 3151590Srgrimes * SuffExpandChildren handle it... 3161590Srgrimes */ 3171590Srgrimes gn = Targ_FindNode(buf, TARG_CREATE); 3181590Srgrimes 31969527Swill if (gn == NULL) { 3201590Srgrimes free(buf); 321138232Sharti return (FAILURE); 3221590Srgrimes } else { 3231590Srgrimes gn->type |= OP_ARCHV; 324138232Sharti Lst_AtEnd(nodeLst, (void *)gn); 3251590Srgrimes } 326138232Sharti } else if (Arch_ParseArchive(&sacrifice, nodeLst, ctxt) != SUCCESS) { 3271590Srgrimes /* 3281590Srgrimes * Error in nested call -- free buffer and return FAILURE 3291590Srgrimes * ourselves. 3301590Srgrimes */ 3311590Srgrimes free(buf); 332138232Sharti return (FAILURE); 3331590Srgrimes } 3341590Srgrimes /* 3351590Srgrimes * Free buffer and continue with our work. 3361590Srgrimes */ 3371590Srgrimes free(buf); 3381590Srgrimes } else if (Dir_HasWildcards(memName)) { 339138916Sharti Lst members = Lst_Initializer(members); 3401590Srgrimes char *member; 34169390Swill size_t sz = MAXPATHLEN; 34269390Swill size_t nsz; 343138196Sharti 34469390Swill nameBuf = emalloc(sz); 3451590Srgrimes 346138916Sharti Dir_Expand(memName, &dirSearchPath, &members); 347138916Sharti while (!Lst_IsEmpty(&members)) { 348138916Sharti member = Lst_DeQueue(&members); 34969390Swill nsz = strlen(libName) + strlen(member) + 3; 350138196Sharti if (nsz > sz) { 351138196Sharti sz = nsz * 2; 352138196Sharti nameBuf = erealloc(nameBuf, sz); 353138196Sharti } 3548874Srgrimes 35569390Swill snprintf(nameBuf, sz, "%s(%s)", libName, member); 3561590Srgrimes free(member); 357138232Sharti gn = Targ_FindNode(nameBuf, TARG_CREATE); 35869527Swill if (gn == NULL) { 35969390Swill free(nameBuf); 360138916Sharti /* XXXHB Lst_Destroy(&members) */ 3611590Srgrimes return (FAILURE); 3621590Srgrimes } else { 3631590Srgrimes /* 3641590Srgrimes * We've found the node, but have to make sure the rest of 3651590Srgrimes * the world knows it's an archive member, without having 3661590Srgrimes * to constantly check for parentheses, so we type the 3671590Srgrimes * thing with the OP_ARCHV bit before we place it on the 3681590Srgrimes * end of the provided list. 3691590Srgrimes */ 3701590Srgrimes gn->type |= OP_ARCHV; 371138232Sharti Lst_AtEnd(nodeLst, (void *)gn); 3721590Srgrimes } 3731590Srgrimes } 37469390Swill free(nameBuf); 3751590Srgrimes } else { 37669390Swill size_t sz = strlen(libName) + strlen(memName) + 3; 37769390Swill nameBuf = emalloc(sz); 37869390Swill snprintf(nameBuf, sz, "%s(%s)", libName, memName); 379138232Sharti gn = Targ_FindNode(nameBuf, TARG_CREATE); 38069390Swill free(nameBuf); 38169527Swill if (gn == NULL) { 3821590Srgrimes return (FAILURE); 3831590Srgrimes } else { 3841590Srgrimes /* 3851590Srgrimes * We've found the node, but have to make sure the rest of the 3861590Srgrimes * world knows it's an archive member, without having to 3871590Srgrimes * constantly check for parentheses, so we type the thing with 3881590Srgrimes * the OP_ARCHV bit before we place it on the end of the 3891590Srgrimes * provided list. 3901590Srgrimes */ 3911590Srgrimes gn->type |= OP_ARCHV; 392138264Sharti Lst_AtEnd(nodeLst, gn); 3931590Srgrimes } 3941590Srgrimes } 3951590Srgrimes if (doSubst) { 3961590Srgrimes free(memName); 3971590Srgrimes } 3988874Srgrimes 3991590Srgrimes *cp = saveChar; 4001590Srgrimes } 4011590Srgrimes 4021590Srgrimes /* 4031590Srgrimes * If substituted libName, free it now, since we need it no longer. 4041590Srgrimes */ 4051590Srgrimes if (subLibName) { 4061590Srgrimes free(libName); 4071590Srgrimes } 4081590Srgrimes 4091590Srgrimes /* 4101590Srgrimes * We promised the pointer would be set up at the next non-space, so 4111590Srgrimes * we must advance cp there before setting *linePtr... (note that on 4121590Srgrimes * entrance to the loop, cp is guaranteed to point at a ')') 4131590Srgrimes */ 4141590Srgrimes do { 4151590Srgrimes cp++; 416138232Sharti } while (*cp != '\0' && isspace((unsigned char)*cp)); 4171590Srgrimes 4181590Srgrimes *linePtr = cp; 4191590Srgrimes return (SUCCESS); 4201590Srgrimes} 4211590Srgrimes 4221590Srgrimes/*- 4231590Srgrimes *----------------------------------------------------------------------- 4241590Srgrimes * ArchFindArchive -- 4251590Srgrimes * See if the given archive is the one we are looking for. Called 426104696Sjmallett * From ArchStatMember and ArchFindMember via Lst_Find with the 427104696Sjmallett * current list element and the name we want. 4281590Srgrimes * 4291590Srgrimes * Results: 4301590Srgrimes * 0 if it is, non-zero if it isn't. 4311590Srgrimes * 4321590Srgrimes * Side Effects: 4331590Srgrimes * None. 4341590Srgrimes * 4351590Srgrimes *----------------------------------------------------------------------- 4361590Srgrimes */ 4371590Srgrimesstatic int 438138561ShartiArchFindArchive(const void *ar, const void *archName) 4391590Srgrimes{ 440138561Sharti 441138561Sharti return (strcmp(archName, ((const Arch *)ar)->name)); 4421590Srgrimes} 4431590Srgrimes 4441590Srgrimes/*- 4451590Srgrimes *----------------------------------------------------------------------- 4461590Srgrimes * ArchStatMember -- 4471590Srgrimes * Locate a member of an archive, given the path of the archive and 448104696Sjmallett * the path of the desired member, and a boolean representing whether 449104696Sjmallett * or not the archive should be hashed (if not already hashed). 4501590Srgrimes * 4511590Srgrimes * Results: 4521590Srgrimes * A pointer to the current struct ar_hdr structure for the member. Note 4531590Srgrimes * That no position is returned, so this is not useful for touching 4541590Srgrimes * archive members. This is mostly because we have no assurances that 4551590Srgrimes * The archive will remain constant after we read all the headers, so 4561590Srgrimes * there's not much point in remembering the position... 4571590Srgrimes * 4581590Srgrimes * Side Effects: 4591590Srgrimes * 4601590Srgrimes *----------------------------------------------------------------------- 4611590Srgrimes */ 4621590Srgrimesstatic struct ar_hdr * 463138232ShartiArchStatMember(char *archive, char *member, Boolean hash) 4641590Srgrimes{ 465138232Sharti#define AR_MAX_NAME_LEN (sizeof(arh.ar_name) - 1) 4661590Srgrimes FILE * arch; /* Stream to archive */ 4671590Srgrimes int size; /* Size of archive member */ 4681590Srgrimes char *cp; /* Useful character pointer */ 4691590Srgrimes char magic[SARMAG]; 470138512Sharti LstNode *ln; /* Lst member containing archive descriptor */ 4711590Srgrimes Arch *ar; /* Archive descriptor */ 4721590Srgrimes Hash_Entry *he; /* Entry containing member's description */ 4731590Srgrimes struct ar_hdr arh; /* archive-member header for reading archive */ 474138232Sharti char memName[MAXPATHLEN + 1]; 4755814Sjkh /* Current member name while hashing. */ 4761590Srgrimes 4771590Srgrimes /* 4781590Srgrimes * Because of space constraints and similar things, files are archived 4791590Srgrimes * using their final path components, not the entire thing, so we need 4801590Srgrimes * to point 'member' to the final component, if there is one, to make 4811590Srgrimes * the comparisons easier... 4821590Srgrimes */ 483138232Sharti cp = strrchr(member, '/'); 48451132Sjulian if ((cp != NULL) && (strcmp(member, RANLIBMAG) != 0)) 4851590Srgrimes member = cp + 1; 4861590Srgrimes 487138916Sharti ln = Lst_Find(&archives, archive, ArchFindArchive); 48869527Swill if (ln != NULL) { 489138264Sharti ar = Lst_Datum(ln); 4901590Srgrimes 491138232Sharti he = Hash_FindEntry(&ar->members, member); 4921590Srgrimes 49349938Shoek if (he != NULL) { 494138232Sharti return ((struct ar_hdr *)Hash_GetValue (he)); 4951590Srgrimes } else { 4965814Sjkh /* Try truncated name */ 497138232Sharti char copy[AR_MAX_NAME_LEN + 1]; 498138232Sharti size_t len = strlen(member); 4995814Sjkh 5005814Sjkh if (len > AR_MAX_NAME_LEN) { 5015814Sjkh len = AR_MAX_NAME_LEN; 5025814Sjkh strncpy(copy, member, AR_MAX_NAME_LEN); 5035814Sjkh copy[AR_MAX_NAME_LEN] = '\0'; 5045814Sjkh } 505138232Sharti if ((he = Hash_FindEntry(&ar->members, copy)) != NULL) 506138264Sharti return (Hash_GetValue(he)); 50749938Shoek return (NULL); 5081590Srgrimes } 5091590Srgrimes } 5101590Srgrimes 5111590Srgrimes if (!hash) { 5121590Srgrimes /* 5131590Srgrimes * Caller doesn't want the thing hashed, just use ArchFindMember 5141590Srgrimes * to read the header for the member out and close down the stream 5151590Srgrimes * again. Since the archive is not to be hashed, we assume there's 5161590Srgrimes * no need to allocate extra room for the header we're returning, 5171590Srgrimes * so just declare it static. 5181590Srgrimes */ 5191590Srgrimes static struct ar_hdr sarh; 5201590Srgrimes 5211590Srgrimes arch = ArchFindMember(archive, member, &sarh, "r"); 5221590Srgrimes 52349938Shoek if (arch == NULL) { 52449938Shoek return (NULL); 5251590Srgrimes } else { 5261590Srgrimes fclose(arch); 5271590Srgrimes return (&sarh); 5281590Srgrimes } 5291590Srgrimes } 5301590Srgrimes 5311590Srgrimes /* 5321590Srgrimes * We don't have this archive on the list yet, so we want to find out 5331590Srgrimes * everything that's in it and cache it so we can get at it quickly. 5341590Srgrimes */ 535138232Sharti arch = fopen(archive, "r"); 53649938Shoek if (arch == NULL) { 53749938Shoek return (NULL); 5381590Srgrimes } 5398874Srgrimes 5401590Srgrimes /* 5411590Srgrimes * We use the ARMAG string to make sure this is an archive we 5421590Srgrimes * can handle... 5431590Srgrimes */ 544138232Sharti if ((fread(magic, SARMAG, 1, arch) != 1) || 545138232Sharti (strncmp(magic, ARMAG, SARMAG) != 0)) { 546138232Sharti fclose(arch); 54749938Shoek return (NULL); 5481590Srgrimes } 5491590Srgrimes 550138264Sharti ar = emalloc(sizeof(Arch)); 551138232Sharti ar->name = estrdup(archive); 55218730Ssteve ar->fnametab = NULL; 55318730Ssteve ar->fnamesize = 0; 554138232Sharti Hash_InitTable(&ar->members, -1); 5551590Srgrimes memName[AR_MAX_NAME_LEN] = '\0'; 5568874Srgrimes 557138264Sharti while (fread(&arh, sizeof(struct ar_hdr), 1, arch) == 1) { 558138232Sharti if (strncmp(arh.ar_fmag, ARFMAG, sizeof(arh.ar_fmag)) != 0) { 55918730Ssteve /* 56018730Ssteve * The header is bogus, so the archive is bad 56118730Ssteve * and there's no way we can recover... 56218730Ssteve */ 56318730Ssteve goto badarch; 5641590Srgrimes } else { 56518730Ssteve /* 56618730Ssteve * We need to advance the stream's pointer to the start of the 56718730Ssteve * next header. Files are padded with newlines to an even-byte 56818730Ssteve * boundary, so we need to extract the size of the file from the 56918730Ssteve * 'size' field of the header and round it up during the seek. 57018730Ssteve */ 571138232Sharti arh.ar_size[sizeof(arh.ar_size) - 1] = '\0'; 572138232Sharti size = (int)strtol(arh.ar_size, NULL, 10); 57318730Ssteve 574138232Sharti strncpy(memName, arh.ar_name, sizeof(arh.ar_name)); 5751590Srgrimes for (cp = &memName[AR_MAX_NAME_LEN]; *cp == ' '; cp--) { 5761590Srgrimes continue; 5771590Srgrimes } 5781590Srgrimes cp[1] = '\0'; 5791590Srgrimes 58018730Ssteve#ifdef SVR4ARCHIVES 58118730Ssteve /* 58218730Ssteve * svr4 names are slash terminated. Also svr4 extended AR format. 58318730Ssteve */ 58418730Ssteve if (memName[0] == '/') { 58518730Ssteve /* 58618730Ssteve * svr4 magic mode; handle it 58718730Ssteve */ 58818730Ssteve switch (ArchSVR4Entry(ar, memName, size, arch)) { 58918730Ssteve case -1: /* Invalid data */ 59018730Ssteve goto badarch; 59118730Ssteve case 0: /* List of files entry */ 59218730Ssteve continue; 59318730Ssteve default: /* Got the entry */ 59418730Ssteve break; 59518730Ssteve } 59618730Ssteve } 59718730Ssteve else { 59818730Ssteve if (cp[0] == '/') 59918730Ssteve cp[0] = '\0'; 60018730Ssteve } 60118730Ssteve#endif 60218730Ssteve 6035814Sjkh#ifdef AR_EFMT1 6045814Sjkh /* 6055814Sjkh * BSD 4.4 extended AR format: #1/<namelen>, with name as the 6065814Sjkh * first <namelen> bytes of the file 6075814Sjkh */ 6085814Sjkh if (strncmp(memName, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0 && 6095814Sjkh isdigit(memName[sizeof(AR_EFMT1) - 1])) { 6105814Sjkh 6115814Sjkh unsigned int elen = atoi(&memName[sizeof(AR_EFMT1)-1]); 6125814Sjkh 61318730Ssteve if (elen > MAXPATHLEN) 61418730Ssteve goto badarch; 615138232Sharti if (fread(memName, elen, 1, arch) != 1) 61618730Ssteve goto badarch; 6175814Sjkh memName[elen] = '\0'; 618138232Sharti fseek(arch, -elen, SEEK_CUR); 619103508Sjmallett /* XXX Multiple levels may be asked for, make this conditional 620103508Sjmallett * on one, and use DEBUGF. 621103508Sjmallett */ 6225814Sjkh if (DEBUG(ARCH) || DEBUG(MAKE)) { 623103508Sjmallett fprintf(stderr, "ArchStat: Extended format entry for %s\n", memName); 6245814Sjkh } 6255814Sjkh } 6265814Sjkh#endif 6275814Sjkh 628138232Sharti he = Hash_CreateEntry(&ar->members, memName, NULL); 629138264Sharti Hash_SetValue(he, emalloc(sizeof(struct ar_hdr))); 630138264Sharti memcpy(Hash_GetValue(he), &arh, sizeof(struct ar_hdr)); 6311590Srgrimes } 632138232Sharti fseek(arch, (size + 1) & ~1, SEEK_CUR); 6331590Srgrimes } 6341590Srgrimes 635138232Sharti fclose(arch); 6361590Srgrimes 637138916Sharti Lst_AtEnd(&archives, ar); 6381590Srgrimes 6391590Srgrimes /* 6401590Srgrimes * Now that the archive has been read and cached, we can look into 6411590Srgrimes * the hash table to find the desired member's header. 6421590Srgrimes */ 643138232Sharti he = Hash_FindEntry(&ar->members, member); 6441590Srgrimes 64549938Shoek if (he != NULL) { 646138264Sharti return (Hash_GetValue (he)); 6471590Srgrimes } else { 64849938Shoek return (NULL); 6491590Srgrimes } 65018730Ssteve 65118730Sstevebadarch: 652138232Sharti fclose(arch); 653138232Sharti Hash_DeleteTable(&ar->members); 654105826Sjmallett free(ar->fnametab); 655138232Sharti free(ar); 65649938Shoek return (NULL); 6571590Srgrimes} 6581590Srgrimes 65918730Ssteve#ifdef SVR4ARCHIVES 6601590Srgrimes/*- 6611590Srgrimes *----------------------------------------------------------------------- 66218730Ssteve * ArchSVR4Entry -- 66318730Ssteve * Parse an SVR4 style entry that begins with a slash. 66418730Ssteve * If it is "//", then load the table of filenames 66518730Ssteve * If it is "/<offset>", then try to substitute the long file name 66618730Ssteve * from offset of a table previously read. 66718730Ssteve * 66818730Ssteve * Results: 66918730Ssteve * -1: Bad data in archive 67018730Ssteve * 0: A table was loaded from the file 67118730Ssteve * 1: Name was successfully substituted from table 67218730Ssteve * 2: Name was not successfully substituted from table 67318730Ssteve * 67418730Ssteve * Side Effects: 67518730Ssteve * If a table is read, the file pointer is moved to the next archive 67618730Ssteve * member 67718730Ssteve * 67818730Ssteve *----------------------------------------------------------------------- 67918730Ssteve */ 68018730Sstevestatic int 681104696SjmallettArchSVR4Entry(Arch *ar, char *name, size_t size, FILE *arch) 68218730Ssteve{ 683103503Sjmallett#define ARLONGNAMES1 "//" 684103503Sjmallett#define ARLONGNAMES2 "/ARFILENAMES" 68518730Ssteve size_t entry; 68618730Ssteve char *ptr, *eptr; 68718730Ssteve 68818730Ssteve if (strncmp(name, ARLONGNAMES1, sizeof(ARLONGNAMES1) - 1) == 0 || 68918730Ssteve strncmp(name, ARLONGNAMES2, sizeof(ARLONGNAMES2) - 1) == 0) { 69018730Ssteve 69118730Ssteve if (ar->fnametab != NULL) { 692103545Sjmallett DEBUGF(ARCH, ("Attempted to redefine an SVR4 name table\n")); 693138232Sharti return (-1); 69418730Ssteve } 69518730Ssteve 69618730Ssteve /* 69718730Ssteve * This is a table of archive names, so we build one for 69818730Ssteve * ourselves 69918730Ssteve */ 70018730Ssteve ar->fnametab = emalloc(size); 70118730Ssteve ar->fnamesize = size; 70218730Ssteve 70318730Ssteve if (fread(ar->fnametab, size, 1, arch) != 1) { 704103545Sjmallett DEBUGF(ARCH, ("Reading an SVR4 name table failed\n")); 705138232Sharti return (-1); 70618730Ssteve } 70718730Ssteve eptr = ar->fnametab + size; 70818730Ssteve for (entry = 0, ptr = ar->fnametab; ptr < eptr; ptr++) 70918730Ssteve switch (*ptr) { 71018730Ssteve case '/': 71118730Ssteve entry++; 71218730Ssteve *ptr = '\0'; 71318730Ssteve break; 71418730Ssteve 71518730Ssteve case '\n': 71618730Ssteve break; 71718730Ssteve 71818730Ssteve default: 71918730Ssteve break; 72018730Ssteve } 721103545Sjmallett DEBUGF(ARCH, ("Found svr4 archive name table with %zu entries\n", entry)); 722138232Sharti return (0); 72318730Ssteve } 72418730Ssteve 72518730Ssteve if (name[1] == ' ' || name[1] == '\0') 726138232Sharti return (2); 72718730Ssteve 728138232Sharti entry = (size_t)strtol(&name[1], &eptr, 0); 72918730Ssteve if ((*eptr != ' ' && *eptr != '\0') || eptr == &name[1]) { 730103545Sjmallett DEBUGF(ARCH, ("Could not parse SVR4 name %s\n", name)); 731138232Sharti return (2); 73218730Ssteve } 73318730Ssteve if (entry >= ar->fnamesize) { 734103545Sjmallett DEBUGF(ARCH, ("SVR4 entry offset %s is greater than %zu\n", 735103545Sjmallett name, ar->fnamesize)); 736138232Sharti return (2); 73718730Ssteve } 73818730Ssteve 739103545Sjmallett DEBUGF(ARCH, ("Replaced %s with %s\n", name, &ar->fnametab[entry])); 74018730Ssteve 741138232Sharti strncpy(name, &ar->fnametab[entry], MAXPATHLEN); 74298501Sjmallett name[MAXPATHLEN] = '\0'; 743138232Sharti return (1); 74418730Ssteve} 74518730Ssteve#endif 74618730Ssteve 74718730Ssteve 74818730Ssteve/*- 74918730Ssteve *----------------------------------------------------------------------- 7501590Srgrimes * ArchFindMember -- 7511590Srgrimes * Locate a member of an archive, given the path of the archive and 7521590Srgrimes * the path of the desired member. If the archive is to be modified, 753104696Sjmallett * the mode should be "r+", if not, it should be "r". arhPtr is a 754104696Sjmallett * poitner to the header structure to fill in. 7551590Srgrimes * 7561590Srgrimes * Results: 7571590Srgrimes * An FILE *, opened for reading and writing, positioned at the 7581590Srgrimes * start of the member's struct ar_hdr, or NULL if the member was 7591590Srgrimes * nonexistent. The current struct ar_hdr for member. 7601590Srgrimes * 7611590Srgrimes * Side Effects: 7621590Srgrimes * The passed struct ar_hdr structure is filled in. 7631590Srgrimes * 7641590Srgrimes *----------------------------------------------------------------------- 7651590Srgrimes */ 7661590Srgrimesstatic FILE * 767138232ShartiArchFindMember(char *archive, char *member, struct ar_hdr *arhPtr, char *mode) 7681590Srgrimes{ 7691590Srgrimes FILE * arch; /* Stream to archive */ 7701590Srgrimes int size; /* Size of archive member */ 7711590Srgrimes char *cp; /* Useful character pointer */ 7721590Srgrimes char magic[SARMAG]; 77398138Sjmallett size_t len, tlen; 7741590Srgrimes 775138232Sharti arch = fopen(archive, mode); 77649938Shoek if (arch == NULL) { 77749938Shoek return (NULL); 7781590Srgrimes } 7798874Srgrimes 7801590Srgrimes /* 7811590Srgrimes * We use the ARMAG string to make sure this is an archive we 7821590Srgrimes * can handle... 7831590Srgrimes */ 784138232Sharti if ((fread(magic, SARMAG, 1, arch) != 1) || 785138232Sharti (strncmp(magic, ARMAG, SARMAG) != 0)) { 786138232Sharti fclose(arch); 78749938Shoek return (NULL); 7881590Srgrimes } 7891590Srgrimes 7901590Srgrimes /* 7911590Srgrimes * Because of space constraints and similar things, files are archived 7921590Srgrimes * using their final path components, not the entire thing, so we need 7931590Srgrimes * to point 'member' to the final component, if there is one, to make 7941590Srgrimes * the comparisons easier... 7951590Srgrimes */ 796138232Sharti cp = strrchr(member, '/'); 79752109Sjulian if ((cp != NULL) && (strcmp(member, RANLIBMAG) != 0)) { 7981590Srgrimes member = cp + 1; 7991590Srgrimes } 800138232Sharti len = tlen = strlen(member); 801138232Sharti if (len > sizeof(arhPtr->ar_name)) { 802138232Sharti tlen = sizeof(arhPtr->ar_name); 8031590Srgrimes } 8048874Srgrimes 805138264Sharti while (fread(arhPtr, sizeof(struct ar_hdr), 1, arch) == 1) { 806138232Sharti if (strncmp(arhPtr->ar_fmag, ARFMAG, sizeof(arhPtr->ar_fmag) ) != 0) { 8071590Srgrimes /* 8081590Srgrimes * The header is bogus, so the archive is bad 8091590Srgrimes * and there's no way we can recover... 8101590Srgrimes */ 811138232Sharti fclose(arch); 81249938Shoek return (NULL); 813138232Sharti } else if (strncmp(member, arhPtr->ar_name, tlen) == 0) { 8141590Srgrimes /* 8151590Srgrimes * If the member's name doesn't take up the entire 'name' field, 8161590Srgrimes * we have to be careful of matching prefixes. Names are space- 8171590Srgrimes * padded to the right, so if the character in 'name' at the end 8181590Srgrimes * of the matched string is anything but a space, this isn't the 8191590Srgrimes * member we sought. 8201590Srgrimes */ 8215814Sjkh if (tlen != sizeof(arhPtr->ar_name) && arhPtr->ar_name[tlen] != ' '){ 8225814Sjkh goto skip; 8231590Srgrimes } else { 8241590Srgrimes /* 8251590Srgrimes * To make life easier, we reposition the file at the start 8261590Srgrimes * of the header we just read before we return the stream. 8271590Srgrimes * In a more general situation, it might be better to leave 8281590Srgrimes * the file at the actual member, rather than its header, but 8291590Srgrimes * not here... 8301590Srgrimes */ 831138232Sharti fseek(arch, -sizeof(struct ar_hdr), SEEK_CUR); 8321590Srgrimes return (arch); 8331590Srgrimes } 8345814Sjkh } else 8355814Sjkh#ifdef AR_EFMT1 8365814Sjkh /* 8375814Sjkh * BSD 4.4 extended AR format: #1/<namelen>, with name as the 8385814Sjkh * first <namelen> bytes of the file 8395814Sjkh */ 8405814Sjkh if (strncmp(arhPtr->ar_name, AR_EFMT1, 8415814Sjkh sizeof(AR_EFMT1) - 1) == 0 && 8425814Sjkh isdigit(arhPtr->ar_name[sizeof(AR_EFMT1) - 1])) { 8435814Sjkh 8445814Sjkh unsigned int elen = atoi(&arhPtr->ar_name[sizeof(AR_EFMT1)-1]); 8455814Sjkh char ename[MAXPATHLEN]; 8465814Sjkh 8475814Sjkh if (elen > MAXPATHLEN) { 848138232Sharti fclose(arch); 8495814Sjkh return NULL; 8505814Sjkh } 851138232Sharti if (fread(ename, elen, 1, arch) != 1) { 852138232Sharti fclose(arch); 8535814Sjkh return NULL; 8545814Sjkh } 8555814Sjkh ename[elen] = '\0'; 856103508Sjmallett /* 857103508Sjmallett * XXX choose one. 858103508Sjmallett */ 8595814Sjkh if (DEBUG(ARCH) || DEBUG(MAKE)) { 8605814Sjkh printf("ArchFind: Extended format entry for %s\n", ename); 8615814Sjkh } 8625814Sjkh if (strncmp(ename, member, len) == 0) { 8635814Sjkh /* Found as extended name */ 864138232Sharti fseek(arch, -sizeof(struct ar_hdr) - elen, SEEK_CUR); 8655814Sjkh return (arch); 8665814Sjkh } 867138232Sharti fseek(arch, -elen, SEEK_CUR); 8685814Sjkh goto skip; 8695814Sjkh } else 8705814Sjkh#endif 8715814Sjkh { 8725814Sjkhskip: 8731590Srgrimes /* 8741590Srgrimes * This isn't the member we're after, so we need to advance the 8751590Srgrimes * stream's pointer to the start of the next header. Files are 8761590Srgrimes * padded with newlines to an even-byte boundary, so we need to 8771590Srgrimes * extract the size of the file from the 'size' field of the 8781590Srgrimes * header and round it up during the seek. 8791590Srgrimes */ 880138232Sharti arhPtr->ar_size[sizeof(arhPtr->ar_size) - 1] = '\0'; 881138232Sharti size = (int)strtol(arhPtr->ar_size, NULL, 10); 882138232Sharti fseek(arch, (size + 1) & ~1, SEEK_CUR); 8831590Srgrimes } 8841590Srgrimes } 8851590Srgrimes 8861590Srgrimes /* 8871590Srgrimes * We've looked everywhere, but the member is not to be found. Close the 8881590Srgrimes * archive and return NULL -- an error. 8891590Srgrimes */ 890138232Sharti fclose(arch); 89149938Shoek return (NULL); 8921590Srgrimes} 8931590Srgrimes 8941590Srgrimes/*- 8951590Srgrimes *----------------------------------------------------------------------- 8961590Srgrimes * Arch_Touch -- 8971590Srgrimes * Touch a member of an archive. 8981590Srgrimes * 8991590Srgrimes * Results: 9001590Srgrimes * The 'time' field of the member's header is updated. 9011590Srgrimes * 9021590Srgrimes * Side Effects: 9031590Srgrimes * The modification time of the entire archive is also changed. 9041590Srgrimes * For a library, this could necessitate the re-ranlib'ing of the 9051590Srgrimes * whole thing. 9061590Srgrimes * 9071590Srgrimes *----------------------------------------------------------------------- 9081590Srgrimes */ 9091590Srgrimesvoid 910138232ShartiArch_Touch(GNode *gn) 9111590Srgrimes{ 9121590Srgrimes FILE * arch; /* Stream open to archive, positioned properly */ 9131590Srgrimes struct ar_hdr arh; /* Current header describing member */ 9145814Sjkh char *p1, *p2; 9151590Srgrimes 916138232Sharti arch = ArchFindMember(Var_Value(ARCHIVE, gn, &p1), 917138232Sharti Var_Value(TARGET, gn, &p2), 9181590Srgrimes &arh, "r+"); 919105826Sjmallett free(p1); 920105826Sjmallett free(p2); 921138232Sharti snprintf(arh.ar_date, sizeof(arh.ar_date), "%-12ld", (long)now); 9221590Srgrimes 92349938Shoek if (arch != NULL) { 924138264Sharti fwrite(&arh, sizeof(struct ar_hdr), 1, arch); 925138232Sharti fclose(arch); 9261590Srgrimes } 9271590Srgrimes} 9281590Srgrimes 9291590Srgrimes/*- 9301590Srgrimes *----------------------------------------------------------------------- 9311590Srgrimes * Arch_TouchLib -- 9321590Srgrimes * Given a node which represents a library, touch the thing, making 9331590Srgrimes * sure that the table of contents also is touched. 9341590Srgrimes * 9351590Srgrimes * Results: 9361590Srgrimes * None. 9371590Srgrimes * 9381590Srgrimes * Side Effects: 9391590Srgrimes * Both the modification time of the library and of the RANLIBMAG 9401590Srgrimes * member are set to 'now'. 9411590Srgrimes * 9421590Srgrimes *----------------------------------------------------------------------- 9431590Srgrimes */ 9441590Srgrimesvoid 945138232ShartiArch_TouchLib(GNode *gn) 9461590Srgrimes{ 94718730Ssteve#ifdef RANLIBMAG 9481590Srgrimes FILE * arch; /* Stream open to archive */ 9491590Srgrimes struct ar_hdr arh; /* Header describing table of contents */ 95018730Ssteve struct utimbuf times; /* Times for utime() call */ 9511590Srgrimes 952138232Sharti arch = ArchFindMember(gn->path, RANLIBMAG, &arh, "r+"); 95369390Swill snprintf(arh.ar_date, sizeof(arh.ar_date), "%-12ld", (long) now); 9541590Srgrimes 95549938Shoek if (arch != NULL) { 956138264Sharti fwrite(&arh, sizeof(struct ar_hdr), 1, arch); 957138232Sharti fclose(arch); 9581590Srgrimes 95918730Ssteve times.actime = times.modtime = now; 96018730Ssteve utime(gn->path, ×); 9611590Srgrimes } 96218730Ssteve#endif 9631590Srgrimes} 9641590Srgrimes 9651590Srgrimes/*- 9661590Srgrimes *----------------------------------------------------------------------- 9671590Srgrimes * Arch_MTime -- 968104696Sjmallett * Return the modification time of a member of an archive, given its 969104696Sjmallett * name. 9701590Srgrimes * 9711590Srgrimes * Results: 972138232Sharti * The modification time(seconds). 9731590Srgrimes * 9741590Srgrimes * Side Effects: 9751590Srgrimes * The mtime field of the given node is filled in with the value 9761590Srgrimes * returned by the function. 9771590Srgrimes * 9781590Srgrimes *----------------------------------------------------------------------- 9791590Srgrimes */ 9801590Srgrimesint 981104696SjmallettArch_MTime(GNode *gn) 9821590Srgrimes{ 9831590Srgrimes struct ar_hdr *arhPtr; /* Header of desired member */ 9841590Srgrimes int modTime; /* Modification time as an integer */ 9855814Sjkh char *p1, *p2; 9861590Srgrimes 987138232Sharti arhPtr = ArchStatMember(Var_Value(ARCHIVE, gn, &p1), 988138232Sharti Var_Value(TARGET, gn, &p2), 9891590Srgrimes TRUE); 990105826Sjmallett free(p1); 991105826Sjmallett free(p2); 9925814Sjkh 99349938Shoek if (arhPtr != NULL) { 994138232Sharti modTime = (int)strtol(arhPtr->ar_date, NULL, 10); 9951590Srgrimes } else { 9961590Srgrimes modTime = 0; 9971590Srgrimes } 9981590Srgrimes 9991590Srgrimes gn->mtime = modTime; 10001590Srgrimes return (modTime); 10011590Srgrimes} 10021590Srgrimes 10031590Srgrimes/*- 10041590Srgrimes *----------------------------------------------------------------------- 10051590Srgrimes * Arch_MemMTime -- 10061590Srgrimes * Given a non-existent archive member's node, get its modification 10071590Srgrimes * time from its archived form, if it exists. 10081590Srgrimes * 10091590Srgrimes * Results: 10101590Srgrimes * The modification time. 10111590Srgrimes * 10121590Srgrimes * Side Effects: 10131590Srgrimes * The mtime field is filled in. 10141590Srgrimes * 10151590Srgrimes *----------------------------------------------------------------------- 10161590Srgrimes */ 10171590Srgrimesint 1018138232ShartiArch_MemMTime(GNode *gn) 10191590Srgrimes{ 1020138512Sharti LstNode *ln; 10211590Srgrimes GNode *pgn; 10221590Srgrimes char *nameStart, 10231590Srgrimes *nameEnd; 10241590Srgrimes 1025138916Sharti for (ln = Lst_First(&gn->parents); ln != NULL; ln = Lst_Succ(ln)) { 1026138264Sharti pgn = Lst_Datum(ln); 10271590Srgrimes 10281590Srgrimes if (pgn->type & OP_ARCHV) { 10291590Srgrimes /* 10301590Srgrimes * If the parent is an archive specification and is being made 10311590Srgrimes * and its member's name matches the name of the node we were 10321590Srgrimes * given, record the modification time of the parent in the 10331590Srgrimes * child. We keep searching its parents in case some other 10341590Srgrimes * parent requires this child to exist... 10351590Srgrimes */ 1036138232Sharti nameStart = strchr(pgn->name, '(') + 1; 1037138232Sharti nameEnd = strchr(nameStart, ')'); 10381590Srgrimes 10391590Srgrimes if (pgn->make && 10401590Srgrimes strncmp(nameStart, gn->name, nameEnd - nameStart) == 0) { 10411590Srgrimes gn->mtime = Arch_MTime(pgn); 10421590Srgrimes } 10431590Srgrimes } else if (pgn->make) { 10441590Srgrimes /* 10451590Srgrimes * Something which isn't a library depends on the existence of 10461590Srgrimes * this target, so it needs to exist. 10471590Srgrimes */ 10481590Srgrimes gn->mtime = 0; 10491590Srgrimes break; 10501590Srgrimes } 10511590Srgrimes } 10521590Srgrimes return (gn->mtime); 10531590Srgrimes} 10541590Srgrimes 10551590Srgrimes/*- 10561590Srgrimes *----------------------------------------------------------------------- 10571590Srgrimes * Arch_FindLib -- 1058104696Sjmallett * Search for a named library along the given search path. 10591590Srgrimes * 10601590Srgrimes * Results: 10611590Srgrimes * None. 10621590Srgrimes * 10631590Srgrimes * Side Effects: 10641590Srgrimes * The node's 'path' field is set to the found path (including the 10651590Srgrimes * actual file name, not -l...). If the system can handle the -L 10661590Srgrimes * flag when linking (or we cannot find the library), we assume that 10671590Srgrimes * the user has placed the .LIBRARIES variable in the final linking 10681590Srgrimes * command (or the linker will know where to find it) and set the 10691590Srgrimes * TARGET variable for this node to be the node's name. Otherwise, 10701590Srgrimes * we set the TARGET variable to be the full path of the library, 10711590Srgrimes * as returned by Dir_FindFile. 10721590Srgrimes * 10731590Srgrimes *----------------------------------------------------------------------- 10741590Srgrimes */ 10751590Srgrimesvoid 1076138512ShartiArch_FindLib(GNode *gn, Lst *path) 10771590Srgrimes{ 10781590Srgrimes char *libName; /* file name for archive */ 107969390Swill size_t sz; 10801590Srgrimes 108170080Sdes sz = strlen(gn->name) + 4; 1082138264Sharti libName = emalloc(sz); 108369390Swill snprintf(libName, sz, "lib%s.a", &gn->name[2]); 10841590Srgrimes 1085138232Sharti gn->path = Dir_FindFile(libName, path); 10861590Srgrimes 1087138232Sharti free(libName); 10881590Srgrimes 10891590Srgrimes#ifdef LIBRARIES 1090138232Sharti Var_Set(TARGET, gn->name, gn); 10911590Srgrimes#else 1092138232Sharti Var_Set(TARGET, gn->path == NULL ? gn->name : gn->path, gn); 109318730Ssteve#endif /* LIBRARIES */ 10941590Srgrimes} 10951590Srgrimes 10961590Srgrimes/*- 10971590Srgrimes *----------------------------------------------------------------------- 10981590Srgrimes * Arch_LibOODate -- 10991590Srgrimes * Decide if a node with the OP_LIB attribute is out-of-date. Called 1100104696Sjmallett * from Make_OODate to make its life easier, with the library's 1101104696Sjmallett * graph node. 11021590Srgrimes * 11031590Srgrimes * There are several ways for a library to be out-of-date that are 11041590Srgrimes * not available to ordinary files. In addition, there are ways 11051590Srgrimes * that are open to regular files that are not available to 11061590Srgrimes * libraries. A library that is only used as a source is never 11071590Srgrimes * considered out-of-date by itself. This does not preclude the 11081590Srgrimes * library's modification time from making its parent be out-of-date. 11091590Srgrimes * A library will be considered out-of-date for any of these reasons, 11101590Srgrimes * given that it is a target on a dependency line somewhere: 11111590Srgrimes * Its modification time is less than that of one of its 11121590Srgrimes * sources (gn->mtime < gn->cmtime). 11131590Srgrimes * Its modification time is greater than the time at which the 11141590Srgrimes * make began (i.e. it's been modified in the course 11151590Srgrimes * of the make, probably by archiving). 11165814Sjkh * The modification time of one of its sources is greater than 11175814Sjkh * the one of its RANLIBMAG member (i.e. its table of contents 11185814Sjkh * is out-of-date). We don't compare of the archive time 11195814Sjkh * vs. TOC time because they can be too close. In my 11205814Sjkh * opinion we should not bother with the TOC at all since 11215814Sjkh * this is used by 'ar' rules that affect the data contents 11225814Sjkh * of the archive, not by ranlib rules, which affect the 11238874Srgrimes * TOC. 11241590Srgrimes * 11251590Srgrimes * Results: 11261590Srgrimes * TRUE if the library is out-of-date. FALSE otherwise. 11271590Srgrimes * 11281590Srgrimes * Side Effects: 11291590Srgrimes * The library will be hashed if it hasn't been already. 11301590Srgrimes * 11311590Srgrimes *----------------------------------------------------------------------- 11321590Srgrimes */ 11331590SrgrimesBoolean 1134138232ShartiArch_LibOODate(GNode *gn) 11351590Srgrimes{ 11361590Srgrimes Boolean oodate; 11378874Srgrimes 1138138916Sharti if (OP_NOP(gn->type) && Lst_IsEmpty(&gn->children)) { 11391590Srgrimes oodate = FALSE; 11401590Srgrimes } else if ((gn->mtime > now) || (gn->mtime < gn->cmtime)) { 11411590Srgrimes oodate = TRUE; 11421590Srgrimes } else { 114318730Ssteve#ifdef RANLIBMAG 11441590Srgrimes struct ar_hdr *arhPtr; /* Header for __.SYMDEF */ 11451590Srgrimes int modTimeTOC; /* The table-of-contents's mod time */ 11461590Srgrimes 1147138232Sharti arhPtr = ArchStatMember(gn->path, RANLIBMAG, FALSE); 11481590Srgrimes 114949938Shoek if (arhPtr != NULL) { 1150138232Sharti modTimeTOC = (int)strtol(arhPtr->ar_date, NULL, 10); 11511590Srgrimes 1152103508Sjmallett /* XXX choose one. */ 11531590Srgrimes if (DEBUG(ARCH) || DEBUG(MAKE)) { 11541590Srgrimes printf("%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC)); 11551590Srgrimes } 11565814Sjkh oodate = (gn->cmtime > modTimeTOC); 11571590Srgrimes } else { 11581590Srgrimes /* 11591590Srgrimes * A library w/o a table of contents is out-of-date 11601590Srgrimes */ 11611590Srgrimes if (DEBUG(ARCH) || DEBUG(MAKE)) { 11621590Srgrimes printf("No t.o.c...."); 11631590Srgrimes } 11641590Srgrimes oodate = TRUE; 11651590Srgrimes } 116618730Ssteve#else 116740392Sjdp oodate = (gn->mtime == 0); /* out-of-date if not present */ 116818730Ssteve#endif 11691590Srgrimes } 11701590Srgrimes return (oodate); 11711590Srgrimes} 11721590Srgrimes 11731590Srgrimes/*- 11741590Srgrimes *----------------------------------------------------------------------- 11751590Srgrimes * Arch_Init -- 11761590Srgrimes * Initialize things for this module. 11771590Srgrimes * 11781590Srgrimes * Results: 11791590Srgrimes * None. 11801590Srgrimes * 11811590Srgrimes *----------------------------------------------------------------------- 11821590Srgrimes */ 11831590Srgrimesvoid 1184138232ShartiArch_Init(void) 11851590Srgrimes{ 11861590Srgrimes} 11875814Sjkh 11885814Sjkh/*- 11895814Sjkh *----------------------------------------------------------------------- 11905814Sjkh * Arch_End -- 11915814Sjkh * Cleanup things for this module. 11925814Sjkh * 11935814Sjkh * Results: 11945814Sjkh * None. 11955814Sjkh * 11965814Sjkh * Side Effects: 11975814Sjkh * The 'archives' list is freed 11985814Sjkh * 11995814Sjkh *----------------------------------------------------------------------- 12005814Sjkh */ 12015814Sjkhvoid 1202138232ShartiArch_End(void) 12035814Sjkh{ 1204138264Sharti 1205138916Sharti Lst_Destroy(&archives, ArchFree); 12065814Sjkh} 1207