dir: restructure in a way to avoid passing around a struct dirent

Restructure the code slightly to avoid passing around a struct dirent
anywhere, which also enables us to avoid trying to manufacture one.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Jeff King 2020-01-16 20:21:55 +00:00 committed by Junio C Hamano
parent 22705334b9
commit ad6f2157f9

69
dir.c
View File

@ -41,7 +41,8 @@ struct cached_dir {
int nr_files; int nr_files;
int nr_dirs; int nr_dirs;
struct dirent *de; const char *d_name;
int d_type;
const char *file; const char *file;
struct untracked_cache_dir *ucd; struct untracked_cache_dir *ucd;
}; };
@ -50,7 +51,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
struct index_state *istate, const char *path, int len, struct index_state *istate, const char *path, int len,
struct untracked_cache_dir *untracked, struct untracked_cache_dir *untracked,
int check_only, int stop_at_first_file, const struct pathspec *pathspec); int check_only, int stop_at_first_file, const struct pathspec *pathspec);
static int get_dtype(struct dirent *de, struct index_state *istate, static int resolve_dtype(int dtype, struct index_state *istate,
const char *path, int len); const char *path, int len);
int count_slashes(const char *s) 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; int prefix = pattern->nowildcardlen;
if (pattern->flags & PATTERN_FLAG_MUSTBEDIR) { if (pattern->flags & PATTERN_FLAG_MUSTBEDIR) {
if (*dtype == DT_UNKNOWN) *dtype = resolve_dtype(*dtype, istate, pathname, pathlen);
*dtype = get_dtype(NULL, istate, pathname, pathlen);
if (*dtype != DT_DIR) if (*dtype != DT_DIR)
continue; continue;
} }
@ -1842,10 +1842,9 @@ static int get_index_dtype(struct index_state *istate,
return DT_UNKNOWN; return DT_UNKNOWN;
} }
static int get_dtype(struct dirent *de, struct index_state *istate, static int resolve_dtype(int dtype, struct index_state *istate,
const char *path, int len) const char *path, int len)
{ {
int dtype = de ? DTYPE(de) : DT_UNKNOWN;
struct stat st; struct stat st;
if (dtype != DT_UNKNOWN) if (dtype != DT_UNKNOWN)
@ -1870,14 +1869,13 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
struct strbuf *path, struct strbuf *path,
int baselen, int baselen,
const struct pathspec *pathspec, const struct pathspec *pathspec,
int dtype, struct dirent *de) int dtype)
{ {
int exclude; int exclude;
int has_path_in_index = !!index_file_exists(istate, path->buf, path->len, ignore_case); int has_path_in_index = !!index_file_exists(istate, path->buf, path->len, ignore_case);
enum path_treatment path_treatment; enum path_treatment path_treatment;
if (dtype == DT_UNKNOWN) dtype = resolve_dtype(dtype, istate, path->buf, path->len);
dtype = get_dtype(de, istate, path->buf, path->len);
/* Always exclude indexed files */ /* Always exclude indexed files */
if (dtype != DT_DIR && has_path_in_index) if (dtype != DT_DIR && has_path_in_index)
@ -1985,21 +1983,18 @@ static enum path_treatment treat_path(struct dir_struct *dir,
int baselen, int baselen,
const struct pathspec *pathspec) const struct pathspec *pathspec)
{ {
int dtype; if (!cdir->d_name)
struct dirent *de = cdir->de;
if (!de)
return treat_path_fast(dir, untracked, cdir, istate, path, return treat_path_fast(dir, untracked, cdir, istate, path,
baselen, pathspec); 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; return path_none;
strbuf_setlen(path, baselen); strbuf_setlen(path, baselen);
strbuf_addstr(path, de->d_name); strbuf_addstr(path, cdir->d_name);
if (simplify_away(path->buf, path->len, pathspec)) if (simplify_away(path->buf, path->len, pathspec))
return path_none; return path_none;
dtype = DTYPE(de); return treat_one_path(dir, untracked, istate, path, baselen, pathspec,
return treat_one_path(dir, untracked, istate, path, baselen, pathspec, dtype, de); cdir->d_type);
} }
static void add_untracked(struct untracked_cache_dir *dir, const char *name) 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) static int read_cached_dir(struct cached_dir *cdir)
{ {
struct dirent *de;
if (cdir->fdir) { if (cdir->fdir) {
cdir->de = readdir(cdir->fdir); de = readdir(cdir->fdir);
if (!cdir->de) if (!de) {
cdir->d_name = NULL;
cdir->d_type = DT_UNKNOWN;
return -1; return -1;
}
cdir->d_name = de->d_name;
cdir->d_type = DTYPE(de);
return 0; return 0;
} }
while (cdir->nr_dirs < cdir->untracked->dirs_nr) { 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 */ /* recurse into subdir if instructed by treat_path */
if ((state == path_recurse) || if ((state == path_recurse) ||
((state == path_untracked) && ((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) || ((dir->flags & DIR_SHOW_IGNORED_TOO) ||
(pathspec && (pathspec &&
do_match_pathspec(istate, pathspec, path.buf, path.len, do_match_pathspec(istate, pathspec, path.buf, path.len,
@ -2314,10 +2316,10 @@ static int treat_leading_path(struct dir_struct *dir,
*/ */
struct strbuf sb = STRBUF_INIT; struct strbuf sb = STRBUF_INIT;
struct strbuf subdir = STRBUF_INIT;
int prevlen, baselen; int prevlen, baselen;
const char *cp; const char *cp;
struct cached_dir cdir; struct cached_dir cdir;
struct dirent *de;
enum path_treatment state = path_none; enum path_treatment state = path_none;
/* /*
@ -2342,22 +2344,8 @@ static int treat_leading_path(struct dir_struct *dir,
if (!len) if (!len)
return 1; 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)); memset(&cdir, 0, sizeof(cdir));
cdir.de = de; cdir.d_type = DT_DIR;
#if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT)
de->d_type = DT_DIR;
#endif
baselen = 0; baselen = 0;
prevlen = 0; prevlen = 0;
while (1) { while (1) {
@ -2374,12 +2362,13 @@ static int treat_leading_path(struct dir_struct *dir,
break; break;
strbuf_reset(&sb); strbuf_reset(&sb);
strbuf_add(&sb, path, prevlen); strbuf_add(&sb, path, prevlen);
memcpy(de->d_name, path+prevlen, baselen-prevlen); strbuf_reset(&subdir);
de->d_name[baselen-prevlen] = '\0'; strbuf_add(&subdir, path+prevlen, baselen-prevlen);
cdir.d_name = subdir.buf;
state = treat_path(dir, NULL, &cdir, istate, &sb, prevlen, state = treat_path(dir, NULL, &cdir, istate, &sb, prevlen,
pathspec); pathspec);
if (state == path_untracked && 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 || (dir->flags & DIR_SHOW_IGNORED_TOO ||
do_match_pathspec(istate, pathspec, sb.buf, sb.len, do_match_pathspec(istate, pathspec, sb.buf, sb.len,
baselen, NULL, DO_MATCH_LEADING_PATHSPEC) == MATCHED_RECURSIVELY_LEADING_PATHSPEC)) { baselen, NULL, DO_MATCH_LEADING_PATHSPEC) == MATCHED_RECURSIVELY_LEADING_PATHSPEC)) {
@ -2403,7 +2392,7 @@ static int treat_leading_path(struct dir_struct *dir,
&sb, baselen, pathspec, &sb, baselen, pathspec,
state); state);
free(de); strbuf_release(&subdir);
strbuf_release(&sb); strbuf_release(&sb);
return state == path_recurse; return state == path_recurse;
} }