4
char path[PATH_MAX];
5
int len;
6
int flags;
7
+ int track_flags;
8
} cache;
9
10
/*
31
return match_len;
32
}
33
33
-static inline void reset_lstat_cache(void)
34
+static inline void reset_lstat_cache(int track_flags)
35
{
36
cache.path[0] = '\0';
37
cache.len = 0;
38
cache.flags = 0;
39
+ cache.track_flags = track_flags;
40
}
41
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)
47
48
/*
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.
51
*
52
* To speed up the check, some information is allowed to be cached.
53
* This can be indicated by the 'track_flags' argument.
59
int match_flags, ret_flags, save_flags, max_len;
60
struct stat st;
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
+ }
91
92
/*
93
* Okay, no match from the cache so far, so now we have to
108
109
if (lstat(cache.path, &st)) {
110
ret_flags = FL_LSTATERR;
111
+ if (errno == ENOENT)
112
+ ret_flags |= FL_NOENT;
113
} else if (S_ISDIR(st.st_mode)) {
114
last_slash_dir = last_slash;
115
continue;
122
}
123
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!
128
*/
114
- save_flags = ret_flags & track_flags & FL_SYMLINK;
129
+ save_flags = ret_flags & track_flags & (FL_NOENT|FL_SYMLINK);
130
if (save_flags && last_slash > 0 && last_slash < PATH_MAX) {
131
cache.path[last_slash] = '\0';
132
cache.len = last_slash;
135
last_slash_dir > 0 && last_slash_dir < PATH_MAX) {
136
/*
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.
142
*
143
* But if we are allowed to track real directories, we
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).
146
*/
147
cache.path[last_slash_dir] = '\0';
148
cache.len = last_slash_dir;
149
cache.flags = FL_DIR;
150
} else {
136
- reset_lstat_cache();
151
+ reset_lstat_cache(track_flags);
152
}
153
return ret_flags;
154
}
162
FL_SYMLINK|FL_DIR) &
163
FL_SYMLINK;
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
+}