istream.c revision 5a9bbcb13b2dd2cf9a825c7ed09fe7ee143b1275
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic bool i_stream_is_buffer_invalid(const struct istream_private *stream);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenvoid i_stream_set_name(struct istream *stream, const char *name)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen stream->real_stream->iostream.name = i_strdup(name);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenconst char *i_stream_get_name(struct istream *stream)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen while (stream->real_stream->iostream.name == NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic void i_stream_close_full(struct istream *stream, bool close_parents)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen io_stream_close(&stream->real_stream->iostream, close_parents);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen io_stream_ref(&stream->real_stream->iostream);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_stream_snapshot_free(&_stream->prev_snapshot);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid i_stream_add_destroy_callback(struct istream *stream,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen io_stream_add_destroy_callback(&stream->real_stream->iostream,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenvoid i_stream_remove_destroy_callback(struct istream *stream,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen io_stream_remove_destroy_callback(&stream->real_stream->iostream,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct istream_private *_stream = stream->real_stream;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenconst char *i_stream_get_error(struct istream *stream)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* we'll only return errors for streams that have stream_errno set or
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen that have reached EOF. we might be returning unintended error
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen otherwise. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen for (s = stream; s != NULL; s = s->real_stream->parent) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenconst char *i_stream_get_disconnect_reason(struct istream *stream)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return io_stream_get_disconnect_reason(stream, NULL);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid i_stream_set_init_buffer_size(struct istream *stream, size_t size)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenvoid i_stream_set_max_buffer_size(struct istream *stream, size_t max_size)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen io_stream_set_max_buffer_size(&stream->real_stream->iostream, max_size);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainensize_t i_stream_get_max_buffer_size(struct istream *stream)
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen if (max_size < stream->real_stream->max_buffer_size)
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen max_size = stream->real_stream->max_buffer_size;
d22301419109ed4a38351715e6760011421dadecTimo Sirainenvoid i_stream_set_return_partial_line(struct istream *stream, bool set)
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainenvoid i_stream_set_persistent_buffers(struct istream *stream, bool set)
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen stream->real_stream->nonpersistent_buffers = !set;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenvoid i_stream_set_blocking(struct istream *stream, bool blocking)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen fd_set_nonblock(stream->real_stream->fd, !blocking);
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Sirainenstatic void i_stream_update(struct istream_private *stream)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen stream->parent_expected_offset = stream->parent->v_offset;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic bool snapshot_has_memarea(struct istream_snapshot *snapshot,
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen return snapshot_has_memarea(snapshot->prev_snapshot, memarea);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Siraineni_stream_default_snapshot(struct istream_private *stream,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (snapshot_has_memarea(prev_snapshot, stream->memarea))
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen /* This stream has a memarea. Reference it, so we can later on
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen rollback if needed. */
939a0d82523538b2de38a02bc9f790a67b7ebf47Timo Sirainen /* Assume that memarea would be used normally, but
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen now it's NULL because the buffer is empty and
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen empty buffers are freed. */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_panic("%s is missing istream.snapshot() implementation",
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen return _parent_stream->snapshot(_parent_stream, prev_snapshot);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenvoid i_stream_snapshot_free(struct istream_snapshot **_snapshot)
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen struct istream_snapshot *snapshot = *_snapshot;
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Sirainen i_stream_snapshot_free(&snapshot->prev_snapshot);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Siraineni_stream_noop_snapshot(struct istream_private *stream ATTR_UNUSED,
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen struct istream_private *_stream = stream->real_stream;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const unsigned char *prev_data = _stream->buffer;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen size_t prev_skip = _stream->skip, prev_pos = _stream->pos;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen bool invalid = i_stream_is_buffer_invalid(_stream);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen memcpy(prev_buf, prev_data + prev_skip, prev_pos - prev_skip);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen memcpy(prev_buf+2, prev_data + prev_pos - 2, 2);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen _stream->snapshot(_stream, _stream->prev_snapshot);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_stream_snapshot_free(&_stream->prev_snapshot);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_assert((_stream->pos - _stream->skip) == (prev_pos - prev_skip));
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_assert(memcmp(prev_buf, prev_data + prev_skip, prev_pos - prev_skip) == 0);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_assert(memcmp(prev_buf, prev_data + prev_skip, 2) == 0);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_assert(memcmp(prev_buf+2, prev_data + prev_pos - 2, 2) == 0);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenssize_t i_stream_read_memarea(struct istream *stream)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct istream_private *_stream = stream->real_stream;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_stream_seek(_stream->parent, _stream->parent_expected_offset);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_assert(old_size <= _stream->pos - _stream->skip);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* error handling should be easier if we now just
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen assume the stream is now at EOF */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_assert(old_size == _stream->pos - _stream->skip);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_assert((size_t)ret+old_size == _stream->pos - _stream->skip);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* error handling should be easier if we now just
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen assume the stream is now at EOF. Note that we could get here
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen even if read() didn't return -1, although that's a little
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen bit sloppy istream implementation. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* verify that parents' access_counters are valid. the parent's
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_stream_read() should guarantee this. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(!i_stream_is_buffer_invalid(_stream));
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenint i_stream_read_more_memarea(struct istream *stream,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid i_stream_get_last_read_time(struct istream *stream, struct timeval *tv_r)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *tv_r = stream->real_stream->last_read_timeval;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenssize_t i_stream_read_copy_from_parent(struct istream *istream)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct istream_private *stream = istream->real_stream;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
42270b2d8d9bb0d04b16e0ead727154b32399a3fTimo Sirainen if ((ret = i_stream_read_memarea(stream->parent)) == -2) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* check again, in case the parent stream had been seeked
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen backwards and the previous read() didn't get us far
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid i_stream_free_buffer(struct istream_private *stream)
4182d8cd818e76856a5a1e25b343fe5ddf69fd8eTimo Sirainen /* don't know how to free it */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid i_stream_skip(struct istream *stream, uoff_t count)
4182d8cd818e76856a5a1e25b343fe5ddf69fd8eTimo Sirainen struct istream_private *_stream = stream->real_stream;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* within buffer */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* have to seek forward */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen _stream->seek(_stream, stream->v_offset + count, FALSE);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic bool i_stream_can_optimize_seek(struct istream_private *stream)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* use the fast route only if the parent stream hasn't been changed */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return i_stream_can_optimize_seek(stream->parent->real_stream);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenvoid i_stream_seek(struct istream *stream, uoff_t v_offset)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct istream_private *_stream = stream->real_stream;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_stream_skip(stream, v_offset - stream->v_offset);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid i_stream_seek_mark(struct istream *stream, uoff_t v_offset)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct istream_private *_stream = stream->real_stream;
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct istream_private *_stream = stream->real_stream;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainenint i_stream_stat(struct istream *stream, bool exact, const struct stat **st_r)
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen struct istream_private *_stream = stream->real_stream;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
e3736b5d480878031c386ac55d201fcf08e68766Timo Sirainenint i_stream_get_size(struct istream *stream, bool exact, uoff_t *size_r)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen struct istream_private *_stream = stream->real_stream;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if ((ret = _stream->get_size(_stream, exact, size_r)) < 0)
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainenbool i_stream_have_bytes_left(struct istream *stream)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return i_stream_get_data_size(stream) > 0 || !stream->eof;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenuoff_t i_stream_get_absolute_offset(struct istream *stream)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen abs_offset += stream->real_stream->start_offset;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstatic char *i_stream_next_line_finish(struct istream_private *stream, size_t i)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* modify the buffer directly */
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen ret = (char *)stream->w_buffer + stream->skip;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* use a temporary string to return it */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen stream->line_str = str_new(default_pool, 256);
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen str_append_n(stream->line_str, stream->buffer + stream->skip,
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainenstatic char *i_stream_last_line(struct istream_private *_stream)
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainen if (_stream->istream.eof && _stream->skip != _stream->pos &&
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* the last line is missing LF and we want to return it. */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return i_stream_next_line_finish(_stream, _stream->pos);
a21823d90cee6a18aeab0378637472c7e3fbbab2Timo Sirainenchar *i_stream_next_line(struct istream *stream)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen struct istream_private *_stream = stream->real_stream;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen const unsigned char *pos;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen pos = memchr(_stream->buffer + _stream->skip, '\n',
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainenchar *i_stream_read_next_line(struct istream *stream)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen io_stream_set_error(&stream->real_stream->iostream,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen i_stream_get_data_size(stream), stream->v_offset);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen return i_stream_last_line(stream->real_stream);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainenbool i_stream_last_line_crlf(struct istream *stream)
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainenstatic bool i_stream_is_buffer_invalid(const struct istream_private *stream)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* the buffer can't point to parent, because it doesn't exist */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen /* we can pretty safely assume that the stream is using its
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen own private buffer, so it can never become invalid. */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen stream->parent->real_stream->access_counter) {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen /* parent has been modified behind this stream, we can't trust
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen that our buffer is valid */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen return i_stream_is_buffer_invalid(stream->parent->real_stream);
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainenconst unsigned char *
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Siraineni_stream_get_data(struct istream *stream, size_t *size_r)
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen struct istream_private *_stream = stream->real_stream;
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen /* This stream may be using parent's buffer directly as
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen _stream->buffer, but the parent stream has already been
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen modified indirectly. This means that the buffer might no
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen longer point to where we assume it points to. So we'll
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen just return the stream as empty until it's read again.
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen It's a bit ugly to suddenly drop data from the stream that
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen was already read, but since this happens only with shared
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen parent istreams the caller is hopefully aware enough that
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen something like this might happen. The other solutions would
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen be to a) try to automatically read the data back (but we
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen can't handle errors..) or b) always copy data to stream's
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen own buffer instead of pointing to parent's buffer (but this
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen causes data copying that is nearly always unnecessary). */
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen /* if we had already read until EOF, mark the stream again as
6cd263d9a9812174a63e852ad6a9a8cdf63cfd8eTimo Sirainen not being at the end of file. */
6cd263d9a9812174a63e852ad6a9a8cdf63cfd8eTimo Sirainensize_t i_stream_get_data_size(struct istream *stream)
6cd263d9a9812174a63e852ad6a9a8cdf63cfd8eTimo Sirainenunsigned char *i_stream_get_modifiable_data(struct istream *stream,
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen struct istream_private *_stream = stream->real_stream;
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen if (_stream->skip >= _stream->pos || _stream->w_buffer == NULL) {
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainenint i_stream_read_data(struct istream *stream, const unsigned char **data_r,
3b49aee9ced3b0370a3be396aca53acd5f21418cTimo Sirainen /* we need more data */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen } while (ret > 0);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* need to read more */
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen /* we read at least some new data */
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainenvoid i_stream_compress(struct istream_private *stream)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen memmove(stream->w_buffer, stream->w_buffer + stream->skip,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Siraineni_stream_w_buffer_realloc(struct istream_private *stream, size_t old_size)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen /* Nobody else is referencing the memarea.
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen We can just reallocate it. */
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen memarea_free_without_callback(&stream->memarea);
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen new_buffer = i_realloc(stream->w_buffer, old_size,
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen memcpy(new_buffer, stream->w_buffer, old_size);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainen stream->memarea = memarea_init(stream->w_buffer, stream->buffer_size,
c20d64512d687f0abf7c1a0aa4fa0174da0a18e3Timo Sirainenvoid i_stream_grow_buffer(struct istream_private *stream, size_t bytes)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (stream->buffer_size <= stream->init_buffer_size)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen stream->buffer_size = stream->init_buffer_size;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen stream->buffer_size = nearest_power(stream->buffer_size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen max_size = i_stream_get_max_buffer_size(&stream->istream);
905457e0982fc15930d90e174f271dc69f9afcf9Timo Sirainenbool i_stream_try_alloc(struct istream_private *stream,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (wanted_size > stream->buffer_size - stream->pos) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* remove the unused bytes from beginning of buffer */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* The memarea is still referenced. We can't
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen overwrite data until extra references are
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_stream_w_buffer_realloc(stream, stream->buffer_size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen } else if (stream->buffer_size < i_stream_get_max_buffer_size(&stream->istream)) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* buffer is full - grow it */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_stream_grow_buffer(stream, I_STREAM_MIN_SIZE);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Siraineni_stream_try_alloc_avoid_compress(struct istream_private *stream,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* try first with skip=0, so no compression is done */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen bool ret = i_stream_try_alloc(stream, wanted_size, size_r);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* it's full. try with compression. */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen return i_stream_try_alloc(stream, wanted_size, size_r);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenvoid *i_stream_alloc(struct istream_private *stream, size_t size)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_stream_try_alloc(stream, size, &avail_size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen stream->buffer_size = nearest_power(stream->pos + size);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_stream_try_alloc(stream, size, &avail_size);
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainenbool i_stream_add_data(struct istream *_stream, const unsigned char *data,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen struct istream_private *stream = _stream->real_stream;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen memcpy(stream->w_buffer + stream->pos, data, size);
41955c400476941fa274f18b106a5922866fd780Timo Sirainenstruct istream *i_stream_get_root_io(struct istream *stream)
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainenvoid i_stream_set_input_pending(struct istream *stream, bool pending)
41955c400476941fa274f18b106a5922866fd780Timo Sirainenvoid i_stream_switch_ioloop_to(struct istream *stream, struct ioloop *ioloop)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen io_stream_switch_ioloop_to(&stream->real_stream->iostream, ioloop);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (stream->real_stream->switch_ioloop_to != NULL) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenvoid i_stream_switch_ioloop(struct istream *stream)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_stream_switch_ioloop_to(stream, current_ioloop);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenvoid i_stream_set_io(struct istream *stream, struct io *io)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenvoid i_stream_unset_io(struct istream *stream, struct io *io)
905457e0982fc15930d90e174f271dc69f9afcf9Timo Siraineni_stream_default_set_max_buffer_size(struct iostream_private *stream,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_stream_set_max_buffer_size(_stream->parent, max_size);
2584e86cc2d8c31ba30a4109cf4ba09d1e37e28aTimo Sirainenstatic void i_stream_default_close(struct iostream_private *stream,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstatic void i_stream_default_destroy(struct iostream_private *stream)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
6d6c1517ef20e340a3aace406724fc8916f2d13fTimo Siraineni_stream_default_seek_seekable(struct istream_private *stream,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenvoid i_stream_default_seek_nonseekable(struct istream_private *stream,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen i_panic("stream %s doesn't support seeking backwards",
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* read failed */
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen ", because we have data only up to offset %"
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen stream->istream.v_offset, stream->istream.eof ? 1 : 0);
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (available <= v_offset - stream->istream.v_offset)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Siraineni_stream_default_stat(struct istream_private *stream, bool exact)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen return stream->istream.stream_errno == 0 ? 0 : -1;
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen if (i_stream_stat(stream->parent, exact, &st) < 0) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (exact && !stream->stream_size_passthrough) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* exact size is not known, even if parent returned something */
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Siraineni_stream_default_get_size(struct istream_private *stream,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenvoid i_stream_init_parent(struct istream_private *_stream,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen _stream->access_counter = parent->real_stream->access_counter;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen _stream->parent_start_offset = parent->v_offset;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen _stream->parent_expected_offset = parent->v_offset;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen /* if parent stream is an istream-error, copy the error */
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen _stream->istream.stream_errno = parent->stream_errno;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Siraineni_stream_create(struct istream_private *_stream, struct istream *parent, int fd,
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen bool noop_snapshot = (flags & ISTREAM_CREATE_FLAG_NOOP_SNAPSHOT) != 0;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen else if (_stream->memarea == NULL && !noop_snapshot) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen /* The stream has no parent and no memarea yet. We'll assume
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen that it wants to be using memareas for the reads. */
ddd5fb9499ae08f7f0d4b41306bb4fca053e493bTimo Sirainen _stream->iostream.close = i_stream_default_close;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen _stream->iostream.destroy = i_stream_default_destroy;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen _stream->get_size = i_stream_default_get_size;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen if (_stream->iostream.set_max_buffer_size == NULL) {
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen _stream->init_buffer_size = I_STREAM_MIN_SIZE;
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainenstruct istream *i_stream_create_error(int stream_errno)
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Sirainen i_stream_set_name(&stream->istream, "(error)");
dee43975a70bcdb9dc83d34d6a2b177d37bb7194Timo Siraineni_stream_create_error_str(int stream_errno, const char *fmt, ...)