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));