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