summaryrefslogtreecommitdiff
path: root/Modules/_io
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2015-03-19 22:53:20 +0100
committerVictor Stinner <victor.stinner@gmail.com>2015-03-19 22:53:20 +0100
commit00471d560c71a73624b8983caf1707ed1610e84d (patch)
tree81840c917e4dfde70b6c494d1368e585d9194e9b /Modules/_io
parent82ab525ae487e6f735821276641415ab58213fd6 (diff)
downloadcpython-00471d560c71a73624b8983caf1707ed1610e84d.tar.gz
Issue #23708: Add _Py_read() and _Py_write() functions to factorize code handle
EINTR error and special cases for Windows. These functions now truncate the length to PY_SSIZE_T_MAX to have a portable and reliable behaviour. For example, read() result is undefined if counter is greater than PY_SSIZE_T_MAX on Linux.
Diffstat (limited to 'Modules/_io')
-rw-r--r--Modules/_io/fileio.c142
1 files changed, 31 insertions, 111 deletions
diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c
index 0f226eafbf..6152cde464 100644
--- a/Modules/_io/fileio.c
+++ b/Modules/_io/fileio.c
@@ -570,8 +570,8 @@ static PyObject *
fileio_readinto(fileio *self, PyObject *args)
{
Py_buffer pbuf;
- Py_ssize_t n, len;
- int err, async_err = 0;
+ Py_ssize_t n;
+ int err;
if (self->fd < 0)
return err_closed();
@@ -581,36 +581,16 @@ fileio_readinto(fileio *self, PyObject *args)
if (!PyArg_ParseTuple(args, "w*", &pbuf))
return NULL;
- if (_PyVerify_fd(self->fd)) {
- len = pbuf.len;
-#ifdef MS_WINDOWS
- if (len > INT_MAX)
- len = INT_MAX;
-#endif
-
- do {
- Py_BEGIN_ALLOW_THREADS
- errno = 0;
-#ifdef MS_WINDOWS
- n = read(self->fd, pbuf.buf, (int)len);
-#else
- n = read(self->fd, pbuf.buf, len);
-#endif
- Py_END_ALLOW_THREADS
- } while (n < 0 && errno == EINTR &&
- !(async_err = PyErr_CheckSignals()));
-
- if (async_err)
- return NULL;
- } else
- n = -1;
+ n = _Py_read(self->fd, pbuf.buf, pbuf.len);
+ /* copy errno because PyBuffer_Release() can indirectly modify it */
err = errno;
PyBuffer_Release(&pbuf);
- if (n < 0) {
- if (err == EAGAIN)
+
+ if (n == -1) {
+ if (err == EAGAIN) {
+ PyErr_Clear();
Py_RETURN_NONE;
- errno = err;
- PyErr_SetFromErrno(PyExc_IOError);
+ }
return NULL;
}
@@ -645,9 +625,8 @@ fileio_readall(fileio *self)
Py_off_t pos, end;
PyObject *result;
Py_ssize_t bytes_read = 0;
- Py_ssize_t len, n;
+ Py_ssize_t n;
size_t bufsize;
- int async_err = 0;
if (self->fd < 0)
return err_closed();
@@ -695,36 +674,21 @@ fileio_readall(fileio *self)
}
}
- len = bufsize - bytes_read;
-#ifdef MS_WINDOWS
- if (len > INT_MAX)
- len = INT_MAX;
-#endif
- do {
- Py_BEGIN_ALLOW_THREADS
- errno = 0;
-#ifdef MS_WINDOWS
- n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, (int)len);
-#else
- n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, len);
-#endif
- Py_END_ALLOW_THREADS
- } while (n < 0 && errno == EINTR &&
- !(async_err = PyErr_CheckSignals()));
+ n = _Py_read(self->fd,
+ PyBytes_AS_STRING(result) + bytes_read,
+ bufsize - bytes_read);
- if (async_err)
- return NULL;
if (n == 0)
break;
- if (n < 0) {
+ if (n == -1) {
if (errno == EAGAIN) {
+ PyErr_Clear();
if (bytes_read > 0)
break;
Py_DECREF(result);
Py_RETURN_NONE;
}
Py_DECREF(result);
- PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
bytes_read += n;
@@ -756,7 +720,6 @@ fileio_read(fileio *self, PyObject *args)
char *ptr;
Py_ssize_t n;
Py_ssize_t size = -1;
- int async_err = 0;
PyObject *bytes;
if (self->fd < 0)
@@ -767,44 +730,29 @@ fileio_read(fileio *self, PyObject *args)
if (!PyArg_ParseTuple(args, "|O&", &_PyIO_ConvertSsize_t, &size))
return NULL;
- if (size < 0) {
+ if (size < 0)
return fileio_readall(self);
- }
#ifdef MS_WINDOWS
+ /* On Windows, the count parameter of read() is an int */
if (size > INT_MAX)
size = INT_MAX;
#endif
+
bytes = PyBytes_FromStringAndSize(NULL, size);
if (bytes == NULL)
return NULL;
ptr = PyBytes_AS_STRING(bytes);
- if (_PyVerify_fd(self->fd)) {
- do {
- Py_BEGIN_ALLOW_THREADS
- errno = 0;
-#ifdef MS_WINDOWS
- n = read(self->fd, ptr, (int)size);
-#else
- n = read(self->fd, ptr, size);
-#endif
- Py_END_ALLOW_THREADS
- } while (n < 0 && errno == EINTR &&
- !(async_err = PyErr_CheckSignals()));
-
- if (async_err)
- return NULL;
- } else
- n = -1;
-
- if (n < 0) {
+ n = _Py_read(self->fd, ptr, size);
+ if (n == -1) {
+ /* copy errno because Py_DECREF() can indirectly modify it */
int err = errno;
Py_DECREF(bytes);
- if (err == EAGAIN)
+ if (err == EAGAIN) {
+ PyErr_Clear();
Py_RETURN_NONE;
- errno = err;
- PyErr_SetFromErrno(PyExc_IOError);
+ }
return NULL;
}
@@ -822,8 +770,8 @@ static PyObject *
fileio_write(fileio *self, PyObject *args)
{
Py_buffer pbuf;
- Py_ssize_t n, len;
- int err, async_err = 0;
+ Py_ssize_t n;
+ int err;
if (self->fd < 0)
return err_closed();
@@ -833,44 +781,16 @@ fileio_write(fileio *self, PyObject *args)
if (!PyArg_ParseTuple(args, "y*", &pbuf))
return NULL;
- if (_PyVerify_fd(self->fd)) {
- len = pbuf.len;
-#ifdef MS_WINDOWS
- if (len > 32767 && isatty(self->fd)) {
- /* Issue #11395: the Windows console returns an error (12: not
- enough space error) on writing into stdout if stdout mode is
- binary and the length is greater than 66,000 bytes (or less,
- depending on heap usage). */
- len = 32767;
- } else if (len > INT_MAX)
- len = INT_MAX;
-#endif
-
- do {
- Py_BEGIN_ALLOW_THREADS
- errno = 0;
-#ifdef MS_WINDOWS
- n = write(self->fd, pbuf.buf, (int)len);
-#else
- n = write(self->fd, pbuf.buf, len);
-#endif
- Py_END_ALLOW_THREADS
- } while (n < 0 && errno == EINTR &&
- !(async_err = PyErr_CheckSignals()));
-
- if (async_err)
- return NULL;
- } else
- n = -1;
+ n = _Py_write(self->fd, pbuf.buf, pbuf.len);
+ /* copy errno because PyBuffer_Release() can indirectly modify it */
err = errno;
-
PyBuffer_Release(&pbuf);
if (n < 0) {
- if (err == EAGAIN)
+ if (err == EAGAIN) {
+ PyErr_Clear();
Py_RETURN_NONE;
- errno = err;
- PyErr_SetFromErrno(PyExc_IOError);
+ }
return NULL;
}