lstat_cache(): small cleanup and optimisation
[git/git.git] / symlinks.c
CommitLineData
f859c846
JH
1#include "cache.h"
2
92604b46 3static struct cache_def {
bad4a54f 4 char path[PATH_MAX + 1];
92604b46
KB
5 int len;
6 int flags;
09c93066 7 int track_flags;
bad4a54f 8 int prefix_len_stat_func;
92604b46 9} cache;
c40641b7 10
92604b46
KB
11/*
12 * Returns the length (on a path component basis) of the longest
13 * common prefix match of 'name' and the cached path string.
14 */
aeabab5c
KB
15static inline int longest_match_lstat_cache(int len, const char *name,
16 int *previous_slash)
c40641b7 17{
aeabab5c 18 int max_len, match_len = 0, match_len_prev = 0, i = 0;
92604b46
KB
19
20 max_len = len < cache.len ? len : cache.len;
21 while (i < max_len && name[i] == cache.path[i]) {
aeabab5c
KB
22 if (name[i] == '/') {
23 match_len_prev = match_len;
92604b46 24 match_len = i;
aeabab5c 25 }
92604b46
KB
26 i++;
27 }
60b458b7
KB
28 /*
29 * Is the cached path string a substring of 'name', is 'name'
30 * a substring of the cached path string, or is 'name' and the
31 * cached path string the exact same string?
32 */
33 if (i >= max_len && ((len > cache.len && name[cache.len] == '/') ||
34 (len < cache.len && cache.path[len] == '/') ||
35 (len == cache.len))) {
aeabab5c 36 match_len_prev = match_len;
60b458b7 37 match_len = i;
aeabab5c
KB
38 }
39 *previous_slash = match_len_prev;
92604b46 40 return match_len;
c40641b7
LT
41}
42
60b458b7 43static inline void reset_lstat_cache(void)
c40641b7 44{
92604b46
KB
45 cache.path[0] = '\0';
46 cache.len = 0;
47 cache.flags = 0;
60b458b7
KB
48 /*
49 * The track_flags and prefix_len_stat_func members is only
50 * set by the safeguard rule inside lstat_cache()
51 */
c40641b7
LT
52}
53
92604b46 54#define FL_DIR (1 << 0)
09c93066
KB
55#define FL_NOENT (1 << 1)
56#define FL_SYMLINK (1 << 2)
57#define FL_LSTATERR (1 << 3)
58#define FL_ERR (1 << 4)
bad4a54f 59#define FL_FULLPATH (1 << 5)
92604b46
KB
60
61/*
62 * Check if name 'name' of length 'len' has a symlink leading
09c93066 63 * component, or if the directory exists and is real, or not.
92604b46
KB
64 *
65 * To speed up the check, some information is allowed to be cached.
bad4a54f
KB
66 * This can be indicated by the 'track_flags' argument, which also can
67 * be used to indicate that we should check the full path.
68 *
69 * The 'prefix_len_stat_func' parameter can be used to set the length
70 * of the prefix, where the cache should use the stat() function
71 * instead of the lstat() function to test each path component.
92604b46
KB
72 */
73static int lstat_cache(int len, const char *name,
bad4a54f 74 int track_flags, int prefix_len_stat_func)
c40641b7 75{
aeabab5c 76 int match_len, last_slash, last_slash_dir, previous_slash;
bad4a54f 77 int match_flags, ret_flags, save_flags, max_len, ret;
c40641b7 78 struct stat st;
f859c846 79
bad4a54f
KB
80 if (cache.track_flags != track_flags ||
81 cache.prefix_len_stat_func != prefix_len_stat_func) {
09c93066 82 /*
60b458b7
KB
83 * As a safeguard rule we clear the cache if the
84 * values of track_flags and/or prefix_len_stat_func
85 * does not match with the last supplied values.
09c93066 86 */
60b458b7
KB
87 reset_lstat_cache();
88 cache.track_flags = track_flags;
89 cache.prefix_len_stat_func = prefix_len_stat_func;
09c93066
KB
90 match_len = last_slash = 0;
91 } else {
92 /*
93 * Check to see if we have a match from the cache for
94 * the 2 "excluding" path types.
95 */
aeabab5c
KB
96 match_len = last_slash =
97 longest_match_lstat_cache(len, name, &previous_slash);
09c93066
KB
98 match_flags = cache.flags & track_flags & (FL_NOENT|FL_SYMLINK);
99 if (match_flags && match_len == cache.len)
100 return match_flags;
101 /*
102 * If we now have match_len > 0, we would know that
103 * the matched part will always be a directory.
104 *
105 * Also, if we are tracking directories and 'name' is
106 * a substring of the cache on a path component basis,
107 * we can return immediately.
108 */
109 match_flags = track_flags & FL_DIR;
110 if (match_flags && len == match_len)
111 return match_flags;
112 }
c40641b7 113
92604b46
KB
114 /*
115 * Okay, no match from the cache so far, so now we have to
116 * check the rest of the path components.
117 */
118 ret_flags = FL_DIR;
119 last_slash_dir = last_slash;
120 max_len = len < PATH_MAX ? len : PATH_MAX;
121 while (match_len < max_len) {
122 do {
123 cache.path[match_len] = name[match_len];
124 match_len++;
125 } while (match_len < max_len && name[match_len] != '/');
bad4a54f 126 if (match_len >= max_len && !(track_flags & FL_FULLPATH))
92604b46
KB
127 break;
128 last_slash = match_len;
129 cache.path[last_slash] = '\0';
f859c846 130
bad4a54f
KB
131 if (last_slash <= prefix_len_stat_func)
132 ret = stat(cache.path, &st);
133 else
134 ret = lstat(cache.path, &st);
135
136 if (ret) {
92604b46 137 ret_flags = FL_LSTATERR;
09c93066
KB
138 if (errno == ENOENT)
139 ret_flags |= FL_NOENT;
92604b46
KB
140 } else if (S_ISDIR(st.st_mode)) {
141 last_slash_dir = last_slash;
c40641b7 142 continue;
92604b46
KB
143 } else if (S_ISLNK(st.st_mode)) {
144 ret_flags = FL_SYMLINK;
145 } else {
146 ret_flags = FL_ERR;
f859c846 147 }
c40641b7 148 break;
f859c846 149 }
92604b46
KB
150
151 /*
09c93066
KB
152 * At the end update the cache. Note that max 3 different
153 * path types, FL_NOENT, FL_SYMLINK and FL_DIR, can be cached
154 * for the moment!
92604b46 155 */
09c93066 156 save_flags = ret_flags & track_flags & (FL_NOENT|FL_SYMLINK);
bad4a54f 157 if (save_flags && last_slash > 0 && last_slash <= PATH_MAX) {
92604b46
KB
158 cache.path[last_slash] = '\0';
159 cache.len = last_slash;
160 cache.flags = save_flags;
60b458b7 161 } else if ((track_flags & FL_DIR) &&
bad4a54f 162 last_slash_dir > 0 && last_slash_dir <= PATH_MAX) {
92604b46
KB
163 /*
164 * We have a separate test for the directory case,
09c93066
KB
165 * since it could be that we have found a symlink or a
166 * non-existing directory and the track_flags says
167 * that we cannot cache this fact, so the cache would
168 * then have been left empty in this case.
92604b46
KB
169 *
170 * But if we are allowed to track real directories, we
171 * can still cache the path components before the last
09c93066 172 * one (the found symlink or non-existing component).
92604b46
KB
173 */
174 cache.path[last_slash_dir] = '\0';
175 cache.len = last_slash_dir;
176 cache.flags = FL_DIR;
177 } else {
60b458b7 178 reset_lstat_cache();
92604b46
KB
179 }
180 return ret_flags;
181}
182
aeabab5c
KB
183/*
184 * Invalidate the given 'name' from the cache, if 'name' matches
185 * completely with the cache.
186 */
187void invalidate_lstat_cache(int len, const char *name)
188{
189 int match_len, previous_slash;
190
191 match_len = longest_match_lstat_cache(len, name, &previous_slash);
192 if (len == match_len) {
193 if ((cache.track_flags & FL_DIR) && previous_slash > 0) {
194 cache.path[previous_slash] = '\0';
195 cache.len = previous_slash;
196 cache.flags = FL_DIR;
197 } else
60b458b7 198 reset_lstat_cache();
aeabab5c
KB
199 }
200}
201
bda6eb0d
KB
202/*
203 * Completely clear the contents of the cache
204 */
205void clear_lstat_cache(void)
206{
60b458b7 207 reset_lstat_cache();
bda6eb0d
KB
208}
209
bad4a54f
KB
210#define USE_ONLY_LSTAT 0
211
92604b46
KB
212/*
213 * Return non-zero if path 'name' has a leading symlink component
214 */
215int has_symlink_leading_path(int len, const char *name)
216{
217 return lstat_cache(len, name,
bad4a54f 218 FL_SYMLINK|FL_DIR, USE_ONLY_LSTAT) &
92604b46 219 FL_SYMLINK;
f859c846 220}
09c93066
KB
221
222/*
223 * Return non-zero if path 'name' has a leading symlink component or
224 * if some leading path component does not exists.
225 */
226int has_symlink_or_noent_leading_path(int len, const char *name)
227{
228 return lstat_cache(len, name,
bad4a54f 229 FL_SYMLINK|FL_NOENT|FL_DIR, USE_ONLY_LSTAT) &
09c93066
KB
230 (FL_SYMLINK|FL_NOENT);
231}
bad4a54f
KB
232
233/*
234 * Return non-zero if all path components of 'name' exists as a
235 * directory. If prefix_len > 0, we will test with the stat()
236 * function instead of the lstat() function for a prefix length of
237 * 'prefix_len', thus we then allow for symlinks in the prefix part as
238 * long as those points to real existing directories.
239 */
240int has_dirs_only_path(int len, const char *name, int prefix_len)
241{
242 return lstat_cache(len, name,
243 FL_DIR|FL_FULLPATH, prefix_len) &
244 FL_DIR;
245}