Coverage Report

Created: 2026-03-31 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/git/symlinks.c
Line
Count
Source
1
#define DISABLE_SIGN_COMPARE_WARNINGS
2
3
#include "git-compat-util.h"
4
#include "gettext.h"
5
#include "setup.h"
6
#include "symlinks.h"
7
8
static int threaded_check_leading_path(struct cache_def *cache, const char *name,
9
               int len, int warn_on_lstat_err);
10
static int threaded_has_dirs_only_path(struct cache_def *cache, const char *name, int len, int prefix_len);
11
12
/*
13
 * Returns the length (on a path component basis) of the longest
14
 * common prefix match of 'name_a' and 'name_b'.
15
 */
16
static int longest_path_match(const char *name_a, int len_a,
17
            const char *name_b, int len_b,
18
            int *previous_slash)
19
0
{
20
0
  int max_len, match_len = 0, match_len_prev = 0, i = 0;
21
22
0
  max_len = len_a < len_b ? len_a : len_b;
23
0
  while (i < max_len && name_a[i] == name_b[i]) {
24
0
    if (name_a[i] == '/') {
25
0
      match_len_prev = match_len;
26
0
      match_len = i;
27
0
    }
28
0
    i++;
29
0
  }
30
  /*
31
   * Is 'name_b' a substring of 'name_a', the other way around,
32
   * or is 'name_a' and 'name_b' the exact same string?
33
   */
34
0
  if (i >= max_len && ((len_a > len_b && name_a[len_b] == '/') ||
35
0
           (len_a < len_b && name_b[len_a] == '/') ||
36
0
           (len_a == len_b))) {
37
0
    match_len_prev = match_len;
38
0
    match_len = i;
39
0
  }
40
0
  *previous_slash = match_len_prev;
41
0
  return match_len;
42
0
}
43
44
static struct cache_def default_cache = CACHE_DEF_INIT;
45
46
static inline void reset_lstat_cache(struct cache_def *cache)
47
0
{
48
0
  strbuf_reset(&cache->path);
49
0
  cache->flags = 0;
50
  /*
51
   * The track_flags and prefix_len_stat_func members is only
52
   * set by the safeguard rule inside lstat_cache()
53
   */
54
0
}
55
56
0
#define FL_DIR      (1 << 0)
57
0
#define FL_NOENT    (1 << 1)
58
0
#define FL_SYMLINK  (1 << 2)
59
0
#define FL_LSTATERR (1 << 3)
60
0
#define FL_ERR      (1 << 4)
61
0
#define FL_FULLPATH (1 << 5)
62
63
/*
64
 * Check if name 'name' of length 'len' has a symlink leading
65
 * component, or if the directory exists and is real, or not.
66
 *
67
 * To speed up the check, some information is allowed to be cached.
68
 * This can be indicated by the 'track_flags' argument, which also can
69
 * be used to indicate that we should check the full path.
70
 *
71
 * The 'prefix_len_stat_func' parameter can be used to set the length
72
 * of the prefix, where the cache should use the stat() function
73
 * instead of the lstat() function to test each path component.
74
 */
75
static int lstat_cache_matchlen(struct cache_def *cache,
76
        const char *name, int len,
77
        unsigned int *ret_flags, unsigned int track_flags,
78
        int prefix_len_stat_func)
