bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen#include "lib.h"
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen#include "buffer.h"
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen#include "ostream-private.h"
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen#include "ostream-failure-at.h"
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainenstruct failure_at_ostream {
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen struct ostream_private ostream;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen char *error_string;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen uoff_t failure_offset;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen bool failed;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen};
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainenstatic void o_stream_failure_at_destroy(struct iostream_private *stream)
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen{
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen struct failure_at_ostream *fstream =
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen (struct failure_at_ostream *)stream;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen i_free(fstream->error_string);
2bee4c37862d33fe09544d865225d140bd533225Phil Carmody o_stream_unref(&fstream->ostream.parent);
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen}
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainenstatic ssize_t
9294b9ad2eb112258c247906b53010664f84e57bTimo Siraineno_stream_failure_at_sendv(struct ostream_private *stream,
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen const struct const_iovec *iov, unsigned int iov_count)
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen{
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen struct failure_at_ostream *fstream =
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen (struct failure_at_ostream *)stream;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen unsigned int i;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen struct const_iovec *iov_dup;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen unsigned int iov_dup_count;
a81be83a3bb00b7b31b832f50bd8542e62a71891Timo Sirainen uoff_t bytes_until_failure, blocking_bytes_count = 0;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen ssize_t ret;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen
a81be83a3bb00b7b31b832f50bd8542e62a71891Timo Sirainen if (stream->ostream.blocking) {
a81be83a3bb00b7b31b832f50bd8542e62a71891Timo Sirainen /* blocking ostream must return either a full success or a
a81be83a3bb00b7b31b832f50bd8542e62a71891Timo Sirainen failure. if the current write would go past failure_offset,
a81be83a3bb00b7b31b832f50bd8542e62a71891Timo Sirainen return a failure now before writing anything. */
a81be83a3bb00b7b31b832f50bd8542e62a71891Timo Sirainen for (i = 0; i < iov_count; i++)
a81be83a3bb00b7b31b832f50bd8542e62a71891Timo Sirainen blocking_bytes_count += iov[i].iov_len;
a81be83a3bb00b7b31b832f50bd8542e62a71891Timo Sirainen if (blocking_bytes_count > 0) {
a81be83a3bb00b7b31b832f50bd8542e62a71891Timo Sirainen /* if we're exactly at the failure offset after this
a81be83a3bb00b7b31b832f50bd8542e62a71891Timo Sirainen write, fail it only on the next write. */
a81be83a3bb00b7b31b832f50bd8542e62a71891Timo Sirainen blocking_bytes_count--;
a81be83a3bb00b7b31b832f50bd8542e62a71891Timo Sirainen }
a81be83a3bb00b7b31b832f50bd8542e62a71891Timo Sirainen }
a81be83a3bb00b7b31b832f50bd8542e62a71891Timo Sirainen
a81be83a3bb00b7b31b832f50bd8542e62a71891Timo Sirainen if (fstream->failure_offset <= stream->ostream.offset + blocking_bytes_count) {
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen io_stream_set_error(&stream->iostream, "%s",
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen fstream->error_string);
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen stream->ostream.stream_errno = errno = EIO;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen fstream->failed = TRUE;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen return -1;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen }
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen bytes_until_failure = fstream->failure_offset - stream->ostream.offset;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen iov_dup = i_new(struct const_iovec, iov_count);
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen iov_dup_count = iov_count;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen for (i = 0; i < iov_count; i++) {
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen iov_dup[i] = iov[i];
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen if (iov_dup[i].iov_len >= bytes_until_failure) {
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen iov_dup[i].iov_len = bytes_until_failure;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen iov_dup_count = i+1;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen break;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen }
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen }
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen ret = o_stream_sendv(stream->parent, iov_dup, iov_dup_count);
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen i_free(iov_dup);
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen if (ret < 0) {
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen o_stream_copy_error_from_parent(stream);
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen return -1;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen }
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen stream->ostream.offset += ret;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen return ret;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen}
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainenstatic int
9294b9ad2eb112258c247906b53010664f84e57bTimo Siraineno_stream_failure_at_flush(struct ostream_private *stream)
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen{
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen struct failure_at_ostream *fstream =
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen (struct failure_at_ostream *)stream;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen if (fstream->failed) {
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen io_stream_set_error(&stream->iostream, "%s",
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen fstream->error_string);
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen stream->ostream.stream_errno = errno = EIO;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen return -1;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen }
8109f3187f5ece5565de1813209af42dc7bb768bTimo Sirainen return o_stream_flush_parent(stream);
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen}
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainenstruct ostream *
9294b9ad2eb112258c247906b53010664f84e57bTimo Siraineno_stream_create_failure_at(struct ostream *output, uoff_t failure_offset,
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen const char *error_string)
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen{
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen struct failure_at_ostream *fstream;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen fstream = i_new(struct failure_at_ostream, 1);
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen fstream->ostream.sendv = o_stream_failure_at_sendv;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen fstream->ostream.flush = o_stream_failure_at_flush;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen fstream->ostream.iostream.destroy = o_stream_failure_at_destroy;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen fstream->failure_offset = failure_offset;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen fstream->error_string = i_strdup(error_string);
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen return o_stream_create(&fstream->ostream, output,
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen o_stream_get_fd(output));
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen}
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainenstruct ostream *
9294b9ad2eb112258c247906b53010664f84e57bTimo Siraineno_stream_create_failure_at_flush(struct ostream *output, const char *error_string)
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen{
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen struct failure_at_ostream *fstream;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen fstream = i_new(struct failure_at_ostream, 1);
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen fstream->ostream.flush = o_stream_failure_at_flush;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen fstream->ostream.iostream.destroy = o_stream_failure_at_destroy;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen fstream->error_string = i_strdup(error_string);
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen fstream->failed = TRUE;
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen return o_stream_create(&fstream->ostream, output,
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen o_stream_get_fd(output));
9294b9ad2eb112258c247906b53010664f84e57bTimo Sirainen}