bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen#include "lib.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "istream-private.h"
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen#include "istream-tee.h"
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainenstruct tee_istream {
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct istream *input;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_child_istream *children;
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen uoff_t max_read_offset;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen};
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainenstruct tee_child_istream {
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private istream;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_istream *tee;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_child_istream *next;
34435ce4a468dc13b23db69dbdd09fe20be88816Timo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool last_read_waiting:1;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen};
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainenstatic void tee_streams_update_buffer(struct tee_istream *tee)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen{
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_child_istream *tstream = tee->children;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen const unsigned char *data;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen size_t size, old_used;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen data = i_stream_get_data(tee->input, &size);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen for (; tstream != NULL; tstream = tstream->next) {
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen if (tstream->istream.istream.closed) {
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen tstream->istream.skip = tstream->istream.pos = 0;
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen continue;
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen }
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen old_used = tstream->istream.pos - tstream->istream.skip;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen tstream->istream.buffer = data;
50332744d549bc1f81423dddfa22ee99a7ff3f69Timo Sirainen i_assert(tstream->istream.istream.v_offset >= tee->input->v_offset);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen tstream->istream.skip = tstream->istream.istream.v_offset -
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen tee->input->v_offset;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen i_assert(tstream->istream.skip + old_used <= size);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen tstream->istream.pos = tstream->istream.skip + old_used;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen tstream->istream.parent_expected_offset =
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen tee->input->v_offset;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen tstream->istream.access_counter =
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen tee->input->real_stream->access_counter;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen }
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen}
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainenstatic void tee_streams_skip(struct tee_istream *tee)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen{
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_child_istream *tstream = tee->children;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen size_t min_skip;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen min_skip = (size_t)-1;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen for (; tstream != NULL; tstream = tstream->next) {
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen if (tstream->istream.skip < min_skip &&
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen !tstream->istream.istream.closed)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen min_skip = tstream->istream.skip;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen }
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen if (min_skip > 0 && min_skip != (size_t)-1) {
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen i_stream_skip(tee->input, min_skip);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen tee_streams_update_buffer(tee);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen }
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen}
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstatic void i_stream_tee_close(struct iostream_private *stream,
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen bool close_parent ATTR_UNUSED)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen{
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_child_istream *tstream = (struct tee_child_istream *)stream;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen tee_streams_skip(tstream->tee);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen}
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenstatic void i_stream_tee_destroy(struct iostream_private *stream)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen{
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_child_istream *tstream = (struct tee_child_istream *)stream;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_istream *tee = tstream->tee;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_child_istream **p;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen if (tstream->istream.istream.v_offset > tee->max_read_offset)
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen tee->max_read_offset = tstream->istream.istream.v_offset;
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen for (p = &tee->children; *p != NULL; p = &(*p)->next) {
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen if (*p == tstream) {
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen *p = tstream->next;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen break;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen }
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen }
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen if (tee->children == NULL) {
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen /* last child. the tee is now destroyed */
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen i_assert(tee->input->v_offset <= tee->max_read_offset);
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen i_stream_skip(tee->input,
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen tee->max_read_offset - tee->input->v_offset);
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen i_stream_unref(&tee->input);
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen i_free(tee);
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen } else {
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen tee_streams_skip(tstream->tee);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen }
5a1b498b646b5c5dbd1b3f3861df766f560578c5Timo Sirainen /* i_stream_unref() shouldn't unref the parent */
5a1b498b646b5c5dbd1b3f3861df766f560578c5Timo Sirainen tstream->istream.parent = NULL;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen}
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic void
a94936bafd127680184da114c6a177b37ff656e5Timo Siraineni_stream_tee_set_max_buffer_size(struct iostream_private *stream,
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen size_t max_size)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen{
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_child_istream *tstream = (struct tee_child_istream *)stream;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
597dba3488c648ffb375ee4a552bd52ac4346979Timo Sirainen tstream->istream.max_buffer_size = max_size;
74f810327aca91b3375d3fc963bce8076785b1cbTimo Sirainen i_stream_set_max_buffer_size(tstream->tee->input, max_size);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen}
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenstatic ssize_t i_stream_tee_read(struct istream_private *stream)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen{
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_child_istream *tstream = (struct tee_child_istream *)stream;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct istream *input = tstream->tee->input;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen const unsigned char *data;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen size_t size;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen uoff_t last_high_offset;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen ssize_t ret;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
34435ce4a468dc13b23db69dbdd09fe20be88816Timo Sirainen tstream->last_read_waiting = FALSE;
f8512649cd4db427a8dc5dc8f45c8e379ffd4d76Timo Sirainen if (stream->buffer == NULL) {
f8512649cd4db427a8dc5dc8f45c8e379ffd4d76Timo Sirainen /* initial read */
f8512649cd4db427a8dc5dc8f45c8e379ffd4d76Timo Sirainen tee_streams_update_buffer(tstream->tee);
f8512649cd4db427a8dc5dc8f45c8e379ffd4d76Timo Sirainen }
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen data = i_stream_get_data(input, &size);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
f8512649cd4db427a8dc5dc8f45c8e379ffd4d76Timo Sirainen /* last_high_offset contains how far we have read this child tee stream
f8512649cd4db427a8dc5dc8f45c8e379ffd4d76Timo Sirainen so far. input->v_offset + size contains how much is available in
f8512649cd4db427a8dc5dc8f45c8e379ffd4d76Timo Sirainen the parent stream without having to read more. */
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen last_high_offset = stream->istream.v_offset +
f8512649cd4db427a8dc5dc8f45c8e379ffd4d76Timo Sirainen (stream->pos - stream->skip);
63a2f941c1ad029061129ba6384d1d2a02382220Timo Sirainen if (stream->pos == size) {
f8512649cd4db427a8dc5dc8f45c8e379ffd4d76Timo Sirainen /* we've read everything, need to read more */
63a2f941c1ad029061129ba6384d1d2a02382220Timo Sirainen i_assert(last_high_offset == input->v_offset + size);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen tee_streams_skip(tstream->tee);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen ret = i_stream_read(input);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen if (ret <= 0) {
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen size = i_stream_get_data_size(input);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen if (ret == -2 && stream->skip != 0) {
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen /* someone else is holding the data,
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen wait for it */
34435ce4a468dc13b23db69dbdd09fe20be88816Timo Sirainen tstream->last_read_waiting = TRUE;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen return 0;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen }
0a70a2e71658d168f75d1f075661d7936701343cTimo Sirainen stream->istream.stream_errno = input->stream_errno;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen stream->istream.eof = input->eof;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen return ret;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen }
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen tee_streams_update_buffer(tstream->tee);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen data = i_stream_get_data(input, &size);
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen } else {
f8512649cd4db427a8dc5dc8f45c8e379ffd4d76Timo Sirainen /* there's still some data available from parent */
63a2f941c1ad029061129ba6384d1d2a02382220Timo Sirainen i_assert(last_high_offset < input->v_offset + size);
50332744d549bc1f81423dddfa22ee99a7ff3f69Timo Sirainen tee_streams_update_buffer(tstream->tee);
f8512649cd4db427a8dc5dc8f45c8e379ffd4d76Timo Sirainen i_assert(stream->pos < size);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen }
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen i_assert(stream->buffer == data);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen ret = size - stream->pos;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen i_assert(ret > 0);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen stream->pos = size;
50332744d549bc1f81423dddfa22ee99a7ff3f69Timo Sirainen
50332744d549bc1f81423dddfa22ee99a7ff3f69Timo Sirainen i_assert(stream->istream.v_offset + (stream->pos - stream->skip) ==
50332744d549bc1f81423dddfa22ee99a7ff3f69Timo Sirainen input->v_offset + size);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen return ret;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen}
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainenstatic int
a94936bafd127680184da114c6a177b37ff656e5Timo Siraineni_stream_tee_stat(struct istream_private *stream, bool exact)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen{
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_child_istream *tstream = (struct tee_child_istream *)stream;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen const struct stat *st;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen if (i_stream_stat(tstream->tee->input, exact, &st) < 0)
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen return -1;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen stream->statbuf = *st;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen return 0;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen}
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenstatic void i_stream_tee_sync(struct istream_private *stream)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen{
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_child_istream *tstream = (struct tee_child_istream *)stream;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen tee_streams_skip(tstream->tee);
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen if (i_stream_get_data_size(tstream->tee->input) != 0) {
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen i_panic("tee-istream: i_stream_sync() called "
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen "with data still buffered");
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen }
74f810327aca91b3375d3fc963bce8076785b1cbTimo Sirainen i_stream_sync(tstream->tee->input);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen}
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainenstruct tee_istream *tee_i_stream_create(struct istream *input)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen{
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_istream *tee;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen tee = i_new(struct tee_istream, 1);
106e86d8bfdfebd3ff55241845920ea3b47e0ba2Timo Sirainen if (input->v_offset == 0) {
106e86d8bfdfebd3ff55241845920ea3b47e0ba2Timo Sirainen i_stream_ref(input);
106e86d8bfdfebd3ff55241845920ea3b47e0ba2Timo Sirainen tee->input = input;
106e86d8bfdfebd3ff55241845920ea3b47e0ba2Timo Sirainen } else {
106e86d8bfdfebd3ff55241845920ea3b47e0ba2Timo Sirainen tee->input = i_stream_create_limit(input, (uoff_t)-1);
106e86d8bfdfebd3ff55241845920ea3b47e0ba2Timo Sirainen }
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen return tee;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen}
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainenstruct istream *tee_i_stream_create_child(struct tee_istream *tee)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen{
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_child_istream *tstream;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen struct istream *ret, *input = tee->input;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen tstream = i_new(struct tee_child_istream, 1);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen tstream->tee = tee;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen tstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen tstream->istream.iostream.close = i_stream_tee_close;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen tstream->istream.iostream.destroy = i_stream_tee_destroy;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen tstream->istream.iostream.set_max_buffer_size =
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen i_stream_tee_set_max_buffer_size;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen tstream->istream.read = i_stream_tee_read;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen tstream->istream.stat = i_stream_tee_stat;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen tstream->istream.sync = i_stream_tee_sync;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen tstream->next = tee->children;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen tee->children = tstream;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen
25c833d3cff7047f5c383892c379f59d116ff218Timo Sirainen ret = i_stream_create(&tstream->istream, input, i_stream_get_fd(input),
25c833d3cff7047f5c383892c379f59d116ff218Timo Sirainen ISTREAM_CREATE_FLAG_NOOP_SNAPSHOT);
d3e02d997e791e8ca624965e5b49e49a08793528Timo Sirainen i_stream_set_name(&tstream->istream.istream, i_stream_get_name(input));
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen /* we keep the reference in tee stream, no need for extra references */
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_stream_unref(&input);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen return ret;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen}
34435ce4a468dc13b23db69dbdd09fe20be88816Timo Sirainen
34435ce4a468dc13b23db69dbdd09fe20be88816Timo Sirainenbool tee_i_stream_child_is_waiting(struct istream *input)
34435ce4a468dc13b23db69dbdd09fe20be88816Timo Sirainen{
34435ce4a468dc13b23db69dbdd09fe20be88816Timo Sirainen struct tee_child_istream *tstream =
34435ce4a468dc13b23db69dbdd09fe20be88816Timo Sirainen (struct tee_child_istream *)input->real_stream;
34435ce4a468dc13b23db69dbdd09fe20be88816Timo Sirainen
34435ce4a468dc13b23db69dbdd09fe20be88816Timo Sirainen return tstream->last_read_waiting;
34435ce4a468dc13b23db69dbdd09fe20be88816Timo Sirainen}