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