ostream.c revision 3d77cc0d502dc69ffe2afe318605964dd40b7b20
89a126810703c666309310d0f3189e9834d70b5bTimo Sirainen/* Copyright (c) 2002-2014 Dovecot authors, see the included COPYING file */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "lib.h"
6157a322f2ac1ea1332d9003ecb0b11466aa8fe7Timo Sirainen#include "istream.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "ostream-private.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainenvoid o_stream_set_name(struct ostream *stream, const char *name)
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen{
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen i_free(stream->real_stream->iostream.name);
c4cfee078c4a185b5ba8f0c55f51275b7e885b2cTimo Sirainen stream->real_stream->iostream.name = i_strdup(name);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenconst char *o_stream_get_name(struct ostream *stream)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen while (stream->real_stream->iostream.name == NULL) {
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen stream = stream->real_stream->parent;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if (stream == NULL)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return "";
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen }
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen return stream->real_stream->iostream.name;
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen}
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainenint o_stream_get_fd(struct ostream *stream)
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen{
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen return stream->real_stream->fd;
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen}
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainenconst char *o_stream_get_error(struct ostream *stream)
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen{
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen struct ostream *s;
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen /* we'll only return errors for streams that have stream_errno set.
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen we might be returning unintended error otherwise. */
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen if (stream->stream_errno == 0)
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen return "<no error>";
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen for (s = stream; s != NULL; s = s->real_stream->parent) {
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen if (s->stream_errno == 0)
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen break;
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen if (s->real_stream->iostream.error != NULL)
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen return s->real_stream->iostream.error;
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen }
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen return strerror(stream->stream_errno);
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen}
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainenstatic void o_stream_close_full(struct ostream *stream, bool close_parents)
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen{
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen if (!stream->closed && !stream->real_stream->closing) {
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen /* first mark the stream as being closed so the
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen o_stream_copy_error_from_parent() won't recurse us back
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen here. but don't immediately mark the stream closed, because
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen we may still want to write something to it. */
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen stream->real_stream->closing = TRUE;
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen io_stream_close(&stream->real_stream->iostream, close_parents);
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen stream->closed = TRUE;
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen }
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen if (stream->stream_errno != 0)
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen i_assert(stream->last_failed_errno != 0);
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen else {
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen stream->stream_errno = EPIPE;
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen stream->last_failed_errno = EPIPE;
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen }
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen}
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainenvoid o_stream_destroy(struct ostream **stream)
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen o_stream_close_full(*stream, FALSE);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen o_stream_unref(stream);
9d3ccd79130199ffdb19a688027d49bf20a4aaaaTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid o_stream_ref(struct ostream *stream)
8d6cb44a0161d88743756733f83c4fb278485987Timo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen io_stream_ref(&stream->real_stream->iostream);
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid o_stream_unref(struct ostream **_stream)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct ostream *stream = *_stream;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen if (stream->real_stream->last_errors_not_checked &&
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen !stream->real_stream->error_handling_disabled &&
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen stream->real_stream->iostream.refcount == 1) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_panic("output stream %s is missing error handling",
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen o_stream_get_name(stream));
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen }
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen io_stream_unref(&stream->real_stream->iostream);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen *_stream = NULL;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainenvoid o_stream_close(struct ostream *stream)
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen{
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen o_stream_close_full(stream, TRUE);
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen}
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen#undef o_stream_set_flush_callback
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainenvoid o_stream_set_flush_callback(struct ostream *stream,
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen stream_flush_callback_t *callback,
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen void *context)
be889d9b142fbb5604a922c6955bd7f6ea32f163Timo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct ostream_private *_stream = stream->real_stream;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen _stream->set_flush_callback(_stream, callback, context);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid o_stream_unset_flush_callback(struct ostream *stream)
0cea9b1f4fa0495a48f5f097e40492517d67e1baTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct ostream_private *_stream = stream->real_stream;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen _stream->set_flush_callback(_stream, NULL, NULL);
0cea9b1f4fa0495a48f5f097e40492517d67e1baTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid o_stream_set_max_buffer_size(struct ostream *stream, size_t max_size)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen io_stream_set_max_buffer_size(&stream->real_stream->iostream, max_size);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainensize_t o_stream_get_max_buffer_size(struct ostream *stream)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return stream->real_stream->max_buffer_size;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
8d6cb44a0161d88743756733f83c4fb278485987Timo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenvoid o_stream_cork(struct ostream *stream)
8d6cb44a0161d88743756733f83c4fb278485987Timo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct ostream_private *_stream = stream->real_stream;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
8d6cb44a0161d88743756733f83c4fb278485987Timo Sirainen _stream->cork(_stream, TRUE);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid o_stream_uncork(struct ostream *stream)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct ostream_private *_stream = stream->real_stream;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen _stream->cork(_stream, FALSE);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (stream->stream_errno != 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen errno = stream->last_failed_errno = stream->stream_errno;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenbool o_stream_is_corked(struct ostream *stream)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen struct ostream_private *_stream = stream->real_stream;
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen return _stream->corked;
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen}
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainenint o_stream_flush(struct ostream *stream)
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen{
bc793bfcee945ce8871edfa298fe7235744425b6Timo Sirainen struct ostream_private *_stream = stream->real_stream;
bc793bfcee945ce8871edfa298fe7235744425b6Timo Sirainen int ret = 1;
bc793bfcee945ce8871edfa298fe7235744425b6Timo Sirainen
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
ea4ca37ec14913354f3a0deebc0df96097eb9468Timo Sirainen errno = stream->stream_errno;
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen return -1;
ea4ca37ec14913354f3a0deebc0df96097eb9468Timo Sirainen }
ea4ca37ec14913354f3a0deebc0df96097eb9468Timo Sirainen
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen if (unlikely((ret = _stream->flush(_stream)) < 0)) {
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen i_assert(stream->stream_errno != 0);
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen stream->last_failed_errno = stream->stream_errno;
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen errno = stream->stream_errno;
16598a1fb870ae40d6177755a4306216e4d6a4cdTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return ret;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid o_stream_set_flush_pending(struct ostream *stream, bool set)
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen{
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen struct ostream_private *_stream = stream->real_stream;
abb83d133dd082527d500916fca66a72fbbbaa8dTimo Sirainen
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen _stream->flush_pending(_stream, set);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainensize_t o_stream_get_buffer_used_size(const struct ostream *stream)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const struct ostream_private *_stream = stream->real_stream;
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen return _stream->get_used_size(_stream);
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainensize_t o_stream_get_buffer_avail_size(const struct ostream *stream)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen{
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen size_t used = o_stream_get_buffer_used_size(stream);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return stream->real_stream->max_buffer_size <= used ? 0 :
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen stream->real_stream->max_buffer_size - used;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainenint o_stream_seek(struct ostream *stream, uoff_t offset)
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen{
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen struct ostream_private *_stream = stream->real_stream;
c4cfee078c4a185b5ba8f0c55f51275b7e885b2cTimo Sirainen
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen errno = stream->stream_errno;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen return -1;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen }
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen if (unlikely(_stream->seek(_stream, offset) < 0)) {
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen i_assert(stream->stream_errno != 0);
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen stream->last_failed_errno = stream->stream_errno;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen errno = stream->stream_errno;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen return -1;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen }
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen return 1;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen}
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainenssize_t o_stream_send(struct ostream *stream, const void *data, size_t size)
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen{
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen struct const_iovec iov;
114a0f74e0f825c6bd8aeadfafb248a030762a1fTimo Sirainen
c4cfee078c4a185b5ba8f0c55f51275b7e885b2cTimo Sirainen memset(&iov, 0, sizeof(iov));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen iov.iov_base = data;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen iov.iov_len = size;
abb83d133dd082527d500916fca66a72fbbbaa8dTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return o_stream_sendv(stream, &iov, 1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainenssize_t o_stream_sendv(struct ostream *stream, const struct const_iovec *iov,
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen unsigned int iov_count)
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen{
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen struct ostream_private *_stream = stream->real_stream;
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen unsigned int i;
abb83d133dd082527d500916fca66a72fbbbaa8dTimo Sirainen size_t total_size;
abb83d133dd082527d500916fca66a72fbbbaa8dTimo Sirainen ssize_t ret;
abb83d133dd082527d500916fca66a72fbbbaa8dTimo Sirainen
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen errno = stream->stream_errno;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen return -1;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen }
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen for (i = 0, total_size = 0; i < iov_count; i++)
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen total_size += iov[i].iov_len;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen if (total_size == 0)
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen return 0;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ret = _stream->sendv(_stream, iov, iov_count);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (unlikely(ret != (ssize_t)total_size)) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (ret < 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_assert(stream->stream_errno != 0);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen stream->last_failed_errno = stream->stream_errno;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen errno = stream->stream_errno;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen } else {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen stream->overflow = TRUE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return ret;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen}
11768c622a8e5aaf0e5d9b3c9a872867b62b4830Timo Sirainen
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainenssize_t o_stream_send_str(struct ostream *stream, const char *str)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return o_stream_send(stream, str, strlen(str));
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid o_stream_nsend(struct ostream *stream, const void *data, size_t size)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct const_iovec iov;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen memset(&iov, 0, sizeof(iov));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen iov.iov_base = data;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen iov.iov_len = size;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen o_stream_nsendv(stream, &iov, 1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid o_stream_nsendv(struct ostream *stream, const struct const_iovec *iov,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int iov_count)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (void)o_stream_sendv(stream, iov, iov_count);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen stream->real_stream->last_errors_not_checked = TRUE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid o_stream_nsend_str(struct ostream *stream, const char *str)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen{
11768c622a8e5aaf0e5d9b3c9a872867b62b4830Timo Sirainen o_stream_nsend(stream, str, strlen(str));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
11768c622a8e5aaf0e5d9b3c9a872867b62b4830Timo Sirainen
265e9d8457aa5ce01b7aad954632aed8c36deeb8Timo Sirainenvoid o_stream_nflush(struct ostream *stream)
265e9d8457aa5ce01b7aad954632aed8c36deeb8Timo Sirainen{
265e9d8457aa5ce01b7aad954632aed8c36deeb8Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
265e9d8457aa5ce01b7aad954632aed8c36deeb8Timo Sirainen return;
11768c622a8e5aaf0e5d9b3c9a872867b62b4830Timo Sirainen (void)o_stream_flush(stream);
265e9d8457aa5ce01b7aad954632aed8c36deeb8Timo Sirainen stream->real_stream->last_errors_not_checked = TRUE;
265e9d8457aa5ce01b7aad954632aed8c36deeb8Timo Sirainen}
265e9d8457aa5ce01b7aad954632aed8c36deeb8Timo Sirainen
11768c622a8e5aaf0e5d9b3c9a872867b62b4830Timo Sirainenint o_stream_nfinish(struct ostream *stream)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen o_stream_nflush(stream);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen o_stream_ignore_last_errors(stream);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen errno = stream->last_failed_errno;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return stream->last_failed_errno != 0 ? -1 : 0;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen}
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenvoid o_stream_ignore_last_errors(struct ostream *stream)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen{
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen while (stream != NULL) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen stream->real_stream->last_errors_not_checked = FALSE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen stream = stream->real_stream->parent;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid o_stream_set_no_error_handling(struct ostream *stream, bool set)
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen{
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen stream->real_stream->error_handling_disabled = set;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenoff_t o_stream_send_istream(struct ostream *outstream,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct istream *instream)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct ostream_private *_outstream = outstream->real_stream;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen off_t ret;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (unlikely(outstream->closed || instream->closed ||
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen outstream->stream_errno != 0)) {
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen errno = outstream->stream_errno;
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen return -1;
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen }
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen ret = _outstream->send_istream(_outstream, instream);
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen if (unlikely(ret < 0)) {
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen if (outstream->stream_errno != 0) {
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen outstream->last_failed_errno = outstream->stream_errno;
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen errno = outstream->stream_errno;
5c0034beb9933bca2a8b7d83d11dface1ea3b7faTimo Sirainen } else {
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen i_assert(instream->stream_errno != 0);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen }
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen }
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return ret;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen}
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenint o_stream_pwrite(struct ostream *stream, const void *data, size_t size,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen uoff_t offset)
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen{
9bf2dc275ec21bff3d468ab1bc4fddc8874f7d1bTimo Sirainen int ret;
7bb939ef70752f2731d27b18c944ea94e5b23eb5Timo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen errno = stream->stream_errno;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return -1;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen }
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen ret = stream->real_stream->write_at(stream->real_stream,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen data, size, offset);
8e574a603c2c02105b073906a7ca91904271b80eTimo Sirainen if (unlikely(ret < 0)) {
8e574a603c2c02105b073906a7ca91904271b80eTimo Sirainen i_assert(stream->stream_errno != 0);
8e574a603c2c02105b073906a7ca91904271b80eTimo Sirainen stream->last_failed_errno = stream->stream_errno;
8e574a603c2c02105b073906a7ca91904271b80eTimo Sirainen errno = stream->stream_errno;
8e574a603c2c02105b073906a7ca91904271b80eTimo Sirainen }
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen return ret;
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenoff_t io_stream_copy(struct ostream *outstream, struct istream *instream)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen uoff_t start_offset;
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen struct const_iovec iov;
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen const unsigned char *data;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen ssize_t ret;
9c4c535b86e9473ad97c6e9242ed84f3d9d69d0dTimo Sirainen
9c4c535b86e9473ad97c6e9242ed84f3d9d69d0dTimo Sirainen start_offset = instream->v_offset;
9c4c535b86e9473ad97c6e9242ed84f3d9d69d0dTimo Sirainen do {
9c4c535b86e9473ad97c6e9242ed84f3d9d69d0dTimo Sirainen (void)i_stream_read_data(instream, &data, &iov.iov_len, 0);
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen if (iov.iov_len == 0) {
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen /* all sent */
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen if (instream->stream_errno != 0)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return -1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen break;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen iov.iov_base = data;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen ret = o_stream_sendv(outstream, &iov, 1);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (ret <= 0) {
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (ret == 0)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen break;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return -1;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen }
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen i_stream_skip(instream, ret);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen } while ((size_t)ret == iov.iov_len);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return (off_t)(instream->v_offset - start_offset);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen}
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainenvoid o_stream_switch_ioloop(struct ostream *stream)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen{
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen struct ostream_private *_stream = stream->real_stream;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen _stream->switch_ioloop(_stream);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen}
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainenstatic void o_stream_default_close(struct iostream_private *stream,
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen bool close_parent)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen{
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen struct ostream_private *_stream = (struct ostream_private *)stream;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen (void)o_stream_flush(&_stream->ostream);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if (close_parent && _stream->parent != NULL)
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen o_stream_close(_stream->parent);
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen}
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainenstatic void o_stream_default_destroy(struct iostream_private *stream)
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen{
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen struct ostream_private *_stream = (struct ostream_private *)stream;
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen if (_stream->parent != NULL)
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen o_stream_unref(&_stream->parent);
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen}
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainenstatic void
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Siraineno_stream_default_set_max_buffer_size(struct iostream_private *stream,
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen size_t max_size)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen{
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen struct ostream_private *_stream = (struct ostream_private *)stream;
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if (_stream->parent != NULL)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen o_stream_set_max_buffer_size(_stream->parent, max_size);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen _stream->max_buffer_size = max_size;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen}
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainenstatic void o_stream_default_cork(struct ostream_private *_stream, bool set)
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen{
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen _stream->corked = set;
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen if (set) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (_stream->parent != NULL)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen o_stream_cork(_stream->parent);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen } else {
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen (void)o_stream_flush(&_stream->ostream);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (_stream->parent != NULL)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen o_stream_uncork(_stream->parent);
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen }
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen}
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenvoid o_stream_copy_error_from_parent(struct ostream_private *_stream)
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen{
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen struct ostream *src = _stream->parent;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen struct ostream *dest = &_stream->ostream;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen dest->stream_errno = src->stream_errno;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen dest->last_failed_errno = src->last_failed_errno;
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen dest->overflow = src->overflow;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (src->closed)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen o_stream_close(dest);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen}
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenint o_stream_flush_parent_if_needed(struct ostream_private *_stream)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen{
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen if (o_stream_get_buffer_used_size(_stream->parent) >= IO_BLOCK_SIZE) {
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen /* we already have quite a lot of data in parent stream.
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen unless we can flush it, don't add any more to it or we
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen could keep wasting memory by just increasing the buffer
2c20ffcb5bb1ccdfdcd0b0ff0c7296f65b990362Timo Sirainen size all the time. */
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (o_stream_flush(_stream->parent) < 0) {
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen o_stream_copy_error_from_parent(_stream);
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen return -1;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen }
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen if (o_stream_get_buffer_used_size(_stream->parent) >= IO_BLOCK_SIZE)
114a0f74e0f825c6bd8aeadfafb248a030762a1fTimo Sirainen return 0;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return 1;
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen}
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainenstatic int o_stream_default_flush(struct ostream_private *_stream)
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen{
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen int ret;
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen if (_stream->parent == NULL)
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen return 1;
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen if ((ret = o_stream_flush(_stream->parent)) < 0)
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen o_stream_copy_error_from_parent(_stream);
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen return ret;
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen}
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainen
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainenstatic void
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Siraineno_stream_default_set_flush_callback(struct ostream_private *_stream,
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen stream_flush_callback_t *callback,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen void *context)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (_stream->parent != NULL)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen o_stream_set_flush_callback(_stream->parent, callback, context);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen _stream->callback = callback;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen _stream->context = context;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic void
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Siraineno_stream_default_set_flush_pending(struct ostream_private *_stream, bool set)
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen{
6157a322f2ac1ea1332d9003ecb0b11466aa8fe7Timo Sirainen if (_stream->parent != NULL)
6157a322f2ac1ea1332d9003ecb0b11466aa8fe7Timo Sirainen o_stream_set_flush_pending(_stream->parent, set);
6157a322f2ac1ea1332d9003ecb0b11466aa8fe7Timo Sirainen}
6157a322f2ac1ea1332d9003ecb0b11466aa8fe7Timo Sirainen
6157a322f2ac1ea1332d9003ecb0b11466aa8fe7Timo Sirainenstatic size_t
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Siraineno_stream_default_get_used_size(const struct ostream_private *_stream)
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen{
9a583c7a827f7a4d89ee43774f2d51ea6a214543Timo Sirainen if (_stream->parent == NULL)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return 0;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen else
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return o_stream_get_buffer_used_size(_stream->parent);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen}
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainenstatic int
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Siraineno_stream_default_seek(struct ostream_private *_stream,
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen uoff_t offset ATTR_UNUSED)
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen{
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen _stream->ostream.stream_errno = ESPIPE;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen _stream->ostream.last_failed_errno = ESPIPE;
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return -1;
e96fb85799dc95603bb1a6b4d3685df2d042a2f8Timo Sirainen}
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainenstatic int
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Siraineno_stream_default_write_at(struct ostream_private *_stream,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const void *data ATTR_UNUSED,
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen size_t size ATTR_UNUSED, uoff_t offset ATTR_UNUSED)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen _stream->ostream.stream_errno = ESPIPE;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen _stream->ostream.last_failed_errno = ESPIPE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return -1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic off_t o_stream_default_send_istream(struct ostream_private *outstream,
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen struct istream *instream)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen{
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen return io_stream_copy(&outstream->ostream, instream);
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic void o_stream_default_switch_ioloop(struct ostream_private *_stream)
8c02331f9f569d8b30e74b6bc8550734d65f9daeTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (_stream->parent != NULL)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen o_stream_switch_ioloop(_stream->parent);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
d5ac54ef50db16b50689b5c8b7bb64d344190832Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstruct ostream *
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Siraineno_stream_create(struct ostream_private *_stream, struct ostream *parent, int fd)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen _stream->fd = fd;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen _stream->ostream.real_stream = _stream;
8b681dae1e8fa564649e703ab17398dcfaf896e4Timo Sirainen if (parent != NULL) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen _stream->parent = parent;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen o_stream_ref(parent);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen _stream->callback = parent->real_stream->callback;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen _stream->context = parent->real_stream->context;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen _stream->max_buffer_size = parent->real_stream->max_buffer_size;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen _stream->error_handling_disabled =
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen parent->real_stream->error_handling_disabled;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (_stream->iostream.close == NULL)
_stream->iostream.close = o_stream_default_close;
if (_stream->iostream.destroy == NULL)
_stream->iostream.destroy = o_stream_default_destroy;
if (_stream->iostream.set_max_buffer_size == NULL) {
_stream->iostream.set_max_buffer_size =
o_stream_default_set_max_buffer_size;
}
if (_stream->cork == NULL)
_stream->cork = o_stream_default_cork;
if (_stream->flush == NULL)
_stream->flush = o_stream_default_flush;
if (_stream->set_flush_callback == NULL) {
_stream->set_flush_callback =
o_stream_default_set_flush_callback;
}
if (_stream->flush_pending == NULL)
_stream->flush_pending = o_stream_default_set_flush_pending;
if (_stream->get_used_size == NULL)
_stream->get_used_size = o_stream_default_get_used_size;
if (_stream->seek == NULL)
_stream->seek = o_stream_default_seek;
if (_stream->write_at == NULL)
_stream->write_at = o_stream_default_write_at;
if (_stream->send_istream == NULL)
_stream->send_istream = o_stream_default_send_istream;
if (_stream->switch_ioloop == NULL)
_stream->switch_ioloop = o_stream_default_switch_ioloop;
io_stream_init(&_stream->iostream);
return &_stream->ostream;
}
struct ostream *o_stream_create_error(int stream_errno)
{
struct ostream_private *stream;
struct ostream *output;
stream = i_new(struct ostream_private, 1);
stream->ostream.closed = TRUE;
stream->ostream.stream_errno = stream_errno;
stream->ostream.last_failed_errno = stream_errno;
output = o_stream_create(stream, NULL, -1);
o_stream_set_no_error_handling(output, TRUE);
o_stream_set_name(output, "(error)");
return output;
}
struct ostream *
o_stream_create_error_str(int stream_errno, const char *fmt, ...)
{
struct ostream *output;
va_list args;
va_start(args, fmt);
output = o_stream_create_error(stream_errno);
io_stream_set_verror(&output->real_stream->iostream, fmt, args);
va_end(args);
return output;
}