@@ -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
@@ -172,7 +173,8 @@ static struct fsentry *fseentry_create_entry(struct fsentry *list,
172
173
* Dir should not contain trailing '/'. Use an empty string for the current
173
174
* directory (not "."!).
174
175
*/
175
- static struct fsentry * fsentry_create_list (const struct fsentry * dir )
176
+ static struct fsentry * fsentry_create_list (const struct fsentry * dir ,
177
+ int * dir_not_found )
176
178
{
177
179
wchar_t pattern [MAX_PATH + 2 ]; /* + 2 for '/' '*' */
178
180
WIN32_FIND_DATAW fdata ;
@@ -181,6 +183,8 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
181
183
struct fsentry * list , * * phead ;
182
184
DWORD err ;
183
185
186
+ * dir_not_found = 0 ;
187
+
184
188
/* convert name to UTF-16 and check length < MAX_PATH */
185
189
if ((wlen = xutftowcsn (pattern , dir -> dirent .d_name , MAX_PATH ,
186
190
dir -> len )) < 0 ) {
@@ -199,12 +203,17 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
199
203
h = FindFirstFileW (pattern , & fdata );
200
204
if (h == INVALID_HANDLE_VALUE ) {
201
205
err = GetLastError ();
206
+ * dir_not_found = 1 ; /* or empty directory */
202
207
errno = (err == ERROR_DIRECTORY ) ? ENOTDIR : err_win_to_posix (err );
208
+ trace_printf_key (& trace_fscache , "fscache: error(%d) '%s'\n" ,
209
+ errno , dir -> dirent .d_name );
203
210
return NULL ;
204
211
}
205
212
206
213
/* allocate object to hold directory listing */
207
214
list = fsentry_alloc (NULL , dir -> dirent .d_name , dir -> len );
215
+ list -> st_mode = S_IFDIR ;
216
+ list -> dirent .d_type = DT_DIR ;
208
217
209
218
/* walk directory and build linked list of fsentry structures */
210
219
phead = & list -> next ;
@@ -289,12 +298,16 @@ static struct fsentry *fscache_get_wait(struct fsentry *key)
289
298
static struct fsentry * fscache_get (struct fsentry * key )
290
299
{
291
300
struct fsentry * fse , * future , * waiter ;
301
+ int dir_not_found ;
292
302
293
303
EnterCriticalSection (& mutex );
294
304
/* check if entry is in cache */
295
305
fse = fscache_get_wait (key );
296
306
if (fse ) {
297
- fsentry_addref (fse );
307
+ if (fse -> st_mode )
308
+ fsentry_addref (fse );
309
+ else
310
+ fse = NULL ; /* non-existing directory */
298
311
LeaveCriticalSection (& mutex );
299
312
return fse ;
300
313
}
@@ -303,7 +316,10 @@ static struct fsentry *fscache_get(struct fsentry *key)
303
316
fse = fscache_get_wait (key -> list );
304
317
if (fse ) {
305
318
LeaveCriticalSection (& mutex );
306
- /* dir entry without file entry -> file doesn't exist */
319
+ /*
320
+ * dir entry without file entry, or dir does not
321
+ * exist -> file doesn't exist
322
+ */
307
323
errno = ENOENT ;
308
324
return NULL ;
309
325
}
@@ -317,7 +333,7 @@ static struct fsentry *fscache_get(struct fsentry *key)
317
333
318
334
/* create the directory listing (outside mutex!) */
319
335
LeaveCriticalSection (& mutex );
320
- fse = fsentry_create_list (future );
336
+ fse = fsentry_create_list (future , & dir_not_found );
321
337
EnterCriticalSection (& mutex );
322
338
323
339
/* remove future entry and signal waiting threads */
@@ -331,6 +347,18 @@ static struct fsentry *fscache_get(struct fsentry *key)
331
347
332
348
/* leave on error (errno set by fsentry_create_list) */
333
349
if (!fse ) {
350
+ if (dir_not_found && key -> list ) {
351
+ /*
352
+ * Record that the directory does not exist (or is
353
+ * empty, which for all practical matters is the same
354
+ * thing as far as fscache is concerned).
355
+ */
356
+ fse = fsentry_alloc (key -> list -> list ,
357
+ key -> list -> dirent .d_name ,
358
+ key -> list -> len );
359
+ fse -> st_mode = 0 ;
360
+ hashmap_add (& map , & fse -> ent );
361
+ }
334
362
LeaveCriticalSection (& mutex );
335
363
return NULL ;
336
364
}
@@ -342,6 +370,9 @@ static struct fsentry *fscache_get(struct fsentry *key)
342
370
if (key -> list )
343
371
fse = hashmap_get_entry (& map , key , ent , NULL );
344
372
373
+ if (fse && !fse -> st_mode )
374
+ fse = NULL ; /* non-existing directory */
375
+
345
376
/* return entry or ENOENT */
346
377
if (fse )
347
378
fsentry_addref (fse );
@@ -385,6 +416,7 @@ int fscache_enable(int enable)
385
416
fscache_clear ();
386
417
LeaveCriticalSection (& mutex );
387
418
}
419
+ trace_printf_key (& trace_fscache , "fscache: enable(%d)\n" , enable );
388
420
return result ;
389
421
}
390
422
0 commit comments