Issue #15478: Use source filename in OSError, not destination filename

And other fixes for Windows:

 * rename, replace and link require arguments of the same type on Windows
 * readlink only supports unicode filenames on Windows
 * os.open() specifies the filename on OSError
This commit is contained in:
Victor Stinner 2012-10-31 22:47:43 +01:00
parent a0c811e439
commit afe1706457
2 changed files with 53 additions and 47 deletions

View file

@ -2051,68 +2051,82 @@ class OSErrorTests(unittest.TestCase):
class Str(str): class Str(str):
pass pass
self.filenames = [] self.bytes_filenames = []
self.unicode_filenames = []
if support.TESTFN_UNENCODABLE is not None: if support.TESTFN_UNENCODABLE is not None:
decoded = support.TESTFN_UNENCODABLE decoded = support.TESTFN_UNENCODABLE
else: else:
decoded = support.TESTFN decoded = support.TESTFN
self.filenames.append(decoded) self.unicode_filenames.append(decoded)
self.filenames.append(Str(decoded)) self.unicode_filenames.append(Str(decoded))
if support.TESTFN_UNDECODABLE is not None: if support.TESTFN_UNDECODABLE is not None:
encoded = support.TESTFN_UNDECODABLE encoded = support.TESTFN_UNDECODABLE
else: else:
encoded = os.fsencode(support.TESTFN) encoded = os.fsencode(support.TESTFN)
self.filenames.append(encoded) self.bytes_filenames.append(encoded)
self.filenames.append(memoryview(encoded)) self.bytes_filenames.append(memoryview(encoded))
self.filenames = self.bytes_filenames + self.unicode_filenames
def test_oserror_filename(self): def test_oserror_filename(self):
funcs = [ funcs = [
(os.chdir,), (self.filenames, os.chdir,),
(os.chmod, 0o777), (self.filenames, os.chmod, 0o777),
(os.listdir,), (self.filenames, os.listdir,),
(os.lstat,), (self.filenames, os.lstat,),
(os.open, os.O_RDONLY), (self.filenames, os.open, os.O_RDONLY),
(os.rename, "dst"), (self.filenames, os.rmdir,),
(os.replace, "dst"), (self.filenames, os.stat,),
(os.rmdir,), (self.filenames, os.unlink,),
(os.stat,),
(os.unlink,),
] ]
if hasattr(os, "chown"):
funcs.append((os.chown, 0, 0))
if hasattr(os, "lchown"):
funcs.append((os.lchown, 0, 0))
if hasattr(os, "truncate"):
funcs.append((os.truncate, 0))
if sys.platform == "win32": if sys.platform == "win32":
import nt
funcs.extend(( funcs.extend((
(nt._getfullpathname,), (self.bytes_filenames, os.rename, b"dst"),
(nt._isdir,), (self.bytes_filenames, os.replace, b"dst"),
(self.unicode_filenames, os.rename, "dst"),
(self.unicode_filenames, os.replace, "dst"),
)) ))
else:
funcs.extend((
(self.filenames, os.rename, "dst"),
(self.filenames, os.replace, "dst"),
))
if hasattr(os, "chown"):
funcs.append((self.filenames, os.chown, 0, 0))
if hasattr(os, "lchown"):
funcs.append((self.filenames, os.lchown, 0, 0))
if hasattr(os, "truncate"):
funcs.append((self.filenames, os.truncate, 0))
if hasattr(os, "chflags"): if hasattr(os, "chflags"):
funcs.extend(( funcs.extend((
(os.chflags, 0), (self.filenames, os.chflags, 0),
(os.lchflags, 0), (self.filenames, os.lchflags, 0),
)) ))
if hasattr(os, "chroot"): if hasattr(os, "chroot"):
funcs.append((os.chroot,)) funcs.append((self.filenames, os.chroot,))
if hasattr(os, "link"): if hasattr(os, "link"):
funcs.append((os.link, "dst")) if sys.platform == "win32":
funcs.append((self.bytes_filenames, os.link, b"dst"))
funcs.append((self.unicode_filenames, os.link, "dst"))
else:
funcs.append((self.filenames, os.link, "dst"))
if hasattr(os, "listxattr"): if hasattr(os, "listxattr"):
funcs.extend(( funcs.extend((
(os.listxattr,), (self.filenames, os.listxattr,),
(os.getxattr, "user.test"), (self.filenames, os.getxattr, "user.test"),
(os.setxattr, "user.test", b'user'), (self.filenames, os.setxattr, "user.test", b'user'),
(os.removexattr, "user.test"), (self.filenames, os.removexattr, "user.test"),
)) ))
if hasattr(os, "lchmod"): if hasattr(os, "lchmod"):
funcs.append((os.lchmod, 0o777)) funcs.append((self.filenames, os.lchmod, 0o777))
if hasattr(os, "readlink"): if hasattr(os, "readlink"):
funcs.append((os.readlink,)) if sys.platform == "win32":
funcs.append((self.unicode_filenames, os.readlink,))
else:
funcs.append((self.filenames, os.readlink,))
for func, *func_args in funcs: for filenames, func, *func_args in funcs:
for name in self.filenames: for name in filenames:
try: try:
func(name, *func_args) func(name, *func_args)
except OSError as err: except OSError as err:

View file

@ -3054,7 +3054,7 @@ posix_link(PyObject *self, PyObject *args, PyObject *kwargs)
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (!result) { if (!result) {
return_value = path_error(&dst); return_value = path_error(&src);
goto exit; goto exit;
} }
#else #else
@ -3234,7 +3234,6 @@ posix_listdir(PyObject *self, PyObject *args, PyObject *kwargs)
if (error == ERROR_FILE_NOT_FOUND) if (error == ERROR_FILE_NOT_FOUND)
goto exit; goto exit;
Py_DECREF(list); Py_DECREF(list);
path.func = "FindFirstFile";
list = path_error(&path); list = path_error(&path);
goto exit; goto exit;
} }
@ -3263,7 +3262,6 @@ posix_listdir(PyObject *self, PyObject *args, PyObject *kwargs)
it got to the end of the directory. */ it got to the end of the directory. */
if (!result && GetLastError() != ERROR_NO_MORE_FILES) { if (!result && GetLastError() != ERROR_NO_MORE_FILES) {
Py_DECREF(list); Py_DECREF(list);
path.func = "FindNextFile";
list = path_error(&path); list = path_error(&path);
goto exit; goto exit;
} }
@ -3782,7 +3780,7 @@ internal_rename(PyObject *args, PyObject *kwargs, int is_replace)
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (!result) { if (!result) {
return_value = path_error(&dst); return_value = path_error(&src);
goto exit; goto exit;
} }
@ -6707,7 +6705,7 @@ posix_symlink(PyObject *self, PyObject *args, PyObject *kwargs)
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (result) { if (result) {
return_value = path_error(&dst); return_value = path_error(&src);
goto exit; goto exit;
} }
#endif #endif
@ -7059,12 +7057,6 @@ posix_open(PyObject *self, PyObject *args, PyObject *kwargs)
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (fd == -1) { if (fd == -1) {
#ifdef MS_WINDOWS
/* force use of posix_error here for exact backwards compatibility */
if (path.wide)
return_value = posix_error();
else
#endif
return_value = path_error(&path); return_value = path_error(&path);
goto exit; goto exit;
} }