struct iostream_private {
int refcount;
char *name;
+ char *error;
void (*close)(struct iostream_private *streami, bool close_parent);
void (*destroy)(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
array_free(&stream->destroy_callbacks);
}
+ i_free(stream->error);
i_free(stream->name);
i_free(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);
+}
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);
/* 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. */
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);
_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;
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;
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;
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)
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);
return -1;
}
+ o_stream_clear_error(stream);
ret = stream->real_stream->write_at(stream->real_stream,
data, size, offset);
if (unlikely(ret < 0)) {
/* 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);