From: Johannes Sixt Date: Thu, 18 Dec 2025 18:13:22 GMT Subject: Re: [PATCH 13/18] mingw: implement `readlink()` Message-ID: <8826825b-79ad-4700-aeb5-71e7847ca5dc@kdbg.org> In-Reply-To: <8fef8220f4d60b48358882fbc961c4604eab3abf.1765980535.git.gitgitgadget@gmail.com> Am 17.12.25 um 15:08 schrieb Karsten Blees via GitGitGadget: > From: Karsten Blees > > Implement `readlink()` by reading NTFS reparse points via the > `read_reparse_point()` function that was introduced earlier to determine > the length of symlink targets. Works for symlinks and directory > junctions. If symlinks are disabled, fail with `ENOSYS`. This last sentence is obsolete, I think, because I cannot see how the patch achieves a failure with ENOSYS. > > Signed-off-by: Karsten Blees > Signed-off-by: Johannes Schindelin > --- > compat/mingw-posix.h | 3 +-- > compat/mingw.c | 24 ++++++++++++++++++++++++ > 2 files changed, 25 insertions(+), 2 deletions(-) > > diff --git a/compat/mingw-posix.h b/compat/mingw-posix.h > index 0939feff27..896aa976b1 100644 > --- a/compat/mingw-posix.h > +++ b/compat/mingw-posix.h > @@ -121,8 +121,6 @@ struct utsname { > * trivial stubs > */ > > -static inline int readlink(const char *path UNUSED, char *buf UNUSED, size_t bufsiz UNUSED) > -{ errno = ENOSYS; return -1; } > static inline int symlink(const char *oldpath UNUSED, const char *newpath UNUSED) > { errno = ENOSYS; return -1; } > static inline int fchmod(int fildes UNUSED, mode_t mode UNUSED) > @@ -197,6 +195,7 @@ int setitimer(int type, struct itimerval *in, struct itimerval *out); > int sigaction(int sig, struct sigaction *in, struct sigaction *out); > int link(const char *oldpath, const char *newpath); > int uname(struct utsname *buf); > +int readlink(const char *path, char *buf, size_t bufsiz); > > /* > * replacements of existing functions > diff --git a/compat/mingw.c b/compat/mingw.c > index 5d2a8c247c..b407a2ac07 100644 > --- a/compat/mingw.c > +++ b/compat/mingw.c > @@ -2698,6 +2698,30 @@ int link(const char *oldpath, const char *newpath) > return 0; > } > > +int readlink(const char *path, char *buf, size_t bufsiz) > +{ > + WCHAR wpath[MAX_PATH]; > + char tmpbuf[MAX_PATH]; > + int len; > + DWORD tag; > + > + if (xutftowcs_path(wpath, path) < 0) > + return -1; > + > + if (read_reparse_point(wpath, TRUE, tmpbuf, &len, &tag) < 0) > + return -1; > + > + /* > + * Adapt to strange readlink() API: Copy up to bufsiz *bytes*, potentially > + * cutting off a UTF-8 sequence. Insufficient bufsize is *not* a failure > + * condition. There is no conversion function that produces invalid UTF-8, > + * so convert to a (hopefully large enough) temporary buffer, then memcpy > + * the requested number of bytes (including '\0' for robustness). > + */ > + memcpy(buf, tmpbuf, min(bufsiz, len + 1)); > + return min(bufsiz, len); > +} > + > pid_t waitpid(pid_t pid, int *status, int options) > { > HANDLE h = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, -- Hannes