]> git.ipfire.org Git - thirdparty/git.git/commitdiff
mingw: implement `readlink()`
authorKarsten Blees <blees@dcon.de>
Wed, 17 Dec 2025 14:08:50 +0000 (14:08 +0000)
committerJunio C Hamano <gitster@pobox.com>
Wed, 17 Dec 2025 23:22:19 +0000 (08:22 +0900)
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`.

Signed-off-by: Karsten Blees <blees@dcon.de>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
compat/mingw-posix.h
compat/mingw.c

index 0939feff27ffec7ea4f65774c4820494696f0b78..896aa976b1949b854837651f6c762eab5083e807 100644 (file)
@@ -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
index 5d2a8c247ce622b923a6d60479a144dcbf2aa4ed..b407a2ac07f9d48e20a30a6b8b01cdd8956f332d 100644 (file)
@@ -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,