79
0
{
80
0
  int match_len, last_slash, last_slash_dir, previous_slash;
81
0
  unsigned int save_flags;
82
0
  int ret, saved_errno = 0;
83
0
  struct stat st;
84
85
0
  if (cache->track_flags != track_flags ||
86
0
      cache->prefix_len_stat_func != prefix_len_stat_func) {
87
    /*
88
     * As a safeguard rule we clear the cache if the
89
     * values of track_flags and/or prefix_len_stat_func
90
     * does not match with the last supplied values.
91
     */
92
0
    reset_lstat_cache(cache);
93
0
    cache->track_flags = track_flags;
94
0
    cache->prefix_len_stat_func = prefix_len_stat_func;
95
0
    match_len = last_slash = 0;
96
0
  } else {
97
    /*
98
     * Check to see if we have a match from the cache for
99
     * the 2 "excluding" path types.
100
     */
101
0
    match_len = last_slash =
102
0
      longest_path_match(name, len, cache->path.buf,
103
0
             cache->path.len, &previous_slash);
104
0
    *ret_flags = cache->flags & track_flags & (FL_NOENT|FL_SYMLINK);
105
106
0
    if (!(track_flags & FL_FULLPATH) && match_len == len)
107
0
      match_len = last_slash = previous_slash;
108
109
0
    if (*ret_flags && match_len == cache->path.len)
110
0
      return match_len;
111
    /*
112
     * If we now have match_len > 0, we would know that
113
     * the matched part will always be a directory.
114
     *
115
     * Also, if we are tracking directories and 'name' is
116
     * a substring of the cache on a path component basis,
117
     * we can return immediately.
118
     */
119
0
    *ret_flags = track_flags & FL_DIR;
120
0
    if (*ret_flags && len == match_len)
121
0
      return match_len;
122
0
  }
123
124
  /*
125
   * Okay, no match from the cache so far, so now we have to
126
   * check the rest of the path components.
127
   */
128
0
  *ret_flags = FL_DIR;
129
0
  last_slash_dir = last_slash;
130
0
  if (len > cache->path.len)
131
0
    strbuf_grow(&cache->path, len - cache->path.len);
132
0
  while (match_len < len) {
133
0
    do {
134
0
      cache->path.buf[match_len] = name[match_len];
135
0
      match_len++;
136
0
    } while (match_len < len && name[match_len] != '/');
137
0
    if (match_len >= len && !(track_flags & FL_FULLPATH))
138
0
      break;
139
0
    last_slash = match_len;
140
0
    cache->path.buf[last_slash] = '\0';
141
142
0
    if (last_slash <= prefix_len_stat_func)
143
0
      ret = stat(cache->path.buf, &st);
144
0
    else
145
0
      ret = lstat(cache->path.buf, &st);
146
147
0
    if (ret) {
148
0
      *ret_flags = FL_LSTATERR;
149
0
      saved_errno = errno;
150
0
      if (errno == ENOENT)
151
0
        *ret_flags |= FL_NOENT;
152
0
    } else if (S_ISDIR(st.st_mode)) {
153
0
      last_slash_dir = last_slash;
154
0
      continue;
155
0
    } else if (S_ISLNK(st.st_mode)) {
156
0
      *ret_flags = FL_SYMLINK;
157
0
    } else {
158
0
      *ret_flags = FL_ERR;
159
0
    }
160
0
    break;
161
0
  }
162
163
  /*
164
   * At the end update the cache.  Note that max 3 different
165
   * path types, FL_NOENT, FL_SYMLINK and FL_DIR, can be cached
166
   * for the moment!
167
   */
168
0
  save_flags = *ret_flags & track_flags & (FL_NOENT|FL_SYMLINK);
169
0
  if (save_flags && last_slash > 0) {
170
0
    cache->path.buf[last_slash] = '\0';
171
0
    cache->path.len = last_slash;
172
0
    cache->flags = save_flags;
173
0
  } else if ((track_flags & FL_DIR) && last_slash_dir > 0) {
174
    /*
175
     * We have a separate test for the directory case,
176
     * since it could be that we have found a symlink or a
177
     * non-existing directory and the track_flags says
178
     * that we cannot cache this fact, so the cache would
179
     * then have been left empty in this case.
180
     *
181
     * But if we are allowed to track real directories, we
182
     * can still cache the path components before the last
183
     * one (the found symlink or non-existing component).
184
     */
185
0
    cache->path.buf[last_slash_dir] = '\0';
186
0
    cache->path.len = last_slash_dir;
187
0
    cache->flags = FL_DIR;
188
0
  } else {
189
0
    reset_lstat_cache(cache);
190
0
  }
191
0
  if (saved_errno)
192
0
    errno = saved_errno;
193
0
  return match_len;
194
0
}
195
196
static unsigned int lstat_cache(struct cache_def *cache, const char *name, int len,
197
           unsigned int track_flags, int prefix_len_stat_func)
198
0
{
199
0
  unsigned int flags;
200
0
  (void)lstat_cache_matchlen(cache, name, len, &flags, track_flags,
201
0
      prefix_len_stat_func);
202
0
  return flags;
203
0
}
204
205
0
#define USE_ONLY_LSTAT  0
206
207
/*
208
 * Return non-zero if path 'name' has a leading symlink component
209
 */
210
int threaded_has_symlink_leading_path(struct cache_def *cache, const char *name, int len)
211
0
{
212
0
  return lstat_cache(cache, name, len, FL_SYMLINK|FL_DIR, USE_ONLY_LSTAT) & FL_SYMLINK;
213
0
}
214
215
int has_symlink_leading_path(const char *name, int len)
216
0
{
217
0
  return threaded_has_symlink_leading_path(&default_cache, name, len);
218
0
}
219
220
int check_leading_path(const char *name, int len, int warn_on_lstat_err)
221
0
{
222
0
  return threaded_check_leading_path(&default_cache, name, len,
223
0
             warn_on_lstat_err);
224
0
}
225
226
/*
227
 * Return zero if some leading path component of 'name' does not exist.
228
 *
229
 * Return -1 if leading path exists and is a directory.
230
 *
231
 * Return the length of a leading component if it either exists but it's not a
232
 * directory, or if we were unable to lstat() it. If warn_on_lstat_err is true,
233
 * also emit a warning for this error.
234
 */
