From 09984ea741b455a4f86fe9e2022ae6ae4af9b4c4 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 22 May 2022 15:59:34 +0100 Subject: win32: let stat(2) return correct st_size for symlink Previously stat(2) set st_size to the length of the canonicalised symlink target. Call readlink(2) to get the actual length of the target string. --- win32/mingw.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/win32/mingw.c b/win32/mingw.c index 95f5e5687..f49d8079d 100644 --- a/win32/mingw.c +++ b/win32/mingw.c @@ -630,6 +630,7 @@ static int do_lstat(int follow, const char *file_name, struct mingw_stat *buf) WIN32_FIND_DATAA findbuf; DWORD low, high; off64_t size; + ssize_t len; #if ENABLE_FEATURE_EXTRA_FILE_DATA DWORD flags; BY_HANDLE_FILE_INFORMATION hdata; @@ -645,20 +646,19 @@ static int do_lstat(int follow, const char *file_name, struct mingw_stat *buf) get_symlink_data(fdata.dwFileAttributes, file_name, &findbuf); if (buf->st_tag) { - char *name = auto_string(xmalloc_realpath(file_name)); - if (follow) { /* The file size and times are wrong when Windows follows - * a symlink. Use the canonicalized path to try again. */ + * a symlink. Use the canonicalized path instead. */ err = errno; - file_name = name; + file_name = auto_string(xmalloc_realpath(file_name)); continue; } /* Get the contents of a symlink, not its target. */ buf->st_mode = S_IFLNK|S_IRWXU|S_IRWXG|S_IRWXO; buf->st_attr = fdata.dwFileAttributes; - buf->st_size = name ? strlen(name) : 0; /* should use readlink */ + len = readlink(file_name, NULL, 0); + buf->st_size = len == -1 ? 0 : len; buf->st_atim = filetime_to_timespec(&(findbuf.ftLastAccessTime)); buf->st_mtim = filetime_to_timespec(&(findbuf.ftLastWriteTime)); buf->st_ctim = filetime_to_timespec(&(findbuf.ftCreationTime)); @@ -1527,6 +1527,7 @@ char *realpath(const char *path, char *resolved_path) } #define SRPB rptr->SymbolicLinkReparseBuffer +/* Non-standard feature: if buf is NULL just return the length. */ ssize_t readlink(const char *pathname, char *buf, size_t bufsiz) { HANDLE h; @@ -1554,6 +1555,8 @@ ssize_t readlink(const char *pathname, char *buf, size_t bufsiz) } if (name) { + if (buf == NULL) + return len; if (len > bufsiz) len = bufsiz; len = WideCharToMultiByte(CP_ACP, 0, name, len, buf, bufsiz, 0, 0); -- cgit v1.2.3-55-g6feb