dir.c revision 1.156 1 /* $NetBSD: dir.c,v 1.156 2020/10/03 21:52:50 rillig Exp $ */
2
3 /*
4 * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Adam de Boor.
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 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 /*
36 * Copyright (c) 1988, 1989 by Adam de Boor
37 * Copyright (c) 1989 by Berkeley Softworks
38 * All rights reserved.
39 *
40 * This code is derived from software contributed to Berkeley by
41 * Adam de Boor.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement:
53 * This product includes software developed by the University of
54 * California, Berkeley and its contributors.
55 * 4. Neither the name of the University nor the names of its contributors
56 * may be used to endorse or promote products derived from this software
57 * without specific prior written permission.
58 *
59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69 * SUCH DAMAGE.
70 */
71
72 /*-
73 * dir.c --
74 * Directory searching using wildcards and/or normal names...
75 * Used both for source wildcarding in the Makefile and for finding
76 * implicit sources.
77 *
78 * The interface for this module is:
79 * Dir_Init Initialize the module.
80 *
81 * Dir_InitCur Set the cur CachedDir.
82 *
83 * Dir_InitDot Set the dot CachedDir.
84 *
85 * Dir_End Cleanup the module.
86 *
87 * Dir_SetPATH Set ${.PATH} to reflect state of dirSearchPath.
88 *
89 * Dir_HasWildcards
90 * Returns TRUE if the name given it needs to
91 * be wildcard-expanded.
92 *
93 * Dir_Expand Given a pattern and a path, return a Lst of names
94 * which match the pattern on the search path.
95 *
96 * Dir_FindFile Searches for a file on a given search path.
97 * If it exists, the entire path is returned.
98 * Otherwise NULL is returned.
99 *
100 * Dir_FindHereOrAbove
101 * Search for a path in the current directory and
102 * then all the directories above it in turn until
103 * the path is found or we reach the root ("/").
104 *
105 * Dir_MTime Return the modification time of a node. The file
106 * is searched for along the default search path.
107 * The path and mtime fields of the node are filled in.
108 *
109 * Dir_AddDir Add a directory to a search path.
110 *
111 * Dir_MakeFlags Given a search path and a command flag, create
112 * a string with each of the directories in the path
113 * preceded by the command flag and all of them
114 * separated by a space.
115 *
116 * Dir_Destroy Destroy an element of a search path. Frees up all
117 * things that can be freed for the element as long
118 * as the element is no longer referenced by any other
119 * search path.
120 *
121 * Dir_ClearPath Resets a search path to the empty list.
122 *
123 * For debugging:
124 * Dir_PrintDirectories Print stats about the directory cache.
125 */
126
127 #include <sys/types.h>
128 #include <sys/stat.h>
129
130 #include <dirent.h>
131 #include <errno.h>
132
133 #include "make.h"
134 #include "dir.h"
135 #include "job.h"
136
137 /* "@(#)dir.c 8.2 (Berkeley) 1/2/94" */
138 MAKE_RCSID("$NetBSD: dir.c,v 1.156 2020/10/03 21:52:50 rillig Exp $");
139
140 #define DIR_DEBUG0(text) DEBUG0(DIR, text)
141 #define DIR_DEBUG1(fmt, arg1) DEBUG1(DIR, fmt, arg1)
142 #define DIR_DEBUG2(fmt, arg1, arg2) DEBUG2(DIR, fmt, arg1, arg2)
143
144 /*
145 * A search path consists of a list of CachedDir structures. A CachedDir
146 * has in it the name of the directory and a hash table of all the files
147 * in the directory. This is used to cut down on the number of system
148 * calls necessary to find implicit dependents and their like. Since
149 * these searches are made before any actions are taken, we need not
150 * worry about the directory changing due to creation commands. If this
151 * hampers the style of some makefiles, they must be changed.
152 *
153 * A list of all previously-read directories is kept in the
154 * openDirectories Lst. This list is checked first before a directory
155 * is opened.
156 *
157 * The need for the caching of whole directories is brought about by
158 * the multi-level transformation code in suff.c, which tends to search
159 * for far more files than regular make does. In the initial
160 * implementation, the amount of time spent performing "stat" calls was
161 * truly astronomical. The problem with hashing at the start is,
162 * of course, that pmake doesn't then detect changes to these directories
163 * during the course of the make. Three possibilities suggest themselves:
164 *
165 * 1) just use stat to test for a file's existence. As mentioned
166 * above, this is very inefficient due to the number of checks
167 * engendered by the multi-level transformation code.
168 * 2) use readdir() and company to search the directories, keeping
169 * them open between checks. I have tried this and while it
170 * didn't slow down the process too much, it could severely
171 * affect the amount of parallelism available as each directory
172 * open would take another file descriptor out of play for
173 * handling I/O for another job. Given that it is only recently
174 * that UNIX OS's have taken to allowing more than 20 or 32
175 * file descriptors for a process, this doesn't seem acceptable
176 * to me.
177 * 3) record the mtime of the directory in the CachedDir structure and
178 * verify the directory hasn't changed since the contents were
179 * hashed. This will catch the creation or deletion of files,
180 * but not the updating of files. However, since it is the
181 * creation and deletion that is the problem, this could be
182 * a good thing to do. Unfortunately, if the directory (say ".")
183 * were fairly large and changed fairly frequently, the constant
184 * rehashing could seriously degrade performance. It might be
185 * good in such cases to keep track of the number of rehashes
186 * and if the number goes over a (small) limit, resort to using
187 * stat in its place.
188 *
189 * An additional thing to consider is that pmake is used primarily
190 * to create C programs and until recently pcc-based compilers refused
191 * to allow you to specify where the resulting object file should be
192 * placed. This forced all objects to be created in the current
193 * directory. This isn't meant as a full excuse, just an explanation of
194 * some of the reasons for the caching used here.
195 *
196 * One more note: the location of a target's file is only performed
197 * on the downward traversal of the graph and then only for terminal
198 * nodes in the graph. This could be construed as wrong in some cases,
199 * but prevents inadvertent modification of files when the "installed"
200 * directory for a file is provided in the search path.
201 *
202 * Another data structure maintained by this module is an mtime
203 * cache used when the searching of cached directories fails to find
204 * a file. In the past, Dir_FindFile would simply perform an access()
205 * call in such a case to determine if the file could be found using
206 * just the name given. When this hit, however, all that was gained
207 * was the knowledge that the file existed. Given that an access() is
208 * essentially a stat() without the copyout() call, and that the same
209 * filesystem overhead would have to be incurred in Dir_MTime, it made
210 * sense to replace the access() with a stat() and record the mtime
211 * in a cache for when Dir_MTime was actually called.
212 */
213
214 typedef List CachedDirList;
215 typedef ListNode CachedDirListNode;
216
217 typedef ListNode SearchPathNode;
218
219 SearchPath *dirSearchPath; /* main search path */
220
221 /* A list of cached directories, with fast lookup by directory name. */
222 typedef struct OpenDirs {
223 CachedDirList *list;
224 Hash_Table /* of CachedDirListNode */ table;
225 } OpenDirs;
226
227 static void
228 OpenDirs_Init(OpenDirs *odirs)
229 {
230 odirs->list = Lst_Init();
231 Hash_InitTable(&odirs->table);
232 }
233
234 static void MAKE_ATTR_UNUSED
235 OpenDirs_Done(OpenDirs *odirs)
236 {
237 Dir_ClearPath(odirs->list);
238 Lst_Free(odirs->list);
239 Hash_DeleteTable(&odirs->table);
240 }
241
242 static CachedDir *
243 OpenDirs_Find(OpenDirs *odirs, const char *name)
244 {
245 CachedDirListNode *ln = Hash_FindValue(&odirs->table, name);
246 return ln != NULL ? ln->datum : NULL;
247 }
248
249 static void
250 OpenDirs_Add(OpenDirs *odirs, CachedDir *cdir)
251 {
252 Hash_Entry *he = Hash_FindEntry(&odirs->table, cdir->name);
253 if (he != NULL)
254 return;
255 he = Hash_CreateEntry(&odirs->table, cdir->name, NULL);
256 Lst_Append(odirs->list, cdir);
257 Hash_SetValue(he, odirs->list->last);
258 }
259
260 static void
261 OpenDirs_Remove(OpenDirs *odirs, const char *name)
262 {
263 Hash_Entry *he = Hash_FindEntry(&odirs->table, name);
264 CachedDirListNode *ln;
265 if (he == NULL)
266 return;
267 ln = Hash_GetValue(he);
268 Hash_DeleteEntry(&odirs->table, he);
269 Lst_Remove(odirs->list, ln);
270 }
271
272 static OpenDirs openDirs; /* the list of all open directories */
273
274 /*
275 * Variables for gathering statistics on the efficiency of the hashing
276 * mechanism.
277 */
278 static int hits; /* Found in directory cache */
279 static int misses; /* Sad, but not evil misses */
280 static int nearmisses; /* Found under search path */
281 static int bigmisses; /* Sought by itself */
282
283 static CachedDir *dot; /* contents of current directory */
284 static CachedDir *cur; /* contents of current directory, if not dot */
285 static CachedDir *dotLast; /* a fake path entry indicating we need to
286 * look for . last */
287
288 /* Results of doing a last-resort stat in Dir_FindFile -- if we have to go to
289 * the system to find the file, we might as well have its mtime on record.
290 *
291 * XXX: If this is done way early, there's a chance other rules will have
292 * already updated the file, in which case we'll update it again. Generally,
293 * there won't be two rules to update a single file, so this should be ok,
294 * but... */
295 static Hash_Table mtimes;
296
297 static Hash_Table lmtimes; /* same as mtimes but for lstat */
298
299 /*
300 * We use stat(2) a lot, cache the results.
301 * mtime and mode are all we care about.
302 */
303 struct cache_st {
304 time_t lmtime; /* lstat */
305 time_t mtime; /* stat */
306 mode_t mode;
307 };
308
309 /* minimize changes below */
310 typedef enum {
311 CST_LSTAT = 0x01, /* call lstat(2) instead of stat(2) */
312 CST_UPDATE = 0x02 /* ignore existing cached entry */
313 } CachedStatsFlags;
314
315 /* Returns 0 and the result of stat(2) or lstat(2) in *mst, or -1 on error. */
316 static int
317 cached_stats(Hash_Table *htp, const char *pathname, struct make_stat *mst,
318 CachedStatsFlags flags)
319 {
320 Hash_Entry *entry;
321 struct stat sys_st;
322 struct cache_st *cst;
323 int rc;
324
325 if (!pathname || !pathname[0])
326 return -1;
327
328 entry = Hash_FindEntry(htp, pathname);
329
330 if (entry && !(flags & CST_UPDATE)) {
331 cst = Hash_GetValue(entry);
332
333 mst->mst_mode = cst->mode;
334 mst->mst_mtime = (flags & CST_LSTAT) ? cst->lmtime : cst->mtime;
335 if (mst->mst_mtime) {
336 DIR_DEBUG2("Using cached time %s for %s\n",
337 Targ_FmtTime(mst->mst_mtime), pathname);
338 return 0;
339 }
340 }
341
342 rc = (flags & CST_LSTAT)
343 ? lstat(pathname, &sys_st)
344 : stat(pathname, &sys_st);
345 if (rc == -1)
346 return -1;
347
348 if (sys_st.st_mtime == 0)
349 sys_st.st_mtime = 1; /* avoid confusion with missing file */
350
351 mst->mst_mode = sys_st.st_mode;
352 mst->mst_mtime = sys_st.st_mtime;
353
354 if (entry == NULL)
355 entry = Hash_CreateEntry(htp, pathname, NULL);
356 if (Hash_GetValue(entry) == NULL) {
357 Hash_SetValue(entry, bmake_malloc(sizeof(*cst)));
358 memset(Hash_GetValue(entry), 0, sizeof(*cst));
359 }
360 cst = Hash_GetValue(entry);
361 if (flags & CST_LSTAT) {
362 cst->lmtime = sys_st.st_mtime;
363 } else {
364 cst->mtime = sys_st.st_mtime;
365 }
366 cst->mode = sys_st.st_mode;
367 DIR_DEBUG2(" Caching %s for %s\n",
368 Targ_FmtTime(sys_st.st_mtime), pathname);
369
370 return 0;
371 }
372
373 int
374 cached_stat(const char *pathname, struct make_stat *st)
375 {
376 return cached_stats(&mtimes, pathname, st, 0);
377 }
378
379 int
380 cached_lstat(const char *pathname, struct make_stat *st)
381 {
382 return cached_stats(&lmtimes, pathname, st, CST_LSTAT);
383 }
384
385 /* Initialize things for this module. */
386 void
387 Dir_Init(void)
388 {
389 dirSearchPath = Lst_Init();
390 OpenDirs_Init(&openDirs);
391 Hash_InitTable(&mtimes);
392 Hash_InitTable(&lmtimes);
393 }
394
395 void
396 Dir_InitDir(const char *cdname)
397 {
398 Dir_InitCur(cdname);
399
400 dotLast = bmake_malloc(sizeof(CachedDir));
401 dotLast->refCount = 1;
402 dotLast->hits = 0;
403 dotLast->name = bmake_strdup(".DOTLAST");
404 Hash_InitTable(&dotLast->files);
405 }
406
407 /*
408 * Called by Dir_InitDir and whenever .CURDIR is assigned to.
409 */
410 void
411 Dir_InitCur(const char *cdname)
412 {
413 CachedDir *dir;
414
415 if (cdname != NULL) {
416 /*
417 * Our build directory is not the same as our source directory.
418 * Keep this one around too.
419 */
420 if ((dir = Dir_AddDir(NULL, cdname))) {
421 dir->refCount++;
422 if (cur && cur != dir) {
423 /*
424 * We've been here before, cleanup.
425 */
426 cur->refCount--;
427 Dir_Destroy(cur);
428 }
429 cur = dir;
430 }
431 }
432 }
433
434 /* (Re)initialize "dot" (current/object directory) path hash.
435 * Some directories may be opened. */
436 void
437 Dir_InitDot(void)
438 {
439 if (dot != NULL) {
440 /* Remove old entry from openDirs, but do not destroy. */
441 OpenDirs_Remove(&openDirs, dot->name);
442 }
443
444 dot = Dir_AddDir(NULL, ".");
445
446 if (dot == NULL) {
447 Error("Cannot open `.' (%s)", strerror(errno));
448 exit(1);
449 }
450
451 /*
452 * We always need to have dot around, so we increment its reference count
453 * to make sure it's not destroyed.
454 */
455 dot->refCount++;
456 Dir_SetPATH(); /* initialize */
457 }
458
459 /* Clean up things for this module. */
460 void
461 Dir_End(void)
462 {
463 #ifdef CLEANUP
464 if (cur) {
465 cur->refCount--;
466 Dir_Destroy(cur);
467 }
468 dot->refCount--;
469 dotLast->refCount--;
470 Dir_Destroy(dotLast);
471 Dir_Destroy(dot);
472 Dir_ClearPath(dirSearchPath);
473 Lst_Free(dirSearchPath);
474 OpenDirs_Done(&openDirs);
475 Hash_DeleteTable(&mtimes);
476 #endif
477 }
478
479 /*
480 * We want ${.PATH} to indicate the order in which we will actually
481 * search, so we rebuild it after any .PATH: target.
482 * This is the simplest way to deal with the effect of .DOTLAST.
483 */
484 void
485 Dir_SetPATH(void)
486 {
487 CachedDirListNode *ln;
488 Boolean hasLastDot = FALSE; /* true if we should search dot last */
489
490 Var_Delete(".PATH", VAR_GLOBAL);
491
492 Lst_Open(dirSearchPath);
493 if ((ln = Lst_First(dirSearchPath)) != NULL) {
494 CachedDir *dir = LstNode_Datum(ln);
495 if (dir == dotLast) {
496 hasLastDot = TRUE;
497 Var_Append(".PATH", dotLast->name, VAR_GLOBAL);
498 }
499 }
500
501 if (!hasLastDot) {
502 if (dot)
503 Var_Append(".PATH", dot->name, VAR_GLOBAL);
504 if (cur)
505 Var_Append(".PATH", cur->name, VAR_GLOBAL);
506 }
507
508 while ((ln = Lst_Next(dirSearchPath)) != NULL) {
509 CachedDir *dir = LstNode_Datum(ln);
510 if (dir == dotLast)
511 continue;
512 if (dir == dot && hasLastDot)
513 continue;
514 Var_Append(".PATH", dir->name, VAR_GLOBAL);
515 }
516
517 if (hasLastDot) {
518 if (dot)
519 Var_Append(".PATH", dot->name, VAR_GLOBAL);
520 if (cur)
521 Var_Append(".PATH", cur->name, VAR_GLOBAL);
522 }
523 Lst_Close(dirSearchPath);
524 }
525
526 /* See if the CachedDir structure describes the same directory as the
527 * given one by comparing their names. Called from Dir_AddDir via
528 * Lst_Find when searching the list of open directories. */
529 static Boolean
530 DirFindName(const void *p, const void *desiredName)
531 {
532 const CachedDir *dir = p;
533 return strcmp(dir->name, desiredName) == 0;
534 }
535
536 /* See if the given name has any wildcard characters in it. Be careful not to
537 * expand unmatching brackets or braces.
538 *
539 * XXX: This code is not 100% correct ([^]] fails etc.). I really don't think
540 * that make(1) should be expanding patterns, because then you have to set a
541 * mechanism for escaping the expansion!
542 *
543 * Input:
544 * name name to check
545 *
546 * Results:
547 * returns TRUE if the word should be expanded, FALSE otherwise
548 */
549 Boolean
550 Dir_HasWildcards(const char *name)
551 {
552 const char *cp;
553 Boolean wild = FALSE;
554 int braces = 0, brackets = 0;
555
556 for (cp = name; *cp; cp++) {
557 switch (*cp) {
558 case '{':
559 braces++;
560 wild = TRUE;
561 break;
562 case '}':
563 braces--;
564 break;
565 case '[':
566 brackets++;
567 wild = TRUE;
568 break;
569 case ']':
570 brackets--;
571 break;
572 case '?':
573 case '*':
574 wild = TRUE;
575 break;
576 default:
577 break;
578 }
579 }
580 return wild && brackets == 0 && braces == 0;
581 }
582
583 /*-
584 *-----------------------------------------------------------------------
585 * DirMatchFiles --
586 * Given a pattern and a CachedDir structure, see if any files
587 * match the pattern and add their names to the 'expansions' list if
588 * any do. This is incomplete -- it doesn't take care of patterns like
589 * src / *src / *.c properly (just *.c on any of the directories), but it
590 * will do for now.
591 *
592 * Input:
593 * pattern Pattern to look for
594 * dir Directory to search
595 * expansion Place to store the results
596 *
597 * Side Effects:
598 * File names are added to the expansions lst. The directory will be
599 * fully hashed when this is done.
600 *-----------------------------------------------------------------------
601 */
602 static void
603 DirMatchFiles(const char *pattern, CachedDir *dir, StringList *expansions)
604 {
605 Hash_Search search; /* Index into the directory's table */
606 Hash_Entry *entry; /* Current entry in the table */
607 Boolean isDot; /* TRUE if the directory being searched is . */
608
609 isDot = (dir->name[0] == '.' && dir->name[1] == '\0');
610
611 for (entry = Hash_EnumFirst(&dir->files, &search);
612 entry != NULL;
613 entry = Hash_EnumNext(&search))
614 {
615 /*
616 * See if the file matches the given pattern. Note we follow the UNIX
617 * convention that dot files will only be found if the pattern
618 * begins with a dot (note also that as a side effect of the hashing
619 * scheme, .* won't match . or .. since they aren't hashed).
620 */
621 if (Str_Match(entry->name, pattern) &&
622 ((entry->name[0] != '.') ||
623 (pattern[0] == '.')))
624 {
625 Lst_Append(expansions,
626 (isDot ? bmake_strdup(entry->name) :
627 str_concat3(dir->name, "/", entry->name)));
628 }
629 }
630 }
631
632 /* Find the next closing brace in the string, taking nested braces into
633 * account. */
634 static const char *
635 closing_brace(const char *p)
636 {
637 int nest = 0;
638 while (*p != '\0') {
639 if (*p == '}' && nest == 0)
640 break;
641 if (*p == '{')
642 nest++;
643 if (*p == '}')
644 nest--;
645 p++;
646 }
647 return p;
648 }
649
650 /* Find the next closing brace or comma in the string, taking nested braces
651 * into account. */
652 static const char *
653 separator_comma(const char *p)
654 {
655 int nest = 0;
656 while (*p != '\0') {
657 if ((*p == '}' || *p == ',') && nest == 0)
658 break;
659 if (*p == '{')
660 nest++;
661 if (*p == '}')
662 nest--;
663 p++;
664 }
665 return p;
666 }
667
668 static Boolean
669 contains_wildcard(const char *p)
670 {
671 for (; *p != '\0'; p++) {
672 switch (*p) {
673 case '*':
674 case '?':
675 case '{':
676 case '[':
677 return TRUE;
678 }
679 }
680 return FALSE;
681 }
682
683 static char *
684 concat3(const char *a, size_t a_len, const char *b, size_t b_len,
685 const char *c, size_t c_len)
686 {
687 size_t s_len = a_len + b_len + c_len;
688 char *s = bmake_malloc(s_len + 1);
689 memcpy(s, a, a_len);
690 memcpy(s + a_len, b, b_len);
691 memcpy(s + a_len + b_len, c, c_len);
692 s[s_len] = '\0';
693 return s;
694 }
695
696 /*-
697 *-----------------------------------------------------------------------
698 * DirExpandCurly --
699 * Expand curly braces like the C shell. Does this recursively.
700 * Note the special case: if after the piece of the curly brace is
701 * done there are no wildcard characters in the result, the result is
702 * placed on the list WITHOUT CHECKING FOR ITS EXISTENCE.
703 *
704 * Input:
705 * word Entire word to expand
706 * brace First curly brace in it
707 * path Search path to use
708 * expansions Place to store the expansions
709 *
710 * Results:
711 * None.
712 *
713 * Side Effects:
714 * The given list is filled with the expansions...
715 *
716 *-----------------------------------------------------------------------
717 */
718 static void
719 DirExpandCurly(const char *word, const char *brace, SearchPath *path,
720 StringList *expansions)
721 {
722 const char *prefix, *middle, *piece, *middle_end, *suffix;
723 size_t prefix_len, suffix_len;
724
725 /* Split the word into prefix '{' middle '}' suffix. */
726
727 middle = brace + 1;
728 middle_end = closing_brace(middle);
729 if (*middle_end == '\0') {
730 Error("Unterminated {} clause \"%s\"", middle);
731 return;
732 }
733
734 prefix = word;
735 prefix_len = (size_t)(brace - prefix);
736 suffix = middle_end + 1;
737 suffix_len = strlen(suffix);
738
739 /* Split the middle into pieces, separated by commas. */
740
741 piece = middle;
742 while (piece < middle_end + 1) {
743 const char *piece_end = separator_comma(piece);
744 size_t piece_len = (size_t)(piece_end - piece);
745
746 char *file = concat3(prefix, prefix_len, piece, piece_len,
747 suffix, suffix_len);
748
749 if (contains_wildcard(file)) {
750 Dir_Expand(file, path, expansions);
751 free(file);
752 } else {
753 Lst_Append(expansions, file);
754 }
755
756 piece = piece_end + 1; /* skip over the comma or closing brace */
757 }
758 }
759
760
761 /*-
762 *-----------------------------------------------------------------------
763 * DirExpandInt --
764 * Internal expand routine. Passes through the directories in the
765 * path one by one, calling DirMatchFiles for each. NOTE: This still
766 * doesn't handle patterns in directories...
767 *
768 * Input:
769 * word Word to expand
770 * path Directory in which to look
771 * expansions Place to store the result
772 *
773 * Results:
774 * None.
775 *
776 * Side Effects:
777 * Things are added to the expansions list.
778 *
779 *-----------------------------------------------------------------------
780 */
781 static void
782 DirExpandInt(const char *word, SearchPath *path, StringList *expansions)
783 {
784 SearchPathNode *ln;
785 for (ln = path->first; ln != NULL; ln = ln->next) {
786 CachedDir *dir = ln->datum;
787 DirMatchFiles(word, dir, expansions);
788 }
789 }
790
791 static void
792 DirPrintExpansions(StringList *words)
793 {
794 StringListNode *ln;
795 for (ln = words->first; ln != NULL; ln = ln->next) {
796 const char *word = ln->datum;
797 debug_printf("%s ", word);
798 }
799 debug_printf("\n");
800 }
801
802 /*-
803 *-----------------------------------------------------------------------
804 * Dir_Expand --
805 * Expand the given word into a list of words by globbing it looking
806 * in the directories on the given search path.
807 *
808 * Input:
809 * word the word to expand
810 * path the list of directories in which to find the
811 * resulting files
812 * expansions the list on which to place the results
813 *
814 * Results:
815 * A list of words consisting of the files which exist along the search
816 * path matching the given pattern.
817 *
818 * Side Effects:
819 * Directories may be opened. Who knows?
820 * Undefined behavior if the word is really in read-only memory.
821 *-----------------------------------------------------------------------
822 */
823 void
824 Dir_Expand(const char *word, SearchPath *path, StringList *expansions)
825 {
826 const char *cp;
827
828 assert(path != NULL);
829 assert(expansions != NULL);
830
831 DIR_DEBUG1("Expanding \"%s\"... ", word);
832
833 cp = strchr(word, '{');
834 if (cp) {
835 DirExpandCurly(word, cp, path, expansions);
836 } else {
837 cp = strchr(word, '/');
838 if (cp) {
839 /*
840 * The thing has a directory component -- find the first wildcard
841 * in the string.
842 */
843 for (cp = word; *cp; cp++) {
844 if (*cp == '?' || *cp == '[' || *cp == '*' || *cp == '{') {
845 break;
846 }
847 }
848 if (*cp == '{') {
849 /*
850 * This one will be fun.
851 */
852 DirExpandCurly(word, cp, path, expansions);
853 return;
854 } else if (*cp != '\0') {
855 /*
856 * Back up to the start of the component
857 */
858 while (cp > word && *cp != '/') {
859 cp--;
860 }
861 if (cp != word) {
862 char sc;
863 char *dirpath;
864 /*
865 * If the glob isn't in the first component, try and find
866 * all the components up to the one with a wildcard.
867 */
868 sc = cp[1];
869 ((char *)UNCONST(cp))[1] = '\0';
870 dirpath = Dir_FindFile(word, path);
871 ((char *)UNCONST(cp))[1] = sc;
872 /*
873 * dirpath is null if can't find the leading component
874 * XXX: Dir_FindFile won't find internal components.
875 * i.e. if the path contains ../Etc/Object and we're
876 * looking for Etc, it won't be found. Ah well.
877 * Probably not important.
878 */
879 if (dirpath != NULL) {
880 char *dp = &dirpath[strlen(dirpath) - 1];
881 if (*dp == '/')
882 *dp = '\0';
883 path = Lst_Init();
884 (void)Dir_AddDir(path, dirpath);
885 DirExpandInt(cp + 1, path, expansions);
886 Lst_Free(path);
887 }
888 } else {
889 /*
890 * Start the search from the local directory
891 */
892 DirExpandInt(word, path, expansions);
893 }
894 } else {
895 /*
896 * Return the file -- this should never happen.
897 */
898 DirExpandInt(word, path, expansions);
899 }
900 } else {
901 /*
902 * First the files in dot
903 */
904 DirMatchFiles(word, dot, expansions);
905
906 /*
907 * Then the files in every other directory on the path.
908 */
909 DirExpandInt(word, path, expansions);
910 }
911 }
912 if (DEBUG(DIR))
913 DirPrintExpansions(expansions);
914 }
915
916 /*-
917 *-----------------------------------------------------------------------
918 * DirLookup --
919 * Find if the file with the given name exists in the given path.
920 *
921 * Results:
922 * The path to the file or NULL. This path is guaranteed to be in a
923 * different part of memory than name and so may be safely free'd.
924 *
925 * Side Effects:
926 * None.
927 *-----------------------------------------------------------------------
928 */
929 static char *
930 DirLookup(CachedDir *dir, const char *name MAKE_ATTR_UNUSED, const char *cp,
931 Boolean hasSlash MAKE_ATTR_UNUSED)
932 {
933 char *file; /* the current filename to check */
934
935 DIR_DEBUG1(" %s ...\n", dir->name);
936
937 if (Hash_FindEntry(&dir->files, cp) == NULL)
938 return NULL;
939
940 file = str_concat3(dir->name, "/", cp);
941 DIR_DEBUG1(" returning %s\n", file);
942 dir->hits++;
943 hits++;
944 return file;
945 }
946
947
948 /*-
949 *-----------------------------------------------------------------------
950 * DirLookupSubdir --
951 * Find if the file with the given name exists in the given path.
952 *
953 * Results:
954 * The path to the file or NULL. This path is guaranteed to be in a
955 * different part of memory than name and so may be safely free'd.
956 *
957 * Side Effects:
958 * If the file is found, it is added in the modification times hash
959 * table.
960 *-----------------------------------------------------------------------
961 */
962 static char *
963 DirLookupSubdir(CachedDir *dir, const char *name)
964 {
965 struct make_stat mst;
966 char *file; /* the current filename to check */
967
968 if (dir != dot) {
969 file = str_concat3(dir->name, "/", name);
970 } else {
971 /*
972 * Checking in dot -- DON'T put a leading ./ on the thing.
973 */
974 file = bmake_strdup(name);
975 }
976
977 DIR_DEBUG1("checking %s ...\n", file);
978
979 if (cached_stat(file, &mst) == 0) {
980 nearmisses++;
981 return file;
982 }
983 free(file);
984 return NULL;
985 }
986
987 /*-
988 *-----------------------------------------------------------------------
989 * DirLookupAbs --
990 * Find if the file with the given name exists in the given path.
991 *
992 * Results:
993 * The path to the file, the empty string or NULL. If the file is
994 * the empty string, the search should be terminated.
995 * This path is guaranteed to be in a different part of memory
996 * than name and so may be safely free'd.
997 *
998 * Side Effects:
999 * None.
1000 *-----------------------------------------------------------------------
1001 */
1002 static char *
1003 DirLookupAbs(CachedDir *dir, const char *name, const char *cp)
1004 {
1005 char *p1; /* pointer into dir->name */
1006 const char *p2; /* pointer into name */
1007
1008 DIR_DEBUG1(" %s ...\n", dir->name);
1009
1010 /*
1011 * If the file has a leading path component and that component
1012 * exactly matches the entire name of the current search
1013 * directory, we can attempt another cache lookup. And if we don't
1014 * have a hit, we can safely assume the file does not exist at all.
1015 */
1016 for (p1 = dir->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) {
1017 continue;
1018 }
1019 if (*p1 != '\0' || p2 != cp - 1) {
1020 return NULL;
1021 }
1022
1023 if (Hash_FindEntry(&dir->files, cp) == NULL) {
1024 DIR_DEBUG0(" must be here but isn't -- returning\n");
1025 /* Return empty string: terminates search */
1026 return bmake_strdup("");
1027 }
1028
1029 dir->hits++;
1030 hits++;
1031 DIR_DEBUG1(" returning %s\n", name);
1032 return bmake_strdup(name);
1033 }
1034
1035 /*-
1036 *-----------------------------------------------------------------------
1037 * DirFindDot --
1038 * Find the file given on "." or curdir
1039 *
1040 * Results:
1041 * The path to the file or NULL. This path is guaranteed to be in a
1042 * different part of memory than name and so may be safely free'd.
1043 *
1044 * Side Effects:
1045 * Hit counts change
1046 *-----------------------------------------------------------------------
1047 */
1048 static char *
1049 DirFindDot(Boolean hasSlash MAKE_ATTR_UNUSED, const char *name, const char *cp)
1050 {
1051
1052 if (Hash_FindEntry(&dot->files, cp) != NULL) {
1053 DIR_DEBUG0(" in '.'\n");
1054 hits++;
1055 dot->hits++;
1056 return bmake_strdup(name);
1057 }
1058 if (cur && Hash_FindEntry(&cur->files, cp) != NULL) {
1059 DIR_DEBUG1(" in ${.CURDIR} = %s\n", cur->name);
1060 hits++;
1061 cur->hits++;
1062 return str_concat3(cur->name, "/", cp);
1063 }
1064
1065 return NULL;
1066 }
1067
1068 /*-
1069 *-----------------------------------------------------------------------
1070 * Dir_FindFile --
1071 * Find the file with the given name along the given search path.
1072 *
1073 * Input:
1074 * name the file to find
1075 * path the Lst of directories to search
1076 *
1077 * Results:
1078 * The path to the file or NULL. This path is guaranteed to be in a
1079 * different part of memory than name and so may be safely free'd.
1080 *
1081 * Side Effects:
1082 * If the file is found in a directory which is not on the path
1083 * already (either 'name' is absolute or it is a relative path
1084 * [ dir1/.../dirn/file ] which exists below one of the directories
1085 * already on the search path), its directory is added to the end
1086 * of the path on the assumption that there will be more files in
1087 * that directory later on. Sometimes this is true. Sometimes not.
1088 *-----------------------------------------------------------------------
1089 */
1090 char *
1091 Dir_FindFile(const char *name, SearchPath *path)
1092 {
1093 SearchPathNode *ln;
1094 char *file; /* the current filename to check */
1095 CachedDir *dir;
1096 const char *base; /* Terminal name of file */
1097 Boolean hasLastDot = FALSE; /* true if we should search dot last */
1098 Boolean hasSlash; /* true if 'name' contains a / */
1099 struct make_stat mst; /* Buffer for stat, if necessary */
1100 const char *trailing_dot = ".";
1101
1102 /*
1103 * Find the final component of the name and note whether it has a
1104 * slash in it (the name, I mean)
1105 */
1106 base = strrchr(name, '/');
1107 if (base) {
1108 hasSlash = TRUE;
1109 base++;
1110 } else {
1111 hasSlash = FALSE;
1112 base = name;
1113 }
1114
1115 DIR_DEBUG1("Searching for %s ...", name);
1116
1117 if (path == NULL) {
1118 DIR_DEBUG0("couldn't open path, file not found\n");
1119 misses++;
1120 return NULL;
1121 }
1122
1123 Lst_Open(path);
1124 if ((ln = Lst_First(path)) != NULL) {
1125 dir = LstNode_Datum(ln);
1126 if (dir == dotLast) {
1127 hasLastDot = TRUE;
1128 DIR_DEBUG0("[dot last]...");
1129 }
1130 }
1131 DIR_DEBUG0("\n");
1132
1133 /*
1134 * If there's no leading directory components or if the leading
1135 * directory component is exactly `./', consult the cached contents
1136 * of each of the directories on the search path.
1137 */
1138 if (!hasSlash || (base - name == 2 && *name == '.')) {
1139 /*
1140 * We look through all the directories on the path seeking one which
1141 * contains the final component of the given name. If such a beast
1142 * is found, we concatenate the directory name and the final
1143 * component and return the resulting string. If we don't find any
1144 * such thing, we go on to phase two...
1145 *
1146 * No matter what, we always look for the file in the current
1147 * directory before anywhere else (unless we found the magic
1148 * DOTLAST path, in which case we search it last) and we *do not*
1149 * add the ./ to it if it exists.
1150 * This is so there are no conflicts between what the user
1151 * specifies (fish.c) and what pmake finds (./fish.c).
1152 */
1153 if (!hasLastDot && (file = DirFindDot(hasSlash, name, base)) != NULL) {
1154 Lst_Close(path);
1155 return file;
1156 }
1157
1158 while ((ln = Lst_Next(path)) != NULL) {
1159 dir = LstNode_Datum(ln);
1160 if (dir == dotLast)
1161 continue;
1162 if ((file = DirLookup(dir, name, base, hasSlash)) != NULL) {
1163 Lst_Close(path);
1164 return file;
1165 }
1166 }
1167
1168 if (hasLastDot && (file = DirFindDot(hasSlash, name, base)) != NULL) {
1169 Lst_Close(path);
1170 return file;
1171 }
1172 }
1173 Lst_Close(path);
1174
1175 /*
1176 * We didn't find the file on any directory in the search path.
1177 * If the name doesn't contain a slash, that means it doesn't exist.
1178 * If it *does* contain a slash, however, there is still hope: it
1179 * could be in a subdirectory of one of the members of the search
1180 * path. (eg. /usr/include and sys/types.h. The above search would
1181 * fail to turn up types.h in /usr/include, but it *is* in
1182 * /usr/include/sys/types.h).
1183 * [ This no longer applies: If we find such a beast, we assume there
1184 * will be more (what else can we assume?) and add all but the last
1185 * component of the resulting name onto the search path (at the
1186 * end).]
1187 * This phase is only performed if the file is *not* absolute.
1188 */
1189 if (!hasSlash) {
1190 DIR_DEBUG0(" failed.\n");
1191 misses++;
1192 return NULL;
1193 }
1194
1195 if (*base == '\0') {
1196 /* we were given a trailing "/" */
1197 base = trailing_dot;
1198 }
1199
1200 if (name[0] != '/') {
1201 Boolean checkedDot = FALSE;
1202
1203 DIR_DEBUG0(" Trying subdirectories...\n");
1204
1205 if (!hasLastDot) {
1206 if (dot) {
1207 checkedDot = TRUE;
1208 if ((file = DirLookupSubdir(dot, name)) != NULL)
1209 return file;
1210 }
1211 if (cur && (file = DirLookupSubdir(cur, name)) != NULL)
1212 return file;
1213 }
1214
1215 Lst_Open(path);
1216 while ((ln = Lst_Next(path)) != NULL) {
1217 dir = LstNode_Datum(ln);
1218 if (dir == dotLast)
1219 continue;
1220 if (dir == dot) {
1221 if (checkedDot)
1222 continue;
1223 checkedDot = TRUE;
1224 }
1225 if ((file = DirLookupSubdir(dir, name)) != NULL) {
1226 Lst_Close(path);
1227 return file;
1228 }
1229 }
1230 Lst_Close(path);
1231
1232 if (hasLastDot) {
1233 if (dot && !checkedDot) {
1234 checkedDot = TRUE;
1235 if ((file = DirLookupSubdir(dot, name)) != NULL)
1236 return file;
1237 }
1238 if (cur && (file = DirLookupSubdir(cur, name)) != NULL)
1239 return file;
1240 }
1241
1242 if (checkedDot) {
1243 /*
1244 * Already checked by the given name, since . was in the path,
1245 * so no point in proceeding...
1246 */
1247 DIR_DEBUG0(" Checked . already, returning NULL\n");
1248 return NULL;
1249 }
1250
1251 } else { /* name[0] == '/' */
1252
1253 /*
1254 * For absolute names, compare directory path prefix against the
1255 * the directory path of each member on the search path for an exact
1256 * match. If we have an exact match on any member of the search path,
1257 * use the cached contents of that member to lookup the final file
1258 * component. If that lookup fails we can safely assume that the
1259 * file does not exist at all. This is signified by DirLookupAbs()
1260 * returning an empty string.
1261 */
1262 DIR_DEBUG0(" Trying exact path matches...\n");
1263
1264 if (!hasLastDot && cur &&
1265 ((file = DirLookupAbs(cur, name, base)) != NULL)) {
1266 if (file[0] == '\0') {
1267 free(file);
1268 return NULL;
1269 }
1270 return file;
1271 }
1272
1273 Lst_Open(path);
1274 while ((ln = Lst_Next(path)) != NULL) {
1275 dir = LstNode_Datum(ln);
1276 if (dir == dotLast)
1277 continue;
1278 if ((file = DirLookupAbs(dir, name, base)) != NULL) {
1279 Lst_Close(path);
1280 if (file[0] == '\0') {
1281 free(file);
1282 return NULL;
1283 }
1284 return file;
1285 }
1286 }
1287 Lst_Close(path);
1288
1289 if (hasLastDot && cur &&
1290 ((file = DirLookupAbs(cur, name, base)) != NULL)) {
1291 if (file[0] == '\0') {
1292 free(file);
1293 return NULL;
1294 }
1295 return file;
1296 }
1297 }
1298
1299 /*
1300 * Didn't find it that way, either. Sigh. Phase 3. Add its directory
1301 * onto the search path in any case, just in case, then look for the
1302 * thing in the hash table. If we find it, grand. We return a new
1303 * copy of the name. Otherwise we sadly return a NULL pointer. Sigh.
1304 * Note that if the directory holding the file doesn't exist, this will
1305 * do an extra search of the final directory on the path. Unless something
1306 * weird happens, this search won't succeed and life will be groovy.
1307 *
1308 * Sigh. We cannot add the directory onto the search path because
1309 * of this amusing case:
1310 * $(INSTALLDIR)/$(FILE): $(FILE)
1311 *
1312 * $(FILE) exists in $(INSTALLDIR) but not in the current one.
1313 * When searching for $(FILE), we will find it in $(INSTALLDIR)
1314 * b/c we added it here. This is not good...
1315 */
1316 #ifdef notdef
1317 if (base == trailing_dot) {
1318 base = strrchr(name, '/');
1319 base++;
1320 }
1321 base[-1] = '\0';
1322 (void)Dir_AddDir(path, name);
1323 base[-1] = '/';
1324
1325 bigmisses++;
1326 ln = Lst_Last(path);
1327 if (ln == NULL) {
1328 return NULL;
1329 } else {
1330 dir = LstNode_Datum(ln);
1331 }
1332
1333 if (Hash_FindEntry(&dir->files, base) != NULL) {
1334 return bmake_strdup(name);
1335 } else {
1336 return NULL;
1337 }
1338 #else /* !notdef */
1339 DIR_DEBUG1(" Looking for \"%s\" ...\n", name);
1340
1341 bigmisses++;
1342 if (cached_stat(name, &mst) == 0) {
1343 return bmake_strdup(name);
1344 }
1345
1346 DIR_DEBUG0(" failed. Returning NULL\n");
1347 return NULL;
1348 #endif /* notdef */
1349 }
1350
1351
1352 /*-
1353 *-----------------------------------------------------------------------
1354 * Dir_FindHereOrAbove --
1355 * search for a path starting at a given directory and then working
1356 * our way up towards the root.
1357 *
1358 * Input:
1359 * here starting directory
1360 * search_path the path we are looking for
1361 * result the result of a successful search is placed here
1362 * result_len the length of the result buffer
1363 * (typically MAXPATHLEN + 1)
1364 *
1365 * Results:
1366 * 0 on failure, 1 on success [in which case the found path is put
1367 * in the result buffer].
1368 *
1369 * Side Effects:
1370 *-----------------------------------------------------------------------
1371 */
1372 Boolean
1373 Dir_FindHereOrAbove(const char *here, const char *search_path,
1374 char *result, int result_len)
1375 {
1376 struct make_stat mst;
1377 char dirbase[MAXPATHLEN + 1], *dirbase_end;
1378 char try[MAXPATHLEN + 1], *try_end;
1379
1380 /* copy out our starting point */
1381 snprintf(dirbase, sizeof(dirbase), "%s", here);
1382 dirbase_end = dirbase + strlen(dirbase);
1383
1384 /* loop until we determine a result */
1385 while (TRUE) {
1386
1387 /* try and stat(2) it ... */
1388 snprintf(try, sizeof(try), "%s/%s", dirbase, search_path);
1389 if (cached_stat(try, &mst) != -1) {
1390 /*
1391 * success! if we found a file, chop off
1392 * the filename so we return a directory.
1393 */
1394 if ((mst.mst_mode & S_IFMT) != S_IFDIR) {
1395 try_end = try + strlen(try);
1396 while (try_end > try && *try_end != '/')
1397 try_end--;
1398 if (try_end > try)
1399 *try_end = '\0'; /* chop! */
1400 }
1401
1402 snprintf(result, result_len, "%s", try);
1403 return TRUE;
1404 }
1405
1406 /*
1407 * nope, we didn't find it. if we used up dirbase we've
1408 * reached the root and failed.
1409 */
1410 if (dirbase_end == dirbase)
1411 break; /* failed! */
1412
1413 /*
1414 * truncate dirbase from the end to move up a dir
1415 */
1416 while (dirbase_end > dirbase && *dirbase_end != '/')
1417 dirbase_end--;
1418 *dirbase_end = '\0'; /* chop! */
1419
1420 } /* while (TRUE) */
1421
1422 return FALSE;
1423 }
1424
1425 /*-
1426 *-----------------------------------------------------------------------
1427 * Dir_MTime --
1428 * Find the modification time of the file described by gn along the
1429 * search path dirSearchPath.
1430 *
1431 * Input:
1432 * gn the file whose modification time is desired
1433 *
1434 * Results:
1435 * The modification time or 0 if it doesn't exist
1436 *
1437 * Side Effects:
1438 * The modification time is placed in the node's mtime slot.
1439 * If the node didn't have a path entry before, and Dir_FindFile
1440 * found one for it, the full name is placed in the path slot.
1441 *-----------------------------------------------------------------------
1442 */
1443 int
1444 Dir_MTime(GNode *gn, Boolean recheck)
1445 {
1446 char *fullName; /* the full pathname of name */
1447 struct make_stat mst; /* buffer for finding the mod time */
1448
1449 if (gn->type & OP_ARCHV) {
1450 return Arch_MTime(gn);
1451 } else if (gn->type & OP_PHONY) {
1452 gn->mtime = 0;
1453 return 0;
1454 } else if (gn->path == NULL) {
1455 if (gn->type & OP_NOPATH)
1456 fullName = NULL;
1457 else {
1458 fullName = Dir_FindFile(gn->name, Suff_FindPath(gn));
1459 if (fullName == NULL && gn->flags & FROM_DEPEND &&
1460 !Lst_IsEmpty(gn->implicitParents)) {
1461 char *cp;
1462
1463 cp = strrchr(gn->name, '/');
1464 if (cp) {
1465 /*
1466 * This is an implied source, and it may have moved,
1467 * see if we can find it via the current .PATH
1468 */
1469 cp++;
1470
1471 fullName = Dir_FindFile(cp, Suff_FindPath(gn));
1472 if (fullName) {
1473 /*
1474 * Put the found file in gn->path
1475 * so that we give that to the compiler.
1476 */
1477 gn->path = bmake_strdup(fullName);
1478 if (!Job_RunTarget(".STALE", gn->fname))
1479 fprintf(stdout,
1480 "%s: %s, %d: ignoring stale %s for %s, "
1481 "found %s\n", progname, gn->fname,
1482 gn->lineno,
1483 makeDependfile, gn->name, fullName);
1484 }
1485 }
1486 }
1487 DIR_DEBUG2("Found '%s' as '%s'\n",
1488 gn->name, fullName ? fullName : "(not found)");
1489 }
1490 } else {
1491 fullName = gn->path;
1492 }
1493
1494 if (fullName == NULL) {
1495 fullName = bmake_strdup(gn->name);
1496 }
1497
1498 if (cached_stats(&mtimes, fullName, &mst, recheck ? CST_UPDATE : 0) < 0) {
1499 if (gn->type & OP_MEMBER) {
1500 if (fullName != gn->path)
1501 free(fullName);
1502 return Arch_MemMTime(gn);
1503 } else {
1504 mst.mst_mtime = 0;
1505 }
1506 }
1507
1508 if (fullName && gn->path == NULL) {
1509 gn->path = fullName;
1510 }
1511
1512 gn->mtime = mst.mst_mtime;
1513 return gn->mtime;
1514 }
1515
1516 /* Read the list of filenames in the directory and store the result
1517 * in openDirectories.
1518 *
1519 * If a path is given, append the directory to that path.
1520 *
1521 * Input:
1522 * path The path to which the directory should be
1523 * added, or NULL to only add the directory to
1524 * openDirectories
1525 * name The name of the directory to add.
1526 * The name is not normalized in any way.
1527 */
1528 CachedDir *
1529 Dir_AddDir(SearchPath *path, const char *name)
1530 {
1531 CachedDir *dir = NULL; /* the added directory */
1532 DIR *d;
1533 struct dirent *dp;
1534
1535 if (path != NULL && strcmp(name, ".DOTLAST") == 0) {
1536 SearchPathNode *ln = Lst_Find(path, DirFindName, name);
1537 if (ln != NULL)
1538 return LstNode_Datum(ln);
1539
1540 dotLast->refCount++;
1541 Lst_Prepend(path, dotLast);
1542 }
1543
1544 if (path != NULL)
1545 dir = OpenDirs_Find(&openDirs, name);
1546 if (dir != NULL) {
1547 if (Lst_FindDatum(path, dir) == NULL) {
1548 dir->refCount++;
1549 Lst_Append(path, dir);
1550 }
1551 return dir;
1552 }
1553
1554 DIR_DEBUG1("Caching %s ...", name);
1555
1556 if ((d = opendir(name)) != NULL) {
1557 dir = bmake_malloc(sizeof(CachedDir));
1558 dir->name = bmake_strdup(name);
1559 dir->hits = 0;
1560 dir->refCount = 1;
1561 Hash_InitTable(&dir->files);
1562
1563 while ((dp = readdir(d)) != NULL) {
1564 #if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */
1565 /*
1566 * The sun directory library doesn't check for a 0 inode
1567 * (0-inode slots just take up space), so we have to do
1568 * it ourselves.
1569 */
1570 if (dp->d_fileno == 0) {
1571 continue;
1572 }
1573 #endif /* sun && d_ino */
1574 (void)Hash_CreateEntry(&dir->files, dp->d_name, NULL);
1575 }
1576 (void)closedir(d);
1577 OpenDirs_Add(&openDirs, dir);
1578 if (path != NULL)
1579 Lst_Append(path, dir);
1580 }
1581 DIR_DEBUG0("done\n");
1582 return dir;
1583 }
1584
1585 /*-
1586 *-----------------------------------------------------------------------
1587 * Dir_CopyDir --
1588 * Callback function for duplicating a search path via Lst_Copy.
1589 * Ups the reference count for the directory.
1590 *
1591 * Results:
1592 * Returns the Path it was given.
1593 *-----------------------------------------------------------------------
1594 */
1595 void *
1596 Dir_CopyDir(void *p)
1597 {
1598 CachedDir *dir = (CachedDir *)p;
1599 dir->refCount++;
1600
1601 return p;
1602 }
1603
1604 /*-
1605 *-----------------------------------------------------------------------
1606 * Dir_MakeFlags --
1607 * Make a string by taking all the directories in the given search
1608 * path and preceding them by the given flag. Used by the suffix
1609 * module to create variables for compilers based on suffix search
1610 * paths.
1611 *
1612 * Input:
1613 * flag flag which should precede each directory
1614 * path list of directories
1615 *
1616 * Results:
1617 * The string mentioned above. Note that there is no space between
1618 * the given flag and each directory. The empty string is returned if
1619 * Things don't go well.
1620 *
1621 * Side Effects:
1622 * None
1623 *-----------------------------------------------------------------------
1624 */
1625 char *
1626 Dir_MakeFlags(const char *flag, SearchPath *path)
1627 {
1628 Buffer buf;
1629 SearchPathNode *ln;
1630
1631 Buf_Init(&buf, 0);
1632
1633 if (path != NULL) {
1634 for (ln = path->first; ln != NULL; ln = ln->next) {
1635 CachedDir *dir = ln->datum;
1636 Buf_AddStr(&buf, " ");
1637 Buf_AddStr(&buf, flag);
1638 Buf_AddStr(&buf, dir->name);
1639 }
1640 }
1641
1642 return Buf_Destroy(&buf, FALSE);
1643 }
1644
1645 /*-
1646 *-----------------------------------------------------------------------
1647 * Dir_Destroy --
1648 * Nuke a directory descriptor, if possible. Callback procedure
1649 * for the suffixes module when destroying a search path.
1650 *
1651 * Input:
1652 * dirp The directory descriptor to nuke
1653 *
1654 * Results:
1655 * None.
1656 *
1657 * Side Effects:
1658 * If no other path references this directory (refCount == 0),
1659 * the CachedDir and all its data are freed.
1660 *
1661 *-----------------------------------------------------------------------
1662 */
1663 void
1664 Dir_Destroy(void *dirp)
1665 {
1666 CachedDir *dir = dirp;
1667 dir->refCount--;
1668
1669 if (dir->refCount == 0) {
1670 OpenDirs_Remove(&openDirs, dir->name);
1671
1672 Hash_DeleteTable(&dir->files);
1673 free(dir->name);
1674 free(dir);
1675 }
1676 }
1677
1678 /*-
1679 *-----------------------------------------------------------------------
1680 * Dir_ClearPath --
1681 * Clear out all elements of the given search path. This is different
1682 * from destroying the list, notice.
1683 *
1684 * Input:
1685 * path Path to clear
1686 *
1687 * Results:
1688 * None.
1689 *
1690 * Side Effects:
1691 * The path is set to the empty list.
1692 *
1693 *-----------------------------------------------------------------------
1694 */
1695 void
1696 Dir_ClearPath(SearchPath *path)
1697 {
1698 while (!Lst_IsEmpty(path)) {
1699 CachedDir *dir = Lst_Dequeue(path);
1700 Dir_Destroy(dir);
1701 }
1702 }
1703
1704
1705 /*-
1706 *-----------------------------------------------------------------------
1707 * Dir_Concat --
1708 * Concatenate two paths, adding the second to the end of the first.
1709 * Makes sure to avoid duplicates.
1710 *
1711 * Input:
1712 * path1 Dest
1713 * path2 Source
1714 *
1715 * Results:
1716 * None
1717 *
1718 * Side Effects:
1719 * Reference counts for added dirs are upped.
1720 *
1721 *-----------------------------------------------------------------------
1722 */
1723 void
1724 Dir_Concat(SearchPath *path1, SearchPath *path2)
1725 {
1726 SearchPathNode *ln;
1727
1728 for (ln = path2->first; ln != NULL; ln = ln->next) {
1729 CachedDir *dir = ln->datum;
1730 if (Lst_FindDatum(path1, dir) == NULL) {
1731 dir->refCount++;
1732 Lst_Append(path1, dir);
1733 }
1734 }
1735 }
1736
1737 static int
1738 percentage(int num, int den)
1739 {
1740 return den != 0 ? num * 100 / den : 0;
1741 }
1742
1743 /********** DEBUG INFO **********/
1744 void
1745 Dir_PrintDirectories(void)
1746 {
1747 CachedDirListNode *ln;
1748
1749 debug_printf("#*** Directory Cache:\n");
1750 debug_printf("# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n",
1751 hits, misses, nearmisses, bigmisses,
1752 percentage(hits, hits + bigmisses + nearmisses));
1753 debug_printf("# %-20s referenced\thits\n", "directory");
1754
1755 for (ln = openDirs.list->first; ln != NULL; ln = ln->next) {
1756 CachedDir *dir = ln->datum;
1757 debug_printf("# %-20s %10d\t%4d\n", dir->name, dir->refCount,
1758 dir->hits);
1759 }
1760 }
1761
1762 void
1763 Dir_PrintPath(SearchPath *path)
1764 {
1765 SearchPathNode *node;
1766 for (node = path->first; node != NULL; node = node->next) {
1767 const CachedDir *dir = node->datum;
1768 debug_printf("%s ", dir->name);
1769 }
1770 }
1771