# HG changeset patch # Parent bb8093e427f9c3fe0bec382c8178c99594d9f988 diff -r bb8093e427f9 Modules/_io/fileio.c --- a/Modules/_io/fileio.c Tue May 14 22:32:34 2013 -0500 +++ b/Modules/_io/fileio.c Thu May 16 16:10:03 2013 +0100 @@ -556,30 +556,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. */ @@ -596,25 +603,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; Py_ssize_t 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 @@ -624,44 +624,37 @@ end = st.st_size; else end = (Py_off_t)-1; -#endif + + 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 = newsize - total; + n = size - total; #if defined(MS_WIN64) || defined(MS_WINDOWS) if (n > INT_MAX) n = INT_MAX; - n = read(self->fd, - PyBytes_AS_STRING(result) + total, - (int)n); + n = read(self->fd, PyBytes_AS_STRING(result) + total, (int)n); #else - n = read(self->fd, - PyBytes_AS_STRING(result) + total, - n); + n = read(self->fd, PyBytes_AS_STRING(result) + total, n); #endif Py_END_ALLOW_THREADS if (n == 0) @@ -685,20 +678,17 @@ return NULL; } total += n; -#ifdef HAVE_FSTAT pos += n; -#endif } if (PyBytes_GET_SIZE(result) > total) { if (_PyBytes_Resize(&result, total) < 0) { - /* This should never happen, but just in case */ - Py_DECREF(result); return NULL; } } return result; } +#endif /* HAVE_FSTAT */ static PyObject * fileio_read(fileio *self, PyObject *args)