diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 5f302f6d0e..d8c875fff0 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -2146,9 +2146,13 @@ class Win32JunctionTests(unittest.TestCase): self.assertTrue(os.path.exists(self.junction)) self.assertTrue(os.path.isdir(self.junction)) - # Junctions are not recognized as links. - self.assertFalse(os.path.islink(self.junction)) - + # Junctions are recognized as links. + self.assertTrue(os.path.islink(self.junction)) + + # os.readlink supports junctions. + real_junction_target = os.readlink(self.junction) + self.assertTrue(os.path.samefile(real_junction_target, self.junction_target)) + def test_unlink_removes_junction(self): _winapi.CreateJunction(self.junction_target, self.junction) self.assertTrue(os.path.exists(self.junction)) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 0ae06eb53e..6aa8d49b56 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -4185,8 +4185,7 @@ BOOL WINAPI Py_DeleteFileW(LPCWSTR lpFileName) if(find_data_handle != INVALID_HANDLE_VALUE) { /* IO_REPARSE_TAG_SYMLINK if it is a symlink and IO_REPARSE_TAG_MOUNT_POINT if it is a junction point. */ - is_link = find_data.dwReserved0 == IO_REPARSE_TAG_SYMLINK || - find_data.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT; + is_link = IsReparseTagNameSurrogate(find_data.dwReserved0); FindClose(find_data_handle); } } @@ -7049,6 +7048,7 @@ win_readlink(PyObject *self, PyObject *args, PyObject *kwargs) char target_buffer[_Py_MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; _Py_REPARSE_DATA_BUFFER *rdb = (_Py_REPARSE_DATA_BUFFER *)target_buffer; const wchar_t *print_name; + USHORT print_name_length; static char *keywords[] = {"path", "dir_fd", NULL}; @@ -7093,17 +7093,26 @@ win_readlink(PyObject *self, PyObject *args, PyObject *kwargs) if (io_result==0) return win32_error_object("readlink", po); - if (rdb->ReparseTag != IO_REPARSE_TAG_SYMLINK) - { + if (rdb->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + print_name = rdb->SymbolicLinkReparseBuffer.PathBuffer + + (rdb->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)); + print_name_length = rdb->SymbolicLinkReparseBuffer.PrintNameLength / + sizeof(WCHAR); + } + else if (rdb->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { + print_name = rdb->MountPointReparseBuffer.PathBuffer + + (rdb->MountPointReparseBuffer.PrintNameOffset / sizeof(WCHAR)); + print_name_length = rdb->MountPointReparseBuffer.PrintNameLength / + sizeof(WCHAR); + } + else { PyErr_SetString(PyExc_ValueError, - "not a symbolic link"); + "unsupported reparse tag"); return NULL; } - print_name = rdb->SymbolicLinkReparseBuffer.PathBuffer + - rdb->SymbolicLinkReparseBuffer.PrintNameOffset; result = PyUnicode_FromWideChar(print_name, - rdb->SymbolicLinkReparseBuffer.PrintNameLength/2); + print_name_length); return result; } diff --git a/Python/fileutils.c b/Python/fileutils.c index f3764e4b3c..9d2bedc6a1 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -584,7 +584,7 @@ _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result->st_atime_nsec); result->st_nlink = info->nNumberOfLinks; result->st_ino = (((uint64_t)info->nFileIndexHigh) << 32) + info->nFileIndexLow; - if (reparse_tag == IO_REPARSE_TAG_SYMLINK) { + if (IsReparseTagNameSurrogate(reparse_tag)) { /* first clear the S_IFMT bits */ result->st_mode ^= (result->st_mode & S_IFMT); /* now set the bits that make this a symlink */