changeset 20799:a46ba877e377

lib: Fixed ostream-failure-at with blocking parent stream. Blocking ostream returns either a full success or a full failure. It can't return that only n/m bytes were written. Fixes assert: Panic: file ostream.c: line 255 (o_stream_sendv_int): assertion failed: (!stream->blocking)
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Wed, 21 Sep 2016 13:47:05 +0300
parents 2260cbf542c2
children c2bbdca09f56
files src/lib/ostream-failure-at.c
diffstat 1 files changed, 15 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib/ostream-failure-at.c	Mon Sep 19 11:08:08 2016 +0300
+++ b/src/lib/ostream-failure-at.c	Wed Sep 21 13:47:05 2016 +0300
@@ -30,10 +30,23 @@
 	unsigned int i;
 	struct const_iovec *iov_dup;
 	unsigned int iov_dup_count;
-	uoff_t bytes_until_failure;
+	uoff_t bytes_until_failure, blocking_bytes_count = 0;
 	ssize_t ret;
 
-	if (fstream->failure_offset <= stream->ostream.offset) {
+	if (stream->ostream.blocking) {
+		/* blocking ostream must return either a full success or a
+		   failure. if the current write would go past failure_offset,
+		   return a failure now before writing anything. */
+		for (i = 0; i < iov_count; i++)
+			blocking_bytes_count += iov[i].iov_len;
+		if (blocking_bytes_count > 0) {
+			/* if we're exactly at the failure offset after this
+			   write, fail it only on the next write. */
+			blocking_bytes_count--;
+		}
+	}
+
+	if (fstream->failure_offset <= stream->ostream.offset + blocking_bytes_count) {
 		io_stream_set_error(&stream->iostream, "%s",
 				    fstream->error_string);
 		stream->ostream.stream_errno = errno = EIO;