diff options
-rw-r--r-- | builtin/ls-files.c | 17 | ||||
-rw-r--r-- | dir.c | 32 | ||||
-rw-r--r-- | dir.h | 16 |
3 files changed, 59 insertions, 6 deletions
diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 7cff175745..90dc3601a8 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -203,6 +203,10 @@ static void show_ru_info(void) static void show_files(struct dir_struct *dir) { int i; + struct path_exclude_check check; + + if ((dir->flags & DIR_SHOW_IGNORED)) + path_exclude_check_init(&check, dir); /* For cached/deleted files we don't need to even do the readdir */ if (show_others || show_killed) { @@ -215,9 +219,8 @@ static void show_files(struct dir_struct *dir) if (show_cached | show_stage) { for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; - int dtype = ce_to_dtype(ce); - if (dir->flags & DIR_SHOW_IGNORED && - !excluded(dir, ce->name, &dtype)) + if ((dir->flags & DIR_SHOW_IGNORED) && + !path_excluded(&check, ce)) continue; if (show_unmerged && !ce_stage(ce)) continue; @@ -232,9 +235,8 @@ static void show_files(struct dir_struct *dir) struct cache_entry *ce = active_cache[i]; struct stat st; int err; - int dtype = ce_to_dtype(ce); - if (dir->flags & DIR_SHOW_IGNORED && - !excluded(dir, ce->name, &dtype)) + if ((dir->flags & DIR_SHOW_IGNORED) && + !path_excluded(&check, ce)) continue; if (ce->ce_flags & CE_UPDATE) continue; @@ -247,6 +249,9 @@ static void show_files(struct dir_struct *dir) show_ce_entry(tag_modified, ce); } } + + if ((dir->flags & DIR_SHOW_IGNORED)) + path_exclude_check_clear(&check); } /* @@ -580,6 +580,38 @@ int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p) return 0; } +void path_exclude_check_init(struct path_exclude_check *check, + struct dir_struct *dir) +{ + check->dir = dir; + strbuf_init(&check->path, 256); +} + +void path_exclude_check_clear(struct path_exclude_check *check) +{ + strbuf_release(&check->path); +} + +int path_excluded(struct path_exclude_check *check, struct cache_entry *ce) +{ + int i, dtype; + struct strbuf *path = &check->path; + + strbuf_setlen(path, 0); + for (i = 0; ce->name[i]; i++) { + int ch = ce->name[i]; + + if (ch == '/') { + dtype = DT_DIR; + if (excluded(check->dir, path->buf, &dtype)) + return 1; + } + strbuf_addch(path, ch); + } + dtype = ce_to_dtype(ce); + return excluded(check->dir, ce->name, &dtype); +} + static struct dir_entry *dir_entry_new(const char *pathname, int len) { struct dir_entry *ent; @@ -1,6 +1,8 @@ #ifndef DIR_H #define DIR_H +#include "strbuf.h" + struct dir_entry { unsigned int len; char name[FLEX_ARRAY]; /* more */ @@ -78,6 +80,20 @@ extern int excluded_from_list(const char *pathname, int pathlen, const char *bas int *dtype, struct exclude_list *el); extern int excluded(struct dir_struct *, const char *, int *); struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len); + +/* + * The excluded() API is meant for callers that check each level of leading + * directory hierarchies with excluded() to avoid recursing into excluded + * directories. Callers that do not do so should use this API instead. + */ +struct path_exclude_check { + struct dir_struct *dir; + struct strbuf path; +}; +extern void path_exclude_check_init(struct path_exclude_check *, struct dir_struct *); +extern void path_exclude_check_clear(struct path_exclude_check *); +extern int path_excluded(struct path_exclude_check *, struct cache_entry *); + extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen, char **buf_p, struct exclude_list *which, int check_index); extern void add_excludes_from_file(struct dir_struct *, const char *fname); |