1 /* $RCSfile: dcache.c,v $
3 -- last change: $Author: ihi $ $Date: 2007-10-15 15:52:47 $
6 -- Directory cache management routines.
9 -- This is the code that maintains a directory cache for each directory
10 -- that dmake visits. The entire directory is thus only read once and
11 -- the need for performing costly 'stat' calls when performing target
12 -- inference is much reduced. The improvement in performance should be
13 -- significant for NFS or remote mounted file systems.
16 -- Dennis Vadura, dvadura@dmake.wticorp.com
19 -- http://dmake.wticorp.com/
22 -- Copyright (c) 1996,1997 by WTI Corp. All rights reserved.
24 -- This program is NOT free software; you can redistribute it and/or
25 -- modify it under the terms of the Software License Agreement Provided
26 -- in the file <distribution-root>/readme/license.txt.
29 -- Use cvs log to obtain detailed change logs.
32 /* For Borland 5.00 compile, for some reason they seem to insist on pulling
33 * in the winnt.h if __WIN32__ is defined and you include <dirent.h>. This
34 * is, in my opinion, a BUG! on Borland's part.
36 #if defined(__BORLANDC__) && defined(__WIN32__)
41 #include <sys/types.h>
57 typedef struct mydir
{
62 } DirEntry
, *DirEntryPtr
;
64 static DirEntryPtr dtab
[HASH_TABLE_SIZE
];
67 /* Stat a path using the directory cache.
69 * We build a cannonical representation of the path using either an absolute
70 * path name if that is what 'path' is or the relative path name constructed
71 * from 'path' and the present value of Pwd.
73 * The present value of Pwd then gives a directory path that we search for
74 * in our cache using a hash lookup. If the directory component is located
75 * then we search the basename component of the path and return the result of
76 * the search: 0L if the component is not in the cache and it's time stamp
79 * If the directory is not in our cache we insert it into the cache by
80 * openning the directory and reading all of the files within. Once read
81 * then we return the result of the above search.
83 * Optionally, if force is TRUE, and we did NOT read the directory to provide
84 * the result then stat the file anyway and update the internal cache.
88 CacheStat(path
, force
)
101 char *udir
; /* Hold the unchanged (DcacheRespCase) directory. */
104 if (If_root_path(path
))
107 spath
= Build_path(Pwd
,path
);
109 fpath
= DmStrDup(spath
);
111 comp
= Basename(fpath
); /* Use before the Filedir() call. */
112 dir
= Filedir(fpath
);
114 /* do caching and comparing lower case if told so. */
115 if( !STOBOOL(DcacheRespCase
) ) {
116 udir
= DmStrDup(dir
);
122 hv
= Hash(dir
,&hkey
);
124 for(dp
=dtab
[hv
]; dp
; dp
=dp
->next
)
125 if (hkey
== dp
->hkey
&& strcmp(dp
->path
,dir
) == 0)
129 /* Not cached yet, doing it now. */
131 struct dirent
*direntp
;
133 if( Verbose
& V_DIR_CACHE
)
134 printf( "%s: Caching directory [%s]\n", Pname
, dir
);
136 /* Load the directory, we have the right hash position already */
139 TALLOC(dp
,1,DirEntry
);
142 dp
->path
= DmStrDup(dir
);
145 /* We use the unchanged (not potentially lowercased because of
146 * DcacheRespCase) directory as this would fail on a case sensitive
148 * Note: Using case insensitive directory caching on case sensitive
149 * file systems is a *BAD* idea. If in doubt use case sensitive
150 * directory caching even on case insensitive file systems as the
151 * worst case in this szenario is that /foo/bar/ and /foo/BAR/ are
152 * cached separately (with the same content) even though they are
153 * the same directory. This would only happen if different targets
154 * using different upper/lower case spellings for the same directory
155 * and is *never* a good idea. */
156 if (Set_dir(udir
) == 0) {
157 if((dirp
=opendir(".")) != NIL(DIR)) {
158 while((direntp
=readdir(dirp
)) != NULL
) {
160 ep
->name
= DmStrDup(direntp
->d_name
); /* basename only */
161 if( !STOBOOL(DcacheRespCase
) )
164 Hash(ep
->name
, &ep
->hkey
); /* This sets ep->hkey. */
166 ep
->next
= dp
->entries
;
168 DMSTAT(direntp
->d_name
,&stbuf
);
169 ep
->isdir
= (stbuf
.st_mode
& S_IFDIR
);
170 ep
->mtime
= stbuf
.st_mtime
;
178 Hash(comp
, &hkey
); /* Calculate hkey. */
180 /* search in dp->entries for comp. */
182 for(ep
=dp
->entries
; ep
; ep
=ep
->next
)
183 if(hkey
== ep
->hkey
&& strcmp(ep
->name
,comp
) == 0)
189 if( force
&& !loaded
) {
190 if (strlen(comp
) > NameMax
|| DMSTAT(spath
,&stbuf
) != 0) {
191 /* Either file to long or the stat failed. */
192 if (strlen(comp
) > NameMax
)
193 Warning( "File [%s] longer than value of NAMEMAX [%d].\n\
194 Assume unix time 0.\n", comp
, NameMax
);
201 ep
->name
= DmStrDup(comp
);
202 if( !STOBOOL(DcacheRespCase
) )
204 Hash(ep
->name
, &ep
->hkey
);
205 ep
->next
= dp
->entries
;
206 ep
->isdir
= (stbuf
.st_mode
& S_IFDIR
);
210 ep
->mtime
= stbuf
.st_mtime
;
213 if( Verbose
& V_DIR_CACHE
)
214 printf("%s: Updating dir cache entry for [%s], new time is %ld\n",
215 Pname
, spath
, ep
? ep
->mtime
: 0L);
219 FREE(udir
); /* Keep this before the free of fpath. */
222 return(!ep
? (time_t)0L : ((STOBOOL(Augmake
) && ep
->isdir
)?0L:ep
->mtime
));