From af81f402ddc897c74c1e85abd02879612ce44882 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Tue, 11 Feb 2003 18:37:47 +0200 Subject: [PATCH] Bugfixes to handling >2GB files. --HG-- branch : HEAD --- src/lib/istream-mmap.c | 14 ++++++------- src/lib/ostream-file.c | 45 +++++++++++++++++++++++------------------ src/lib/sendfile-util.c | 12 +++++++---- src/lib/sendfile-util.h | 4 +++- 4 files changed, 43 insertions(+), 32 deletions(-) diff --git a/src/lib/istream-mmap.c b/src/lib/istream-mmap.c index 0196443cb9..c83195222c 100644 --- a/src/lib/istream-mmap.c +++ b/src/lib/istream-mmap.c @@ -94,14 +94,14 @@ static void _set_blocking(struct _iostream *stream __attr_unused__, static ssize_t io_stream_set_mmaped_pos(struct _istream *stream) { struct mmap_istream *mstream = (struct mmap_istream *) stream; + uoff_t top; i_assert((uoff_t)mstream->mmap_offset <= stream->istream.start_offset + stream->istream.v_limit); - stream->pos = stream->istream.start_offset + stream->istream.v_limit - + top = stream->istream.start_offset + stream->istream.v_limit - mstream->mmap_offset; - if (stream->pos > stream->buffer_size) - stream->pos = stream->buffer_size; + stream->pos = I_MIN(top, stream->buffer_size); return stream->pos - stream->skip; } @@ -110,6 +110,7 @@ static ssize_t _read(struct _istream *stream) { struct mmap_istream *mstream = (struct mmap_istream *) stream; size_t aligned_skip, limit_size; + uoff_t top; if (stream->istream.start_offset + stream->istream.v_limit <= (uoff_t)mstream->mmap_offset + stream->pos) { @@ -137,10 +138,9 @@ static ssize_t _read(struct _istream *stream) i_error("io_stream_read_mmaped(): munmap() failed: %m"); } - stream->buffer_size = stream->istream.start_offset + - stream->istream.v_size - mstream->mmap_offset; - if (stream->buffer_size > mstream->mmap_block_size) - stream->buffer_size = mstream->mmap_block_size; + top = stream->istream.start_offset + stream->istream.v_size - + mstream->mmap_offset; + stream->buffer_size = I_MIN(top, mstream->mmap_block_size); i_assert((uoff_t)mstream->mmap_offset + stream->buffer_size <= stream->istream.start_offset + stream->istream.v_size); diff --git a/src/lib/ostream-file.c b/src/lib/ostream-file.c index 1f75058874..92c1b6bda4 100644 --- a/src/lib/ostream-file.c +++ b/src/lib/ostream-file.c @@ -203,7 +203,11 @@ o_stream_writev(struct file_ostream *fstream, struct iovec *iov, int iov_size) i_assert(iov_size > 0); - ret = writev(fstream->fd, iov, iov_size); + if (iov_size == 1) + ret = write(fstream->fd, iov->iov_base, iov->iov_len); + else + ret = writev(fstream->fd, iov, iov_size); + if (ret < 0) { if (errno == EAGAIN || errno == EINTR) return 0; @@ -501,13 +505,13 @@ static ssize_t _send(struct _ostream *stream, const void *data, size_t size) } } -static off_t io_stream_sendfile(struct _ostream *outstream, - struct istream *instream) +static int io_stream_sendfile(struct _ostream *outstream, + struct istream *instream) { struct file_ostream *foutstream = (struct file_ostream *) outstream; time_t timeout_time; uoff_t start_offset; - uoff_t offset, send_size; + uoff_t offset, send_size, v_offset; ssize_t ret; int in_fd, first; @@ -525,8 +529,10 @@ static off_t io_stream_sendfile(struct _ostream *outstream, if (buffer_flush(foutstream) < 0) return -1; + v_offset = instream->v_offset; + first = TRUE; - for (;;) { + do { if (first) first = FALSE; else if (timeout_time > 0 && time(NULL) > timeout_time) { @@ -536,11 +542,12 @@ static off_t io_stream_sendfile(struct _ostream *outstream, foutstream->timeout_context); } outstream->ostream.stream_errno = EAGAIN; - return -1; + ret = -1; + break; } - offset = instream->start_offset + instream->v_offset; - send_size = instream->v_limit - instream->v_offset; + offset = instream->start_offset + v_offset; + send_size = instream->v_limit - v_offset; ret = safe_sendfile(foutstream->fd, in_fd, &offset, MAX_SSIZE_T(send_size)); @@ -552,26 +559,22 @@ static off_t io_stream_sendfile(struct _ostream *outstream, sendfile() isn't supported */ stream_closed(foutstream); } - return -1; + break; } + ret = 0; if (!STREAM_IS_BLOCKING(foutstream)) { /* don't block */ break; } - ret = 0; } - i_stream_skip(instream, (size_t)ret); + v_offset += ret; outstream->ostream.offset += ret; + } while ((uoff_t)ret != send_size); - if ((uoff_t)ret == send_size) { - /* yes, all sent */ - break; - } - } - - return (off_t) (instream->v_offset - start_offset); + i_stream_seek(instream, instream->start_offset + v_offset); + return ret < 0 ? -1 : 0; } static off_t io_stream_copy(struct _ostream *outstream, @@ -605,7 +608,7 @@ static off_t io_stream_copy(struct _ostream *outstream, iov[pos].iov_len = size; ret = o_stream_writev(foutstream, iov, iov_len); - if (ret < 0) { + if (ret < 0) { /* error */ return -1; } @@ -648,6 +651,8 @@ static off_t _send_istream(struct _ostream *outstream, struct istream *instream) i_assert(instream->v_limit <= OFF_T_MAX); i_assert(instream->v_offset <= instream->v_limit); + outstream->ostream.stream_errno = 0; + if (instream->v_offset == instream->v_limit) return 0; @@ -657,7 +662,7 @@ static off_t _send_istream(struct _ostream *outstream, struct istream *instream) return ret; /* sendfile() not supported (with this fd), fallback to - regular sending */ + regular sending. */ outstream->ostream.stream_errno = 0; foutstream->no_sendfile = TRUE; } diff --git a/src/lib/sendfile-util.c b/src/lib/sendfile-util.c index 5988302ffc..8a189ab80f 100644 --- a/src/lib/sendfile-util.c +++ b/src/lib/sendfile-util.c @@ -23,19 +23,23 @@ ssize_t safe_sendfile(int out_fd, int in_fd, uoff_t *offset, size_t count) /* make sure given offset fits into off_t */ if (sizeof(off_t) * CHAR_BIT == 32) { /* 32bit off_t */ - if (*offset > 2147483647L) { - errno = EOVERFLOW; + if (*offset >= 2147483647L) { + errno = EINVAL; return -1; } + if (count > 2147483647L - *offset) + count = 2147483647L - *offset; } else { /* they're most likely the same size. if not, fix this code later */ i_assert(sizeof(off_t) == sizeof(uoff_t)); - if (*offset > OFF_T_MAX) { - errno = EOVERFLOW; + if (*offset >= OFF_T_MAX) { + errno = EINVAL; return -1; } + if (count > OFF_T_MAX - *offset) + count = OFF_T_MAX - *offset; } safe_offset = (off_t)*offset; diff --git a/src/lib/sendfile-util.h b/src/lib/sendfile-util.h index df3d653fe0..d73775e744 100644 --- a/src/lib/sendfile-util.h +++ b/src/lib/sendfile-util.h @@ -1,7 +1,9 @@ #ifndef __SENDFILE_UTIL_H #define __SENDFILE_UTIL_H -/* simple wrapper for sendfile(), allowing usage of 64bit off_t with it */ +/* Wrapper for various sendfile()-like calls. Returns -1 and errno=EINVAL if + it isn't supported for some reason (out_fd isn't a socket, offset is too + large, or there simply is no sendfile()). */ ssize_t safe_sendfile(int out_fd, int in_fd, uoff_t *offset, size_t count); #endif -- 2.47.3