Bug Summary

File:src/usr.bin/make/arch.c
Warning:line 669, column 12
The right operand of '>=' is a garbage value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name arch.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/make/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.bin/make/obj -I /usr/src/usr.bin/make -D HAS_PATHS_H -D HAS_EXTENDED_GETCWD -I /usr/src/usr.bin/make/lst.lib -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/make/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/make/arch.c
1/* $OpenBSD: arch.c,v 1.91 2020/01/13 13:54:44 espie Exp $ */
2/* $NetBSD: arch.c,v 1.17 1996/11/06 17:58:59 christos Exp $ */
3
4/*
5 * Copyright (c) 1999,2000 Marc Espie.
6 *
7 * Extensive code changes for the OpenBSD project.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD
22 * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30/*
31 * Copyright (c) 1988, 1989, 1990, 1993
32 * The Regents of the University of California. All rights reserved.
33 * Copyright (c) 1989 by Berkeley Softworks
34 * All rights reserved.
35 *
36 * This code is derived from software contributed to Berkeley by
37 * Adam de Boor.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 * 3. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 */
63
64/*
65 * Once again, cacheing/hashing comes into play in the manipulation
66 * of archives. The first time an archive is referenced, all of its members'
67 * headers are read and hashed and the archive closed again. All hashed
68 * archives are kept in a hash (archives) which is searched each time
69 * an archive member is referenced.
70 *
71 */
72
73#include <ar.h>
74#include <assert.h>
75#include <ctype.h>
76#include <fcntl.h>
77#include <limits.h>
78#include <stddef.h>
79#include <stdint.h>
80#include <stdio.h>
81#include <stdlib.h>
82#include <string.h>
83#include <unistd.h>
84#include <ohash.h>
85#include "config.h"
86#include "defines.h"
87#include "buf.h"
88#include "dir.h"
89#include "direxpand.h"
90#include "arch.h"
91#include "var.h"
92#include "targ.h"
93#include "memory.h"
94#include "gnode.h"
95#include "timestamp.h"
96#include "lst.h"
97
98#ifdef TARGET_MACHINE
99#undef MACHINE
100#define MACHINE TARGET_MACHINE
101#endif
102#ifdef TARGET_MACHINE_ARCH
103#undef MACHINE_ARCH
104#define MACHINE_ARCH TARGET_MACHINE_ARCH
105#endif
106#ifdef TARGET_MACHINE_CPU
107#undef MACHINE_CPU
108#define MACHINE_CPU TARGET_MACHINE_CPU
109#endif
110
111static struct ohash archives; /* Archives we've already examined. */
112
113typedef struct Arch_ {
114 struct ohash members; /* All the members of this archive, as
115 * struct arch_member entries. */
116 char name[1]; /* Archive name. */
117} Arch;
118
119/* Used to get to ar's field sizes. */
120static struct ar_hdr *dummy;
121#define AR_NAME_SIZE(sizeof(dummy->ar_name)) (sizeof(dummy->ar_name))
122#define AR_DATE_SIZE(sizeof(dummy->ar_date)) (sizeof(dummy->ar_date))
123
124/* Each archive member is tied to an arch_member structure,
125 * suitable for hashing. */
126struct arch_member {
127 struct timespec mtime; /* Member modification date. */
128 char date[AR_DATE_SIZE(sizeof(dummy->ar_date))+1]; /* Same, before conversion to numeric
129 * value. */
130 char name[1]; /* Member name. */
131};
132
133static struct ohash_info members_info = {
134 offsetof(struct arch_member, name)__builtin_offsetof(struct arch_member, name), NULL((void*)0),
135 hash_calloc, hash_free, element_alloc
136};
137
138static struct ohash_info arch_info = {
139 offsetof(Arch, name)__builtin_offsetof(Arch, name), NULL((void*)0), hash_calloc, hash_free, element_alloc
140};
141
142
143
144static struct arch_member *new_arch_member(struct ar_hdr *, const char *);
145static struct timespec mtime_of_member(struct arch_member *);
146static long field2long(const char *, size_t);
147static Arch *read_archive(const char *, const char *);
148
149static struct timespec ArchMTimeMember(const char *, const char *, bool_Bool);
150static FILE *ArchFindMember(const char *, const char *, struct ar_hdr *, const char *);
151static void ArchTouch(const char *, const char *);
152#if defined(__svr4__) || defined(__SVR4) || \
153 (defined(__OpenBSD__1) && defined(__ELF__1))
154#define SVR4ARCHIVES
155#endif
156static bool_Bool parse_archive(Buffer, const char **, Lst, SymTable *);
157static void add_archive_node(Lst, const char *);
158
159struct SVR4namelist {
160 char *fnametab; /* Extended name table strings */
161 size_t fnamesize; /* Size of the string table */
162};
163
164#ifdef SVR4ARCHIVES
165static const char *svr4list = "Archive list";
166
167static char *ArchSVR4Entry(struct SVR4namelist *, const char *, size_t, FILE *);
168#endif
169
170static struct arch_member *
171new_arch_member(struct ar_hdr *hdr, const char *name)
172{
173 const char *end = NULL((void*)0);
174 struct arch_member *n;
175
176 n = ohash_create_entry(&members_info, name, &end);
177 /* XXX ar entries are NOT null terminated. */
178 memcpy(n->date, &(hdr->ar_date), AR_DATE_SIZE(sizeof(dummy->ar_date)));
179 n->date[AR_DATE_SIZE(sizeof(dummy->ar_date))] = '\0';
180 /* Don't compute mtime before it is needed. */
181 ts_set_out_of_date(n->mtime)(n->mtime).tv_sec = (sizeof(time_t) == sizeof(int32_t) ? (
-0x7fffffff - 1) : (-0x7fffffffffffffffLL - 1)), (n->mtime
).tv_nsec = 0
;
182 return n;
183}
184
185static struct timespec
186mtime_of_member(struct arch_member *m)
187{
188 if (is_out_of_date(m->mtime)((m->mtime).tv_sec == (sizeof(time_t) == sizeof(int32_t) ?
(-0x7fffffff - 1) : (-0x7fffffffffffffffLL - 1)) && (
m->mtime).tv_nsec == 0)
)
189 ts_set_from_time_t((time_t) strtoll(m->date, NULL, 10),do { (m->mtime).tv_sec = (time_t) strtoll(m->date, ((void
*)0), 10); (m->mtime).tv_nsec = 0; if (((m->mtime).tv_sec
== (sizeof(time_t) == sizeof(int32_t) ? (-0x7fffffff - 1) : (
-0x7fffffffffffffffLL - 1)) && (m->mtime).tv_nsec ==
0)) (m->mtime).tv_nsec++; } while (0)
190 m->mtime)do { (m->mtime).tv_sec = (time_t) strtoll(m->date, ((void
*)0), 10); (m->mtime).tv_nsec = 0; if (((m->mtime).tv_sec
== (sizeof(time_t) == sizeof(int32_t) ? (-0x7fffffff - 1) : (
-0x7fffffffffffffffLL - 1)) && (m->mtime).tv_nsec ==
0)) (m->mtime).tv_nsec++; } while (0)
;
191 return m->mtime;
192}
193
194bool_Bool
195Arch_ParseArchive(const char **line, Lst nodes, SymTable *ctxt)
196{
197 bool_Bool result;
198 static BUFFER expand;
199
200 Buf_Reinit(&expand, MAKE_BSIZE256);
201 result = parse_archive(&expand, line, nodes, ctxt);
202 return result;
203}
204
205static void
206add_archive_node(Lst nodes, const char *name)
207{
208 GNode *gn;
209
210 gn = Targ_FindNode(name, TARG_CREATE)Targ_FindNodei(name, ((void*)0), 0x01);
211 gn->type |= OP_ARCHV0x00200000;
212 Lst_AtEnd(nodes, gn);
213}
214
215static bool_Bool
216parse_archive(Buffer expand, const char **linePtr, Lst nodeLst, SymTable *ctxt)
217{
218 const char *cp; /* Pointer into line */
219 const char *lib; /* Library-part of specification */
220 const char *elib;
221 const char *member; /* Member-part of specification */
222 const char *emember;
223 bool_Bool subst_lib;
224
225 /* figure out the library name part */
226 lib = *linePtr;
227 subst_lib = false0;
228
229 for (cp = lib; *cp != '(' && *cp != '\0';) {
230 if (*cp == '$') {
231 if (!Var_ParseSkip(&cp, ctxt))
232 return false0;
233 subst_lib = true1;
234 } else
235 cp++;
236 }
237
238 elib = cp;
239 if (subst_lib) {
240 lib = Var_Substi(lib, elib, ctxt, true1);
241 elib = lib + strlen(lib);
242 }
243
244 if (*cp == '\0') {
245 printf("Unclosed parenthesis in archive specification\n");
246 return false0;
247 }
248 cp++;
249 /* iterate on members, that may be separated by spaces */
250 for (;;) {
251 /* First skip to the start of the member's name, mark that
252 * place and skip to the end of it (either white-space or
253 * a close paren). */
254 bool_Bool subst_member = false0;
255
256 while (ISSPACE(*cp)(isspace((unsigned char)(*cp))))
257 cp++;
258 member = cp;
259 while (*cp != '\0' && *cp != ')' && !ISSPACE(*cp)(isspace((unsigned char)(*cp)))) {
260 if (*cp == '$') {
261 if (!Var_ParseSkip(&cp, ctxt))
262 return false0;
263 subst_member = true1;
264 } else
265 cp++;
266 }
267
268 /* If the specification ends without a closing parenthesis,
269 * chances are there's something wrong (like a missing
270 * backslash), so it's better to return failure than allow such
271 * things to happen. */
272 if (*cp == '\0' || ISSPACE(*cp)(isspace((unsigned char)(*cp)))) {
273 printf("No closing parenthesis in archive specification\n");
274 return false0;
275 }
276
277 /* If we didn't move anywhere, we must be done. */
278 if (cp == member)
279 break;
280
281 emember = cp;
282
283 /* XXX: This should be taken care of intelligently by
284 * SuffExpandChildren, both for the archive and the member
285 * portions. */
286
287 /* If member contains variables, try and substitute for them.
288 * This will slow down archive specs with dynamic sources, of
289 * course, since we'll be (non-)substituting them three times,
290 * but them's the breaks -- we need to do this since
291 * SuffExpandChildren calls us, otherwise we could assume the
292 * thing would be taken care of later. */
293 if (subst_member) {
294 const char *oldMemberName = member;
295 const char *result;
296
297 member = Var_Substi(member, emember, ctxt, true1);
298
299 /* Now form an archive spec and recurse to deal with
300 * nested variables and multi-word variable values....
301 * The results are just placed at the end of the
302 * nodeLst we're returning. */
303 Buf_Addi(expand, lib, elib)Buf_AddChars((expand), (elib) - (lib), (lib));
304 Buf_AddChar(expand, '(')do { if ((expand)->endPtr - (expand)->inPtr <= 1) BufExpand
(expand, 1); *(expand)->inPtr++ = ('('); } while (0)
;
305 Buf_AddString(expand, member)Buf_AddChars((expand), strlen(member), (member));
306 Buf_AddChar(expand, ')')do { if ((expand)->endPtr - (expand)->inPtr <= 1) BufExpand
(expand, 1); *(expand)->inPtr++ = (')'); } while (0)
;
307 result = Buf_Retrieve(expand)(*(expand)->inPtr = '\0', (expand)->buffer);
308
309 if (strchr(member, '$') &&
310 memcmp(member, oldMemberName,
311 emember - oldMemberName) == 0) {
312 /* Must contain dynamic sources, so we can't
313 * deal with it now. let SuffExpandChildren
314 * handle it later */
315 add_archive_node(nodeLst, result);
316 } else if (!Arch_ParseArchive(&result, nodeLst, ctxt))
317 return false0;
318 Buf_Reset(expand)((void)((expand)->inPtr = (expand)->buffer + (0)));
319 } else if (Dir_HasWildcardsi(member, emember)) {
320 LIST members;
321 char *m;
322
323 Lst_Init(&members)(&members)->firstPtr = (&members)->lastPtr = ((
void*)0)
;
324
325 Dir_Expandi(member, emember, defaultPath, &members);
326 while ((m = Lst_DeQueue(&members)) != NULL((void*)0)) {
327 Buf_Addi(expand, lib, elib)Buf_AddChars((expand), (elib) - (lib), (lib));
328 Buf_AddChar(expand, '(')do { if ((expand)->endPtr - (expand)->inPtr <= 1) BufExpand
(expand, 1); *(expand)->inPtr++ = ('('); } while (0)
;
329 Buf_AddString(expand, m)Buf_AddChars((expand), strlen(m), (m));
330 Buf_AddChar(expand, ')')do { if ((expand)->endPtr - (expand)->inPtr <= 1) BufExpand
(expand, 1); *(expand)->inPtr++ = (')'); } while (0)
;
331 free(m);
332 add_archive_node(nodeLst, Buf_Retrieve(expand)(*(expand)->inPtr = '\0', (expand)->buffer));
333 Buf_Reset(expand)((void)((expand)->inPtr = (expand)->buffer + (0)));
334 }
335 } else {
336 Buf_Addi(expand, lib, elib)Buf_AddChars((expand), (elib) - (lib), (lib));
337 Buf_AddChar(expand, '(')do { if ((expand)->endPtr - (expand)->inPtr <= 1) BufExpand
(expand, 1); *(expand)->inPtr++ = ('('); } while (0)
;
338 Buf_Addi(expand, member, emember)Buf_AddChars((expand), (emember) - (member), (member));
339 Buf_AddChar(expand, ')')do { if ((expand)->endPtr - (expand)->inPtr <= 1) BufExpand
(expand, 1); *(expand)->inPtr++ = (')'); } while (0)
;
340 add_archive_node(nodeLst, Buf_Retrieve(expand)(*(expand)->inPtr = '\0', (expand)->buffer));
341 Buf_Reset(expand)((void)((expand)->inPtr = (expand)->buffer + (0)));
342 }
343 if (subst_member)
344 free((char *)member);
345
346 }
347
348 if (subst_lib)
349 free((char *)lib);
350
351 /* We promised the pointer would be set up at the next non-space, so
352 * we must advance cp there before setting *linePtr... (note that on
353 * entrance to the loop, cp is guaranteed to point at a ')') */
354 do {
355 cp++;
356 } while (ISSPACE(*cp)(isspace((unsigned char)(*cp))));
357
358 *linePtr = cp;
359 return true1;
360}
361
362/* Helper function: ar fields are not null terminated. */
363static long
364field2long(const char *field, size_t length)
365{
366 static char enough[32];
367
368 assert(length < sizeof(enough))((length < sizeof(enough)) ? (void)0 : __assert2("/usr/src/usr.bin/make/arch.c"
, 368, __func__, "length < sizeof(enough)"))
;
369 memcpy(enough, field, length);
370 enough[length] = '\0';
371 return strtol(enough, NULL((void*)0), 10);
372}
373
374static Arch *
375read_archive(const char *archive, const char *earchive)
376{
377 FILE *arch; /* Stream to archive */
378 char magic[SARMAG8];
379 Arch *ar;
380 struct SVR4namelist list;
381
382 list.fnametab = NULL((void*)0);
383
384 /* When we encounter an archive for the first time, we read its
385 * whole contents, to place it in the cache. */
386 arch = fopen(archive, "r");
387 if (arch == NULL((void*)0))
20
Assuming 'arch' is not equal to NULL
21
Taking false branch
388 return NULL((void*)0);
389
390 /* Make sure this is an archive we can handle. */
391 if ((fread(magic, SARMAG8, 1, arch) != 1) ||
22
Assuming the condition is false
24
Taking false branch
392 (strncmp(magic, ARMAG"!<arch>\n", SARMAG8) != 0)) {
23
Assuming the condition is false
393 fclose(arch);
394 return NULL((void*)0);
395 }
396
397 ar = ohash_create_entry(&arch_info, archive, &earchive);
398 ohash_init(&ar->members, 8, &members_info);
399
400 for (;;) {
25
Loop condition is true. Entering loop body
401 size_t n;
402 struct ar_hdr arHeader; /* Archive-member header */
403 off_t size; /* Size of archive member */
404 char buffer[PATH_MAX1024];
405 char *memberName; /* Current member name while hashing. */
406 char *cp;
407
408 memberName = buffer;
409 n = fread(&arHeader, 1, sizeof(struct ar_hdr), arch);
410
411 /* Whole archive read ok. */
412 if (n == 0 && feof(arch)(!__isthreaded ? (((arch)->_flags & 0x0020) != 0) : (feof
)(arch))
) {
26
Assuming 'n' is not equal to 0
413 free(list.fnametab);
414 fclose(arch);
415 return ar;
416 }
417 if (n < sizeof(struct ar_hdr))
27
Assuming the condition is false
28
Taking false branch
418 break;
419
420 if (memcmp(arHeader.ar_fmag, ARFMAG"`\n", sizeof(arHeader.ar_fmag))
29
Assuming the condition is false
30
Taking false branch
421 != 0) {
422 /* header is bogus. */
423 break;
424 } else {
425 /* We need to advance the stream's pointer to the start
426 * of the next header. Records are padded with
427 * newlines to an even-byte boundary, so we need to
428 * extract the size of the record and round it up
429 * during the seek. */
430 size = (off_t) field2long(arHeader.ar_size,
431 sizeof(arHeader.ar_size));
432
433 (void)memcpy(memberName, arHeader.ar_name,
434 AR_NAME_SIZE(sizeof(dummy->ar_name)));
435 /* Find real end of name (strip extranous ' ') */
436 for (cp = memberName + AR_NAME_SIZE(sizeof(dummy->ar_name)) - 1; *cp == ' ';)
31
Assuming the condition is false
32
Loop condition is false. Execution continues on line 438
437 cp--;
438 cp[1] = '\0';
439
440#ifdef SVR4ARCHIVES
441 /* SVR4 names are slash terminated. Also svr4 extended
442 * AR format.
443 */
444 if (memberName[0] == '/') {
33
Assuming the condition is true
34
Taking true branch
445 /* SVR4 magic mode. */
446 memberName = ArchSVR4Entry(&list, memberName,
35
Calling 'ArchSVR4Entry'
447 size, arch);
448 if (memberName == NULL((void*)0))
449 /* Invalid data */
450 break;
451 else if (memberName == svr4list)
452 /* List of files entry */
453 continue;
454 /* Got the entry. */
455 /* XXX this assumes further processing, such as
456 * AR_EFMT1, also applies to SVR4ARCHIVES. */
457 }
458 else {
459 if (cp[0] == '/')
460 cp[0] = '\0';
461 }
462#endif
463
464#ifdef AR_EFMT1"#1/"
465 /* BSD 4.4 extended AR format: #1/<namelen>, with name
466 * as the first <namelen> bytes of the file. */
467 if (memcmp(memberName, AR_EFMT1"#1/", sizeof(AR_EFMT1"#1/") - 1)
468 == 0 && ISDIGIT(memberName[sizeof(AR_EFMT1) - 1])(isdigit((unsigned char)(memberName[sizeof("#1/") - 1])))) {
469
470 int elen = atoi(memberName +
471 sizeof(AR_EFMT1"#1/")-1);
472
473 if (elen <= 0 || elen >= PATH_MAX1024)
474 break;
475 memberName = buffer;
476 if (fread(memberName, elen, 1, arch) != 1)
477 break;
478 memberName[elen] = '\0';
479 if (fseek(arch, -elen, SEEK_CUR1) != 0)
480 break;
481 if (DEBUG(ARCH)(debug & 0x0001) || DEBUG(MAKE)(debug & 0x0040))
482 printf("ArchStat: Extended format entry for %s\n",
483 memberName);
484 }
485#endif
486
487 ohash_insert(&ar->members,
488 ohash_qlookup(&ar->members, memberName),
489 new_arch_member(&arHeader, memberName));
490 }
491 if (fseek(arch, (size + 1) & ~1, SEEK_CUR1) != 0)
492 break;
493 }
494
495 fclose(arch);
496 ohash_delete(&ar->members);
497 free(list.fnametab);
498 free(ar);
499 return NULL((void*)0);
500}
501
502/*-
503 *-----------------------------------------------------------------------
504 * ArchMTimeMember --
505 * Find the modification time of an archive's member, given the
506 * path to the archive and the path to the desired member.
507 *
508 * Results:
509 * The archive member's modification time, or OUT_OF_DATE if member
510 * was not found (convenient, so that missing members are always
511 * out of date).
512 *
513 * Side Effects:
514 * Cache the whole archive contents if hash is true.
515 *-----------------------------------------------------------------------
516 */
517static struct timespec
518ArchMTimeMember(
519 const char *archive, /* Path to the archive */
520 const char *member, /* Name of member. If it is a path, only the
521 * last component is used. */
522 bool_Bool hash) /* true if archive should be hashed if not
523 * already so. */
524{
525 FILE *arch; /* Stream to archive */
526 Arch *ar; /* Archive descriptor */
527 unsigned int slot; /* Place of archive in the archives hash */
528 const char *end = NULL((void*)0);
529 const char *cp;
530 struct timespec result;
531
532 ts_set_out_of_date(result)(result).tv_sec = (sizeof(time_t) == sizeof(int32_t) ? (-0x7fffffff
- 1) : (-0x7fffffffffffffffLL - 1)), (result).tv_nsec = 0
;
13
'?' condition is false
533 /* Because of space constraints and similar things, files are archived
534 * using their final path components, not the entire thing, so we need
535 * to point 'member' to the final component, if there is one, to make
536 * the comparisons easier... */
537 cp = strrchr(member, '/');
538 if (cp != NULL((void*)0))
14
Assuming 'cp' is equal to NULL
15
Taking false branch
539 member = cp + 1;
540
541 /* Try to find archive in cache. */
542 slot = ohash_qlookupi(&archives, archive, &end);
543 ar = ohash_find(&archives, slot);
544
545 /* If not found, get it now. */
546 if (ar == NULL((void*)0)) {
16
Assuming 'ar' is equal to NULL
17
Taking true branch
547 if (!hash
17.1
'hash' is true
) {
18
Taking false branch
548 /* Quick path: no need to hash the whole archive, just
549 * use ArchFindMember to get the member's header and
550 * close the stream again. */
551 struct ar_hdr arHeader;
552
553 arch = ArchFindMember(archive, member, &arHeader, "r");
554
555 if (arch != NULL((void*)0)) {
556 fclose(arch);
557 ts_set_from_time_t(do { (result).tv_sec = (time_t)strtol(arHeader.ar_date, ((void
*)0), 10); (result).tv_nsec = 0; if (((result).tv_sec == (sizeof
(time_t) == sizeof(int32_t) ? (-0x7fffffff - 1) : (-0x7fffffffffffffffLL
- 1)) && (result).tv_nsec == 0)) (result).tv_nsec++;
} while (0)
558 (time_t)strtol(arHeader.ar_date, NULL, 10),do { (result).tv_sec = (time_t)strtol(arHeader.ar_date, ((void
*)0), 10); (result).tv_nsec = 0; if (((result).tv_sec == (sizeof
(time_t) == sizeof(int32_t) ? (-0x7fffffff - 1) : (-0x7fffffffffffffffLL
- 1)) && (result).tv_nsec == 0)) (result).tv_nsec++;
} while (0)
559 result)do { (result).tv_sec = (time_t)strtol(arHeader.ar_date, ((void
*)0), 10); (result).tv_nsec = 0; if (((result).tv_sec == (sizeof
(time_t) == sizeof(int32_t) ? (-0x7fffffff - 1) : (-0x7fffffffffffffffLL
- 1)) && (result).tv_nsec == 0)) (result).tv_nsec++;
} while (0)
;
560 }
561 return result;
562 }
563 ar = read_archive(archive, end);
19
Calling 'read_archive'
564 if (ar != NULL((void*)0))
565 ohash_insert(&archives, slot, ar);
566 }
567
568 /* If archive was found, get entry we seek. */
569 if (ar != NULL((void*)0)) {
570 struct arch_member *he;
571 end = NULL((void*)0);
572
573 he = ohash_find(&ar->members, ohash_qlookupi(&ar->members,
574 member, &end));
575 if (he != NULL((void*)0))
576 return mtime_of_member(he);
577 else {
578 if ((size_t)(end - member) > AR_NAME_SIZE(sizeof(dummy->ar_name))) {
579 /* Try truncated name. */
580 end = member + AR_NAME_SIZE(sizeof(dummy->ar_name));
581 he = ohash_find(&ar->members,
582 ohash_qlookupi(&ar->members, member, &end));
583 if (he != NULL((void*)0))
584 return mtime_of_member(he);
585 }
586 }
587 }
588 return result;
589}
590
591#ifdef SVR4ARCHIVES
592/*-
593 *-----------------------------------------------------------------------
594 * ArchSVR4Entry --
595 * Parse an SVR4 style entry that begins with a slash.
596 * If it is "//", then load the table of filenames
597 * If it is "/<offset>", then try to substitute the long file name
598 * from offset of a table previously read.
599 *
600 * Results:
601 * svr4list: just read a list of names
602 * NULL: error occurred
603 * extended name
604 *
605 * Side-effect:
606 * For a list of names, store the list in l.
607 *-----------------------------------------------------------------------
608 */
609
610static char *
611ArchSVR4Entry(struct SVR4namelist *l, const char *name, size_t size, FILE *arch)
612{
613#define ARLONGNAMES1"/" "/"
614#define ARLONGNAMES2"ARFILENAMES" "ARFILENAMES"
615 size_t entry;
616 char *ptr, *eptr;
617
618 assert(name[0] == '/')((name[0] == '/') ? (void)0 : __assert2("/usr/src/usr.bin/make/arch.c"
, 618, __func__, "name[0] == '/'"))
;
36
'?' condition is true
619 name++;
620 /* First comes a table of archive names, to be used by subsequent
621 * calls. */
622 if (memcmp(name, ARLONGNAMES1"/", sizeof(ARLONGNAMES1"/") - 1) == 0 ||
37
Assuming the condition is false
39
Taking false branch
623 memcmp(name, ARLONGNAMES2"ARFILENAMES", sizeof(ARLONGNAMES2"ARFILENAMES") - 1) == 0) {
38
Assuming the condition is false
624
625 if (l->fnametab != NULL((void*)0)) {
626 if (DEBUG(ARCH)(debug & 0x0001))
627 printf("Attempted to redefine an SVR4 name table\n");
628 return NULL((void*)0);
629 }
630
631 l->fnametab = emalloc(size);
632 l->fnamesize = size;
633
634 if (fread(l->fnametab, size, 1, arch) != 1) {
635 if (DEBUG(ARCH)(debug & 0x0001))
636 printf("Reading an SVR4 name table failed\n");
637 return NULL((void*)0);
638 }
639
640 eptr = l->fnametab + size;
641 for (entry = 0, ptr = l->fnametab; ptr < eptr; ptr++)
642 switch (*ptr) {
643 case '/':
644 entry++;
645 *ptr = '\0';
646 break;
647
648 case '\n':
649 break;
650
651 default:
652 break;
653 }
654 if (DEBUG(ARCH)(debug & 0x0001))
655 printf("Found svr4 archive name table with %zu entries\n",
656 entry);
657 return (char *)svr4list;
658 }
659 /* Then the names themselves are given as offsets in this table. */
660 if (*name == ' ' || *name == '\0')
40
Assuming the condition is false
41
Assuming the condition is false
42
Taking false branch
661 return NULL((void*)0);
662
663 entry = (size_t) strtol(name, &eptr, 0);
664 if ((*eptr != ' ' && *eptr != '\0') || eptr
43.1
'eptr' is not equal to 'name'
== name) {
43
Assuming the condition is false
44
Taking false branch
665 if (DEBUG(ARCH)(debug & 0x0001))
666 printf("Could not parse SVR4 name /%s\n", name);
667 return NULL((void*)0);
668 }
669 if (entry >= l->fnamesize) {
45
The right operand of '>=' is a garbage value
670 if (DEBUG(ARCH)(debug & 0x0001))
671 printf("SVR4 entry offset /%s is greater than %zu\n",
672 name, l->fnamesize);
673 return NULL((void*)0);
674 }
675
676 if (DEBUG(ARCH)(debug & 0x0001))
677 printf("Replaced /%s with %s\n", name, l->fnametab + entry);
678
679 return l->fnametab + entry;
680}
681#endif
682
683
684/*-
685 *-----------------------------------------------------------------------
686 * ArchFindMember --
687 * Locate a member of an archive, given the path of the archive and
688 * the path of the desired member. If the archive is to be modified,
689 * the mode should be "r+", if not, it should be "r".
690 *
691 * Results:
692 * A FILE *, opened for reading and writing, positioned right after
693 * the member's header, or NULL if the member was nonexistent.
694 *
695 * Side Effects:
696 * Fill the struct ar_hdr pointed by arHeaderPtr.
697 *-----------------------------------------------------------------------
698 */
699static FILE *
700ArchFindMember(
701 const char *archive, /* Path to the archive */
702 const char *member, /* Name of member. If it is a path, only the
703 * last component is used. */
704 struct ar_hdr *arHeaderPtr,/* Pointer to header structure to be filled in */
705 const char *mode) /* mode for opening the stream */
706{
707 FILE * arch; /* Stream to archive */
708 char *cp;
709 char magic[SARMAG8];
710 size_t length;
711 struct SVR4namelist list;
712
713 list.fnametab = NULL((void*)0);
714
715 arch = fopen(archive, mode);
716 if (arch == NULL((void*)0))
717 return NULL((void*)0);
718
719 /* Make sure this is an archive we can handle. */
720 if (fread(magic, SARMAG8, 1, arch) != 1 ||
721 strncmp(magic, ARMAG"!<arch>\n", SARMAG8) != 0) {
722 fclose(arch);
723 return NULL((void*)0);
724 }
725
726 /* Because of space constraints and similar things, files are archived
727 * using their final path components, not the entire thing, so we need
728 * to point 'member' to the final component, if there is one, to make
729 * the comparisons easier... */
730 cp = strrchr(member, '/');
731 if (cp != NULL((void*)0))
732 member = cp + 1;
733
734 length = strlen(member);
735 if (length >= AR_NAME_SIZE(sizeof(dummy->ar_name)))
736 length = AR_NAME_SIZE(sizeof(dummy->ar_name));
737
738 /* Error handling is simpler than for read_archive, since we just
739 * look for a given member. */
740 while (fread(arHeaderPtr, sizeof(struct ar_hdr), 1, arch) == 1) {
741 off_t size; /* Size of archive member */
742 char *memberName;
743
744 if (memcmp(arHeaderPtr->ar_fmag, ARFMAG"`\n",
745 sizeof(arHeaderPtr->ar_fmag) ) != 0)
746 /* The header is bogus, so the archive is bad. */
747 break;
748
749 memberName = arHeaderPtr->ar_name;
750 if (memcmp(member, memberName, length) == 0) {
751 /* If the member's name doesn't take up the entire
752 * 'name' field, we have to be careful of matching
753 * prefixes. Names are space- padded to the right, so
754 * if the character in 'name' at the end of the matched
755 * string is anything but a space, this isn't the
756 * member we sought. */
757#ifdef SVR4ARCHIVES
758 if (length < sizeof(arHeaderPtr->ar_name) &&
759 memberName[length] == '/')
760 length++;
761#endif
762 if (length == sizeof(arHeaderPtr->ar_name) ||
763 memberName[length] == ' ') {
764 free(list.fnametab);
765 return arch;
766 }
767 }
768
769 size = (off_t) field2long(arHeaderPtr->ar_size,
770 sizeof(arHeaderPtr->ar_size));
771
772#ifdef SVR4ARCHIVES
773 /* svr4 names are slash terminated. Also svr4 extended AR
774 * format.
775 */
776 if (memberName[0] == '/') {
777 /* svr4 magic mode. */
778 memberName = ArchSVR4Entry(&list, arHeaderPtr->ar_name,
779 size, arch);
780 if (memberName == NULL((void*)0))
781 /* Invalid data */
782 break;
783 else if (memberName == svr4list)
784 /* List of files entry */
785 continue;
786 /* Got the entry. */
787 if (strcmp(memberName, member) == 0) {
788 free(list.fnametab);
789 return arch;
790 }
791 }
792#endif
793
794#ifdef AR_EFMT1"#1/"
795 /* BSD 4.4 extended AR format: #1/<namelen>, with name as the
796 * first <namelen> bytes of the file. */
797 if (memcmp(memberName, AR_EFMT1"#1/", sizeof(AR_EFMT1"#1/") - 1) == 0 &&
798 ISDIGIT(memberName[sizeof(AR_EFMT1) - 1])(isdigit((unsigned char)(memberName[sizeof("#1/") - 1])))) {
799 char ename[PATH_MAX1024];
800
801 int elength = atoi(memberName + sizeof(AR_EFMT1"#1/")-1);
802
803 if (elength <= 0 || elength >= PATH_MAX1024)
804 break;
805 if (fread(ename, elength, 1, arch) != 1)
806 break;
807 if (fseek(arch, -elength, SEEK_CUR1) != 0)
808 break;
809 ename[elength] = '\0';
810 if (DEBUG(ARCH)(debug & 0x0001) || DEBUG(MAKE)(debug & 0x0040))
811 printf("ArchFind: Extended format entry for %s\n", ename);
812 /* Found as extended name. */
813 if (strcmp(ename, member) == 0) {
814 free(list.fnametab);
815 return arch;
816 }
817 }
818#endif
819 /* This isn't the member we're after, so we need to advance the
820 * stream's pointer to the start of the next header. */
821 if (fseek(arch, (size + 1) & ~1, SEEK_CUR1) != 0)
822 break;
823 }
824
825 /* We did not find the member, or we ran into an error while reading
826 * the archive. */
827#ifdef SVRARCHIVES
828 free(list.fnametab);
829#endif
830 fclose(arch);
831 return NULL((void*)0);
832}
833
834static void
835ArchTouch(const char *archive, const char *member)
836{
837 FILE *arch;
838 struct ar_hdr arHeader;
839
840 arch = ArchFindMember(archive, member, &arHeader, "r+");
841 if (arch != NULL((void*)0)) {
842 snprintf(arHeader.ar_date, sizeof(arHeader.ar_date),
843 "%-12ld", (long) time(NULL((void*)0)));
844 if (fseek(arch, -sizeof(struct ar_hdr), SEEK_CUR1) == 0)
845 (void)fwrite(&arHeader, sizeof(struct ar_hdr), 1, arch);
846 fclose(arch);
847 }
848}
849
850/*
851 * Side Effects:
852 * The modification time of the entire archive is also changed.
853 * For a library, this could necessitate the re-ranlib'ing of the
854 * whole thing.
855 */
856void
857Arch_Touch(GNode *gn)
858{
859 ArchTouch(Var(ARCHIVE_INDEX, gn)((gn)->localvars.locals[2]), Var(MEMBER_INDEX, gn)((gn)->localvars.locals[3]));
860}
861
862struct timespec
863Arch_MTime(GNode *gn)
864{
865 gn->mtime = ArchMTimeMember(Var(ARCHIVE_INDEX, gn)((gn)->localvars.locals[2]),
12
Calling 'ArchMTimeMember'
866 Var(MEMBER_INDEX, gn)((gn)->localvars.locals[3]), true1);
867
868 return gn->mtime;
869}
870
871struct timespec
872Arch_MemMTime(GNode *gn)
873{
874 LstNode ln;
875
876 for (ln = Lst_First(&gn->parents)((&gn->parents)->firstPtr); ln != NULL((void*)0); ln = Lst_Adv(ln)((ln)->nextPtr)) {
1
Assuming 'ln' is not equal to NULL
2
Loop condition is true. Entering loop body
877 GNode *pgn;
878 char *nameStart;
879 char *nameEnd;
880
881 pgn = Lst_Datum(ln)((ln)->datum);
882
883 if (pgn->type & OP_ARCHV0x00200000) {
3
Assuming the condition is true
4
Taking true branch
884 /* If the parent is an archive specification and is
885 * being built and its member's name matches the name of
886 * the node we were given, record the modification time
887 * of the parent in the child. We keep searching its
888 * parents in case some other parent requires this
889 * child to exist... */
890 if ((nameStart = strchr(pgn->name, '(') ) != NULL((void*)0)) {
5
Assuming the condition is true
6
Taking true branch
891 nameStart++;
892 nameEnd = strchr(nameStart, ')');
893 } else
894 nameEnd = NULL((void*)0);
895
896 if (pgn->must_make && nameEnd != NULL((void*)0) &&
7
Assuming field 'must_make' is true
8
Assuming 'nameEnd' is not equal to NULL
10
Taking true branch
897 strncmp(nameStart, gn->name, nameEnd - nameStart)
898 == 0 && gn->name[nameEnd-nameStart] == '\0')
9
Assuming the condition is true
899 gn->mtime = Arch_MTime(pgn);
11
Calling 'Arch_MTime'
900 } else if (pgn->must_make) {
901 /* Something which isn't a library depends on the
902 * existence of this target, so it needs to exist. */
903 ts_set_out_of_date(gn->mtime)(gn->mtime).tv_sec = (sizeof(time_t) == sizeof(int32_t) ? (
-0x7fffffff - 1) : (-0x7fffffffffffffffLL - 1)), (gn->mtime
).tv_nsec = 0
;
904 break;
905 }
906 }
907 return gn->mtime;
908}
909
910void
911Arch_Init(void)
912{
913 ohash_init(&archives, 4, &arch_info);
914}