Annotation of src/usr.bin/make/dir.c, Revision 1.30
1.30 ! espie 1: /* $OpenBSD: dir.c,v 1.29 2000/11/24 14:36:33 espie Exp $ */
1.7 millert 2: /* $NetBSD: dir.c,v 1.14 1997/03/29 16:51:26 christos Exp $ */
1.1 deraadt 3:
4: /*
5: * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
6: * Copyright (c) 1988, 1989 by Adam de Boor
7: * Copyright (c) 1989 by Berkeley Softworks
8: * All rights reserved.
9: *
10: * This code is derived from software contributed to Berkeley by
11: * Adam de Boor.
12: *
13: * Redistribution and use in source and binary forms, with or without
14: * modification, are permitted provided that the following conditions
15: * are met:
16: * 1. Redistributions of source code must retain the above copyright
17: * notice, this list of conditions and the following disclaimer.
18: * 2. Redistributions in binary form must reproduce the above copyright
19: * notice, this list of conditions and the following disclaimer in the
20: * documentation and/or other materials provided with the distribution.
21: * 3. All advertising materials mentioning features or use of this software
22: * must display the following acknowledgement:
23: * This product includes software developed by the University of
24: * California, Berkeley and its contributors.
25: * 4. Neither the name of the University nor the names of its contributors
26: * may be used to endorse or promote products derived from this software
27: * without specific prior written permission.
28: *
29: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39: * SUCH DAMAGE.
40: */
41:
42: /*-
43: * dir.c --
44: * Directory searching using wildcards and/or normal names...
45: * Used both for source wildcarding in the Makefile and for finding
46: * implicit sources.
47: *
48: * The interface for this module is:
49: * Dir_Init Initialize the module.
50: *
51: * Dir_End Cleanup the module.
52: *
53: * Dir_HasWildcards Returns TRUE if the name given it needs to
54: * be wildcard-expanded.
55: *
56: * Dir_Expand Given a pattern and a path, return a Lst of names
57: * which match the pattern on the search path.
58: *
59: * Dir_FindFile Searches for a file on a given search path.
60: * If it exists, the entire path is returned.
61: * Otherwise NULL is returned.
62: *
1.16 espie 63: * Dir_MTime Return TRUE if node exists. The file
1.1 deraadt 64: * is searched for along the default search path.
65: * The path and mtime fields of the node are filled
66: * in.
67: *
68: * Dir_AddDir Add a directory to a search path.
69: *
70: * Dir_MakeFlags Given a search path and a command flag, create
71: * a string with each of the directories in the path
72: * preceded by the command flag and all of them
73: * separated by a space.
74: *
75: * Dir_Destroy Destroy an element of a search path. Frees up all
76: * things that can be freed for the element as long
77: * as the element is no longer referenced by any other
78: * search path.
79: * Dir_ClearPath Resets a search path to the empty list.
80: *
81: * For debugging:
82: * Dir_PrintDirectories Print stats about the directory cache.
83: */
84:
1.25 espie 85: #include <stddef.h>
1.1 deraadt 86: #include <stdio.h>
87: #include <sys/types.h>
88: #include <dirent.h>
89: #include <sys/stat.h>
90: #include "make.h"
1.25 espie 91: #include "ohash.h"
1.1 deraadt 92: #include "dir.h"
1.24 espie 93:
94: #ifndef lint
95: #if 0
96: static char sccsid[] = "@(#)dir.c 8.2 (Berkeley) 1/2/94";
97: #else
98: UNUSED
1.30 ! espie 99: static char rcsid[] = "$OpenBSD: dir.c,v 1.29 2000/11/24 14:36:33 espie Exp $";
1.24 espie 100: #endif
101: #endif /* not lint */
1.1 deraadt 102:
103: /*
104: * A search path consists of a Lst of Path structures. A Path structure
105: * has in it the name of the directory and a hash table of all the files
106: * in the directory. This is used to cut down on the number of system
107: * calls necessary to find implicit dependents and their like. Since
108: * these searches are made before any actions are taken, we need not
109: * worry about the directory changing due to creation commands. If this
110: * hampers the style of some makefiles, they must be changed.
111: *
112: * A list of all previously-read directories is kept in the
1.25 espie 113: * openDirectories cache.
1.1 deraadt 114: *
115: * The need for the caching of whole directories is brought about by
116: * the multi-level transformation code in suff.c, which tends to search
117: * for far more files than regular make does. In the initial
118: * implementation, the amount of time spent performing "stat" calls was
119: * truly astronomical. The problem with hashing at the start is,
120: * of course, that pmake doesn't then detect changes to these directories
121: * during the course of the make. Three possibilities suggest themselves:
122: *
123: * 1) just use stat to test for a file's existence. As mentioned
124: * above, this is very inefficient due to the number of checks
125: * engendered by the multi-level transformation code.
126: * 2) use readdir() and company to search the directories, keeping
127: * them open between checks. I have tried this and while it
128: * didn't slow down the process too much, it could severely
129: * affect the amount of parallelism available as each directory
130: * open would take another file descriptor out of play for
131: * handling I/O for another job. Given that it is only recently
132: * that UNIX OS's have taken to allowing more than 20 or 32
133: * file descriptors for a process, this doesn't seem acceptable
134: * to me.
135: * 3) record the mtime of the directory in the Path structure and
136: * verify the directory hasn't changed since the contents were
137: * hashed. This will catch the creation or deletion of files,
138: * but not the updating of files. However, since it is the
139: * creation and deletion that is the problem, this could be
140: * a good thing to do. Unfortunately, if the directory (say ".")
141: * were fairly large and changed fairly frequently, the constant
142: * rehashing could seriously degrade performance. It might be
143: * good in such cases to keep track of the number of rehashes
144: * and if the number goes over a (small) limit, resort to using
145: * stat in its place.
146: *
147: * An additional thing to consider is that pmake is used primarily
148: * to create C programs and until recently pcc-based compilers refused
149: * to allow you to specify where the resulting object file should be
150: * placed. This forced all objects to be created in the current
151: * directory. This isn't meant as a full excuse, just an explanation of
152: * some of the reasons for the caching used here.
153: *
154: * One more note: the location of a target's file is only performed
155: * on the downward traversal of the graph and then only for terminal
156: * nodes in the graph. This could be construed as wrong in some cases,
157: * but prevents inadvertent modification of files when the "installed"
158: * directory for a file is provided in the search path.
159: *
160: * Another data structure maintained by this module is an mtime
161: * cache used when the searching of cached directories fails to find
162: * a file. In the past, Dir_FindFile would simply perform an access()
163: * call in such a case to determine if the file could be found using
164: * just the name given. When this hit, however, all that was gained
165: * was the knowledge that the file existed. Given that an access() is
166: * essentially a stat() without the copyout() call, and that the same
167: * filesystem overhead would have to be incurred in Dir_MTime, it made
168: * sense to replace the access() with a stat() and record the mtime
169: * in a cache for when Dir_MTime was actually called.
170: */
171:
1.20 espie 172: LIST dirSearchPath; /* main search path */
1.1 deraadt 173:
1.30 ! espie 174: static struct ohash openDirectories; /* cache all open directories */
1.1 deraadt 175:
176: /*
177: * Variables for gathering statistics on the efficiency of the hashing
178: * mechanism.
179: */
180: static int hits, /* Found in directory cache */
181: misses, /* Sad, but not evil misses */
182: nearmisses, /* Found under search path */
183: bigmisses; /* Sought by itself */
184:
185: static Path *dot; /* contents of current directory */
1.27 espie 186:
187: struct file_stamp {
188: TIMESTAMP mtime; /* time stamp... */
189: char name[1]; /* ...for that file. */
190: };
191:
1.30 ! espie 192: static struct ohash mtimes; /* Results of doing a last-resort stat in
1.1 deraadt 193: * Dir_FindFile -- if we have to go to the
194: * system to find the file, we might as well
195: * have its mtime on record. XXX: If this is done
196: * way early, there's a chance other rules will
197: * have already updated the file, in which case
198: * we'll update it again. Generally, there won't
199: * be two rules to update a single file, so this
200: * should be ok, but... */
201:
1.27 espie 202: /* There are three distinct hash structures:
203: * - to collate files's last modification times (global mtimes)
204: * - to collate file names (in each Path structure)
205: * - to collate known directories (global openDirectories). */
1.30 ! espie 206: static struct ohash_info stamp_info = { offsetof(struct file_stamp, name),
1.27 espie 207: NULL, hash_alloc, hash_free, element_alloc };
208:
1.30 ! espie 209: static struct ohash_info file_info = { 0,
1.26 espie 210: NULL, hash_alloc, hash_free, element_alloc };
211:
1.30 ! espie 212: static struct ohash_info dir_info = { offsetof(Path, name),
1.25 espie 213: NULL, hash_alloc, hash_free, element_alloc };
1.1 deraadt 214:
1.27 espie 215: static void record_stamp __P((const char *, TIMESTAMP));
1.26 espie 216: static void add_file __P((Path *, const char *));
217: static char *find_file_hash __P((Path *, const char *, const char *, u_int32_t));
1.27 espie 218: static struct file_stamp *find_stamp __P((const char *));
1.30 ! espie 219: static void free_hash __P((struct ohash *));
1.26 espie 220:
1.25 espie 221: static Path *DirReaddir __P((const char *, const char *));
1.26 espie 222: static void DirMatchFiles __P((char *, Path *, Lst));
1.1 deraadt 223: static void DirExpandCurly __P((char *, char *, Lst, Lst));
224: static void DirExpandInt __P((char *, Lst, Lst));
1.19 espie 225: static void DirPrintWord __P((void *));
226: static void DirPrintDir __P((void *));
1.1 deraadt 227:
1.26 espie 228: static void
1.27 espie 229: record_stamp(file, t)
230: const char *file;
231: TIMESTAMP t;
232: {
233: unsigned slot;
234: const char *end = NULL;
235: struct file_stamp *n;
236:
1.30 ! espie 237: slot = ohash_qlookupi(&mtimes, file, &end);
! 238: n = ohash_find(&mtimes, slot);
1.27 espie 239: if (n)
240: n->mtime = t;
241: else {
1.30 ! espie 242: n = ohash_create_entry(&stamp_info, file, &end);
1.27 espie 243: n->mtime = t;
1.30 ! espie 244: ohash_insert(&mtimes, slot, n);
1.27 espie 245: }
246: }
247:
248: static struct file_stamp *
249: find_stamp(file)
250: const char *file;
251: {
1.30 ! espie 252: return ohash_find(&mtimes, ohash_qlookup(&mtimes, file));
1.27 espie 253: }
254:
255: static void
1.26 espie 256: add_file(p, file)
257: Path *p;
258: const char *file;
259: {
260: unsigned slot;
261: const char *end = NULL;
262: char *n;
1.30 ! espie 263: struct ohash *h = &p->files;
1.26 espie 264:
1.30 ! espie 265: slot = ohash_qlookupi(h, file, &end);
! 266: n = ohash_find(h, slot);
1.26 espie 267: if (n == NULL) {
1.30 ! espie 268: n = ohash_create_entry(&file_info, file, &end);
! 269: ohash_insert(h, slot, n);
1.26 espie 270: }
271: }
272:
273: static char *
274: find_file_hash(p, file, e, hv)
275: Path *p;
276: const char *file;
277: const char *e;
278: u_int32_t hv;
279: {
1.30 ! espie 280: struct ohash *h = &p->files;
1.26 espie 281:
1.30 ! espie 282: return ohash_find(h, ohash_lookup_interval(h, file, e, hv));
1.26 espie 283: }
284:
285: static void
286: free_hash(h)
1.30 ! espie 287: struct ohash *h;
1.26 espie 288: {
289: void *e;
290: unsigned i;
291:
1.30 ! espie 292: for (e = ohash_first(h, &i); e != NULL; e = ohash_next(h, &i))
1.26 espie 293: free(e);
1.30 ! espie 294: ohash_delete(h);
1.26 espie 295: }
296:
1.1 deraadt 297: /*-
298: *-----------------------------------------------------------------------
299: * Dir_Init --
300: * initialize things for this module
301: *
302: * Results:
303: * none
304: *
305: * Side Effects:
306: * some directories may be opened.
307: *-----------------------------------------------------------------------
308: */
309: void
1.20 espie 310: Dir_Init()
1.1 deraadt 311: {
1.20 espie 312: Lst_Init(&dirSearchPath);
1.30 ! espie 313: ohash_init(&openDirectories, 4, &dir_info);
! 314: ohash_init(&mtimes, 4, &stamp_info);
1.6 millert 315:
1.25 espie 316: dot = DirReaddir(".", NULL);
1.1 deraadt 317:
1.25 espie 318: /* We always need to have dot around, so we increment its reference count
319: * to make sure it's not destroyed. */
320: dot->refCount++;
1.1 deraadt 321: }
322:
323: /*-
324: *-----------------------------------------------------------------------
325: * Dir_End --
326: * cleanup things for this module
327: *
328: * Results:
329: * none
330: *
331: * Side Effects:
332: * none
333: *-----------------------------------------------------------------------
334: */
335: void
336: Dir_End()
337: {
1.9 espie 338: #ifdef CLEANUP
1.25 espie 339: struct Path *p;
340: unsigned int i;
341:
342: dot->refCount--;
1.17 espie 343: Dir_Destroy(dot);
1.25 espie 344: Lst_Destroy(&dirSearchPath, Dir_Destroy);
1.30 ! espie 345: for (p = ohash_first(&openDirectories, &i); p != NULL;
! 346: p = ohash_next(&openDirectories, &i))
1.25 espie 347: Dir_Destroy(p);
1.30 ! espie 348: ohash_delete(&openDirectories);
1.28 espie 349: free_hash(&mtimes);
1.9 espie 350: #endif
1.1 deraadt 351: }
352:
353: /*-
354: *-----------------------------------------------------------------------
355: * Dir_HasWildcards --
356: * see if the given name has any wildcard characters in it
1.7 millert 357: * be careful not to expand unmatching brackets or braces.
358: * XXX: This code is not 100% correct. ([^]] fails etc.)
1.1 deraadt 359: *-----------------------------------------------------------------------
360: */
361: Boolean
362: Dir_HasWildcards (name)
1.28 espie 363: const char *name; /* name to check */
1.1 deraadt 364: {
1.28 espie 365: const char *cp;
366: Boolean wild = FALSE;
367: unsigned long brace = 0, bracket = 0;
1.6 millert 368:
1.28 espie 369: for (cp = name; *cp != '\0' ; cp++) {
370: switch (*cp) {
1.1 deraadt 371: case '{':
1.7 millert 372: brace++;
1.28 espie 373: wild = TRUE;
1.7 millert 374: break;
375: case '}':
1.28 espie 376: if (brace == 0)
377: return FALSE;
1.7 millert 378: brace--;
379: break;
1.1 deraadt 380: case '[':
1.7 millert 381: bracket++;
1.28 espie 382: wild = TRUE;
1.7 millert 383: break;
384: case ']':
1.28 espie 385: if (bracket == 0)
386: return FALSE;
1.7 millert 387: bracket--;
388: break;
1.1 deraadt 389: case '?':
390: case '*':
1.28 espie 391: wild = TRUE;
1.7 millert 392: break;
393: default:
394: break;
1.1 deraadt 395: }
396: }
1.28 espie 397: return wild && bracket == 0 && brace == 0;
1.1 deraadt 398: }
399:
400: /*-
401: *-----------------------------------------------------------------------
402: * DirMatchFiles --
403: * Given a pattern and a Path structure, see if any files
404: * match the pattern and add their names to the 'expansions' list if
405: * any do. This is incomplete -- it doesn't take care of patterns like
406: * src / *src / *.c properly (just *.c on any of the directories), but it
407: * will do for now.
408: *
409: * Side Effects:
410: * File names are added to the expansions lst. The directory will be
411: * fully hashed when this is done.
412: *-----------------------------------------------------------------------
413: */
1.26 espie 414: static void
1.1 deraadt 415: DirMatchFiles (pattern, p, expansions)
416: char *pattern; /* Pattern to look for */
417: Path *p; /* Directory to search */
418: Lst expansions; /* Place to store the results */
419: {
1.26 espie 420: unsigned int search; /* Index into the directory's table */
421: char *entry; /* Current entry in the table */
1.1 deraadt 422: Boolean isDot; /* TRUE if the directory being searched is . */
1.6 millert 423:
1.1 deraadt 424: isDot = (*p->name == '.' && p->name[1] == '\0');
1.6 millert 425:
1.30 ! espie 426: for (entry = ohash_first(&p->files, &search); entry != NULL;
! 427: entry = ohash_next(&p->files, &search)) {
1.26 espie 428: /* See if the file matches the given pattern. Note we follow the UNIX
1.1 deraadt 429: * convention that dot files will only be found if the pattern
430: * begins with a dot (note also that as a side effect of the hashing
1.26 espie 431: * scheme, .* won't match . or .. since they aren't hashed). */
432: if (*pattern != '.' && * entry == '.')
433: continue;
434: if (Str_Match(entry, pattern))
1.13 espie 435: Lst_AtEnd(expansions,
1.26 espie 436: (isDot ? estrdup(entry) :
437: str_concat(p->name, entry, '/')));
1.1 deraadt 438: }
439: }
440:
441: /*-
442: *-----------------------------------------------------------------------
443: * DirExpandCurly --
444: * Expand curly braces like the C shell. Does this recursively.
445: * Note the special case: if after the piece of the curly brace is
446: * done there are no wildcard characters in the result, the result is
447: * placed on the list WITHOUT CHECKING FOR ITS EXISTENCE.
448: *
449: * Results:
450: * None.
451: *
452: * Side Effects:
453: * The given list is filled with the expansions...
454: *
455: *-----------------------------------------------------------------------
456: */
457: static void
458: DirExpandCurly(word, brace, path, expansions)
459: char *word; /* Entire word to expand */
460: char *brace; /* First curly brace in it */
461: Lst path; /* Search path to use */
462: Lst expansions; /* Place to store the expansions */
463: {
464: char *end; /* Character after the closing brace */
465: char *cp; /* Current position in brace clause */
466: char *start; /* Start of current piece of brace clause */
467: int bracelevel; /* Number of braces we've seen. If we see a
468: * right brace when this is 0, we've hit the
469: * end of the clause. */
470: char *file; /* Current expansion */
471: int otherLen; /* The length of the other pieces of the
472: * expansion (chars before and after the
473: * clause in 'word') */
474: char *cp2; /* Pointer for checking for wildcards in
475: * expansion before calling Dir_Expand */
476:
477: start = brace+1;
478:
479: /*
480: * Find the end of the brace clause first, being wary of nested brace
481: * clauses.
482: */
483: for (end = start, bracelevel = 0; *end != '\0'; end++) {
484: if (*end == '{') {
485: bracelevel++;
486: } else if ((*end == '}') && (bracelevel-- == 0)) {
487: break;
488: }
489: }
490: if (*end == '\0') {
491: Error("Unterminated {} clause \"%s\"", start);
492: return;
493: } else {
494: end++;
495: }
496: otherLen = brace - word + strlen(end);
497:
498: for (cp = start; cp < end; cp++) {
499: /*
500: * Find the end of this piece of the clause.
501: */
502: bracelevel = 0;
503: while (*cp != ',') {
504: if (*cp == '{') {
505: bracelevel++;
506: } else if ((*cp == '}') && (bracelevel-- <= 0)) {
507: break;
508: }
509: cp++;
510: }
511: /*
512: * Allocate room for the combination and install the three pieces.
513: */
514: file = emalloc(otherLen + cp - start + 1);
515: if (brace != word) {
516: strncpy(file, word, brace-word);
517: }
518: if (cp != start) {
519: strncpy(&file[brace-word], start, cp-start);
520: }
521: strcpy(&file[(brace-word)+(cp-start)], end);
522:
523: /*
524: * See if the result has any wildcards in it. If we find one, call
525: * Dir_Expand right away, telling it to place the result on our list
526: * of expansions.
527: */
528: for (cp2 = file; *cp2 != '\0'; cp2++) {
529: switch(*cp2) {
530: case '*':
531: case '?':
532: case '{':
533: case '[':
534: Dir_Expand(file, path, expansions);
535: goto next;
536: }
537: }
538: if (*cp2 == '\0') {
539: /*
540: * Hit the end w/o finding any wildcards, so stick the expansion
541: * on the end of the list.
542: */
1.13 espie 543: Lst_AtEnd(expansions, file);
1.1 deraadt 544: } else {
545: next:
546: free(file);
547: }
548: start = cp+1;
549: }
550: }
551:
552:
553: /*-
554: *-----------------------------------------------------------------------
555: * DirExpandInt --
556: * Internal expand routine. Passes through the directories in the
557: * path one by one, calling DirMatchFiles for each. NOTE: This still
558: * doesn't handle patterns in directories...
559: *
560: * Side Effects:
561: * Things are added to the expansions list.
562: *
563: *-----------------------------------------------------------------------
564: */
565: static void
566: DirExpandInt(word, path, expansions)
567: char *word; /* Word to expand */
568: Lst path; /* Path on which to look */
569: Lst expansions; /* Place to store the result */
570: {
571: LstNode ln; /* Current node */
572: Path *p; /* Directory in the node */
573:
1.22 espie 574: Lst_Open(path);
575: while ((ln = Lst_Next(path)) != NULL) {
576: p = (Path *)Lst_Datum(ln);
577: DirMatchFiles(word, p, expansions);
1.1 deraadt 578: }
1.22 espie 579: Lst_Close(path);
1.1 deraadt 580: }
581:
582: /*-
583: *-----------------------------------------------------------------------
584: * DirPrintWord --
1.18 espie 585: * Print a word in the list of expansions, followed by a space.
586: * Callback for Dir_Expand when DEBUG(DIR), via Lst_ForEach.
1.1 deraadt 587: *-----------------------------------------------------------------------
588: */
1.18 espie 589: static void
590: DirPrintWord(word)
1.19 espie 591: void *word;
1.1 deraadt 592: {
1.18 espie 593: printf("%s ", (char *)word);
1.1 deraadt 594: }
595:
596: /*-
597: *-----------------------------------------------------------------------
598: * Dir_Expand --
599: * Expand the given word into a list of words by globbing it looking
600: * in the directories on the given search path.
601: *
602: * Results:
603: * A list of words consisting of the files which exist along the search
604: * path matching the given pattern.
605: *
606: * Side Effects:
607: * Directories may be opened. Who knows?
608: *-----------------------------------------------------------------------
609: */
610: void
611: Dir_Expand (word, path, expansions)
612: char *word; /* the word to expand */
613: Lst path; /* the list of directories in which to find
614: * the resulting files */
615: Lst expansions; /* the list on which to place the results */
616: {
617: char *cp;
618:
619: if (DEBUG(DIR)) {
620: printf("expanding \"%s\"...", word);
621: }
1.6 millert 622:
1.1 deraadt 623: cp = strchr(word, '{');
624: if (cp) {
625: DirExpandCurly(word, cp, path, expansions);
626: } else {
627: cp = strchr(word, '/');
628: if (cp) {
629: /*
630: * The thing has a directory component -- find the first wildcard
631: * in the string.
632: */
633: for (cp = word; *cp; cp++) {
634: if (*cp == '?' || *cp == '[' || *cp == '*' || *cp == '{') {
635: break;
636: }
637: }
638: if (*cp == '{') {
1.21 espie 639: /* This one will be fun. */
1.1 deraadt 640: DirExpandCurly(word, cp, path, expansions);
641: return;
642: } else if (*cp != '\0') {
1.21 espie 643: /* Back up to the start of the component. */
1.1 deraadt 644: char *dirpath;
645:
1.21 espie 646: while (cp > word && *cp != '/')
1.1 deraadt 647: cp--;
648: if (cp != word) {
649: char sc;
650: /*
651: * If the glob isn't in the first component, try and find
652: * all the components up to the one with a wildcard.
653: */
654: sc = cp[1];
655: cp[1] = '\0';
656: dirpath = Dir_FindFile(word, path);
657: cp[1] = sc;
658: /*
659: * dirpath is null if can't find the leading component
660: * XXX: Dir_FindFile won't find internal components.
661: * i.e. if the path contains ../Etc/Object and we're
662: * looking for Etc, it won't be found. Ah well.
663: * Probably not important.
664: */
1.21 espie 665: if (dirpath != NULL) {
666: LIST temp;
667:
1.1 deraadt 668: char *dp = &dirpath[strlen(dirpath) - 1];
669: if (*dp == '/')
670: *dp = '\0';
1.21 espie 671: Lst_Init(&temp);
1.25 espie 672: Dir_AddDir(&temp, dirpath, NULL);
1.21 espie 673: DirExpandInt(cp+1, &temp, expansions);
674: Lst_Destroy(&temp, NOFREE);
1.1 deraadt 675: }
1.21 espie 676: } else
677: /* Start the search from the local directory. */
1.1 deraadt 678: DirExpandInt(word, path, expansions);
1.21 espie 679: } else
680: /* Return the file -- this should never happen. */
1.1 deraadt 681: DirExpandInt(word, path, expansions);
682: } else {
1.21 espie 683: /* First the files in dot. */
1.1 deraadt 684: DirMatchFiles(word, dot, expansions);
1.6 millert 685:
1.21 espie 686: /* Then the files in every other directory on the path. */
1.1 deraadt 687: DirExpandInt(word, path, expansions);
688: }
689: }
690: if (DEBUG(DIR)) {
1.18 espie 691: Lst_Every(expansions, DirPrintWord);
1.1 deraadt 692: fputc('\n', stdout);
693: }
694: }
695:
696: /*-
697: *-----------------------------------------------------------------------
698: * Dir_FindFile --
699: * Find the file with the given name along the given search path.
700: *
701: * Results:
702: * The path to the file or NULL. This path is guaranteed to be in a
703: * different part of memory than name and so may be safely free'd.
704: *
705: * Side Effects:
706: * If the file is found in a directory which is not on the path
707: * already (either 'name' is absolute or it is a relative path
708: * [ dir1/.../dirn/file ] which exists below one of the directories
709: * already on the search path), its directory is added to the end
710: * of the path on the assumption that there will be more files in
711: * that directory later on. Sometimes this is true. Sometimes not.
712: *-----------------------------------------------------------------------
713: */
714: char *
1.26 espie 715: Dir_FindFile(name, path)
1.1 deraadt 716: char *name; /* the file to find */
717: Lst path; /* the Lst of directories to search */
718: {
719: register char *p1; /* pointer into p->name */
720: register char *p2; /* pointer into name */
721: LstNode ln; /* a list element */
722: register char *file; /* the current filename to check */
723: register Path *p; /* current path member */
724: register char *cp; /* index of first slash, if any */
725: Boolean hasSlash; /* true if 'name' contains a / */
726: struct stat stb; /* Buffer for stat, if necessary */
1.27 espie 727: struct file_stamp
728: *entry; /* Entry for mtimes table */
1.26 espie 729: const char *e;
730: u_int32_t hv;
1.6 millert 731:
1.1 deraadt 732: /*
733: * Find the final component of the name and note whether it has a
734: * slash in it (the name, I mean)
735: */
1.26 espie 736: cp = strrchr(name, '/');
1.1 deraadt 737: if (cp) {
738: hasSlash = TRUE;
739: cp += 1;
740: } else {
741: hasSlash = FALSE;
742: cp = name;
743: }
1.6 millert 744:
1.26 espie 745: e = NULL;
1.30 ! espie 746: hv = ohash_interval(cp, &e);
1.26 espie 747:
1.1 deraadt 748: if (DEBUG(DIR)) {
749: printf("Searching for %s...", name);
750: }
751: /*
752: * No matter what, we always look for the file in the current directory
753: * before anywhere else and we *do not* add the ./ to it if it exists.
754: * This is so there are no conflicts between what the user specifies
755: * (fish.c) and what pmake finds (./fish.c).
756: */
757: if ((!hasSlash || (cp - name == 2 && *name == '.')) &&
1.26 espie 758: find_file_hash(dot, cp, e, hv) != NULL) {
759: if (DEBUG(DIR))
1.1 deraadt 760: printf("in '.'\n");
761: hits += 1;
762: dot->hits += 1;
1.5 briggs 763: return (estrdup (name));
1.1 deraadt 764: }
1.6 millert 765:
1.1 deraadt 766: /*
767: * We look through all the directories on the path seeking one which
768: * contains the final component of the given name and whose final
769: * component(s) match the name's initial component(s). If such a beast
770: * is found, we concatenate the directory name and the final component
771: * and return the resulting string. If we don't find any such thing,
772: * we go on to phase two...
773: */
1.26 espie 774: for (ln = Lst_First(path); ln != NULL; ln = Lst_Adv(ln)) {
1.22 espie 775: p = (Path *)Lst_Datum(ln);
1.26 espie 776: if (DEBUG(DIR))
1.1 deraadt 777: printf("%s...", p->name);
1.26 espie 778: if (find_file_hash(p, cp, e, hv) != NULL) {
779: if (DEBUG(DIR))
1.1 deraadt 780: printf("here...");
781: if (hasSlash) {
782: /*
783: * If the name had a slash, its initial components and p's
784: * final components must match. This is false if a mismatch
785: * is encountered before all of the initial components
786: * have been checked (p2 > name at the end of the loop), or
787: * we matched only part of one of the components of p
788: * along with all the rest of them (*p1 != '/').
789: */
790: p1 = p->name + strlen (p->name) - 1;
791: p2 = cp - 2;
792: while (p2 >= name && p1 >= p->name && *p1 == *p2) {
793: p1 -= 1; p2 -= 1;
794: }
795: if (p2 >= name || (p1 >= p->name && *p1 != '/')) {
1.26 espie 796: if (DEBUG(DIR))
1.1 deraadt 797: printf("component mismatch -- continuing...");
798: continue;
799: }
800: }
1.23 espie 801: file = str_concat(p->name, cp, '/');
1.26 espie 802: if (DEBUG(DIR))
1.1 deraadt 803: printf("returning %s\n", file);
804: p->hits += 1;
805: hits += 1;
1.26 espie 806: return file;
1.1 deraadt 807: } else if (hasSlash) {
1.26 espie 808: /* If the file has a leading path component and that component
1.1 deraadt 809: * exactly matches the entire name of the current search
1.26 espie 810: * directory, we assume the file doesn't exist and return NULL. */
1.1 deraadt 811: for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) {
812: continue;
813: }
814: if (*p1 == '\0' && p2 == cp - 1) {
1.26 espie 815: if (DEBUG(DIR))
1.1 deraadt 816: printf("must be here but isn't -- returing NULL\n");
1.26 espie 817: return NULL;
1.1 deraadt 818: }
819: }
820: }
1.6 millert 821:
1.26 espie 822: /* We didn't find the file on any existing members of the directory.
1.1 deraadt 823: * If the name doesn't contain a slash, that means it doesn't exist.
824: * If it *does* contain a slash, however, there is still hope: it
825: * could be in a subdirectory of one of the members of the search
826: * path. (eg. /usr/include and sys/types.h. The above search would
827: * fail to turn up types.h in /usr/include, but it *is* in
828: * /usr/include/sys/types.h) If we find such a beast, we assume there
829: * will be more (what else can we assume?) and add all but the last
830: * component of the resulting name onto the search path (at the
1.26 espie 831: * end). This phase is only performed if the file is *not* absolute. */
1.1 deraadt 832: if (!hasSlash) {
1.26 espie 833: if (DEBUG(DIR))
1.1 deraadt 834: printf("failed.\n");
835: misses += 1;
1.26 espie 836: return NULL;
1.1 deraadt 837: }
1.6 millert 838:
1.1 deraadt 839: if (*name != '/') {
840: Boolean checkedDot = FALSE;
1.6 millert 841:
1.26 espie 842: if (DEBUG(DIR))
1.1 deraadt 843: printf("failed. Trying subdirectories...");
1.22 espie 844: Lst_Open(path);
1.26 espie 845: for (ln = Lst_First(path); ln != NULL; ln = Lst_Adv(ln)) {
1.22 espie 846: p = (Path *)Lst_Datum(ln);
1.26 espie 847: if (p != dot)
1.23 espie 848: file = str_concat(p->name, name, '/');
1.26 espie 849: else {
850: /* Checking in dot -- DON'T put a leading ./ on the thing. */
1.5 briggs 851: file = estrdup(name);
1.1 deraadt 852: checkedDot = TRUE;
853: }
1.26 espie 854: if (DEBUG(DIR))
1.1 deraadt 855: printf("checking %s...", file);
1.6 millert 856:
1.26 espie 857: if (stat(file, &stb) == 0) {
1.27 espie 858: TIMESTAMP mtime;
859:
860: grab_stat(stb, mtime);
1.26 espie 861: if (DEBUG(DIR))
1.1 deraadt 862: printf("got it.\n");
1.6 millert 863:
1.26 espie 864: /* We've found another directory to search. We know there's
865: * a slash in 'file' because we put one there. We call
866: * Dir_AddDir to add this new directory onto the existing
867: * search path. Once that's done, we return the file name,
868: * knowing that should a file in this directory ever be
869: * referenced again in such a manner, we will find it
870: * without having to do numerous access calls. Hurrah! */
1.25 espie 871: cp = strrchr(file, '/');
872: Dir_AddDir(path, file, cp);
1.6 millert 873:
1.26 espie 874: /* Save the modification time so if it's needed, we don't have
875: * to fetch it again. */
876: if (DEBUG(DIR))
1.29 espie 877: printf("Caching %s for %s\n", Targ_FmtTime(mtime),
1.1 deraadt 878: file);
1.27 espie 879: record_stamp(file, mtime);
1.1 deraadt 880: nearmisses += 1;
1.26 espie 881: return file;
882: } else
883: free(file);
1.1 deraadt 884: }
1.6 millert 885:
1.26 espie 886: if (DEBUG(DIR))
1.1 deraadt 887: printf("failed. ");
888: if (checkedDot) {
1.26 espie 889: /* Already checked by the given name, since . was in the path,
890: * so no point in proceeding... */
891: if (DEBUG(DIR))
1.1 deraadt 892: printf("Checked . already, returning NULL\n");
1.26 espie 893: return NULL;
1.1 deraadt 894: }
895: }
1.6 millert 896:
1.26 espie 897: /* Didn't find it that way, either. Sigh. Phase 3. Add its directory
1.1 deraadt 898: * onto the search path in any case, just in case, then look for the
899: * thing in the hash table. If we find it, grand. We return a new
900: * copy of the name. Otherwise we sadly return a NULL pointer. Sigh.
901: * Note that if the directory holding the file doesn't exist, this will
902: * do an extra search of the final directory on the path. Unless something
903: * weird happens, this search won't succeed and life will be groovy.
904: *
905: * Sigh. We cannot add the directory onto the search path because
906: * of this amusing case:
907: * $(INSTALLDIR)/$(FILE): $(FILE)
908: *
909: * $(FILE) exists in $(INSTALLDIR) but not in the current one.
910: * When searching for $(FILE), we will find it in $(INSTALLDIR)
1.26 espie 911: * b/c we added it here. This is not good... */
1.1 deraadt 912: #ifdef notdef
1.25 espie 913: Dir_AddDir(path, name, cp-1);
1.6 millert 914:
1.1 deraadt 915: bigmisses += 1;
1.22 espie 916: ln = Lst_Last(path);
917: if (ln == NULL)
918: return NULL;
919: else
920: p = (Path *)Lst_Datum(ln);
1.6 millert 921:
1.26 espie 922: if (find_file_hash(p, cp, e, hv) != NULL)
923: return estrdup (name);
924: else
925: return NULL;
1.1 deraadt 926: #else /* !notdef */
1.26 espie 927: if (DEBUG(DIR))
1.1 deraadt 928: printf("Looking for \"%s\"...", name);
1.6 millert 929:
1.1 deraadt 930: bigmisses += 1;
1.27 espie 931: entry = find_stamp(name);
932: if (entry != NULL) {
1.26 espie 933: if (DEBUG(DIR))
1.1 deraadt 934: printf("got it (in mtime cache)\n");
1.26 espie 935: return estrdup(name);
936: } else if (stat(name, &stb) == 0) {
1.27 espie 937: TIMESTAMP mtime;
938:
939: grab_stat(stb, mtime);
1.26 espie 940: if (DEBUG(DIR))
1.29 espie 941: printf("Caching %s for %s\n", Targ_FmtTime(mtime),
1.1 deraadt 942: name);
1.27 espie 943: record_stamp(name, mtime);
1.26 espie 944: return estrdup(name);
1.1 deraadt 945: } else {
1.26 espie 946: if (DEBUG(DIR))
1.1 deraadt 947: printf("failed. Returning NULL\n");
1.26 espie 948: return NULL;
1.1 deraadt 949: }
950: #endif /* notdef */
951: }
952:
953: /*-
954: *-----------------------------------------------------------------------
955: * Dir_MTime --
956: * Find the modification time of the file described by gn along the
957: * search path dirSearchPath.
1.6 millert 958: *
1.1 deraadt 959: * Results:
1.27 espie 960: * The modification time or OUT_OF_DATE if it doesn't exist
1.1 deraadt 961: *
962: * Side Effects:
963: * The modification time is placed in the node's mtime slot.
964: * If the node didn't have a path entry before, and Dir_FindFile
965: * found one for it, the full name is placed in the path slot.
966: *-----------------------------------------------------------------------
967: */
1.27 espie 968: TIMESTAMP
1.20 espie 969: Dir_MTime(gn)
1.1 deraadt 970: GNode *gn; /* the file whose modification time is
971: * desired */
972: {
973: char *fullName; /* the full pathname of name */
974: struct stat stb; /* buffer for finding the mod time */
1.27 espie 975: struct file_stamp
976: *entry;
977: unsigned int slot;
978: TIMESTAMP mtime;
1.6 millert 979:
1.20 espie 980: if (gn->type & OP_ARCHV)
981: return Arch_MTime(gn);
1.27 espie 982: if (gn->path == NULL) {
1.20 espie 983: fullName = Dir_FindFile(gn->name, &dirSearchPath);
1.27 espie 984: if (fullName == NULL)
985: fullName = estrdup(gn->name);
986: } else
1.1 deraadt 987: fullName = gn->path;
1.6 millert 988:
1.30 ! espie 989: slot = ohash_qlookup(&mtimes, fullName);
! 990: entry = ohash_find(&mtimes, slot);
1.27 espie 991: if (entry != NULL) {
992: /* Only do this once -- the second time folks are checking to
1.1 deraadt 993: * see if the file was actually updated, so we need to actually go
1.27 espie 994: * to the file system. */
995: if (DEBUG(DIR))
1.1 deraadt 996: printf("Using cached time %s for %s\n",
1.27 espie 997: Targ_FmtTime(entry->mtime), fullName);
998: mtime = entry->mtime;
999: free(entry);
1.30 ! espie 1000: ohash_remove(&mtimes, slot);
1.27 espie 1001: } else if (stat(fullName, &stb) == 0)
1002: grab_stat(stb, mtime);
1003: else {
1.1 deraadt 1004: if (gn->type & OP_MEMBER) {
1005: if (fullName != gn->path)
1006: free(fullName);
1.29 espie 1007: return Arch_MemMTime(gn);
1.27 espie 1008: } else
1009: set_out_of_date(mtime);
1.1 deraadt 1010: }
1.27 espie 1011: if (fullName && gn->path == NULL)
1.1 deraadt 1012: gn->path = fullName;
1.6 millert 1013:
1.27 espie 1014: gn->mtime = mtime;
1015: return gn->mtime;
1.1 deraadt 1016: }
1017:
1.25 espie 1018: /* Read a directory, either from the disk, or from the cache. */
1019: static Path *
1020: DirReaddir(name, end)
1021: const char *name;
1022: const char *end;
1023: {
1024: Path *p; /* pointer to new Path structure */
1025: DIR *d; /* for reading directory */
1026: struct dirent *dp; /* entry in directory */
1027: unsigned int slot;
1028:
1.30 ! espie 1029: slot = ohash_qlookupi(&openDirectories, name, &end);
! 1030: p = ohash_find(&openDirectories, slot);
1.25 espie 1031:
1032: if (p != NULL)
1033: return p;
1034:
1.30 ! espie 1035: p = ohash_create_entry(&dir_info, name, &end);
1.25 espie 1036: p->hits = 0;
1037: p->refCount = 0;
1.30 ! espie 1038: ohash_init(&p->files, 4, &file_info);
1.25 espie 1039:
1040: if (DEBUG(DIR)) {
1041: printf("Caching %s...", p->name);
1042: fflush(stdout);
1043: }
1044:
1045: if ((d = opendir(p->name)) == NULL)
1046: return NULL;
1047: /* Skip the first two entries -- these will *always* be . and .. */
1048: (void)readdir(d);
1049: (void)readdir(d);
1050:
1051: while ((dp = readdir(d)) != NULL) {
1052: #if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */
1053: /* The sun directory library doesn't check for a 0 inode
1054: * (0-inode slots just take up space), so we have to do
1055: * it ourselves. */
1056: if (dp->d_fileno == 0)
1057: continue;
1058: #endif /* sun && d_ino */
1.26 espie 1059: add_file(p, dp->d_name);
1.25 espie 1060: }
1061: (void)closedir(d);
1062: if (DEBUG(DIR))
1063: printf("done\n");
1064:
1.30 ! espie 1065: ohash_insert(&openDirectories, slot, p);
1.25 espie 1066: return p;
1067: }
1068:
1.1 deraadt 1069: /*-
1070: *-----------------------------------------------------------------------
1071: * Dir_AddDir --
1072: * Add the given name to the end of the given path. The order of
1073: * the arguments is backwards so ParseDoDependency can do a
1074: * Lst_ForEach of its list of paths...
1075: *
1076: * Side Effects:
1.6 millert 1077: * A structure is added to the list and the directory is
1.1 deraadt 1078: * read and hashed.
1079: *-----------------------------------------------------------------------
1080: */
1081: void
1.25 espie 1082: Dir_AddDir(path, name, end)
1083: Lst path; /* the path to which the directory should be
1084: * added */
1085: const char *name; /* the name of the directory to add */
1086: const char *end;
1.1 deraadt 1087: {
1.25 espie 1088: Path *p; /* pointer to new Path structure */
1.6 millert 1089:
1.25 espie 1090: p = DirReaddir(name, end);
1091: if (p == NULL)
1092: return;
1093: if (p->refCount == 0)
1094: Lst_AtEnd(path, p);
1095: else if (Lst_Member(path, p) != NULL)
1096: return;
1097: else
1098: Lst_AtEnd(path, p);
1099: p->refCount++;
1.1 deraadt 1100: }
1101:
1102: /*-
1103: *-----------------------------------------------------------------------
1104: * Dir_CopyDir --
1105: * Callback function for duplicating a search path via Lst_Duplicate.
1106: * Ups the reference count for the directory.
1107: *
1108: * Results:
1109: * Returns the Path it was given.
1110: *
1111: * Side Effects:
1112: * The refCount of the path is incremented.
1113: *
1114: *-----------------------------------------------------------------------
1115: */
1.19 espie 1116: void *
1.1 deraadt 1117: Dir_CopyDir(p)
1.19 espie 1118: void *p;
1.1 deraadt 1119: {
1.19 espie 1120: ((Path *)p)->refCount += 1;
1.1 deraadt 1121:
1.17 espie 1122: return p;
1.1 deraadt 1123: }
1124:
1125: /*-
1126: *-----------------------------------------------------------------------
1127: * Dir_MakeFlags --
1128: * Make a string by taking all the directories in the given search
1129: * path and preceding them by the given flag. Used by the suffix
1130: * module to create variables for compilers based on suffix search
1131: * paths.
1132: *
1133: * Results:
1134: * The string mentioned above. Note that there is no space between
1135: * the given flag and each directory. The empty string is returned if
1136: * Things don't go well.
1137: *
1138: * Side Effects:
1139: * None
1140: *-----------------------------------------------------------------------
1141: */
1142: char *
1.22 espie 1143: Dir_MakeFlags(flag, path)
1.1 deraadt 1144: char *flag; /* flag which should precede each directory */
1145: Lst path; /* list of directories */
1146: {
1147: LstNode ln; /* the node of the current directory */
1.23 espie 1148: BUFFER buf;
1.6 millert 1149:
1.23 espie 1150: Buf_Init(&buf, 0);
1.6 millert 1151:
1.23 espie 1152: for (ln = Lst_First(path); ln != NULL; ln = Lst_Adv(ln)) {
1153: Buf_AddString(&buf, flag);
1154: Buf_AddString(&buf, ((Path *)Lst_Datum(ln))->name);
1155: Buf_AddSpace(&buf);
1.1 deraadt 1156: }
1.6 millert 1157:
1.23 espie 1158: return Buf_Retrieve(&buf);
1.1 deraadt 1159: }
1160:
1161: /*-
1162: *-----------------------------------------------------------------------
1163: * Dir_Destroy --
1164: * Nuke a directory descriptor, if possible. Callback procedure
1165: * for the suffixes module when destroying a search path.
1166: *
1167: * Results:
1168: * None.
1169: *
1170: * Side Effects:
1171: * If no other path references this directory (refCount == 0),
1172: * the Path and all its data are freed.
1173: *
1174: *-----------------------------------------------------------------------
1175: */
1176: void
1177: Dir_Destroy (pp)
1.19 espie 1178: void *pp; /* The directory descriptor to nuke */
1.1 deraadt 1179: {
1180: Path *p = (Path *) pp;
1181:
1.25 espie 1182: if (--p->refCount == 0) {
1.30 ! espie 1183: ohash_remove(&openDirectories, ohash_qlookup(&openDirectories, p->name));
1.26 espie 1184: free_hash(&p->files);
1.19 espie 1185: free(p);
1.1 deraadt 1186: }
1187: }
1188:
1189: /*-
1190: *-----------------------------------------------------------------------
1191: * Dir_ClearPath --
1192: * Clear out all elements of the given search path. This is different
1193: * from destroying the list, notice.
1194: *
1195: * Results:
1196: * None.
1197: *
1198: * Side Effects:
1199: * The path is set to the empty list.
1200: *
1201: *-----------------------------------------------------------------------
1202: */
1203: void
1204: Dir_ClearPath(path)
1205: Lst path; /* Path to clear */
1206: {
1207: Path *p;
1.12 espie 1208: while ((p = (Path *)Lst_DeQueue(path)) != NULL)
1.17 espie 1209: Dir_Destroy(p);
1.1 deraadt 1210: }
1.6 millert 1211:
1.1 deraadt 1212:
1213: /*-
1214: *-----------------------------------------------------------------------
1215: * Dir_Concat --
1216: * Concatenate two paths, adding the second to the end of the first.
1217: * Makes sure to avoid duplicates.
1218: *
1219: * Results:
1220: * None
1221: *
1222: * Side Effects:
1223: * Reference counts for added dirs are upped.
1224: *
1225: *-----------------------------------------------------------------------
1226: */
1227: void
1228: Dir_Concat(path1, path2)
1229: Lst path1; /* Dest */
1230: Lst path2; /* Source */
1231: {
1232: LstNode ln;
1233: Path *p;
1234:
1.22 espie 1235: for (ln = Lst_First(path2); ln != NULL; ln = Lst_Adv(ln)) {
1.1 deraadt 1236: p = (Path *)Lst_Datum(ln);
1.17 espie 1237: if (Lst_Member(path1, p) == NULL) {
1.1 deraadt 1238: p->refCount += 1;
1.17 espie 1239: Lst_AtEnd(path1, p);
1.1 deraadt 1240: }
1241: }
1242: }
1243:
1244: /********** DEBUG INFO **********/
1245: void
1246: Dir_PrintDirectories()
1247: {
1248: Path *p;
1.25 espie 1249: unsigned int i;
1.6 millert 1250:
1.1 deraadt 1251: printf ("#*** Directory Cache:\n");
1252: printf ("# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n",
1253: hits, misses, nearmisses, bigmisses,
1254: (hits+bigmisses+nearmisses ?
1255: hits * 100 / (hits + bigmisses + nearmisses) : 0));
1256: printf ("# %-20s referenced\thits\n", "directory");
1.30 ! espie 1257: for (p = ohash_first(&openDirectories, &i); p != NULL;
! 1258: p = ohash_next(&openDirectories, &i))
1.25 espie 1259: printf("# %-20s %10d\t%4d\n", p->name, p->refCount, p->hits);
1.1 deraadt 1260: }
1261:
1.19 espie 1262: static void
1263: DirPrintDir(p)
1264: void *p;
1.6 millert 1265: {
1.18 espie 1266: printf("%s ", ((Path *)p)->name);
1.1 deraadt 1267: }
1268:
1269: void
1.18 espie 1270: Dir_PrintPath(path)
1.1 deraadt 1271: Lst path;
1272: {
1.18 espie 1273: Lst_Every(path, DirPrintDir);
1.29 espie 1274: }
1275:
1276: #ifndef USE_TIMESPEC
1277: #include <sys/types.h>
1278: #include <utime.h>
1279: #endif
1280: int
1281: set_times(f)
1282: const char *f;
1283: {
1284: #ifdef USE_TIMESPEC
1285: struct timeval tv[2];
1286:
1287: TIMESPEC_TO_TIMEVAL(&tv[0], &now);
1288: TIMESPEC_TO_TIMEVAL(&tv[1], &now);
1289: return utimes(f, tv);
1290: #else
1291: struct utimbuf times;
1292:
1293: times.actime = times.modtime = now;
1294: return utime(f, ×);
1295: #endif
1.1 deraadt 1296: }