]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
iostream: Added ability to set/get error strings for streams.
authorTimo Sirainen <tss@iki.fi>
Thu, 19 Sep 2013 21:00:49 +0000 (00:00 +0300)
committerTimo Sirainen <tss@iki.fi>
Thu, 19 Sep 2013 21:00:49 +0000 (00:00 +0300)
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

index 870a995311469df8e5c8878ac239680c9e861796..4622d095c8aa2fc2793daa2eb2416194aacd0803 100644 (file)
@@ -11,6 +11,7 @@ struct iostream_destroy_callback {
 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_unref(struct iostream_private *stream);
 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
index 66ad38fe76baedd9a040d3e87fcc550adb66db51..9bd83f925d10a297d8e3ff47e243bbdc9d31ad55 100644 (file)
@@ -46,6 +46,7 @@ void io_stream_unref(struct iostream_private *stream)
                array_free(&stream->destroy_callbacks);
        }
 
+        i_free(stream->error);
         i_free(stream->name);
         i_free(stream);
 }
@@ -60,3 +61,14 @@ void io_stream_set_max_buffer_size(struct iostream_private *stream,
 {
        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);
+}
index 34ce69eb7337d98e8d9a5d708e0697fbfd18c73b..46888aa84be629c658ba280dfd2a08ed662d3d21 100644 (file)
@@ -92,6 +92,24 @@ int i_stream_get_fd(struct istream *stream)
        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);
index 2a4b9ae96b7486959ba36864d725a9dc305e6f99..4bfe29568123743c4139ce030d5bd9b2be877fd3 100644 (file)
@@ -65,6 +65,8 @@ void i_stream_remove_destroy_callback(struct istream *stream,
 
 /* 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. */
index c974a928e7c0be204618039b490e718bf246f43a..ad81fa203a6a04b0bc28c02357a42e88c7f51a3e 100644 (file)
@@ -25,6 +25,24 @@ int o_stream_get_fd(struct ostream *stream)
        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 @@ void o_stream_uncork(struct ostream *stream)
        _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 @@ int o_stream_flush(struct ostream *stream)
                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 @@ int o_stream_seek(struct ostream *stream, uoff_t offset)
                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 @@ ssize_t o_stream_sendv(struct ostream *stream, const struct const_iovec *iov,
                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 @@ off_t o_stream_send_istream(struct ostream *outstream,
                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 @@ int o_stream_pwrite(struct ostream *stream, const void *data, size_t size,
                return -1;
        }
 
+       o_stream_clear_error(stream);
        ret = stream->real_stream->write_at(stream->real_stream,
                                            data, size, offset);
        if (unlikely(ret < 0)) {
index 8d3874ff356fc8e371413849061b633ca3a08b63..6c429e603402d7adc3a85256cafa7dbdb1fa91f2 100644 (file)
@@ -46,6 +46,9 @@ const char *o_stream_get_name(struct ostream *stream);
 
 /* 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);