@@ -7,6 +7,7 @@ static int initialized;
77static volatile long enabled ;
88static struct hashmap map ;
99static CRITICAL_SECTION mutex ;
10+ static struct trace_key trace_fscache = TRACE_KEY_INIT (FSCACHE );
1011
1112/*
1213 * An entry in the file system cache. Used for both entire directory listings
@@ -163,7 +164,8 @@ static struct fsentry *fseentry_create_entry(struct fsentry *list,
163164 * Dir should not contain trailing '/'. Use an empty string for the current
164165 * directory (not "."!).
165166 */
166- static struct fsentry * fsentry_create_list (const struct fsentry * dir )
167+ static struct fsentry * fsentry_create_list (const struct fsentry * dir ,
168+ int * dir_not_found )
167169{
168170 wchar_t pattern [MAX_LONG_PATH + 2 ]; /* + 2 for "\*" */
169171 WIN32_FIND_DATAW fdata ;
@@ -172,6 +174,8 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
172174 struct fsentry * list , * * phead ;
173175 DWORD err ;
174176
177+ * dir_not_found = 0 ;
178+
175179 /* convert name to UTF-16 and check length */
176180 if ((wlen = xutftowcs_path_ex (pattern , dir -> name , MAX_LONG_PATH ,
177181 dir -> len , MAX_PATH - 2 , core_long_paths )) < 0 )
@@ -190,12 +194,16 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
190194 h = FindFirstFileW (pattern , & fdata );
191195 if (h == INVALID_HANDLE_VALUE ) {
192196 err = GetLastError ();
197+ * dir_not_found = 1 ; /* or empty directory */
193198 errno = (err == ERROR_DIRECTORY ) ? ENOTDIR : err_win_to_posix (err );
199+ trace_printf_key (& trace_fscache , "fscache: error(%d) '%.*s'\n" ,
200+ errno , dir -> len , dir -> name );
194201 return NULL ;
195202 }
196203
197204 /* allocate object to hold directory listing */
198205 list = fsentry_alloc (NULL , dir -> name , dir -> len );
206+ list -> st_mode = S_IFDIR ;
199207
200208 /* walk directory and build linked list of fsentry structures */
201209 phead = & list -> next ;
@@ -296,12 +304,16 @@ static struct fsentry *fscache_get_wait(struct fsentry *key)
296304static struct fsentry * fscache_get (struct fsentry * key )
297305{
298306 struct fsentry * fse , * future , * waiter ;
307+ int dir_not_found ;
299308
300309 EnterCriticalSection (& mutex );
301310 /* check if entry is in cache */
302311 fse = fscache_get_wait (key );
303312 if (fse ) {
304- fsentry_addref (fse );
313+ if (fse -> st_mode )
314+ fsentry_addref (fse );
315+ else
316+ fse = NULL ; /* non-existing directory */
305317 LeaveCriticalSection (& mutex );
306318 return fse ;
307319 }
@@ -310,7 +322,10 @@ static struct fsentry *fscache_get(struct fsentry *key)
310322 fse = fscache_get_wait (key -> list );
311323 if (fse ) {
312324 LeaveCriticalSection (& mutex );
313- /* dir entry without file entry -> file doesn't exist */
325+ /*
326+ * dir entry without file entry, or dir does not
327+ * exist -> file doesn't exist
328+ */
314329 errno = ENOENT ;
315330 return NULL ;
316331 }
@@ -324,7 +339,7 @@ static struct fsentry *fscache_get(struct fsentry *key)
324339
325340 /* create the directory listing (outside mutex!) */
326341 LeaveCriticalSection (& mutex );
327- fse = fsentry_create_list (future );
342+ fse = fsentry_create_list (future , & dir_not_found );
328343 EnterCriticalSection (& mutex );
329344
330345 /* remove future entry and signal waiting threads */
@@ -338,6 +353,17 @@ static struct fsentry *fscache_get(struct fsentry *key)
338353
339354 /* leave on error (errno set by fsentry_create_list) */
340355 if (!fse ) {
356+ if (dir_not_found && key -> list ) {
357+ /*
358+ * Record that the directory does not exist (or is
359+ * empty, which for all practical matters is the same
360+ * thing as far as fscache is concerned).
361+ */
362+ fse = fsentry_alloc (key -> list -> list ,
363+ key -> list -> name , key -> list -> len );
364+ fse -> st_mode = 0 ;
365+ hashmap_add (& map , fse );
366+ }
341367 LeaveCriticalSection (& mutex );
342368 return NULL ;
343369 }
@@ -349,6 +375,9 @@ static struct fsentry *fscache_get(struct fsentry *key)
349375 if (key -> list )
350376 fse = hashmap_get (& map , key , NULL );
351377
378+ if (fse && !fse -> st_mode )
379+ fse = NULL ; /* non-existing directory */
380+
352381 /* return entry or ENOENT */
353382 if (fse )
354383 fsentry_addref (fse );
@@ -392,6 +421,7 @@ int fscache_enable(int enable)
392421 fscache_clear ();
393422 LeaveCriticalSection (& mutex );
394423 }
424+ trace_printf_key (& trace_fscache , "fscache: enable(%d)\n" , enable );
395425 return result ;
396426}
397427
0 commit comments