Mercurial > dovecot > core-2.2
changeset 22982:697e36c7feae
lib-dcrypt: istream-decrypt - Add support for getting stream size
author | Timo Sirainen <timo.sirainen@dovecot.fi> |
---|---|
date | Tue, 05 Jun 2018 15:31:20 +0300 |
parents | acc052049f0b |
children | f2f813d047c8 |
files | src/lib-dcrypt/istream-decrypt.c |
diffstat | 1 files changed, 49 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-dcrypt/istream-decrypt.c Tue Jun 05 13:34:02 2018 +0300 +++ b/src/lib-dcrypt/istream-decrypt.c Tue Jun 05 15:31:20 2018 +0300 @@ -40,6 +40,10 @@ struct dcrypt_context_hmac *ctx_mac; enum decrypt_istream_format format; + + /* Initially (uoff_t)-1. Otherwise it's the exact known stream size, + which can be used by stat() / get_size(). */ + uoff_t cached_stream_size; }; static void i_stream_decrypt_reset(struct decrypt_istream *dstream) @@ -855,6 +859,47 @@ i_unreached(); } +static int +seekable_i_stream_get_size(struct istream_private *stream) +{ + struct decrypt_istream *dstream = + (struct decrypt_istream *)stream; + + if (dstream->cached_stream_size == (uoff_t)-1) { + uoff_t old_offset = stream->istream.v_offset; + ssize_t ret; + + do { + i_stream_skip(&stream->istream, + i_stream_get_data_size(&stream->istream)); + } while ((ret = i_stream_read(&stream->istream)) > 0); + i_assert(ret == -1); + if (stream->istream.stream_errno != 0) + return -1; + + dstream->cached_stream_size = stream->istream.v_offset; + i_stream_seek(&stream->istream, old_offset); + } + stream->statbuf.st_size = dstream->cached_stream_size; + return 0; +} + +static int i_stream_decrypt_stat(struct istream_private *stream, bool exact) +{ + const struct stat *st; + + if (i_stream_stat(stream->parent, exact, &st) < 0) { + stream->istream.stream_errno = stream->parent->stream_errno; + return -1; + } + stream->statbuf = *st; + if (exact) { + if (seekable_i_stream_get_size(stream) < 0) + return -1; + } + return 0; +} + static void i_stream_decrypt_close(struct iostream_private *stream, bool close_parent) @@ -894,8 +939,10 @@ dstream = i_new(struct decrypt_istream, 1); dstream->istream.max_buffer_size = input->real_stream->max_buffer_size; dstream->istream.read = i_stream_decrypt_read; - if (input->seekable) + if (input->seekable) { dstream->istream.seek = i_stream_decrypt_seek; + dstream->istream.stat = i_stream_decrypt_stat; + } dstream->istream.iostream.close = i_stream_decrypt_close; dstream->istream.iostream.destroy = i_stream_decrypt_destroy; @@ -904,6 +951,7 @@ dstream->istream.istream.seekable = input->seekable; dstream->buf = buffer_create_dynamic(default_pool, 512); + dstream->cached_stream_size = (uoff_t)-1; (void)i_stream_create(&dstream->istream, input, i_stream_get_fd(input));