Coverage Report

Created: 2024-09-16 06:10

/src/git/sparse-index.c
Line
Count
Source (jump to first uncovered line)
1
#include "git-compat-util.h"
2
#include "environment.h"
3
#include "gettext.h"
4
#include "name-hash.h"
5
#include "read-cache-ll.h"
6
#include "repository.h"
7
#include "sparse-index.h"
8
#include "tree.h"
9
#include "pathspec.h"
10
#include "trace2.h"
11
#include "cache-tree.h"
12
#include "config.h"
13
#include "dir.h"
14
#include "fsmonitor-ll.h"
15
#include "advice.h"
16
17
/**
18
 * This global is used by expand_index() to determine if we should give the
19
 * advice for advice.sparseIndexExpanded when expanding a sparse index to a full
20
 * one. However, this is sometimes done on purpose, such as in the sparse-checkout
21
 * builtin, even when index.sparse=false. This may be disabled in
22
 * convert_to_sparse().
23
 */
24
static int give_advice_on_expansion = 1;
25
#define ADVICE_MSG \
26
0
  "The sparse index is expanding to a full index, a slow operation.\n"   \
27
0
  "Your working directory likely has contents that are outside of\n"     \
28
0
  "your sparse-checkout patterns. Use 'git sparse-checkout list' to\n"   \
29
0
  "see your sparse-checkout definition and compare it to your working\n" \
30
0
  "directory contents. Running 'git clean' may assist in this cleanup."
31
32
struct modify_index_context {
33
  struct index_state *write;
34
  struct pattern_list *pl;
35
};
36
37
static struct cache_entry *construct_sparse_dir_entry(
38
        struct index_state *istate,
39
        const char *sparse_dir,
40
        struct cache_tree *tree)
41
0
{
42
0
  struct cache_entry *de;
43
44
0
  de = make_cache_entry(istate, S_IFDIR, &tree->oid, sparse_dir, 0, 0);
45
46
0
  de->ce_flags |= CE_SKIP_WORKTREE;
47
0
  return de;
48
0
}
49
50
/*
51
 * Returns the number of entries "inserted" into the index.
52
 */
53
static int convert_to_sparse_rec(struct index_state *istate,
54
         int num_converted,
55
         int start, int end,
56
         const char *ct_path, size_t ct_pathlen,
57
         struct cache_tree *ct)
