From 6831a88ac03759a8133f10ffd52ad235a081a8a3 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 31 Jan 2008 20:23:25 -0800 Subject: gitignore: lazily find dtype 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 diff --git a/builtin-ls-files.c b/builtin-ls-files.c index dbba371..54cb251 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -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 --- 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 --- 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); diff --git a/unpack-trees.c b/unpack-trees.c index 11af263..29848e9 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -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. -- cgit v0.10.2-6-g49f6