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