58
0
{
59
0
  int i, can_convert = 1;
60
0
  int start_converted = num_converted;
61
0
  struct strbuf child_path = STRBUF_INIT;
62
63
  /*
64
   * Is the current path outside of the sparse cone?
65
   * Then check if the region can be replaced by a sparse
66
   * directory entry (everything is sparse and merged).
67
   */
68
0
  if (path_in_sparse_checkout(ct_path, istate))
69
0
    can_convert = 0;
70
71
0
  for (i = start; can_convert && i < end; i++) {
72
0
    struct cache_entry *ce = istate->cache[i];
73
74
0
    if (ce_stage(ce) ||
75
0
        S_ISGITLINK(ce->ce_mode) ||
76
0
        !(ce->ce_flags & CE_SKIP_WORKTREE))
77
0
      can_convert = 0;
78
0
  }
79
80
0
  if (can_convert) {
81
0
    struct cache_entry *se;
82
0
    se = construct_sparse_dir_entry(istate, ct_path, ct);
83
84
0
    istate->cache[num_converted++] = se;
85
0
    return 1;
86
0
  }
87
88
0
  for (i = start; i < end; ) {
89
0
    int count, span, pos = -1;
90
0
    const char *base, *slash;
91
0
    struct cache_entry *ce = istate->cache[i];
92
93
    /*
94
     * Detect if this is a normal entry outside of any subtree
95
     * entry.
96
     */
97
0
    base = ce->name + ct_pathlen;
98
0
    slash = strchr(base, '/');
99
100
0
    if (slash)
101
0
      pos = cache_tree_subtree_pos(ct, base, slash - base);
102
103
0
    if (pos < 0) {
104
0
      istate->cache[num_converted++] = ce;
105
0
      i++;
106
0
      continue;
107
0
    }
108
109
0
    strbuf_setlen(&child_path, 0);
110
0
    strbuf_add(&child_path, ce->name, slash - ce->name + 1);
111
112
0
    span = ct->down[pos]->cache_tree->entry_count;
113
0
    count = convert_to_sparse_rec(istate,
114
0
                num_converted, i, i + span,
115
0
                child_path.buf, child_path.len,
116
0
                ct->down[pos]->cache_tree);
117
0
    num_converted += count;
118
0
    i += span;
119
0
  }
120
121
0
  strbuf_release(&child_path);
122
0
  return num_converted - start_converted;
123
0
}
124
125
int set_sparse_index_config(struct repository *repo, int enable)
126
0
{
127
0
  int res = repo_config_set_worktree_gently(repo,
128
0
              "index.sparse",
129
0
              enable ? "true" : "false");
130
0
  prepare_repo_settings(repo);
131
0
  repo->settings.sparse_index = enable;
132
0
  return res;
133
0
}
134
135
static int index_has_unmerged_entries(struct index_state *istate)
136
0
{
137
0
  int i;
138
0
  for (i = 0; i < istate->cache_nr; i++) {
139
0
    if (ce_stage(istate->cache[i]))
140
0
      return 1;
141
0
  }
142
143
0
  return 0;
144
0
}
145
146
int is_sparse_index_allowed(struct index_state *istate, int flags)
147
0
{
148
0
  if (!core_apply_sparse_checkout || !core_sparse_checkout_cone)
149
0
    return 0;
150
151
0
  if (!(flags & SPARSE_INDEX_MEMORY_ONLY)) {
152
0
    int test_env;
153
154
    /*
155
     * The sparse index is not (yet) integrated with a split index.
156
     */
157
0
    if (istate->split_index || git_env_bool("GIT_TEST_SPLIT_INDEX", 0))
158
0
      return 0;
159
    /*
160
     * The GIT_TEST_SPARSE_INDEX environment variable triggers the
161
     * index.sparse config variable to be on.
162
     */
163
0
    test_env = git_env_bool("GIT_TEST_SPARSE_INDEX", -1);
164
0
    if (test_env >= 0)
165
0
      set_sparse_index_config(istate->repo, test_env);
166
167
    /*
168
     * Only convert to sparse if index.sparse is set.
169
     */
170
0
    prepare_repo_settings(istate->repo);
171
0
    if (!istate->repo->settings.sparse_index)
172
0
      return 0;
173
0
  }
174
175
0
  if (init_sparse_checkout_patterns(istate))
176
0
    return 0;
177
178
  /*
179
   * We need cone-mode patterns to use sparse-index. If a user edits
180
   * their sparse-checkout file manually, then we can detect during
181
   * parsing that they are not actually using cone-mode patterns and
182
   * hence we need to abort this conversion _without error_. Warnings
183
   * already exist in the pattern parsing to inform the user of their
184
   * bad patterns.
185
   */
186
0
  if (!istate->sparse_checkout_patterns->use_cone_patterns)
187
0
    return 0;
188
189
0
  return 1;
190
0
}
191
192
int convert_to_sparse(struct index_state *istate, int flags)
193
0
{
194
  /*
195
   * If the index is already sparse, empty, or otherwise
196
   * cannot be converted to sparse, do not convert.
197
   */
198
0
  if (istate->sparse_index == INDEX_COLLAPSED || !istate->cache_nr ||
199
0
      !is_sparse_index_allowed(istate, flags))
200
0
    return 0;
201
202
  /*
203
   * If we are purposefully collapsing a full index, then don't give
204
   * advice when it is expanded later.
205
   */
206
0
  give_advice_on_expansion = 0;
207
208
  /*
209
   * NEEDSWORK: If we have unmerged entries, then stay full.
210
   * Unmerged entries prevent the cache-tree extension from working.
211
   */
212
0
  if (index_has_unmerged_entries(istate))
213
0
    return 0;
214
215
0
  if (!cache_tree_fully_valid(istate->cache_tree)) {
216
    /* Clear and recompute the cache-tree */
217
0
    cache_tree_free(&istate->cache_tree);
218
219
    /*
220
     * Silently return if there is a problem with the cache tree update,
221
     * which might just be due to a conflict state in some entry.
222
     *
223
     * This might create new tree objects, so be sure to use
224
     * WRITE_TREE_MISSING_OK.
225
     */
226
0
    if (cache_tree_update(istate, WRITE_TREE_MISSING_OK))
227
0
      return 0;
228
0
  }
229
230
0
  remove_fsmonitor(istate);
231
232
0
  trace2_region_enter("index", "convert_to_sparse", istate->repo);
233
0
  istate->cache_nr = convert_to_sparse_rec(istate,
234
0
             0, 0, istate->cache_nr,
235
0
             "", 0, istate->cache_tree);
236
237
  /* Clear and recompute the cache-tree */
238
0
  cache_tree_free(&istate->cache_tree);
239
0
  cache_tree_update(istate, 0);
240
241
0
  istate->fsmonitor_has_run_once = 0;
242
0
  FREE_AND_NULL(istate->fsmonitor_dirty);
243
0
  FREE_AND_NULL(istate->fsmonitor_last_update);
244
245
0
  istate->sparse_index = INDEX_COLLAPSED;
246
0
  trace2_region_leave("index", "convert_to_sparse", istate->repo);
247
0
  return 0;
248
0
}
249
250
static void set_index_entry(struct index_state *istate, int nr, struct cache_entry *ce)
251
0
{
252
0
  ALLOC_GROW(istate->cache, nr + 1, istate->cache_alloc);
253
254
0
  istate->cache[nr] = ce;
255
0
  add_name_hash(istate, ce);
256
0
}
257
258
static int add_path_to_index(const struct object_id *oid,
259
           struct strbuf *base, const char *path,
260
           unsigned int mode, void *context)
