ostream.c revision 46631c1d903c409444b1b1c4a1d41a033c09ee37
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2014 Dovecot authors, see the included COPYING file */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "lib.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "istream.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "ostream-private.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenvoid o_stream_set_name(struct ostream *stream, const char *name)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_free(stream->real_stream->iostream.name);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen stream->real_stream->iostream.name = i_strdup(name);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenconst char *o_stream_get_name(struct ostream *stream)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen while (stream->real_stream->iostream.name == NULL) {
0db42260be85e797aa9909a29b20296996f52e75Timo Sirainen stream = stream->real_stream->parent;
0db42260be85e797aa9909a29b20296996f52e75Timo Sirainen if (stream == NULL)
0db42260be85e797aa9909a29b20296996f52e75Timo Sirainen return "";
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return stream->real_stream->iostream.name;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenint o_stream_get_fd(struct ostream *stream)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return stream->real_stream->fd;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenconst char *o_stream_get_error(struct ostream *stream)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct ostream *s;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* we'll only return errors for streams that have stream_errno set.
46e917c9fa05cbe7bddf805d3a9838b61e3960e1Timo Sirainen we might be returning unintended error otherwise. */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (stream->stream_errno == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return "<no error>";
95d62f8d6d281cc488dc4f488d4388701e559012Josef 'Jeff' Sipek
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen for (s = stream; s != NULL; s = s->real_stream->parent) {
46e917c9fa05cbe7bddf805d3a9838b61e3960e1Timo Sirainen if (s->stream_errno == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (s->real_stream->iostream.error != NULL)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return s->real_stream->iostream.error;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
b49aa341d28c0eec1229e30baa2f89d5bae52ff8Phil Carmody return strerror(stream->stream_errno);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic void o_stream_close_full(struct ostream *stream, bool close_parents)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (!stream->closed && !stream->real_stream->closing) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* first mark the stream as being closed so the
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen o_stream_copy_error_from_parent() won't recurse us back
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen here. but don't immediately mark the stream closed, because
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen we may still want to write something to it. */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen stream->real_stream->closing = TRUE;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen io_stream_close(&stream->real_stream->iostream, close_parents);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen stream->closed = TRUE;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch if (stream->stream_errno == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen stream->stream_errno = EPIPE;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
0ca3b9cb0f2a322a25ce7f229dc3d3a0b46be17bTimo Sirainenvoid o_stream_destroy(struct ostream **stream)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen o_stream_close_full(*stream, FALSE);
7a88e726e7300fb0273cb4e55b43c27fbd90bdbdTimo Sirainen o_stream_unref(stream);
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenvoid o_stream_ref(struct ostream *stream)
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen io_stream_ref(&stream->real_stream->iostream);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenvoid o_stream_unref(struct ostream **_stream)
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct ostream *stream = *_stream;
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen
56d1345c43bbd28c36b7faa85e4163bd9e874290Timo Sirainen if (stream->real_stream->last_errors_not_checked &&
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen !stream->real_stream->error_handling_disabled &&
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen stream->real_stream->iostream.refcount == 1) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_panic("output stream %s is missing error handling",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen o_stream_get_name(stream));
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen io_stream_unref(&stream->real_stream->iostream);
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen *_stream = NULL;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenvoid o_stream_close(struct ostream *stream)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen o_stream_close_full(stream, TRUE);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#undef o_stream_set_flush_callback
56aa97d74071f3a2987140c2ff1cfd5a59cb35aaTimo Sirainenvoid o_stream_set_flush_callback(struct ostream *stream,
56aa97d74071f3a2987140c2ff1cfd5a59cb35aaTimo Sirainen stream_flush_callback_t *callback,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen void *context)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct ostream_private *_stream = stream->real_stream;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen _stream->set_flush_callback(_stream, callback, context);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenvoid o_stream_unset_flush_callback(struct ostream *stream)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct ostream_private *_stream = stream->real_stream;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen _stream->set_flush_callback(_stream, NULL, NULL);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenvoid o_stream_set_max_buffer_size(struct ostream *stream, size_t max_size)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen io_stream_set_max_buffer_size(&stream->real_stream->iostream, max_size);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainensize_t o_stream_get_max_buffer_size(struct ostream *stream)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return stream->real_stream->max_buffer_size;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
95d62f8d6d281cc488dc4f488d4388701e559012Josef 'Jeff' Sipek
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenvoid o_stream_cork(struct ostream *stream)
8c909e451d14075c05d90382cf8eebc4e354f569Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct ostream_private *_stream = stream->real_stream;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (unlikely(stream->closed))
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen _stream->cork(_stream, TRUE);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenvoid o_stream_uncork(struct ostream *stream)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct ostream_private *_stream = stream->real_stream;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (unlikely(stream->closed))
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen _stream->cork(_stream, FALSE);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenbool o_stream_is_corked(struct ostream *stream)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct ostream_private *_stream = stream->real_stream;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return _stream->corked;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic void o_stream_clear_error(struct ostream *stream)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen stream->stream_errno = 0;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_free_and_null(stream->real_stream->iostream.error);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenint o_stream_flush(struct ostream *stream)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct ostream_private *_stream = stream->real_stream;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen int ret = 1;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (unlikely(stream->closed)) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen errno = stream->stream_errno;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return -1;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen o_stream_clear_error(stream);
95d62f8d6d281cc488dc4f488d4388701e559012Josef 'Jeff' Sipek if (unlikely((ret = _stream->flush(_stream)) < 0)) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_assert(stream->stream_errno != 0);
9a1f68e5ab08eabd352d533315cba1c69006e2c1Timo Sirainen stream->last_failed_errno = stream->stream_errno;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen errno = stream->stream_errno;
bdb026e2dc8a7c77585ed5ba489f0056df8074d4Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return ret;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenvoid o_stream_set_flush_pending(struct ostream *stream, bool set)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct ostream_private *_stream = stream->real_stream;
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (unlikely(stream->closed))
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return;
60d1fdf2c17fd0c7020234590dbd73da81c3ce8fTimo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen _stream->flush_pending(_stream, set);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainensize_t o_stream_get_buffer_used_size(const struct ostream *stream)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
95d62f8d6d281cc488dc4f488d4388701e559012Josef 'Jeff' Sipek const struct ostream_private *_stream = stream->real_stream;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
c69a177207ed18d0f0210347430a60957136bd6cJosef 'Jeff' Sipek return _stream->get_used_size(_stream);
5cdb246858f37469fe61351dbc147dabbdde342cTimo Sirainen}
5cdb246858f37469fe61351dbc147dabbdde342cTimo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainensize_t o_stream_get_buffer_avail_size(const struct ostream *stream)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen size_t used = o_stream_get_buffer_used_size(stream);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return stream->real_stream->max_buffer_size <= used ? 0 :
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen stream->real_stream->max_buffer_size - used;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenint o_stream_seek(struct ostream *stream, uoff_t offset)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct ostream_private *_stream = stream->real_stream;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (unlikely(stream->closed)) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen errno = stream->stream_errno;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return -1;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen o_stream_clear_error(stream);
5d4a0dac041964a04405bc6b94de51315ca917afTimo Sirainen if (unlikely(_stream->seek(_stream, offset) < 0)) {
5d4a0dac041964a04405bc6b94de51315ca917afTimo Sirainen i_assert(stream->stream_errno != 0);
5d4a0dac041964a04405bc6b94de51315ca917afTimo Sirainen stream->last_failed_errno = stream->stream_errno;
5d4a0dac041964a04405bc6b94de51315ca917afTimo Sirainen errno = stream->stream_errno;
5d4a0dac041964a04405bc6b94de51315ca917afTimo Sirainen return -1;
5d4a0dac041964a04405bc6b94de51315ca917afTimo Sirainen }
5d4a0dac041964a04405bc6b94de51315ca917afTimo Sirainen return 1;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainenssize_t o_stream_send(struct ostream *stream, const void *data, size_t size)
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen{
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen struct const_iovec iov;
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen
95d62f8d6d281cc488dc4f488d4388701e559012Josef 'Jeff' Sipek memset(&iov, 0, sizeof(iov));
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen iov.iov_base = data;
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen iov.iov_len = size;
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen return o_stream_sendv(stream, &iov, 1);
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen}
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainenssize_t o_stream_sendv(struct ostream *stream, const struct const_iovec *iov,
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen unsigned int iov_count)
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen{
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen struct ostream_private *_stream = stream->real_stream;
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen unsigned int i;
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen size_t total_size;
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen ssize_t ret;
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen if (unlikely(stream->closed)) {
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen errno = stream->stream_errno;
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen return -1;
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen }
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen o_stream_clear_error(stream);
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen for (i = 0, total_size = 0; i < iov_count; i++)
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen total_size += iov[i].iov_len;
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen if (total_size == 0)
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen return 0;
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen ret = _stream->sendv(_stream, iov, iov_count);
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen if (unlikely(ret != (ssize_t)total_size)) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (ret < 0) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_assert(stream->stream_errno != 0);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen stream->last_failed_errno = stream->stream_errno;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen errno = stream->stream_errno;
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen } else {
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen stream->overflow = TRUE;
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen }
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen }
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen return ret;
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen}
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainenssize_t o_stream_send_str(struct ostream *stream, const char *str)
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen{
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen return o_stream_send(stream, str, strlen(str));
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen}
1ee74d70bb758637e560d556c7240563967d22c8Timo Sirainen
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainenvoid o_stream_nsend(struct ostream *stream, const void *data, size_t size)
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen{
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen struct const_iovec iov;
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen memset(&iov, 0, sizeof(iov));
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen iov.iov_base = data;
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen iov.iov_len = size;
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen o_stream_nsendv(stream, &iov, 1);
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen}
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainenvoid o_stream_nsendv(struct ostream *stream, const struct const_iovec *iov,
1ee74d70bb758637e560d556c7240563967d22c8Timo Sirainen unsigned int iov_count)
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen{
1ee74d70bb758637e560d556c7240563967d22c8Timo Sirainen if (unlikely(stream->closed))
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen return;
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen (void)o_stream_sendv(stream, iov, iov_count);
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen stream->real_stream->last_errors_not_checked = TRUE;
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen}
1ee74d70bb758637e560d556c7240563967d22c8Timo Sirainen
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainenvoid o_stream_nsend_str(struct ostream *stream, const char *str)
1ee74d70bb758637e560d556c7240563967d22c8Timo Sirainen{
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen o_stream_nsend(stream, str, strlen(str));
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenvoid o_stream_nflush(struct ostream *stream)
95d62f8d6d281cc488dc4f488d4388701e559012Josef 'Jeff' Sipek{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (unlikely(stream->closed))
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen (void)o_stream_flush(stream);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen stream->real_stream->last_errors_not_checked = TRUE;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenint o_stream_nfinish(struct ostream *stream)
e130bb802c8bfb6c6cc44e5c8bc098b4fa5af789Timo Sirainen{
e130bb802c8bfb6c6cc44e5c8bc098b4fa5af789Timo Sirainen o_stream_nflush(stream);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen o_stream_ignore_last_errors(stream);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen errno = stream->last_failed_errno;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return stream->last_failed_errno != 0 ? -1 : 0;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
c6afd726060aae56b6622c6c52aec10231c4bf1cTimo Sirainenvoid o_stream_ignore_last_errors(struct ostream *stream)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen while (stream != NULL) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen stream->real_stream->last_errors_not_checked = FALSE;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen stream = stream->real_stream->parent;
857c471c13ca215f4be9dd4b336b742b8d434e31Timo Sirainen }
857c471c13ca215f4be9dd4b336b742b8d434e31Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenvoid o_stream_set_no_error_handling(struct ostream *stream, bool set)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen stream->real_stream->error_handling_disabled = set;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenoff_t o_stream_send_istream(struct ostream *outstream,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct istream *instream)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct ostream_private *_outstream = outstream->real_stream;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen off_t ret;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (unlikely(outstream->closed || instream->closed)) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen errno = outstream->stream_errno;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return -1;
050acc3755ccc5bcf261a6de3250164a54a0b6f3Timo Sirainen }
cf35bb040d505e2fc333470850c65029992778a4Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen o_stream_clear_error(outstream);
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen ret = _outstream->send_istream(_outstream, instream);
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen if (unlikely(ret < 0)) {
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen i_assert(outstream->stream_errno != 0);
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen outstream->last_failed_errno = outstream->stream_errno;
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen errno = outstream->stream_errno;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return ret;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenint o_stream_pwrite(struct ostream *stream, const void *data, size_t size,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen uoff_t offset)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen int ret;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (unlikely(stream->closed)) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen errno = stream->stream_errno;
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen return -1;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen o_stream_clear_error(stream);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen ret = stream->real_stream->write_at(stream->real_stream,
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen data, size, offset);
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen if (unlikely(ret < 0)) {
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen i_assert(stream->stream_errno != 0);
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen stream->last_failed_errno = stream->stream_errno;
2e708f348f20caa47210cf46cf7654f167fa47bbTimo Sirainen errno = stream->stream_errno;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return ret;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenoff_t io_stream_copy(struct ostream *outstream, struct istream *instream)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen uoff_t start_offset;
struct const_iovec iov;
const unsigned char *data;
ssize_t ret;
start_offset = instream->v_offset;
do {
(void)i_stream_read_data(instream, &data, &iov.iov_len, 0);
if (iov.iov_len == 0) {
/* all sent */
break;
}
iov.iov_base = data;
ret = o_stream_sendv(outstream, &iov, 1);
if (ret <= 0) {
if (ret == 0)
break;
return -1;
}
i_stream_skip(instream, ret);
} while ((size_t)ret == iov.iov_len);
return (off_t)(instream->v_offset - start_offset);
}
void o_stream_switch_ioloop(struct ostream *stream)
{
struct ostream_private *_stream = stream->real_stream;
_stream->switch_ioloop(_stream);
}
static void o_stream_default_close(struct iostream_private *stream,
bool close_parent)
{
struct ostream_private *_stream = (struct ostream_private *)stream;
(void)o_stream_flush(&_stream->ostream);
if (close_parent && _stream->parent != NULL)
o_stream_close(_stream->parent);
}
static void o_stream_default_destroy(struct iostream_private *stream)
{
struct ostream_private *_stream = (struct ostream_private *)stream;
if (_stream->parent != NULL)
o_stream_unref(&_stream->parent);
}
static void
o_stream_default_set_max_buffer_size(struct iostream_private *stream,
size_t max_size)
{
struct ostream_private *_stream = (struct ostream_private *)stream;
if (_stream->parent != NULL)
o_stream_set_max_buffer_size(_stream->parent, max_size);
_stream->max_buffer_size = max_size;
}
static void o_stream_default_cork(struct ostream_private *_stream, bool set)
{
_stream->corked = set;
if (set) {
if (_stream->parent != NULL)
o_stream_cork(_stream->parent);
} else {
(void)o_stream_flush(&_stream->ostream);
if (_stream->parent != NULL)
o_stream_uncork(_stream->parent);
}
}
void o_stream_copy_error_from_parent(struct ostream_private *_stream)
{
struct ostream *src = _stream->parent;
struct ostream *dest = &_stream->ostream;
dest->stream_errno = src->stream_errno;
dest->last_failed_errno = src->last_failed_errno;
dest->overflow = src->overflow;
if (src->closed)
o_stream_close(dest);
}
int o_stream_flush_parent_if_needed(struct ostream_private *_stream)
{
if (o_stream_get_buffer_used_size(_stream->parent) >= IO_BLOCK_SIZE) {
/* we already have quite a lot of data in parent stream.
unless we can flush it, don't add any more to it or we
could keep wasting memory by just increasing the buffer
size all the time. */
if (o_stream_flush(_stream->parent) < 0) {
o_stream_copy_error_from_parent(_stream);
return -1;
}
if (o_stream_get_buffer_used_size(_stream->parent) >= IO_BLOCK_SIZE)
return 0;
}
return 1;
}
static int o_stream_default_flush(struct ostream_private *_stream)
{
int ret;
if (_stream->parent == NULL)
return 1;
if ((ret = o_stream_flush(_stream->parent)) < 0)
o_stream_copy_error_from_parent(_stream);
return ret;
}
static void
o_stream_default_set_flush_callback(struct ostream_private *_stream,
stream_flush_callback_t *callback,
void *context)
{
if (_stream->parent != NULL)
o_stream_set_flush_callback(_stream->parent, callback, context);
_stream->callback = callback;
_stream->context = context;
}
static void
o_stream_default_set_flush_pending(struct ostream_private *_stream, bool set)
{
if (_stream->parent != NULL)
o_stream_set_flush_pending(_stream->parent, set);
}
static size_t
o_stream_default_get_used_size(const struct ostream_private *_stream)
{
if (_stream->parent == NULL)
return 0;
else
return o_stream_get_buffer_used_size(_stream->parent);
}
static int
o_stream_default_seek(struct ostream_private *_stream,
uoff_t offset ATTR_UNUSED)
{
_stream->ostream.stream_errno = ESPIPE;
return -1;
}
static int
o_stream_default_write_at(struct ostream_private *_stream,
const void *data ATTR_UNUSED,
size_t size ATTR_UNUSED, uoff_t offset ATTR_UNUSED)
{
_stream->ostream.stream_errno = ESPIPE;
return -1;
}
static off_t o_stream_default_send_istream(struct ostream_private *outstream,
struct istream *instream)
{
return io_stream_copy(&outstream->ostream, instream);
}
static void o_stream_default_switch_ioloop(struct ostream_private *_stream)
{
if (_stream->parent != NULL)
o_stream_switch_ioloop(_stream->parent);
}
struct ostream *
o_stream_create(struct ostream_private *_stream, struct ostream *parent, int fd)
{
_stream->fd = fd;
_stream->ostream.real_stream = _stream;
if (parent != NULL) {
_stream->parent = parent;
o_stream_ref(parent);
_stream->callback = parent->real_stream->callback;
_stream->context = parent->real_stream->context;
_stream->max_buffer_size = parent->real_stream->max_buffer_size;
_stream->error_handling_disabled =
parent->real_stream->error_handling_disabled;
}
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;
}