diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 4a71a57ec0d..2b40ada195a 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -146,9 +146,15 @@ dircheck(fileio* self, PyObject *nameobj) { #if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR) struct stat buf; + int res; if (self->fd < 0) return 0; - if (fstat(self->fd, &buf) == 0 && S_ISDIR(buf.st_mode)) { + + Py_BEGIN_ALLOW_THREADS + res = fstat(self->fd, &buf); + Py_END_ALLOW_THREADS + + if (res == 0 && S_ISDIR(buf.st_mode)) { errno = EISDIR; PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj); return -1; @@ -162,17 +168,34 @@ check_fd(int fd) { #if defined(HAVE_FSTAT) struct stat buf; - if (!_PyVerify_fd(fd) || (fstat(fd, &buf) < 0 && errno == EBADF)) { - PyObject *exc; - char *msg = strerror(EBADF); - exc = PyObject_CallFunction(PyExc_OSError, "(is)", - EBADF, msg); - PyErr_SetObject(PyExc_OSError, exc); - Py_XDECREF(exc); - return -1; + int res; + PyObject *exc; + char *msg; + + if (!_PyVerify_fd(fd)) { + goto badfd; } -#endif + + Py_BEGIN_ALLOW_THREADS + res = fstat(fd, &buf); + Py_END_ALLOW_THREADS + + if (res < 0 && errno == EBADF) { + goto badfd; + } + return 0; + +badfd: + msg = strerror(EBADF); + exc = PyObject_CallFunction(PyExc_OSError, "(is)", + EBADF, msg); + PyErr_SetObject(PyExc_OSError, exc); + Py_XDECREF(exc); + return -1; +#else + return 0; +#endif } @@ -519,9 +542,19 @@ new_buffersize(fileio *self, size_t currentsize) #ifdef HAVE_FSTAT off_t pos, end; struct stat st; - if (fstat(self->fd, &st) == 0) { + int res; + + Py_BEGIN_ALLOW_THREADS + res = fstat(self->fd, &st); + Py_END_ALLOW_THREADS + + if (res == 0) { end = st.st_size; + + Py_BEGIN_ALLOW_THREADS pos = lseek(self->fd, 0L, SEEK_CUR); + Py_END_ALLOW_THREADS + /* Files claiming a size smaller than SMALLCHUNK may actually be streaming pseudo-files. In this case, we apply the more aggressive algorithm below. diff --git a/Objects/fileobject.c b/Objects/fileobject.c index 2f63c374d1e..8d1c5812f0d 100644 --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -121,10 +121,15 @@ dircheck(PyFileObject* f) { #if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR) struct stat buf; + int res; if (f->f_fp == NULL) return f; - if (fstat(fileno(f->f_fp), &buf) == 0 && - S_ISDIR(buf.st_mode)) { + + Py_BEGIN_ALLOW_THREADS + res = fstat(fileno(f->f_fp), &buf); + Py_END_ALLOW_THREADS + + if (res == 0 && S_ISDIR(buf.st_mode)) { char *msg = strerror(EISDIR); PyObject *exc = PyObject_CallFunction(PyExc_IOError, "(isO)", EISDIR, msg, f->f_name); @@ -1010,7 +1015,13 @@ new_buffersize(PyFileObject *f, size_t currentsize) #ifdef HAVE_FSTAT off_t pos, end; struct stat st; - if (fstat(fileno(f->f_fp), &st) == 0) { + int res; + + Py_BEGIN_ALLOW_THREADS + res = fstat(fileno(f->f_fp), &st); + Py_END_ALLOW_THREADS + + if (res == 0) { end = st.st_size; /* The following is not a bug: we really need to call lseek() *and* ftell(). The reason is that some stdio libraries @@ -1021,7 +1032,11 @@ new_buffersize(PyFileObject *f, size_t currentsize) works. We can't use the lseek() value either, because we need to take the amount of buffered data into account. (Yet another reason why stdio stinks. :-) */ + + Py_BEGIN_ALLOW_THREADS pos = lseek(fileno(f->f_fp), 0L, SEEK_CUR); + Py_END_ALLOW_THREADS + if (pos >= 0) { pos = ftell(f->f_fp); }