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