istream.c revision f20e7fbdc9bdbe8fecb9c661c9b8175f3bb78c69
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (c) 2002-2014 Dovecot authors, see the included COPYING file */
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenvoid i_stream_set_name(struct istream *stream, const char *name)
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen stream->real_stream->iostream.name = i_strdup(name);
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenconst char *i_stream_get_name(struct istream *stream)
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen while (stream->real_stream->iostream.name == NULL) {
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstatic void i_stream_close_full(struct istream *stream, bool close_parents)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen io_stream_close(&stream->real_stream->iostream, close_parents);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen io_stream_ref(&stream->real_stream->iostream);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = (*stream)->real_stream;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen io_stream_unref(&(*stream)->real_stream->iostream);
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainenvoid i_stream_add_destroy_callback(struct istream *stream,
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen struct iostream_private *iostream = &stream->real_stream->iostream;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen if (!array_is_created(&iostream->destroy_callbacks))
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen i_array_init(&iostream->destroy_callbacks, 2);
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen dc = array_append_space(&iostream->destroy_callbacks);
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainenvoid i_stream_remove_destroy_callback(struct istream *stream,
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen struct iostream_private *iostream = &stream->real_stream->iostream;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen unsigned int i, count;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen dcs = array_get(&iostream->destroy_callbacks, &count);
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen for (i = 0; i < count; i++) {
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen array_delete(&iostream->destroy_callbacks, i, 1);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenconst char *i_stream_get_error(struct istream *stream)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen /* we'll only return errors for streams that have stream_errno set.
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen we might be returning unintended error otherwise. */
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen return "<no error>";
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen for (s = stream; s != NULL; s = s->real_stream->parent) {
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainenvoid i_stream_set_init_buffer_size(struct istream *stream, size_t size)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_set_max_buffer_size(struct istream *stream, size_t max_size)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen io_stream_set_max_buffer_size(&stream->real_stream->iostream, max_size);
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainensize_t i_stream_get_max_buffer_size(struct istream *stream)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenvoid i_stream_set_return_partial_line(struct istream *stream, bool set)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenstatic void i_stream_update(struct istream_private *stream)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen stream->parent_expected_offset = stream->parent->v_offset;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
a2738cdb6d2733fb3e186331d68009421a19ea00Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_stream_seek(_stream->parent, _stream->parent_expected_offset);
7af4788b402346c94496095dd819f95ce03fe431Timo Sirainen i_assert(old_size <= _stream->pos - _stream->skip);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen /* error handling should be easier if we now just
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen assume the stream is now at EOF */
c24ef531ca58abad996482f5c2e8992be9ae8981Timo Sirainen i_assert(old_size == _stream->pos - _stream->skip);
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen i_assert((size_t)ret+old_size == _stream->pos - _stream->skip);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenssize_t i_stream_read_copy_from_parent(struct istream *istream)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen struct istream_private *stream = istream->real_stream;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if ((ret = i_stream_read(stream->parent)) == -2)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen /* check again, in case the parent stream had been seeked
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen backwards and the previous read() didn't get us far
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_skip(struct istream *stream, uoff_t count)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* within buffer */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* have to seek forward */
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen _stream->seek(_stream, stream->v_offset + count, FALSE);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenstatic bool i_stream_can_optimize_seek(struct istream_private *stream)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen /* use the fast route only if the parent stream hasn't been changed */
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen return i_stream_can_optimize_seek(stream->parent->real_stream);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid i_stream_seek(struct istream *stream, uoff_t v_offset)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen i_stream_skip(stream, v_offset - stream->v_offset);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainenvoid i_stream_seek_mark(struct istream *stream, uoff_t v_offset)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainenint i_stream_stat(struct istream *stream, bool exact, const struct stat **st_r)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainenint i_stream_get_size(struct istream *stream, bool exact, uoff_t *size_r)
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen struct istream_private *_stream = stream->real_stream;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen return _stream->get_size(_stream, exact, size_r);
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenbool i_stream_have_bytes_left(const struct istream *stream)
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen const struct istream_private *_stream = stream->real_stream;
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen return !stream->eof || _stream->skip != _stream->pos;
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen const struct istream_private *_stream = stream->real_stream;
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainenuoff_t i_stream_get_absolute_offset(struct istream *stream)
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen return stream->real_stream->abs_start_offset + stream->v_offset;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic char *i_stream_next_line_finish(struct istream_private *stream, size_t i)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen /* modify the buffer directly */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen ret = (char *)stream->w_buffer + stream->skip;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen /* use a temporary string to return it */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen stream->line_str = str_new(default_pool, 256);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen str_append_n(stream->line_str, stream->buffer + stream->skip,
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenstatic char *i_stream_last_line(struct istream_private *_stream)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if (_stream->istream.eof && _stream->skip != _stream->pos &&
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen /* the last line is missing LF and we want to return it. */
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen return i_stream_next_line_finish(_stream, _stream->pos);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenchar *i_stream_next_line(struct istream *stream)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = stream->real_stream;
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen const unsigned char *pos;
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen pos = memchr(_stream->buffer + _stream->skip, '\n',
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainenchar *i_stream_read_next_line(struct istream *stream)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen return i_stream_last_line(stream->real_stream);
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainenbool i_stream_last_line_crlf(struct istream *stream)
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenconst unsigned char *
68a4946b12583b88fa802e52ebee45cd96056772Timo Siraineni_stream_get_data(const struct istream *stream, size_t *size_r)
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen const struct istream_private *_stream = stream->real_stream;
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainensize_t i_stream_get_data_size(const struct istream *stream)
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen const struct istream_private *_stream = stream->real_stream;
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenunsigned char *i_stream_get_modifiable_data(const struct istream *stream,
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen const struct istream_private *_stream = stream->real_stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (_stream->skip >= _stream->pos || _stream->w_buffer == NULL) {
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainenint i_stream_read_data(struct istream *stream, const unsigned char **data_r,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* we need more data */
abe8754852e70763e92f74caabbcc13d0917714cTimo Sirainen } while (ret > 0);
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen /* need to read more */
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen /* we read at least some new data */
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenvoid i_stream_compress(struct istream_private *stream)
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen memmove(stream->w_buffer, stream->w_buffer + stream->skip,
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenvoid i_stream_grow_buffer(struct istream_private *stream, size_t bytes)
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen if (stream->buffer_size <= stream->init_buffer_size)
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen stream->buffer_size = stream->init_buffer_size;
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen stream->buffer_size = nearest_power(stream->buffer_size);
97e62b2b36dda0acb3215667042f5c80cdee8155Timo Sirainen if (stream->buffer_size > stream->max_buffer_size)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen stream->buffer_size = stream->max_buffer_size;
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen stream->w_buffer = i_realloc(stream->w_buffer, old_size,
dd2df6a67f10792ce31a3666197c0b6885893a3aTimo Sirainenbool i_stream_try_alloc(struct istream_private *stream,
14175321ddb88619015866978c05a27786ca4814Timo Sirainen if (wanted_size > stream->buffer_size - stream->pos) {
14175321ddb88619015866978c05a27786ca4814Timo Sirainen /* remove the unused bytes from beginning of buffer */
14175321ddb88619015866978c05a27786ca4814Timo Sirainen stream->buffer_size < stream->max_buffer_size) {
14175321ddb88619015866978c05a27786ca4814Timo Sirainen /* buffer is full - grow it */
14175321ddb88619015866978c05a27786ca4814Timo Sirainen i_stream_grow_buffer(stream, I_STREAM_MIN_SIZE);
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainenvoid *i_stream_alloc(struct istream_private *stream, size_t size)
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen i_stream_try_alloc(stream, size, &avail_size);
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen stream->buffer_size = nearest_power(stream->pos + size);
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen stream->w_buffer = i_realloc(stream->w_buffer, old_size,
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen i_stream_try_alloc(stream, size, &avail_size);
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainenbool i_stream_add_data(struct istream *_stream, const unsigned char *data,
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen struct istream_private *stream = _stream->real_stream;
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen memcpy(stream->w_buffer + stream->pos, data, size);
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainenvoid i_stream_set_input_pending(struct istream *stream, bool pending)
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainenvoid i_stream_switch_ioloop(struct istream *stream)
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen if (stream->real_stream->switch_ioloop != NULL)
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen stream->real_stream->switch_ioloop(stream->real_stream);
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainenvoid i_stream_set_io(struct istream *stream, struct io *io)
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainenvoid i_stream_unset_io(struct istream *stream, struct io *io)
a94936bafd127680184da114c6a177b37ff656e5Timo Siraineni_stream_default_set_max_buffer_size(struct iostream_private *stream,
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen i_stream_set_max_buffer_size(_stream->parent, max_size);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstatic void i_stream_default_close(struct iostream_private *stream,
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainenstatic void i_stream_default_destroy(struct iostream_private *stream)
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
032964c7cc6788188b63ae6270fc26cbd4a3ca26Timo Siraineni_stream_default_seek_seekable(struct istream_private *stream,
032964c7cc6788188b63ae6270fc26cbd4a3ca26Timo Sirainenvoid i_stream_default_seek_nonseekable(struct istream_private *stream,
66d84e6f0ae34a3cf5b8fa8e009d6caf025b6a2aTimo Sirainen i_panic("stream %s doesn't support seeking backwards",
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen if (available <= v_offset - stream->istream.v_offset)
5df8396a7cbad0b38b83a86667fb3d4c223f6f7cTimo Siraineni_stream_default_stat(struct istream_private *stream, bool exact)
d5b3f66491101aba8667369586c95c615cb26ae6Timo Sirainen return stream->istream.stream_errno == 0 ? 0 : -1;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen if (i_stream_stat(stream->parent, exact, &st) < 0)
9db5ade1c16c7f67c51004f28c28ea335755d3f0Timo Sirainen if (exact && !stream->stream_size_passthrough) {
9db5ade1c16c7f67c51004f28c28ea335755d3f0Timo Sirainen /* exact size is not known, even if parent returned something */
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Siraineni_stream_default_get_size(struct istream_private *stream,
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainenvoid i_stream_init_parent(struct istream_private *_stream,
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen _stream->access_counter = parent->real_stream->access_counter;
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen _stream->parent_start_offset = parent->v_offset;
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen _stream->parent_expected_offset = parent->v_offset;
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen _stream->abs_start_offset = parent->v_offset +
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen /* if parent stream is an istream-error, copy the error */
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen _stream->istream.stream_errno = parent->stream_errno;
9511a40d933181045343110c8101b75887062aaeTimo Siraineni_stream_create(struct istream_private *_stream, struct istream *parent, int fd)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen _stream->iostream.close = i_stream_default_close;
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen _stream->iostream.destroy = i_stream_default_destroy;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen _stream->get_size = i_stream_default_get_size;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen if (_stream->iostream.set_max_buffer_size == NULL) {
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen _stream->init_buffer_size = I_STREAM_MIN_SIZE;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen memset(&_stream->statbuf, 0, sizeof(_stream->statbuf));
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainenstruct istream *i_stream_create_error(int stream_errno)
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen i_stream_set_name(&stream->istream, "(error)");
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Siraineni_stream_create_error_str(int stream_errno, const char *fmt, ...)