istream-concat.c revision a91f2c465f026ca4ebb9e6c8e92800175c0dece6
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2007-2012 Dovecot authors, see the included COPYING file */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstatic void i_stream_concat_close(struct iostream_private *stream)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct concat_istream *cstream = (struct concat_istream *)stream;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen unsigned int i;
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainenstatic void i_stream_concat_destroy(struct iostream_private *stream)
2dd39e478269d6fb0bb26d12b394aa30ee965e38Timo Sirainen struct concat_istream *cstream = (struct concat_istream *)stream;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int i;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Siraineni_stream_concat_set_max_buffer_size(struct iostream_private *stream,
3e564425db51f3921ce4de11859777135fdedd15Timo Sirainen struct concat_istream *cstream = (struct concat_istream *)stream;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen unsigned int i;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen i_stream_set_max_buffer_size(cstream->input[i], max_size);
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainenstatic void i_stream_concat_read_next(struct concat_istream *cstream)
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen const unsigned char *data;
4ba9a1d3facc515b3feb5238a16bcf91f76fac61Timo Sirainen data = i_stream_get_data(cstream->cur_input, &data_size);
dfaefeabae939803ceb8c503101e86b5496541d1Timo Sirainen cstream->cur_input = cstream->input[cstream->cur_idx];
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen if (cstream->prev_stream_left > 0 || cstream->istream.pos == 0) {
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen cstream->istream.pos - cstream->istream.skip);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we already verified that the data size is less than the
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen maximum buffer size */
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen if (!i_stream_try_alloc(&cstream->istream, data_size, &size))
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen memcpy(cstream->istream.w_buffer, data, data_size);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic ssize_t i_stream_concat_read(struct istream_private *stream)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct concat_istream *cstream = (struct concat_istream *)stream;
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen const unsigned char *data;
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen size_t size, data_size, cur_data_pos, new_pos, bytes_skipped;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen bytes_skipped = stream->skip - cstream->prev_skip;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* no need to worry about buffers, skip everything */
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen } else if (bytes_skipped < cstream->prev_stream_left) {
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen /* we're still skipping inside buffer */
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* done with the buffer */
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen i_stream_skip(cstream->cur_input, bytes_skipped);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen i_assert(stream->pos >= stream->skip + cstream->prev_stream_left);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen cur_data_pos = stream->pos - (stream->skip + cstream->prev_stream_left);
d3280fe317a4598c0868cc440e7a1191c06d0db3Timo Sirainen data = i_stream_get_data(cstream->cur_input, &data_size);
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen /* need to read more */
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen if (ret == -1 && cstream->cur_input->stream_errno != 0) {
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen /* we either read something or we're at EOF */
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen last_stream = cstream->input[cstream->cur_idx+1] == NULL;
4b41116563110d00330896a568eff1078c382827Timo Sirainen stream->istream.eof = cstream->cur_input->eof && last_stream;
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen data = i_stream_get_data(cstream->cur_input, &data_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we can point directly to the current stream's buffers */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* nothing new read */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen /* we still have some of the previous stream left. merge the
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen new data with it. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!i_stream_try_alloc(stream, new_bytes_count, &size)) {
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen ret = new_pos > stream->pos ? (ssize_t)(new_pos - stream->pos) :
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic unsigned int
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenfind_v_offset(struct concat_istream *cstream, uoff_t *v_offset)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen unsigned int i;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen /* seek to beginning of this stream */
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen /* we'll need to figure out this stream's size */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen "Failed to get size of stream %s",
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen return (unsigned int)-1;
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen /* @UNSAFE */
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainenstatic void i_stream_concat_seek(struct istream_private *stream,
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen struct concat_istream *cstream = (struct concat_istream *)stream;
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen cstream->cur_idx = find_v_offset(cstream, &v_offset);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen cstream->cur_input = cstream->input[cstream->cur_idx];
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainenstatic const struct stat *
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Siraineni_stream_concat_stat(struct istream_private *stream, bool exact ATTR_UNUSED)
4bbd396aa6198c84f3f7763b6e8a63a26e97e141Timo Sirainen struct concat_istream *cstream = (struct concat_istream *)stream;
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen unsigned int i;
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen /* make sure we have all sizes */
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen for (i = 0; i < cstream->unknown_size_idx; i++)
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen stream->statbuf.st_size += cstream->input_size[i];
7f735cb86b2d8abd8f230089065eacfc24e9e5d6Timo Sirainenstruct istream *i_stream_create_concat(struct istream *input[])
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen unsigned int count;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen /* if any of the streams isn't blocking or seekable, set ourself also
aa247243412a49f9bdebf7255e131dc6ece4ed46Timo Sirainen for (count = 0; input[count] != NULL; count++) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen size_t cur_max = input[count]->real_stream->max_buffer_size;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen cstream->input = i_new(struct istream *, count + 1);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen cstream->input_size = i_new(uoff_t, count + 1);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen memcpy(cstream->input, input, sizeof(*input) * count);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen cstream->istream.iostream.close = i_stream_concat_close;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen cstream->istream.iostream.destroy = i_stream_concat_destroy;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen cstream->istream.iostream.set_max_buffer_size =
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen cstream->istream.max_buffer_size = max_buffer_size;