44#include "fscache.h"
55#include "../../dir.h"
66#include "../../abspath.h"
7+ #include "../../trace.h"
78
89static int initialized ;
910static volatile long enabled ;
1011static struct hashmap map ;
1112static CRITICAL_SECTION mutex ;
13+ static struct trace_key trace_fscache = TRACE_KEY_INIT (FSCACHE );
1214
1315/*
1416 * An entry in the file system cache. Used for both entire directory listings
@@ -179,7 +181,8 @@ static struct fsentry *fseentry_create_entry(struct fsentry *list,
179181 * Dir should not contain trailing '/'. Use an empty string for the current
180182 * directory (not "."!).
181183 */
182- static struct fsentry * fsentry_create_list (const struct fsentry * dir )
184+ static struct fsentry * fsentry_create_list (const struct fsentry * dir ,
185+ int * dir_not_found )
183186{
184187 wchar_t pattern [MAX_PATH + 2 ]; /* + 2 for '/' '*' */
185188 WIN32_FIND_DATAW fdata ;
@@ -188,6 +191,8 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
188191 struct fsentry * list , * * phead ;
189192 DWORD err ;
190193
194+ * dir_not_found = 0 ;
195+
191196 /* convert name to UTF-16 and check length < MAX_PATH */
192197 if ((wlen = xutftowcsn (pattern , dir -> dirent .d_name , MAX_PATH ,
193198 dir -> len )) < 0 ) {
@@ -206,12 +211,17 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
206211 h = FindFirstFileW (pattern , & fdata );
207212 if (h == INVALID_HANDLE_VALUE ) {
208213 err = GetLastError ();
214+ * dir_not_found = 1 ; /* or empty directory */
209215 errno = (err == ERROR_DIRECTORY ) ? ENOTDIR : err_win_to_posix (err );
216+ trace_printf_key (& trace_fscache , "fscache: error(%d) '%s'\n" ,
217+ errno , dir -> dirent .d_name );
210218 return NULL ;
211219 }
212220
213221 /* allocate object to hold directory listing */
214222 list = fsentry_alloc (NULL , dir -> dirent .d_name , dir -> len );
223+ list -> st_mode = S_IFDIR ;
224+ list -> dirent .d_type = DT_DIR ;
215225
216226 /* walk directory and build linked list of fsentry structures */
217227 phead = & list -> next ;
@@ -296,12 +306,16 @@ static struct fsentry *fscache_get_wait(struct fsentry *key)
296306static struct fsentry * fscache_get (struct fsentry * key )
297307{
298308 struct fsentry * fse , * future , * waiter ;
309+ int dir_not_found ;
299310
300311 EnterCriticalSection (& mutex );
301312 /* check if entry is in cache */
302313 fse = fscache_get_wait (key );
303314 if (fse ) {
304- fsentry_addref (fse );
315+ if (fse -> st_mode )
316+ fsentry_addref (fse );
317+ else
318+ fse = NULL ; /* non-existing directory */
305319 LeaveCriticalSection (& mutex );
306320 return fse ;
307321 }
@@ -310,7 +324,10 @@ static struct fsentry *fscache_get(struct fsentry *key)
310324 fse = fscache_get_wait (key -> list );
311325 if (fse ) {
312326 LeaveCriticalSection (& mutex );
313- /* dir entry without file entry -> file doesn't exist */
327+ /*
328+ * dir entry without file entry, or dir does not
329+ * exist -> file doesn't exist
330+ */
314331 errno = ENOENT ;
315332 return NULL ;
316333 }
@@ -324,7 +341,7 @@ static struct fsentry *fscache_get(struct fsentry *key)
324341
325342 /* create the directory listing (outside mutex!) */
326343 LeaveCriticalSection (& mutex );
327- fse = fsentry_create_list (future );
344+ fse = fsentry_create_list (future , & dir_not_found );
328345 EnterCriticalSection (& mutex );
329346
330347 /* remove future entry and signal waiting threads */
@@ -338,6 +355,18 @@ static struct fsentry *fscache_get(struct fsentry *key)
338355
339356 /* leave on error (errno set by fsentry_create_list) */
340357 if (!fse ) {
358+ if (dir_not_found && key -> list ) {
359+ /*
360+ * Record that the directory does not exist (or is
361+ * empty, which for all practical matters is the same
362+ * thing as far as fscache is concerned).
363+ */
364+ fse = fsentry_alloc (key -> list -> list ,
365+ key -> list -> dirent .d_name ,
366+ key -> list -> len );
367+ fse -> st_mode = 0 ;
368+ hashmap_add (& map , & fse -> ent );
369+ }
341370 LeaveCriticalSection (& mutex );
342371 return NULL ;
343372 }
@@ -349,6 +378,9 @@ static struct fsentry *fscache_get(struct fsentry *key)
349378 if (key -> list )
350379 fse = hashmap_get_entry (& map , key , ent , NULL );
351380
381+ if (fse && !fse -> st_mode )
382+ fse = NULL ; /* non-existing directory */
383+
352384 /* return entry or ENOENT */
353385 if (fse )
354386 fsentry_addref (fse );
@@ -392,6 +424,7 @@ int fscache_enable(int enable)
392424 fscache_clear ();
393425 LeaveCriticalSection (& mutex );
394426 }
427+ trace_printf_key (& trace_fscache , "fscache: enable(%d)\n" , enable );
395428 return result ;
396429}
397430
0 commit comments