istream-chain.c revision 7be8ba0c0462887826e5ee6da6a27964d30383b5
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (c) 2003-2016 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Siraineni_stream_chain_append_internal(struct istream_chain *chain,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (stream == NULL && chain->tail != NULL && chain->tail->stream == NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct chain_istream *cstream = (struct chain_istream *)chain->stream;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t max_size = i_stream_get_max_buffer_size(stream);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (cstream->istream.max_buffer_size < max_size)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen DLLIST2_APPEND(&chain->head, &chain->tail, link);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* if io_add_istream() has been added to this chain stream, notify
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen the callback that we have more data available. */
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenvoid i_stream_chain_append(struct istream_chain *chain, struct istream *stream)
5c1a8aee989af87bddefd71e2aa83aa2bd695155Timo Sirainen i_stream_chain_append_internal(chain, stream);
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainenvoid i_stream_chain_append_eof(struct istream_chain *chain)
ec1e30ecc38f0deddaf655413cf02d5972ddbc70Timo Siraineni_stream_chain_set_max_buffer_size(struct iostream_private *stream,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct chain_istream *cstream = (struct chain_istream *)stream;
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen struct istream_chain_link *link = cstream->chain.head;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen cstream->have_explicit_max_buffer_size = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_set_max_buffer_size(link->stream, max_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void i_stream_chain_destroy(struct iostream_private *stream)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct chain_istream *cstream = (struct chain_istream *)stream;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct istream_chain_link *link = cstream->chain.head;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void i_stream_chain_read_next(struct chain_istream *cstream)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct istream_chain_link *link = cstream->chain.head;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const unsigned char *data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(link != NULL && link->stream != NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data = i_stream_get_data(prev_input, &data_size);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen DLLIST2_REMOVE(&cstream->chain.head, &cstream->chain.tail, link);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen /* a) we have more streams, b) we have EOF, c) we need to wait
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen for more streams */
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen /* we've already buffered some of the prev_input. continue
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen appending the rest to it. */
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen (cstream->istream.skip + cstream->prev_stream_left);
bef8712387812fc5d9496b9958935c6d0c418777Timo Sirainen memcpy(i_stream_alloc(&cstream->istream, data_size),
bef8712387812fc5d9496b9958935c6d0c418777Timo Sirainen i_stream_skip(prev_input, i_stream_get_data_size(prev_input));
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainenstatic bool i_stream_chain_skip(struct chain_istream *cstream)
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen struct istream_private *stream = &cstream->istream;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen struct istream_chain_link *link = cstream->chain.head;
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen bytes_skipped = stream->skip - cstream->prev_skip;
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen /* no need to worry about buffers, skip everything */
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen } else if (bytes_skipped < cstream->prev_stream_left) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we're still skipping inside buffer */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* done with the buffer */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic ssize_t i_stream_chain_read(struct istream_private *stream)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct chain_istream *cstream = (struct chain_istream *)stream;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct istream_chain_link *link = cstream->chain.head;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const unsigned char *data;
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen i_assert(stream->pos >= stream->skip + cstream->prev_stream_left);
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen cur_data_pos = stream->pos - (stream->skip + cstream->prev_stream_left);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data = i_stream_get_data(link->stream, &data_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* need to read more */
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen "read(%s) failed: %s",
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* EOF of this stream, go to next stream */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we read something */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data = i_stream_get_data(link->stream, &data_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we can point directly to the current stream's buffers */
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen /* nothing new read */
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen /* we still have some of the previous stream left. merge the
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen new data with it. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memcpy(i_stream_alloc(stream, new_bytes_count),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = new_pos > stream->pos ? (ssize_t)(new_pos - stream->pos) :
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainenstatic void i_stream_chain_close(struct iostream_private *stream,
62950eeff28f00989a17b20eeade3af7e200c6bcTimo Sirainen struct chain_istream *cstream = (struct chain_istream *)stream;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* seek to the correct position in parent stream in case it didn't
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen end with EOF */
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen struct istream_chain_link *link = cstream->chain.head;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct istream *i_stream_create_chain(struct istream_chain **chain_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cstream->istream.iostream.close = i_stream_chain_close;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cstream->istream.iostream.destroy = i_stream_chain_destroy;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cstream->istream.iostream.set_max_buffer_size =