summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2017-05-02 13:10:39 (GMT)
committerGitHub <noreply@github.com>2017-05-02 13:10:39 (GMT)
commit999707373630ce090300c3c542066f493b12faa0 (patch)
tree1085aacebf78a2a85280c6c9934ecfd315f13fcf /Modules
parent1dae7450c68bad498e57800387b24cb103c461fa (diff)
downloadcpython-999707373630ce090300c3c542066f493b12faa0.zip
cpython-999707373630ce090300c3c542066f493b12faa0.tar.gz
cpython-999707373630ce090300c3c542066f493b12faa0.tar.bz2
bpo-30228: FileIO seek() and tell() set seekable (#1384)
FileIO.seek() and FileIO.tell() method now set the internal seekable attribute to avoid one syscall on open() (in buffered or text mode). The seekable property is now also more reliable since its value is set correctly on memory allocation failure.
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_io/fileio.c36
1 files changed, 21 insertions, 15 deletions
diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c
index 922db3e..a09c39f7 100644
--- a/Modules/_io/fileio.c
+++ b/Modules/_io/fileio.c
@@ -73,6 +73,9 @@ _Py_IDENTIFIER(name);
#define PyFileIO_Check(op) (PyObject_TypeCheck((op), &PyFileIO_Type))
+/* Forward declarations */
+static PyObject* portable_lseek(fileio *self, PyObject *posobj, int whence);
+
int
_PyFileIO_closed(PyObject *self)
{
@@ -98,11 +101,6 @@ fileio_dealloc_warn(fileio *self, PyObject *source)
Py_RETURN_NONE;
}
-static PyObject *
-portable_lseek(int fd, PyObject *posobj, int whence);
-
-static PyObject *portable_lseek(int fd, PyObject *posobj, int whence);
-
/* Returns 0 on success, -1 with exception set on failure. */
static int
internal_close(fileio *self)
@@ -478,7 +476,7 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode,
/* For consistent behaviour, we explicitly seek to the
end of file (otherwise, it might be done only on the
first write()). */
- PyObject *pos = portable_lseek(self->fd, NULL, 2);
+ PyObject *pos = portable_lseek(self, NULL, 2);
if (pos == NULL)
goto error;
Py_DECREF(pos);
@@ -600,13 +598,14 @@ _io_FileIO_seekable_impl(fileio *self)
if (self->fd < 0)
return err_closed();
if (self->seekable < 0) {
- PyObject *pos = portable_lseek(self->fd, NULL, SEEK_CUR);
+ /* portable_lseek() sets the seekable attribute */
+ PyObject *pos = portable_lseek(self, NULL, SEEK_CUR);
+ assert(self->seekable >= 0);
if (pos == NULL) {
PyErr_Clear();
- self->seekable = 0;
- } else {
+ }
+ else {
Py_DECREF(pos);
- self->seekable = 1;
}
}
return PyBool_FromLong((long) self->seekable);
@@ -865,9 +864,10 @@ _io_FileIO_write_impl(fileio *self, Py_buffer *b)
/* Cribbed from posix_lseek() */
static PyObject *
-portable_lseek(int fd, PyObject *posobj, int whence)
+portable_lseek(fileio *self, PyObject *posobj, int whence)
{
Py_off_t pos, res;
+ int fd = self->fd;
#ifdef SEEK_SET
/* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
@@ -884,8 +884,9 @@ portable_lseek(int fd, PyObject *posobj, int whence)
}
#endif /* SEEK_SET */
- if (posobj == NULL)
+ if (posobj == NULL) {
pos = 0;
+ }
else {
if(PyFloat_Check(posobj)) {
PyErr_SetString(PyExc_TypeError, "an integer is required");
@@ -909,6 +910,11 @@ portable_lseek(int fd, PyObject *posobj, int whence)
#endif
_Py_END_SUPPRESS_IPH
Py_END_ALLOW_THREADS
+
+ if (self->seekable < 0) {
+ self->seekable = (res >= 0);
+ }
+
if (res < 0)
return PyErr_SetFromErrno(PyExc_OSError);
@@ -943,7 +949,7 @@ _io_FileIO_seek_impl(fileio *self, PyObject *pos, int whence)
if (self->fd < 0)
return err_closed();
- return portable_lseek(self->fd, pos, whence);
+ return portable_lseek(self, pos, whence);
}
/*[clinic input]
@@ -961,7 +967,7 @@ _io_FileIO_tell_impl(fileio *self)
if (self->fd < 0)
return err_closed();
- return portable_lseek(self->fd, NULL, 1);
+ return portable_lseek(self, NULL, 1);
}
#ifdef HAVE_FTRUNCATE
@@ -992,7 +998,7 @@ _io_FileIO_truncate_impl(fileio *self, PyObject *posobj)
if (posobj == Py_None || posobj == NULL) {
/* Get the current position. */
- posobj = portable_lseek(fd, NULL, 1);
+ posobj = portable_lseek(self, NULL, 1);
if (posobj == NULL)
return NULL;
}