xref: /openbsd/usr.bin/make/dir.c (revision 898184e3)
1 /*	$OpenBSD: dir.c,v 1.61 2012/12/07 07:15:31 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 /*-
373  *-----------------------------------------------------------------------
374  * Dir_MatchFilesi --
375  *	Given a pattern and a PathEntry structure, see if any files
376  *	match the pattern and add their names to the 'expansions' list if
377  *	any do. This is incomplete -- it doesn't take care of patterns like
378  *	src / *src / *.c properly (just *.c on any of the directories), but it
379  *	will do for now.
380  *-----------------------------------------------------------------------
381  */
382 void
383 Dir_MatchFilesi(const char *word, const char *eword, struct PathEntry *p,
384     Lst expansions)
385 {
386 	unsigned int search; 	/* Index into the directory's table */
387 	const char *entry; 	/* Current entry in the table */
388 
389 	for (entry = ohash_first(&p->files, &search); entry != NULL;
390 	     entry = ohash_next(&p->files, &search)) {
391 		/* See if the file matches the given pattern. We follow the UNIX
392 		 * convention that dot files will only be found if the pattern
393 		 * begins with a dot (the hashing scheme doesn't hash . or ..,
394 		 * so they won't match `.*'.  */
395 		if (*word != '.' && *entry == '.')
396 			continue;
397 		if (Str_Matchi(entry, strchr(entry, '\0'), word, eword))
398 			Lst_AtEnd(expansions,
399 			    p == dot  ? estrdup(entry) :
400 			    Str_concat(p->name, entry, '/'));
401 	}
402 }
403 
404 /*-
405  * Side Effects:
406  *	If the file is found in a directory which is not on the path
407  *	already (either 'name' is absolute or it is a relative path
408  *	[ dir1/.../dirn/file ] which exists below one of the directories
409  *	already on the search path), its directory is added to the end
410  *	of the path on the assumption that there will be more files in
411  *	that directory later on.
412  */
413 char *
414 Dir_FindFileComplexi(const char *name, const char *ename, Lst path,
415     bool checkCurdirFirst)
416 {
417 	struct PathEntry *p;	/* current path member */
418 	char *p1;	/* pointer into p->name */
419 	const char *p2;	/* pointer into name */
420 	LstNode ln;	/* a list element */
421 	char *file;	/* the current filename to check */
422 	char *temp;	/* index into file */
423 	const char *basename;
424 	bool hasSlash;
425 	struct stat stb;/* Buffer for stat, if necessary */
426 	struct file_stamp *entry;
427 			/* Entry for mtimes table */
428 	uint32_t hv;	/* hash value for last component in file name */
429 	char *q;	/* Str_dupi(name, ename) */
430 
431 	/* Find the final component of the name and note whether name has a
432 	 * slash in it */
433 	basename = Str_rchri(name, ename, '/');
434 	if (basename) {
435 		hasSlash = true;
436 		basename++;
437 	} else {
438 		hasSlash = false;
439 		basename = name;
440 	}
441 
442 	hv = ohash_interval(basename, &ename);
443 
444 	if (DEBUG(DIR))
445 		printf("Searching for %s...", name);
446 	/* Unless checkCurDirFirst is false, we always look for
447 	 * the file in the current directory before anywhere else
448 	 * and we always return exactly what the caller specified. */
449 	if (checkCurdirFirst &&
450 	    (!hasSlash || (basename - name == 2 && *name == '.')) &&
451 	    find_file_hashi(dot, basename, ename, hv) != NULL) {
452 		if (DEBUG(DIR))
453 			printf("in '.'\n");
454 		return Str_dupi(name, ename);
455 	}
456 
457 	/* Then, we look through all the directories on path, seeking one
458 	 * containing the final component of name and whose final
459 	 * component(s) match name's initial component(s).
460 	 * If found, we concatenate the directory name and the
461 	 * final component and return the resulting string.  */
462 	for (ln = Lst_First(path); ln != NULL; ln = Lst_Adv(ln)) {
463 		p = (struct PathEntry *)Lst_Datum(ln);
464 		if (DEBUG(DIR))
465 			printf("%s...", p->name);
466 		if (find_file_hashi(p, basename, ename, hv) != NULL) {
467 			if (DEBUG(DIR))
468 				printf("here...");
469 			if (hasSlash) {
470 				/* If the name had a slash, its initial
471 				 * components and p's final components must
472 				 * match. This is false if a mismatch is
473 				 * encountered before all of the initial
474 				 * components have been checked (p2 > name at
475 				 * the end of the loop), or we matched only
476 				 * part of one of the components of p along
477 				 * with all the rest of them (*p1 != '/').  */
478 				p1 = p->name + strlen(p->name) - 1;
479 				p2 = basename - 2;
480 				while (p2 >= name && p1 >= p->name &&
481 				    *p1 == *p2) {
482 					p1--;
483 					p2--;
484 				}
485 				if (p2 >= name ||
486 				    (p1 >= p->name && *p1 != '/')) {
487 					if (DEBUG(DIR))
488 						printf("component mismatch -- continuing...");
489 					continue;
490 				}
491 			}
492 			file = Str_concati(p->name, strchr(p->name, '\0'), basename,
493 			    ename, '/');
494 			if (DEBUG(DIR))
495 				printf("returning %s\n", file);
496 			return file;
497 		} else if (hasSlash) {
498 			/* If the file has a leading path component and that
499 			 * component exactly matches the entire name of the
500 			 * current search directory, we assume the file
501 			 * doesn't exist and return NULL.  */
502 			for (p1 = p->name, p2 = name; *p1 && *p1 == *p2;
503 			    p1++, p2++)
504 				continue;
505 			if (*p1 == '\0' && p2 == basename - 1) {
506 				if (DEBUG(DIR))
507 					printf("has to be here but isn't -- returning NULL\n");
508 				return NULL;
509 			}
510 		}
511 	}
512 
513 	/* We didn't find the file on any existing member of the path.
514 	 * If the name doesn't contain a slash, end of story.
515 	 * If it does contain a slash, however, it could be in a subdirectory
516 	 * of one of the members of the search path. (eg., for path=/usr/include
517 	 * and name=sys/types.h, the above search fails to turn up types.h
518 	 * in /usr/include, even though /usr/include/sys/types.h exists).
519 	 *
520 	 * We only perform this look-up for non-absolute file names.
521 	 *
522 	 * Whenever we score a hit, we assume there will be more matches from
523 	 * that directory, and append all but the last component of the
524 	 * resulting name onto the search path. */
525 	if (!hasSlash) {
526 		if (DEBUG(DIR))
527 			printf("failed.\n");
528 		return NULL;
529 	}
530 
531 	if (*name != '/') {
532 		bool checkedDot = false;
533 
534 		if (DEBUG(DIR))
535 			printf("failed. Trying subdirectories...");
536 		for (ln = Lst_First(path); ln != NULL; ln = Lst_Adv(ln)) {
537 			p = (struct PathEntry *)Lst_Datum(ln);
538 			if (p != dot)
539 				file = Str_concati(p->name,
540 				    strchr(p->name, '\0'), name, ename, '/');
541 			else {
542 				/* Checking in dot -- DON'T put a leading
543 				* ./ on the thing.  */
544 				file = Str_dupi(name, ename);
545 				checkedDot = true;
546 			}
547 			if (DEBUG(DIR))
548 				printf("checking %s...", file);
549 
550 			if (stat(file, &stb) == 0) {
551 				TIMESTAMP mtime;
552 
553 				ts_set_from_stat(stb, mtime);
554 				if (DEBUG(DIR))
555 					printf("got it.\n");
556 
557 				/* We've found another directory to search.
558 				 * We know there is a slash in 'file'. We
559 				 * call Dir_AddDiri to add the new directory
560 				 * onto the existing search path. Once that's
561 				 * done, we return the file name, knowing that
562 				 * should a file in this directory ever be
563 				 * referenced again in such a manner, we will
564 				 * find it without having to do numerous
565 				 * access calls.  */
566 				temp = strrchr(file, '/');
567 				Dir_AddDiri(path, file, temp);
568 
569 				/* Save the modification time so if it's
570 				* needed, we don't have to fetch it again.  */
571 				if (DEBUG(DIR))
572 					printf("Caching %s for %s\n",
573 					    time_to_string(mtime), file);
574 				record_stamp(file, mtime);
575 				return file;
576 			} else
577 				free(file);
578 		}
579 
580 		if (DEBUG(DIR))
581 			printf("failed. ");
582 
583 		if (checkedDot) {
584 			/* Already checked by the given name, since . was in
585 			 * the path, so no point in proceeding...  */
586 			if (DEBUG(DIR))
587 				printf("Checked . already, returning NULL\n");
588 			return NULL;
589 		}
590 	}
591 
592 	/* Didn't find it that way, either. Last resort: look for the file
593 	 * in the global mtime cache, then on the disk.
594 	 * If this doesn't succeed, we finally return a NULL pointer.
595 	 *
596 	 * We cannot add this directory onto the search path because
597 	 * of this amusing case:
598 	 * $(INSTALLDIR)/$(FILE): $(FILE)
599 	 *
600 	 * $(FILE) exists in $(INSTALLDIR) but not in the current one.
601 	 * When searching for $(FILE), we will find it in $(INSTALLDIR)
602 	 * b/c we added it here. This is not good...  */
603 	q = Str_dupi(name, ename);
604 	if (DEBUG(DIR))
605 		printf("Looking for \"%s\"...", q);
606 
607 	entry = find_stampi(name, ename);
608 	if (entry != NULL) {
609 		if (DEBUG(DIR))
610 			printf("got it (in mtime cache)\n");
611 		return q;
612 	} else if (stat(q, &stb) == 0) {
613 		TIMESTAMP mtime;
614 
615 		ts_set_from_stat(stb, mtime);
616 		if (DEBUG(DIR))
617 			printf("Caching %s for %s\n", time_to_string(mtime), q);
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 	}
626 }
627 
628 void
629 Dir_AddDiri(Lst path, const char *name, const char *ename)
630 {
631 	struct PathEntry	*p;
632 
633 	p = create_PathEntry(name, ename);
634 	if (p == NULL)
635 		return;
636 	if (p->refCount == 1)
637 		Lst_AtEnd(path, p);
638 	else if (!Lst_AddNew(path, p))
639 		return;
640 }
641 
642 void *
643 Dir_CopyDir(void *p)
644 {
645 	((struct PathEntry *)p)->refCount++;
646 	return p;
647 }
648 
649 void
650 Dir_Destroy(void *pp)
651 {
652 	struct PathEntry *p = (struct PathEntry *)pp;
653 
654 	if (--p->refCount == 0) {
655 		ohash_remove(&knownDirectories,
656 		    ohash_qlookup(&knownDirectories, p->name));
657 		free_hash(&p->files);
658 		free(p);
659 	}
660 }
661 
662 /*-
663  *-----------------------------------------------------------------------
664  * Dir_Concat --
665  *	Concatenate two paths, adding the second to the end of the first.
666  *	Makes sure to avoid duplicates.
667  *
668  * Side Effects:
669  *	Reference counts for added dirs are upped.
670  *-----------------------------------------------------------------------
671  */
672 void
673 Dir_Concat(Lst path1, Lst path2)
674 {
675 	LstNode	ln;
676 	struct PathEntry *p;
677 
678 	for (ln = Lst_First(path2); ln != NULL; ln = Lst_Adv(ln)) {
679 		p = (struct PathEntry *)Lst_Datum(ln);
680 		if (Lst_AddNew(path1, p))
681 			p->refCount++;
682 	}
683 }
684 
685 static void
686 DirPrintDir(void *p)
687 {
688 	printf("%s ", ((struct PathEntry *)p)->name);
689 }
690 
691 void
692 Dir_PrintPath(Lst path)
693 {
694 	Lst_Every(path, DirPrintDir);
695 }
696 
697 TIMESTAMP
698 Dir_MTime(GNode *gn)
699 {
700 	char *fullName;
701 	struct stat stb;
702 	struct file_stamp *entry;
703 	unsigned int slot;
704 	TIMESTAMP	  mtime;
705 
706 	if (gn->type & OP_PHONY)
707 		return gn->mtime;
708 
709 	if (gn->type & OP_ARCHV)
710 		return Arch_MTime(gn);
711 
712 	if (gn->path == NULL) {
713 		fullName = Dir_FindFile(gn->name, defaultPath);
714 		if (fullName == NULL)
715 			fullName = estrdup(gn->name);
716 	} else
717 		fullName = gn->path;
718 
719 	slot = ohash_qlookup(&mtimes, fullName);
720 	entry = ohash_find(&mtimes, slot);
721 	if (entry != NULL) {
722 		/* Only do this once -- the second time folks are checking to
723 		 * see if the file was actually updated, so we need to
724 		 * actually go to the file system.	*/
725 		if (DEBUG(DIR))
726 			printf("Using cached time %s for %s\n",
727 			    time_to_string(entry->mtime), fullName);
728 		mtime = entry->mtime;
729 		free(entry);
730 		ohash_remove(&mtimes, slot);
731 	} else if (stat(fullName, &stb) == 0)
732 		ts_set_from_stat(stb, mtime);
733 	else {
734 		if (gn->type & OP_MEMBER) {
735 			if (fullName != gn->path)
736 				free(fullName);
737 			return Arch_MemMTime(gn);
738 		} else
739 			ts_set_out_of_date(mtime);
740 	}
741 	if (fullName && gn->path == NULL)
742 		gn->path = fullName;
743 
744 	gn->mtime = mtime;
745 	return gn->mtime;
746 }
747 
748