From b0696b94ab963fe0dd47f5c1ed6327a4337afa09 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Fri, 13 May 2022 08:14:42 +0100 Subject: win32: treat junctions as symlinks Directory junctions were always followed to their target so they appeared to *be* directories. This resulted in counter-intuitive behaviour: - a directory junction could be removed with rmdir even though the directory wasn't empty; - 'rm -rf' on a directory junction deleted it but also deleted the contents of the linked directory. A better approximation is to treat directory junctions as symbolic links. (GitHub issue #254) --- win32/mingw.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/win32/mingw.c b/win32/mingw.c index 6954ee9b5..539aa48d2 100644 --- a/win32/mingw.c +++ b/win32/mingw.c @@ -571,7 +571,8 @@ static int get_symlink_data(DWORD attr, const char *pathname, if (handle != INVALID_HANDLE_VALUE) { FindClose(handle); return ((fbuf->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && - fbuf->dwReserved0 == IO_REPARSE_TAG_SYMLINK); + (fbuf->dwReserved0 == IO_REPARSE_TAG_SYMLINK || + fbuf->dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT)); } } return 0; @@ -1377,6 +1378,7 @@ static wchar_t *normalize_ntpath(wchar_t *wbuf) } #define SRPB rptr->SymbolicLinkReparseBuffer +#define MRPB rptr->MountPointReparseBuffer ssize_t readlink(const char *pathname, char *buf, size_t bufsiz) { HANDLE h; @@ -1388,24 +1390,29 @@ ssize_t readlink(const char *pathname, char *buf, size_t bufsiz) BYTE rbuf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; PREPARSE_DATA_BUFFER rptr = (PREPARSE_DATA_BUFFER)rbuf; BOOL status; + size_t len; + WCHAR *name = NULL; status = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, rptr, sizeof(rbuf), &nbytes, NULL); CloseHandle(h); if (status && rptr->ReparseTag == IO_REPARSE_TAG_SYMLINK) { - size_t len = SRPB.SubstituteNameLength/sizeof(WCHAR); - WCHAR *name = SRPB.PathBuffer + - SRPB.SubstituteNameOffset/sizeof(WCHAR); + len = SRPB.SubstituteNameLength/sizeof(WCHAR); + name = SRPB.PathBuffer + SRPB.SubstituteNameOffset/sizeof(WCHAR); + } else if (status && rptr->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { + len = MRPB.SubstituteNameLength/sizeof(WCHAR); + name = MRPB.PathBuffer + MRPB.SubstituteNameOffset/sizeof(WCHAR); + } + if (name) { name[len] = 0; name = normalize_ntpath(name); len = wcslen(name); if (len > bufsiz) len = bufsiz; - if (WideCharToMultiByte(CP_ACP, 0, name, len, buf, bufsiz, 0, 0)) { + if (WideCharToMultiByte(CP_ACP, 0, name, len, buf, bufsiz, 0, 0)) return len; - } } } errno = err_win_to_posix(); -- cgit v1.2.3-55-g6feb