Skip to content

Commit 95c11ec

Browse files
newrengitster
authored andcommitted
Fix error-prone fill_directory() API; make it only return matches
Traditionally, the expected calling convention for the dir.c API was: fill_directory(&dir, ..., pathspec) foreach entry in dir->entries: if (dir_path_match(entry, pathspec)) process_or_display(entry) This may have made sense once upon a time, because the fill_directory() call could use cheap checks to avoid doing full pathspec matching, and an external caller may have wanted to do other post-processing of the results anyway. However: * this structure makes it easy for users of the API to get it wrong * this structure actually makes it harder to understand fill_directory() and the functions it uses internally. It has tripped me up several times while trying to fix bugs and restructure things. * relying on post-filtering was already found to produce wrong results; pathspec matching had to be added internally for multiple cases in order to get the right results (see commits 404ebce (dir: also check directories for matching pathspecs, 2019-09-17) and 89a1f4a (dir: if our pathspec might match files under a dir, recurse into it, 2019-09-17)) * it's bad for performance: fill_directory() already has to do lots of checks and knows the subset of cases where it still needs to do more checks. Forcing external callers to do full pathspec matching means they must re-check _every_ path. So, add the pathspec matching within the fill_directory() internals, and remove it from external callers. Signed-off-by: Elijah Newren <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 7f45ab2 commit 95c11ec

File tree

6 files changed

+18
-27
lines changed

6 files changed

+18
-27
lines changed

builtin/clean.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -989,12 +989,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
989989
if (!cache_name_is_other(ent->name, ent->len))
990990
continue;
991991

992-
if (pathspec.nr)
993-
matches = dir_path_match(&the_index, ent, &pathspec, 0, NULL);
994-
995-
if (pathspec.nr && !matches)
996-
continue;
997-
998992
if (lstat(ent->name, &st))
999993
die_errno("Cannot lstat '%s'", ent->name);
1000994

builtin/grep.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -691,8 +691,6 @@ static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,
691691

692692
fill_directory(&dir, opt->repo->index, pathspec);
693693
for (i = 0; i < dir.nr; i++) {
694-
if (!dir_path_match(opt->repo->index, dir.entries[i], pathspec, 0, NULL))
695-
continue;
696694
hit |= grep_file(opt, dir.entries[i]->name);
697695
if (hit && opt->status_only)
698696
break;

builtin/ls-files.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,9 @@ static void show_dir_entry(const struct index_state *istate,
128128
if (len > ent->len)
129129
die("git ls-files: internal error - directory entry not superset of prefix");
130130

131-
if (!dir_path_match(istate, ent, &pathspec, len, ps_matched))
132-
return;
131+
/* If ps_matches is non-NULL, figure out which pathspec(s) match. */
132+
if (ps_matched)
133+
dir_path_match(istate, ent, &pathspec, len, ps_matched);
133134

134135
fputs(tag, stdout);
135136
write_eolinfo(istate, NULL, ent->name);

builtin/stash.c

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -856,30 +856,23 @@ static int get_untracked_files(const struct pathspec *ps, int include_untracked,
856856
struct strbuf *untracked_files)
857857
{
858858
int i;
859-
int max_len;
860859
int found = 0;
861-
char *seen;
862860
struct dir_struct dir;
863861

864862
memset(&dir, 0, sizeof(dir));
865863
if (include_untracked != INCLUDE_ALL_FILES)
866864
setup_standard_excludes(&dir);
867865

868-
seen = xcalloc(ps->nr, 1);
869-
870-
max_len = fill_directory(&dir, the_repository->index, ps);
866+
fill_directory(&dir, the_repository->index, ps);
871867
for (i = 0; i < dir.nr; i++) {
872868
struct dir_entry *ent = dir.entries[i];
873-
if (dir_path_match(&the_index, ent, ps, max_len, seen)) {
874-
found++;
875-
strbuf_addstr(untracked_files, ent->name);
876-
/* NUL-terminate: will be fed to update-index -z */
877-
strbuf_addch(untracked_files, '\0');
878-
}
869+
found++;
870+
strbuf_addstr(untracked_files, ent->name);
871+
/* NUL-terminate: will be fed to update-index -z */
872+
strbuf_addch(untracked_files, '\0');
879873
free(ent);
880874
}
881875

882-
free(seen);
883876
free(dir.entries);
884877
free(dir.ignored);
885878
clear_directory(&dir);

dir.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2117,7 +2117,14 @@ static enum path_treatment treat_path(struct dir_struct *dir,
21172117
baselen, excluded, pathspec);
21182118
case DT_REG:
21192119
case DT_LNK:
2120-
return excluded ? path_excluded : path_untracked;
2120+
if (excluded)
2121+
return path_excluded;
2122+
if (pathspec &&
2123+
!do_match_pathspec(istate, pathspec, path->buf, path->len,
2124+
0 /* prefix */, NULL /* seen */,
2125+
0 /* flags */))
2126+
return path_none;
2127+
return path_untracked;
21212128
}
21222129
}
21232130

wt-status.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -722,16 +722,14 @@ static void wt_status_collect_untracked(struct wt_status *s)
722722

723723
for (i = 0; i < dir.nr; i++) {
724724
struct dir_entry *ent = dir.entries[i];
725-
if (index_name_is_other(istate, ent->name, ent->len) &&
726-
dir_path_match(istate, ent, &s->pathspec, 0, NULL))
725+
if (index_name_is_other(istate, ent->name, ent->len))
727726
string_list_insert(&s->untracked, ent->name);
728727
free(ent);
729728
}
730729

731730
for (i = 0; i < dir.ignored_nr; i++) {
732731
struct dir_entry *ent = dir.ignored[i];
733-
if (index_name_is_other(istate, ent->name, ent->len) &&
734-
dir_path_match(istate, ent, &s->pathspec, 0, NULL))
732+
if (index_name_is_other(istate, ent->name, ent->len))
735733
string_list_insert(&s->ignored, ent->name);
736734
free(ent);
737735
}

0 commit comments

Comments
 (0)