From e742bfec1787583d20c658d0fbdce7b1ae5933b5 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 6 Jul 2026 20:49:00 +0200 Subject: [PATCH] On Unix, avoid a conversion to wchar_t in getpath.c * Replace _Py_wstat() with _Py_stat() in isfile() and isxfile(). * Replace _Py_wfopen() with Py_fopen() in readlines(). --- Modules/getpath.c | 85 +++++++++++++++++++++++----------------------- Python/fileutils.c | 13 ++++--- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/Modules/getpath.c b/Modules/getpath.c index 0c80678a678dc8..ed41536acbcc81 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -198,57 +198,67 @@ getpath_isdir(PyObject *Py_UNUSED(self), PyObject *args) static PyObject * getpath_isfile(PyObject *Py_UNUSED(self), PyObject *args) { - PyObject *r = NULL; PyObject *pathobj; - const wchar_t *path; if (!PyArg_ParseTuple(args, "U", &pathobj)) { return NULL; } - path = PyUnicode_AsWideCharString(pathobj, NULL); - if (path) { + + int isfile; #ifdef MS_WINDOWS - DWORD attr = GetFileAttributesW(path); - r = (attr != INVALID_FILE_ATTRIBUTES) && - !(attr & FILE_ATTRIBUTE_DIRECTORY) ? Py_True : Py_False; + wchar_t *path = PyUnicode_AsWideCharString(pathobj, NULL); + if (path == NULL) { + return NULL; + } + + DWORD attr = GetFileAttributesW(path); + PyMem_Free(path); + isfile = ((attr != INVALID_FILE_ATTRIBUTES) + && !(attr & FILE_ATTRIBUTE_DIRECTORY)); #else - struct stat st; - r = (_Py_wstat(path, &st) == 0) && S_ISREG(st.st_mode) ? Py_True : Py_False; -#endif - PyMem_Free((void *)path); + struct stat st; + int res = _Py_stat(pathobj, &st); + if (res == -2) { + return NULL; } - return Py_XNewRef(r); + isfile = ((res == 0) && S_ISREG(st.st_mode)); +#endif + return PyBool_FromLong(isfile); } static PyObject * getpath_isxfile(PyObject *Py_UNUSED(self), PyObject *args) { - PyObject *r = NULL; PyObject *pathobj; - const wchar_t *path; - Py_ssize_t cchPath; if (!PyArg_ParseTuple(args, "U", &pathobj)) { return NULL; } - path = PyUnicode_AsWideCharString(pathobj, &cchPath); - if (path) { + + int isxfile; #ifdef MS_WINDOWS - DWORD attr = GetFileAttributesW(path); - r = (attr != INVALID_FILE_ATTRIBUTES) && - !(attr & FILE_ATTRIBUTE_DIRECTORY) && - (cchPath >= 4) && - (CompareStringOrdinal(path + cchPath - 4, -1, L".exe", -1, 1 /* ignore case */) == CSTR_EQUAL) - ? Py_True : Py_False; + Py_ssize_t cchPath; + wchar_t *path = PyUnicode_AsWideCharString(pathobj, &cchPath); + if (path == NULL) { + return NULL; + } + + DWORD attr = GetFileAttributesW(path); + PyMem_Free(path); + isxfile = (attr != INVALID_FILE_ATTRIBUTES) && + !(attr & FILE_ATTRIBUTE_DIRECTORY) && + (cchPath >= 4) && + (CompareStringOrdinal(path + cchPath - 4, -1, L".exe", -1, 1 /* ignore case */) == CSTR_EQUAL); #else - struct stat st; - r = (_Py_wstat(path, &st) == 0) && - S_ISREG(st.st_mode) && - (st.st_mode & 0111) - ? Py_True : Py_False; -#endif - PyMem_Free((void *)path); + struct stat st; + int res = _Py_stat(pathobj, &st); + if (res == -2) { + return NULL; } - return Py_XNewRef(r); + isxfile = ((res == 0) + && S_ISREG(st.st_mode) + && (st.st_mode & 0111)); +#endif + return PyBool_FromLong(isxfile); } @@ -340,25 +350,16 @@ getpath_joinpath(PyObject *Py_UNUSED(self), PyObject *args) static PyObject * getpath_readlines(PyObject *Py_UNUSED(self), PyObject *args) { - PyObject *r = NULL; PyObject *pathobj; - const wchar_t *path; if (!PyArg_ParseTuple(args, "U", &pathobj)) { return NULL; } - path = PyUnicode_AsWideCharString(pathobj, NULL); - if (!path) { - return NULL; - } - FILE *fp = _Py_wfopen(path, L"rb"); + FILE *fp = Py_fopen(pathobj, "rb"); if (!fp) { - PyErr_SetFromErrno(PyExc_OSError); - PyMem_Free((void *)path); return NULL; } - PyMem_Free((void *)path); - r = PyList_New(0); + PyObject *r = PyList_New(0); if (!r) { fclose(fp); return NULL; diff --git a/Python/fileutils.c b/Python/fileutils.c index 0c1766b8804500..98ed66eff94ee1 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -1368,22 +1368,21 @@ _Py_stat(PyObject *path, struct stat *statbuf) PyMem_Free(wpath); return err; #else - int ret; - PyObject *bytes; - char *cpath; - - bytes = PyUnicode_EncodeFSDefault(path); - if (bytes == NULL) + PyObject *bytes = PyUnicode_EncodeFSDefault(path); + if (bytes == NULL) { return -2; + } /* check for embedded null bytes */ + char *cpath; if (PyBytes_AsStringAndSize(bytes, &cpath, NULL) == -1) { Py_DECREF(bytes); return -2; } - ret = stat(cpath, statbuf); + int ret = stat(cpath, statbuf); Py_DECREF(bytes); + assert(ret == 0 || ret == -1); return ret; #endif }