dovecot-2.2: lib: o_stream_send_istream() shouldn't ignore EINTR...

dovecot at dovecot.org dovecot at dovecot.org
Thu Oct 9 15:15:35 UTC 2014


details:   http://hg.dovecot.org/dovecot-2.2/rev/00115d4930d4
changeset: 17922:00115d4930d4
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Oct 09 18:14:43 2014 +0300
description:
lib: o_stream_send_istream() shouldn't ignore EINTRs for file ostreams.
Also added extra asserts to make sure that either we return an error or we
write everything from input stream to output stream. This should make it
safe to write to files using just:

if (o_stream_send_istream(ostream, istream) < 0) {
  // failed
} else {
  // everything in istream was written to ostream
}

diffstat:

 src/lib/ostream-file.c |  46 +++++++++++++++++++++++++++++++++++++---------
 1 files changed, 37 insertions(+), 9 deletions(-)

diffs (90 lines):

diff -r 5e53b6d55f63 -r 00115d4930d4 src/lib/ostream-file.c
--- a/src/lib/ostream-file.c	Thu Oct 09 18:12:46 2014 +0300
+++ b/src/lib/ostream-file.c	Thu Oct 09 18:14:43 2014 +0300
@@ -173,10 +173,13 @@
 			       const struct const_iovec *iov, int iov_size)
 {
 	ssize_t ret, ret2;
-	size_t size, sent;
+	size_t size, sent, total_size;
 	bool partial;
 	int i;
 
+	for (i = 0, total_size = 0; i < iov_size; i++)
+		total_size += iov[i].iov_len;
+
 	o_stream_socket_cork(fstream);
 	if (iov_size == 1) {
 		i_assert(iov->iov_len > 0);
@@ -234,8 +237,15 @@
 	}
 
 	if (ret < 0) {
-		if (errno == EAGAIN || errno == EINTR)
+		if (fstream->file) {
+			if (errno == EINTR) {
+				/* automatically retry */
+				return o_stream_writev(fstream, iov, iov_size);
+			}
+		} else if (errno == EAGAIN || errno == EINTR) {
+			/* try again later */
 			return 0;
+		}
 		fstream->ostream.ostream.stream_errno = errno;
 		stream_closed(fstream);
 		return -1;
@@ -278,10 +288,14 @@
 				}
 			}
 		}
-		if (ret2 <= 0)
-			return ret2;
-		ret += ret2;
+		i_assert(ret2 != 0);
+		if (ret2 < 0)
+			ret = ret2;
+		else
+			ret += ret2;
 	}
+	i_assert(ret < 0 || !fstream->file ||
+		 (size_t)ret == total_size);
 	return ret;
 }
 
@@ -713,9 +727,18 @@
 		ret = safe_sendfile(foutstream->fd, in_fd, &offset,
 				    MAX_SSIZE_T(send_size));
 		if (ret <= 0) {
-			if (ret == 0 || errno == EINTR || errno == EAGAIN) {
-				ret = 0;
+			if (ret == 0)
 				break;
+			if (foutstream->file) {
+				if (errno == EINTR) {
+					/* automatically retry */
+					continue;
+				}
+			} else {
+				if (errno == EINTR || errno == EAGAIN) {
+					ret = 0;
+					break;
+				}
 			}
 
 			outstream->ostream.stream_errno = errno;
@@ -735,8 +758,13 @@
 
 	i_stream_seek(instream, v_offset);
 	if (ret == 0) {
-		/* we should be at EOF, verify it by reading instream */
-		(void)i_stream_read(instream);
+		/* we should be at EOF. if not, write more. */
+		i_assert(!foutstream->file ||
+			 instream->v_offset - start_offset == in_size);
+		if (i_stream_read(instream) > 0) {
+			if (io_stream_sendfile(outstream, instream, in_fd) < 0)
+				return -1;
+		}
 	}
 	return ret < 0 ? -1 : (off_t)(instream->v_offset - start_offset);
 }


More information about the dovecot-cvs mailing list