summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dir.c107
-rw-r--r--dir.h6
2 files changed, 46 insertions, 67 deletions
diff --git a/dir.c b/dir.c
index 7d87c3c52b..8ac3d5a973 100644
--- a/dir.c
+++ b/dir.c
@@ -754,10 +754,6 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
struct exclude_stack *stk = NULL;
int current;
- if ((!dir->exclude_per_dir) ||
- (baselen + strlen(dir->exclude_per_dir) >= PATH_MAX))
- return; /* too long a path -- ignore */
-
group = &dir->exclude_list_group[EXC_DIRS];
/* Pop the exclude lists from the EXCL_DIRS exclude_list_group
@@ -769,12 +765,17 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
break;
el = &group->el[dir->exclude_stack->exclude_ix];
dir->exclude_stack = stk->prev;
+ dir->exclude = NULL;
free((char *)el->src); /* see strdup() below */
clear_exclude_list(el);
free(stk);
group->nr--;
}
+ /* Skip traversing into sub directories if the parent is excluded */
+ if (dir->exclude)
+ return;
+
/* Read from the parent directories and push them down. */
current = stk ? stk->baselen : -1;
while (current < baselen) {
@@ -793,22 +794,43 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
}
stk->prev = dir->exclude_stack;
stk->baselen = cp - base;
+ stk->exclude_ix = group->nr;
+ el = add_exclude_list(dir, EXC_DIRS, NULL);
memcpy(dir->basebuf + current, base + current,
stk->baselen - current);
- strcpy(dir->basebuf + stk->baselen, dir->exclude_per_dir);
- /*
- * dir->basebuf gets reused by the traversal, but we
- * need fname to remain unchanged to ensure the src
- * member of each struct exclude correctly
- * back-references its source file. Other invocations
- * of add_exclude_list provide stable strings, so we
- * strdup() and free() here in the caller.
- */
- el = add_exclude_list(dir, EXC_DIRS, strdup(dir->basebuf));
- stk->exclude_ix = group->nr - 1;
- add_excludes_from_file_to_list(dir->basebuf,
- dir->basebuf, stk->baselen,
- el, 1);
+
+ /* Abort if the directory is excluded */
+ if (stk->baselen) {
+ int dt = DT_DIR;
+ dir->basebuf[stk->baselen - 1] = 0;
+ dir->exclude = last_exclude_matching_from_lists(dir,
+ dir->basebuf, stk->baselen - 1,
+ dir->basebuf + current, &dt);
+ dir->basebuf[stk->baselen - 1] = '/';
+ if (dir->exclude) {
+ dir->basebuf[stk->baselen] = 0;
+ dir->exclude_stack = stk;
+ return;
+ }
+ }
+
+ /* Try to read per-directory file unless path is too long */
+ if (dir->exclude_per_dir &&
+ stk->baselen + strlen(dir->exclude_per_dir) < PATH_MAX) {
+ strcpy(dir->basebuf + stk->baselen,
+ dir->exclude_per_dir);
+ /*
+ * dir->basebuf gets reused by the traversal, but we
+ * need fname to remain unchanged to ensure the src
+ * member of each struct exclude correctly
+ * back-references its source file. Other invocations
+ * of add_exclude_list provide stable strings, so we
+ * strdup() and free() here in the caller.
+ */
+ el->src = strdup(dir->basebuf);
+ add_excludes_from_file_to_list(dir->basebuf,
+ dir->basebuf, stk->baselen, el, 1);
+ }
dir->exclude_stack = stk;
current = stk->baselen;
}
@@ -831,6 +853,9 @@ static struct exclude *last_exclude_matching(struct dir_struct *dir,
prep_exclude(dir, pathname, basename-pathname);
+ if (dir->exclude)
+ return dir->exclude;
+
return last_exclude_matching_from_lists(dir, pathname, pathlen,
basename, dtype_p);
}
@@ -853,13 +878,10 @@ void path_exclude_check_init(struct path_exclude_check *check,
struct dir_struct *dir)
{
check->dir = dir;
- check->exclude = NULL;
- strbuf_init(&check->path, 256);
}
void path_exclude_check_clear(struct path_exclude_check *check)
{
- strbuf_release(&check->path);
}
/*
@@ -875,49 +897,6 @@ struct exclude *last_exclude_matching_path(struct path_exclude_check *check,
const char *name, int namelen,
int *dtype)
{
- int i;
- struct strbuf *path = &check->path;
- struct exclude *exclude;
-
- /*
- * we allow the caller to pass namelen as an optimization; it
- * must match the length of the name, as we eventually call
- * is_excluded() on the whole name string.
- */
- if (namelen < 0)
- namelen = strlen(name);
-
- /*
- * If path is non-empty, and name is equal to path or a
- * subdirectory of path, name should be excluded, because
- * it's inside a directory which is already known to be
- * excluded and was previously left in check->path.
- */
- if (path->len &&
- path->len <= namelen &&
- !memcmp(name, path->buf, path->len) &&
- (!name[path->len] || name[path->len] == '/'))
- return check->exclude;
-
- strbuf_setlen(path, 0);
- for (i = 0; name[i]; i++) {
- int ch = name[i];
-
- if (ch == '/') {
- int dt = DT_DIR;
- exclude = last_exclude_matching(check->dir,
- path->buf, &dt);
- if (exclude) {
- check->exclude = exclude;
- return exclude;
- }
- }
- strbuf_addch(path, ch);
- }
-
- /* An entry in the index; cannot be a directory with subentries */
- strbuf_setlen(path, 0);
-
return last_exclude_matching(check->dir, name, dtype);
}
diff --git a/dir.h b/dir.h
index c3eb4b520e..cd166d0c63 100644
--- a/dir.h
+++ b/dir.h
@@ -110,9 +110,11 @@ struct dir_struct {
*
* exclude_stack points to the top of the exclude_stack, and
* basebuf contains the full path to the current
- * (sub)directory in the traversal.
+ * (sub)directory in the traversal. Exclude points to the
+ * matching exclude struct if the directory is excluded.
*/
struct exclude_stack *exclude_stack;
+ struct exclude *exclude;
char basebuf[PATH_MAX];
};
@@ -156,8 +158,6 @@ extern int match_pathname(const char *, int,
*/
struct path_exclude_check {
struct dir_struct *dir;
- struct exclude *exclude;
- 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 *);