changeset 16773:76d5e3c8cec3

iostreams: Set stream error string when it provides extra information.
author Timo Sirainen <tss@iki.fi>
date Fri, 20 Sep 2013 00:12:45 +0300
parents e35be66003e2
children 28df180ec3ab
files src/lib-compression/istream-bzlib.c src/lib-compression/istream-zlib.c src/lib-fs/istream-metawrap.c src/lib-mail/istream-dot.c src/lib-mail/istream-qp-decoder.c src/lib-ssl-iostream/iostream-openssl.c src/lib-ssl-iostream/iostream-openssl.h src/lib-ssl-iostream/istream-openssl.c src/lib-ssl-iostream/ostream-openssl.c src/lib-storage/index/istream-mail.c src/lib-storage/index/mbox/istream-raw-mbox.c src/lib/istream-base64-decoder.c src/lib/istream-concat.c src/lib/istream-file.c src/lib/istream-hash.c src/lib/istream-jsonstr.c src/lib/istream-mmap.c src/lib/istream-sized.c src/lib/ostream-file.c
diffstat 19 files changed, 138 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-compression/istream-bzlib.c	Fri Sep 20 00:00:49 2013 +0300
+++ b/src/lib-compression/istream-bzlib.c	Fri Sep 20 00:12:45 2013 +0300
@@ -38,10 +38,13 @@
 
 static void bzlib_read_error(struct bzlib_istream *zstream, const char *error)
 {
-	i_error("bzlib.read(%s): %s at %"PRIuUOFF_T,
-		i_stream_get_name(&zstream->istream.istream), error,
-		zstream->istream.abs_start_offset +
-		zstream->istream.istream.v_offset);
+	io_stream_set_error(&zstream->istream.iostream,
+			    "bzlib.read(%s): %s at %"PRIuUOFF_T,
+			    i_stream_get_name(&zstream->istream.istream), error,
+			    zstream->istream.abs_start_offset +
+			    zstream->istream.istream.v_offset);
+	if (zstream->log_errors)
+		i_error("%s", zstream->istream.iostream.error);
 }
 
 static ssize_t i_stream_bzlib_read(struct istream_private *stream)
@@ -104,8 +107,7 @@
 				stream->parent->stream_errno;
 		} else {
 			i_assert(stream->parent->eof);
-			if (zstream->log_errors)
-				bzlib_read_error(zstream, "unexpected EOF");
+			bzlib_read_error(zstream, "unexpected EOF");
 			stream->istream.stream_errno = EINVAL;
 		}
 		return -1;
@@ -135,15 +137,12 @@
 	case BZ_PARAM_ERROR:
 		i_unreached();
 	case BZ_DATA_ERROR:
-		if (zstream->log_errors)
-			bzlib_read_error(zstream, "corrupted data");
+		bzlib_read_error(zstream, "corrupted data");
 		stream->istream.stream_errno = EINVAL;
 		return -1;
 	case BZ_DATA_ERROR_MAGIC:
-		if (zstream->log_errors) {
-			bzlib_read_error(zstream,
-				"wrong magic in header (not bz2 file?)");
-		}
+		bzlib_read_error(zstream,
+			"wrong magic in header (not bz2 file?)");
 		stream->istream.stream_errno = EINVAL;
 		return -1;
 	case BZ_MEM_ERROR:
--- a/src/lib-compression/istream-zlib.c	Fri Sep 20 00:00:49 2013 +0300
+++ b/src/lib-compression/istream-zlib.c	Fri Sep 20 00:12:45 2013 +0300
@@ -55,10 +55,13 @@
 
 static void zlib_read_error(struct zlib_istream *zstream, const char *error)
 {
-	i_error("zlib.read(%s): %s at %"PRIuUOFF_T,
-		i_stream_get_name(&zstream->istream.istream), error,
-		zstream->istream.abs_start_offset +
-		zstream->istream.istream.v_offset);
+	io_stream_set_error(&zstream->istream.iostream,
+			    "zlib.read(%s): %s at %"PRIuUOFF_T,
+			    i_stream_get_name(&zstream->istream.istream), error,
+			    zstream->istream.abs_start_offset +
+			    zstream->istream.istream.v_offset);
+	if (zstream->log_errors)
+		i_error("%s", zstream->istream.iostream.error);
 }
 
 static int i_stream_zlib_read_header(struct istream_private *stream)
