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.
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 @@
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 @@
}
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) */