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 3c34aad4e7)

Co-authored-by: SSE4 <tomskside@gmail.com>
This commit is contained in:
Miss Islington (bot) 2018-02-12 13:39:42 -08:00 committed by GitHub
parent 38b4dd7f83
commit 74ebbaeb56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 21 additions and 3 deletions

View 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):

View File

@ -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.

View 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;
}