@@ -73,8 +76,7 @@
 				 zstream->prev_size);
 	if (size == zstream->prev_size) {
 		if (ret == -1) {
-			if (zstream->log_errors)
-				zlib_read_error(zstream, "missing gz header");
+			zlib_read_error(zstream, "missing gz header");
 			stream->istream.stream_errno = EINVAL;
 		}
 		return ret;
@@ -87,10 +89,7 @@
 
 	if (data[0] != GZ_MAGIC1 || data[1] != GZ_MAGIC2) {
 		/* missing gzip magic header */
-		if (zstream->log_errors) {
-			zlib_read_error(zstream, "wrong magic in header "
-					"(not gz file?)");
-		}
+		zlib_read_error(zstream, "wrong magic in header (not gz file?)");
 		stream->istream.stream_errno = EINVAL;
 		return -1;
 	}
@@ -143,8 +142,7 @@
 				 GZ_TRAILER_SIZE-1);
 	if (size == zstream->prev_size) {
 		if (ret == -1) {
-			if (zstream->log_errors)
-				zlib_read_error(zstream, "missing gz trailer");
+			zlib_read_error(zstream, "missing gz trailer");
 			stream->istream.stream_errno = EINVAL;
 		}
 		return ret;
@@ -155,10 +153,7 @@
 		return 0;
 
 	if (data_get_uint32(data) != zstream->crc32) {
-		if (zstream->log_errors) {
-			zlib_read_error(zstream,
-					"gz trailer has wrong CRC value");
-		}
+		zlib_read_error(zstream, "gz trailer has wrong CRC value");
 		stream->istream.stream_errno = EINVAL;
 		return -1;
 	}
@@ -254,8 +249,7 @@
 				stream->parent->stream_errno;
 		} else {
 			i_assert(stream->parent->eof);
-			if (zstream->log_errors)
-				zlib_read_error(zstream, "unexpected EOF");
+			zlib_read_error(zstream, "unexpected EOF");
 			stream->istream.stream_errno = EPIPE;
 		}
 		return -1;
@@ -286,13 +280,11 @@
 	case Z_OK:
 		break;
 	case Z_NEED_DICT:
-		if (zstream->log_errors)
-			zlib_read_error(zstream, "can't read file without dict");
+		zlib_read_error(zstream, "can't read file without dict");
 		stream->istream.stream_errno = EINVAL;
 		return -1;
 	case Z_DATA_ERROR:
-		if (zstream->log_errors)
-			zlib_read_error(zstream, "corrupted data");
+		zlib_read_error(zstream, "corrupted data");
 		stream->istream.stream_errno = EINVAL;
 		return -1;
 	case Z_MEM_ERROR:
--- a/src/lib-fs/istream-metawrap.c	Fri Sep 20 00:00:49 2013 +0300
+++ b/src/lib-fs/istream-metawrap.c	Fri Sep 20 00:12:45 2013 +0300
@@ -24,6 +24,8 @@
 		}
 		p = strchr(line, ':');
 		if (p == NULL) {
+			io_stream_set_error(&mstream->istream.iostream,
+				"Metadata header line is missing ':'");
 			mstream->istream.istream.stream_errno = EINVAL;
 			return -1;
 		}
--- a/src/lib-mail/istream-dot.c	Fri Sep 20 00:00:49 2013 +0300
+++ b/src/lib-mail/istream-dot.c	Fri Sep 20 00:12:45 2013 +0300
@@ -36,6 +36,8 @@
 					stream->parent->stream_errno;
 			} else if (ret < 0 && stream->parent->eof) {
 				/* we didn't see "." line */
+				io_stream_set_error(&stream->iostream,
+					"dot-input stream ends without '.' line");
 				stream->istream.stream_errno = EPIPE;
 			}
 			return ret;
--- a/src/lib-mail/istream-qp-decoder.c	Fri Sep 20 00:00:49 2013 +0300
+++ b/src/lib-mail/istream-qp-decoder.c	Fri Sep 20 00:12:45 2013 +0300
@@ -2,6 +2,7 @@
 
 #include "lib.h"
 #include "buffer.h"
+#include "hex-binary.h"
 #include "istream-private.h"
 #include "quoted-printable.h"
 #include "istream-qp.h"
@@ -64,6 +65,9 @@
 	ret = !eof ? quoted_printable_decode(data, size, &pos, &buf) :
 		quoted_printable_decode_final(data, size, &pos, &buf);
 	if (ret < 0) {
+		io_stream_set_error(&stream->iostream,
+			"Invalid quoted-printable data: 0x%s",
+			binary_to_hex(data+pos, I_MAX(size-pos, 8)));
 		stream->istream.stream_errno = EINVAL;
 		return -1;
 	}
@@ -77,7 +81,8 @@
 {
 	struct qp_decoder_istream *bstream =
 		(struct qp_decoder_istream *)stream;
-	size_t pre_count, post_count;
+	const unsigned char *data;
+	size_t pre_count, post_count, size;
 	int ret;
 	size_t prev_size = 0;
 
@@ -95,6 +100,10 @@
 			}
 			/* partial qp input */
 			i_assert(ret < 0);
+			data = i_stream_get_data(stream->parent, &size);
+			io_stream_set_error(&stream->iostream,
+				"quoted-printable input ends with a partial block: 0x%s",
+				binary_to_hex(data, size));
 			stream->istream.stream_errno = EINVAL;
 			return -1;
 		}
--- a/src/lib-ssl-iostream/iostream-openssl.c	Fri Sep 20 00:00:49 2013 +0300
+++ b/src/lib-ssl-iostream/iostream-openssl.c	Fri Sep 20 00:12:45 2013 +0300
@@ -270,6 +270,7 @@
 	o_stream_unref(&ssl_io->plain_output);
 	BIO_free(ssl_io->bio_ext);
 	SSL_free(ssl_io->ssl);
+	i_free(ssl_io->plain_stream_errstr);
 	i_free(ssl_io->last_error);
 	i_free(ssl_io->host);
 	i_free(ssl_io->log_prefix);
