44#include  "fscache.h" 
55#include  "../../dir.h" 
66#include  "../../abspath.h" 
7+ #include  "../../trace.h" 
78
89static  int  initialized ;
910static  volatile  long  enabled ;
1011static  struct  hashmap  map ;
1112static  CRITICAL_SECTION  mutex ;
13+ static  struct  trace_key  trace_fscache  =  TRACE_KEY_INIT (FSCACHE );
1214
1315/* 
1416 * 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,
179181 * Dir should not contain trailing '/'. Use an empty string for the current 
180182 * directory (not "."!). 
181183 */ 
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 )
183186{
184187	wchar_t  pattern [MAX_PATH  +  2 ]; /* + 2 for '/' '*' */ 
185188	WIN32_FIND_DATAW  fdata ;
@@ -188,6 +191,8 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
188191	struct  fsentry  * list , * * phead ;
189192	DWORD  err ;
190193
194+ 	* dir_not_found  =  0 ;
195+ 
191196	/* convert name to UTF-16 and check length < MAX_PATH */ 
192197	if  ((wlen  =  xutftowcsn (pattern , dir -> dirent .d_name , MAX_PATH ,
193198			       dir -> len )) <  0 ) {
@@ -206,12 +211,17 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
206211	h  =  FindFirstFileW (pattern , & fdata );
207212	if  (h  ==  INVALID_HANDLE_VALUE ) {
208213		err  =  GetLastError ();
214+ 		* dir_not_found  =  1 ; /* or empty directory */ 
209215		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 );
210218		return  NULL ;
211219	}
212220
213221	/* allocate object to hold directory listing */ 
214222	list  =  fsentry_alloc (NULL , dir -> dirent .d_name , dir -> len );
223+ 	list -> st_mode  =  S_IFDIR ;
224+ 	list -> dirent .d_type  =  DT_DIR ;
215225
216226	/* walk directory and build linked list of fsentry structures */ 
217227	phead  =  & list -> next ;
@@ -296,12 +306,16 @@ static struct fsentry *fscache_get_wait(struct fsentry *key)
296306static  struct  fsentry  * fscache_get (struct  fsentry  * key )
297307{
298308	struct  fsentry  * fse , * future , * waiter ;
309+ 	int  dir_not_found ;
299310
300311	EnterCriticalSection (& mutex );
301312	/* check if entry is in cache */ 
302313	fse  =  fscache_get_wait (key );
303314	if  (fse ) {
304- 		fsentry_addref (fse );
315+ 		if  (fse -> st_mode )
316+ 			fsentry_addref (fse );
317+ 		else 
318+ 			fse  =  NULL ; /* non-existing directory */ 
305319		LeaveCriticalSection (& mutex );
306320		return  fse ;
307321	}
@@ -310,7 +324,10 @@ static struct fsentry *fscache_get(struct fsentry *key)
310324		fse  =  fscache_get_wait (key -> list );
311325		if  (fse ) {
312326			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+ 			 */ 
314331			errno  =  ENOENT ;
315332			return  NULL ;
316333		}
@@ -324,7 +341,7 @@ static struct fsentry *fscache_get(struct fsentry *key)
324341
325342	/* create the directory listing (outside mutex!) */ 
326343	LeaveCriticalSection (& mutex );
327- 	fse  =  fsentry_create_list (future );
344+ 	fse  =  fsentry_create_list (future ,  & dir_not_found );
328345	EnterCriticalSection (& mutex );
329346
330347	/* remove future entry and signal waiting threads */ 
@@ -338,6 +355,18 @@ static struct fsentry *fscache_get(struct fsentry *key)
338355
339356	/* leave on error (errno set by fsentry_create_list) */ 
340357	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+ 		}
341370		LeaveCriticalSection (& mutex );
342371		return  NULL ;
343372	}
@@ -349,6 +378,9 @@ static struct fsentry *fscache_get(struct fsentry *key)
349378	if  (key -> list )
350379		fse  =  hashmap_get_entry (& map , key , ent , NULL );
351380
381+ 	if  (fse  &&  !fse -> st_mode )
382+ 		fse  =  NULL ; /* non-existing directory */ 
383+ 
352384	/* return entry or ENOENT */ 
353385	if  (fse )
354386		fsentry_addref (fse );
@@ -392,6 +424,7 @@ int fscache_enable(int enable)
392424		fscache_clear ();
393425		LeaveCriticalSection (& mutex );
394426	}
427+ 	trace_printf_key (& trace_fscache , "fscache: enable(%d)\n" , enable );
395428	return  result ;
396429}
397430
0 commit comments