From aa79636fe70247a19648d73e52a7774536100567 Mon Sep 17 00:00:00 2001 From: Victoria Dye Date: Mon, 9 Oct 2023 21:58:55 +0000 Subject: 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 Signed-off-by: Junio C Hamano --- dir.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'dir.c') diff --git a/dir.c b/dir.c index 5e01af3a25..16fdb03f2a 100644 --- a/dir.c +++ b/dir.c @@ -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 */ -- cgit v1.2.3