changeset 17922:00115d4930d4

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 }
author Timo Sirainen <tss@iki.fi>
date Thu, 09 Oct 2014 18:14:43 +0300
parents 5e53b6d55f63
children 568f817804b3
files src/lib/ostream-file.c
diffstat 1 files changed, 37 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- 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);
 }