istream-concat.c revision f89cb43088c8b46d12d66ac924724b53ab14ce66
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2007 Dovecot authors, see the included COPYING file */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
80c1d98d3638b71e57a39cafa88b9122bf8169c6Timo Sirainen#include "buffer.h"
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen#include "istream-internal.h"
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen#include "istream-concat.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
94a8cb0ee1d85569ad1a2acacd92d3ce22f8a1cbTimo Sirainenstruct concat_istream {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct istream_private istream;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
795aeec896095aa8f08cc5d3282c88cc0921bff6Timo Sirainen struct istream **input, *cur_input;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uoff_t *input_size;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int cur_idx, unknown_size_idx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t prev_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void i_stream_concat_close(struct iostream_private *stream)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen{
8887bf3757d51d73887dd20b1db3334d867d3817Timo Sirainen struct concat_istream *cstream = (struct concat_istream *)stream;
8887bf3757d51d73887dd20b1db3334d867d3817Timo Sirainen unsigned int i;
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen for (i = 0; cstream->input[i] != NULL; i++)
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen i_stream_close(cstream->input[i]);
589a9c6e8ee22071c14171c04bfc6bfe17121871Timo Sirainen}
589a9c6e8ee22071c14171c04bfc6bfe17121871Timo Sirainen
ef5fb27361cc5e15766e85e28355750ff04b13c9Timo Sirainenstatic void i_stream_concat_destroy(struct iostream_private *stream)
ef5fb27361cc5e15766e85e28355750ff04b13c9Timo Sirainen{
ef5fb27361cc5e15766e85e28355750ff04b13c9Timo Sirainen struct concat_istream *cstream = (struct concat_istream *)stream;
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen unsigned int i;
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen for (i = 0; cstream->input[i] != NULL; i++)
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen i_stream_unref(&cstream->input[i]);
a53cb86b4d733d9c48ee4d285bed477c80825804Timo Sirainen}
a53cb86b4d733d9c48ee4d285bed477c80825804Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Siraineni_stream_concat_set_max_buffer_size(struct iostream_private *stream,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t max_size)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct concat_istream *cstream = (struct concat_istream *)stream;
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen unsigned int i;
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen
6ec7cf71ccd0eed1f9cc1b0bda8960796b04160bTimo Sirainen cstream->istream.max_buffer_size = max_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; cstream->input[i] != NULL; i++)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_set_max_buffer_size(cstream->input[i], max_size);
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen}
db5164c9a1129af0cfb11fc18d88da361a8011fbTimo Sirainen
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainenstatic void i_stream_concat_read_next(struct concat_istream *cstream)
db5164c9a1129af0cfb11fc18d88da361a8011fbTimo Sirainen{
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen const unsigned char *data;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen size_t data_size, size;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(cstream->cur_input->eof);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cstream->cur_idx++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cstream->cur_input = cstream->input[cstream->cur_idx];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (cstream->istream.pos == cstream->istream.skip)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we need to keep the current data */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data = cstream->istream.buffer + cstream->istream.skip;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data_size = cstream->istream.pos - cstream->istream.skip;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen /* we already verified that the data size is less than the
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen maximum buffer size */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (!i_stream_get_buffer_space(&cstream->istream, data_size, &size))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_unreached();
811f2e26d9782d9cb99fdf82e18ffa0a77564fe2Timo Sirainen i_assert(size >= data_size);
811f2e26d9782d9cb99fdf82e18ffa0a77564fe2Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cstream->prev_size = data_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memcpy(cstream->istream.w_buffer, data, data_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic ssize_t i_stream_concat_read(struct istream_private *stream)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct concat_istream *cstream = (struct concat_istream *)stream;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const unsigned char *data;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen size_t size, pos, skip;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ssize_t ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen bool last_stream;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen if (cstream->cur_input == NULL)
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen skip = stream->skip;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (cstream->prev_size > 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (stream->skip < cstream->prev_size) {
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen cstream->prev_size -= stream->skip;
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen skip = 0;
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen } else {
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen /* we don't need the buffer anymore */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen skip -= cstream->prev_size;
b84451fa6ada675ae504725702e0815967124cbbTimo Sirainen stream->skip -= cstream->prev_size;
b84451fa6ada675ae504725702e0815967124cbbTimo Sirainen cstream->prev_size = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen i_free_and_null(stream->w_buffer);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen stream->buffer = NULL;
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen stream->buffer_size = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_skip(cstream->cur_input, skip);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen data = i_stream_get_data(cstream->cur_input, &pos);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (pos > stream->pos)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = 0;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen else {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* need to read more */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen ret = i_stream_read(cstream->cur_input);
84ed9f8f3d0e5ed47607ef417618e49e4f865557Timo Sirainen if (ret == -2 || ret == 0)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return ret;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (ret == -1 && stream->istream.stream_errno != 0) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen stream->istream.stream_errno =
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen cstream->cur_input->stream_errno;
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen return -1;
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen }
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen /* we either read something or we're at EOF */
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen last_stream = cstream->input[cstream->cur_idx+1] == NULL;
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen if (ret == -1 && !last_stream) {
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen if (stream->pos - stream->skip >=
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen stream->max_buffer_size)
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen return -2;
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen
807b48fe1f6a57b01ed2cc20247d5b5e3facc562Timo Sirainen i_stream_concat_read_next(cstream);
807b48fe1f6a57b01ed2cc20247d5b5e3facc562Timo Sirainen last_stream =
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen cstream->input[cstream->cur_idx+1] == NULL;
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen }
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen stream->istream.eof = cstream->cur_input->eof && last_stream;
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen data = i_stream_get_data(cstream->cur_input, &pos);
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen if (stream->w_buffer == NULL) {
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen stream->buffer = data;
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen stream->pos -= stream->skip;
250105a1440167ef000323cdb2721cd2a3688e1eTimo Sirainen stream->skip = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
6bc98d3898c475ba7615ba2b016e5142c8b2c09fTimo Sirainen if (!i_stream_get_buffer_space(stream, pos, &size))
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen return -2;
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen memcpy(stream->w_buffer + stream->pos, data, I_MIN(size, pos));
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen }
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen (ret == 0 ? 0 : -1);
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen stream->pos = pos;
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen return ret;
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen}
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainenstatic unsigned int
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainenfind_v_offset(struct concat_istream *cstream, uoff_t *v_offset)
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen{
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen const struct stat *st;
d6a1fa1d65c6d1996937802c2482c0f14dd821a7Timo Sirainen unsigned int i;
d6a1fa1d65c6d1996937802c2482c0f14dd821a7Timo Sirainen
807b48fe1f6a57b01ed2cc20247d5b5e3facc562Timo Sirainen for (i = 0; cstream->input[i] != NULL; i++) {
807b48fe1f6a57b01ed2cc20247d5b5e3facc562Timo Sirainen if (*v_offset == 0) {
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen /* seek to beginning of this stream */
cfbacf6ea5fb39ae5304e4d95a78d9d4751bdfe1Timo Sirainen break;
dc912088f84c263db1609435c2f5d7cb29bf1a33Timo Sirainen }
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen if (i == cstream->unknown_size_idx) {
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen /* we'll need to figure out this stream's size */
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen st = i_stream_stat(cstream->input[i], TRUE);
7761758f43d6150be4b07f4c54457ce662f78c4cTimo Sirainen if (st == NULL) {
6bc98d3898c475ba7615ba2b016e5142c8b2c09fTimo Sirainen cstream->istream.istream.stream_errno =
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen cstream->input[i]->stream_errno;
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen return (unsigned int)-1;
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen }
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen /* @UNSAFE */
6bc98d3898c475ba7615ba2b016e5142c8b2c09fTimo Sirainen cstream->input_size[i] = st->st_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cstream->unknown_size_idx = i + 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
659fe5d24825b160cae512538088020d97a60239Timo Sirainen if (*v_offset < cstream->input_size[i])
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *v_offset -= cstream->input_size[i];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return i;
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainenstatic void i_stream_concat_seek(struct istream_private *stream,
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen uoff_t v_offset, bool mark ATTR_UNUSED)
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen{
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen struct concat_istream *cstream = (struct concat_istream *)stream;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen stream->istream.stream_errno = 0;
1f43c8ac132c153c224c4fffe34b2c3075d87ef7Timo Sirainen stream->istream.v_offset = v_offset;
1f43c8ac132c153c224c4fffe34b2c3075d87ef7Timo Sirainen stream->skip = stream->pos = 0;
e68fc7dc8c8a75842f1e39deb49d196d1cfdb3b3Timo Sirainen
e68fc7dc8c8a75842f1e39deb49d196d1cfdb3b3Timo Sirainen cstream->cur_idx = find_v_offset(cstream, &v_offset);
1f43c8ac132c153c224c4fffe34b2c3075d87ef7Timo Sirainen if (cstream->cur_idx == (unsigned int)-1) {
1f43c8ac132c153c224c4fffe34b2c3075d87ef7Timo Sirainen cstream->cur_input = NULL;
020a39a395d2adb768e0179631b37bc78ecd9471Timo Sirainen return;
020a39a395d2adb768e0179631b37bc78ecd9471Timo Sirainen }
1f43c8ac132c153c224c4fffe34b2c3075d87ef7Timo Sirainen cstream->cur_input = cstream->input[cstream->cur_idx];
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen i_stream_seek(cstream->cur_input, v_offset);
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen}
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen
020a39a395d2adb768e0179631b37bc78ecd9471Timo Sirainenstatic const struct stat *
020a39a395d2adb768e0179631b37bc78ecd9471Timo Siraineni_stream_concat_stat(struct istream_private *stream, bool exact ATTR_UNUSED)
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen{
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen struct concat_istream *cstream = (struct concat_istream *)stream;
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen uoff_t v_offset = (uoff_t)-1;
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen unsigned int i;
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen /* make sure we have all sizes */
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen (void)find_v_offset(cstream, &v_offset);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen stream->statbuf.st_size = 0;
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen for (i = 0; i < cstream->unknown_size_idx; i++)
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen stream->statbuf.st_size += cstream->input_size[i];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return &stream->statbuf;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct istream *i_stream_create_concat(struct istream *input[])
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct concat_istream *cstream;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int count;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t max_buffer_size = I_STREAM_MIN_SIZE;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (count = 0; input[count] != NULL; count++) {
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen size_t cur_max = input[count]->real_stream->max_buffer_size;
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen if (cur_max > max_buffer_size)
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen max_buffer_size = cur_max;
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen i_stream_ref(input[count]);
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen }
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen i_assert(count != 0);
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen cstream = i_new(struct concat_istream, 1);
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen cstream->input = i_new(struct istream *, count + 1);
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen cstream->input_size = i_new(uoff_t, count + 1);
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen memcpy(cstream->input, input, sizeof(*input) * count);
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen cstream->cur_input = cstream->input[0];
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen cstream->istream.iostream.close = i_stream_concat_close;
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen cstream->istream.iostream.destroy = i_stream_concat_destroy;
41e6eb07b411ea58352ba9d2cc8cf340325d49f3Timo Sirainen cstream->istream.iostream.set_max_buffer_size =
41e6eb07b411ea58352ba9d2cc8cf340325d49f3Timo Sirainen i_stream_concat_set_max_buffer_size;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen
41e6eb07b411ea58352ba9d2cc8cf340325d49f3Timo Sirainen cstream->istream.max_buffer_size = max_buffer_size;
41e6eb07b411ea58352ba9d2cc8cf340325d49f3Timo Sirainen cstream->istream.read = i_stream_concat_read;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen cstream->istream.seek = i_stream_concat_seek;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cstream->istream.stat = i_stream_concat_stat;
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen return i_stream_create(&cstream->istream, -1, 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
15cc66ca72982a43e3bfa58f307adc57e9caa52dTimo Sirainen