@@ -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
@@ -177,7 +178,8 @@ static struct fsentry *fseentry_create_entry(struct fsentry *list,
177
178
* Dir should not contain trailing '/'. Use an empty string for the current
178
179
* directory (not "."!).
179
180
*/
180
- static struct fsentry * fsentry_create_list (const struct fsentry * dir )
181
+ static struct fsentry * fsentry_create_list (const struct fsentry * dir ,
182
+ int * dir_not_found )
181
183
{
182
184
wchar_t pattern [MAX_PATH + 2 ]; /* + 2 for '/' '*' */
183
185
WIN32_FIND_DATAW fdata ;
@@ -186,6 +188,8 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
186
188
struct fsentry * list , * * phead ;
187
189
DWORD err ;
188
190
191
+ * dir_not_found = 0 ;
192
+
189
193
/* convert name to UTF-16 and check length < MAX_PATH */
190
194
if ((wlen = xutftowcsn (pattern , dir -> dirent .d_name , MAX_PATH ,
191
195
dir -> len )) < 0 ) {
@@ -204,12 +208,17 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
204
208
h = FindFirstFileW (pattern , & fdata );
205
209
if (h == INVALID_HANDLE_VALUE ) {
206
210
err = GetLastError ();
211
+ * dir_not_found = 1 ; /* or empty directory */
207
212
errno = (err == ERROR_DIRECTORY ) ? ENOTDIR : err_win_to_posix (err );
213
+ trace_printf_key (& trace_fscache , "fscache: error(%d) '%s'\n" ,
214
+ errno , dir -> dirent .d_name );
208
215
return NULL ;
209
216
}
210
217
211
218
/* allocate object to hold directory listing */
212
219
list = fsentry_alloc (NULL , dir -> dirent .d_name , dir -> len );
220
+ list -> st_mode = S_IFDIR ;
221
+ list -> dirent .d_type = DT_DIR ;
213
222
214
223
/* walk directory and build linked list of fsentry structures */
215
224
phead = & list -> next ;
@@ -294,12 +303,16 @@ static struct fsentry *fscache_get_wait(struct fsentry *key)
294
303
static struct fsentry * fscache_get (struct fsentry * key )
295
304
{
296
305
struct fsentry * fse , * future , * waiter ;
306
+ int dir_not_found ;
297
307
298
308
EnterCriticalSection (& mutex );
299
309
/* check if entry is in cache */
300
310
fse = fscache_get_wait (key );
301
311
if (fse ) {
302
- fsentry_addref (fse );
312
+ if (fse -> st_mode )
313
+ fsentry_addref (fse );
314
+ else
315
+ fse = NULL ; /* non-existing directory */
303
316
LeaveCriticalSection (& mutex );
304
317
return fse ;
305
318
}
@@ -308,7 +321,10 @@ static struct fsentry *fscache_get(struct fsentry *key)
308
321
fse = fscache_get_wait (key -> list );
309
322
if (fse ) {
310
323
LeaveCriticalSection (& mutex );
311
- /* dir entry without file entry -> file doesn't exist */
324
+ /*
325
+ * dir entry without file entry, or dir does not
326
+ * exist -> file doesn't exist
327
+ */
312
328
errno = ENOENT ;
313
329
return NULL ;
314
330
}
@@ -322,7 +338,7 @@ static struct fsentry *fscache_get(struct fsentry *key)
322
338
323
339
/* create the directory listing (outside mutex!) */
324
340
LeaveCriticalSection (& mutex );
325
- fse = fsentry_create_list (future );
341
+ fse = fsentry_create_list (future , & dir_not_found );
326
342
EnterCriticalSection (& mutex );
327
343
328
344
/* remove future entry and signal waiting threads */
@@ -336,6 +352,18 @@ static struct fsentry *fscache_get(struct fsentry *key)
336
352
337
353
/* leave on error (errno set by fsentry_create_list) */
338
354
if (!fse ) {
355
+ if (dir_not_found && key -> list ) {
356
+ /*
357
+ * Record that the directory does not exist (or is
358
+ * empty, which for all practical matters is the same
359
+ * thing as far as fscache is concerned).
360
+ */
361
+ fse = fsentry_alloc (key -> list -> list ,
362
+ key -> list -> dirent .d_name ,
363
+ key -> list -> len );
364
+ fse -> st_mode = 0 ;
365
+ hashmap_add (& map , & fse -> ent );
366
+ }
339
367
LeaveCriticalSection (& mutex );
340
368
return NULL ;
341
369
}
@@ -347,6 +375,9 @@ static struct fsentry *fscache_get(struct fsentry *key)
347
375
if (key -> list )
348
376
fse = hashmap_get_entry (& map , key , ent , NULL );
349
377
378
+ if (fse && !fse -> st_mode )
379
+ fse = NULL ; /* non-existing directory */
380
+
350
381
/* return entry or ENOENT */
351
382
if (fse )
352
383
fsentry_addref (fse );
@@ -390,6 +421,7 @@ int fscache_enable(int enable)
390
421
fscache_clear ();
391
422
LeaveCriticalSection (& mutex );
392
423
}
424
+ trace_printf_key (& trace_fscache , "fscache: enable(%d)\n" , enable );
393
425
return result ;
394
426
}
395
427
0 commit comments