]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Bugfixes to handling >2GB files.
authorTimo Sirainen <tss@iki.fi>
Tue, 11 Feb 2003 16:37:47 +0000 (18:37 +0200)
committerTimo Sirainen <tss@iki.fi>
Tue, 11 Feb 2003 16:37:47 +0000 (18:37 +0200)
--HG--
branch : HEAD

src/lib/istream-mmap.c
src/lib/ostream-file.c
src/lib/sendfile-util.c
src/lib/sendfile-util.h

index 0196443cb95f949f77af96b9cd0b4781799942bf..c83195222cbf9dd3353e87facbba939ddc687d74 100644 (file)
@@ -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);
index 1f750588746b19c1709f19d2ff442e2912995e4b..92c1b6bda4b0961a829e5a036c88602cb2cd1770 100644 (file)
@@ -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;
        }
index 5988302ffc0d4f66007a66ad5c86e82bf121b63f..8a189ab80f020933d625f8aa1b221b8568b1d0ef 100644 (file)
@@ -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;
index df3d653fe0a14525ed683c5b0c7d86c3f57cdb6d..d73775e744345f2ea53a8690ca530f95496f1429 100644 (file)
@@ -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