bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen#include "lib.h"
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen#include "istream-private.h"
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen#include "istream-failure-at.h"
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainenstruct failure_at_istream {
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen struct istream_private istream;
a4985564b81d51caaddd38376792432428fd449bStephan Bosch int error_code;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen char *error_string;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen uoff_t failure_offset;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen};
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainenstatic void i_stream_failure_at_destroy(struct iostream_private *stream)
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen{
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen struct failure_at_istream *fstream =
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen (struct failure_at_istream *)stream;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen i_free(fstream->error_string);
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen}
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainenstatic ssize_t
289bb39856d74484c1622d096922acf126dd90fcTimo Siraineni_stream_failure_at_read(struct istream_private *stream)
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen{
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen struct failure_at_istream *fstream = (struct failure_at_istream *)stream;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen uoff_t new_offset;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen ssize_t ret;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen i_stream_seek(stream->parent, stream->parent_start_offset +
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen stream->istream.v_offset);
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen ret = i_stream_read_copy_from_parent(&stream->istream);
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen new_offset = stream->istream.v_offset + (stream->pos - stream->skip);
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen if (ret >= 0 && new_offset >= fstream->failure_offset) {
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen if (stream->istream.v_offset >= fstream->failure_offset) {
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen /* we already passed the wanted failure offset,
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen return error immediately. */
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen stream->pos = stream->skip;
a4985564b81d51caaddd38376792432428fd449bStephan Bosch stream->istream.stream_errno = errno =
a4985564b81d51caaddd38376792432428fd449bStephan Bosch fstream->error_code;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen io_stream_set_error(&stream->iostream, "%s",
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen fstream->error_string);
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen ret = -1;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen } else {
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen /* return data up to the wanted failure offset and
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen on the next read() call return failure */
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen size_t new_pos = fstream->failure_offset -
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen stream->istream.v_offset + stream->skip;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen i_assert(new_pos >= stream->skip &&
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen stream->pos >= new_pos);
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen ret -= stream->pos - new_pos;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen stream->pos = new_pos;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen }
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen } else if (ret < 0 && stream->istream.stream_errno == 0 &&
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen fstream->failure_offset == (uoff_t)-1) {
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen /* failure at EOF */
a4985564b81d51caaddd38376792432428fd449bStephan Bosch stream->istream.stream_errno = errno =
a4985564b81d51caaddd38376792432428fd449bStephan Bosch fstream->error_code;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen io_stream_set_error(&stream->iostream, "%s",
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen fstream->error_string);
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen }
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen return ret;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen}
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainenstruct istream *
289bb39856d74484c1622d096922acf126dd90fcTimo Siraineni_stream_create_failure_at(struct istream *input, uoff_t failure_offset,
a4985564b81d51caaddd38376792432428fd449bStephan Bosch int stream_errno, const char *error_string)
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen{
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen struct failure_at_istream *fstream;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen fstream = i_new(struct failure_at_istream, 1);
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen fstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen fstream->istream.stream_size_passthrough = TRUE;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen fstream->istream.read = i_stream_failure_at_read;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen fstream->istream.iostream.destroy = i_stream_failure_at_destroy;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen
25fb397382c6f7d39bfeee85774e7675f02bfb3cTimo Sirainen fstream->istream.istream.readable_fd = input->readable_fd;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen fstream->istream.istream.blocking = input->blocking;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen fstream->istream.istream.seekable = input->seekable;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen
a4985564b81d51caaddd38376792432428fd449bStephan Bosch fstream->error_code = stream_errno;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen fstream->error_string = i_strdup(error_string);
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen fstream->failure_offset = failure_offset;
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen return i_stream_create(&fstream->istream, input,
2974dca6be5120e49279f06c8aa952e5fac56048Timo Sirainen i_stream_get_fd(input), 0);
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen}
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainenstruct istream *
a4985564b81d51caaddd38376792432428fd449bStephan Boschi_stream_create_failure_at_eof(struct istream *input, int stream_errno,
a4985564b81d51caaddd38376792432428fd449bStephan Bosch const char *error_string)
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen{
a4985564b81d51caaddd38376792432428fd449bStephan Bosch return i_stream_create_failure_at(input, (uoff_t)-1, stream_errno,
a4985564b81d51caaddd38376792432428fd449bStephan Bosch error_string);
289bb39856d74484c1622d096922acf126dd90fcTimo Sirainen}