changeset 16772:e35be66003e2

iostream: Added ability to set/get error strings for streams.
author Timo Sirainen <tss@iki.fi>
date Fri, 20 Sep 2013 00:00:49 +0300
parents 5a334879572b
children 76d5e3c8cec3
files src/lib/iostream-private.h src/lib/iostream.c src/lib/istream.c src/lib/istream.h src/lib/ostream.c src/lib/ostream.h
diffstat 6 files changed, 71 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib/iostream-private.h	Thu Sep 19 22:44:20 2013 +0300
+++ b/src/lib/iostream-private.h	Fri Sep 20 00:00:49 2013 +0300
@@ -11,6 +11,7 @@
 struct iostream_private {
 	int refcount;
 	char *name;
+	char *error;
 
 	void (*close)(struct iostream_private *streami, bool close_parent);
 	void (*destroy)(struct iostream_private *stream);
@@ -26,5 +27,11 @@
 void io_stream_close(struct iostream_private *stream, bool close_parent);
 void io_stream_set_max_buffer_size(struct iostream_private *stream,
 				   size_t max_size);
+/* Set a specific error for the stream. This shouldn't be used for regular
+   syscall errors where stream's errno is enough, since it's used by default.
+   The stream errno must always be set even if the error string is also set.
+   Setting this error replaces the previously set error. */
+void io_stream_set_error(struct iostream_private *stream,
+			 const char *fmt, ...) ATTR_FORMAT(2, 3);
 
 #endif
--- a/src/lib/iostream.c	Thu Sep 19 22:44:20 2013 +0300
+++ b/src/lib/iostream.c	Fri Sep 20 00:00:49 2013 +0300
@@ -46,6 +46,7 @@
 		array_free(&stream->destroy_callbacks);
 	}
 
+        i_free(stream->error);
         i_free(stream->name);
         i_free(stream);
 }
@@ -60,3 +61,14 @@
 {
 	stream->set_max_buffer_size(stream, max_size);
 }
+
+void io_stream_set_error(struct iostream_private *stream,
+			 const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	i_free(stream->error);
+	stream->error = i_strdup_vprintf(fmt, args);
+	va_end(args);
+}
--- a/src/lib/istream.c	Thu Sep 19 22:44:20 2013 +0300
+++ b/src/lib/istream.c	Fri Sep 20 00:00:49 2013 +0300
@@ -92,6 +92,24 @@
 	return _stream->fd;
 }
 
+const char *i_stream_get_error(struct istream *stream)
+{
+	struct istream *s;
+
+	/* we'll only return errors for streams that have stream_errno set.
+	   we might be returning unintended error otherwise. */
+	if (stream->stream_errno == 0)
+		return "<no error>";
+
+	for (s = stream; s != NULL; s = s->real_stream->parent) {
+		if (s->stream_errno == 0)
+			break;
+		if (s->real_stream->iostream.error != NULL)
+			return s->real_stream->iostream.error;
+	}
+	return strerror(stream->stream_errno);
+}
+
 void i_stream_close(struct istream *stream)
 {
 	i_stream_close_full(stream, TRUE);
--- a/src/lib/istream.h	Thu Sep 19 22:44:20 2013 +0300
+++ b/src/lib/istream.h	Fri Sep 20 00:00:49 2013 +0300
@@ -65,6 +65,8 @@
 
 /* Return file descriptor for stream, or -1 if none is available. */
 int i_stream_get_fd(struct istream *stream);
+/* Returns error string for the last error. */
+const char *i_stream_get_error(struct istream *stream);
 
 /* Mark the stream and all of its parent streams closed. Any reads after this
    will return -1. The data already read can still be used. */
--- a/src/lib/ostream.c	Thu Sep 19 22:44:20 2013 +0300
+++ b/src/lib/ostream.c	Fri Sep 20 00:00:49 2013 +0300
@@ -25,6 +25,24 @@
 	return stream->real_stream->fd;
 }
 
+const char *o_stream_get_error(struct ostream *stream)
+{
+	struct ostream *s;
+
+	/* we'll only return errors for streams that have stream_errno set.
+	   we might be returning unintended error otherwise. */
+	if (stream->stream_errno == 0)
+		return "<no error>";
+
+	for (s = stream; s != NULL; s = s->real_stream->parent) {
+		if (s->stream_errno == 0)
+			break;
+		if (s->real_stream->iostream.error != NULL)
+			return s->real_stream->iostream.error;
+	}
+	return strerror(stream->stream_errno);
+}
+
 static void o_stream_close_full(struct ostream *stream, bool close_parents)
 {
 	io_stream_close(&stream->real_stream->iostream, close_parents);
@@ -107,6 +125,12 @@
 	_stream->cork(_stream, FALSE);
 }
 
+static void o_stream_clear_error(struct ostream *stream)
+{
+	stream->stream_errno = 0;
+	i_free_and_null(stream->real_stream->iostream.error);
+}
+
 int o_stream_flush(struct ostream *stream)
 {
 	struct ostream_private *_stream = stream->real_stream;
@@ -117,7 +141,7 @@
 		return -1;
 	}
 
-	stream->stream_errno = 0;
+	o_stream_clear_error(stream);
 	if (unlikely((ret = _stream->flush(_stream)) < 0)) {
 		i_assert(stream->stream_errno != 0);
 		stream->last_failed_errno = stream->stream_errno;
@@ -160,7 +184,7 @@
 		return -1;
 	}
 
-	stream->stream_errno = 0;
+	o_stream_clear_error(stream);
 	if (unlikely(_stream->seek(_stream, offset) < 0)) {
 		i_assert(stream->stream_errno != 0);
 		stream->last_failed_errno = stream->stream_errno;
@@ -194,7 +218,7 @@
 		return -1;
 	}
 
-	stream->stream_errno = 0;
+	o_stream_clear_error(stream);
 	for (i = 0, total_size = 0; i < iov_count; i++)
 		total_size += iov[i].iov_len;
 	if (total_size == 0)
@@ -283,7 +307,7 @@
 		return -1;
 	}
 
-	outstream->stream_errno = 0;
+	o_stream_clear_error(outstream);
 	ret = _outstream->send_istream(_outstream, instream);
 	if (unlikely(ret < 0)) {
 		i_assert(outstream->stream_errno != 0);
@@ -303,6 +327,7 @@
 		return -1;
 	}
 
+	o_stream_clear_error(stream);
 	ret = stream->real_stream->write_at(stream->real_stream,
 					    data, size, offset);
 	if (unlikely(ret < 0)) {
--- a/src/lib/ostream.h	Thu Sep 19 22:44:20 2013 +0300
+++ b/src/lib/ostream.h	Fri Sep 20 00:00:49 2013 +0300
@@ -46,6 +46,9 @@
 
 /* Return file descriptor for stream, or -1 if none is available. */
 int o_stream_get_fd(struct ostream *stream);
+/* Returns error string for the previous error (stream_errno,
+   not last_failed_errno). */
+const char *o_stream_get_error(struct ostream *stream);
 
 /* Close this stream (but not its parents) and unreference it. */
 void o_stream_destroy(struct ostream **stream);