istream.c revision 5a1b498b646b5c5dbd1b3f3861df766f560578c5
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic bool i_stream_is_buffer_invalid(const struct istream_private *stream);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid i_stream_set_name(struct istream *stream, const char *name)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen stream->real_stream->iostream.name = i_strdup(name);
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainenconst char *i_stream_get_name(struct istream *stream)
213b139965e8bde6c8aff02ffd9fd39a74c887a9Timo Sirainen while (stream->real_stream->iostream.name == NULL) {
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainenstatic void i_stream_close_full(struct istream *stream, bool close_parents)
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen io_stream_close(&stream->real_stream->iostream, close_parents);
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen io_stream_ref(&stream->real_stream->iostream);
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen struct istream_private *_stream = (*stream)->real_stream;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen if (!io_stream_unref(&(*stream)->real_stream->iostream)) {
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen i_stream_unref(&(*stream)->real_stream->parent);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_stream_free(&(*stream)->real_stream->iostream);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenvoid i_stream_add_destroy_callback(struct istream *stream,
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen io_stream_add_destroy_callback(&stream->real_stream->iostream,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid i_stream_remove_destroy_callback(struct istream *stream,
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen io_stream_remove_destroy_callback(&stream->real_stream->iostream,
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen struct istream_private *_stream = stream->real_stream;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenconst char *i_stream_get_error(struct istream *stream)
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen /* we'll only return errors for streams that have stream_errno set or
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen that have reached EOF. we might be returning unintended error
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen otherwise. */
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen for (s = stream; s != NULL; s = s->real_stream->parent) {
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainenvoid i_stream_set_init_buffer_size(struct istream *stream, size_t size)
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainenvoid i_stream_set_max_buffer_size(struct istream *stream, size_t max_size)
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen io_stream_set_max_buffer_size(&stream->real_stream->iostream, max_size);
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainensize_t i_stream_get_max_buffer_size(struct istream *stream)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenvoid i_stream_set_return_partial_line(struct istream *stream, bool set)
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainenvoid i_stream_set_persistent_buffers(struct istream *stream, bool set)
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen stream->real_stream->nonpersistent_buffers = !set;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainenstatic void i_stream_update(struct istream_private *stream)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen stream->parent_expected_offset = stream->parent->v_offset;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen struct istream_private *_stream = stream->real_stream;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_stream_seek(_stream->parent, _stream->parent_expected_offset);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_assert(old_size <= _stream->pos - _stream->skip);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* error handling should be easier if we now just
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen assume the stream is now at EOF */
c21c33a8c98972c45349066fc76ac9e2c05013c1Timo Sirainen i_assert(old_size == _stream->pos - _stream->skip);
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen i_assert((size_t)ret+old_size == _stream->pos - _stream->skip);
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen /* error handling should be easier if we now just
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen assume the stream is now at EOF. Note that we could get here
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen even if read() didn't return -1, although that's a little
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen bit sloppy istream implementation. */
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen /* verify that parents' access_counters are valid. the parent's
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen i_stream_read() should guarantee this. */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_assert(!i_stream_is_buffer_invalid(_stream));
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainenssize_t i_stream_read_copy_from_parent(struct istream *istream)
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen struct istream_private *stream = istream->real_stream;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if ((ret = i_stream_read(stream->parent)) == -2) {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen stream->buffer = i_stream_get_data(stream->parent, &pos);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen /* check again, in case the parent stream had been seeked
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen backwards and the previous read() didn't get us far
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenvoid i_stream_skip(struct istream *stream, uoff_t count)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen struct istream_private *_stream = stream->real_stream;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* within buffer */
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen /* have to seek forward */
688f0fdfb7ca946e38ae34459b0ca30b71c8457cTimo Sirainen _stream->seek(_stream, stream->v_offset + count, FALSE);
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainenstatic bool i_stream_can_optimize_seek(struct istream_private *stream)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* use the fast route only if the parent stream hasn't been changed */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return i_stream_can_optimize_seek(stream->parent->real_stream);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenvoid i_stream_seek(struct istream *stream, uoff_t v_offset)
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen struct istream_private *_stream = stream->real_stream;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen i_stream_skip(stream, v_offset - stream->v_offset);
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainenvoid i_stream_seek_mark(struct istream *stream, uoff_t v_offset)
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen struct istream_private *_stream = stream->real_stream;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen struct istream_private *_stream = stream->real_stream;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainenint i_stream_stat(struct istream *stream, bool exact, const struct stat **st_r)
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen struct istream_private *_stream = stream->real_stream;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenint i_stream_get_size(struct istream *stream, bool exact, uoff_t *size_r)
0fa842717a8b163252e55c229c37ca0c5d7ff056Timo Sirainen struct istream_private *_stream = stream->real_stream;
096953143c4032bad154637f687551856f7946cbTimo Sirainen return _stream->get_size(_stream, exact, size_r);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenbool i_stream_have_bytes_left(struct istream *stream)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return i_stream_get_data_size(stream) > 0 || !stream->eof;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenuoff_t i_stream_get_absolute_offset(struct istream *stream)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return stream->real_stream->abs_start_offset + stream->v_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic char *i_stream_next_line_finish(struct istream_private *stream, size_t i)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* modify the buffer directly */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen ret = (char *)stream->w_buffer + stream->skip;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* use a temporary string to return it */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen stream->line_str = str_new(default_pool, 256);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen str_append_n(stream->line_str, stream->buffer + stream->skip,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenstatic char *i_stream_last_line(struct istream_private *_stream)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (_stream->istream.eof && _stream->skip != _stream->pos &&
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* the last line is missing LF and we want to return it. */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return i_stream_next_line_finish(_stream, _stream->pos);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenchar *i_stream_next_line(struct istream *stream)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen struct istream_private *_stream = stream->real_stream;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen const unsigned char *pos;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen pos = memchr(_stream->buffer + _stream->skip, '\n',
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenchar *i_stream_read_next_line(struct istream *stream)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen io_stream_set_error(&stream->real_stream->iostream,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_get_data_size(stream), stream->v_offset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return i_stream_last_line(stream->real_stream);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainenbool i_stream_last_line_crlf(struct istream *stream)
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainenstatic bool i_stream_is_buffer_invalid(const struct istream_private *stream)
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen /* the buffer can't point to parent, because it doesn't exist */
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen /* we can pretty safely assume that the stream is using its
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen own private buffer, so it can never become invalid. */
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen stream->parent->real_stream->access_counter) {
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen /* parent has been modified behind this stream, we can't trust
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen that our buffer is valid */
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen return i_stream_is_buffer_invalid(stream->parent->real_stream);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainenconst unsigned char *
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Siraineni_stream_get_data(struct istream *stream, size_t *size_r)
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen struct istream_private *_stream = stream->real_stream;
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen /* This stream may be using parent's buffer directly as
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen _stream->buffer, but the parent stream has already been
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen modified indirectly. This means that the buffer might no
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen longer point to where we assume it points to. So we'll
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen just return the stream as empty until it's read again.
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen It's a bit ugly to suddenly drop data from the stream that
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen was already read, but since this happens only with shared
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen parent istreams the caller is hopefully aware enough that
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen something like this might happen. The other solutions would
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen be to a) try to automatically read the data back (but we
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen can't handle errors..) or b) always copy data to stream's
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen own buffer instead of pointing to parent's buffer (but this
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen causes data copying that is nearly always unnecessary). */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* if we had already read until EOF, mark the stream again as
37b805dfb45902b6b41c45482f67e6f98e08b0a3Timo Sirainen not being at the end of file. */
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainensize_t i_stream_get_data_size(struct istream *stream)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenunsigned char *i_stream_get_modifiable_data(struct istream *stream,
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen struct istream_private *_stream = stream->real_stream;
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen if (_stream->skip >= _stream->pos || _stream->w_buffer == NULL) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenint i_stream_read_data(struct istream *stream, const unsigned char **data_r,
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen /* we need more data */
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen } while (ret > 0);
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen /* need to read more */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* we read at least some new data */
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainenvoid i_stream_compress(struct istream_private *stream)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen memmove(stream->w_buffer, stream->w_buffer + stream->skip,
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainenvoid i_stream_grow_buffer(struct istream_private *stream, size_t bytes)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (stream->buffer_size <= stream->init_buffer_size)
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen stream->buffer_size = stream->init_buffer_size;
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen stream->buffer_size = nearest_power(stream->buffer_size);
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen if (stream->buffer_size > stream->max_buffer_size)
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen stream->buffer_size = stream->max_buffer_size;
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen stream->w_buffer = i_realloc(stream->w_buffer, old_size,
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainenbool i_stream_try_alloc(struct istream_private *stream,
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen if (wanted_size > stream->buffer_size - stream->pos) {
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen /* remove the unused bytes from beginning of buffer */
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen stream->buffer_size < stream->max_buffer_size) {
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen /* buffer is full - grow it */
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen i_stream_grow_buffer(stream, I_STREAM_MIN_SIZE);
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainenvoid *i_stream_alloc(struct istream_private *stream, size_t size)
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen i_stream_try_alloc(stream, size, &avail_size);
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen stream->buffer_size = nearest_power(stream->pos + size);
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen stream->w_buffer = i_realloc(stream->w_buffer, old_size,
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen i_stream_try_alloc(stream, size, &avail_size);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenbool i_stream_add_data(struct istream *_stream, const unsigned char *data,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen struct istream_private *stream = _stream->real_stream;
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainen memcpy(stream->w_buffer + stream->pos, data, size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid i_stream_set_input_pending(struct istream *stream, bool pending)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenvoid i_stream_switch_ioloop(struct istream *stream)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (stream->real_stream->switch_ioloop != NULL)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen stream->real_stream->switch_ioloop(stream->real_stream);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenvoid i_stream_set_io(struct istream *stream, struct io *io)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid i_stream_unset_io(struct istream *stream, struct io *io)
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Siraineni_stream_default_set_max_buffer_size(struct iostream_private *stream,
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_set_max_buffer_size(_stream->parent, max_size);
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainenstatic void i_stream_default_close(struct iostream_private *stream,
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainenstatic void i_stream_default_destroy(struct iostream_private *stream)
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Siraineni_stream_default_seek_seekable(struct istream_private *stream,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid i_stream_default_seek_nonseekable(struct istream_private *stream,
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen i_panic("stream %s doesn't support seeking backwards",
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen /* read failed */
8bae533c96e129dca8ee7b494d7de5aeb4a043a2Timo Sirainen ", because we have data only up to offset %"
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen stream->istream.v_offset, stream->istream.eof);
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen if (available <= v_offset - stream->istream.v_offset)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Siraineni_stream_default_stat(struct istream_private *stream, bool exact)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return stream->istream.stream_errno == 0 ? 0 : -1;
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen if (i_stream_stat(stream->parent, exact, &st) < 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (exact && !stream->stream_size_passthrough) {
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen /* exact size is not known, even if parent returned something */
struct istream *
struct istream *
return input;