# HG changeset patch # User Timo Sirainen # Date 1528194842 -10800 # Node ID acc052049f0bddd915169d0cfa2133b6b812948f # Parent fed657e0b156bf0d86749cb26ab3584fd42220b0 lib-dcrypt: istream-decrypt - Add support for seeking diff -r fed657e0b156 -r acc052049f0b src/lib-dcrypt/istream-decrypt.c --- a/src/lib-dcrypt/istream-decrypt.c Tue Jun 05 13:25:30 2018 +0300 +++ b/src/lib-dcrypt/istream-decrypt.c Tue Jun 05 13:34:02 2018 +0300 @@ -21,6 +21,7 @@ struct decrypt_istream { struct istream_private istream; buffer_t *buf; + bool symmetric; i_stream_decrypt_get_key_callback_t *key_callback; void *key_context; @@ -41,6 +42,26 @@ enum decrypt_istream_format format; }; +static void i_stream_decrypt_reset(struct decrypt_istream *dstream) +{ + dstream->finalized = FALSE; + dstream->use_mac = FALSE; + + dstream->ftr = 0; + dstream->pos = 0; + dstream->flags = 0; + + if (!dstream->symmetric) { + dstream->initialized = FALSE; + if (dstream->ctx_sym != NULL) + dcrypt_ctx_sym_destroy(&dstream->ctx_sym); + if (dstream->ctx_mac != NULL) + dcrypt_ctx_hmac_destroy(&dstream->ctx_mac); + } + i_free(dstream->iv); + dstream->format = DECRYPT_FORMAT_V1; +} + enum decrypt_istream_format i_stream_encrypt_get_format(const struct istream *input) { return ((const struct decrypt_istream*)input->real_stream)->format; @@ -818,6 +839,22 @@ } } +static void +i_stream_decrypt_seek(struct istream_private *stream, uoff_t v_offset, + bool mark ATTR_UNUSED) +{ + struct decrypt_istream *dstream = + (struct decrypt_istream *)stream; + + if (i_stream_nonseekable_try_seek(stream, v_offset)) + return; + + /* have to seek backwards - reset crypt state and retry */ + i_stream_decrypt_reset(dstream); + if (!i_stream_nonseekable_try_seek(stream, v_offset)) + i_unreached(); +} + static void i_stream_decrypt_close(struct iostream_private *stream, bool close_parent) @@ -857,12 +894,14 @@ 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) + dstream->istream.seek = i_stream_decrypt_seek; dstream->istream.iostream.close = i_stream_decrypt_close; dstream->istream.iostream.destroy = i_stream_decrypt_destroy; dstream->istream.istream.readable_fd = FALSE; dstream->istream.istream.blocking = input->blocking; - dstream->istream.istream.seekable = FALSE; + dstream->istream.istream.seekable = input->seekable; dstream->buf = buffer_create_dynamic(default_pool, 512); @@ -891,6 +930,7 @@ dstream = i_stream_create_decrypt_common(input); dstream->use_mac = FALSE; dstream->initialized = TRUE; + dstream->symmetric = TRUE; if (!dcrypt_ctx_sym_init(ctx, &error)) ec = -1; else ec = 0; diff -r fed657e0b156 -r acc052049f0b src/lib-dcrypt/test-stream.c --- a/src/lib-dcrypt/test-stream.c Tue Jun 05 13:25:30 2018 +0300 +++ b/src/lib-dcrypt/test-stream.c Tue Jun 05 13:34:02 2018 +0300 @@ -367,6 +367,16 @@ if (is_2->stream_errno != 0) i_debug("error: %s", i_stream_get_error(is_2)); + /* test seeking */ + for (size_t i = sizeof(payload)-100; i > 100; i -= 100) { + i_stream_seek(is_2, i); + test_assert_idx(i_stream_read_data(is_2, &ptr, &siz, 0) == 1, i); + test_assert_idx(memcmp(ptr, payload + i, siz) == 0, i); + } + i_stream_seek(is_2, 0); + test_assert(i_stream_read_data(is_2, &ptr, &siz, 0) == 1); + test_assert(memcmp(ptr, payload, siz) == 0); + i_stream_unref(&is); i_stream_unref(&is_2); buffer_free(&buf);