bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "istream.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "ostream-private.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenvoid o_stream_set_name(struct ostream *stream, const char *name)
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen{
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen i_free(stream->real_stream->iostream.name);
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen stream->real_stream->iostream.name = i_strdup(name);
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen}
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenconst char *o_stream_get_name(struct ostream *stream)
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen while (stream->real_stream->iostream.name == NULL) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen stream = stream->real_stream->parent;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (stream == NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return "";
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return stream->real_stream->iostream.name;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen}
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainenint o_stream_get_fd(struct ostream *stream)
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen{
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen return stream->real_stream->fd;
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen}
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenconst char *o_stream_get_error(struct ostream *stream)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen{
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen struct ostream *s;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen /* we'll only return errors for streams that have stream_errno set.
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen we might be returning unintended error otherwise. */
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if (stream->stream_errno == 0)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen return "<no error>";
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen for (s = stream; s != NULL; s = s->real_stream->parent) {
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if (s->stream_errno == 0)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen break;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if (s->real_stream->iostream.error != NULL)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen return s->real_stream->iostream.error;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen }
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen return strerror(stream->stream_errno);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen}
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstatic void o_stream_close_full(struct ostream *stream, bool close_parents)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen{
5ec4fc44e8d4e2160f07b1a7f4fce1ccfec3f6c1Timo Sirainen /* Ideally o_stream_finish() would be called for all non-failed
5ec4fc44e8d4e2160f07b1a7f4fce1ccfec3f6c1Timo Sirainen ostreams, but strictly requiring it would cause unnecessary
5ec4fc44e8d4e2160f07b1a7f4fce1ccfec3f6c1Timo Sirainen complexity for many callers. Just require that at this point
5ec4fc44e8d4e2160f07b1a7f4fce1ccfec3f6c1Timo Sirainen after flushing there isn't anything in the output buffer or that
5ec4fc44e8d4e2160f07b1a7f4fce1ccfec3f6c1Timo Sirainen we're ignoring all errors. */
5ec4fc44e8d4e2160f07b1a7f4fce1ccfec3f6c1Timo Sirainen if (o_stream_flush(stream) == 0)
5ec4fc44e8d4e2160f07b1a7f4fce1ccfec3f6c1Timo Sirainen i_assert(stream->real_stream->error_handling_disabled);
5ec4fc44e8d4e2160f07b1a7f4fce1ccfec3f6c1Timo Sirainen
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen if (!stream->closed && !stream->real_stream->closing) {
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen /* first mark the stream as being closed so the
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen o_stream_copy_error_from_parent() won't recurse us back
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen here. but don't immediately mark the stream closed, because
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen we may still want to write something to it. */
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen stream->real_stream->closing = TRUE;
59e26ff34b05cd971a111f8a42fc60c13d9f688bTimo Sirainen io_stream_close(&stream->real_stream->iostream, close_parents);
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen stream->closed = TRUE;
2d2ebe91d56e9a158de000c9d0026f65600fbcfaTimo Sirainen }
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
f988b93c2ef773987bcdcbfb4cca39b955e3a392Timo Sirainen if (stream->stream_errno == 0)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen stream->stream_errno = EPIPE;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen}
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainenvoid o_stream_destroy(struct ostream **stream)
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen{
d6684856fb99e51bc22a6346e08b2d81c996f963Josef 'Jeff' Sipek if (*stream == NULL)
d6684856fb99e51bc22a6346e08b2d81c996f963Josef 'Jeff' Sipek return;
d6684856fb99e51bc22a6346e08b2d81c996f963Josef 'Jeff' Sipek
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen o_stream_close_full(*stream, FALSE);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen o_stream_unref(stream);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen}
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid o_stream_ref(struct ostream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen io_stream_ref(&stream->real_stream->iostream);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenvoid o_stream_unref(struct ostream **_stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek struct ostream *stream;
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek if (*_stream == NULL)
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek return;
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipek stream = *_stream;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
571fd6ff94570ee11a72a20b649acfdac2495919Timo Sirainen if (stream->real_stream->last_errors_not_checked &&
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen !stream->real_stream->error_handling_disabled &&
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen stream->real_stream->iostream.refcount == 1) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen i_panic("output stream %s is missing error handling",
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_get_name(stream));
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
5a1b498b646b5c5dbd1b3f3861df766f560578c5Timo Sirainen if (!io_stream_unref(&stream->real_stream->iostream))
5a1b498b646b5c5dbd1b3f3861df766f560578c5Timo Sirainen io_stream_free(&stream->real_stream->iostream);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen *_stream = NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen#undef o_stream_add_destroy_callback
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainenvoid o_stream_add_destroy_callback(struct ostream *stream,
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen ostream_callback_t *callback, void *context)
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen{
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen io_stream_add_destroy_callback(&stream->real_stream->iostream,
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen callback, context);
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen}
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainenvoid o_stream_remove_destroy_callback(struct ostream *stream,
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen void (*callback)())
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen{
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen io_stream_remove_destroy_callback(&stream->real_stream->iostream,
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen callback);
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen}
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid o_stream_close(struct ostream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
660ecbaf80e6b3cf3a70ed1e0cdf7f8af6d895d0Josef 'Jeff' Sipek if (stream != NULL)
660ecbaf80e6b3cf3a70ed1e0cdf7f8af6d895d0Josef 'Jeff' Sipek o_stream_close_full(stream, TRUE);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen#undef o_stream_set_flush_callback
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenvoid o_stream_set_flush_callback(struct ostream *stream,
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen stream_flush_callback_t *callback,
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen void *context)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct ostream_private *_stream = stream->real_stream;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen _stream->set_flush_callback(_stream, callback, context);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainenvoid o_stream_unset_flush_callback(struct ostream *stream)
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen{
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen struct ostream_private *_stream = stream->real_stream;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen _stream->set_flush_callback(_stream, NULL, NULL);
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen}
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid o_stream_set_max_buffer_size(struct ostream *stream, size_t max_size)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen io_stream_set_max_buffer_size(&stream->real_stream->iostream, max_size);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainensize_t o_stream_get_max_buffer_size(struct ostream *stream)
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainen{
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainen return stream->real_stream->max_buffer_size;
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainen}
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenvoid o_stream_cork(struct ostream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct ostream_private *_stream = stream->real_stream;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen _stream->cork(_stream, TRUE);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenvoid o_stream_uncork(struct ostream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct ostream_private *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen _stream->cork(_stream, FALSE);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainenbool o_stream_is_corked(struct ostream *stream)
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen{
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen struct ostream_private *_stream = stream->real_stream;
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen return _stream->corked;
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen}
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenint o_stream_flush(struct ostream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct ostream_private *_stream = stream->real_stream;
8f32e59200da904613506f5649ffa4d9f5989cebTimo Sirainen int ret = 1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
34d5077c37dc6224a2d430a72ae51a3f38e9e4f6Timo Sirainen o_stream_ignore_last_errors(stream);
34d5077c37dc6224a2d430a72ae51a3f38e9e4f6Timo Sirainen
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen errno = stream->stream_errno;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
34d5077c37dc6224a2d430a72ae51a3f38e9e4f6Timo Sirainen if (unlikely(_stream->noverflow)) {
34d5077c37dc6224a2d430a72ae51a3f38e9e4f6Timo Sirainen io_stream_set_error(&_stream->iostream,
34d5077c37dc6224a2d430a72ae51a3f38e9e4f6Timo Sirainen "Output stream buffer was full (%"PRIuSIZE_T" bytes)",
34d5077c37dc6224a2d430a72ae51a3f38e9e4f6Timo Sirainen o_stream_get_max_buffer_size(stream));
34d5077c37dc6224a2d430a72ae51a3f38e9e4f6Timo Sirainen errno = stream->stream_errno = ENOBUFS;
34d5077c37dc6224a2d430a72ae51a3f38e9e4f6Timo Sirainen return -1;
34d5077c37dc6224a2d430a72ae51a3f38e9e4f6Timo Sirainen }
34d5077c37dc6224a2d430a72ae51a3f38e9e4f6Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (unlikely((ret = _stream->flush(_stream)) < 0)) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen i_assert(stream->stream_errno != 0);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen errno = stream->stream_errno;
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen }
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen return ret;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenvoid o_stream_set_flush_pending(struct ostream *stream, bool set)
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct ostream_private *_stream = stream->real_stream;
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen return;
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen _stream->flush_pending(_stream, set);
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen}
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainensize_t o_stream_get_buffer_used_size(const struct ostream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen const struct ostream_private *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return _stream->get_used_size(_stream);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainensize_t o_stream_get_buffer_avail_size(const struct ostream *stream)
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen{
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen size_t used = o_stream_get_buffer_used_size(stream);
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen return stream->real_stream->max_buffer_size <= used ? 0 :
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen stream->real_stream->max_buffer_size - used;
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen}
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenint o_stream_seek(struct ostream *stream, uoff_t offset)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct ostream_private *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen errno = stream->stream_errno;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (unlikely(_stream->seek(_stream, offset) < 0)) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen i_assert(stream->stream_errno != 0);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen errno = stream->stream_errno;
8f32e59200da904613506f5649ffa4d9f5989cebTimo Sirainen return -1;
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen }
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen return 1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
b92e979748a22925b0770d3004eaab043ed69574Timo Sirainenssize_t o_stream_send(struct ostream *stream, const void *data, size_t size)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen struct const_iovec iov;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&iov);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen iov.iov_base = data;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen iov.iov_len = size;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen return o_stream_sendv(stream, &iov, 1);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainenstatic ssize_t
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Siraineno_stream_sendv_int(struct ostream *stream, const struct const_iovec *iov,
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen unsigned int iov_count, bool *overflow_r)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct ostream_private *_stream = stream->real_stream;
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen unsigned int i;
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen size_t total_size;
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen ssize_t ret;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen *overflow_r = FALSE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen for (i = 0, total_size = 0; i < iov_count; i++)
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen total_size += iov[i].iov_len;
0dbcf4026ff8471b4d6d2e14f7e52321396bf087Timo Sirainen if (total_size == 0)
0dbcf4026ff8471b4d6d2e14f7e52321396bf087Timo Sirainen return 0;
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen
84717f00ddbf5cd0ebe3f285090d5e97e458e19cTimo Sirainen i_assert(!_stream->finished);
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen ret = _stream->sendv(_stream, iov, iov_count);
f8b6c3d6bc9d63665af5e0a3c8b604438e4c3a4eTimo Sirainen if (ret > 0)
f8b6c3d6bc9d63665af5e0a3c8b604438e4c3a4eTimo Sirainen stream->real_stream->last_write_timeval = ioloop_timeval;
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen if (unlikely(ret != (ssize_t)total_size)) {
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen if (ret < 0) {
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen i_assert(stream->stream_errno != 0);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen errno = stream->stream_errno;
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen } else {
8b2cf1c1bd8ddcea0525b62fd35ba76e136828a1Timo Sirainen i_assert(!stream->blocking);
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen stream->overflow = TRUE;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen *overflow_r = TRUE;
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen }
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen }
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen return ret;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainenssize_t o_stream_sendv(struct ostream *stream, const struct const_iovec *iov,
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen unsigned int iov_count)
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen{
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen bool overflow;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen errno = stream->stream_errno;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen return -1;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen }
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen return o_stream_sendv_int(stream, iov, iov_count, &overflow);
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen}
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen
b92e979748a22925b0770d3004eaab043ed69574Timo Sirainenssize_t o_stream_send_str(struct ostream *stream, const char *str)
555ebb032f9b8f0cdb66f27ce7374734833e7cacTimo Sirainen{
555ebb032f9b8f0cdb66f27ce7374734833e7cacTimo Sirainen return o_stream_send(stream, str, strlen(str));
555ebb032f9b8f0cdb66f27ce7374734833e7cacTimo Sirainen}
555ebb032f9b8f0cdb66f27ce7374734833e7cacTimo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenvoid o_stream_nsend(struct ostream *stream, const void *data, size_t size)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen{
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen struct const_iovec iov;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&iov);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen iov.iov_base = data;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen iov.iov_len = size;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
4e8d6d03c2ff85448df79b181a2ea850fb5d4199Timo Sirainen o_stream_nsendv(stream, &iov, 1);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen}
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenvoid o_stream_nsendv(struct ostream *stream, const struct const_iovec *iov,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen unsigned int iov_count)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen{
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen bool overflow;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0 ||
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen stream->real_stream->noverflow))
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen (void)o_stream_sendv_int(stream, iov, iov_count, &overflow);
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen if (overflow)
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen stream->real_stream->noverflow = TRUE;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen stream->real_stream->last_errors_not_checked = TRUE;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen}
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenvoid o_stream_nsend_str(struct ostream *stream, const char *str)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen{
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(stream, str, strlen(str));
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen}
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
84717f00ddbf5cd0ebe3f285090d5e97e458e19cTimo Sirainenint o_stream_finish(struct ostream *stream)
84717f00ddbf5cd0ebe3f285090d5e97e458e19cTimo Sirainen{
84717f00ddbf5cd0ebe3f285090d5e97e458e19cTimo Sirainen stream->real_stream->finished = TRUE;
84717f00ddbf5cd0ebe3f285090d5e97e458e19cTimo Sirainen return o_stream_flush(stream);
84717f00ddbf5cd0ebe3f285090d5e97e458e19cTimo Sirainen}
84717f00ddbf5cd0ebe3f285090d5e97e458e19cTimo Sirainen
d6193a892452ae87548f5745dada01f82816765dTimo Sirainenvoid o_stream_set_finish_also_parent(struct ostream *stream, bool set)
d6193a892452ae87548f5745dada01f82816765dTimo Sirainen{
d6193a892452ae87548f5745dada01f82816765dTimo Sirainen stream->real_stream->finish_also_parent = set;
d6193a892452ae87548f5745dada01f82816765dTimo Sirainen}
d6193a892452ae87548f5745dada01f82816765dTimo Sirainen
d6193a892452ae87548f5745dada01f82816765dTimo Sirainenvoid o_stream_set_finish_via_child(struct ostream *stream, bool set)
d6193a892452ae87548f5745dada01f82816765dTimo Sirainen{
d6193a892452ae87548f5745dada01f82816765dTimo Sirainen stream->real_stream->finish_via_child = set;
d6193a892452ae87548f5745dada01f82816765dTimo Sirainen}
d6193a892452ae87548f5745dada01f82816765dTimo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenvoid o_stream_ignore_last_errors(struct ostream *stream)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen{
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen while (stream != NULL) {
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen stream->real_stream->last_errors_not_checked = FALSE;
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen stream = stream->real_stream->parent;
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen}
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
7660a5183e89459d255dc5873894ff08806711d5Timo Sirainenvoid o_stream_abort(struct ostream *stream)
7660a5183e89459d255dc5873894ff08806711d5Timo Sirainen{
7660a5183e89459d255dc5873894ff08806711d5Timo Sirainen o_stream_ignore_last_errors(stream);
7660a5183e89459d255dc5873894ff08806711d5Timo Sirainen if (stream->stream_errno != 0)
7660a5183e89459d255dc5873894ff08806711d5Timo Sirainen return;
7660a5183e89459d255dc5873894ff08806711d5Timo Sirainen io_stream_set_error(&stream->real_stream->iostream, "aborted writing");
7660a5183e89459d255dc5873894ff08806711d5Timo Sirainen stream->stream_errno = EPIPE;
7660a5183e89459d255dc5873894ff08806711d5Timo Sirainen}
7660a5183e89459d255dc5873894ff08806711d5Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenvoid o_stream_set_no_error_handling(struct ostream *stream, bool set)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen{
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen stream->real_stream->error_handling_disabled = set;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen}
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainenenum ostream_send_istream_result
378e6cb162b355d6f103526505bc00b9a78962e7Timo Siraineno_stream_send_istream(struct ostream *outstream, struct istream *instream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct ostream_private *_outstream = outstream->real_stream;
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen uoff_t old_outstream_offset = outstream->offset;
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen uoff_t old_instream_offset = instream->v_offset;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen enum ostream_send_istream_result res;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if (unlikely(instream->closed || instream->stream_errno != 0)) {
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen errno = instream->stream_errno;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen }
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if (unlikely(outstream->closed || outstream->stream_errno != 0)) {
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen errno = outstream->stream_errno;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT;
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen }
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
84717f00ddbf5cd0ebe3f285090d5e97e458e19cTimo Sirainen i_assert(!_outstream->finished);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen res = _outstream->send_istream(_outstream, instream);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen switch (res) {
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_assert(instream->stream_errno == 0);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_assert(outstream->stream_errno == 0);
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen i_assert(!i_stream_have_bytes_left(instream));
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen break;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_assert(!instream->blocking);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen break;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_assert(!outstream->blocking);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen o_stream_set_flush_pending(outstream, TRUE);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen break;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_assert(instream->stream_errno != 0);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return res;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_assert(outstream->stream_errno != 0);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return res;
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen }
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen /* non-failure - make sure stream offsets match */
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen i_assert((outstream->offset - old_outstream_offset) ==
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen (instream->v_offset - old_instream_offset));
f8b6c3d6bc9d63665af5e0a3c8b604438e4c3a4eTimo Sirainen
f8b6c3d6bc9d63665af5e0a3c8b604438e4c3a4eTimo Sirainen if (outstream->offset != old_outstream_offset)
f8b6c3d6bc9d63665af5e0a3c8b604438e4c3a4eTimo Sirainen outstream->real_stream->last_write_timeval = ioloop_timeval;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return res;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainenvoid o_stream_nsend_istream(struct ostream *outstream, struct istream *instream)
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen{
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_assert(instream->blocking);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen switch (o_stream_send_istream(outstream, instream)) {
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen break;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_unreached();
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen outstream->real_stream->noverflow = TRUE;
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen break;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen outstream->stream_errno = instream->stream_errno;
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen io_stream_set_error(&outstream->real_stream->iostream,
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen "nsend-istream: read(%s) failed: %s",
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen i_stream_get_name(instream),
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_stream_get_error(instream));
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen break;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen break;
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen }
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen outstream->real_stream->last_errors_not_checked = TRUE;
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen}
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainenint o_stream_pwrite(struct ostream *stream, const void *data, size_t size,
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen uoff_t offset)
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen{
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen int ret;
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen errno = stream->stream_errno;
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen return -1;
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen }
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen
84717f00ddbf5cd0ebe3f285090d5e97e458e19cTimo Sirainen i_assert(!stream->real_stream->finished);
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen ret = stream->real_stream->write_at(stream->real_stream,
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen data, size, offset);
f8b6c3d6bc9d63665af5e0a3c8b604438e4c3a4eTimo Sirainen if (ret > 0)
f8b6c3d6bc9d63665af5e0a3c8b604438e4c3a4eTimo Sirainen stream->real_stream->last_write_timeval = ioloop_timeval;
f8b6c3d6bc9d63665af5e0a3c8b604438e4c3a4eTimo Sirainen else if (unlikely(ret < 0)) {
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen i_assert(stream->stream_errno != 0);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen errno = stream->stream_errno;
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen }
f8b6c3d6bc9d63665af5e0a3c8b604438e4c3a4eTimo Sirainen
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen return ret;
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen}
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen
f8b6c3d6bc9d63665af5e0a3c8b604438e4c3a4eTimo Sirainenvoid o_stream_get_last_write_time(struct ostream *stream, struct timeval *tv_r)
f8b6c3d6bc9d63665af5e0a3c8b604438e4c3a4eTimo Sirainen{
f8b6c3d6bc9d63665af5e0a3c8b604438e4c3a4eTimo Sirainen *tv_r = stream->real_stream->last_write_timeval;
f8b6c3d6bc9d63665af5e0a3c8b604438e4c3a4eTimo Sirainen}
f8b6c3d6bc9d63665af5e0a3c8b604438e4c3a4eTimo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainenenum ostream_send_istream_result
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainenio_stream_copy(struct ostream *outstream, struct istream *instream)
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen{
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen struct const_iovec iov;
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen const unsigned char *data;
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen ssize_t ret;
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen while (i_stream_read_more(instream, &data, &iov.iov_len) > 0) {
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen iov.iov_base = data;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if ((ret = o_stream_sendv(outstream, &iov, 1)) < 0)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen else if (ret == 0)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT;
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen i_stream_skip(instream, ret);
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen }
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen if (instream->stream_errno != 0)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if (i_stream_have_bytes_left(instream))
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return OSTREAM_SEND_ISTREAM_RESULT_FINISHED;
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen}
71da447014454c84828d9dface77219875554d7dTimo Sirainen
8aa8399893c66b40e2790a4568256807a6ec6742Stephan Boschvoid o_stream_switch_ioloop_to(struct ostream *stream, struct ioloop *ioloop)
71da447014454c84828d9dface77219875554d7dTimo Sirainen{
71da447014454c84828d9dface77219875554d7dTimo Sirainen struct ostream_private *_stream = stream->real_stream;
71da447014454c84828d9dface77219875554d7dTimo Sirainen
8aa8399893c66b40e2790a4568256807a6ec6742Stephan Bosch io_stream_switch_ioloop_to(&_stream->iostream, ioloop);
8aa8399893c66b40e2790a4568256807a6ec6742Stephan Bosch
8aa8399893c66b40e2790a4568256807a6ec6742Stephan Bosch _stream->switch_ioloop_to(_stream, ioloop);
8aa8399893c66b40e2790a4568256807a6ec6742Stephan Bosch}
b3b813a6473d1210eee94bd60eaa6bafd2131ed3Stephan Bosch
8aa8399893c66b40e2790a4568256807a6ec6742Stephan Boschvoid o_stream_switch_ioloop(struct ostream *stream)
8aa8399893c66b40e2790a4568256807a6ec6742Stephan Bosch{
8aa8399893c66b40e2790a4568256807a6ec6742Stephan Bosch o_stream_switch_ioloop_to(stream, current_ioloop);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstatic void o_stream_default_close(struct iostream_private *stream,
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen bool close_parent)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct ostream_private *_stream = (struct ostream_private *)stream;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen (void)o_stream_flush(&_stream->ostream);
9a84b90d894a741ae6e090de104d31382a41d0aaJosef 'Jeff' Sipek if (close_parent)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen o_stream_close(_stream->parent);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic void o_stream_default_destroy(struct iostream_private *stream)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct ostream_private *_stream = (struct ostream_private *)stream;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
204ee6ed414f5e4eeb6f6c10763b55daf56f11acJosef 'Jeff' Sipek o_stream_unref(&_stream->parent);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic void
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Siraineno_stream_default_set_max_buffer_size(struct iostream_private *stream,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen size_t max_size)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct ostream_private *_stream = (struct ostream_private *)stream;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (_stream->parent != NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen o_stream_set_max_buffer_size(_stream->parent, max_size);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen _stream->max_buffer_size = max_size;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic void o_stream_default_cork(struct ostream_private *_stream, bool set)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen _stream->corked = set;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (set) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (_stream->parent != NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen o_stream_cork(_stream->parent);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen } else {
b688884f23be2333bea1a8bd4ee849336aebedaaTimo Sirainen (void)o_stream_flush(&_stream->ostream);
b688884f23be2333bea1a8bd4ee849336aebedaaTimo Sirainen _stream->last_errors_not_checked = TRUE;
b688884f23be2333bea1a8bd4ee849336aebedaaTimo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (_stream->parent != NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen o_stream_uncork(_stream->parent);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid o_stream_copy_error_from_parent(struct ostream_private *_stream)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct ostream *src = _stream->parent;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct ostream *dest = &_stream->ostream;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen dest->stream_errno = src->stream_errno;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen dest->overflow = src->overflow;
2d2ebe91d56e9a158de000c9d0026f65600fbcfaTimo Sirainen if (src->closed)
2d2ebe91d56e9a158de000c9d0026f65600fbcfaTimo Sirainen o_stream_close(dest);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainenint o_stream_flush_parent_if_needed(struct ostream_private *_stream)
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen{
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen if (o_stream_get_buffer_used_size(_stream->parent) >= IO_BLOCK_SIZE) {
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen /* we already have quite a lot of data in parent stream.
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen unless we can flush it, don't add any more to it or we
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen could keep wasting memory by just increasing the buffer
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen size all the time. */
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen if (o_stream_flush(_stream->parent) < 0) {
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen o_stream_copy_error_from_parent(_stream);
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen return -1;
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen }
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen if (o_stream_get_buffer_used_size(_stream->parent) >= IO_BLOCK_SIZE)
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen return 0;
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen }
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen return 1;
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen}
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen
5df4dbc38d7b7d54cba35a2c258366e1d4bac3c8Timo Sirainenint o_stream_flush_parent(struct ostream_private *_stream)
5df4dbc38d7b7d54cba35a2c258366e1d4bac3c8Timo Sirainen{
5df4dbc38d7b7d54cba35a2c258366e1d4bac3c8Timo Sirainen int ret;
5df4dbc38d7b7d54cba35a2c258366e1d4bac3c8Timo Sirainen
5df4dbc38d7b7d54cba35a2c258366e1d4bac3c8Timo Sirainen i_assert(_stream->parent != NULL);
5df4dbc38d7b7d54cba35a2c258366e1d4bac3c8Timo Sirainen
d6193a892452ae87548f5745dada01f82816765dTimo Sirainen if (!_stream->finished || !_stream->finish_also_parent ||
d6193a892452ae87548f5745dada01f82816765dTimo Sirainen !_stream->parent->real_stream->finish_via_child)
5df4dbc38d7b7d54cba35a2c258366e1d4bac3c8Timo Sirainen ret = o_stream_flush(_stream->parent);
5df4dbc38d7b7d54cba35a2c258366e1d4bac3c8Timo Sirainen else
5df4dbc38d7b7d54cba35a2c258366e1d4bac3c8Timo Sirainen ret = o_stream_finish(_stream->parent);
5df4dbc38d7b7d54cba35a2c258366e1d4bac3c8Timo Sirainen if (ret < 0)
5df4dbc38d7b7d54cba35a2c258366e1d4bac3c8Timo Sirainen o_stream_copy_error_from_parent(_stream);
5df4dbc38d7b7d54cba35a2c258366e1d4bac3c8Timo Sirainen return ret;
5df4dbc38d7b7d54cba35a2c258366e1d4bac3c8Timo Sirainen}
5df4dbc38d7b7d54cba35a2c258366e1d4bac3c8Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic int o_stream_default_flush(struct ostream_private *_stream)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (_stream->parent == NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return 1;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
8109f3187f5ece5565de1813209af42dc7bb768bTimo Sirainen return o_stream_flush_parent(_stream);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic void
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Siraineno_stream_default_set_flush_callback(struct ostream_private *_stream,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen stream_flush_callback_t *callback,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen void *context)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen if (_stream->parent != NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen o_stream_set_flush_callback(_stream->parent, callback, context);
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen _stream->callback = callback;
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen _stream->context = context;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic void
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Siraineno_stream_default_set_flush_pending(struct ostream_private *_stream, bool set)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (_stream->parent != NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen o_stream_set_flush_pending(_stream->parent, set);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic size_t
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Siraineno_stream_default_get_used_size(const struct ostream_private *_stream)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (_stream->parent == NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return 0;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen else
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return o_stream_get_buffer_used_size(_stream->parent);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic int
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Siraineno_stream_default_seek(struct ostream_private *_stream,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen uoff_t offset ATTR_UNUSED)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
d78be924ad150840e018eda6a8a7d5e46a39bda2Timo Sirainen _stream->ostream.stream_errno = ESPIPE;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return -1;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainenstatic ssize_t
981139bb2e446bb2050c1158614725f8413fd709Timo Siraineno_stream_default_sendv(struct ostream_private *stream,
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen const struct const_iovec *iov, unsigned int iov_count)
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen{
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen ssize_t ret;
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen if ((ret = o_stream_sendv(stream->parent, iov, iov_count)) < 0) {
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen o_stream_copy_error_from_parent(stream);
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen return -1;
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen }
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen stream->ostream.offset += ret;
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen return ret;
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen}
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic int
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Siraineno_stream_default_write_at(struct ostream_private *_stream,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen const void *data ATTR_UNUSED,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen size_t size ATTR_UNUSED, uoff_t offset ATTR_UNUSED)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
d78be924ad150840e018eda6a8a7d5e46a39bda2Timo Sirainen _stream->ostream.stream_errno = ESPIPE;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return -1;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainenstatic enum ostream_send_istream_result
378e6cb162b355d6f103526505bc00b9a78962e7Timo Siraineno_stream_default_send_istream(struct ostream_private *outstream,
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen struct istream *instream)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
46631c1d903c409444b1b1c4a1d41a033c09ee37Timo Sirainen return io_stream_copy(&outstream->ostream, instream);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
8aa8399893c66b40e2790a4568256807a6ec6742Stephan Boschstatic void
8aa8399893c66b40e2790a4568256807a6ec6742Stephan Boscho_stream_default_switch_ioloop_to(struct ostream_private *_stream,
8aa8399893c66b40e2790a4568256807a6ec6742Stephan Bosch struct ioloop *ioloop)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (_stream->parent != NULL)
8aa8399893c66b40e2790a4568256807a6ec6742Stephan Bosch o_stream_switch_ioloop_to(_stream->parent, ioloop);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstruct ostream *
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Siraineno_stream_create(struct ostream_private *_stream, struct ostream *parent, int fd)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
d6193a892452ae87548f5745dada01f82816765dTimo Sirainen _stream->finish_also_parent = TRUE;
d6193a892452ae87548f5745dada01f82816765dTimo Sirainen _stream->finish_via_child = TRUE;
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen _stream->fd = fd;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen _stream->ostream.real_stream = _stream;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (parent != NULL) {
8b2cf1c1bd8ddcea0525b62fd35ba76e136828a1Timo Sirainen _stream->ostream.blocking = parent->blocking;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen _stream->parent = parent;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen o_stream_ref(parent);
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen _stream->callback = parent->real_stream->callback;
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen _stream->context = parent->real_stream->context;
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen _stream->max_buffer_size = parent->real_stream->max_buffer_size;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen _stream->error_handling_disabled =
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen parent->real_stream->error_handling_disabled;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (_stream->iostream.close == NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen _stream->iostream.close = o_stream_default_close;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (_stream->iostream.destroy == NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen _stream->iostream.destroy = o_stream_default_destroy;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (_stream->iostream.set_max_buffer_size == NULL) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen _stream->iostream.set_max_buffer_size =
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen o_stream_default_set_max_buffer_size;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (_stream->cork == NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen _stream->cork = o_stream_default_cork;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (_stream->flush == NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen _stream->flush = o_stream_default_flush;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (_stream->set_flush_callback == NULL) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen _stream->set_flush_callback =
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen o_stream_default_set_flush_callback;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (_stream->flush_pending == NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen _stream->flush_pending = o_stream_default_set_flush_pending;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (_stream->get_used_size == NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen _stream->get_used_size = o_stream_default_get_used_size;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (_stream->seek == NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen _stream->seek = o_stream_default_seek;
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen if (_stream->sendv == NULL)
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen _stream->sendv = o_stream_default_sendv;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (_stream->write_at == NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen _stream->write_at = o_stream_default_write_at;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (_stream->send_istream == NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen _stream->send_istream = o_stream_default_send_istream;
8aa8399893c66b40e2790a4568256807a6ec6742Stephan Bosch if (_stream->switch_ioloop_to == NULL)
8aa8399893c66b40e2790a4568256807a6ec6742Stephan Bosch _stream->switch_ioloop_to = o_stream_default_switch_ioloop_to;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen io_stream_init(&_stream->iostream);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return &_stream->ostream;
71da447014454c84828d9dface77219875554d7dTimo Sirainen}
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainenstruct ostream *o_stream_create_error(int stream_errno)
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen{
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen struct ostream_private *stream;
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen struct ostream *output;
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen stream = i_new(struct ostream_private, 1);
8b2cf1c1bd8ddcea0525b62fd35ba76e136828a1Timo Sirainen stream->ostream.blocking = TRUE;
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen stream->ostream.closed = TRUE;
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen stream->ostream.stream_errno = stream_errno;
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen output = o_stream_create(stream, NULL, -1);
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen o_stream_set_no_error_handling(output, TRUE);
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen o_stream_set_name(output, "(error)");
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen return output;
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen}
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainenstruct ostream *
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Siraineno_stream_create_error_str(int stream_errno, const char *fmt, ...)
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen{
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen struct ostream *output;
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen va_list args;
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen va_start(args, fmt);
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen output = o_stream_create_error(stream_errno);
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen io_stream_set_verror(&output->real_stream->iostream, fmt, args);
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen va_end(args);
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen return output;
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen}
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainenstruct ostream *o_stream_create_passthrough(struct ostream *output)
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen{
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen struct ostream_private *stream;
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen stream = i_new(struct ostream_private, 1);
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen return o_stream_create(stream, output, o_stream_get_fd(output));
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen}