diff options
author | Victor Stinner <vstinner@python.org> | 2025-01-06 12:43:09 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-06 12:43:09 (GMT) |
commit | f89e5e20cb8964653ea7d6f53d3e40953b6548ce (patch) | |
tree | 743bfa078c6861561f1a1b908fc848b968e89fad /Python | |
parent | 7e8c571604cd18e65cefd26bfc48082840264549 (diff) | |
download | cpython-f89e5e20cb8964653ea7d6f53d3e40953b6548ce.zip cpython-f89e5e20cb8964653ea7d6f53d3e40953b6548ce.tar.gz cpython-f89e5e20cb8964653ea7d6f53d3e40953b6548ce.tar.bz2 |
gh-127350: Add Py_fopen() and Py_fclose() functions (#127821)
Diffstat (limited to 'Python')
-rw-r--r-- | Python/errors.c | 2 | ||||
-rw-r--r-- | Python/fileutils.c | 79 | ||||
-rw-r--r-- | Python/import.c | 2 | ||||
-rw-r--r-- | Python/pythonrun.c | 2 | ||||
-rw-r--r-- | Python/sysmodule.c | 2 |
5 files changed, 53 insertions, 34 deletions
diff --git a/Python/errors.c b/Python/errors.c index 2d362c1..b6ac2f7 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -1981,7 +1981,7 @@ _PyErr_ProgramDecodedTextObject(PyObject *filename, int lineno, const char* enco return NULL; } - FILE *fp = _Py_fopen_obj(filename, "r" PY_STDIOTEXTMODE); + FILE *fp = Py_fopen(filename, "r" PY_STDIOTEXTMODE); if (fp == NULL) { PyErr_Clear(); return NULL; diff --git a/Python/fileutils.c b/Python/fileutils.c index 8127665..6bc3a44 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -1748,8 +1748,10 @@ _Py_wfopen(const wchar_t *path, const wchar_t *mode) } -/* Open a file. Call _wfopen() on Windows, or encode the path to the filesystem - encoding and call fopen() otherwise. +/* Open a file. + + On Windows, if 'path' is a Unicode string, call _wfopen(). Otherwise, encode + the path to the filesystem encoding and call fopen(). Return the new file object on success. Raise an exception and return NULL on error. @@ -1762,32 +1764,32 @@ _Py_wfopen(const wchar_t *path, const wchar_t *mode) Release the GIL to call _wfopen() or fopen(). The caller must hold the GIL. */ FILE* -_Py_fopen_obj(PyObject *path, const char *mode) +Py_fopen(PyObject *path, const char *mode) { - FILE *f; - int async_err = 0; -#ifdef MS_WINDOWS - wchar_t wmode[10]; - int usize; - assert(PyGILState_Check()); if (PySys_Audit("open", "Osi", path, mode, 0) < 0) { return NULL; } - if (!PyUnicode_Check(path)) { - PyErr_Format(PyExc_TypeError, - "str file path expected under Windows, got %R", - Py_TYPE(path)); + + FILE *f; + int async_err = 0; + int saved_errno; +#ifdef MS_WINDOWS + PyObject *unicode; + if (!PyUnicode_FSDecoder(path, &unicode)) { return NULL; } - wchar_t *wpath = PyUnicode_AsWideCharString(path, NULL); - if (wpath == NULL) + wchar_t *wpath = PyUnicode_AsWideCharString(unicode, NULL); + Py_DECREF(unicode); + if (wpath == NULL) { return NULL; + } - usize = MultiByteToWideChar(CP_ACP, 0, mode, -1, - wmode, Py_ARRAY_LENGTH(wmode)); + wchar_t wmode[10]; + int usize = MultiByteToWideChar(CP_ACP, 0, mode, -1, + wmode, Py_ARRAY_LENGTH(wmode)); if (usize == 0) { PyErr_SetFromWindowsErr(0); PyMem_Free(wpath); @@ -1796,26 +1798,20 @@ _Py_fopen_obj(PyObject *path, const char *mode) do { Py_BEGIN_ALLOW_THREADS + _Py_BEGIN_SUPPRESS_IPH f = _wfopen(wpath, wmode); + _Py_END_SUPPRESS_IPH Py_END_ALLOW_THREADS } while (f == NULL && errno == EINTR && !(async_err = PyErr_CheckSignals())); - int saved_errno = errno; + saved_errno = errno; PyMem_Free(wpath); #else PyObject *bytes; - const char *path_bytes; - - assert(PyGILState_Check()); - - if (!PyUnicode_FSConverter(path, &bytes)) - return NULL; - path_bytes = PyBytes_AS_STRING(bytes); - - if (PySys_Audit("open", "Osi", path, mode, 0) < 0) { - Py_DECREF(bytes); + if (!PyUnicode_FSConverter(path, &bytes)) { return NULL; } + const char *path_bytes = PyBytes_AS_STRING(bytes); do { Py_BEGIN_ALLOW_THREADS @@ -1823,11 +1819,13 @@ _Py_fopen_obj(PyObject *path, const char *mode) Py_END_ALLOW_THREADS } while (f == NULL && errno == EINTR && !(async_err = PyErr_CheckSignals())); - int saved_errno = errno; + saved_errno = errno; Py_DECREF(bytes); #endif - if (async_err) + + if (async_err) { return NULL; + } if (f == NULL) { errno = saved_errno; @@ -1842,6 +1840,27 @@ _Py_fopen_obj(PyObject *path, const char *mode) return f; } + +// Deprecated alias to Py_fopen() kept for backward compatibility +FILE* +_Py_fopen_obj(PyObject *path, const char *mode) +{ + return Py_fopen(path, mode); +} + + +// Call fclose(). +// +// On Windows, files opened by Py_fopen() in the Python DLL must be closed by +// the Python DLL to use the same C runtime version. Otherwise, calling +// fclose() directly can cause undefined behavior. +int +Py_fclose(FILE *file) +{ + return fclose(file); +} + + /* Read count bytes from fd into buf. On success, return the number of read bytes, it can be lower than count. diff --git a/Python/import.c b/Python/import.c index a9282dd..b3648e2 100644 --- a/Python/import.c +++ b/Python/import.c @@ -4688,7 +4688,7 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) * code relies on fp still being open. */ FILE *fp; if (file != NULL) { - fp = _Py_fopen_obj(info.filename, "r"); + fp = Py_fopen(info.filename, "r"); if (fp == NULL) { goto finally; } diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 31e065f..0da26ad 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -467,7 +467,7 @@ _PyRun_SimpleFileObject(FILE *fp, PyObject *filename, int closeit, fclose(fp); } - pyc_fp = _Py_fopen_obj(filename, "rb"); + pyc_fp = Py_fopen(filename, "rb"); if (pyc_fp == NULL) { fprintf(stderr, "python: Can't reopen .pyc file\n"); goto done; diff --git a/Python/sysmodule.c b/Python/sysmodule.c index d6719f9..887591a 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2356,7 +2356,7 @@ static PyObject * sys__dump_tracelets_impl(PyObject *module, PyObject *outpath) /*[clinic end generated code: output=a7fe265e2bc3b674 input=5bff6880cd28ffd1]*/ { - FILE *out = _Py_fopen_obj(outpath, "wb"); + FILE *out = Py_fopen(outpath, "wb"); if (out == NULL) { return NULL; } |