dir.[ch]: add 'follow_symlink' arg to 'get_dtype'

Add a 'follow_symlink' boolean option to 'get_type()'. If 'follow_symlink'
is enabled, DT_LNK (in addition to DT_UNKNOWN) d_types triggers the
stat-based d_type resolution, using 'stat' instead of 'lstat' to get the
type of the followed symlink. Note that symlinks are not followed
recursively, so a symlink pointing to another symlink will still resolve to
DT_LNK.

Update callers in 'diagnose.c' to specify 'follow_symlink = 0' to preserve
current behavior.

Signed-off-by: Victoria Dye <vdye@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Victoria Dye
2023-10-09 21:58:55 +00:00
committed by Junio C Hamano
parent 6dc1004333
commit aa79636fe7
3 changed files with 18 additions and 8 deletions

13
dir.c
View File

@@ -2235,19 +2235,24 @@ static int get_index_dtype(struct index_state *istate,
return DT_UNKNOWN;
}
unsigned char get_dtype(struct dirent *e, struct strbuf *path)
unsigned char get_dtype(struct dirent *e, struct strbuf *path,
int follow_symlink)
{
struct stat st;
unsigned char dtype = DTYPE(e);
size_t base_path_len;
if (dtype != DT_UNKNOWN)
if (dtype != DT_UNKNOWN && !(follow_symlink && dtype == DT_LNK))
return dtype;
/* d_type unknown in dirent, try to fall back on lstat results */
/*
* d_type unknown or unfollowed symlink, try to fall back on [l]stat
* results. If [l]stat fails, explicitly set DT_UNKNOWN.
*/
base_path_len = path->len;
strbuf_addstr(path, e->d_name);
if (lstat(path->buf, &st))
if ((follow_symlink && stat(path->buf, &st)) ||
(!follow_symlink && lstat(path->buf, &st)))
goto cleanup;
/* determine d_type from st_mode */