summaryrefslogtreecommitdiffstats
path: root/Objects/fileobject.c
diff options
context:
space:
mode:
authorGustavo Niemeyer <gustavo@niemeyer.net>2002-12-16 18:12:53 (GMT)
committerGustavo Niemeyer <gustavo@niemeyer.net>2002-12-16 18:12:53 (GMT)
commit786ddb29c9170a585ca1010bd392fb5a5ff4078c (patch)
treef13b95625431e6be163ae9f0a03118b3f9d13a0d /Objects/fileobject.c
parent17c5a33582be263e3d3484f1c16f17dadeea5b6f (diff)
downloadcpython-786ddb29c9170a585ca1010bd392fb5a5ff4078c.zip
cpython-786ddb29c9170a585ca1010bd392fb5a5ff4078c.tar.gz
cpython-786ddb29c9170a585ca1010bd392fb5a5ff4078c.tar.bz2
Fixed bug
[#521782] unreliable file.read() error handling * Objects/fileobject.c (file_read): Clear errors before leaving the loop in all situations, and also check if some data was read before exiting the loop with an EWOULDBLOCK exception. * Doc/lib/libstdtypes.tex * Objects/fileobject.c Document that sometimes a read() operation can return less data than what the user asked, if running in non-blocking mode. * Misc/NEWS Document the fix.
Diffstat (limited to 'Objects/fileobject.c')
-rw-r--r--Objects/fileobject.c33
1 files changed, 30 insertions, 3 deletions
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index 86620ff..612cefd 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -741,6 +741,20 @@ new_buffersize(PyFileObject *f, size_t currentsize)
return currentsize + SMALLCHUNK;
}
+#if defined(EWOULDBLOCK) && defined(EAGAIN) && EWOULDBLOCK != EAGAIN
+#define BLOCKED_ERRNO(x) ((x) == EWOULDBLOCK || (x) == EAGAIN)
+#else
+#ifdef EWOULDBLOCK
+#define BLOCKED_ERRNO(x) ((x) == EWOULDBLOCK)
+#else
+#ifdef EAGAIN
+#define BLOCKED_ERRNO(x) ((x) == EAGAIN)
+#else
+#define BLOCKED_ERRNO(x) 0
+#endif
+#endif
+#endif
+
static PyObject *
file_read(PyFileObject *f, PyObject *args)
{
@@ -774,18 +788,29 @@ file_read(PyFileObject *f, PyObject *args)
if (chunksize == 0) {
if (!ferror(f->f_fp))
break;
- PyErr_SetFromErrno(PyExc_IOError);
clearerr(f->f_fp);
+ /* When in non-blocking mode, data shouldn't
+ * be discarded if a blocking signal was
+ * received. That will also happen if
+ * chunksize != 0, but bytesread < buffersize. */
+ if (bytesread > 0 && BLOCKED_ERRNO(errno))
+ break;
+ PyErr_SetFromErrno(PyExc_IOError);
Py_DECREF(v);
return NULL;
}
bytesread += chunksize;
- if (bytesread < buffersize)
+ if (bytesread < buffersize) {
+ clearerr(f->f_fp);
break;
+ }
if (bytesrequested < 0) {
buffersize = new_buffersize(f, buffersize);
if (_PyString_Resize(&v, buffersize) < 0)
return NULL;
+ } else {
+ assert(bytesread == bytesrequested);
+ break;
}
}
if (bytesread != buffersize)
@@ -1518,7 +1543,9 @@ PyDoc_STRVAR(readline_doc,
PyDoc_STRVAR(read_doc,
"read([size]) -> read at most size bytes, returned as a string.\n"
"\n"
-"If the size argument is negative or omitted, read until EOF is reached.");
+"If the size argument is negative or omitted, read until EOF is reached.\n"
+"Notice that when in non-blocking mode, less data than what was requested\n"
+"may be returned, even if no size parameter was given.");
PyDoc_STRVAR(write_doc,
"write(str) -> None. Write string str to file.\n"