@@ -7,6 +7,7 @@ static int initialized;
7
7
static volatile long enabled ;
8
8
static struct hashmap map ;
9
9
static CRITICAL_SECTION mutex ;
10
+ static struct trace_key trace_fscache = TRACE_KEY_INIT (FSCACHE );
10
11
11
12
/*
12
13
* 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,
165
166
* Dir should not contain trailing '/'. Use an empty string for the current
166
167
* directory (not "."!).
167
168
*/
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 )
169
171
{
170
172
wchar_t pattern [MAX_LONG_PATH + 2 ]; /* + 2 for "\*" */
171
173
WIN32_FIND_DATAW fdata ;
@@ -174,6 +176,8 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
174
176
struct fsentry * list , * * phead ;
175
177
DWORD err ;
176
178
179
+ * dir_not_found = 0 ;
180
+
177
181
/* convert name to UTF-16 and check length */
178
182
if ((wlen = xutftowcs_path_ex (pattern , dir -> name , MAX_LONG_PATH ,
179
183
dir -> len , MAX_PATH - 2 , core_long_paths )) < 0 )
@@ -192,12 +196,16 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
192
196
h = FindFirstFileW (pattern , & fdata );
193
197
if (h == INVALID_HANDLE_VALUE ) {
194
198
err = GetLastError ();
199
+ * dir_not_found = 1 ; /* or empty directory */
195
200
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 );
196
203
return NULL ;
197
204
}
198
205
199
206
/* allocate object to hold directory listing */
200
207
list = fsentry_alloc (NULL , dir -> name , dir -> len );
208
+ list -> st_mode = S_IFDIR ;
201
209
202
210
/* walk directory and build linked list of fsentry structures */
203
211
phead = & list -> next ;
@@ -282,12 +290,16 @@ static struct fsentry *fscache_get_wait(struct fsentry *key)
282
290
static struct fsentry * fscache_get (struct fsentry * key )
283
291
{
284
292
struct fsentry * fse , * future , * waiter ;
293
+ int dir_not_found ;
285
294
286
295
EnterCriticalSection (& mutex );
287
296
/* check if entry is in cache */
288
297
fse = fscache_get_wait (key );
289
298
if (fse ) {
290
- fsentry_addref (fse );
299
+ if (fse -> st_mode )
300
+ fsentry_addref (fse );
301
+ else
302
+ fse = NULL ; /* non-existing directory */
291
303
LeaveCriticalSection (& mutex );
292
304
return fse ;
293
305
}
@@ -296,7 +308,10 @@ static struct fsentry *fscache_get(struct fsentry *key)
296
308
fse = fscache_get_wait (key -> list );
297
309
if (fse ) {
298
310
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
+ */
300
315
errno = ENOENT ;
301
316
return NULL ;
302
317
}
@@ -310,7 +325,7 @@ static struct fsentry *fscache_get(struct fsentry *key)
310
325
311
326
/* create the directory listing (outside mutex!) */
312
327
LeaveCriticalSection (& mutex );
313
- fse = fsentry_create_list (future );
328
+ fse = fsentry_create_list (future , & dir_not_found );
314
329
EnterCriticalSection (& mutex );
315
330
316
331
/* remove future entry and signal waiting threads */
@@ -324,6 +339,17 @@ static struct fsentry *fscache_get(struct fsentry *key)
324
339
325
340
/* leave on error (errno set by fsentry_create_list) */
326
341
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
+ }
327
353
LeaveCriticalSection (& mutex );
328
354
return NULL ;
329
355
}
@@ -335,6 +361,9 @@ static struct fsentry *fscache_get(struct fsentry *key)
335
361
if (key -> list )
336
362
fse = hashmap_get (& map , key , NULL );
337
363
364
+ if (fse && !fse -> st_mode )
365
+ fse = NULL ; /* non-existing directory */
366
+
338
367
/* return entry or ENOENT */
339
368
if (fse )
340
369
fsentry_addref (fse );
@@ -378,6 +407,7 @@ int fscache_enable(int enable)
378
407
fscache_clear ();
379
408
LeaveCriticalSection (& mutex );
380
409
}
410
+ trace_printf_key (& trace_fscache , "fscache: enable(%d)\n" , enable );
381
411
return result ;
382
412
}
383
413
0 commit comments