261
0
{
262
0
  struct modify_index_context *ctx = (struct modify_index_context *)context;
263
0
  struct cache_entry *ce;
264
0
  size_t len = base->len;
265
266
0
  if (S_ISDIR(mode)) {
267
0
    int dtype;
268
0
    size_t baselen = base->len;
269
0
    if (!ctx->pl)
270
0
      return READ_TREE_RECURSIVE;
271
272
    /*
273
     * Have we expanded to a point outside of the sparse-checkout?
274
     *
275
     * Artificially pad the path name with a slash "/" to
276
     * indicate it as a directory, and add an arbitrary file
277
     * name ("-") so we can consider base->buf as a file name
278
     * to match against the cone-mode patterns.
279
     *
280
     * If we compared just "path", then we would expand more
281
     * than we should. Since every file at root is always
282
     * included, we would expand every directory at root at
283
     * least one level deep instead of using sparse directory
284
     * entries.
285
     */
286
0
    strbuf_addstr(base, path);
287
0
    strbuf_add(base, "/-", 2);
288
289
0
    if (path_matches_pattern_list(base->buf, base->len,
290
0
                NULL, &dtype,
291
0
                ctx->pl, ctx->write)) {
292
0
      strbuf_setlen(base, baselen);
293
0
      return READ_TREE_RECURSIVE;
294
0
    }
295
296
    /*
297
     * The path "{base}{path}/" is a sparse directory. Create the correct
298
     * name for inserting the entry into the index.
299
     */
300
0
    strbuf_setlen(base, base->len - 1);
301
0
  } else {
302
0
    strbuf_addstr(base, path);
303
0
  }
304
305
0
  ce = make_cache_entry(ctx->write, mode, oid, base->buf, 0, 0);
306
0
  ce->ce_flags |= CE_SKIP_WORKTREE | CE_EXTENDED;
307
0
  set_index_entry(ctx->write, ctx->write->cache_nr++, ce);
308
309
0
  strbuf_setlen(base, len);
310
0
  return 0;
311
0
}
312
313
void expand_index(struct index_state *istate, struct pattern_list *pl)
314
0
{
315
0
  int i;
316
0
  struct index_state *full;
317
0
  struct strbuf base = STRBUF_INIT;
318
0
  const char *tr_region;
319
0
  struct modify_index_context ctx;
320
321
  /*
322
   * If the index is already full, then keep it full. We will convert
323
   * it to a sparse index on write, if possible.
324
   */
325
0
  if (istate->sparse_index == INDEX_EXPANDED)
326
0
    return;
327
328
  /*
329
   * If our index is sparse, but our new pattern set does not use
330
   * cone mode patterns, then we need to expand the index before we
331
   * continue. A NULL pattern set indicates a full expansion to a
332
   * full index.
333
   */
334
0
  if (pl && !pl->use_cone_patterns) {
335
0
    pl = NULL;
336
0
  } else {
337
    /*
338
     * We might contract file entries into sparse-directory
339
     * entries, and for that we will need the cache tree to
340
     * be recomputed.
341
     */
342
0
    cache_tree_free(&istate->cache_tree);
343
344
    /*
345
     * If there is a problem creating the cache tree, then we
346
     * need to expand to a full index since we cannot satisfy
347
     * the current request as a sparse index.
348
     */
349
0
    if (cache_tree_update(istate, 0))
350
0
      pl = NULL;
351
0
  }
352
353
0
  if (!pl && give_advice_on_expansion) {
354
0
    give_advice_on_expansion = 0;
355
0
    advise_if_enabled(ADVICE_SPARSE_INDEX_EXPANDED,
356
0
          _(ADVICE_MSG));
357
0
  }
358
359
  /*
360
   * A NULL pattern set indicates we are expanding a full index, so
361
   * we use a special region name that indicates the full expansion.
362
   * This is used by test cases, but also helps to differentiate the
363
   * two cases.
364
   */
365
0
  tr_region = pl ? "expand_index" : "ensure_full_index";
366
0
  trace2_region_enter("index", tr_region, istate->repo);
367
368
  /* initialize basics of new index */
369
0
  full = xcalloc(1, sizeof(struct index_state));
370
0
  memcpy(full, istate, sizeof(struct index_state));
371
372
  /*
373
   * This slightly-misnamed 'full' index might still be sparse if we
374
   * are only modifying the list of sparse directories. This hinges
375
   * on whether we have a non-NULL pattern list.
376
   */
377
0
  full->sparse_index = pl ? INDEX_PARTIALLY_SPARSE : INDEX_EXPANDED;
378
379
  /* then change the necessary things */
380
0
  full->cache_alloc = (3 * istate->cache_alloc) / 2;
381
0
  full->cache_nr = 0;
382
0
  ALLOC_ARRAY(full->cache, full->cache_alloc);
383
384
0
  ctx.write = full;
385
0
  ctx.pl = pl;
386
387
0
  for (i = 0; i < istate->cache_nr; i++) {
388
0
    struct cache_entry *ce = istate->cache[i];
389
0
    struct tree *tree;
390
0
    struct pathspec ps;
391
0
    int dtype;
392
393
0
    if (!S_ISSPARSEDIR(ce->ce_mode)) {
394
0
      set_index_entry(full, full->cache_nr++, ce);
395
0
      continue;
396
0
    }
397
398
    /* We now have a sparse directory entry. Should we expand? */
399
0
    if (pl &&
400
0
        path_matches_pattern_list(ce->name, ce->ce_namelen,
401
0
                NULL, &dtype,
402
0
                pl, istate) == NOT_MATCHED) {
403
0
      set_index_entry(full, full->cache_nr++, ce);
404
0
      continue;
405
0
    }
406
407
0
    if (!(ce->ce_flags & CE_SKIP_WORKTREE))
408
0
      warning(_("index entry is a directory, but not sparse (%08x)"),
409
0
        ce->ce_flags);
410
411
    /* recursively walk into cd->name */
412
0
    tree = lookup_tree(istate->repo, &ce->oid);
413
414
0
    memset(&ps, 0, sizeof(ps));
415
0
    ps.recursive = 1;
416
0
    ps.has_wildcard = 1;
417
0
    ps.max_depth = -1;
418
419
0
    strbuf_setlen(&base, 0);
420
0
    strbuf_add(&base, ce->name, strlen(ce->name));
421
422
0
    read_tree_at(istate->repo, tree, &base, 0, &ps,
423
0
           add_path_to_index, &ctx);
424
425
    /* free directory entries. full entries are re-used */
426
0
    discard_cache_entry(ce);
427
0
  }
428
429
  /* Copy back into original index. */
430
0
  memcpy(&istate->name_hash, &full->name_hash, sizeof(full->name_hash));
431
0
  memcpy(&istate->dir_hash, &full->dir_hash, sizeof(full->dir_hash));
432
0
  istate->sparse_index = pl ? INDEX_PARTIALLY_SPARSE : INDEX_EXPANDED;
433
0
  free(istate->cache);
434
0
  istate->cache = full->cache;
435
0
  istate->cache_nr = full->cache_nr;
436
0
  istate->cache_alloc = full->cache_alloc;
437
0
  istate->fsmonitor_has_run_once = 0;
438
0
  FREE_AND_NULL(istate->fsmonitor_dirty);
439
0
  FREE_AND_NULL(istate->fsmonitor_last_update);
440
441
0
  strbuf_release(&base);
442
0
  free(full);
443
444
  /* Clear and recompute the cache-tree */
445
0
  cache_tree_free(&istate->cache_tree);
446
0
  cache_tree_update(istate, 0);
447
448
0
  trace2_region_leave("index", tr_region, istate->repo);
449
0
}
450
451
void ensure_full_index(struct index_state *istate)
452
0
{
453
0
  if (!istate)
454
0
    BUG("ensure_full_index() must get an index!");
455
0
  expand_index(istate, NULL);
456
0
}
457
458
void ensure_correct_sparsity(struct index_state *istate)
459
0
{
460
  /*
461
   * If the index can be sparse, make it sparse. Otherwise,
462
   * ensure the index is full.
463
   */
464
0
  if (is_sparse_index_allowed(istate, 0))
465
0
    convert_to_sparse(istate, 0);
466
0
  else
467
0
    ensure_full_index(istate);
468
0
}
469
470
struct path_found_data {
471
  /**
472
   * The path stored in 'dir', if non-empty, corresponds to the most-
473
   * recent path that we checked where:
474
   *
475
   *   1. The path should be a directory, according to the index.
476
   *   2. The path does not exist.
477
   *   3. The parent path _does_ exist. (This may be the root of the
478
   *      working directory.)
479
   */
480
  struct strbuf dir;
481
  size_t lstat_count;
482
};
483
484
0
#define PATH_FOUND_DATA_INIT { \
485
0
  .dir = STRBUF_INIT \
