istream-chain.c revision 59a63791d4ec70a134cb0dcbad1255d952075efe
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2003-2017 Dovecot authors, see the included COPYING file */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
46552a931924c2d743f045e95b08c3ce6beda91aTimo Sirainen#include "lib.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "llist.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "istream-private.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "istream-chain.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstruct chain_istream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstruct istream_chain_link {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct istream_chain_link *prev, *next;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct istream *stream;
53dfcefa9440a49d703e49193819a79be99c9ba6Timo Sirainen bool eof;
2ef0e8ee48c9683f7bd6698798efa3328e4322d1Timo Sirainen};
53dfcefa9440a49d703e49193819a79be99c9ba6Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstruct istream_chain {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct istream_chain_link *head, *tail;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct chain_istream *stream;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen};
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen
660b99a7059824676b2b8d6f79b8e15d47df25a2Timo Sirainenstruct chain_istream {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct istream_private istream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* how much of the previous link's stream still exists at the
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen beginning of our buffer. skipping through this should point to
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen the beginning of the current link's stream. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen size_t prev_stream_left;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen size_t prev_skip;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen bool have_explicit_max_buffer_size;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
660b99a7059824676b2b8d6f79b8e15d47df25a2Timo Sirainen struct istream_chain chain;
660b99a7059824676b2b8d6f79b8e15d47df25a2Timo Sirainen};
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void ATTR_NULL(2)
e248fe370c4047cee921a91b48edc37944ab0526Timo Siraineni_stream_chain_append_internal(struct istream_chain *chain,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct istream *stream)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct istream_chain_link *link;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (stream == NULL && chain->tail != NULL && chain->tail->stream == NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen link = i_new(struct istream_chain_link, 1);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen link->stream = stream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen link->eof = stream == NULL;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (stream != NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_stream_ref(stream);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (chain->head == NULL && stream != NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct chain_istream *cstream = (struct chain_istream *)chain->stream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (cstream->have_explicit_max_buffer_size) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_stream_set_max_buffer_size(stream,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen chain->stream->istream.max_buffer_size);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen size_t max_size = i_stream_get_max_buffer_size(stream);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (cstream->istream.max_buffer_size < max_size)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen cstream->istream.max_buffer_size = max_size;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen DLLIST2_APPEND(&chain->head, &chain->tail, link);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* if io_add_istream() has been added to this chain stream, notify
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen the callback that we have more data available. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (stream != NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_stream_set_input_pending(stream, TRUE);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid i_stream_chain_append(struct istream_chain *chain, struct istream *stream)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_stream_chain_append_internal(chain, stream);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid i_stream_chain_append_eof(struct istream_chain *chain)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_stream_chain_append_internal(chain, NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void
e248fe370c4047cee921a91b48edc37944ab0526Timo Siraineni_stream_chain_set_max_buffer_size(struct iostream_private *stream,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen size_t max_size)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct chain_istream *cstream = (struct chain_istream *)stream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct istream_chain_link *link = cstream->chain.head;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen cstream->have_explicit_max_buffer_size = TRUE;
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen cstream->istream.max_buffer_size = max_size;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen while (link != NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (link->stream != NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_stream_set_max_buffer_size(link->stream, max_size);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen link = link->next;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void i_stream_chain_destroy(struct iostream_private *stream)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct chain_istream *cstream = (struct chain_istream *)stream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct istream_chain_link *link = cstream->chain.head;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen while (link != NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct istream_chain_link *next = link->next;
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_stream_unref(&link->stream);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_free(link);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen link = next;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_free(cstream->istream.w_buffer);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void i_stream_chain_read_next(struct chain_istream *cstream)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct istream_chain_link *link = cstream->chain.head;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct istream *prev_input;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const unsigned char *data;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen size_t data_size, cur_data_pos;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(link != NULL && link->stream != NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(link->stream->eof);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen prev_input = link->stream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen data = i_stream_get_data(prev_input, &data_size);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen DLLIST2_REMOVE(&cstream->chain.head, &cstream->chain.tail, link);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_free(link);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* a) we have more streams, b) we have EOF, c) we need to wait
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen for more streams */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen link = cstream->chain.head;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (link != NULL && link->stream != NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_stream_seek(link->stream, 0);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (cstream->prev_stream_left > 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* we've already buffered some of the prev_input. continue
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen appending the rest to it. if it's already at EOF, there's
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen nothing more to append. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen cur_data_pos = cstream->istream.pos -
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen (cstream->istream.skip + cstream->prev_stream_left);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(cur_data_pos <= data_size);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen data += cur_data_pos;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen data_size -= cur_data_pos;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* the stream has now become "previous", so its contents in
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen buffer are now part of prev_stream_left. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen cstream->prev_stream_left += cur_data_pos;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen cstream->istream.pos = 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen cstream->istream.skip = 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen cstream->prev_stream_left = 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (data_size > 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen memcpy(i_stream_alloc(&cstream->istream, data_size),
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen data, data_size);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen cstream->istream.pos += data_size;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen cstream->prev_stream_left += data_size;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_stream_skip(prev_input, i_stream_get_data_size(prev_input));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_stream_unref(&prev_input);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic bool i_stream_chain_skip(struct chain_istream *cstream)
53dfcefa9440a49d703e49193819a79be99c9ba6Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct istream_private *stream = &cstream->istream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct istream_chain_link *link = cstream->chain.head;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen size_t bytes_skipped;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(stream->skip >= cstream->prev_skip);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen bytes_skipped = stream->skip - cstream->prev_skip;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (cstream->prev_stream_left == 0) {
660b99a7059824676b2b8d6f79b8e15d47df25a2Timo Sirainen /* no need to worry about buffers, skip everything */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else if (bytes_skipped < cstream->prev_stream_left) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* we're still skipping inside buffer */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen cstream->prev_stream_left -= bytes_skipped;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen bytes_skipped = 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* done with the buffer */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen bytes_skipped -= cstream->prev_stream_left;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen cstream->prev_stream_left = 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen stream->pos -= bytes_skipped;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen stream->skip -= bytes_skipped;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen stream->buffer += bytes_skipped;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen cstream->prev_skip = stream->skip;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (link == NULL || link->eof) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(bytes_skipped == 0);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_stream_skip(link->stream, bytes_skipped);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic ssize_t i_stream_chain_read(struct istream_private *stream)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct chain_istream *cstream = (struct chain_istream *)stream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct istream_chain_link *link = cstream->chain.head;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const unsigned char *data;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen size_t data_size, cur_data_pos, new_pos;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen size_t new_bytes_count;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ssize_t ret;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (link != NULL && link->eof) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen stream->istream.eof = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (!i_stream_chain_skip(cstream))
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(link != NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(stream->pos >= stream->skip + cstream->prev_stream_left);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen cur_data_pos = stream->pos - (stream->skip + cstream->prev_stream_left);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen data = i_stream_get_data(link->stream, &data_size);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (data_size > cur_data_pos)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else {
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen /* need to read more */
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen i_assert(cur_data_pos == data_size);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = i_stream_read(link->stream);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (ret == -2 || ret == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return ret;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (ret == -1) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (link->stream->stream_errno != 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen io_stream_set_error(&stream->iostream,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "read(%s) failed: %s",
53dfcefa9440a49d703e49193819a79be99c9ba6Timo Sirainen i_stream_get_name(link->stream),
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_stream_get_error(link->stream));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen stream->istream.stream_errno =
04b7dc631f33bf61f273138c679da9bd0910fb6dTimo Sirainen link->stream->stream_errno;
04b7dc631f33bf61f273138c679da9bd0910fb6dTimo Sirainen return -1;
04b7dc631f33bf61f273138c679da9bd0910fb6dTimo Sirainen }
04b7dc631f33bf61f273138c679da9bd0910fb6dTimo Sirainen /* EOF of this stream, go to next stream */
04b7dc631f33bf61f273138c679da9bd0910fb6dTimo Sirainen i_stream_chain_read_next(cstream);
04b7dc631f33bf61f273138c679da9bd0910fb6dTimo Sirainen cstream->prev_skip = stream->skip;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return i_stream_chain_read(stream);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* we read something */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen data = i_stream_get_data(link->stream, &data_size);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (data_size == cur_data_pos) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* nothing new read - preserve the buffer as it was */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(ret == 0 || ret == -1);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return ret;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (cstream->prev_stream_left == 0) {
53dfcefa9440a49d703e49193819a79be99c9ba6Timo Sirainen /* we can point directly to the current stream's buffers */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen stream->buffer = data;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen stream->pos -= stream->skip;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen stream->skip = 0;
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen new_pos = data_size;
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen } else {
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen /* we still have some of the previous stream left. merge the
2ef0e8ee48c9683f7bd6698798efa3328e4322d1Timo Sirainen new data with it. */
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen i_assert(data_size > cur_data_pos);
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen new_bytes_count = data_size - cur_data_pos;
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen memcpy(i_stream_alloc(stream, new_bytes_count),
2ef0e8ee48c9683f7bd6698798efa3328e4322d1Timo Sirainen data + cur_data_pos, new_bytes_count);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen stream->buffer = stream->w_buffer;
53dfcefa9440a49d703e49193819a79be99c9ba6Timo Sirainen new_pos = stream->pos + new_bytes_count;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(new_pos > stream->pos);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = (ssize_t)(new_pos - stream->pos);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen stream->pos = new_pos;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen cstream->prev_skip = stream->skip;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return ret;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void i_stream_chain_close(struct iostream_private *stream,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen bool close_parent)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct chain_istream *cstream = (struct chain_istream *)stream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* seek to the correct position in parent stream in case it didn't
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen end with EOF */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen (void)i_stream_chain_skip(cstream);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (close_parent) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct istream_chain_link *link = cstream->chain.head;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen while (link != NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_stream_close(link->stream);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen link = link->next;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
660b99a7059824676b2b8d6f79b8e15d47df25a2Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstruct istream *i_stream_create_chain(struct istream_chain **chain_r)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct chain_istream *cstream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen cstream = i_new(struct chain_istream, 1);
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen cstream->chain.stream = cstream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen cstream->istream.iostream.close = i_stream_chain_close;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen cstream->istream.iostream.destroy = i_stream_chain_destroy;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen cstream->istream.iostream.set_max_buffer_size =
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen i_stream_chain_set_max_buffer_size;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen cstream->istream.read = i_stream_chain_read;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen cstream->istream.istream.readable_fd = FALSE;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen cstream->istream.istream.blocking = FALSE;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen cstream->istream.istream.seekable = FALSE;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen *chain_r = &cstream->chain;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen return i_stream_create(&cstream->istream, NULL, -1);
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen}
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen