bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainenstatic void tee_streams_update_buffer(struct tee_istream *tee)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_child_istream *tstream = tee->children;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen for (; tstream != NULL; tstream = tstream->next) {
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen tstream->istream.skip = tstream->istream.pos = 0;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen old_used = tstream->istream.pos - tstream->istream.skip;
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 i_assert(tstream->istream.skip + old_used <= size);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen tstream->istream.pos = tstream->istream.skip + old_used;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainenstatic void tee_streams_skip(struct tee_istream *tee)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_child_istream *tstream = tee->children;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen for (; tstream != NULL; tstream = tstream->next) {
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstatic void i_stream_tee_close(struct iostream_private *stream,
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_child_istream *tstream = (struct tee_child_istream *)stream;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenstatic void i_stream_tee_destroy(struct iostream_private *stream)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_child_istream *tstream = (struct tee_child_istream *)stream;
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen if (tstream->istream.istream.v_offset > tee->max_read_offset)
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen tee->max_read_offset = tstream->istream.istream.v_offset;
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen for (p = &tee->children; *p != NULL; p = &(*p)->next) {
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen /* last child. the tee is now destroyed */
4fdf60e22b5340fe35f083b9ea5eb3fd1cf2e742Timo Sirainen i_assert(tee->input->v_offset <= tee->max_read_offset);
5a1b498b646b5c5dbd1b3f3861df766f560578c5Timo Sirainen /* i_stream_unref() shouldn't unref the parent */
a94936bafd127680184da114c6a177b37ff656e5Timo Siraineni_stream_tee_set_max_buffer_size(struct iostream_private *stream,
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_child_istream *tstream = (struct tee_child_istream *)stream;
74f810327aca91b3375d3fc963bce8076785b1cbTimo Sirainen i_stream_set_max_buffer_size(tstream->tee->input, max_size);
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenstatic ssize_t i_stream_tee_read(struct istream_private *stream)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_child_istream *tstream = (struct tee_child_istream *)stream;
f8512649cd4db427a8dc5dc8f45c8e379ffd4d76Timo Sirainen /* initial read */
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. */
f8512649cd4db427a8dc5dc8f45c8e379ffd4d76Timo Sirainen /* we've read everything, need to read more */
63a2f941c1ad029061129ba6384d1d2a02382220Timo Sirainen i_assert(last_high_offset == input->v_offset + size);
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen /* someone else is holding the data,
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen wait for it */
0a70a2e71658d168f75d1f075661d7936701343cTimo Sirainen stream->istream.stream_errno = input->stream_errno;
f8512649cd4db427a8dc5dc8f45c8e379ffd4d76Timo Sirainen /* there's still some data available from parent */
63a2f941c1ad029061129ba6384d1d2a02382220Timo Sirainen i_assert(last_high_offset < input->v_offset + size);
50332744d549bc1f81423dddfa22ee99a7ff3f69Timo Sirainen i_assert(stream->istream.v_offset + (stream->pos - stream->skip) ==
a94936bafd127680184da114c6a177b37ff656e5Timo Siraineni_stream_tee_stat(struct istream_private *stream, bool exact)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_child_istream *tstream = (struct tee_child_istream *)stream;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen if (i_stream_stat(tstream->tee->input, exact, &st) < 0)
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenstatic void i_stream_tee_sync(struct istream_private *stream)
ea37a9aedfc3a6ff5f4ea10bc4eff4ca23f62a15Timo Sirainen struct tee_child_istream *tstream = (struct tee_child_istream *)stream;
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");
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainenstruct tee_istream *tee_i_stream_create(struct istream *input)
106e86d8bfdfebd3ff55241845920ea3b47e0ba2Timo Sirainen tee->input = i_stream_create_limit(input, (uoff_t)-1);
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainenstruct istream *tee_i_stream_create_child(struct tee_istream *tee)
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 =
25c833d3cff7047f5c383892c379f59d116ff218Timo Sirainen ret = i_stream_create(&tstream->istream, input, i_stream_get_fd(input),
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 */
34435ce4a468dc13b23db69dbdd09fe20be88816Timo Sirainenbool tee_i_stream_child_is_waiting(struct istream *input)