@@ -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
@@ -163,7 +164,8 @@ static struct fsentry *fseentry_create_entry(struct fsentry *list,
163
164
* Dir should not contain trailing '/'. Use an empty string for the current
164
165
* directory (not "."!).
165
166
*/
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 )
167
169
{
168
170
wchar_t pattern [MAX_LONG_PATH + 2 ]; /* + 2 for "\*" */
169
171
WIN32_FIND_DATAW fdata ;
@@ -172,6 +174,8 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
172
174
struct fsentry * list , * * phead ;
173
175
DWORD err ;
174
176
177
+ * dir_not_found = 0 ;
178
+
175
179
/* convert name to UTF-16 and check length */
176
180
if ((wlen = xutftowcs_path_ex (pattern , dir -> name , MAX_LONG_PATH ,
177
181
dir -> len , MAX_PATH - 2 , core_long_paths )) < 0 )
@@ -190,12 +194,16 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
190
194
h = FindFirstFileW (pattern , & fdata );
191
195
if (h == INVALID_HANDLE_VALUE ) {
192
196
err = GetLastError ();
197
+ * dir_not_found = 1 ; /* or empty directory */
193
198
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 );
194
201
return NULL ;
195
202
}
196
203
197
204
/* allocate object to hold directory listing */
198
205
list = fsentry_alloc (NULL , dir -> name , dir -> len );
206
+ list -> st_mode = S_IFDIR ;
199
207
200
208
/* walk directory and build linked list of fsentry structures */
201
209
phead = & list -> next ;
@@ -299,12 +307,16 @@ static struct fsentry *fscache_get_wait(struct fsentry *key)
299
307
static struct fsentry * fscache_get (struct fsentry * key )
300
308
{
301
309
struct fsentry * fse , * future , * waiter ;
310
+ int dir_not_found ;
302
311
303
312
EnterCriticalSection (& mutex );
304
313
/* check if entry is in cache */
305
314
fse = fscache_get_wait (key );
306
315
if (fse ) {
307
- fsentry_addref (fse );
316
+ if (fse -> st_mode )
317
+ fsentry_addref (fse );
318
+ else
319
+ fse = NULL ; /* non-existing directory */
308
320
LeaveCriticalSection (& mutex );
309
321
return fse ;
310
322
}
@@ -313,7 +325,10 @@ static struct fsentry *fscache_get(struct fsentry *key)
313
325
fse = fscache_get_wait (key -> list );
314
326
if (fse ) {
315
327
LeaveCriticalSection (& mutex );
316
- /* dir entry without file entry -> file doesn't exist */
328
+ /*
329
+ * dir entry without file entry, or dir does not
330
+ * exist -> file doesn't exist
331
+ */
317
332
errno = ENOENT ;
318
333
return NULL ;
319
334
}
@@ -327,7 +342,7 @@ static struct fsentry *fscache_get(struct fsentry *key)
327
342
328
343
/* create the directory listing (outside mutex!) */
329
344
LeaveCriticalSection (& mutex );
330
- fse = fsentry_create_list (future );
345
+ fse = fsentry_create_list (future , & dir_not_found );
331
346
EnterCriticalSection (& mutex );
332
347
333
348
/* remove future entry and signal waiting threads */
@@ -341,6 +356,17 @@ static struct fsentry *fscache_get(struct fsentry *key)
341
356
342
357
/* leave on error (errno set by fsentry_create_list) */
343
358
if (!fse ) {
359
+ if (dir_not_found && key -> list ) {
360
+ /*
361
+ * Record that the directory does not exist (or is
362
+ * empty, which for all practical matters is the same
363
+ * thing as far as fscache is concerned).
364
+ */
365
+ fse = fsentry_alloc (key -> list -> list ,
366
+ key -> list -> name , key -> list -> len );
367
+ fse -> st_mode = 0 ;
368
+ hashmap_add (& map , fse );
369
+ }
344
370
LeaveCriticalSection (& mutex );
345
371
return NULL ;
346
372
}
@@ -352,6 +378,9 @@ static struct fsentry *fscache_get(struct fsentry *key)
352
378
if (key -> list )
353
379
fse = hashmap_get (& map , key , NULL );
354
380
381
+ if (fse && !fse -> st_mode )
382
+ fse = NULL ; /* non-existing directory */
383
+
355
384
/* return entry or ENOENT */
356
385
if (fse )
357
386
fsentry_addref (fse );
@@ -395,6 +424,7 @@ int fscache_enable(int enable)
395
424
fscache_clear ();
396
425
LeaveCriticalSection (& mutex );
397
426
}
427
+ trace_printf_key (& trace_fscache , "fscache: enable(%d)\n" , enable );
398
428
return result ;
399
429
}
400
430
0 commit comments