# HG changeset patch
# Parent 76d921391e9d6f337813af45f539712b0bf3655f
Changes default bytes FS encoding on Windows to UTF-8, switches implementation to always call Unicode functions, and un-deprecates byte paths.
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -90,16 +90,6 @@
yield
[email protected]
-def bytes_filename_warn(expected):
- msg = 'The Windows bytes API has been deprecated'
- if os.name == 'nt':
- with ignore_deprecation_warnings(msg, quiet=not expected):
- yield
- else:
- yield
-
-
def create_file(filename, content=b'content'):
with open(filename, "xb", 0) as fp:
fp.write(content)
@@ -327,8 +317,7 @@
fname = self.fname.encode(sys.getfilesystemencoding())
except UnicodeEncodeError:
self.skipTest("cannot encode %a for the filesystem" % self.fname)
- with bytes_filename_warn(True):
- self.check_stat_attributes(fname)
+ self.check_stat_attributes(fname)
def test_stat_result_pickle(self):
result = os.stat(self.fname)
@@ -1012,8 +1001,6 @@
def setUp(self):
super().setUp()
self.stack = contextlib.ExitStack()
- if os.name == 'nt':
- self.stack.enter_context(bytes_filename_warn(False))
def tearDown(self):
self.stack.close()
@@ -1576,8 +1563,7 @@
def _test_link(self, file1, file2):
create_file(file1)
- with bytes_filename_warn(False):
- os.link(file1, file2)
+ os.link(file1, file2)
with open(file1, "r") as f1, open(file2, "r") as f2:
self.assertTrue(os.path.sameopenfile(f1.fileno(), f2.fileno()))
@@ -1870,10 +1856,9 @@
self.created_paths)
# bytes
- with bytes_filename_warn(False):
- self.assertEqual(
- sorted(os.listdir(os.fsencode(support.TESTFN))),
- [os.fsencode(path) for path in self.created_paths])
+ self.assertEqual(
+ sorted(os.listdir(os.fsencode(support.TESTFN))),
+ [os.fsencode(path) for path in self.created_paths])
def test_listdir_extended_path(self):
"""Test when the path starts with '\\\\?\\'."""
@@ -1885,11 +1870,10 @@
self.created_paths)
# bytes
- with bytes_filename_warn(False):
- path = b'\\\\?\\' + os.fsencode(os.path.abspath(support.TESTFN))
- self.assertEqual(
- sorted(os.listdir(path)),
- [os.fsencode(path) for path in self.created_paths])
+ path = b'\\\\?\\' + os.fsencode(os.path.abspath(support.TESTFN))
+ self.assertEqual(
+ sorted(os.listdir(path)),
+ [os.fsencode(path) for path in self.created_paths])
@unittest.skipUnless(sys.platform == "win32", "Win32 specific tests")
@@ -1964,10 +1948,8 @@
self.assertNotEqual(os.lstat(link), os.stat(link))
bytes_link = os.fsencode(link)
- with bytes_filename_warn(True):
- self.assertEqual(os.stat(bytes_link), os.stat(target))
- with bytes_filename_warn(True):
- self.assertNotEqual(os.lstat(bytes_link), os.stat(bytes_link))
+ self.assertEqual(os.stat(bytes_link), os.stat(target))
+ self.assertNotEqual(os.lstat(bytes_link), os.stat(bytes_link))
def test_12084(self):
level1 = os.path.abspath(support.TESTFN)
@@ -2524,46 +2506,6 @@
self._check_xattrs(getxattr, setxattr, removexattr, listxattr)
[email protected](sys.platform == "win32", "Win32 specific tests")
-class Win32DeprecatedBytesAPI(unittest.TestCase):
- def test_deprecated(self):
- import nt
- filename = os.fsencode(support.TESTFN)
- for func, *args in (
- (nt._getfullpathname, filename),
- (nt._isdir, filename),
- (os.access, filename, os.R_OK),
- (os.chdir, filename),
- (os.chmod, filename, 0o777),
- (os.getcwdb,),
- (os.link, filename, filename),
- (os.listdir, filename),
- (os.lstat, filename),
- (os.mkdir, filename),
- (os.open, filename, os.O_RDONLY),
- (os.rename, filename, filename),
- (os.rmdir, filename),
- (os.startfile, filename),
- (os.stat, filename),
- (os.unlink, filename),
- (os.utime, filename),
- ):
- with bytes_filename_warn(True):
- try:
- func(*args)
- except OSError:
- # ignore OSError, we only care about DeprecationWarning
- pass
-
- @support.skip_unless_symlink
- def test_symlink(self):
- self.addCleanup(support.unlink, support.TESTFN)
-
- filename = os.fsencode(support.TESTFN)
- with bytes_filename_warn(True):
- os.symlink(filename, filename)
-
-
@unittest.skipUnless(hasattr(os, 'get_terminal_size'), "requires os.get_terminal_size")
class TermsizeTests(unittest.TestCase):
def test_does_not_crash(self):
@@ -2703,13 +2645,12 @@
if isinstance(name, str):
func(name, *func_args)
elif isinstance(name, bytes):
- with bytes_filename_warn(False):
- func(name, *func_args)
+ func(name, *func_args)
else:
with self.assertWarnsRegex(DeprecationWarning, 'should be'):
func(name, *func_args)
except OSError as err:
- self.assertIs(err.filename, name)
+ self.assertIs(err.filename, name, str(func))
else:
self.fail("No exception thrown by {}".format(func))
@@ -2964,7 +2905,6 @@
entry = self.create_file_entry()
self.assertEqual(os.fspath(entry), os.path.join(self.path, 'file.txt'))
- @unittest.skipIf(os.name == "nt", "test requires bytes path support")
def test_fspath_protocol_bytes(self):
bytes_filename = os.fsencode('bytesfile.txt')
bytes_entry = self.create_file_entry(name=bytes_filename)
@@ -3036,12 +2976,6 @@
entry.stat(follow_symlinks=False)
def test_bytes(self):
- if os.name == "nt":
- # On Windows, os.scandir(bytes) must raise an exception
- with bytes_filename_warn(True):
- self.assertRaises(TypeError, os.scandir, b'.')
- return
-
self.create_file("file.txt")
path_bytes = os.fsencode(self.path)
diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h
--- a/Modules/clinic/posixmodule.c.h
+++ b/Modules/clinic/posixmodule.c.h
@@ -1618,24 +1618,24 @@
{"execv", (PyCFunction)os_execv, METH_VARARGS, os_execv__doc__},
static PyObject *
-os_execv_impl(PyObject *module, PyObject *path, PyObject *argv);
+os_execv_impl(PyObject *module, path_t *path, PyObject *argv);
static PyObject *
os_execv(PyObject *module, PyObject *args)
{
PyObject *return_value = NULL;
- PyObject *path = NULL;
+ path_t path = PATH_T_INITIALIZE("execv", "path", 0, 0);
PyObject *argv;
if (!PyArg_ParseTuple(args, "O&O:execv",
- PyUnicode_FSConverter, &path, &argv)) {
+ path_converter, &path, &argv)) {
goto exit;
}
- return_value = os_execv_impl(module, path, argv);
+ return_value = os_execv_impl(module, &path, argv);
exit:
/* Cleanup for path */
- Py_XDECREF(path);
+ path_cleanup(&path);
return return_value;
}
@@ -1687,7 +1687,7 @@
#endif /* defined(HAVE_EXECV) */
-#if defined(HAVE_SPAWNV)
+#if (defined(HAVE_SPAWNV) || defined(HAVE_WSPAWNV))
PyDoc_STRVAR(os_spawnv__doc__,
"spawnv($module, mode, path, argv, /)\n"
@@ -1706,32 +1706,32 @@
{"spawnv", (PyCFunction)os_spawnv, METH_VARARGS, os_spawnv__doc__},
static PyObject *
-os_spawnv_impl(PyObject *module, int mode, PyObject *path, PyObject *argv);
+os_spawnv_impl(PyObject *module, int mode, path_t *path, PyObject *argv);
static PyObject *
os_spawnv(PyObject *module, PyObject *args)
{
PyObject *return_value = NULL;
int mode;
- PyObject *path = NULL;
+ path_t path = PATH_T_INITIALIZE("spawnv", "path", 0, 0);
PyObject *argv;
if (!PyArg_ParseTuple(args, "iO&O:spawnv",
- &mode, PyUnicode_FSConverter, &path, &argv)) {
+ &mode, path_converter, &path, &argv)) {
goto exit;
}
- return_value = os_spawnv_impl(module, mode, path, argv);
+ return_value = os_spawnv_impl(module, mode, &path, argv);
exit:
/* Cleanup for path */
- Py_XDECREF(path);
+ path_cleanup(&path);
return return_value;
}
-#endif /* defined(HAVE_SPAWNV) */
-
-#if defined(HAVE_SPAWNV)
+#endif /* (defined(HAVE_SPAWNV) || defined(HAVE_WSPAWNV)) */
+
+#if (defined(HAVE_SPAWNV) || defined(HAVE_WSPAWNV))
PyDoc_STRVAR(os_spawnve__doc__,
"spawnve($module, mode, path, argv, env, /)\n"
@@ -1752,7 +1752,7 @@
{"spawnve", (PyCFunction)os_spawnve, METH_VARARGS, os_spawnve__doc__},
static PyObject *
-os_spawnve_impl(PyObject *module, int mode, PyObject *path, PyObject *argv,
+os_spawnve_impl(PyObject *module, int mode, path_t *path, PyObject *argv,
PyObject *env);
static PyObject *
@@ -1760,24 +1760,24 @@
{
PyObject *return_value = NULL;
int mode;
- PyObject *path = NULL;
+ path_t path = PATH_T_INITIALIZE("spawnve", "path", 0, 0);
PyObject *argv;
PyObject *env;
if (!PyArg_ParseTuple(args, "iO&OO:spawnve",
- &mode, PyUnicode_FSConverter, &path, &argv, &env)) {
+ &mode, path_converter, &path, &argv, &env)) {
goto exit;
}
- return_value = os_spawnve_impl(module, mode, path, argv, env);
+ return_value = os_spawnve_impl(module, mode, &path, argv, env);
exit:
/* Cleanup for path */
- Py_XDECREF(path);
+ path_cleanup(&path);
return return_value;
}
-#endif /* defined(HAVE_SPAWNV) */
+#endif /* (defined(HAVE_SPAWNV) || defined(HAVE_WSPAWNV)) */
#if defined(HAVE_FORK1)
@@ -4938,6 +4938,60 @@
return os_abort_impl(module);
}
+#if defined(MS_WINDOWS)
+
+PyDoc_STRVAR(os_startfile__doc__,
+"startfile($module, /, filepath, operation=None)\n"
+"--\n"
+"\n"
+"startfile(filepath [, operation])\n"
+"\n"
+"Start a file with its associated application.\n"
+"\n"
+"When \"operation\" is not specified or \"open\", this acts like\n"
+"double-clicking the file in Explorer, or giving the file name as an\n"
+"argument to the DOS \"start\" command: the file is opened with whatever\n"
+"application (if any) its extension is associated.\n"
+"When another \"operation\" is given, it specifies what should be done with\n"
+"the file. A typical operation is \"print\".\n"
+"\n"
+"startfile returns as soon as the associated application is launched.\n"
+"There is no option to wait for the application to close, and no way\n"
+"to retrieve the application\'s exit status.\n"
+"\n"
+"The filepath is relative to the current directory. If you want to use\n"
+"an absolute path, make sure the first character is not a slash (\"/\");\n"
+"the underlying Win32 ShellExecute function doesn\'t work if it is.");
+
+#define OS_STARTFILE_METHODDEF \
+ {"startfile", (PyCFunction)os_startfile, METH_VARARGS|METH_KEYWORDS, os_startfile__doc__},
+
+static PyObject *
+os_startfile_impl(PyObject *module, path_t *filepath, Py_UNICODE *operation);
+
+static PyObject *
+os_startfile(PyObject *module, PyObject *args, PyObject *kwargs)
+{
+ PyObject *return_value = NULL;
+ static char *_keywords[] = {"filepath", "operation", NULL};
+ path_t filepath = PATH_T_INITIALIZE("startfile", "filepath", 0, 0);
+ Py_UNICODE *operation = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|u:startfile", _keywords,
+ path_converter, &filepath, &operation)) {
+ goto exit;
+ }
+ return_value = os_startfile_impl(module, &filepath, operation);
+
+exit:
+ /* Cleanup for filepath */
+ path_cleanup(&filepath);
+
+ return return_value;
+}
+
+#endif /* defined(MS_WINDOWS) */
+
#if defined(HAVE_GETLOADAVG)
PyDoc_STRVAR(os_getloadavg__doc__,
@@ -5937,6 +5991,10 @@
#define OS_SYSCONF_METHODDEF
#endif /* !defined(OS_SYSCONF_METHODDEF) */
+#ifndef OS_STARTFILE_METHODDEF
+ #define OS_STARTFILE_METHODDEF
+#endif /* !defined(OS_STARTFILE_METHODDEF) */
+
#ifndef OS_GETLOADAVG_METHODDEF
#define OS_GETLOADAVG_METHODDEF
#endif /* !defined(OS_GETLOADAVG_METHODDEF) */
@@ -5980,4 +6038,4 @@
#ifndef OS_SET_HANDLE_INHERITABLE_METHODDEF
#define OS_SET_HANDLE_INHERITABLE_METHODDEF
#endif /* !defined(OS_SET_HANDLE_INHERITABLE_METHODDEF) */
-/*[clinic end generated code: output=e91e62d8e8f1b6ac input=a9049054013a1b77]*/
+/*[clinic end generated code: output=608e00dbe6af2967 input=a9049054013a1b77]*/
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -157,6 +157,8 @@
#define HAVE_GETLOGIN 1
#define HAVE_SPAWNV 1
#define HAVE_EXECV 1
+#define HAVE_WSPAWNV 1
+#define HAVE_WEXECV 1
#define HAVE_PIPE 1
#define HAVE_SYSTEM 1
#define HAVE_CWAIT 1
@@ -736,7 +738,7 @@
*
* * On Windows, if we get a (Unicode) string we
* extract the wchar_t * and return it; if we get
- * bytes we extract the char * and return that.
+ * bytes we decode to wchar_t * and return that.
*
* * On all other platforms, strings are encoded
* to bytes using PyUnicode_FSConverter, then we
@@ -768,7 +770,9 @@
* and was not encoded. (Only used on Windows.)
* path.narrow
* Points to the path if it was expressed as bytes,
- * or it was Unicode and was encoded to bytes.
+ * or it was Unicode and was encoded to bytes. (On Windows,
+ * is an non-zero integer if the path was expressed as bytes.
+ * The type is deliberately incompatible to prevent misuse.)
* path.fd
* Contains a file descriptor if path.accept_fd was true
* and the caller provided a signed integer instead of any
@@ -813,15 +817,24 @@
int nullable;
int allow_fd;
const wchar_t *wide;
+#ifdef MS_WINDOWS
+ BOOL narrow;
+#else
const char *narrow;
+#endif
int fd;
Py_ssize_t length;
PyObject *object;
PyObject *cleanup;
} path_t;
+#ifdef MS_WINDOWS
+#define PATH_T_INITIALIZE(function_name, argument_name, nullable, allow_fd) \
+ {function_name, argument_name, nullable, allow_fd, NULL, FALSE, -1, 0, NULL, NULL}
+#else
#define PATH_T_INITIALIZE(function_name, argument_name, nullable, allow_fd) \
{function_name, argument_name, nullable, allow_fd, NULL, NULL, -1, 0, NULL, NULL}
+#endif
static void
path_cleanup(path_t *path) {
@@ -834,9 +847,11 @@
path_converter(PyObject *o, void *p)
{
path_t *path = (path_t *)p;
+ Py_ssize_t length;
+#ifndef MS_WINDOWS
PyObject *bytes;
- Py_ssize_t length;
const char *narrow;
+#endif
#define FORMAT_EXCEPTION(exc, fmt) \
PyErr_Format(exc, "%s%s" fmt, \
@@ -855,15 +870,45 @@
if ((o == Py_None) && path->nullable) {
path->wide = NULL;
+#ifdef MS_WINDOWS
+ path->narrow = FALSE;
+#else
path->narrow = NULL;
+#endif
path->length = 0;
path->object = o;
path->fd = -1;
return 1;
}
+#ifdef MS_WINDOWS
+ path->narrow = FALSE;
+
+ /* Convert bytes to Unicode using defalut FS encoding */
+ if (PyBytes_Check(o)) {
+ PyObject *wo = PyUnicode_DecodeFSDefaultAndSize(
+ PyBytes_AS_STRING(o),
+ PyBytes_GET_SIZE(o)
+ );
+ path->narrow = TRUE;
+ path->object = o;
+ o = wo;
+ } else if (PyObject_CheckBuffer(o)) {
+ PyObject *byteso = PyBytes_FromObject(o);
+ if (!byteso) {
+ return 0;
+ }
+ PyObject *wo = PyUnicode_DecodeFSDefaultAndSize(
+ PyBytes_AS_STRING(byteso),
+ PyBytes_GET_SIZE(byteso)
+ );
+ Py_DECREF(byteso);
+ path->narrow = TRUE;
+ path->object = o;
+ o = wo;
+ }
+
if (PyUnicode_Check(o)) {
-#ifdef MS_WINDOWS
const wchar_t *wide;
wide = PyUnicode_AsUnicodeAndSize(o, &length);
@@ -880,23 +925,42 @@
}
path->wide = wide;
- path->narrow = NULL;
path->length = length;
- path->object = o;
+ if (!path->narrow)
+ path->object = o;
path->fd = -1;
return 1;
-#else
+ } else if (path->allow_fd && PyIndex_Check(o)) {
+ if (!_fd_converter(o, &path->fd)) {
+ return 0;
+ }
+ path->wide = NULL;
+ path->narrow = FALSE;
+ path->length = 0;
+ path->object = o;
+ return 1;
+ } else {
+ PyErr_Format(PyExc_TypeError,
+ "%s%s%s should be %s, not %.200s",
+ path->function_name ? path->function_name : "",
+ path->function_name ? ": " : "",
+ path->argument_name ? path->argument_name : "path",
+ path->allow_fd && path->nullable ? "string, bytes, integer or None" :
+ path->allow_fd ? "string, bytes or integer" :
+ path->nullable ? "string, bytes or None" :
+ "string or bytes",
+ Py_TYPE(o)->tp_name);
+ return 0;
+ }
+
+#else /* MS_WINDOWS */
+
+ if (PyUnicode_Check(o)) {
if (!PyUnicode_FSConverter(o, &bytes)) {
return 0;
}
-#endif
}
else if (PyBytes_Check(o)) {
-#ifdef MS_WINDOWS
- if (win32_warn_bytes_api()) {
- return 0;
- }
-#endif
bytes = o;
Py_INCREF(bytes);
}
@@ -913,11 +977,6 @@
Py_TYPE(o)->tp_name)) {
return 0;
}
-#ifdef MS_WINDOWS
- if (win32_warn_bytes_api()) {
- return 0;
- }
-#endif
bytes = PyBytes_FromObject(o);
if (!bytes) {
return 0;
@@ -947,13 +1006,6 @@
}
length = PyBytes_GET_SIZE(bytes);
-#ifdef MS_WINDOWS
- if (length > MAX_PATH-1) {
- FORMAT_EXCEPTION(PyExc_ValueError, "%s too long for Windows");
- Py_DECREF(bytes);
- return 0;
- }
-#endif
narrow = PyBytes_AS_STRING(bytes);
if ((size_t)length != strlen(narrow)) {
@@ -975,6 +1027,7 @@
path->cleanup = bytes;
return Py_CLEANUP_SUPPORTED;
}
+#endif
}
static void
@@ -1024,7 +1077,11 @@
static int
path_and_dir_fd_invalid(const char *function_name, path_t *path, int dir_fd)
{
- if (!path->narrow && !path->wide && (dir_fd != DEFAULT_DIR_FD)) {
+ if (!path->wide && (dir_fd != DEFAULT_DIR_FD)
+#ifndef MS_WINDOWS
+ && !path->narrow
+#endif
+ ) {
PyErr_Format(PyExc_ValueError,
"%s: can't specify dir_fd without matching path",
function_name);
@@ -1354,31 +1411,6 @@
it also needs to set "magic" environment variables indicating
the per-drive current directory, which are of the form =: */
static BOOL __stdcall
-win32_chdir(LPCSTR path)
-{
- char new_path[MAX_PATH];
- int result;
- char env[4] = "=x:";
-
- if(!SetCurrentDirectoryA(path))
- return FALSE;
- result = GetCurrentDirectoryA(Py_ARRAY_LENGTH(new_path), new_path);
- if (!result)
- return FALSE;
- /* In the ANSI API, there should not be any paths longer
- than MAX_PATH-1 (not including the final null character). */
- assert(result fd, &st);
else
#ifdef MS_WINDOWS
- if (path->wide) {
- if (follow_symlinks)
- result = win32_stat_w(path->wide, &st);
- else
- result = win32_lstat_w(path->wide, &st);
- }
+ if (follow_symlinks)
+ result = win32_stat_w(path->wide, &st);
else
-#endif
-#if defined(HAVE_LSTAT) || defined(MS_WINDOWS)
+ result = win32_lstat_w(path->wide, &st);
+#else
+ else
+#if defined(HAVE_LSTAT)
if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD))
result = LSTAT(path->narrow, &st);
else
-#endif
+#endif /* HAVE_LSTAT */
#ifdef HAVE_FSTATAT
if ((dir_fd != DEFAULT_DIR_FD) || !follow_symlinks)
result = fstatat(dir_fd, path->narrow, &st,
follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW);
else
-#endif
+#endif /* HAVE_FSTATAT */
result = STAT(path->narrow, &st);
+#endif /* MS_WINDOWS */
Py_END_ALLOW_THREADS
if (result != 0) {
@@ -2612,10 +2643,7 @@
#ifdef MS_WINDOWS
Py_BEGIN_ALLOW_THREADS
- if (path->wide != NULL)
- attr = GetFileAttributesW(path->wide);
- else
- attr = GetFileAttributesA(path->narrow);
+ attr = GetFileAttributesW(path->wide);
Py_END_ALLOW_THREADS
/*
@@ -2739,11 +2767,8 @@
Py_BEGIN_ALLOW_THREADS
#ifdef MS_WINDOWS
- if (path->wide)
- result = win32_wchdir(path->wide);
- else
- result = win32_chdir(path->narrow);
- result = !result; /* on unix, success = 0, on windows, success = !0 */
+ /* on unix, success = 0, on windows, success = !0 */
+ result = !win32_wchdir(path->wide);
#else
#ifdef HAVE_FCHDIR
if (path->fd != -1)
@@ -2838,10 +2863,7 @@
#ifdef MS_WINDOWS
Py_BEGIN_ALLOW_THREADS
- if (path->wide)
- attr = GetFileAttributesW(path->wide);
- else
- attr = GetFileAttributesA(path->narrow);
+ attr = GetFileAttributesW(path->wide);
if (attr == INVALID_FILE_ATTRIBUTES)
result = 0;
else {
@@ -2849,10 +2871,7 @@
attr &= ~FILE_ATTRIBUTE_READONLY;
else
attr |= FILE_ATTRIBUTE_READONLY;
- if (path->wide)
- result = SetFileAttributesW(path->wide, attr);
- else
- result = SetFileAttributesA(path->narrow, attr);
+ result = SetFileAttributesW(path->wide, attr);
}
Py_END_ALLOW_THREADS
@@ -3445,7 +3464,7 @@
/*[clinic end generated code: output=7f00f6007fd5269a input=b0095ebbcbaa7e04]*/
{
#ifdef MS_WINDOWS
- BOOL result;
+ BOOL result = FALSE;
#else
int result;
#endif
@@ -3457,18 +3476,18 @@
}
#endif
+#ifndef MS_WINDOWS
if ((src->narrow && dst->wide) || (src->wide && dst->narrow)) {
PyErr_SetString(PyExc_NotImplementedError,
"link: src and dst must be the same type");
return NULL;
}
+#endif
#ifdef MS_WINDOWS
Py_BEGIN_ALLOW_THREADS
if (src->wide)
result = CreateHardLinkW(dst->wide, src->wide, NULL);
- else
- result = CreateHardLinkA(dst->narrow, src->narrow, NULL);
Py_END_ALLOW_THREADS
if (!result)
@@ -3483,13 +3502,13 @@
dst_dir_fd, dst->narrow,
follow_symlinks ? AT_SYMLINK_FOLLOW : 0);
else
-#endif
+#endif /* HAVE_LINKAT */
result = link(src->narrow, dst->narrow);
Py_END_ALLOW_THREADS
if (result)
return path_error2(src, dst);
-#endif
+#endif /* MS_WINDOWS */
Py_RETURN_NONE;
}
@@ -3503,97 +3522,39 @@
PyObject *v;
HANDLE hFindFile = INVALID_HANDLE_VALUE;
BOOL result;
- WIN32_FIND_DATA FileData;
- char namebuf[MAX_PATH+4]; /* Overallocate for "\*.*" */
+ wchar_t namebuf[MAX_PATH+4]; /* Overallocate for "\*.*" */
/* only claim to have space for MAX_PATH */
Py_ssize_t len = Py_ARRAY_LENGTH(namebuf)-4;
wchar_t *wnamebuf = NULL;
- if (!path->narrow) {
- WIN32_FIND_DATAW wFileData;
- const wchar_t *po_wchars;
-
- if (!path->wide) { /* Default arg: "." */
- po_wchars = L".";
- len = 1;
- } else {
- po_wchars = path->wide;
- len = wcslen(path->wide);
- }
- /* The +5 is so we can append "\\*.*\0" */
- wnamebuf = PyMem_New(wchar_t, len + 5);
- if (!wnamebuf) {
- PyErr_NoMemory();
- goto exit;
- }
- wcscpy(wnamebuf, po_wchars);
- if (len > 0) {
- wchar_t wch = wnamebuf[len-1];
- if (wch != SEP && wch != ALTSEP && wch != L':')
- wnamebuf[len++] = SEP;
- wcscpy(wnamebuf + len, L"*.*");
- }
- if ((list = PyList_New(0)) == NULL) {
- goto exit;
- }
- Py_BEGIN_ALLOW_THREADS
- hFindFile = FindFirstFileW(wnamebuf, &wFileData);
- Py_END_ALLOW_THREADS
- if (hFindFile == INVALID_HANDLE_VALUE) {
- int error = GetLastError();
- if (error == ERROR_FILE_NOT_FOUND)
- goto exit;
- Py_DECREF(list);
- list = path_error(path);
- goto exit;
- }
- do {
- /* Skip over . and .. */
- if (wcscmp(wFileData.cFileName, L".") != 0 &&
- wcscmp(wFileData.cFileName, L"..") != 0) {
- v = PyUnicode_FromWideChar(wFileData.cFileName,
- wcslen(wFileData.cFileName));
- if (v == NULL) {
- Py_DECREF(list);
- list = NULL;
- break;
- }
- if (PyList_Append(list, v) != 0) {
- Py_DECREF(v);
- Py_DECREF(list);
- list = NULL;
- break;
- }
- Py_DECREF(v);
- }
- Py_BEGIN_ALLOW_THREADS
- result = FindNextFileW(hFindFile, &wFileData);
- Py_END_ALLOW_THREADS
- /* FindNextFile sets error to ERROR_NO_MORE_FILES if
- it got to the end of the directory. */
- if (!result && GetLastError() != ERROR_NO_MORE_FILES) {
- Py_DECREF(list);
- list = path_error(path);
- goto exit;
- }
- } while (result == TRUE);
-
+ WIN32_FIND_DATAW wFileData;
+ const wchar_t *po_wchars;
+
+ if (!path->wide) { /* Default arg: "." */
+ po_wchars = L".";
+ len = 1;
+ } else {
+ po_wchars = path->wide;
+ len = wcslen(path->wide);
+ }
+ /* The +5 is so we can append "\\*.*\0" */
+ wnamebuf = PyMem_New(wchar_t, len + 5);
+ if (!wnamebuf) {
+ PyErr_NoMemory();
goto exit;
}
- strcpy(namebuf, path->narrow);
- len = path->length;
+ wcscpy(wnamebuf, po_wchars);
if (len > 0) {
- char ch = namebuf[len-1];
- if (ch != '\\' && ch != '/' && ch != ':')
- namebuf[len++] = '\\';
- strcpy(namebuf + len, "*.*");
- }
-
- if ((list = PyList_New(0)) == NULL)
- return NULL;
-
+ wchar_t wch = wnamebuf[len-1];
+ if (wch != SEP && wch != ALTSEP && wch != L':')
+ wnamebuf[len++] = SEP;
+ wcscpy(wnamebuf + len, L"*.*");
+ }
+ if ((list = PyList_New(0)) == NULL) {
+ goto exit;
+ }
Py_BEGIN_ALLOW_THREADS
- hFindFile = FindFirstFile(namebuf, &FileData);
+ hFindFile = FindFirstFileW(wnamebuf, &wFileData);
Py_END_ALLOW_THREADS
if (hFindFile == INVALID_HANDLE_VALUE) {
int error = GetLastError();
@@ -3605,9 +3566,13 @@
}
do {
/* Skip over . and .. */
- if (strcmp(FileData.cFileName, ".") != 0 &&
- strcmp(FileData.cFileName, "..") != 0) {
- v = PyBytes_FromString(FileData.cFileName);
+ if (wcscmp(wFileData.cFileName, L".") != 0 &&
+ wcscmp(wFileData.cFileName, L"..") != 0) {
+ v = PyUnicode_FromWideChar(wFileData.cFileName,
+ wcslen(wFileData.cFileName));
+ if (path->narrow && v) {
+ Py_SETREF(v, PyUnicode_EncodeFSDefault(v));
+ }
if (v == NULL) {
Py_DECREF(list);
list = NULL;
@@ -3622,7 +3587,7 @@
Py_DECREF(v);
}
Py_BEGIN_ALLOW_THREADS
- result = FindNextFile(hFindFile, &FileData);
+ result = FindNextFileW(hFindFile, &wFileData);
Py_END_ALLOW_THREADS
/* FindNextFile sets error to ERROR_NO_MORE_FILES if
it got to the end of the directory. */
@@ -3803,41 +3768,29 @@
os__getfullpathname_impl(PyObject *module, path_t *path)
/*[clinic end generated code: output=bb8679d56845bc9b input=332ed537c29d0a3e]*/
{
- if (!path->narrow)
- {
- wchar_t woutbuf[MAX_PATH], *woutbufp = woutbuf;
- wchar_t *wtemp;
- DWORD result;
- PyObject *v;
-
- result = GetFullPathNameW(path->wide,
- Py_ARRAY_LENGTH(woutbuf),
- woutbuf, &wtemp);
- if (result > Py_ARRAY_LENGTH(woutbuf)) {
- woutbufp = PyMem_New(wchar_t, result);
- if (!woutbufp)
- return PyErr_NoMemory();
- result = GetFullPathNameW(path->wide, result, woutbufp, &wtemp);
- }
- if (result)
- v = PyUnicode_FromWideChar(woutbufp, wcslen(woutbufp));
- else
- v = win32_error_object("GetFullPathNameW", path->object);
- if (woutbufp != woutbuf)
- PyMem_Free(woutbufp);
- return v;
- }
- else {
- char outbuf[MAX_PATH];
- char *temp;
-
- if (!GetFullPathName(path->narrow, Py_ARRAY_LENGTH(outbuf),
- outbuf, &temp)) {
- win32_error_object("GetFullPathName", path->object);
- return NULL;
- }
- return PyBytes_FromString(outbuf);
- }
+ wchar_t woutbuf[MAX_PATH], *woutbufp = woutbuf;
+ wchar_t *wtemp;
+ DWORD result;
+ PyObject *v;
+
+ result = GetFullPathNameW(path->wide,
+ Py_ARRAY_LENGTH(woutbuf),
+ woutbuf, &wtemp);
+ if (result > Py_ARRAY_LENGTH(woutbuf)) {
+ woutbufp = PyMem_New(wchar_t, result);
+ if (!woutbufp)
+ return PyErr_NoMemory();
+ result = GetFullPathNameW(path->wide, result, woutbufp, &wtemp);
+ }
+ if (result) {
+ v = PyUnicode_FromWideChar(woutbufp, wcslen(woutbufp));
+ if (path->narrow)
+ Py_SETREF(v, PyUnicode_EncodeFSDefault(v));
+ } else
+ v = win32_error_object("GetFullPathNameW", path->object);
+ if (woutbufp != woutbuf)
+ PyMem_Free(woutbufp);
+ return v;
}
@@ -3921,10 +3874,7 @@
DWORD attributes;
Py_BEGIN_ALLOW_THREADS
- if (!path->narrow)
- attributes = GetFileAttributesW(path->wide);
- else
- attributes = GetFileAttributesA(path->narrow);
+ attributes = GetFileAttributesW(path->wide);
Py_END_ALLOW_THREADS
if (attributes == INVALID_FILE_ATTRIBUTES)
@@ -4022,10 +3972,7 @@
#ifdef MS_WINDOWS
Py_BEGIN_ALLOW_THREADS
- if (path->wide)
- result = CreateDirectoryW(path->wide, NULL);
- else
- result = CreateDirectoryA(path->narrow, NULL);
+ result = CreateDirectoryW(path->wide, NULL);
Py_END_ALLOW_THREADS
if (!result)
@@ -4045,7 +3992,7 @@
Py_END_ALLOW_THREADS
if (result wide, dst->wide, flags);
+ Py_END_ALLOW_THREADS
+
+ if (!result)
+ return path_error2(src, dst);
+
+#else
if ((src->narrow && dst->wide) || (src->wide && dst->narrow)) {
PyErr_Format(PyExc_ValueError,
"%s: src and dst must be the same type", function_name);
return NULL;
}
-#ifdef MS_WINDOWS
- Py_BEGIN_ALLOW_THREADS
- if (src->wide)
- result = MoveFileExW(src->wide, dst->wide, flags);
- else
- result = MoveFileExA(src->narrow, dst->narrow, flags);
- Py_END_ALLOW_THREADS
-
- if (!result)
- return path_error2(src, dst);
-
-#else
Py_BEGIN_ALLOW_THREADS
#ifdef HAVE_RENAMEAT
if (dir_fd_specified)
result = renameat(src_dir_fd, src->narrow, dst_dir_fd, dst->narrow);
else
#endif
- result = rename(src->narrow, dst->narrow);
+ result = rename(src->narrow, dst->narrow);
Py_END_ALLOW_THREADS
if (result)
@@ -4273,11 +4217,8 @@
Py_BEGIN_ALLOW_THREADS
#ifdef MS_WINDOWS
- if (path->wide)
- result = RemoveDirectoryW(path->wide);
- else
- result = RemoveDirectoryA(path->narrow);
- result = !result; /* Windows, success=1, UNIX, success=0 */
+ /* Windows, success=1, UNIX, success=0 */
+ result = !RemoveDirectoryW(path->wide);
#else
#ifdef HAVE_UNLINKAT
if (dir_fd != DEFAULT_DIR_FD)
@@ -4423,11 +4364,8 @@
Py_BEGIN_ALLOW_THREADS
_Py_BEGIN_SUPPRESS_IPH
#ifdef MS_WINDOWS
- if (path->wide)
- result = Py_DeleteFileW(path->wide);
- else
- result = DeleteFileA(path->narrow);
- result = !result; /* Windows, success=1, UNIX, success=0 */
+ /* Windows, success=1, UNIX, success=0 */
+ result = !Py_DeleteFileW(path->wide);
#else
#ifdef HAVE_UNLINKAT
if (dir_fd != DEFAULT_DIR_FD)
@@ -4838,14 +4776,9 @@
#ifdef MS_WINDOWS
Py_BEGIN_ALLOW_THREADS
- if (path->wide)
- hFile = CreateFileW(path->wide, FILE_WRITE_ATTRIBUTES, 0,
- NULL, OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS, NULL);
- else
- hFile = CreateFileA(path->narrow, FILE_WRITE_ATTRIBUTES, 0,
- NULL, OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ hFile = CreateFileW(path->wide, FILE_WRITE_ATTRIBUTES, 0,
+ NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
Py_END_ALLOW_THREADS
if (hFile == INVALID_HANDLE_VALUE) {
path_error(path);
@@ -4931,9 +4864,15 @@
return NULL; /* Make gcc -Wall happy */
}
+#if defined(HAVE_WEXECV) || defined(HAVE_WSPAWNV)
+#define EXECV_CHAR wchar_t
+#else
+#define EXECV_CHAR char
+#endif
+
#if defined(HAVE_EXECV) || defined(HAVE_SPAWNV)
static void
-free_string_array(char **array, Py_ssize_t count)
+free_string_array(EXECV_CHAR **array, Py_ssize_t count)
{
Py_ssize_t i;
for (i = 0; i = 0)
- PyMem_DEL(envlist[envc]);
- PyMem_DEL(envlist);
+ free_string_array(envlist, envc);
return NULL;
}
-static char**
+static EXECV_CHAR**
parse_arglist(PyObject* argv, Py_ssize_t *argc)
{
int i;
- char **argvlist = PyMem_NEW(char *, *argc+1);
+ EXECV_CHAR **argvlist = PyMem_NEW(EXECV_CHAR *, *argc+1);
if (argvlist == NULL) {
PyErr_NoMemory();
return NULL;
@@ -5064,6 +4992,7 @@
free_string_array(argvlist, *argc);
return NULL;
}
+
#endif
@@ -5071,7 +5000,7 @@
/*[clinic input]
os.execv
- path: FSConverter
+ path: path_t
Path of executable file.
argv: object
Tuple or list of strings.
@@ -5081,17 +5010,15 @@
[clinic start generated code]*/
static PyObject *
-os_execv_impl(PyObject *module, PyObject *path, PyObject *argv)
-/*[clinic end generated code: output=b21dc34deeb5b004 input=96041559925e5229]*/
-{
- const char *path_char;
- char **argvlist;
+os_execv_impl(PyObject *module, path_t *path, PyObject *argv)
+/*[clinic end generated code: output=3b52fec34cd0dafd input=9bac31efae07dac7]*/
+{
+ EXECV_CHAR **argvlist;
Py_ssize_t argc;
/* execv has two arguments: (path, argv), where
argv is a list or tuple of strings. */
- path_char = PyBytes_AsString(path);
if (!PyList_Check(argv) && !PyTuple_Check(argv)) {
PyErr_SetString(PyExc_TypeError,
"execv() arg 2 must be a tuple or list");
@@ -5108,7 +5035,11 @@
return NULL;
}
- execv(path_char, argvlist);
+#ifdef HAVE_WEXECV
+ _wexecv(path->wide, argvlist);
+#else
+ execv(path->narrow, argvlist);
+#endif
/* If we get here it's definitely an error */
@@ -5134,8 +5065,8 @@
os_execve_impl(PyObject *module, path_t *path, PyObject *argv, PyObject *env)
/*[clinic end generated code: output=ff9fa8e4da8bde58 input=626804fa092606d9]*/
{
- char **argvlist = NULL;
- char **envlist;
+ EXECV_CHAR **argvlist = NULL;
+ EXECV_CHAR **envlist;
Py_ssize_t argc, envc;
/* execve has three arguments: (path, argv, env), where
@@ -5168,30 +5099,33 @@
fexecve(path->fd, argvlist, envlist);
else
#endif
+#ifdef HAVE_WEXECV
+ _wexecve(path->wide, argvlist, envlist);
+#else
execve(path->narrow, argvlist, envlist);
+#endif
/* If we get here it's definitely an error */
path_error(path);
- while (--envc >= 0)
- PyMem_DEL(envlist[envc]);
- PyMem_DEL(envlist);
+ free_string_array(envlist, envc);
fail:
if (argvlist)
free_string_array(argvlist, argc);
return NULL;
}
+
#endif /* HAVE_EXECV */
-#ifdef HAVE_SPAWNV
+#if defined(HAVE_SPAWNV) || defined(HAVE_WSPAWNV)
/*[clinic input]
os.spawnv
mode: int
Mode of process creation.
- path: FSConverter
+ path: path_t
Path of executable file.
argv: object
Tuple or list of strings.
@@ -5201,11 +5135,10 @@
[clinic start generated code]*/
static PyObject *
-os_spawnv_impl(PyObject *module, int mode, PyObject *path, PyObject *argv)
-/*[clinic end generated code: output=c427c0ce40f10638 input=042c91dfc1e6debc]*/
-{
- const char *path_char;
- char **argvlist;
+os_spawnv_impl(PyObject *module, int mode, path_t *path, PyObject *argv)
+/*[clinic end generated code: output=71cd037a9d96b816 input=43224242303291be]*/
+{
+ EXECV_CHAR **argvlist;
int i;
Py_ssize_t argc;
Py_intptr_t spawnval;
@@ -5214,7 +5147,6 @@
/* spawnv has three arguments: (mode, path, argv), where
argv is a list or tuple of strings. */
- path_char = PyBytes_AsString(path);
if (PyList_Check(argv)) {
argc = PyList_Size(argv);
getitem = PyList_GetItem;
@@ -5229,7 +5161,7 @@
return NULL;
}
- argvlist = PyMem_NEW(char *, argc+1);
+ argvlist = PyMem_NEW(EXECV_CHAR *, argc+1);
if (argvlist == NULL) {
return PyErr_NoMemory();
}
@@ -5249,7 +5181,11 @@
mode = _P_OVERLAY;
Py_BEGIN_ALLOW_THREADS
- spawnval = _spawnv(mode, path_char, argvlist);
+#ifdef HAVE_WSPAWNV
+ spawnval = _wspawnv(mode, path->wide, argvlist);
+#else
+ spawnval = _spawnv(mode, path->narrow, argvlist);
+#endif
Py_END_ALLOW_THREADS
free_string_array(argvlist, argc);
@@ -5266,7 +5202,7 @@
mode: int
Mode of process creation.
- path: FSConverter
+ path: path_t
Path of executable file.
argv: object
Tuple or list of strings.
@@ -5278,13 +5214,12 @@
[clinic start generated code]*/
static PyObject *
-os_spawnve_impl(PyObject *module, int mode, PyObject *path, PyObject *argv,
+os_spawnve_impl(PyObject *module, int mode, path_t *path, PyObject *argv,
PyObject *env)
-/*[clinic end generated code: output=ebcfa5f7ba2f4219 input=02362fd937963f8f]*/
-{
- const char *path_char;
- char **argvlist;
- char **envlist;
+/*[clinic end generated code: output=30fe85be56fe37ad input=3e40803ee7c4c586]*/
+{
+ EXECV_CHAR **argvlist;
+ EXECV_CHAR **envlist;
PyObject *res = NULL;
Py_ssize_t argc, i, envc;
Py_intptr_t spawnval;
@@ -5295,7 +5230,6 @@
argv is a list or tuple of strings and env is a dictionary
like posix.environ. */
- path_char = PyBytes_AsString(path);
if (PyList_Check(argv)) {
argc = PyList_Size(argv);
getitem = PyList_GetItem;
@@ -5315,7 +5249,7 @@
goto fail_0;
}
- argvlist = PyMem_NEW(char *, argc+1);
+ argvlist = PyMem_NEW(EXECV_CHAR *, argc+1);
if (argvlist == NULL) {
PyErr_NoMemory();
goto fail_0;
@@ -5339,7 +5273,11 @@
mode = _P_OVERLAY;
Py_BEGIN_ALLOW_THREADS
- spawnval = _spawnve(mode, path_char, argvlist, envlist);
+#ifdef HAVE_WSPAWNV
+ spawnval = _wspawnve(mode, path->wide, argvlist, envlist);
+#else
+ spawnval = _spawnve(mode, path->narrow, argvlist, envlist);
+#endif
Py_END_ALLOW_THREADS
if (spawnval == -1)
@@ -7247,21 +7185,18 @@
/* Grab CreateSymbolicLinkW dynamically from kernel32 */
static DWORD (CALLBACK *Py_CreateSymbolicLinkW)(LPCWSTR, LPCWSTR, DWORD) = NULL;
-static DWORD (CALLBACK *Py_CreateSymbolicLinkA)(LPCSTR, LPCSTR, DWORD) = NULL;
static int
check_CreateSymbolicLink(void)
{
HINSTANCE hKernel32;
/* only recheck */
- if (Py_CreateSymbolicLinkW && Py_CreateSymbolicLinkA)
+ if (Py_CreateSymbolicLinkW)
return 1;
hKernel32 = GetModuleHandleW(L"KERNEL32");
*(FARPROC*)&Py_CreateSymbolicLinkW = GetProcAddress(hKernel32,
"CreateSymbolicLinkW");
- *(FARPROC*)&Py_CreateSymbolicLinkA = GetProcAddress(hKernel32,
- "CreateSymbolicLinkA");
- return (Py_CreateSymbolicLinkW && Py_CreateSymbolicLinkA);
+ return Py_CreateSymbolicLinkW != NULL;
}
/* Remove the last portion of the path */
@@ -7278,20 +7213,6 @@
*ptr = 0;
}
-/* Remove the last portion of the path */
-static void
-_dirnameA(char *path)
-{
- char *ptr;
-
- /* walk the path from the end until a backslash is encountered */
- for(ptr = path + strlen(path); ptr != path; ptr--) {
- if (*ptr == '\\' || *ptr == '/')
- break;
- }
- *ptr = 0;
-}
-
/* Is this path absolute? */
static int
_is_absW(const WCHAR *path)
@@ -7300,14 +7221,6 @@
}
-/* Is this path absolute? */
-static int
-_is_absA(const char *path)
-{
- return path[0] == '\\' || path[0] == '/' || path[1] == ':';
-
-}
-
/* join root and rest with a backslash */
static void
_joinW(WCHAR *dest_path, const WCHAR *root, const WCHAR *rest)
@@ -7329,27 +7242,6 @@
wcscpy(dest_path+root_len, rest);
}
-/* join root and rest with a backslash */
-static void
-_joinA(char *dest_path, const char *root, const char *rest)
-{
- size_t root_len;
-
- if (_is_absA(rest)) {
- strcpy(dest_path, rest);
- return;
- }
-
- root_len = strlen(root);
-
- strcpy(dest_path, root);
- if(root_len) {
- dest_path[root_len] = '\\';
- root_len++;
- }
- strcpy(dest_path+root_len, rest);
-}
-
/* Return True if the path at src relative to dest is a directory */
static int
_check_dirW(LPCWSTR src, LPCWSTR dest)
@@ -7368,25 +7260,6 @@
&& src_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
);
}
-
-/* Return True if the path at src relative to dest is a directory */
-static int
-_check_dirA(LPCSTR src, LPCSTR dest)
-{
- WIN32_FILE_ATTRIBUTE_DATA src_info;
- char dest_parent[MAX_PATH];
- char src_resolved[MAX_PATH] = "";
-
- /* dest_parent = os.path.dirname(dest) */
- strcpy(dest_parent, dest);
- _dirnameA(dest_parent);
- /* src_resolved = os.path.join(dest_parent, src) */
- _joinA(src_resolved, dest_parent, src);
- return (
- GetFileAttributesExA(src_resolved, GetFileExInfoStandard, &src_info)
- && src_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
- );
-}
#endif
@@ -7446,18 +7319,10 @@
#ifdef MS_WINDOWS
Py_BEGIN_ALLOW_THREADS
- if (dst->wide) {
- /* if src is a directory, ensure target_is_directory==1 */
- target_is_directory |= _check_dirW(src->wide, dst->wide);
- result = Py_CreateSymbolicLinkW(dst->wide, src->wide,
- target_is_directory);
- }
- else {
- /* if src is a directory, ensure target_is_directory==1 */
- target_is_directory |= _check_dirA(src->narrow, dst->narrow);
- result = Py_CreateSymbolicLinkA(dst->narrow, src->narrow,
- target_is_directory);
- }
+ /* if src is a directory, ensure target_is_directory==1 */
+ target_is_directory |= _check_dirW(src->wide, dst->wide);
+ result = Py_CreateSymbolicLinkW(dst->wide, src->wide,
+ target_is_directory);
Py_END_ALLOW_THREADS
if (!result)
@@ -7762,16 +7627,14 @@
do {
Py_BEGIN_ALLOW_THREADS
#ifdef MS_WINDOWS
- if (path->wide)
- fd = _wopen(path->wide, flags, mode);
- else
+ fd = _wopen(path->wide, flags, mode);
#endif
#ifdef HAVE_OPENAT
if (dir_fd != DEFAULT_DIR_FD)
fd = openat(dir_fd, path->narrow, flags, mode);
else
-#endif
fd = open(path->narrow, flags, mode);
+#endif
Py_END_ALLOW_THREADS
} while (fd wide)
- fd = _wopen(path->wide, _O_WRONLY | _O_BINARY | _O_NOINHERIT);
- else
- fd = _open(path->narrow, _O_WRONLY | _O_BINARY | _O_NOINHERIT);
+ fd = _wopen(path->wide, _O_WRONLY | _O_BINARY | _O_NOINHERIT);
if (fd wide,
NULL, NULL, SW_SHOWNORMAL);
Py_END_ALLOW_THREADS
- Py_XDECREF(uoperation);
if (rc object);
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
#endif /* MS_WINDOWS */
@@ -11868,6 +11670,11 @@
entry->name = PyUnicode_FromWideChar(dataW->cFileName, -1);
if (!entry->name)
goto error;
+ if (path->narrow) {
+ Py_SETREF(entry->name, PyUnicode_EncodeFSDefault(entry->name));
+ if (!entry->name)
+ goto error;
+ }
joined_path = join_path_filenameW(path->wide, dataW->cFileName);
if (!joined_path)
@@ -11877,6 +11684,11 @@
PyMem_Free(joined_path);
if (!entry->path)
goto error;
+ if (path->narrow) {
+ Py_SETREF(entry->path, PyUnicode_EncodeFSDefault(entry->path));
+ if (!entry->path)
+ goto error;
+ }
find_data_to_file_info_w(dataW, &file_info, &reparse_tag);
_Py_attribute_data_to_stat(&file_info, reparse_tag, &entry->win32_lstat);
@@ -12274,11 +12086,6 @@
Py_XINCREF(iterator->path.object);
#ifdef MS_WINDOWS
- if (iterator->path.narrow) {
- PyErr_SetString(PyExc_TypeError,
- "os.scandir() doesn't support bytes path on Windows, use Unicode instead");
- goto error;
- }
iterator->first_time = 1;
path_strW = join_path_filenameW(iterator->path.wide, L"*.*");
@@ -12473,7 +12280,7 @@
OS_KILLPG_METHODDEF
OS_PLOCK_METHODDEF
#ifdef MS_WINDOWS
- {"startfile", win32_startfile, METH_VARARGS, win32_startfile__doc__},
+ OS_STARTFILE_METHODDEF
#endif
OS_SETUID_METHODDEF
OS_SETEUID_METHODDEF
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -3757,10 +3757,10 @@
PyObject*
PyUnicode_DecodeFSDefaultAndSize(const char *s, Py_ssize_t size)
{
-#ifdef HAVE_MBCS
+#if defined(MS_WINDOWS) || defined(__APPLE__)
+ return PyUnicode_DecodeUTF8Stateful(s, size, "surrogateescape", NULL);
+#elif defined(HAVE_MBCS)
return PyUnicode_DecodeMBCS(s, size, NULL);
-#elif defined(__APPLE__)
- return PyUnicode_DecodeUTF8Stateful(s, size, "surrogateescape", NULL);
#else
PyInterpreterState *interp = PyThreadState_GET()->interp;
/* Bootstrap check: if the filesystem codec is implemented in Python, we
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -21,12 +21,12 @@
Don't forget to modify PyUnicode_DecodeFSDefault() if you touch any of the
values for Py_FileSystemDefaultEncoding!
*/
-#ifdef HAVE_MBCS
+#if defined(MS_WINDOWS) || defined(__APPLE__)
+const char *Py_FileSystemDefaultEncoding = "utf-8";
+int Py_HasFileSystemDefaultEncoding = 1;
+#elif defined(HAVE_MBCS)
const char *Py_FileSystemDefaultEncoding = "mbcs";
int Py_HasFileSystemDefaultEncoding = 1;
-#elif defined(__APPLE__)
-const char *Py_FileSystemDefaultEncoding = "utf-8";
-int Py_HasFileSystemDefaultEncoding = 1;
#else
const char *Py_FileSystemDefaultEncoding = NULL; /* set by initfsencoding() */
int Py_HasFileSystemDefaultEncoding = 0;