static void i_stream_tee_destroy(struct iostream_private *stream) { struct tee_child_istream *tstream = (struct tee_child_istream *)stream; struct tee_istream *tee = tstream->tee; struct tee_child_istream **p; if (tstream->istream.istream.v_offset > tee->max_read_offset) tee->max_read_offset = tstream->istream.istream.v_offset; for (p = &tee->children; *p != NULL; p = &(*p)->next) { if (*p == tstream) { *p = tstream->next; break; } } if (tee->children == NULL) { /* last child. the tee is now destroyed */ i_assert(tee->input->v_offset <= tee->max_read_offset); i_stream_skip(tee->input, tee->max_read_offset - tee->input->v_offset); i_stream_unref(&tee->input); i_free(tee); } else { tee_streams_skip(tstream->tee); } /* i_stream_unref() shouldn't unref the parent */ tstream->istream.parent = NULL; }
static void i_stream_tee_close(struct iostream_private *stream, bool close_parent ATTR_UNUSED) { struct tee_child_istream *tstream = (struct tee_child_istream *)stream; tee_streams_skip(tstream->tee); }
static ssize_t i_stream_tee_read(struct istream_private *stream) { struct tee_child_istream *tstream = (struct tee_child_istream *)stream; struct istream *input = tstream->tee->input; const unsigned char *data; size_t size; uoff_t last_high_offset; ssize_t ret; tstream->last_read_waiting = FALSE; if (stream->buffer == NULL) { /* initial read */ tee_streams_update_buffer(tstream->tee); } data = i_stream_get_data(input, &size); /* last_high_offset contains how far we have read this child tee stream so far. input->v_offset + size contains how much is available in the parent stream without having to read more. */ last_high_offset = stream->istream.v_offset + (stream->pos - stream->skip); if (stream->pos == size) { /* we've read everything, need to read more */ i_assert(last_high_offset == input->v_offset + size); tee_streams_skip(tstream->tee); ret = i_stream_read(input); if (ret <= 0) { size = i_stream_get_data_size(input); if (ret == -2 && stream->skip != 0) { /* someone else is holding the data, wait for it */ tstream->last_read_waiting = TRUE; return 0; } stream->istream.stream_errno = input->stream_errno; stream->istream.eof = input->eof; return ret; } tee_streams_update_buffer(tstream->tee); data = i_stream_get_data(input, &size); } else { /* there's still some data available from parent */ i_assert(last_high_offset < input->v_offset + size); tee_streams_update_buffer(tstream->tee); i_assert(stream->pos < size); } i_assert(stream->buffer == data); ret = size - stream->pos; i_assert(ret > 0); stream->pos = size; i_assert(stream->istream.v_offset + (stream->pos - stream->skip) == input->v_offset + size); return ret; }
static void i_stream_tee_sync(struct istream_private *stream) { struct tee_child_istream *tstream = (struct tee_child_istream *)stream; tee_streams_skip(tstream->tee); if (i_stream_get_data_size(tstream->tee->input) != 0) { i_panic("tee-istream: i_stream_sync() called " "with data still buffered"); } i_stream_sync(tstream->tee->input); }
static void i_stream_tee_close(struct iostream_private *stream) { struct tee_child_istream *tstream = (struct tee_child_istream *)stream; tee_streams_skip(tstream->tee); }