Line data Source code
1 : /*
2 : --
3 : -- SYNOPSIS
4 : -- Directory cache management routines.
5 : --
6 : -- DESCRIPTION
7 : -- This is the code that maintains a directory cache for each directory
8 : -- that dmake visits. The entire directory is thus only read once and
9 : -- the need for performing costly 'stat' calls when performing target
10 : -- inference is much reduced. The improvement in performance should be
11 : -- significant for NFS or remote mounted file systems.
12 : --
13 : -- AUTHOR
14 : -- Dennis Vadura, dvadura@dmake.wticorp.com
15 : --
16 : -- WWW
17 : -- http://dmake.wticorp.com/
18 : --
19 : -- COPYRIGHT
20 : -- Copyright (c) 1996,1997 by WTI Corp. All rights reserved.
21 : --
22 : -- This program is NOT free software; you can redistribute it and/or
23 : -- modify it under the terms of the Software License Agreement Provided
24 : -- in the file <distribution-root>/readme/license.txt.
25 : --
26 : -- LOG
27 : -- Use cvs log to obtain detailed change logs.
28 : */
29 :
30 : /* For Borland 5.00 compile, for some reason they seem to insist on pulling
31 : * in the winnt.h if __WIN32__ is defined and you include <dirent.h>. This
32 : * is, in my opinion, a BUG! on Borland's part.
33 : */
34 : #if defined(__BORLANDC__) && defined(__WIN32__)
35 : #undef __WIN32__
36 : #endif
37 :
38 : #ifdef __APPLE__
39 : #include <sys/types.h>
40 : #endif
41 : #include <dirent.h>
42 : #include "extern.h"
43 : #include "sysintf.h"
44 :
45 :
46 : typedef struct ent {
47 : char *name;
48 : uint32 hkey;
49 : time_t mtime;
50 : int isdir;
51 : struct ent *next;
52 : } Entry, *EntryPtr;
53 :
54 :
55 : typedef struct mydir {
56 : char *path;
57 : uint32 hkey;
58 : EntryPtr entries;
59 : struct mydir *next;
60 : } DirEntry, *DirEntryPtr;
61 :
62 : static DirEntryPtr dtab[HASH_TABLE_SIZE];
63 :
64 :
65 : /* Stat a path using the directory cache.
66 : *
67 : * We build a cannonical representation of the path using either an absolute
68 : * path name if that is what 'path' is or the relative path name constructed
69 : * from 'path' and the present value of Pwd.
70 : *
71 : * The present value of Pwd then gives a directory path that we search for
72 : * in our cache using a hash lookup. If the directory component is located
73 : * then we search the basename component of the path and return the result of
74 : * the search: 0L if the component is not in the cache and it's time stamp
75 : * otherwise.
76 : *
77 : * If the directory is not in our cache we insert it into the cache by
78 : * openning the directory and reading all of the files within. Once read
79 : * then we return the result of the above search.
80 : *
81 : * Optionally, if force is TRUE, and we did NOT read the directory to provide
82 : * the result then stat the file anyway and update the internal cache.
83 : */
84 :
85 : PUBLIC time_t
86 37761 : CacheStat(path, force)
87 : char *path;
88 : int force;
89 : {
90 : struct stat stbuf;
91 : DirEntryPtr dp;
92 : EntryPtr ep;
93 : uint32 hkey;
94 : uint16 hv;
95 : char *fpath;
96 : char *spath;
97 : char *comp;
98 : char *dir;
99 : char *udir; /* Hold the unchanged (DcacheRespCase) directory. */
100 37761 : int loaded=FALSE;
101 :
102 37761 : if (If_root_path(path))
103 1464 : spath = path;
104 : else
105 36297 : spath = Build_path(Pwd,path);
106 :
107 37761 : fpath = DmStrDup(spath);
108 :
109 37761 : comp = Basename(fpath); /* Use before the Filedir() call. */
110 37761 : dir = Filedir(fpath);
111 :
112 : /* do caching and comparing lower case if told so. */
113 37761 : if( !STOBOOL(DcacheRespCase) ) {
114 0 : udir = DmStrDup(dir);
115 0 : strlwr(comp);
116 0 : strlwr(dir);
117 : } else
118 37761 : udir = dir;
119 :
120 37761 : hv = Hash(dir,&hkey);
121 :
122 37981 : for(dp=dtab[hv]; dp; dp=dp->next)
123 36553 : if (hkey == dp->hkey && strcmp(dp->path,dir) == 0)
124 36333 : break;
125 :
126 37761 : if (!dp) {
127 : /* Not cached yet, doing it now. */
128 : DIR *dirp;
129 : struct dirent *direntp;
130 :
131 1428 : if( Verbose & V_DIR_CACHE )
132 0 : printf( "%s: Caching directory [%s]\n", Pname, dir );
133 :
134 : /* Load the directory, we have the right hash position already */
135 1428 : loaded = TRUE;
136 :
137 1428 : TALLOC(dp,1,DirEntry);
138 1428 : dp->next = dtab[hv];
139 1428 : dtab[hv] = dp;
140 1428 : dp->path = DmStrDup(dir);
141 1428 : dp->hkey = hkey;
142 :
143 : /* We use the unchanged (not potentially lowercased because of
144 : * DcacheRespCase) directory as this would fail on a case sensitive
145 : * file system.
146 : * Note: Using case insensitive directory caching on case sensitive
147 : * file systems is a *BAD* idea. If in doubt use case sensitive
148 : * directory caching even on case insensitive file systems as the
149 : * worst case in this szenario is that /foo/bar/ and /foo/BAR/ are
150 : * cached separately (with the same content) even though they are
151 : * the same directory. This would only happen if different targets
152 : * using different upper/lower case spellings for the same directory
153 : * and is *never* a good idea. */
154 1428 : if (Set_dir(udir) == 0) {
155 1428 : if((dirp=opendir(".")) != NIL(DIR)) {
156 64849 : while((direntp=readdir(dirp)) != NULL) {
157 61993 : TALLOC(ep,1,Entry);
158 61993 : ep->name = DmStrDup(direntp->d_name); /* basename only */
159 61993 : if( !STOBOOL(DcacheRespCase) )
160 0 : strlwr(ep->name);
161 :
162 61993 : Hash(ep->name, &ep->hkey); /* This sets ep->hkey. */
163 :
164 61993 : ep->next = dp->entries;
165 61993 : dp->entries = ep;
166 61993 : DMSTAT(direntp->d_name,&stbuf);
167 61993 : ep->isdir = (stbuf.st_mode & S_IFDIR);
168 61993 : ep->mtime = stbuf.st_mtime;
169 : }
170 1428 : closedir(dirp);
171 : }
172 1428 : Set_dir(Pwd);
173 : }
174 : }
175 :
176 37761 : Hash(comp, &hkey); /* Calculate hkey. */
177 :
178 : /* search in dp->entries for comp. */
179 37761 : if (dp) {
180 2714212 : for(ep=dp->entries; ep; ep=ep->next)
181 2712493 : if(hkey == ep->hkey && strcmp(ep->name,comp) == 0)
182 36042 : break;
183 : }
184 : else
185 0 : ep = NULL;
186 :
187 37761 : if( force && !loaded) {
188 542 : if (strlen(comp) > NameMax || DMSTAT(spath,&stbuf) != 0) {
189 : /* Either file to long or the stat failed. */
190 542 : if (strlen(comp) > NameMax)
191 0 : Warning( "File [%s] longer than value of NAMEMAX [%d].\n\
192 : Assume unix time 0.\n", comp, NameMax );
193 1084 : if(ep)
194 0 : ep->mtime = 0L;
195 : }
196 : else {
197 0 : if (!ep) {
198 0 : TALLOC(ep,1,Entry);
199 0 : ep->name = DmStrDup(comp);
200 0 : if( !STOBOOL(DcacheRespCase) )
201 0 : strlwr(ep->name);
202 0 : Hash(ep->name, &ep->hkey);
203 0 : ep->next = dp->entries;
204 0 : ep->isdir = (stbuf.st_mode & S_IFDIR);
205 0 : dp->entries = ep;
206 : }
207 :
208 0 : ep->mtime = stbuf.st_mtime;
209 : }
210 :
211 542 : if( Verbose & V_DIR_CACHE )
212 0 : printf("%s: Updating dir cache entry for [%s], new time is %ld\n",
213 : Pname, spath, ep ? ep->mtime : 0L);
214 : }
215 :
216 37761 : if( udir != dir )
217 0 : FREE(udir); /* Keep this before the free of fpath. */
218 :
219 37761 : FREE(fpath);
220 37761 : return(!ep ? (time_t)0L : ((STOBOOL(Augmake) && ep->isdir)?0L:ep->mtime));
221 : }
|