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