1
#include "cache.h"
2
3
static struct cache_def {
4
- char path[PATH_MAX];
4
+ char path[PATH_MAX + 1];
5
int len;
6
int flags;
7
int track_flags;
8
+ int prefix_len_stat_func;
9
} cache;
10
11
/*
32
return match_len;
33
}
34
34
-static inline void reset_lstat_cache(int track_flags)
35
+static inline void reset_lstat_cache(int track_flags, int prefix_len_stat_func)
36
{
37
cache.path[0] = '\0';
38
cache.len = 0;
39
cache.flags = 0;
40
cache.track_flags = track_flags;
41
+ cache.prefix_len_stat_func = prefix_len_stat_func;
42
}
43
44
#define FL_DIR (1 << 0)
46
#define FL_SYMLINK (1 << 2)
47
#define FL_LSTATERR (1 << 3)
48
#define FL_ERR (1 << 4)
49
+#define FL_FULLPATH (1 << 5)
50
51
/*
52
* Check if name 'name' of length 'len' has a symlink leading
53
* component, or if the directory exists and is real, or not.
54
*
55
* To speed up the check, some information is allowed to be cached.
53
- * This can be indicated by the 'track_flags' argument.
56
+ * This can be indicated by the 'track_flags' argument, which also can
57
+ * be used to indicate that we should check the full path.
58
+ *
59
+ * The 'prefix_len_stat_func' parameter can be used to set the length
60
+ * of the prefix, where the cache should use the stat() function
61
+ * instead of the lstat() function to test each path component.
62
*/
63
static int lstat_cache(int len, const char *name,
56
- int track_flags)
64
+ int track_flags, int prefix_len_stat_func)
65
{
66
int match_len, last_slash, last_slash_dir;
59
- int match_flags, ret_flags, save_flags, max_len;
67
+ int match_flags, ret_flags, save_flags, max_len, ret;
68
struct stat st;
69
62
- if (cache.track_flags != track_flags) {
70
+ if (cache.track_flags != track_flags ||
71
+ cache.prefix_len_stat_func != prefix_len_stat_func) {
72
/*
64
- * As a safeguard we clear the cache if the value of
65
- * track_flags does not match with the last supplied
66
- * value.
73
+ * As a safeguard we clear the cache if the values of
74
+ * track_flags and/or prefix_len_stat_func does not
75
+ * match with the last supplied values.
76
*/
68
- reset_lstat_cache(track_flags);
77
+ reset_lstat_cache(track_flags, prefix_len_stat_func);
78
match_len = last_slash = 0;
79
} else {
80
/*
110
cache.path[match_len] = name[match_len];
111
match_len++;
112
} while (match_len < max_len && name[match_len] != '/');
104
- if (match_len >= max_len)
113
+ if (match_len >= max_len && !(track_flags & FL_FULLPATH))
114
break;
115
last_slash = match_len;
116
cache.path[last_slash] = '\0';
117
109
- if (lstat(cache.path, &st)) {
118
+ if (last_slash <= prefix_len_stat_func)
119
+ ret = stat(cache.path, &st);
120
+ else
121
+ ret = lstat(cache.path, &st);
122
+
123
+ if (ret) {
124
ret_flags = FL_LSTATERR;
125
if (errno == ENOENT)
126
ret_flags |= FL_NOENT;
141
* for the moment!
142
*/
143
save_flags = ret_flags & track_flags & (FL_NOENT|FL_SYMLINK);
130
- if (save_flags && last_slash > 0 && last_slash < PATH_MAX) {
144
+ if (save_flags && last_slash > 0 && last_slash <= PATH_MAX) {
145
cache.path[last_slash] = '\0';
146
cache.len = last_slash;
147
cache.flags = save_flags;
148
} else if (track_flags & FL_DIR &&
135
- last_slash_dir > 0 && last_slash_dir < PATH_MAX) {
149
+ last_slash_dir > 0 && last_slash_dir <= PATH_MAX) {
150
/*
151
* We have a separate test for the directory case,
152
* since it could be that we have found a symlink or a
162
cache.len = last_slash_dir;
163
cache.flags = FL_DIR;
164
} else {
151
- reset_lstat_cache(track_flags);
165
+ reset_lstat_cache(track_flags, prefix_len_stat_func);
166
}
167
return ret_flags;
168
}
169
170
+#define USE_ONLY_LSTAT 0
171
+
172
/*
173
* Return non-zero if path 'name' has a leading symlink component
174
*/
175
int has_symlink_leading_path(int len, const char *name)
176
{
177
return lstat_cache(len, name,
162
- FL_SYMLINK|FL_DIR) &
178
+ FL_SYMLINK|FL_DIR, USE_ONLY_LSTAT) &
179
FL_SYMLINK;
180
}
181
186
int has_symlink_or_noent_leading_path(int len, const char *name)
187
{
188
return lstat_cache(len, name,
173
- FL_SYMLINK|FL_NOENT|FL_DIR) &
189
+ FL_SYMLINK|FL_NOENT|FL_DIR, USE_ONLY_LSTAT) &
190
(FL_SYMLINK|FL_NOENT);
191
}
192
+
193
+/*
194
+ * Return non-zero if all path components of 'name' exists as a
195
+ * directory. If prefix_len > 0, we will test with the stat()
196
+ * function instead of the lstat() function for a prefix length of
197
+ * 'prefix_len', thus we then allow for symlinks in the prefix part as
198
+ * long as those points to real existing directories.
199
+ */
200
+int has_dirs_only_path(int len, const char *name, int prefix_len)
201
+{
202
+ return lstat_cache(len, name,
203
+ FL_DIR|FL_FULLPATH, prefix_len) &
204
+ FL_DIR;
205
+}