gitignore: lazily find dtype
authorJunio C Hamano <gitster@pobox.com>
Fri, 1 Feb 2008 04:23:25 +0000 (20:23 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 5 Feb 2008 08:46:49 +0000 (00:46 -0800)
When we process "foo/" entries in gitignore files on a system
that does not have d_type member in "struct dirent", the earlier
implementation ran lstat(2) separately when matching with
entries that came from the command line, in-tree .gitignore
files, and $GIT_DIR/info/excludes file.

This optimizes it by delaying the lstat(2) call until it becomes
absolutely necessary.

The initial idea for this change was by Jeff King, but I
optimized it further to pass pointers to around.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin-ls-files.c
dir.c
dir.h
unpack-trees.c

index dbba371..54cb251 100644 (file)
@@ -238,8 +238,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)
        if (show_cached | show_stage) {
                for (i = 0; i < active_nr; i++) {
                        struct cache_entry *ce = active_cache[i];
-                       if (excluded(dir, ce->name, ce_to_dtype(ce)) !=
-                           dir->show_ignored)
+                       int dtype = ce_to_dtype(ce);
+                       if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
                                continue;
                        if (show_unmerged && !ce_stage(ce))
                                continue;
@@ -253,8 +253,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)
                        struct cache_entry *ce = active_cache[i];
                        struct stat st;
                        int err;
-                       if (excluded(dir, ce->name, ce_to_dtype(ce)) !=
-                           dir->show_ignored)
+                       int dtype = ce_to_dtype(ce);
+                       if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
                                continue;
                        err = lstat(ce->name, &st);
                        if (show_deleted && err)
diff --git a/dir.c b/dir.c
index a4f8c25..292639b 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -17,6 +17,7 @@ struct path_simplify {
 static int read_directory_recursive(struct dir_struct *dir,
        const char *path, const char *base, int baselen,
        int check_only, const struct path_simplify *simplify);
+static int get_dtype(struct dirent *de, const char *path);
 
 int common_prefix(const char **pathspec)
 {
@@ -277,7 +278,7 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
  * Return 1 for exclude, 0 for include and -1 for undecided.
  */
 static int excluded_1(const char *pathname,
-                     int pathlen, const char *basename, int dtype,
+                     int pathlen, const char *basename, int *dtype,
                      struct exclude_list *el)
 {
        int i;
@@ -288,9 +289,12 @@ static int excluded_1(const char *pathname,
                        const char *exclude = x->pattern;
                        int to_exclude = x->to_exclude;
 
-                       if ((x->flags & EXC_FLAG_MUSTBEDIR) &&
-                           (dtype != DT_DIR))
-                               continue;
+                       if (x->flags & EXC_FLAG_MUSTBEDIR) {
+                               if (*dtype == DT_UNKNOWN)
+                                       *dtype = get_dtype(NULL, pathname);
+                               if (*dtype != DT_DIR)
+                                       continue;
+                       }
 
                        if (x->flags & EXC_FLAG_NODIR) {
                                /* match basename */
@@ -334,7 +338,7 @@ static int excluded_1(const char *pathname,
        return -1; /* undecided */
 }
 
-int excluded(struct dir_struct *dir, const char *pathname, int dtype)
+int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
 {
        int pathlen = strlen(pathname);
        int st;
@@ -344,7 +348,7 @@ int excluded(struct dir_struct *dir, const char *pathname, int dtype)
        prep_exclude(dir, pathname, basename-pathname);
        for (st = EXC_CMDL; st <= EXC_FILE; st++) {
                switch (excluded_1(pathname, pathlen, basename,
-                                  dtype, &dir->exclude_list[st])) {
+                                  dtype_p, &dir->exclude_list[st])) {
                case 0:
                        return 0;
                case 1:
@@ -529,7 +533,7 @@ static int in_pathspec(const char *path, int len, const struct path_simplify *si
 
 static int get_dtype(struct dirent *de, const char *path)
 {
-       int dtype = DTYPE(de);
+       int dtype = de ? DTYPE(de) : DT_UNKNOWN;
        struct stat st;
 
        if (dtype != DT_UNKNOWN)
@@ -581,8 +585,8 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
                        if (simplify_away(fullname, baselen + len, simplify))
                                continue;
 
-                       dtype = get_dtype(de, fullname);
-                       exclude = excluded(dir, fullname, dtype);
+                       dtype = DTYPE(de);
+                       exclude = excluded(dir, fullname, &dtype);
                        if (exclude && dir->collect_ignored
                            && in_pathspec(fullname, baselen + len, simplify))
                                dir_add_ignored(dir, fullname, baselen + len);
@@ -594,6 +598,9 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
                        if (exclude && !dir->show_ignored)
                                continue;
 
+                       if (dtype == DT_UNKNOWN)
+                               dtype = get_dtype(de, fullname);
+
                        /*
                         * Do we want to see just the ignored files?
                         * We still need to recurse into directories,
diff --git a/dir.h b/dir.h
index 10d72b5..2df15de 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -68,7 +68,7 @@ extern int match_pathspec(const char **pathspec, const char *name, int namelen,
 
 extern int read_directory(struct dir_struct *, const char *path, const char *base, int baselen, const char **pathspec);
 
-extern int excluded(struct dir_struct *, const char *, int);
+extern int excluded(struct dir_struct *, const char *, int *);
 extern void add_excludes_from_file(struct dir_struct *, const char *fname);
 extern void add_exclude(const char *string, const char *base,
                        int baselen, struct exclude_list *which);
index 11af263..29848e9 100644 (file)
@@ -522,8 +522,9 @@ static void verify_absent(struct cache_entry *ce, const char *action,
 
        if (!lstat(ce->name, &st)) {
                int cnt;
+               int dtype = ce_to_dtype(ce);
 
-               if (o->dir && excluded(o->dir, ce->name, ce_to_dtype(ce)))
+               if (o->dir && excluded(o->dir, ce->name, &dtype))
                        /*
                         * ce->name is explicitly excluded, so it is Ok to
                         * overwrite it.