@@ -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
@@ -187,7 +188,8 @@ static struct fsentry *fseentry_create_entry(struct fsentry *list,
187
188
* Dir should not contain trailing '/'. Use an empty string for the current
188
189
* directory (not "."!).
189
190
*/
190
- static struct fsentry * fsentry_create_list (const struct fsentry * dir )
191
+ static struct fsentry * fsentry_create_list (const struct fsentry * dir ,
192
+ int * dir_not_found )
191
193
{
192
194
wchar_t pattern [MAX_LONG_PATH + 2 ]; /* + 2 for "\*" */
193
195
WIN32_FIND_DATAW fdata ;
@@ -196,6 +198,8 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
196
198
struct fsentry * list , * * phead ;
197
199
DWORD err ;
198
200
201
+ * dir_not_found = 0 ;
202
+
199
203
/* convert name to UTF-16 and check length */
200
204
if ((wlen = xutftowcs_path_ex (pattern , dir -> name , MAX_LONG_PATH ,
201
205
dir -> len , MAX_PATH - 2 , core_long_paths )) < 0 )
@@ -214,12 +218,16 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
214
218
h = FindFirstFileW (pattern , & fdata );
215
219
if (h == INVALID_HANDLE_VALUE ) {
216
220
err = GetLastError ();
221
+ * dir_not_found = 1 ; /* or empty directory */
217
222
errno = (err == ERROR_DIRECTORY ) ? ENOTDIR : err_win_to_posix (err );
223
+ trace_printf_key (& trace_fscache , "fscache: error(%d) '%.*s'\n" ,
224
+ errno , dir -> len , dir -> name );
218
225
return NULL ;
219
226
}
220
227
221
228
/* allocate object to hold directory listing */
222
229
list = fsentry_alloc (NULL , dir -> name , dir -> len );
230
+ list -> st_mode = S_IFDIR ;
223
231
224
232
/* walk directory and build linked list of fsentry structures */
225
233
phead = & list -> next ;
@@ -304,12 +312,16 @@ static struct fsentry *fscache_get_wait(struct fsentry *key)
304
312
static struct fsentry * fscache_get (struct fsentry * key )
305
313
{
306
314
struct fsentry * fse , * future , * waiter ;
315
+ int dir_not_found ;
307
316
308
317
EnterCriticalSection (& mutex );
309
318
/* check if entry is in cache */
310
319
fse = fscache_get_wait (key );
311
320
if (fse ) {
312
- fsentry_addref (fse );
321
+ if (fse -> st_mode )
322
+ fsentry_addref (fse );
323
+ else
324
+ fse = NULL ; /* non-existing directory */
313
325
LeaveCriticalSection (& mutex );
314
326
return fse ;
315
327
}
@@ -318,7 +330,10 @@ static struct fsentry *fscache_get(struct fsentry *key)
318
330
fse = fscache_get_wait (key -> list );
319
331
if (fse ) {
320
332
LeaveCriticalSection (& mutex );
321
- /* dir entry without file entry -> file doesn't exist */
333
+ /*
334
+ * dir entry without file entry, or dir does not
335
+ * exist -> file doesn't exist
336
+ */
322
337
errno = ENOENT ;
323
338
return NULL ;
324
339
}
@@ -332,7 +347,7 @@ static struct fsentry *fscache_get(struct fsentry *key)
332
347
333
348
/* create the directory listing (outside mutex!) */
334
349
LeaveCriticalSection (& mutex );
335
- fse = fsentry_create_list (future );
350
+ fse = fsentry_create_list (future , & dir_not_found );
336
351
EnterCriticalSection (& mutex );
337
352
338
353
/* remove future entry and signal waiting threads */
@@ -346,6 +361,17 @@ static struct fsentry *fscache_get(struct fsentry *key)
346
361
347
362
/* leave on error (errno set by fsentry_create_list) */
348
363
if (!fse ) {
364
+ if (dir_not_found && key -> list ) {
365
+ /*
366
+ * Record that the directory does not exist (or is
367
+ * empty, which for all practical matters is the same
368
+ * thing as far as fscache is concerned).
369
+ */
370
+ fse = fsentry_alloc (key -> list -> list ,
371
+ key -> list -> name , key -> list -> len );
372
+ fse -> st_mode = 0 ;
373
+ hashmap_add (& map , fse );
374
+ }
349
375
LeaveCriticalSection (& mutex );
350
376
return NULL ;
351
377
}
@@ -357,6 +383,9 @@ static struct fsentry *fscache_get(struct fsentry *key)
357
383
if (key -> list )
358
384
fse = hashmap_get (& map , key , NULL );
359
385
386
+ if (fse && !fse -> st_mode )
387
+ fse = NULL ; /* non-existing directory */
388
+
360
389
/* return entry or ENOENT */
361
390
if (fse )
362
391
fsentry_addref (fse );
@@ -400,6 +429,7 @@ int fscache_enable(int enable)
400
429
fscache_clear ();
401
430
LeaveCriticalSection (& mutex );
402
431
}
432
+ trace_printf_key (& trace_fscache , "fscache: enable(%d)\n" , enable );
403
433
return result ;
404
434
}
405
435
0 commit comments