diff -r 2358a46b621e Lib/test/test_os.py --- a/Lib/test/test_os.py Mon Oct 24 21:22:39 2011 +0300 +++ b/Lib/test/test_os.py Mon Oct 24 16:11:26 2011 -0700 @@ -1074,6 +1074,86 @@ @unittest.skipUnless(sys.platform == "win32", "Win32 specific tests") +class Win32ListdirTests(unittest.TestCase): + """Test listdir on Windows.""" + + def setUp(self): + """Set the different tests.""" + super(Win32ListdirTests, self).setUp() + self.created_paths = [] + while len(self.created_paths) < 3: + dir_name = 'SUB' + str(len(self.created_paths)) + dir_path = os.path.join(support.TESTFN, dir_name) + file_name = 'FILE' + str(len(self.created_paths)) + file_path = os.path.join(support.TESTFN, file_name) + os.makedirs(dir_path) + with open(file_path, 'w') as f: + f.write("I'm %s and proud of it. Blame test_os.\n" % file_path) + self.created_paths.extend([dir_name, file_name]) + self.created_paths.sort() + + def tearDown(self): + """Clean after tests.""" + # same tear down as the one found in the walk tests + for root, dirs, files in os.walk(support.TESTFN, topdown=False): + for name in files: + os.remove(os.path.join(root, name)) + for name in dirs: + dirname = os.path.join(root, name) + if not os.path.islink(dirname): + os.rmdir(dirname) + else: + os.remove(dirname) + os.rmdir(support.TESTFN) + + def test_listdir_no_extended_path(self): + """Test when the path is not an "extended" path.""" + # unicode + self.assertEqual(self.created_paths, + sorted(os.listdir(support.TESTFN))) + # and narrow string + self.assertEqual([os.fsencode(path) for path in self.created_paths], + sorted(os.listdir(os.fsencode(support.TESTFN)))) + + def test_listdir_extended_path(self): + """Test when the path starts with '\\\\?\\'.""" + # See: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath + # unicode + path = '\\\\?\\' + os.path.abspath(support.TESTFN) + self.assertEqual(self.created_paths, sorted(os.listdir(path))) + # and narrow string + path = b'\\\\?\\' + os.fsencode(os.path.abspath(support.TESTFN)) + self.assertEqual([os.fsencode(path) for path in self.created_paths], + sorted(os.listdir(path))) + + def test_listdir_extended_path_trailing_altsep(self): + """Test when the extended path ('\\\\?\\[...]') trails with an + alternative separator character ('/').""" + # unicode + path = '\\\\?\\' + os.path.abspath(support.TESTFN) + os.altsep + self.assertEqual(self.created_paths, sorted(os.listdir(path))) + # and narow string + path = b'\\\\?\\' + os.fsencode(os.path.abspath(support.TESTFN)) + \ + os.fsencode(os.altsep) + self.assertEqual([os.fsencode(path) for path in self.created_paths], + sorted(os.listdir(path))) + + def test_listdir_extended_path_altsep(self): + """Test when the extended path ('\\\\?\\[...]') is followed by + a path with an alternative separator ('/') inside it.""" + # unicode + path = '\\\\?\\' + os.path.abspath(support.TESTFN).replace('\\', '/') \ + + os.altsep + self.assertEqual(self.created_paths, sorted(os.listdir(path))) + # and narrow string + path = b'\\\\?\\' + \ + os.fsencode(os.path.abspath(support.TESTFN)).replace(b'\\', b'/') \ + + os.fsencode(os.altsep) + self.assertEqual([os.fsencode(path) for path in self.created_paths], + sorted(os.listdir(path))) + + +@unittest.skipUnless(sys.platform == "win32", "Win32 specific tests") @support.skip_unless_symlink class Win32SymlinkTests(unittest.TestCase): filelink = 'filelinktest' @@ -1621,6 +1701,7 @@ Pep383Tests, Win32KillTests, Win32SymlinkTests, + Win32ListdirTests, FSEncodingTests, PidTests, LoginTests, diff -r 2358a46b621e Modules/posixmodule.c --- a/Modules/posixmodule.c Mon Oct 24 21:22:39 2011 +0300 +++ b/Modules/posixmodule.c Mon Oct 24 16:11:26 2011 -0700 @@ -2542,8 +2542,21 @@ wcscpy(wnamebuf, po_wchars); if (len > 0) { wchar_t wch = wnamebuf[len-1]; - if (wch != L'/' && wch != L'\\' && wch != L':') - wnamebuf[len++] = L'\\'; + + /* Issue 13234: When a literal path is prefixed with r'\\?\', + Windows API cannot handle '/' in the subsequent path. + See: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath. + */ + if (wcsncmp(L"\\\\?\\", wnamebuf, 4) == 0) { + wchar_t *wc; + for (wc = &wnamebuf[4]; *wc != L'\0'; wc++) { + if (*wc == ALTSEP) + *wc = SEP; + } + } + + if (wch != SEP && wch != ALTSEP && wch != L':') + wnamebuf[len++] = SEP; wcscpy(wnamebuf + len, L"*.*"); } if ((d = PyList_New(0)) == NULL) { @@ -2622,8 +2635,21 @@ Py_DECREF(opath); if (len > 0) { char ch = namebuf[len-1]; - if (ch != SEP && ch != ALTSEP && ch != ':') - namebuf[len++] = '/'; + + /* Issue 13234: When a literal path is prefixed with r'\\?\', + Windows API cannot handle '/' in its subsequent path. + See: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath. + */ + if (strncmp("\\\\?\\", namebuf, 4) == 0) { + char *c; + for (c = &namebuf[4]; *c != '\0'; c++) { + if (*c == '/') + *c = '\\'; + } + } + + if (ch != '\\' && ch != '/' && ch != ':') + namebuf[len++] = '\\'; strcpy(namebuf + len, "*.*"); }