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