486
0
}
487
488
static void clear_path_found_data(struct path_found_data *data)
489
0
{
490
0
  strbuf_release(&data->dir);
491
0
}
492
493
/**
494
 * Return the length of the longest common substring that ends in a
495
 * slash ('/') to indicate the longest common parent directory. Returns
496
 * zero if no common directory exists.
497
 */
498
static size_t max_common_dir_prefix(const char *path1, const char *path2)
499
0
{
500
0
  size_t common_prefix = 0;
501
0
  for (size_t i = 0; path1[i] && path2[i]; i++) {
502
0
    if (path1[i] != path2[i])
503
0
      break;
504
505
    /*
506
     * If they agree at a directory separator, then add one
507
     * to make sure it is included in the common prefix string.
508
     */
509
0
    if (path1[i] == '/')
510
0
      common_prefix = i + 1;
511
0
  }
512
513
0
  return common_prefix;
514
0
}
515
516
static int path_found(const char *path, struct path_found_data *data)
517
0
{
518
0
  struct stat st;
519
0
  size_t common_prefix;
520
521
  /*
522
   * If data->dir is non-empty, then it contains a path that doesn't
523
   * exist, including an ending slash ('/'). If it is a prefix of 'path',
524
   * then we can return 0.
525
   */
526
0
  if (data->dir.len && !memcmp(path, data->dir.buf, data->dir.len))
527
0
    return 0;
528
529
  /*
530
   * Otherwise, we must check if the current path exists. If it does, then
531
   * return 1. The cached directory will be skipped until we come across
532
   * a missing path again.
533
   */
534
0
  data->lstat_count++;
535
0
  if (!lstat(path, &st))
536
0
    return 1;
537
538
  /*
539
   * At this point, we know that 'path' doesn't exist, and we know that
540
   * the parent directory of 'data->dir' does exist. Let's set 'data->dir'
541
   * to be the top-most non-existing directory of 'path'. If the first
542
   * parent of 'path' exists, then we will act as though 'path'
543
   * corresponds to a directory (by adding a slash).
544
   */
545
0
  common_prefix = max_common_dir_prefix(path, data->dir.buf);
546
547
  /*
548
   * At this point, 'path' and 'data->dir' have a common existing parent
549
   * directory given by path[0..common_prefix] (which could have length 0).
550
   * We "grow" the data->dir buffer by checking for existing directories
551
   * along 'path'.
552
   */
553
554
0
  strbuf_setlen(&data->dir, common_prefix);
555
0
  while (1) {
556
    /* Find the next directory in 'path'. */
557
0
    const char *rest = path + data->dir.len;
558
0
    const char *next_slash = strchr(rest, '/');
559
560
    /*
561
     * If there are no more slashes, then 'path' doesn't contain a
562
     * non-existent _parent_ directory. Set 'data->dir' to be equal
563
     * to 'path' plus an additional slash, so it can be used for
564
     * caching in the future. The filename of 'path' is considered
565
     * a non-existent directory.
566
     *
567
     * Note: if "{path}/" exists as a directory, then it will never
568
     * appear as a prefix of other callers to this method, assuming
569
     * the context from the clear_skip_worktree... methods. If this
570
     * method is reused, then this must be reconsidered.
571
     */
572
0
    if (!next_slash) {
573
0
      strbuf_addstr(&data->dir, rest);
574
0
      strbuf_addch(&data->dir, '/');
575
0
      break;
576
0
    }
577
578
    /*
579
     * Now that we have a slash, let's grow 'data->dir' to include
580
     * this slash, then test if we should stop.
581
     */
582
0
    strbuf_add(&data->dir, rest, next_slash - rest + 1);
583
584
    /* If the parent dir doesn't exist, then stop here. */
585
0
    data->lstat_count++;
586
0
    if (lstat(data->dir.buf, &st))
587
0
      return 0;
588
0
  }
589
590
  /*
591
   * At this point, 'data->dir' is equal to 'path' plus a slash character,
592
   * and the parent directory of 'path' definitely exists. Moreover, we
593
   * know that 'path' doesn't exist, or we would have returned 1 earlier.
594
   */
595
0
  return 0;
596
0
}
597
598
static int clear_skip_worktree_from_present_files_sparse(struct index_state *istate)
599
0
{
600
0
  struct path_found_data data = PATH_FOUND_DATA_INIT;
601
602
0
  int path_count = 0;
603
0
  int to_restart = 0;
604
605
0
  trace2_region_enter("index", "clear_skip_worktree_from_present_files_sparse",
606
0
          istate->repo);
607
0
  for (int i = 0; i < istate->cache_nr; i++) {
608
0
    struct cache_entry *ce = istate->cache[i];
609
610
0
    if (ce_skip_worktree(ce)) {
611
0
      path_count++;
612
0
      if (path_found(ce->name, &data)) {
613
0
        if (S_ISSPARSEDIR(ce->ce_mode)) {
614
0
          to_restart = 1;
615
0
          break;
616
0
        }
617
0
        ce->ce_flags &= ~CE_SKIP_WORKTREE;
618
0
      }
619
0
    }
620
0
  }
621
622
0
  trace2_data_intmax("index", istate->repo,
623
0
         "sparse_path_count", path_count);
624
0
  trace2_data_intmax("index", istate->repo,
625
0
         "sparse_lstat_count", data.lstat_count);
626
0
  trace2_region_leave("index", "clear_skip_worktree_from_present_files_sparse",
627
0
          istate->repo);
628
0
  clear_path_found_data(&data);
629
0
  return to_restart;
630
0
}
631
632
static void clear_skip_worktree_from_present_files_full(struct index_state *istate)
633
0
{
634
0
  struct path_found_data data = PATH_FOUND_DATA_INIT;
635
636
0
  int path_count = 0;
637
638
0
  trace2_region_enter("index", "clear_skip_worktree_from_present_files_full",
639
0
          istate->repo);
640
0
  for (int i = 0; i < istate->cache_nr; i++) {
641
0
    struct cache_entry *ce = istate->cache[i];
642
643
0
    if (S_ISSPARSEDIR(ce->ce_mode))
644
0
      BUG("ensure-full-index did not fully flatten?");
645
646
0
    if (ce_skip_worktree(ce)) {
647
0
      path_count++;
648
0
      if (path_found(ce->name, &data))
649
0
        ce->ce_flags &= ~CE_SKIP_WORKTREE;
650
0
    }
651
0
  }
652
653
0
  trace2_data_intmax("index", istate->repo,
654
0
         "full_path_count", path_count);
655
0
  trace2_data_intmax("index", istate->repo,
656
0
         "full_lstat_count", data.lstat_count);
657
0
  trace2_region_leave("index", "clear_skip_worktree_from_present_files_full",
658
0
          istate->repo);
659
0
  clear_path_found_data(&data);
660
0
}
661
662
void clear_skip_worktree_from_present_files(struct index_state *istate)
663
0
{
664
0
  if (!core_apply_sparse_checkout ||
665
0
      sparse_expect_files_outside_of_patterns)
666
0
    return;
667
668
0
  if (clear_skip_worktree_from_present_files_sparse(istate)) {
669
0
    ensure_full_index(istate);
670
0
    clear_skip_worktree_from_present_files_full(istate);
671
0
  }
672
0
}
673
674
/*
675
 * This static global helps avoid infinite recursion between
676
 * expand_to_path() and index_file_exists().
677
 */
