@@ -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
@@ -165,7 +166,8 @@ static struct fsentry *fseentry_create_entry(struct fsentry *list,
165166 * Dir should not contain trailing '/'. Use an empty string for the current
166167 * directory (not "."!).
167168 */
168- static struct fsentry * fsentry_create_list (const struct fsentry * dir )
169+ static struct fsentry * fsentry_create_list (const struct fsentry * dir ,
170+ int * dir_not_found )
169171{
170172 wchar_t pattern [MAX_LONG_PATH + 2 ]; /* + 2 for "\*" */
171173 WIN32_FIND_DATAW fdata ;
@@ -174,6 +176,8 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
174176 struct fsentry * list , * * phead ;
175177 DWORD err ;
176178
179+ * dir_not_found = 0 ;
180+
177181 /* convert name to UTF-16 and check length */
178182 if ((wlen = xutftowcs_path_ex (pattern , dir -> name , MAX_LONG_PATH ,
179183 dir -> len , MAX_PATH - 2 , core_long_paths )) < 0 )
@@ -192,12 +196,16 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
192196 h = FindFirstFileW (pattern , & fdata );
193197 if (h == INVALID_HANDLE_VALUE ) {
194198 err = GetLastError ();
199+ * dir_not_found = 1 ; /* or empty directory */
195200 errno = (err == ERROR_DIRECTORY ) ? ENOTDIR : err_win_to_posix (err );
201+ trace_printf_key (& trace_fscache , "fscache: error(%d) '%.*s'\n" ,
202+ errno , dir -> len , dir -> name );
196203 return NULL ;
197204 }
198205
199206 /* allocate object to hold directory listing */
200207 list = fsentry_alloc (NULL , dir -> name , dir -> len );
208+ list -> st_mode = S_IFDIR ;
201209
202210 /* walk directory and build linked list of fsentry structures */
203211 phead = & list -> next ;
@@ -282,12 +290,16 @@ static struct fsentry *fscache_get_wait(struct fsentry *key)
282290static struct fsentry * fscache_get (struct fsentry * key )
283291{
284292 struct fsentry * fse , * future , * waiter ;
293+ int dir_not_found ;
285294
286295 EnterCriticalSection (& mutex );
287296 /* check if entry is in cache */
288297 fse = fscache_get_wait (key );
289298 if (fse ) {
290- fsentry_addref (fse );
299+ if (fse -> st_mode )
300+ fsentry_addref (fse );
301+ else
302+ fse = NULL ; /* non-existing directory */
291303 LeaveCriticalSection (& mutex );
292304 return fse ;
293305 }
@@ -296,7 +308,10 @@ static struct fsentry *fscache_get(struct fsentry *key)
296308 fse = fscache_get_wait (key -> list );
297309 if (fse ) {
298310 LeaveCriticalSection (& mutex );
299- /* dir entry without file entry -> file doesn't exist */
311+ /*
312+ * dir entry without file entry, or dir does not
313+ * exist -> file doesn't exist
314+ */
300315 errno = ENOENT ;
301316 return NULL ;
302317 }
@@ -310,7 +325,7 @@ static struct fsentry *fscache_get(struct fsentry *key)
310325
311326 /* create the directory listing (outside mutex!) */
312327 LeaveCriticalSection (& mutex );
313- fse = fsentry_create_list (future );
328+ fse = fsentry_create_list (future , & dir_not_found );
314329 EnterCriticalSection (& mutex );
315330
316331 /* remove future entry and signal waiting threads */
@@ -324,6 +339,17 @@ static struct fsentry *fscache_get(struct fsentry *key)
324339
325340 /* leave on error (errno set by fsentry_create_list) */
326341 if (!fse ) {
342+ if (dir_not_found && key -> list ) {
343+ /*
344+ * Record that the directory does not exist (or is
345+ * empty, which for all practical matters is the same
346+ * thing as far as fscache is concerned).
347+ */
348+ fse = fsentry_alloc (key -> list -> list ,
349+ key -> list -> name , key -> list -> len );
350+ fse -> st_mode = 0 ;
351+ hashmap_add (& map , fse );
352+ }
327353 LeaveCriticalSection (& mutex );
328354 return NULL ;
329355 }
@@ -335,6 +361,9 @@ static struct fsentry *fscache_get(struct fsentry *key)
335361 if (key -> list )
336362 fse = hashmap_get (& map , key , NULL );
337363
364+ if (fse && !fse -> st_mode )
365+ fse = NULL ; /* non-existing directory */
366+
338367 /* return entry or ENOENT */
339368 if (fse )
340369 fsentry_addref (fse );
@@ -378,6 +407,7 @@ int fscache_enable(int enable)
378407 fscache_clear ();
379408 LeaveCriticalSection (& mutex );
380409 }
410+ trace_printf_key (& trace_fscache , "fscache: enable(%d)\n" , enable );
381411 return result ;
382412}
383413
0 commit comments