235
static int threaded_check_leading_path(struct cache_def *cache, const char *name,
236
               int len, int warn_on_lstat_err)
237
0
{
238
0
  unsigned int flags;
239
0
  int match_len = lstat_cache_matchlen(cache, name, len, &flags,
240
0
         FL_SYMLINK|FL_NOENT|FL_DIR, USE_ONLY_LSTAT);
241
0
  int saved_errno = errno;
242
243
0
  if (flags & FL_NOENT)
244
0
    return 0;
245
0
  else if (flags & FL_DIR)
246
0
    return -1;
247
0
  if (warn_on_lstat_err && (flags & FL_LSTATERR)) {
248
0
    char *path = xmemdupz(name, match_len);
249
0
    errno = saved_errno;
250
0
    warning_errno(_("failed to lstat '%s'"), path);
251
0
    free(path);
252
0
  }
253
0
  return match_len;
254
0
}
255
256
int has_dirs_only_path(const char *name, int len, int prefix_len)
257
0
{
258
0
  return threaded_has_dirs_only_path(&default_cache, name, len, prefix_len);
259
0
}
260
261
/*
262
 * Return non-zero if all path components of 'name' exists as a
263
 * directory.  If prefix_len > 0, we will test with the stat()
264
 * function instead of the lstat() function for a prefix length of
265
 * 'prefix_len', thus we then allow for symlinks in the prefix part as
266
 * long as those points to real existing directories.
267
 */
268
static int threaded_has_dirs_only_path(struct cache_def *cache, const char *name, int len, int prefix_len)
269
0
{
270
  /*
271
   * Note: this function is used by the checkout machinery, which also
272
   * takes care to properly reset the cache when it performs an operation
273
   * that would leave the cache outdated. If this function starts caching
274
   * anything else besides FL_DIR, remember to also invalidate the cache
275
   * when creating or deleting paths that might be in the cache.
276
   */
277
0
  return lstat_cache(cache, name, len,
278
0
         FL_DIR|FL_FULLPATH, prefix_len) &
279
0
    FL_DIR;
280
0
}
281
282
static struct strbuf removal = STRBUF_INIT;
283
284
static void do_remove_scheduled_dirs(int new_len)
285
0
{
286
0
  while (removal.len > new_len) {
287
0
    removal.buf[removal.len] = '\0';
288
0
    if ((startup_info->original_cwd &&
289
0
         !strcmp(removal.buf, startup_info->original_cwd)) ||
290
0
        rmdir(removal.buf))
291
0
      break;
292
0
    do {
293
0
      removal.len--;
294
0
    } while (removal.len > new_len &&
295
0
       removal.buf[removal.len] != '/');
296
0
  }
297
0
  removal.len = new_len;
298
0
}
299
300
void schedule_dir_for_removal(const char *name, int len)
301
0
{
302
0
  int match_len, last_slash, i, previous_slash;
303
304
0
  if (startup_info->original_cwd &&
305
0
      !strcmp(name, startup_info->original_cwd))
306
0
    return; /* Do not remove the current working directory */
307
308
0
  match_len = last_slash = i =
309
0
    longest_path_match(name, len, removal.buf, removal.len,
310
0
           &previous_slash);
311
  /* Find last slash inside 'name' */
312
0
  while (i < len) {
313
0
    if (name[i] == '/')
314
0
      last_slash = i;
315
0
    i++;
316
0
  }
317
318
  /*
319
   * If we are about to go down the directory tree, we check if
320
   * we must first go upwards the tree, such that we then can
321
   * remove possible empty directories as we go upwards.
322
   */
323
0
  if (match_len < last_slash && match_len < removal.len)
324
0
    do_remove_scheduled_dirs(match_len);
325
  /*
326
   * If we go deeper down the directory tree, we only need to
327
   * save the new path components as we go down.
328
   */
329
0
  if (match_len < last_slash)
330
0
    strbuf_add(&removal, &name[match_len], last_slash - match_len);
331
0
}
332
333
void remove_scheduled_dirs(void)
334
0
{
335
0
  do_remove_scheduled_dirs(0);
336
0
}
337
338
void invalidate_lstat_cache(void)
339
0
{
340
0
  reset_lstat_cache(&default_cache);
341
0
}
342
343
#undef rmdir
344
int lstat_cache_aware_rmdir(const char *path)
345
0
{
346
  /* Any change in this function must be made also in `mingw_rmdir()` */
347
0
  int ret = rmdir(path);
348
349
0
  if (!ret)
350
0
    invalidate_lstat_cache();
351
352
0
  return ret;
353
0
}