678
static int in_expand_to_path = 0;
679
680
void expand_to_path(struct index_state *istate,
681
        const char *path, size_t pathlen, int icase)
682
0
{
683
0
  struct strbuf path_mutable = STRBUF_INIT;
684
0
  size_t substr_len;
685
686
  /* prevent extra recursion */
687
0
  if (in_expand_to_path)
688
0
    return;
689
690
0
  if (!istate->sparse_index)
691
0
    return;
692
693
0
  in_expand_to_path = 1;
694
695
  /*
696
   * We only need to actually expand a region if the
697
   * following are both true:
698
   *
699
   * 1. 'path' is not already in the index.
700
   * 2. Some parent directory of 'path' is a sparse directory.
701
   */
702
703
0
  if (index_file_exists(istate, path, pathlen, icase))
704
0
    goto cleanup;
705
706
0
  strbuf_add(&path_mutable, path, pathlen);
707
0
  strbuf_addch(&path_mutable, '/');
708
709
  /* Check the name hash for all parent directories */
710
0
  substr_len = 0;
711
0
  while (substr_len < pathlen) {
712
0
    char temp;
713
0
    char *replace = strchr(path_mutable.buf + substr_len, '/');
714
715
0
    if (!replace)
716
0
      break;
717
718
    /* replace the character _after_ the slash */
719
0
    replace++;
720
0
    temp = *replace;
721
0
    *replace = '\0';
722
0
    substr_len = replace - path_mutable.buf;
723
0
    if (index_file_exists(istate, path_mutable.buf,
724
0
              substr_len, icase)) {
725
      /*
726
       * We found a parent directory in the name-hash
727
       * hashtable, because only sparse directory entries
728
       * have a trailing '/' character.  Since "path" wasn't
729
       * in the index, perhaps it exists within this
730
       * sparse-directory.  Expand accordingly.
731
       */
732
0
      ensure_full_index(istate);
733
0
      break;
734
0
    }
735
736
0
    *replace = temp;
737
0
  }
738
739
0
cleanup:
740
0
  strbuf_release(&path_mutable);
741
0
  in_expand_to_path = 0;
742
0
}