diff options
Diffstat (limited to 'file_io/win32/readwrite.c')
-rw-r--r-- | file_io/win32/readwrite.c | 80 |
1 files changed, 57 insertions, 23 deletions
diff --git a/file_io/win32/readwrite.c b/file_io/win32/readwrite.c index b13b230e9..027ef988d 100644 --- a/file_io/win32/readwrite.c +++ b/file_io/win32/readwrite.c @@ -145,8 +145,9 @@ static apr_status_t read_buffered(apr_file_t *thefile, void *buf, apr_size_t *le { apr_status_t rv; char *pos = (char *)buf; - apr_size_t blocksize; - apr_size_t size = *len; + apr_size_t bytes_read; + apr_size_t size; + apr_size_t remaining = *len; if (thefile->direction == 1) { rv = apr_file_flush(thefile); @@ -158,29 +159,62 @@ static apr_status_t read_buffered(apr_file_t *thefile, void *buf, apr_size_t *le thefile->dataRead = 0; } - rv = 0; - while (rv == 0 && size > 0) { - if (thefile->bufpos >= thefile->dataRead) { - apr_size_t read; - rv = read_with_timeout(thefile, thefile->buffer, - thefile->bufsize, &read); - if (read == 0) { - if (rv == APR_EOF) - thefile->eof_hit = TRUE; - break; - } - else { - thefile->dataRead = read; - thefile->filePtr += thefile->dataRead; - thefile->bufpos = 0; - } + /* Copy the data we have in the buffer. */ + size = thefile->dataRead - thefile->bufpos; + if (size > remaining) { + size = remaining; + } + memcpy(pos, thefile->buffer + thefile->bufpos, size); + pos += size; + remaining -= size; + thefile->bufpos += size; + + if (remaining == 0) { + /* Nothing to do more, keep *LEN unchanged and return. */ + return APR_SUCCESS; + } + /* The buffer is empty, but the caller wants more. + * Decide on the most appropriate way to read from the file: + */ + if (remaining > thefile->bufsize) { + /* If the remaining chunk won't fit into the buffer, read it into + * the destination buffer with a single syscall. + */ + rv = read_with_timeout(thefile, pos, remaining, &bytes_read); + thefile->filePtr += bytes_read; + pos += bytes_read; + /* Also, copy the last BUFSIZE (or less in case of a short read) bytes + * from the chunk to our buffer so that seeking backwards and reading + * would work from the buffer. + */ + size = thefile->bufsize; + if (size > bytes_read) { + size = bytes_read; } + memcpy(thefile->buffer, pos - size, size); + thefile->bufpos = size; + thefile->dataRead = size; + } + else { + /* The remaining chunk fits into the buffer. Read up to BUFSIZE bytes + * from the file to our internal buffer. + */ + rv = read_with_timeout(thefile, thefile->buffer, thefile->bufsize, &bytes_read); + thefile->filePtr += bytes_read; + thefile->bufpos = 0; + thefile->dataRead = bytes_read; + /* Copy the required part to the caller. */ + size = remaining; + if (size > bytes_read) { + size = bytes_read; + } + memcpy(pos, thefile->buffer, size); + pos += size; + thefile->bufpos += size; + } - blocksize = size > thefile->dataRead - thefile->bufpos ? thefile->dataRead - thefile->bufpos : size; - memcpy(pos, thefile->buffer + thefile->bufpos, blocksize); - thefile->bufpos += blocksize; - pos += blocksize; - size -= blocksize; + if (bytes_read == 0 && rv == APR_EOF) { + thefile->eof_hit = TRUE; } *len = pos - (char *)buf; |