From 0bb62b12a3a13486c29092b38081391487119223 Mon Sep 17 00:00:00 2001 From: Martin Panter Date: Sun, 6 Dec 2015 03:15:05 +0000 Subject: Issue #25717: Tolerate fstat() failures in the FileIO constructor This restores 3.4 behaviour, which was removed by revision 3b5279b5bfd1. The fstat() call fails with ENOENT for a Virtual Box shared folder filesystem if the file entry has been unlinked, e.g. for a temporary file. --- Misc/NEWS | 4 ++++ Modules/_io/fileio.c | 39 +++++++++++++++++++++++++++------------ 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS index 4399da2..f868037 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -22,6 +22,10 @@ Core and Builtins Library ------- +- Issue #25717: Restore the previous behaviour of tolerating most fstat() + errors when opening files. This was a regression in 3.5a1, and stopped + anonymous temporary files from working in special cases. + - Issue #24903: Fix regression in number of arguments compileall accepts when '-d' is specified. The check on the number of arguments has been dropped completely as it never worked correctly anyway. diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 12e37bb..5f88d58 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -250,6 +250,7 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, int *atomic_flag_works = NULL; #endif struct _Py_stat_struct fdfstat; + int fstat_result; int async_err = 0; assert(PyFileIO_Check(self)); @@ -438,22 +439,36 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, } self->blksize = DEFAULT_BUFFER_SIZE; - if (_Py_fstat(self->fd, &fdfstat) < 0) - goto error; -#if defined(S_ISDIR) && defined(EISDIR) - /* On Unix, open will succeed for directories. - In Python, there should be no file objects referring to - directories, so we need a check. */ - if (S_ISDIR(fdfstat.st_mode)) { - errno = EISDIR; - PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj); - goto error; + Py_BEGIN_ALLOW_THREADS + fstat_result = _Py_fstat_noraise(self->fd, &fdfstat); + Py_END_ALLOW_THREADS + if (fstat_result < 0) { +#ifdef MS_WINDOWS + if (GetLastError() == ERROR_INVALID_HANDLE) { + PyErr_SetFromWindowsErr(0); +#else + if (errno == EBADF) { + PyErr_SetFromErrno(PyExc_OSError); +#endif + goto error; + } } + else { +#if defined(S_ISDIR) && defined(EISDIR) + /* On Unix, open will succeed for directories. + In Python, there should be no file objects referring to + directories, so we need a check. */ + if (S_ISDIR(fdfstat.st_mode)) { + errno = EISDIR; + PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj); + goto error; + } #endif /* defined(S_ISDIR) */ #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE - if (fdfstat.st_blksize > 1) - self->blksize = fdfstat.st_blksize; + if (fdfstat.st_blksize > 1) + self->blksize = fdfstat.st_blksize; #endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */ + } #if defined(MS_WINDOWS) || defined(__CYGWIN__) /* don't translate newlines (\r\n <=> \n) */ -- cgit v0.12