# HG changeset patch # Parent ca54c27a9045c655ef1ad9ce248f02eb00137476 diff -r ca54c27a9045 Modules/_io/fileio.c --- a/Modules/_io/fileio.c Tue Aug 21 14:54:22 2012 +0100 +++ b/Modules/_io/fileio.c Thu Aug 23 14:59:40 2012 +0100 @@ -561,30 +561,37 @@ return PyLong_FromSsize_t(n); } +#ifndef HAVE_FSTAT + +static PyObject * +fileio_readall(fileio *self) +{ + _Py_IDENTIFIER(readall); + return _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type, + &PyId_readall, "O", self); +} + +#else + static size_t -new_buffersize(fileio *self, size_t currentsize -#ifdef HAVE_FSTAT - , Py_off_t pos, Py_off_t end -#endif - ) +new_buffersize(fileio *self, size_t currentsize, Py_off_t pos, Py_off_t end) { size_t addend; -#ifdef HAVE_FSTAT - if (end != (Py_off_t)-1) { - /* Files claiming a size smaller than SMALLCHUNK may - actually be streaming pseudo-files. In this case, we - apply the more aggressive algorithm below. - */ - if (end >= SMALLCHUNK && end >= pos && pos >= 0) { - /* Add 1 so if the file were to grow we'd notice. */ - Py_off_t bufsize = currentsize + end - pos + 1; - if (bufsize < PY_SSIZE_T_MAX) - return (size_t)bufsize; - else - return PY_SSIZE_T_MAX; - } + + if (end > 0 && end >= pos && pos >= 0 && currentsize == 0) { + /* This is probably a real file, so we try to allocate a + buffer one byte larger than the rest of the file. If the + calculation is right then we should get EOF without having + to enlarge the buffer. If we are wrong then it will at + worst cost one small read before we apply the more + aggressive algorithm below. */ + Py_off_t bufsize = end - pos + 1; + if (bufsize < PY_SSIZE_T_MAX) + return (size_t)bufsize; + else + return PY_SSIZE_T_MAX; } -#endif + /* Expand the buffer by an amount proportional to the current size, giving us amortized linear-time behavior. For bigger sizes, use a less-than-double growth factor to avoid excessive allocation. */ @@ -601,25 +608,18 @@ static PyObject * fileio_readall(fileio *self) { -#ifdef HAVE_FSTAT struct stat st; Py_off_t pos, end; -#endif PyObject *result; Py_ssize_t total = 0; int n; - size_t newsize; + size_t size; if (self->fd < 0) return err_closed(); if (!_PyVerify_fd(self->fd)) return PyErr_SetFromErrno(PyExc_IOError); - result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK); - if (result == NULL) - return NULL; - -#ifdef HAVE_FSTAT #if defined(MS_WIN64) || defined(MS_WINDOWS) pos = _lseeki64(self->fd, 0L, SEEK_CUR); #else @@ -629,36 +629,42 @@ end = st.st_size; else end = (Py_off_t)-1; -#endif + + if (pos < 0 || end <= 0 || end < pos) { + /* We can't calculate the buffer size needed, so fall back to + reading in chunks. Note that pos == 0 and end == 0 might + mean a streaming pseudo-file. */ + _Py_IDENTIFIER(readall); + return _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type, + &PyId_readall, "O", self); + } + + size = new_buffersize(self, total, pos, end); + result = PyBytes_FromStringAndSize(NULL, size); + if (result == NULL) + return NULL; + while (1) { -#ifdef HAVE_FSTAT - newsize = new_buffersize(self, total, pos, end); -#else - newsize = new_buffersize(self, total); -#endif - if (newsize > PY_SSIZE_T_MAX || newsize <= 0) { - PyErr_SetString(PyExc_OverflowError, - "unbounded read returned more bytes " - "than a Python string can hold "); - Py_DECREF(result); - return NULL; - } + if (total >= (Py_ssize_t)size) { + size = new_buffersize(self, total, -1, -1); + if (size > PY_SSIZE_T_MAX || size <= 0) { + PyErr_SetString(PyExc_OverflowError, + "unbounded read returned more bytes " + "than a Python string can hold "); + Py_DECREF(result); + return NULL; + } - if (PyBytes_GET_SIZE(result) < (Py_ssize_t)newsize) { - if (_PyBytes_Resize(&result, newsize) < 0) { - if (total == 0) { - Py_DECREF(result); + if (PyBytes_GET_SIZE(result) < (Py_ssize_t)size) { + if (_PyBytes_Resize(&result, size) < 0) return NULL; - } - PyErr_Clear(); - break; } } Py_BEGIN_ALLOW_THREADS errno = 0; n = read(self->fd, PyBytes_AS_STRING(result) + total, - newsize - total); + size - total); Py_END_ALLOW_THREADS if (n == 0) break; @@ -681,9 +687,7 @@ return NULL; } total += n; -#ifdef HAVE_FSTAT pos += n; -#endif } if (PyBytes_GET_SIZE(result) > total) { @@ -695,6 +699,7 @@ } return result; } +#endif /* HAVE_FSTAT */ static PyObject * fileio_read(fileio *self, PyObject *args)