@@ -331,6 +332,9 @@
 		if (sent < 0) {
 			i_assert(ssl_io->plain_output->closed ||
 				 ssl_io->plain_output->stream_errno != 0);
+			i_free(ssl_io->plain_stream_errstr);
+			ssl_io->plain_stream_errstr =
+				i_strdup(o_stream_get_error(ssl_io->plain_output));
 			ssl_io->plain_stream_errno =
 				ssl_io->plain_output->stream_errno;
 			ssl_io->closed = TRUE;
@@ -376,6 +380,9 @@
 		ret = openssl_iostream_read_more(ssl_io, &data, &size);
 		ssl_io->plain_input->real_stream->try_alloc_limit = 0;
 		if (ret == -1 && size == 0 && !bytes_read) {
+			i_free(ssl_io->plain_stream_errstr);
+			ssl_io->plain_stream_errstr =
+				i_strdup(i_stream_get_error(ssl_io->plain_input));
 			ssl_io->plain_stream_errno =
 				ssl_io->plain_input->stream_errno;
 			ssl_io->closed = TRUE;
@@ -397,12 +404,18 @@
 	if (bytes == 0 && !bytes_read && ssl_io->want_read) {
 		/* shouldn't happen */
 		i_error("SSL BIO buffer size too small");
+		i_free(ssl_io->plain_stream_errstr);
+		ssl_io->plain_stream_errstr =
+			i_strdup("SSL BIO buffer size too small");
 		ssl_io->plain_stream_errno = EINVAL;
 		ssl_io->closed = TRUE;
 		return FALSE;
 	}
 	if (i_stream_get_data_size(ssl_io->plain_input) > 0) {
 		i_error("SSL: Too much data in buffered plain input buffer");
+		i_free(ssl_io->plain_stream_errstr);
+		ssl_io->plain_stream_errstr =
+			i_strdup("SSL: Too much data in buffered plain input buffer");
 		ssl_io->plain_stream_errno = EINVAL;
 		ssl_io->closed = TRUE;
 		return FALSE;
@@ -455,6 +468,8 @@
 			return 0;
 		}
 		if (ssl_io->closed) {
+			if (ssl_io->plain_stream_errstr != NULL)
+				openssl_iostream_set_error(ssl_io, ssl_io->plain_stream_errstr);
 			errno = ssl_io->plain_stream_errno != 0 ?
 				ssl_io->plain_stream_errno : EPIPE;
 			return -1;
@@ -464,6 +479,8 @@
 		ssl_io->want_read = TRUE;
 		(void)openssl_iostream_bio_sync(ssl_io);
 		if (ssl_io->closed) {
+			if (ssl_io->plain_stream_errstr != NULL)
+				openssl_iostream_set_error(ssl_io, ssl_io->plain_stream_errstr);
 			errno = ssl_io->plain_stream_errno != 0 ?
 				ssl_io->plain_stream_errno : EPIPE;
 			return -1;
@@ -489,7 +506,8 @@
 	case SSL_ERROR_ZERO_RETURN:
 		/* clean connection closing */
 		errno = ECONNRESET;
-		break;
+		i_free_and_null(ssl_io->last_error);
+		return -1;
 	case SSL_ERROR_SSL:
 		errstr = t_strdup_printf("%s failed: %s",
 					 func_name, openssl_iostream_error());
@@ -503,8 +521,7 @@
 		break;
 	}
 
-	if (errstr != NULL)
-		openssl_iostream_set_error(ssl_io, errstr);
+	openssl_iostream_set_error(ssl_io, errstr);
 	return -1;
 }
 
--- a/src/lib-ssl-iostream/iostream-openssl.h	Fri Sep 20 00:00:49 2013 +0300
+++ b/src/lib-ssl-iostream/iostream-openssl.h	Fri Sep 20 00:12:45 2013 +0300
@@ -31,6 +31,7 @@
 	char *host;
 	char *last_error;
 	char *log_prefix;
+	char *plain_stream_errstr;
 	int plain_stream_errno;
 
 	/* copied settings */
--- a/src/lib-ssl-iostream/istream-openssl.c	Fri Sep 20 00:00:49 2013 +0300
+++ b/src/lib-ssl-iostream/istream-openssl.c	Fri Sep 20 00:12:45 2013 +0300
@@ -52,6 +52,8 @@
 		if (ret < 0) {
 			/* handshake failed */
 			i_assert(errno != 0);
+			io_stream_set_error(&stream->iostream,
+					    "%s", ssl_io->last_error);
 			stream->istream.stream_errno = errno;
 		}
 		return ret;
@@ -70,6 +72,8 @@
 		ret = openssl_iostream_handle_error(ssl_io, ret, "SSL_read");
 		if (ret <= 0) {
 			if (ret < 0) {
+				io_stream_set_error(&stream->iostream,
+						    "%s", ssl_io->last_error);
 				stream->istream.stream_errno = errno;
 				stream->istream.eof = TRUE;
 				sstream->seen_eof = TRUE;
--- a/src/lib-ssl-iostream/ostream-openssl.c	Fri Sep 20 00:00:49 2013 +0300
+++ b/src/lib-ssl-iostream/ostream-openssl.c	Fri Sep 20 00:12:45 2013 +0300
@@ -98,6 +98,8 @@
 			ret = openssl_iostream_handle_write_error(sstream->ssl_io,
 								  ret, "SSL_write");
 			if (ret < 0) {
+				io_stream_set_error(&sstream->ostream.iostream,
+					"%s", sstream->ssl_io->last_error);
 				sstream->ostream.ostream.stream_errno = errno;
 				break;
 			}
@@ -119,6 +121,8 @@
 
 	if ((ret = openssl_iostream_more(sstream->ssl_io)) < 0) {
 		/* handshake failed */
+		io_stream_set_error(&stream->iostream, "%s",
+				    sstream->ssl_io->last_error);
 		stream->ostream.stream_errno = errno;
 	} else if (ret > 0 && sstream->buffer != NULL &&
 		   sstream->buffer->used > 0) {
--- a/src/lib-storage/index/istream-mail.c	Fri Sep 20 00:00:49 2013 +0300
+++ b/src/lib-storage/index/istream-mail.c	Fri Sep 20 00:12:45 2013 +0300
@@ -46,10 +46,12 @@
 		chr = '>';
 	}
 
-	mail_storage_set_critical(mstream->mail->box->storage,
+	io_stream_set_error(&mstream->istream.iostream,
 		"Cached message size %s than expected "
 		"(%"PRIuUOFF_T" %c %"PRIuUOFF_T")", str,
 		mstream->expected_size, chr, cur_size);
+	mail_storage_set_critical(mstream->mail->box->storage, "%s",
+				  mstream->istream.iostream.error);
 	mail_set_cache_corrupted(mstream->mail, MAIL_FETCH_PHYSICAL_SIZE);
 	mstream->istream.istream.stream_errno = EINVAL;
 }
--- a/src/lib-storage/index/mbox/istream-raw-mbox.c	Fri Sep 20 00:00:49 2013 +0300
+++ b/src/lib-storage/index/mbox/istream-raw-mbox.c	Fri Sep 20 00:12:45 2013 +0300
@@ -85,6 +85,8 @@
 			    &received_time, &tz, &sender) < 0) {
 		/* broken From - should happen only at beginning of
 		   file if this isn't a mbox.. */
+		io_stream_set_error(&rstream->istream.iostream,
+			"mbox file doesn't begin with 'From ' line");
 		rstream->istream.istream.stream_errno = EINVAL;
 		return -1;
 	}
@@ -253,12 +255,13 @@
 			return i_stream_raw_mbox_read(stream);
 		}
 		if (mbox_read_from_line(rstream) < 0) {
-			if (stream->istream.v_offset != 0) {
-				i_error("Next message unexpectedly corrupted in mbox file "
-					"%s at %"PRIuUOFF_T,
-					i_stream_get_name(&stream->istream),
-					stream->istream.v_offset);
-			}
+			io_stream_set_error(&stream->iostream,
+				"Next message unexpectedly corrupted in mbox file "
+				"%s at %"PRIuUOFF_T,
+				i_stream_get_name(&stream->istream),
+				stream->istream.v_offset);
+			if (stream->istream.v_offset != 0)
+				i_error("%s", stream->iostream.error);
 			stream->pos = 0;
 			rstream->eof = TRUE;
 			rstream->corrupted = TRUE;
@@ -356,11 +359,13 @@
 	    rstream->hdr_offset + new_pos > rstream->mail_size) {
 		/* istream_raw_mbox_set_next_offset() used invalid
 		   cached next_offset? */
-		i_error("Next message unexpectedly lost from mbox file "
+		io_stream_set_error(&stream->iostream,
+			"Next message unexpectedly lost from mbox file "
 			"%s at %"PRIuUOFF_T" (%s)",
 			i_stream_get_name(&stream->istream),
 			rstream->hdr_offset + rstream->mail_size,
 			rstream->mail_size_forced ? "cached" : "noncached");
+		i_error("%s", stream->iostream.error);
 		rstream->eof = TRUE;
 		rstream->corrupted = TRUE;
 		rstream->istream.istream.stream_errno = EINVAL;
--- a/src/lib/istream-base64-decoder.c	Fri Sep 20 00:00:49 2013 +0300
+++ b/src/lib/istream-base64-decoder.c	Fri Sep 20 00:12:45 2013 +0300
@@ -3,6 +3,7 @@
 #include "lib.h"
 #include "buffer.h"
 #include "base64.h"
+#include "hex-binary.h"
 #include "istream-private.h"
 #include "istream-base64.h"
 
@@ -58,6 +59,9 @@
 	buffer_create_from_data(&buf, stream->w_buffer + stream->pos,
 				buffer_avail);
 	if (base64_decode(data, size, &pos, &buf) < 0) {
+		io_stream_set_error(&stream->iostream,
+			"Invalid base64 data: 0x%s",
+			binary_to_hex(data+pos, I_MAX(size-pos, 8)));
 		stream->istream.stream_errno = EINVAL;
 		return -1;
 	}
@@ -71,7 +75,8 @@
 {
 	struct base64_decoder_istream *bstream =
 		(struct base64_decoder_istream *)stream;
-	size_t pre_count, post_count;
+	const unsigned char *data;
+	size_t pre_count, post_count, size;
 	int ret;
 
 	do {
@@ -80,6 +85,10 @@
 			if (ret < 0 && stream->istream.stream_errno == 0 &&
 			    i_stream_get_data_size(stream->parent) > 0) {
 				/* base64 input with a partial block */
+				data = i_stream_get_data(stream->parent, &size);
+				io_stream_set_error(&stream->iostream,
+					"base64 input ends with a partial block: 0x%s",
+					binary_to_hex(data, size));
 				stream->istream.stream_errno = EINVAL;
 			}
 			return ret;
--- a/src/lib/istream-concat.c	Fri Sep 20 00:00:49 2013 +0300
+++ b/src/lib/istream-concat.c	Fri Sep 20 00:12:45 2013 +0300
@@ -204,9 +204,13 @@
 		if (i == cstream->unknown_size_idx) {
 			/* we'll need to figure out this stream's size */
 			if (i_stream_stat(cstream->input[i], TRUE, &st) < 0) {
-				i_error("istream-concat: "
-					"Failed to get size of stream %s",
-					i_stream_get_name(cstream->input[i]));
+				io_stream_set_error(&cstream->istream.iostream,
+					"stat(%s) failed: %s",
+					i_stream_get_name(cstream->input[i]),
+					i_stream_get_error(cstream->input[i]));
+				i_error("istream-concat: stat(%s) failed: %s",
+					i_stream_get_name(cstream->input[i]),
+					i_stream_get_error(cstream->input[i]));
 				cstream->istream.istream.stream_errno =
 					cstream->input[i]->stream_errno;
 				return UINT_MAX;
--- a/src/lib/istream-file.c	Fri Sep 20 00:00:49 2013 +0300
+++ b/src/lib/istream-file.c	Fri Sep 20 00:12:45 2013 +0300
@@ -43,8 +43,9 @@
 
 	stream->fd = open(path, O_RDONLY);
 	if (stream->fd == -1) {
+		io_stream_set_error(&stream->iostream,
+				    "open(%s) failed: %m", path);
 		stream->istream.stream_errno = errno;
-		i_error("file_istream.open(%s) failed: %m", path);
 		return -1;
 	}
 	return 0;
@@ -169,7 +170,8 @@
 }
 
 static struct istream *
-i_stream_create_file_common(int fd, size_t max_buffer_size, bool autoclose_fd)
+i_stream_create_file_common(int fd, const char *path,
+			    size_t max_buffer_size, bool autoclose_fd)
 {
 	struct file_istream *fstream;
 	struct istream *input;
@@ -198,6 +200,9 @@
 	else {
 		/* we're trying to open a directory.
 		   we're not designed for it. */
+		io_stream_set_error(&fstream->istream.iostream,
+			"%s is a directory, can't read it as file",
+			path != NULL ? path : t_strdup_printf("<fd %d>", fd));
 		fstream->istream.istream.stream_errno = EISDIR;
 		is_file = FALSE;
 	}
@@ -218,14 +223,14 @@
 {
 	i_assert(fd != -1);
 
-	return i_stream_create_file_common(fd, max_buffer_size, autoclose_fd);
+	return i_stream_create_file_common(fd, NULL, max_buffer_size, autoclose_fd);
 }
 
 struct istream *i_stream_create_file(const char *path, size_t max_buffer_size)
 {
 	struct istream *input;
 
-	input = i_stream_create_file_common(-1, max_buffer_size, TRUE);
+	input = i_stream_create_file_common(-1, path, max_buffer_size, TRUE);
 	i_stream_set_name(input, path);
 	return input;
 }
--- a/src/lib/istream-hash.c	Fri Sep 20 00:00:49 2013 +0300
+++ b/src/lib/istream-hash.c	Fri Sep 20 00:12:45 2013 +0300
@@ -53,7 +53,8 @@
 	struct hash_istream *hstream = (struct hash_istream *)stream;
 
 	if (hstream->hash_context != NULL) {
-		/* we support seeking only after the hash is finished */
+		io_stream_set_error(&stream->iostream,
+			"Seeking not supported before hashing is finished");
 		stream->istream.stream_errno = ESPIPE;
 	}
 	stream->istream.v_offset = v_offset;
--- a/src/lib/istream-jsonstr.c	Fri Sep 20 00:00:49 2013 +0300
+++ b/src/lib/istream-jsonstr.c	Fri Sep 20 00:12:45 2013 +0300
@@ -135,6 +135,8 @@
 						   stream->w_buffer + dest,
 						   &srcskip, &destskip) < 0) {
 				/* invalid string */
+				io_stream_set_error(&stream->iostream,
+						    "Invalid JSON string");
 				stream->istream.stream_errno = EINVAL;
 				return -1;
 			}
--- a/src/lib/istream-mmap.c	Fri Sep 20 00:00:49 2013 +0300
+++ b/src/lib/istream-mmap.c	Fri Sep 20 00:12:45 2013 +0300
@@ -119,6 +119,8 @@
 			stream->buffer = NULL;
 			stream->buffer_size = 0;
 			stream->skip = stream->pos = 0;
+			io_stream_set_error(&stream->iostream,
+					    "mmap() failed: %m");
 			i_error("mmap_istream.mmap(%s) failed: %m",
 				i_stream_get_name(&stream->istream));
 			return -1;
--- a/src/lib/istream-sized.c	Fri Sep 20 00:00:49 2013 +0300
+++ b/src/lib/istream-sized.c	Fri Sep 20 00:12:45 2013 +0300
@@ -46,8 +46,14 @@
 	if (pos == left)
 		stream->istream.eof = TRUE;
 	else if (pos > left) {
-		i_error("%s is larger than expected (%"PRIuUOFF_T")",
-			i_stream_get_name(stream->parent), sstream->size);
+		io_stream_set_error(&stream->iostream,
+			"Stream is larger than expected "
+			"(%"PRIuUOFF_T" > %"PRIuUOFF_T", eof=%d)",
+			stream->istream.v_offset+pos, sstream->size,
+			stream->istream.eof);
+		i_error("read(%s) failed: %s",
+			i_stream_get_name(stream->parent),
+			stream->iostream.error);
 		pos = left;
 		stream->istream.eof = TRUE;
 	} else if (!stream->istream.eof) {
@@ -55,10 +61,13 @@
 	} else if (stream->istream.stream_errno == ENOENT) {
 		/* lost the file */
 	} else {
-		i_error("%s smaller than expected "
-			"(%"PRIuUOFF_T" < %"PRIuUOFF_T")",
+		io_stream_set_error(&stream->iostream,
+				    "Stream is smaller than expected "
+				    "(%"PRIuUOFF_T" < %"PRIuUOFF_T")",
+				    stream->istream.v_offset+pos, sstream->size);
+		i_error("read(%s) failed: %s",
 			i_stream_get_name(stream->parent),
-			stream->istream.v_offset, sstream->size);
+			stream->iostream.error);
 		stream->istream.stream_errno = EINVAL;
 	}
 
--- a/src/lib/ostream-file.c	Fri Sep 20 00:00:49 2013 +0300
+++ b/src/lib/ostream-file.c	Fri Sep 20 00:12:45 2013 +0300
@@ -153,11 +153,15 @@
 
 	ret = lseek(fstream->fd, (off_t)fstream->buffer_offset, SEEK_SET);
 	if (ret < 0) {
+		io_stream_set_error(&fstream->ostream.iostream,
+				    "lseek() failed: %m");
 		fstream->ostream.ostream.stream_errno = errno;
 		return -1;
 	}
 
 	if (ret != (off_t)fstream->buffer_offset) {
+		io_stream_set_error(&fstream->ostream.iostream,
+				    "lseek() returned wrong value");
 		fstream->ostream.ostream.stream_errno = EINVAL;
 		return -1;
 	}
@@ -397,10 +401,14 @@
 {
 	struct file_ostream *fstream = (struct file_ostream *)stream;
 
-	if (offset > OFF_T_MAX || !fstream->file) {
+	if (offset > OFF_T_MAX) {
 		stream->ostream.stream_errno = EINVAL;
 		return -1;
 	}
+	if (!fstream->file) {
+		stream->ostream.stream_errno = ESPIPE;
+		return -1;
+	}
 
 	if (buffer_flush(fstream) < 0)
 		return -1;