@@ -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 ;
@@ -296,12 +304,16 @@ static struct fsentry *fscache_get_wait(struct fsentry *key)
296
304
static struct fsentry * fscache_get (struct fsentry * key )
297
305
{
298
306
struct fsentry * fse , * future , * waiter ;
307
+ int dir_not_found ;
299
308
300
309
EnterCriticalSection (& mutex );
301
310
/* check if entry is in cache */
302
311
fse = fscache_get_wait (key );
303
312
if (fse ) {
304
- fsentry_addref (fse );
313
+ if (fse -> st_mode )
314
+ fsentry_addref (fse );
315
+ else
316
+ fse = NULL ; /* non-existing directory */
305
317
LeaveCriticalSection (& mutex );
306
318
return fse ;
307
319
}
@@ -310,7 +322,10 @@ static struct fsentry *fscache_get(struct fsentry *key)
310
322
fse = fscache_get_wait (key -> list );
311
323
if (fse ) {
312
324
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
+ */
314
329
errno = ENOENT ;
315
330
return NULL ;
316
331
}
@@ -324,7 +339,7 @@ static struct fsentry *fscache_get(struct fsentry *key)
324
339
325
340
/* create the directory listing (outside mutex!) */
326
341
LeaveCriticalSection (& mutex );
327
- fse = fsentry_create_list (future );
342
+ fse = fsentry_create_list (future , & dir_not_found );
328
343
EnterCriticalSection (& mutex );
329
344
330
345
/* remove future entry and signal waiting threads */
@@ -338,6 +353,17 @@ static struct fsentry *fscache_get(struct fsentry *key)
338
353
339
354
/* leave on error (errno set by fsentry_create_list) */
340
355
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
+ }
341
367
LeaveCriticalSection (& mutex );
342
368
return NULL ;
343
369
}
@@ -349,6 +375,9 @@ static struct fsentry *fscache_get(struct fsentry *key)
349
375
if (key -> list )
350
376
fse = hashmap_get (& map , key , NULL );
351
377
378
+ if (fse && !fse -> st_mode )
379
+ fse = NULL ; /* non-existing directory */
380
+
352
381
/* return entry or ENOENT */
353
382
if (fse )
354
383
fsentry_addref (fse );
@@ -392,6 +421,7 @@ int fscache_enable(int enable)
392
421
fscache_clear ();
393
422
LeaveCriticalSection (& mutex );
394
423
}
424
+ trace_printf_key (& trace_fscache , "fscache: enable(%d)\n" , enable );
395
425
return result ;
396
426
}
397
427
0 commit comments