diff options
Diffstat (limited to 'dir.c')
-rw-r--r-- | dir.c | 83 |
1 files changed, 38 insertions, 45 deletions
@@ -41,7 +41,8 @@ struct cached_dir { int nr_files; int nr_dirs; - struct dirent *de; + const char *d_name; + int d_type; const char *file; struct untracked_cache_dir *ucd; }; @@ -50,8 +51,8 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir, struct index_state *istate, const char *path, int len, struct untracked_cache_dir *untracked, int check_only, int stop_at_first_file, const struct pathspec *pathspec); -static int get_dtype(struct dirent *de, struct index_state *istate, - const char *path, int len); +static int resolve_dtype(int dtype, struct index_state *istate, + const char *path, int len); int count_slashes(const char *s) { @@ -1215,8 +1216,7 @@ static struct path_pattern *last_matching_pattern_from_list(const char *pathname int prefix = pattern->nowildcardlen; if (pattern->flags & PATTERN_FLAG_MUSTBEDIR) { - if (*dtype == DT_UNKNOWN) - *dtype = get_dtype(NULL, istate, pathname, pathlen); + *dtype = resolve_dtype(*dtype, istate, pathname, pathlen); if (*dtype != DT_DIR) continue; } @@ -1842,10 +1842,9 @@ static int get_index_dtype(struct index_state *istate, return DT_UNKNOWN; } -static int get_dtype(struct dirent *de, struct index_state *istate, - const char *path, int len) +static int resolve_dtype(int dtype, struct index_state *istate, + const char *path, int len) { - int dtype = de ? DTYPE(de) : DT_UNKNOWN; struct stat st; if (dtype != DT_UNKNOWN) @@ -1870,14 +1869,13 @@ static enum path_treatment treat_one_path(struct dir_struct *dir, struct strbuf *path, int baselen, const struct pathspec *pathspec, - int dtype, struct dirent *de) + int dtype) { int exclude; int has_path_in_index = !!index_file_exists(istate, path->buf, path->len, ignore_case); enum path_treatment path_treatment; - if (dtype == DT_UNKNOWN) - dtype = get_dtype(de, istate, path->buf, path->len); + dtype = resolve_dtype(dtype, istate, path->buf, path->len); /* Always exclude indexed files */ if (dtype != DT_DIR && has_path_in_index) @@ -1985,21 +1983,18 @@ static enum path_treatment treat_path(struct dir_struct *dir, int baselen, const struct pathspec *pathspec) { - int dtype; - struct dirent *de = cdir->de; - - if (!de) + if (!cdir->d_name) return treat_path_fast(dir, untracked, cdir, istate, path, baselen, pathspec); - if (is_dot_or_dotdot(de->d_name) || !fspathcmp(de->d_name, ".git")) + if (is_dot_or_dotdot(cdir->d_name) || !fspathcmp(cdir->d_name, ".git")) return path_none; strbuf_setlen(path, baselen); - strbuf_addstr(path, de->d_name); + strbuf_addstr(path, cdir->d_name); if (simplify_away(path->buf, path->len, pathspec)) return path_none; - dtype = DTYPE(de); - return treat_one_path(dir, untracked, istate, path, baselen, pathspec, dtype, de); + return treat_one_path(dir, untracked, istate, path, baselen, pathspec, + cdir->d_type); } static void add_untracked(struct untracked_cache_dir *dir, const char *name) @@ -2087,10 +2082,17 @@ static int open_cached_dir(struct cached_dir *cdir, static int read_cached_dir(struct cached_dir *cdir) { + struct dirent *de; + if (cdir->fdir) { - cdir->de = readdir(cdir->fdir); - if (!cdir->de) + de = readdir(cdir->fdir); + if (!de) { + cdir->d_name = NULL; + cdir->d_type = DT_UNKNOWN; return -1; + } + cdir->d_name = de->d_name; + cdir->d_type = DTYPE(de); return 0; } while (cdir->nr_dirs < cdir->untracked->dirs_nr) { @@ -2216,7 +2218,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir, /* recurse into subdir if instructed by treat_path */ if ((state == path_recurse) || ((state == path_untracked) && - (get_dtype(cdir.de, istate, path.buf, path.len) == DT_DIR) && + (resolve_dtype(cdir.d_type, istate, path.buf, path.len) == DT_DIR) && ((dir->flags & DIR_SHOW_IGNORED_TOO) || (pathspec && do_match_pathspec(istate, pathspec, path.buf, path.len, @@ -2308,16 +2310,16 @@ static int treat_leading_path(struct dir_struct *dir, * WARNING WARNING WARNING: * * Any updates to the traversal logic here may need corresponding - * updates in treat_leading_path(). See the commit message for the - * commit adding this warning as well as the commit preceding it - * for details. + * updates in read_directory_recursive(). See 777b420347 (dir: + * synchronize treat_leading_path() and read_directory_recursive(), + * 2019-12-19) and its parent commit for details. */ struct strbuf sb = STRBUF_INIT; + struct strbuf subdir = STRBUF_INIT; int prevlen, baselen; const char *cp; struct cached_dir cdir; - struct dirent *de; enum path_treatment state = path_none; /* @@ -2342,22 +2344,8 @@ static int treat_leading_path(struct dir_struct *dir, if (!len) return 1; - /* - * We need a manufactured dirent with sufficient space to store a - * leading directory component of path in its d_name. Here, we - * assume that the dirent's d_name is either declared as - * char d_name[BIG_ENOUGH] - * or that it is declared at the end of the struct as - * char d_name[] - * For either case, padding with len+1 bytes at the end will ensure - * sufficient storage space. - */ - de = xcalloc(1, st_add3(sizeof(struct dirent), len, 1)); memset(&cdir, 0, sizeof(cdir)); - cdir.de = de; -#if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT) - de->d_type = DT_DIR; -#endif + cdir.d_type = DT_DIR; baselen = 0; prevlen = 0; while (1) { @@ -2374,15 +2362,20 @@ static int treat_leading_path(struct dir_struct *dir, break; strbuf_reset(&sb); strbuf_add(&sb, path, prevlen); - memcpy(de->d_name, path+prevlen, baselen-prevlen); - de->d_name[baselen-prevlen] = '\0'; + strbuf_reset(&subdir); + strbuf_add(&subdir, path+prevlen, baselen-prevlen); + cdir.d_name = subdir.buf; state = treat_path(dir, NULL, &cdir, istate, &sb, prevlen, pathspec); if (state == path_untracked && - get_dtype(cdir.de, istate, sb.buf, sb.len) == DT_DIR && + resolve_dtype(cdir.d_type, istate, sb.buf, sb.len) == DT_DIR && (dir->flags & DIR_SHOW_IGNORED_TOO || do_match_pathspec(istate, pathspec, sb.buf, sb.len, baselen, NULL, DO_MATCH_LEADING_PATHSPEC) == MATCHED_RECURSIVELY_LEADING_PATHSPEC)) { + if (!match_pathspec(istate, pathspec, sb.buf, sb.len, + 0 /* prefix */, NULL, + 0 /* do NOT special case dirs */)) + state = path_none; add_path_to_appropriate_result_list(dir, NULL, &cdir, istate, &sb, baselen, @@ -2399,7 +2392,7 @@ static int treat_leading_path(struct dir_struct *dir, &sb, baselen, pathspec, state); - free(de); + strbuf_release(&subdir); strbuf_release(&sb); return state == path_recurse; } |