istream-tee.c revision 4334b9b032298defd4d3906f5357698ff016ead0
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen/* Copyright (c) 2006-2010 Dovecot authors, see the included COPYING file */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "lib.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "istream-internal.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "istream-tee.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenstruct tee_istream {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct istream *input;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct tee_child_istream *children;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen uoff_t max_read_offset;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen};
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenstruct tee_child_istream {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct istream_private istream;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct tee_istream *tee;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct tee_child_istream *next;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen unsigned int last_read_waiting:1;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen};
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenstatic void tee_streams_update_buffer(struct tee_istream *tee)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct tee_child_istream *tstream = tee->children;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen const unsigned char *data;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen size_t size, old_used;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen data = i_stream_get_data(tee->input, &size);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen for (; tstream != NULL; tstream = tstream->next) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (tstream->istream.istream.closed) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tstream->istream.skip = tstream->istream.pos = 0;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen continue;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen old_used = tstream->istream.pos - tstream->istream.skip;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tstream->istream.buffer = data;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tstream->istream.skip = tstream->istream.istream.v_offset -
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tee->input->v_offset;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_assert(tstream->istream.skip + old_used <= size);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tstream->istream.pos = tstream->istream.skip + old_used;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tstream->istream.parent_expected_offset =
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tee->input->v_offset;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tstream->istream.access_counter =
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tee->input->real_stream->access_counter;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenstatic void tee_streams_skip(struct tee_istream *tee)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct tee_child_istream *tstream = tee->children;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen size_t min_skip;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen min_skip = (size_t)-1;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen for (; tstream != NULL; tstream = tstream->next) {
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen if (tstream->istream.skip < min_skip &&
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen !tstream->istream.istream.closed)
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen min_skip = tstream->istream.skip;
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen }
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen if (min_skip > 0 && min_skip != (size_t)-1) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_stream_skip(tee->input, min_skip);
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen tee_streams_update_buffer(tee);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenstatic void i_stream_tee_close(struct iostream_private *stream)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen struct tee_child_istream *tstream = (struct tee_child_istream *)stream;
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tee_streams_skip(tstream->tee);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenstatic void i_stream_tee_destroy(struct iostream_private *stream)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct tee_child_istream *tstream = (struct tee_child_istream *)stream;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct tee_istream *tee = tstream->tee;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct tee_child_istream **p;
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (tstream->istream.istream.v_offset > tee->max_read_offset)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tee->max_read_offset = tstream->istream.istream.v_offset;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen for (p = &tee->children; *p != NULL; p = &(*p)->next) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (*p == tstream) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen *p = tstream->next;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen break;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (tee->children == NULL) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* last child. the tee is now destroyed */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_assert(tee->input->v_offset <= tee->max_read_offset);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_stream_skip(tee->input,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tee->max_read_offset - tee->input->v_offset);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_stream_unref(&tee->input);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_free(tee);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen } else {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tee_streams_skip(tstream->tee);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenstatic void
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Siraineni_stream_tee_set_max_buffer_size(struct iostream_private *stream,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen size_t max_size)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct tee_child_istream *tstream = (struct tee_child_istream *)stream;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tstream->istream.max_buffer_size = max_size;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_stream_set_max_buffer_size(tstream->tee->input, max_size);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenstatic ssize_t i_stream_tee_read(struct istream_private *stream)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct tee_child_istream *tstream = (struct tee_child_istream *)stream;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct istream *input = tstream->tee->input;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen const unsigned char *data;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen size_t size;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen uoff_t last_high_offset;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ssize_t ret;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tstream->last_read_waiting = FALSE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (stream->buffer == NULL) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* initial read */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tee_streams_update_buffer(tstream->tee);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen data = i_stream_get_data(input, &size);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* last_high_offset contains how far we have read this child tee stream
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen so far. input->v_offset + size contains how much is available in
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen the parent stream without having to read more. */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen last_high_offset = stream->istream.v_offset +
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen (stream->pos - stream->skip);
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen if (stream->pos == size) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* we've read everything, need to read more */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_assert(last_high_offset == input->v_offset + size);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tee_streams_skip(tstream->tee);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ret = i_stream_read(input);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (ret <= 0) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen data = i_stream_get_data(input, &size);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (ret == -2 && stream->skip != 0) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* someone else is holding the data,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen wait for it */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tstream->last_read_waiting = TRUE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return 0;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen stream->istream.stream_errno = input->stream_errno;
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen stream->istream.eof = input->eof;
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen return ret;
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen }
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen tee_streams_update_buffer(tstream->tee);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen data = i_stream_get_data(input, &size);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen } else {
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen /* there's still some data available from parent */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_assert(last_high_offset < input->v_offset + size);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_assert(stream->pos < size);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen stream->buffer = data;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_assert(stream->buffer == data);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ret = size - stream->pos;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_assert(ret > 0);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen stream->pos = size;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return ret;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenstatic const struct stat *
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Siraineni_stream_tee_stat(struct istream_private *stream, bool exact)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct tee_child_istream *tstream = (struct tee_child_istream *)stream;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return i_stream_stat(tstream->tee->input, exact);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenstatic void i_stream_tee_sync(struct istream_private *stream)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct tee_child_istream *tstream = (struct tee_child_istream *)stream;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen size_t size;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tee_streams_skip(tstream->tee);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen (void)i_stream_get_data(tstream->tee->input, &size);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (size != 0) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_panic("tee-istream: i_stream_sync() called "
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen "with data still buffered");
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_stream_sync(tstream->tee->input);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenstruct tee_istream *tee_i_stream_create(struct istream *input)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct tee_istream *tee;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tee = i_new(struct tee_istream, 1);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tee->input = input;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_stream_ref(input);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return tee;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenstruct istream *tee_i_stream_create_child(struct tee_istream *tee)
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct tee_child_istream *tstream;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct istream *ret, *input = tee->input;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tstream = i_new(struct tee_child_istream, 1);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tstream->tee = tee;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tstream->istream.iostream.close = i_stream_tee_close;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tstream->istream.iostream.destroy = i_stream_tee_destroy;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tstream->istream.iostream.set_max_buffer_size =
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_stream_tee_set_max_buffer_size;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tstream->istream.read = i_stream_tee_read;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tstream->istream.stat = i_stream_tee_stat;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tstream->istream.sync = i_stream_tee_sync;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tstream->next = tee->children;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen tee->children = tstream;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ret = i_stream_create(&tstream->istream, input, i_stream_get_fd(input));
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* we keep the reference in tee stream, no need for extra references */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_stream_unref(&input);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return ret;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenbool tee_i_stream_child_is_waiting(struct istream *input)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct tee_child_istream *tstream =
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen (struct tee_child_istream *)input->real_stream;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return tstream->last_read_waiting;
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen