@@ -4,6 +4,7 @@ static struct cache_def {
4
4
char path [PATH_MAX ];
5
5
int len ;
6
6
int flags ;
7
+ int track_flags ;
7
8
} cache ;
8
9
9
10
/*
@@ -30,21 +31,23 @@ static inline int longest_match_lstat_cache(int len, const char *name)
30
31
return match_len ;
31
32
}
32
33
33
- static inline void reset_lstat_cache (void )
34
+ static inline void reset_lstat_cache (int track_flags )
34
35
{
35
36
cache .path [0 ] = '\0' ;
36
37
cache .len = 0 ;
37
38
cache .flags = 0 ;
39
+ cache .track_flags = track_flags ;
38
40
}
39
41
40
42
#define FL_DIR (1 << 0)
41
- #define FL_SYMLINK (1 << 1)
42
- #define FL_LSTATERR (1 << 2)
43
- #define FL_ERR (1 << 3)
43
+ #define FL_NOENT (1 << 1)
44
+ #define FL_SYMLINK (1 << 2)
45
+ #define FL_LSTATERR (1 << 3)
46
+ #define FL_ERR (1 << 4)
44
47
45
48
/*
46
49
* Check if name 'name' of length 'len' has a symlink leading
47
- * component, or if the directory exists and is real.
50
+ * component, or if the directory exists and is real, or not .
48
51
*
49
52
* To speed up the check, some information is allowed to be cached.
50
53
* This can be indicated by the 'track_flags' argument.
@@ -56,25 +59,35 @@ static int lstat_cache(int len, const char *name,
56
59
int match_flags , ret_flags , save_flags , max_len ;
57
60
struct stat st ;
58
61
59
- /*
60
- * Check to see if we have a match from the cache for the
61
- * symlink path type.
62
- */
63
- match_len = last_slash = longest_match_lstat_cache (len , name );
64
- match_flags = cache .flags & track_flags & FL_SYMLINK ;
65
- if (match_flags && match_len == cache .len )
66
- return match_flags ;
67
- /*
68
- * If we now have match_len > 0, we would know that the
69
- * matched part will always be a directory.
70
- *
71
- * Also, if we are tracking directories and 'name' is a
72
- * substring of the cache on a path component basis, we can
73
- * return immediately.
74
- */
75
- match_flags = track_flags & FL_DIR ;
76
- if (match_flags && len == match_len )
77
- return match_flags ;
62
+ if (cache .track_flags != track_flags ) {
63
+ /*
64
+ * As a safeguard we clear the cache if the value of
65
+ * track_flags does not match with the last supplied
66
+ * value.
67
+ */
68
+ reset_lstat_cache (track_flags );
69
+ match_len = last_slash = 0 ;
70
+ } else {
71
+ /*
72
+ * Check to see if we have a match from the cache for
73
+ * the 2 "excluding" path types.
74
+ */
75
+ match_len = last_slash = longest_match_lstat_cache (len , name );
76
+ match_flags = cache .flags & track_flags & (FL_NOENT |FL_SYMLINK );
77
+ if (match_flags && match_len == cache .len )
78
+ return match_flags ;
79
+ /*
80
+ * If we now have match_len > 0, we would know that
81
+ * the matched part will always be a directory.
82
+ *
83
+ * Also, if we are tracking directories and 'name' is
84
+ * a substring of the cache on a path component basis,
85
+ * we can return immediately.
86
+ */
87
+ match_flags = track_flags & FL_DIR ;
88
+ if (match_flags && len == match_len )
89
+ return match_flags ;
90
+ }
78
91
79
92
/*
80
93
* Okay, no match from the cache so far, so now we have to
@@ -95,6 +108,8 @@ static int lstat_cache(int len, const char *name,
95
108
96
109
if (lstat (cache .path , & st )) {
97
110
ret_flags = FL_LSTATERR ;
111
+ if (errno == ENOENT )
112
+ ret_flags |= FL_NOENT ;
98
113
} else if (S_ISDIR (st .st_mode )) {
99
114
last_slash_dir = last_slash ;
100
115
continue ;
@@ -107,11 +122,11 @@ static int lstat_cache(int len, const char *name,
107
122
}
108
123
109
124
/*
110
- * At the end update the cache. Note that max 2 different
111
- * path types, FL_SYMLINK and FL_DIR, can be cached for the
112
- * moment!
125
+ * At the end update the cache. Note that max 3 different
126
+ * path types, FL_NOENT, FL_SYMLINK and FL_DIR, can be cached
127
+ * for the moment!
113
128
*/
114
- save_flags = ret_flags & track_flags & FL_SYMLINK ;
129
+ save_flags = ret_flags & track_flags & ( FL_NOENT | FL_SYMLINK ) ;
115
130
if (save_flags && last_slash > 0 && last_slash < PATH_MAX ) {
116
131
cache .path [last_slash ] = '\0' ;
117
132
cache .len = last_slash ;
@@ -120,20 +135,20 @@ static int lstat_cache(int len, const char *name,
120
135
last_slash_dir > 0 && last_slash_dir < PATH_MAX ) {
121
136
/*
122
137
* We have a separate test for the directory case,
123
- * since it could be that we have found a symlink and
124
- * the track_flags says that we cannot cache this
125
- * fact, so the cache would then have been left empty
126
- * in this case.
138
+ * since it could be that we have found a symlink or a
139
+ * non-existing directory and the track_flags says
140
+ * that we cannot cache this fact, so the cache would
141
+ * then have been left empty in this case.
127
142
*
128
143
* But if we are allowed to track real directories, we
129
144
* can still cache the path components before the last
130
- * one (the found symlink component).
145
+ * one (the found symlink or non-existing component).
131
146
*/
132
147
cache .path [last_slash_dir ] = '\0' ;
133
148
cache .len = last_slash_dir ;
134
149
cache .flags = FL_DIR ;
135
150
} else {
136
- reset_lstat_cache ();
151
+ reset_lstat_cache (track_flags );
137
152
}
138
153
return ret_flags ;
139
154
}
@@ -147,3 +162,14 @@ int has_symlink_leading_path(int len, const char *name)
147
162
FL_SYMLINK |FL_DIR ) &
148
163
FL_SYMLINK ;
149
164
}
165
+
166
+ /*
167
+ * Return non-zero if path 'name' has a leading symlink component or
168
+ * if some leading path component does not exists.
169
+ */
170
+ int has_symlink_or_noent_leading_path (int len , const char * name )
171
+ {
172
+ return lstat_cache (len , name ,
173
+ FL_SYMLINK |FL_NOENT |FL_DIR ) &
174
+ (FL_SYMLINK |FL_NOENT );
175
+ }
0 commit comments