From a1d33f742515dc70ae99bc3ea1c851729522afc3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 12 Feb 2018 10:14:08 -0800 Subject: [PATCH] bpo-29248: Fix os.readlink() on Windows (GH-5577) The PrintNameOffset field of the reparse data buffer was treated as a number of characters instead of bytes. (cherry picked from commit 3c34aad4e7a95913ec7db8e5e948a8fc69047bf7) Co-authored-by: SSE4 --- Lib/test/test_os.py | 15 +++++++++++++++ .../2018-02-07-17-50-48.bpo-29248.Xzwj-6.rst | 3 +++ Modules/posixmodule.c | 6 +++--- 3 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2018-02-07-17-50-48.bpo-29248.Xzwj-6.rst diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index b65ccb7159..033e544ffe 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -2171,6 +2171,21 @@ class Win32SymlinkTests(unittest.TestCase): finally: os.chdir(orig_dir) + @unittest.skipUnless(os.path.lexists(r'C:\Users\All Users') + and os.path.exists(r'C:\ProgramData'), + 'Test directories not found') + def test_29248(self): + # os.symlink() calls CreateSymbolicLink, which creates + # the reparse data buffer with the print name stored + # first, so the offset is always 0. CreateSymbolicLink + # stores the "PrintName" DOS path (e.g. "C:\") first, + # with an offset of 0, followed by the "SubstituteName" + # NT path (e.g. "\??\C:\"). The "All Users" link, on + # the other hand, seems to have been created manually + # with an inverted order. + target = os.readlink(r'C:\Users\All Users') + self.assertTrue(os.path.samefile(target, r'C:\ProgramData')) + @unittest.skipUnless(sys.platform == "win32", "Win32 specific tests") class Win32JunctionTests(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Windows/2018-02-07-17-50-48.bpo-29248.Xzwj-6.rst b/Misc/NEWS.d/next/Windows/2018-02-07-17-50-48.bpo-29248.Xzwj-6.rst new file mode 100644 index 0000000000..3030ef6958 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2018-02-07-17-50-48.bpo-29248.Xzwj-6.rst @@ -0,0 +1,3 @@ +Fix :func:`os.readlink` on Windows, which was mistakenly treating the +``PrintNameOffset`` field of the reparse data buffer as a number of +characters instead of bytes. Patch by Craig Holmquist and SSE4. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index e30d3c13bb..80b1fbdfd2 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -7127,11 +7127,11 @@ win_readlink(PyObject *self, PyObject *args, PyObject *kwargs) "not a symbolic link"); return NULL; } - print_name = rdb->SymbolicLinkReparseBuffer.PathBuffer + - rdb->SymbolicLinkReparseBuffer.PrintNameOffset; + print_name = (wchar_t *)((char*)rdb->SymbolicLinkReparseBuffer.PathBuffer + + rdb->SymbolicLinkReparseBuffer.PrintNameOffset); result = PyUnicode_FromWideChar(print_name, - rdb->SymbolicLinkReparseBuffer.PrintNameLength/2); + rdb->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(wchar_t)); return result; } -- 2.40.0