changeset 21687:bc16d43aed49

lib: Added i_stream_create_min_sized*()
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Tue, 01 Nov 2016 18:35:48 +0200
parents e33f5589923f
children d1788e9bd7ea
files src/lib/istream-sized.c src/lib/istream-sized.h src/lib/test-istream-sized.c
diffstat 3 files changed, 82 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib/istream-sized.c	Fri Dec 23 12:52:45 2016 -0500
+++ b/src/lib/istream-sized.c	Tue Nov 01 18:35:48 2016 +0200
@@ -11,6 +11,7 @@
 	void *error_context;
 
 	uoff_t size;
+	bool min_size_only;
 };
 
 static void i_stream_sized_destroy(struct iostream_private *stream)
@@ -102,10 +103,17 @@
 		   parent is at EOF. */
 	} else if (pos > left) {
 		/* parent has more data available than expected */
-		error = sstream->error_callback(&data, sstream->error_context);
-		io_stream_set_error(&stream->iostream, "%s", error);
-		stream->istream.stream_errno = EINVAL;
-		return -1;
+		if (!sstream->min_size_only) {
+			error = sstream->error_callback(&data, sstream->error_context);
+			io_stream_set_error(&stream->iostream, "%s", error);
+			stream->istream.stream_errno = EINVAL;
+			return -1;
+		}
+		pos = left;
+		if (pos <= stream->pos) {
+			stream->istream.eof = TRUE;
+			ret = -1;
+		}
 	} else if (!stream->istream.eof) {
 		/* still more to read */
 	} else if (stream->istream.stream_errno == ENOENT) {
@@ -187,6 +195,25 @@
 	return ret;
 }
 
+struct istream *i_stream_create_min_sized(struct istream *input, uoff_t min_size)
+{
+	struct istream *ret;
+
+	ret= i_stream_create_sized(input, min_size);
+	((struct sized_istream *)ret->real_stream)->min_size_only = TRUE;
+	return ret;
+}
+
+struct istream *i_stream_create_min_sized_range(struct istream *input,
+						uoff_t offset, uoff_t min_size)
+{
+	struct istream *ret;
+
+	ret = i_stream_create_sized_range(input, offset, min_size);
+	((struct sized_istream *)ret->real_stream)->min_size_only = TRUE;
+	return ret;
+}
+
 #undef i_stream_create_sized_with_callback
 struct istream *
 i_stream_create_sized_with_callback(struct istream *input, uoff_t size,
--- a/src/lib/istream-sized.h	Fri Dec 23 12:52:45 2016 -0500
+++ b/src/lib/istream-sized.h	Tue Nov 01 18:35:48 2016 +0200
@@ -22,6 +22,10 @@
 struct istream *i_stream_create_sized(struct istream *input, uoff_t size);
 struct istream *i_stream_create_sized_range(struct istream *input,
 					    uoff_t offset, uoff_t size);
+/* Like i_stream_create_sized*(), but allow input stream's size to be larger. */
+struct istream *i_stream_create_min_sized(struct istream *input, uoff_t min_size);
+struct istream *i_stream_create_min_sized_range(struct istream *input,
+						uoff_t offset, uoff_t min_size);
 /* Same as i_stream_create_sized(), but set the error message via the
    callback. */
 struct istream *
--- a/src/lib/test-istream-sized.c	Fri Dec 23 12:52:45 2016 -0500
+++ b/src/lib/test-istream-sized.c	Tue Nov 01 18:35:48 2016 +0200
@@ -1,8 +1,7 @@
 /* Copyright (c) 2016 Dovecot authors, see the included COPYING file */
 
 #include "test-lib.h"
-#include "str.h"
-#include "istream-private.h"
+#include "istream.h"
 #include "istream-sized.h"
 
 static const struct {
@@ -54,6 +53,45 @@
 	i_stream_unref(&input_data);
 }
 
+static void test_istream_sized_full(bool exact)
+{
+	const unsigned char test_data[10] = "1234567890";
+	struct istream *test_input, *input;
+	unsigned int i, j;
+	int expected_errno;
+
+	for (i = 1; i < sizeof(test_data)*2; i++) {
+		test_input = test_istream_create_data(test_data, sizeof(test_data));
+		test_istream_set_allow_eof(test_input, FALSE);
+		test_istream_set_size(test_input, 0);
+
+		if (exact)
+			input = i_stream_create_sized(test_input, i);
+		else
+			input = i_stream_create_min_sized(test_input, i);
+		for (j = 1; j <= I_MIN(i, sizeof(test_data)); j++) {
+			test_assert_idx(i_stream_read(input) == 0, j);
+			test_istream_set_size(test_input, j);
+			test_assert_idx(i_stream_read(input) == 1, j);
+		}
+		test_assert_idx(i_stream_read(input) == 0, i);
+		if (j <= sizeof(test_data))
+			test_istream_set_size(test_input, j);
+		else
+			test_istream_set_allow_eof(test_input, TRUE);
+		test_assert_idx(i_stream_read(input) == -1 && input->eof, i);
+		if (i > sizeof(test_data))
+			expected_errno = EPIPE;
+		else if (i < sizeof(test_data) && exact)
+			expected_errno = EINVAL;
+		else
+			expected_errno = 0;
+		test_assert_idx(input->stream_errno == expected_errno, i);
+		i_stream_unref(&input);
+		i_stream_unref(&test_input);
+	}
+}
+
 void test_istream_sized(void)
 {
 	unsigned int i;
@@ -63,4 +101,11 @@
 		run_test(tests[i].input, tests[i].size, tests[i].stream_errno);
 		test_end();
 	}
+	test_begin("istream sized");
+	test_istream_sized_full(TRUE);
+	test_end();
+
+	test_begin("istream sized min");
+	test_istream_sized_full(FALSE);
+	test_end();
 }