Commit a555cfcb authored by Victor Stinner's avatar Victor Stinner

Issue #23694: Enhance _Py_open(), it now raises exceptions

* _Py_open() now raises exceptions on error. If open() fails, it raises an
  OSError with the filename.
* _Py_open() now releases the GIL while calling open()
* Add _Py_open_noraise() when _Py_open() cannot be used because the GIL is not
  held
parent 6562b29e
...@@ -62,6 +62,10 @@ PyAPI_FUNC(int) _Py_stat( ...@@ -62,6 +62,10 @@ PyAPI_FUNC(int) _Py_stat(
PyAPI_FUNC(int) _Py_open( PyAPI_FUNC(int) _Py_open(
const char *pathname, const char *pathname,
int flags); int flags);
PyAPI_FUNC(int) _Py_open_noraise(
const char *pathname,
int flags);
#endif #endif
PyAPI_FUNC(FILE *) _Py_wfopen( PyAPI_FUNC(FILE *) _Py_wfopen(
......
...@@ -257,6 +257,7 @@ _close_open_fds_safe(int start_fd, PyObject* py_fds_to_keep) ...@@ -257,6 +257,7 @@ _close_open_fds_safe(int start_fd, PyObject* py_fds_to_keep)
fd_dir_fd = _Py_open(FD_DIR, O_RDONLY); fd_dir_fd = _Py_open(FD_DIR, O_RDONLY);
if (fd_dir_fd == -1) { if (fd_dir_fd == -1) {
/* No way to get a list of open fds. */ /* No way to get a list of open fds. */
PyErr_Clear();
_close_fds_by_brute_force(start_fd, py_fds_to_keep); _close_fds_by_brute_force(start_fd, py_fds_to_keep);
return; return;
} else { } else {
......
...@@ -1221,7 +1221,6 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) ...@@ -1221,7 +1221,6 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
fd = devzero = _Py_open("/dev/zero", O_RDWR); fd = devzero = _Py_open("/dev/zero", O_RDWR);
if (devzero == -1) { if (devzero == -1) {
Py_DECREF(m_obj); Py_DECREF(m_obj);
PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
#endif #endif
......
...@@ -116,11 +116,8 @@ newossobject(PyObject *arg) ...@@ -116,11 +116,8 @@ newossobject(PyObject *arg)
provides a special ioctl() for non-blocking read/write, which is provides a special ioctl() for non-blocking read/write, which is
exposed via oss_nonblock() below. */ exposed via oss_nonblock() below. */
fd = _Py_open(devicename, imode|O_NONBLOCK); fd = _Py_open(devicename, imode|O_NONBLOCK);
if (fd == -1)
if (fd == -1) {
PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename);
return NULL; return NULL;
}
/* And (try to) put it back in blocking mode so we get the /* And (try to) put it back in blocking mode so we get the
expected write() semantics. */ expected write() semantics. */
...@@ -180,10 +177,8 @@ newossmixerobject(PyObject *arg) ...@@ -180,10 +177,8 @@ newossmixerobject(PyObject *arg)
} }
fd = _Py_open(devicename, O_RDWR); fd = _Py_open(devicename, O_RDWR);
if (fd == -1) { if (fd == -1)
PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename);
return NULL; return NULL;
}
if ((self = PyObject_New(oss_mixer_t, &OSSMixerType)) == NULL) { if ((self = PyObject_New(oss_mixer_t, &OSSMixerType)) == NULL) {
close(fd); close(fd);
......
...@@ -7930,7 +7930,7 @@ os_openpty_impl(PyModuleDef *module) ...@@ -7930,7 +7930,7 @@ os_openpty_impl(PyModuleDef *module)
slave_fd = _Py_open(slave_name, O_RDWR); slave_fd = _Py_open(slave_name, O_RDWR);
if (slave_fd < 0) if (slave_fd < 0)
goto posix_error; goto error;
#else #else
master_fd = open(DEV_PTY_FILE, O_RDWR | O_NOCTTY); /* open master */ master_fd = open(DEV_PTY_FILE, O_RDWR | O_NOCTTY); /* open master */
...@@ -7958,8 +7958,8 @@ os_openpty_impl(PyModuleDef *module) ...@@ -7958,8 +7958,8 @@ os_openpty_impl(PyModuleDef *module)
goto posix_error; goto posix_error;
slave_fd = _Py_open(slave_name, O_RDWR | O_NOCTTY); /* open slave */ slave_fd = _Py_open(slave_name, O_RDWR | O_NOCTTY); /* open slave */
if (slave_fd < 0) if (slave_fd == -1)
goto posix_error; goto error;
if (_Py_set_inheritable(master_fd, 0, NULL) < 0) if (_Py_set_inheritable(master_fd, 0, NULL) < 0)
goto posix_error; goto posix_error;
...@@ -7977,9 +7977,7 @@ os_openpty_impl(PyModuleDef *module) ...@@ -7977,9 +7977,7 @@ os_openpty_impl(PyModuleDef *module)
posix_error: posix_error:
posix_error(); posix_error();
#if defined(HAVE_OPENPTY) || defined(HAVE__GETPTY)
error: error:
#endif
if (master_fd != -1) if (master_fd != -1)
close(master_fd); close(master_fd);
if (slave_fd != -1) if (slave_fd != -1)
......
...@@ -1013,7 +1013,6 @@ newDevPollObject(void) ...@@ -1013,7 +1013,6 @@ newDevPollObject(void)
struct pollfd *fds; struct pollfd *fds;
struct rlimit limit; struct rlimit limit;
Py_BEGIN_ALLOW_THREADS
/* /*
** If we try to process more that getrlimit() ** If we try to process more that getrlimit()
** fds, the kernel will give an error, so ** fds, the kernel will give an error, so
...@@ -1021,18 +1020,14 @@ newDevPollObject(void) ...@@ -1021,18 +1020,14 @@ newDevPollObject(void)
** value, because we can change rlimit() anytime. ** value, because we can change rlimit() anytime.
*/ */
limit_result = getrlimit(RLIMIT_NOFILE, &limit); limit_result = getrlimit(RLIMIT_NOFILE, &limit);
if (limit_result != -1)
fd_devpoll = _Py_open("/dev/poll", O_RDWR);
Py_END_ALLOW_THREADS
if (limit_result == -1) { if (limit_result == -1) {
PyErr_SetFromErrno(PyExc_OSError); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
if (fd_devpoll == -1) {
PyErr_SetFromErrnoWithFilename(PyExc_IOError, "/dev/poll"); fd_devpoll = _Py_open("/dev/poll", O_RDWR);
if (fd_devpoll == -1)
return NULL; return NULL;
}
fds = PyMem_NEW(struct pollfd, limit.rlim_cur); fds = PyMem_NEW(struct pollfd, limit.rlim_cur);
if (fds == NULL) { if (fds == NULL) {
......
...@@ -30,7 +30,8 @@ extern wchar_t* _Py_DecodeUTF8_surrogateescape(const char *s, Py_ssize_t size); ...@@ -30,7 +30,8 @@ extern wchar_t* _Py_DecodeUTF8_surrogateescape(const char *s, Py_ssize_t size);
0: open() ignores O_CLOEXEC flag, ex: Linux kernel older than 2.6.23 0: open() ignores O_CLOEXEC flag, ex: Linux kernel older than 2.6.23
1: open() supports O_CLOEXEC flag, close-on-exec is set 1: open() supports O_CLOEXEC flag, close-on-exec is set
The flag is used by _Py_open(), io.FileIO and os.open() */ The flag is used by _Py_open(), _Py_open_noraise(), io.FileIO
and os.open(). */
int _Py_open_cloexec_works = -1; int _Py_open_cloexec_works = -1;
#endif #endif
...@@ -907,37 +908,74 @@ _Py_set_inheritable(int fd, int inheritable, int *atomic_flag_works) ...@@ -907,37 +908,74 @@ _Py_set_inheritable(int fd, int inheritable, int *atomic_flag_works)
return set_inheritable(fd, inheritable, 1, atomic_flag_works); return set_inheritable(fd, inheritable, 1, atomic_flag_works);
} }
/* Open a file with the specified flags (wrapper to open() function). static int
The file descriptor is created non-inheritable. */ _Py_open_impl(const char *pathname, int flags, int gil_held)
int
_Py_open(const char *pathname, int flags)
{ {
int fd; int fd;
#ifdef MS_WINDOWS #ifndef MS_WINDOWS
fd = open(pathname, flags | O_NOINHERIT);
if (fd < 0)
return fd;
#else
int *atomic_flag_works; int *atomic_flag_works;
#ifdef O_CLOEXEC #endif
#ifdef MS_WINDOWS
flags |= O_NOINHERIT;
#elif defined(O_CLOEXEC)
atomic_flag_works = &_Py_open_cloexec_works; atomic_flag_works = &_Py_open_cloexec_works;
flags |= O_CLOEXEC; flags |= O_CLOEXEC;
#else #else
atomic_flag_works = NULL; atomic_flag_works = NULL;
#endif #endif
if (gil_held) {
Py_BEGIN_ALLOW_THREADS
fd = open(pathname, flags);
Py_END_ALLOW_THREADS
if (fd < 0) {
PyErr_SetFromErrnoWithFilename(PyExc_OSError, pathname);
return -1;
}
}
else {
fd = open(pathname, flags); fd = open(pathname, flags);
if (fd < 0) if (fd < 0)
return fd; return -1;
}
if (set_inheritable(fd, 0, 0, atomic_flag_works) < 0) { #ifndef MS_WINDOWS
if (set_inheritable(fd, 0, gil_held, atomic_flag_works) < 0) {
close(fd); close(fd);
return -1; return -1;
} }
#endif /* !MS_WINDOWS */ #endif
return fd; return fd;
} }
/* Open a file with the specified flags (wrapper to open() function).
Return a file descriptor on success. Raise an exception and return -1 on
error.
The file descriptor is created non-inheritable.
The GIL must be held. Use _Py_open_noraise() if the GIL cannot be held. */
int
_Py_open(const char *pathname, int flags)
{
/* _Py_open() must be called with the GIL held. */
assert(PyGILState_Check());
return _Py_open_impl(pathname, flags, 1);
}
/* Open a file with the specified flags (wrapper to open() function).
Return a file descriptor on success. Set errno and return -1 on error.
The file descriptor is created non-inheritable. */
int
_Py_open_noraise(const char *pathname, int flags)
{
return _Py_open_impl(pathname, flags, 0);
}
/* Open a file. Use _wfopen() on Windows, encode the path to the locale /* Open a file. Use _wfopen() on Windows, encode the path to the locale
encoding and use fopen() otherwise. The file descriptor is created encoding and use fopen() otherwise. The file descriptor is created
non-inheritable. */ non-inheritable. */
......
...@@ -111,7 +111,7 @@ dev_urandom_noraise(unsigned char *buffer, Py_ssize_t size) ...@@ -111,7 +111,7 @@ dev_urandom_noraise(unsigned char *buffer, Py_ssize_t size)
assert (0 < size); assert (0 < size);
fd = _Py_open("/dev/urandom", O_RDONLY); fd = _Py_open_noraise("/dev/urandom", O_RDONLY);
if (fd < 0) if (fd < 0)
Py_FatalError("Failed to open /dev/urandom"); Py_FatalError("Failed to open /dev/urandom");
...@@ -158,17 +158,13 @@ dev_urandom_python(char *buffer, Py_ssize_t size) ...@@ -158,17 +158,13 @@ dev_urandom_python(char *buffer, Py_ssize_t size)
if (urandom_cache.fd >= 0) if (urandom_cache.fd >= 0)
fd = urandom_cache.fd; fd = urandom_cache.fd;
else { else {
Py_BEGIN_ALLOW_THREADS
fd = _Py_open("/dev/urandom", O_RDONLY); fd = _Py_open("/dev/urandom", O_RDONLY);
Py_END_ALLOW_THREADS if (fd < 0) {
if (fd < 0)
{
if (errno == ENOENT || errno == ENXIO || if (errno == ENOENT || errno == ENXIO ||
errno == ENODEV || errno == EACCES) errno == ENODEV || errno == EACCES)
PyErr_SetString(PyExc_NotImplementedError, PyErr_SetString(PyExc_NotImplementedError,
"/dev/urandom (or equivalent) not found"); "/dev/urandom (or equivalent) not found");
else /* otherwise, keep the OSError exception raised by _Py_open() */
PyErr_SetFromErrno(PyExc_OSError);
return -1; return -1;
} }
if (urandom_cache.fd >= 0) { if (urandom_cache.fd >= 0) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment