Annotation of src/usr.bin/make/dir.c, Revision 1.68
1.68 ! espie 1: /* $OpenBSD: dir.c,v 1.67 2015/01/23 22:35:57 espie Exp $ */
1.7 millert 2: /* $NetBSD: dir.c,v 1.14 1997/03/29 16:51:26 christos Exp $ */
1.1 deraadt 3:
4: /*
1.31 espie 5: * Copyright (c) 1999 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: /*
1.1 deraadt 31: * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
32: * Copyright (c) 1988, 1989 by Adam de Boor
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.
1.40 millert 47: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 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:
1.32 espie 64: #include <sys/stat.h>
65: #include <dirent.h>
1.34 espie 66: #include <limits.h>
1.25 espie 67: #include <stddef.h>
1.62 espie 68: #include <stdint.h>
1.1 deraadt 69: #include <stdio.h>
1.34 espie 70: #include <stdlib.h>
1.32 espie 71: #include <string.h>
1.62 espie 72: #include <ohash.h>
1.32 espie 73: #include "config.h"
74: #include "defines.h"
1.1 deraadt 75: #include "dir.h"
1.32 espie 76: #include "lst.h"
77: #include "memory.h"
78: #include "buf.h"
79: #include "gnode.h"
80: #include "arch.h"
1.55 espie 81: #include "targ.h"
1.32 espie 82: #include "error.h"
83: #include "str.h"
84: #include "timestamp.h"
85:
86:
1.55 espie 87: /* A search path consists of a Lst of PathEntry structures. A Path
1.50 espie 88: * structure has in it the name of the directory and a hash table of all
89: * the files in the directory. This is used to cut down on the number of
90: * system calls necessary to find implicit dependents and their like.
91: * Since these searches are made before any actions are taken, we need not
1.1 deraadt 92: * worry about the directory changing due to creation commands. If this
93: * hampers the style of some makefiles, they must be changed.
94: *
95: * A list of all previously-read directories is kept in the
1.51 espie 96: * knownDirectories cache.
1.1 deraadt 97: *
98: * The need for the caching of whole directories is brought about by
99: * the multi-level transformation code in suff.c, which tends to search
100: * for far more files than regular make does. In the initial
101: * implementation, the amount of time spent performing "stat" calls was
102: * truly astronomical. The problem with hashing at the start is,
103: * of course, that pmake doesn't then detect changes to these directories
104: * during the course of the make. Three possibilities suggest themselves:
105: *
106: * 1) just use stat to test for a file's existence. As mentioned
107: * above, this is very inefficient due to the number of checks
108: * engendered by the multi-level transformation code.
109: * 2) use readdir() and company to search the directories, keeping
110: * them open between checks. I have tried this and while it
111: * didn't slow down the process too much, it could severely
112: * affect the amount of parallelism available as each directory
113: * open would take another file descriptor out of play for
114: * handling I/O for another job. Given that it is only recently
115: * that UNIX OS's have taken to allowing more than 20 or 32
116: * file descriptors for a process, this doesn't seem acceptable
117: * to me.
1.50 espie 118: * 3) record the mtime of the directory in the PathEntry structure and
1.1 deraadt 119: * verify the directory hasn't changed since the contents were
120: * hashed. This will catch the creation or deletion of files,
121: * but not the updating of files. However, since it is the
122: * creation and deletion that is the problem, this could be
123: * a good thing to do. Unfortunately, if the directory (say ".")
124: * were fairly large and changed fairly frequently, the constant
125: * rehashing could seriously degrade performance. It might be
126: * good in such cases to keep track of the number of rehashes
127: * and if the number goes over a (small) limit, resort to using
128: * stat in its place.
129: *
130: * An additional thing to consider is that pmake is used primarily
131: * to create C programs and until recently pcc-based compilers refused
132: * to allow you to specify where the resulting object file should be
133: * placed. This forced all objects to be created in the current
134: * directory. This isn't meant as a full excuse, just an explanation of
135: * some of the reasons for the caching used here.
136: *
137: * One more note: the location of a target's file is only performed
138: * on the downward traversal of the graph and then only for terminal
139: * nodes in the graph. This could be construed as wrong in some cases,
140: * but prevents inadvertent modification of files when the "installed"
141: * directory for a file is provided in the search path.
142: *
143: * Another data structure maintained by this module is an mtime
144: * cache used when the searching of cached directories fails to find
145: * a file. In the past, Dir_FindFile would simply perform an access()
146: * call in such a case to determine if the file could be found using
147: * just the name given. When this hit, however, all that was gained
148: * was the knowledge that the file existed. Given that an access() is
149: * essentially a stat() without the copyout() call, and that the same
150: * filesystem overhead would have to be incurred in Dir_MTime, it made
151: * sense to replace the access() with a stat() and record the mtime
1.31 espie 152: * in a cache for when Dir_MTime was actually called. */
1.1 deraadt 153:
154:
1.55 espie 155: /* several data structures exist to handle caching of directory stuff.
156: *
157: * There is a global hash of directory names (knownDirectories), and each
158: * read directory is kept there as one PathEntry instance. Such a structure
159: * only contains the file names.
160: *
161: * There is a global hash of timestamps (modification times), so care must
162: * be taken of giving the right file names to that structure.
163: *
164: * XXX A set of similar structure should exist at the Target level to properly
165: * take care of VPATH issues.
166: */
167:
168:
169: /* each directory is cached into a PathEntry structure. */
170: struct PathEntry {
171: int refCount; /* ref-counted, can participate to
172: * several paths */
173: struct ohash files; /* hash of name of files in the directory */
174: char name[1]; /* directory name */
175: };
1.27 espie 176:
1.55 espie 177: /* PathEntry kept on knownDirectories */
178: static struct ohash_info dir_info = {
1.64 espie 179: offsetof(struct PathEntry, name), NULL, hash_calloc, hash_free,
1.55 espie 180: element_alloc
1.27 espie 181: };
182:
1.51 espie 183: static struct ohash knownDirectories; /* cache all open directories */
1.31 espie 184:
1.55 espie 185:
186: /* file names kept in a path entry */
187: static struct ohash_info file_info = {
1.64 espie 188: 0, NULL, hash_calloc, hash_free, element_alloc
1.55 espie 189: };
190:
191:
1.32 espie 192: /* Global structure used to cache mtimes. XXX We don't cache an mtime
193: * before a caller actually looks up for the given time, because of the
194: * possibility a caller might update the file and invalidate the cache
195: * entry, and we don't look up in this cache except as a last resort.
196: */
1.55 espie 197: struct file_stamp {
1.62 espie 198: struct timespec mtime; /* time stamp... */
1.55 espie 199: char name[1]; /* ...for that file. */
200: };
201:
1.53 espie 202: static struct ohash mtimes;
1.1 deraadt 203:
1.31 espie 204:
1.53 espie 205: static struct ohash_info stamp_info = {
1.64 espie 206: offsetof(struct file_stamp, name), NULL, hash_calloc, hash_free,
1.55 espie 207: element_alloc
208: };
209:
210:
211:
212: static LIST theDefaultPath; /* main search path */
213: Lst defaultPath= &theDefaultPath;
214: struct PathEntry *dot; /* contents of current directory */
1.27 espie 215:
1.26 espie 216:
1.1 deraadt 217:
1.32 espie 218: /* add_file(path, name): add a file name to a path hash structure. */
1.50 espie 219: static void add_file(struct PathEntry *, const char *);
1.32 espie 220: /* n = find_file_hashi(p, name, end, hv): retrieve name in a path hash
221: * structure. */
1.53 espie 222: static char *find_file_hashi(struct PathEntry *, const char *, const char *,
1.50 espie 223: uint32_t);
1.32 espie 224:
225: /* stamp = find_stampi(name, end): look for (name, end) in the global
226: * cache. */
1.31 espie 227: static struct file_stamp *find_stampi(const char *, const char *);
1.32 espie 228: /* record_stamp(name, timestamp): record timestamp for name in the global
229: * cache. */
1.62 espie 230: static void record_stamp(const char *, struct timespec);
1.32 espie 231:
1.55 espie 232: static bool read_directory(struct PathEntry *);
1.32 espie 233: /* p = DirReaddiri(name, end): read an actual directory, caching results
234: * as we go. */
1.55 espie 235: static struct PathEntry *create_PathEntry(const char *, const char *);
1.32 espie 236: /* Debugging: show a dir name in a path. */
1.31 espie 237: static void DirPrintDir(void *);
1.1 deraadt 238:
1.55 espie 239: /***
240: *** timestamp handling
241: ***/
242:
1.26 espie 243: static void
1.62 espie 244: record_stamp(const char *file, struct timespec t)
1.27 espie 245: {
1.46 espie 246: unsigned int slot;
247: const char *end = NULL;
248: struct file_stamp *n;
249:
250: slot = ohash_qlookupi(&mtimes, file, &end);
251: n = ohash_find(&mtimes, slot);
252: if (n)
253: n->mtime = t;
254: else {
255: n = ohash_create_entry(&stamp_info, file, &end);
256: n->mtime = t;
257: ohash_insert(&mtimes, slot, n);
258: }
1.27 espie 259: }
1.31 espie 260:
1.27 espie 261: static struct file_stamp *
1.41 espie 262: find_stampi(const char *file, const char *efile)
1.27 espie 263: {
1.46 espie 264: return ohash_find(&mtimes, ohash_qlookupi(&mtimes, file, &efile));
1.27 espie 265: }
266:
1.55 espie 267: /***
268: *** PathEntry handling
269: ***/
270:
1.27 espie 271: static void
1.50 espie 272: add_file(struct PathEntry *p, const char *file)
1.26 espie 273: {
1.46 espie 274: unsigned int slot;
275: const char *end = NULL;
276: char *n;
277: struct ohash *h = &p->files;
278:
279: slot = ohash_qlookupi(h, file, &end);
280: n = ohash_find(h, slot);
281: if (n == NULL) {
282: n = ohash_create_entry(&file_info, file, &end);
283: ohash_insert(h, slot, n);
284: }
1.26 espie 285: }
1.31 espie 286:
1.26 espie 287: static char *
1.53 espie 288: find_file_hashi(struct PathEntry *p, const char *file, const char *efile,
1.50 espie 289: uint32_t hv)
1.26 espie 290: {
1.46 espie 291: struct ohash *h = &p->files;
1.26 espie 292:
1.46 espie 293: return ohash_find(h, ohash_lookup_interval(h, file, efile, hv));
1.26 espie 294: }
295:
1.55 espie 296: static bool
297: read_directory(struct PathEntry *p)
298: {
299: DIR *d;
300: struct dirent *dp;
301:
302: if (DEBUG(DIR)) {
303: printf("Caching %s...", p->name);
304: fflush(stdout);
305: }
306:
307: if ((d = opendir(p->name)) == NULL)
308: return false;
309:
310: ohash_init(&p->files, 4, &file_info);
311:
312: while ((dp = readdir(d)) != NULL) {
313: if (dp->d_name[0] == '.' &&
314: (dp->d_name[1] == '\0' ||
315: (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
316: continue;
317: add_file(p, dp->d_name);
318: }
319: (void)closedir(d);
320: if (DEBUG(DIR))
321: printf("done\n");
322: return true;
323: }
324:
325: /* Read a directory, either from the disk, or from the cache. */
326: static struct PathEntry *
327: create_PathEntry(const char *name, const char *ename)
328: {
329: struct PathEntry *p;
330: unsigned int slot;
331:
332: slot = ohash_qlookupi(&knownDirectories, name, &ename);
333: p = ohash_find(&knownDirectories, slot);
334:
335: if (p == NULL) {
336: p = ohash_create_entry(&dir_info, name, &ename);
337: p->refCount = 0;
338: if (!read_directory(p)) {
339: free(p);
340: return NULL;
341: }
342: ohash_insert(&knownDirectories, slot, p);
343: }
344: p->refCount++;
345: return p;
1.56 espie 346: }
347:
348: char *
349: PathEntry_name(struct PathEntry *p)
350: {
351: return p->name;
1.55 espie 352: }
1.32 espie 353:
354: /* Side Effects: cache the current directory */
1.1 deraadt 355: void
1.41 espie 356: Dir_Init(void)
1.1 deraadt 357: {
1.46 espie 358: char *dotname = ".";
1.32 espie 359:
1.51 espie 360: Static_Lst_Init(defaultPath);
361: ohash_init(&knownDirectories, 4, &dir_info);
1.46 espie 362: ohash_init(&mtimes, 4, &stamp_info);
1.6 millert 363:
1.32 espie 364:
1.55 espie 365: dot = create_PathEntry(dotname, dotname+1);
1.1 deraadt 366:
1.46 espie 367: if (!dot)
368: Fatal("Can't access current directory");
1.1 deraadt 369: }
1.55 espie 370:
1.1 deraadt 371: /*-
372: *-----------------------------------------------------------------------
1.47 espie 373: * Dir_MatchFilesi --
1.50 espie 374: * Given a pattern and a PathEntry structure, see if any files
1.1 deraadt 375: * match the pattern and add their names to the 'expansions' list if
376: * any do. This is incomplete -- it doesn't take care of patterns like
377: * src / *src / *.c properly (just *.c on any of the directories), but it
378: * will do for now.
379: *-----------------------------------------------------------------------
380: */
1.47 espie 381: void
1.53 espie 382: Dir_MatchFilesi(const char *word, const char *eword, struct PathEntry *p,
1.50 espie 383: Lst expansions)
1.31 espie 384: {
1.46 espie 385: unsigned int search; /* Index into the directory's table */
386: const char *entry; /* Current entry in the table */
387:
388: for (entry = ohash_first(&p->files, &search); entry != NULL;
389: entry = ohash_next(&p->files, &search)) {
390: /* See if the file matches the given pattern. We follow the UNIX
391: * convention that dot files will only be found if the pattern
392: * begins with a dot (the hashing scheme doesn't hash . or ..,
393: * so they won't match `.*'. */
394: if (*word != '.' && *entry == '.')
395: continue;
396: if (Str_Matchi(entry, strchr(entry, '\0'), word, eword))
1.53 espie 397: Lst_AtEnd(expansions,
1.55 espie 398: p == dot ? estrdup(entry) :
1.46 espie 399: Str_concat(p->name, entry, '/'));
400: }
1.1 deraadt 401: }
1.32 espie 402:
1.1 deraadt 403: /*-
404: * Side Effects:
405: * If the file is found in a directory which is not on the path
406: * already (either 'name' is absolute or it is a relative path
407: * [ dir1/.../dirn/file ] which exists below one of the directories
408: * already on the search path), its directory is added to the end
409: * of the path on the assumption that there will be more files in
1.53 espie 410: * that directory later on.
1.1 deraadt 411: */
412: char *
1.53 espie 413: Dir_FindFileComplexi(const char *name, const char *ename, Lst path,
1.45 espie 414: bool checkCurdirFirst)
1.31 espie 415: {
1.50 espie 416: struct PathEntry *p; /* current path member */
1.46 espie 417: char *p1; /* pointer into p->name */
418: const char *p2; /* pointer into name */
419: LstNode ln; /* a list element */
420: char *file; /* the current filename to check */
421: char *temp; /* index into file */
1.54 espie 422: const char *basename;
1.46 espie 423: bool hasSlash;
424: struct stat stb;/* Buffer for stat, if necessary */
1.53 espie 425: struct file_stamp *entry;
1.46 espie 426: /* Entry for mtimes table */
427: uint32_t hv; /* hash value for last component in file name */
428: char *q; /* Str_dupi(name, ename) */
429:
430: /* Find the final component of the name and note whether name has a
431: * slash in it */
1.54 espie 432: basename = Str_rchri(name, ename, '/');
433: if (basename) {
1.46 espie 434: hasSlash = true;
1.54 espie 435: basename++;
1.46 espie 436: } else {
437: hasSlash = false;
1.54 espie 438: basename = name;
1.46 espie 439: }
440:
1.54 espie 441: hv = ohash_interval(basename, &ename);
1.6 millert 442:
1.26 espie 443: if (DEBUG(DIR))
1.46 espie 444: printf("Searching for %s...", name);
1.53 espie 445: /* Unless checkCurDirFirst is false, we always look for
446: * the file in the current directory before anywhere else
1.46 espie 447: * and we always return exactly what the caller specified. */
1.53 espie 448: if (checkCurdirFirst &&
1.54 espie 449: (!hasSlash || (basename - name == 2 && *name == '.')) &&
450: find_file_hashi(dot, basename, ename, hv) != NULL) {
1.46 espie 451: if (DEBUG(DIR))
452: printf("in '.'\n");
453: return Str_dupi(name, ename);
1.1 deraadt 454: }
1.6 millert 455:
1.53 espie 456: /* Then, we look through all the directories on path, seeking one
1.46 espie 457: * containing the final component of name and whose final
1.53 espie 458: * component(s) match name's initial component(s).
459: * If found, we concatenate the directory name and the
1.46 espie 460: * final component and return the resulting string. */
461: for (ln = Lst_First(path); ln != NULL; ln = Lst_Adv(ln)) {
1.68 ! espie 462: p = Lst_Datum(ln);
1.46 espie 463: if (DEBUG(DIR))
464: printf("%s...", p->name);
1.54 espie 465: if (find_file_hashi(p, basename, ename, hv) != NULL) {
1.46 espie 466: if (DEBUG(DIR))
467: printf("here...");
468: if (hasSlash) {
1.53 espie 469: /* If the name had a slash, its initial
470: * components and p's final components must
471: * match. This is false if a mismatch is
472: * encountered before all of the initial
473: * components have been checked (p2 > name at
474: * the end of the loop), or we matched only
475: * part of one of the components of p along
1.46 espie 476: * with all the rest of them (*p1 != '/'). */
477: p1 = p->name + strlen(p->name) - 1;
1.54 espie 478: p2 = basename - 2;
1.53 espie 479: while (p2 >= name && p1 >= p->name &&
1.46 espie 480: *p1 == *p2) {
481: p1--;
482: p2--;
483: }
1.53 espie 484: if (p2 >= name ||
1.46 espie 485: (p1 >= p->name && *p1 != '/')) {
486: if (DEBUG(DIR))
487: printf("component mismatch -- continuing...");
488: continue;
489: }
490: }
1.55 espie 491: file = Str_concati(p->name, strchr(p->name, '\0'), basename,
492: ename, '/');
1.46 espie 493: if (DEBUG(DIR))
494: printf("returning %s\n", file);
495: return file;
496: } else if (hasSlash) {
1.53 espie 497: /* If the file has a leading path component and that
498: * component exactly matches the entire name of the
499: * current search directory, we assume the file
1.46 espie 500: * doesn't exist and return NULL. */
1.53 espie 501: for (p1 = p->name, p2 = name; *p1 && *p1 == *p2;
1.46 espie 502: p1++, p2++)
503: continue;
1.54 espie 504: if (*p1 == '\0' && p2 == basename - 1) {
1.46 espie 505: if (DEBUG(DIR))
506: printf("has to be here but isn't -- returning NULL\n");
507: return NULL;
508: }
509: }
510: }
1.27 espie 511:
1.46 espie 512: /* We didn't find the file on any existing member of the path.
513: * If the name doesn't contain a slash, end of story.
1.53 espie 514: * If it does contain a slash, however, it could be in a subdirectory
515: * of one of the members of the search path. (eg., for path=/usr/include
516: * and name=sys/types.h, the above search fails to turn up types.h
1.46 espie 517: * in /usr/include, even though /usr/include/sys/types.h exists).
518: *
519: * We only perform this look-up for non-absolute file names.
520: *
521: * Whenever we score a hit, we assume there will be more matches from
1.53 espie 522: * that directory, and append all but the last component of the
1.46 espie 523: * resulting name onto the search path. */
524: if (!hasSlash) {
1.26 espie 525: if (DEBUG(DIR))
1.46 espie 526: printf("failed.\n");
527: return NULL;
528: }
1.6 millert 529:
1.46 espie 530: if (*name != '/') {
531: bool checkedDot = false;
1.6 millert 532:
1.26 espie 533: if (DEBUG(DIR))
1.46 espie 534: printf("failed. Trying subdirectories...");
535: for (ln = Lst_First(path); ln != NULL; ln = Lst_Adv(ln)) {
1.68 ! espie 536: p = Lst_Datum(ln);
1.46 espie 537: if (p != dot)
1.53 espie 538: file = Str_concati(p->name,
1.46 espie 539: strchr(p->name, '\0'), name, ename, '/');
540: else {
1.53 espie 541: /* Checking in dot -- DON'T put a leading
1.46 espie 542: * ./ on the thing. */
543: file = Str_dupi(name, ename);
544: checkedDot = true;
545: }
546: if (DEBUG(DIR))
547: printf("checking %s...", file);
548:
549: if (stat(file, &stb) == 0) {
1.62 espie 550: struct timespec mtime;
1.46 espie 551:
552: ts_set_from_stat(stb, mtime);
553: if (DEBUG(DIR))
554: printf("got it.\n");
555:
1.53 espie 556: /* We've found another directory to search.
557: * We know there is a slash in 'file'. We
558: * call Dir_AddDiri to add the new directory
559: * onto the existing search path. Once that's
560: * done, we return the file name, knowing that
561: * should a file in this directory ever be
562: * referenced again in such a manner, we will
563: * find it without having to do numerous
1.46 espie 564: * access calls. */
565: temp = strrchr(file, '/');
566: Dir_AddDiri(path, file, temp);
567:
1.53 espie 568: /* Save the modification time so if it's
1.46 espie 569: * needed, we don't have to fetch it again. */
570: if (DEBUG(DIR))
1.53 espie 571: printf("Caching %s for %s\n",
1.63 espie 572: time_to_string(&mtime), file);
1.46 espie 573: record_stamp(file, mtime);
574: return file;
575: } else
576: free(file);
577: }
1.6 millert 578:
1.46 espie 579: if (DEBUG(DIR))
580: printf("failed. ");
1.31 espie 581:
1.46 espie 582: if (checkedDot) {
1.53 espie 583: /* Already checked by the given name, since . was in
1.46 espie 584: * the path, so no point in proceeding... */
585: if (DEBUG(DIR))
586: printf("Checked . already, returning NULL\n");
587: return NULL;
588: }
1.1 deraadt 589: }
1.6 millert 590:
1.46 espie 591: /* Didn't find it that way, either. Last resort: look for the file
592: * in the global mtime cache, then on the disk.
593: * If this doesn't succeed, we finally return a NULL pointer.
594: *
595: * We cannot add this directory onto the search path because
596: * of this amusing case:
597: * $(INSTALLDIR)/$(FILE): $(FILE)
598: *
599: * $(FILE) exists in $(INSTALLDIR) but not in the current one.
600: * When searching for $(FILE), we will find it in $(INSTALLDIR)
601: * b/c we added it here. This is not good... */
602: q = Str_dupi(name, ename);
603: if (DEBUG(DIR))
604: printf("Looking for \"%s\"...", q);
1.6 millert 605:
1.46 espie 606: entry = find_stampi(name, ename);
607: if (entry != NULL) {
608: if (DEBUG(DIR))
609: printf("got it (in mtime cache)\n");
610: return q;
611: } else if (stat(q, &stb) == 0) {
1.62 espie 612: struct timespec mtime;
1.27 espie 613:
1.46 espie 614: ts_set_from_stat(stb, mtime);
615: if (DEBUG(DIR))
1.63 espie 616: printf("Caching %s for %s\n", time_to_string(&mtime),
617: q);
1.46 espie 618: record_stamp(q, mtime);
619: return q;
620: } else {
621: if (DEBUG(DIR))
622: printf("failed. Returning NULL\n");
623: free(q);
624: return NULL;
625: }
1.1 deraadt 626: }
627:
628: void
1.41 espie 629: Dir_AddDiri(Lst path, const char *name, const char *ename)
1.1 deraadt 630: {
1.50 espie 631: struct PathEntry *p;
1.6 millert 632:
1.55 espie 633: p = create_PathEntry(name, ename);
1.46 espie 634: if (p == NULL)
635: return;
1.55 espie 636: if (p->refCount == 1)
1.46 espie 637: Lst_AtEnd(path, p);
638: else if (!Lst_AddNew(path, p))
639: return;
1.1 deraadt 640: }
641:
1.19 espie 642: void *
1.41 espie 643: Dir_CopyDir(void *p)
1.1 deraadt 644: {
1.66 espie 645: struct PathEntry *q = p;
646: q->refCount++;
1.46 espie 647: return p;
1.1 deraadt 648: }
649:
650: void
1.41 espie 651: Dir_Destroy(void *pp)
1.1 deraadt 652: {
1.66 espie 653: struct PathEntry *p = pp;
1.1 deraadt 654:
1.46 espie 655: if (--p->refCount == 0) {
1.53 espie 656: ohash_remove(&knownDirectories,
1.51 espie 657: ohash_qlookup(&knownDirectories, p->name));
1.46 espie 658: free_hash(&p->files);
659: free(p);
660: }
1.1 deraadt 661: }
662:
663: /*-
664: *-----------------------------------------------------------------------
665: * Dir_Concat --
666: * Concatenate two paths, adding the second to the end of the first.
667: * Makes sure to avoid duplicates.
668: *
669: * Side Effects:
670: * Reference counts for added dirs are upped.
671: *-----------------------------------------------------------------------
672: */
673: void
1.41 espie 674: Dir_Concat(Lst path1, Lst path2)
1.1 deraadt 675: {
1.46 espie 676: LstNode ln;
1.55 espie 677: struct PathEntry *p;
1.1 deraadt 678:
1.46 espie 679: for (ln = Lst_First(path2); ln != NULL; ln = Lst_Adv(ln)) {
1.68 ! espie 680: p = Lst_Datum(ln);
1.46 espie 681: if (Lst_AddNew(path1, p))
682: p->refCount++;
683: }
1.1 deraadt 684: }
685:
1.31 espie 686: static void
1.41 espie 687: DirPrintDir(void *p)
1.6 millert 688: {
1.67 espie 689: const struct PathEntry *q = p;
1.66 espie 690: printf("%s ", q->name);
1.1 deraadt 691: }
692:
693: void
1.41 espie 694: Dir_PrintPath(Lst path)
1.1 deraadt 695: {
1.46 espie 696: Lst_Every(path, DirPrintDir);
1.29 espie 697: }
698:
1.62 espie 699: struct timespec
1.41 espie 700: Dir_MTime(GNode *gn)
1.32 espie 701: {
1.46 espie 702: char *fullName;
703: struct stat stb;
704: struct file_stamp *entry;
705: unsigned int slot;
1.62 espie 706: struct timespec mtime;
1.46 espie 707:
1.57 espie 708: if (gn->type & OP_PHONY)
709: return gn->mtime;
710:
1.46 espie 711: if (gn->type & OP_ARCHV)
712: return Arch_MTime(gn);
713:
714: if (gn->path == NULL) {
1.51 espie 715: fullName = Dir_FindFile(gn->name, defaultPath);
1.46 espie 716: if (fullName == NULL)
717: fullName = estrdup(gn->name);
1.32 espie 718: } else
1.46 espie 719: fullName = gn->path;
720:
721: slot = ohash_qlookup(&mtimes, fullName);
722: entry = ohash_find(&mtimes, slot);
723: if (entry != NULL) {
724: /* Only do this once -- the second time folks are checking to
1.53 espie 725: * see if the file was actually updated, so we need to
1.46 espie 726: * actually go to the file system. */
727: if (DEBUG(DIR))
728: printf("Using cached time %s for %s\n",
1.63 espie 729: time_to_string(&entry->mtime), fullName);
1.46 espie 730: mtime = entry->mtime;
731: free(entry);
732: ohash_remove(&mtimes, slot);
733: } else if (stat(fullName, &stb) == 0)
734: ts_set_from_stat(stb, mtime);
735: else {
736: if (gn->type & OP_MEMBER) {
737: if (fullName != gn->path)
738: free(fullName);
739: return Arch_MemMTime(gn);
740: } else
741: ts_set_out_of_date(mtime);
742: }
743: if (fullName && gn->path == NULL)
744: gn->path = fullName;
1.29 espie 745:
1.46 espie 746: gn->mtime = mtime;
747: return gn->mtime;
1.1 deraadt 748: }
1.32 espie 749: