@@ -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
@@ -164,7 +165,8 @@ static struct fsentry *fseentry_create_entry(struct fsentry *list,
164
165
* Dir should not contain trailing '/'. Use an empty string for the current
165
166
* directory (not "."!).
166
167
*/
167
- static struct fsentry * fsentry_create_list (const struct fsentry * dir )
168
+ static struct fsentry * fsentry_create_list (const struct fsentry * dir ,
169
+ int * dir_not_found )
168
170
{
169
171
wchar_t pattern [MAX_PATH + 2 ]; /* + 2 for '/' '*' */
170
172
WIN32_FIND_DATAW fdata ;
@@ -173,6 +175,8 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
173
175
struct fsentry * list , * * phead ;
174
176
DWORD err ;
175
177
178
+ * dir_not_found = 0 ;
179
+
176
180
/* convert name to UTF-16 and check length < MAX_PATH */
177
181
if ((wlen = xutftowcsn (pattern , dir -> name , MAX_PATH , dir -> len )) < 0 ) {
178
182
if (errno == ERANGE )
@@ -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 ;
@@ -280,12 +288,16 @@ static struct fsentry *fscache_get_wait(struct fsentry *key)
280
288
static struct fsentry * fscache_get (struct fsentry * key )
281
289
{
282
290
struct fsentry * fse , * future , * waiter ;
291
+ int dir_not_found ;
283
292
284
293
EnterCriticalSection (& mutex );
285
294
/* check if entry is in cache */
286
295
fse = fscache_get_wait (key );
287
296
if (fse ) {
288
- fsentry_addref (fse );
297
+ if (fse -> st_mode )
298
+ fsentry_addref (fse );
299
+ else
300
+ fse = NULL ; /* non-existing directory */
289
301
LeaveCriticalSection (& mutex );
290
302
return fse ;
291
303
}
@@ -294,7 +306,10 @@ static struct fsentry *fscache_get(struct fsentry *key)
294
306
fse = fscache_get_wait (key -> list );
295
307
if (fse ) {
296
308
LeaveCriticalSection (& mutex );
297
- /* dir entry without file entry -> file doesn't exist */
309
+ /*
310
+ * dir entry without file entry, or dir does not
311
+ * exist -> file doesn't exist
312
+ */
298
313
errno = ENOENT ;
299
314
return NULL ;
300
315
}
@@ -308,7 +323,7 @@ static struct fsentry *fscache_get(struct fsentry *key)
308
323
309
324
/* create the directory listing (outside mutex!) */
310
325
LeaveCriticalSection (& mutex );
311
- fse = fsentry_create_list (future );
326
+ fse = fsentry_create_list (future , & dir_not_found );
312
327
EnterCriticalSection (& mutex );
313
328
314
329
/* remove future entry and signal waiting threads */
@@ -322,6 +337,17 @@ static struct fsentry *fscache_get(struct fsentry *key)
322
337
323
338
/* leave on error (errno set by fsentry_create_list) */
324
339
if (!fse ) {
340
+ if (dir_not_found && key -> list ) {
341
+ /*
342
+ * Record that the directory does not exist (or is
343
+ * empty, which for all practical matters is the same
344
+ * thing as far as fscache is concerned).
345
+ */
346
+ fse = fsentry_alloc (key -> list -> list ,
347
+ key -> list -> name , key -> list -> len );
348
+ fse -> st_mode = 0 ;
349
+ hashmap_add (& map , fse );
350
+ }
325
351
LeaveCriticalSection (& mutex );
326
352
return NULL ;
327
353
}
@@ -333,6 +359,9 @@ static struct fsentry *fscache_get(struct fsentry *key)
333
359
if (key -> list )
334
360
fse = hashmap_get (& map , key , NULL );
335
361
362
+ if (fse && !fse -> st_mode )
363
+ fse = NULL ; /* non-existing directory */
364
+
336
365
/* return entry or ENOENT */
337
366
if (fse )
338
367
fsentry_addref (fse );
@@ -376,6 +405,7 @@ int fscache_enable(int enable)
376
405
fscache_clear ();
377
406
LeaveCriticalSection (& mutex );
378
407
}
408
+ trace_printf_key (& trace_fscache , "fscache: enable(%d)\n" , enable );
379
409
return result ;
380
410
}
381
411
0 commit comments