dir.c: replace is_path_excluded with now equivalent is_excluded API
[gitweb.git] / dir.c
diff --git a/dir.c b/dir.c
index 46d127ca20f48ce792848e022ddf4dae284fcfae..47397600af6dcb1cd26557d5f58a81696a746fc4 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -578,78 +578,6 @@ void add_excludes_from_file(struct dir_struct *dir, const char *fname)
                die("cannot use %s as an exclude file", fname);
 }
 
-/*
- * Loads the per-directory exclude list for the substring of base
- * which has a char length of baselen.
- */
-static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
-{
-       struct exclude_list_group *group;
-       struct exclude_list *el;
-       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
-        * which originate from directories not in the prefix of the
-        * path being checked. */
-       while ((stk = dir->exclude_stack) != NULL) {
-               if (stk->baselen <= baselen &&
-                   !strncmp(dir->basebuf, base, stk->baselen))
-                       break;
-               el = &group->el[dir->exclude_stack->exclude_ix];
-               dir->exclude_stack = stk->prev;
-               free((char *)el->src); /* see strdup() below */
-               clear_exclude_list(el);
-               free(stk);
-               group->nr--;
-       }
-
-       /* Read from the parent directories and push them down. */
-       current = stk ? stk->baselen : -1;
-       while (current < baselen) {
-               struct exclude_stack *stk = xcalloc(1, sizeof(*stk));
-               const char *cp;
-
-               if (current < 0) {
-                       cp = base;
-                       current = 0;
-               }
-               else {
-                       cp = strchr(base + current + 1, '/');
-                       if (!cp)
-                               die("oops in prep_exclude");
-                       cp++;
-               }
-               stk->prev = dir->exclude_stack;
-               stk->baselen = cp - base;
-               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);
-               dir->exclude_stack = stk;
-               current = stk->baselen;
-       }
-       dir->basebuf[baselen] = '\0';
-}
-
 int match_basename(const char *basename, int basenamelen,
                   const char *pattern, int prefix, int patternlen,
                   int flags)
@@ -815,13 +743,107 @@ static struct exclude *last_exclude_matching_from_lists(struct dir_struct *dir,
        return NULL;
 }
 
+/*
+ * Loads the per-directory exclude list for the substring of base
+ * which has a char length of baselen.
+ */
+static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
+{
+       struct exclude_list_group *group;
+       struct exclude_list *el;
+       struct exclude_stack *stk = NULL;
+       int current;
+
+       group = &dir->exclude_list_group[EXC_DIRS];
+
+       /* Pop the exclude lists from the EXCL_DIRS exclude_list_group
+        * which originate from directories not in the prefix of the
+        * path being checked. */
+       while ((stk = dir->exclude_stack) != NULL) {
+               if (stk->baselen <= baselen &&
+                   !strncmp(dir->basebuf, base, stk->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) {
+               struct exclude_stack *stk = xcalloc(1, sizeof(*stk));
+               const char *cp;
+
+               if (current < 0) {
+                       cp = base;
+                       current = 0;
+               }
+               else {
+                       cp = strchr(base + current + 1, '/');
+                       if (!cp)
+                               die("oops in prep_exclude");
+                       cp++;
+               }
+               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);
+
+               /* 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;
+       }
+       dir->basebuf[baselen] = '\0';
+}
+
 /*
  * Loads the exclude lists for the directory containing pathname, then
  * scans all exclude lists to determine whether pathname is excluded.
  * Returns the exclude_list element which matched, or NULL for
  * undecided.
  */
-static struct exclude *last_exclude_matching(struct dir_struct *dir,
+struct exclude *last_exclude_matching(struct dir_struct *dir,
                                             const char *pathname,
                                             int *dtype_p)
 {
@@ -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);
 }
@@ -840,7 +865,7 @@ static struct exclude *last_exclude_matching(struct dir_struct *dir,
  * scans all exclude lists to determine whether pathname is excluded.
  * Returns 1 if true, otherwise 0.
  */
-static int is_excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
+int is_excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
 {
        struct exclude *exclude =
                last_exclude_matching(dir, pathname, dtype_p);
@@ -849,93 +874,6 @@ static int is_excluded(struct dir_struct *dir, const char *pathname, int *dtype_
        return 0;
 }
 
-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);
-}
-
-/*
- * For each subdirectory in name, starting with the top-most, checks
- * to see if that subdirectory is excluded, and if so, returns the
- * corresponding exclude structure.  Otherwise, checks whether name
- * itself (which is presumably a file) is excluded.
- *
- * A path to a directory known to be excluded is left in check->path to
- * optimize for repeated checks for files in the same excluded directory.
- */
-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);
-}
-
-/*
- * Is this name excluded?  This is for a caller like show_files() that
- * do not honor directory hierarchy and iterate through paths that are
- * possibly in an ignored directory.
- */
-int is_path_excluded(struct path_exclude_check *check,
-                 const char *name, int namelen, int *dtype)
-{
-       struct exclude *exclude =
-               last_exclude_matching_path(check, name, namelen, dtype);
-       if (exclude)
-               return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
-       return 0;
-}
-
 static struct dir_entry *dir_entry_new(const char *pathname, int len)
 {
        struct dir_entry *ent;
@@ -1107,15 +1045,6 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
 
        /* This is the "show_other_directories" case */
 
-       /* might be a sub directory in an excluded directory */
-       if (!exclude) {
-               struct path_exclude_check check;
-               int dt = DT_DIR;
-               path_exclude_check_init(&check, dir);
-               exclude = is_path_excluded(&check, dirname, len, &dt);
-               path_exclude_check_clear(&check);
-       }
-
        /*
         * We are looking for ignored files and our directory is not ignored,
         * check if it contains untracked files (i.e. is listed as untracked)
@@ -1150,27 +1079,13 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
  *
  * Return 1 for exclude, 0 for include.
  */
-static int treat_file(struct dir_struct *dir, struct strbuf *path, int exclude, int *dtype)
+static int treat_file(struct dir_struct *dir, struct strbuf *path, int exclude)
 {
-       struct path_exclude_check check;
-       int exclude_file = 0;
-
        /* Always exclude indexed files */
        if (index_name_exists(&the_index, path->buf, path->len, ignore_case))
                return 1;
 
-       if (exclude)
-               exclude_file = !(dir->flags & DIR_SHOW_IGNORED);
-       else if (dir->flags & DIR_SHOW_IGNORED) {
-               path_exclude_check_init(&check, dir);
-
-               if (!is_path_excluded(&check, path->buf, path->len, dtype))
-                       exclude_file = 1;
-
-               path_exclude_check_clear(&check);
-       }
-
-       return exclude_file;
+       return exclude == !(dir->flags & DIR_SHOW_IGNORED);
 }
 
 /*
@@ -1327,12 +1242,9 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
                break;
        case DT_REG:
        case DT_LNK:
-               switch (treat_file(dir, path, exclude, &dtype)) {
-               case 1:
+               if (treat_file(dir, path, exclude))
                        return path_ignored;
-               default:
-                       break;
-               }
+               break;
        }
        return path_handled;
 }