summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin/ls-files.c17
-rw-r--r--dir.c32
-rw-r--r--dir.h16
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);
}
/*
diff --git a/dir.c b/dir.c
index 0a78d00b54..c3f08849bc 100644
--- a/dir.c
+++ b/dir.c
@@ -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;
diff --git a/dir.h b/dir.h
index dd6947e1d4..7378e69c17 100644
--- a/dir.h
+++ b/dir.h
@@ -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);