]> granicus.if.org Git - python/commitdiff
bpo-29248: Fix os.readlink() on Windows (GH-5577)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Mon, 12 Feb 2018 21:39:42 +0000 (13:39 -0800)
committerGitHub <noreply@github.com>
Mon, 12 Feb 2018 21:39:42 +0000 (13:39 -0800)
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 <tomskside@gmail.com>
Lib/test/test_os.py
Misc/NEWS.d/next/Windows/2018-02-07-17-50-48.bpo-29248.Xzwj-6.rst [new file with mode: 0644]
Modules/posixmodule.c

index 02611d223b7665ebca9a9bf3b8b9882d12be9f50..77e4a008ae61e8a4a244a93be952628ee775c754 100644 (file)
@@ -2165,6 +2165,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 (file)
index 0000000..3030ef6
--- /dev/null
@@ -0,0 +1,3 @@
+Fix :func:`os.readlink` on Windows, which was mistakenly treating the\r
+``PrintNameOffset`` field of the reparse data buffer as a number of\r
+characters instead of bytes. Patch by Craig Holmquist and SSE4.\r
index 4a1c9f398a07b76d1661c8add8f1ad0178f4f12b..63f5b2a3889608cd65e290411d6df9bb572661ef 100644 (file)
@@ -7439,11 +7439,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;
 }