dovecot-2.2: lib: Added i_stream_create_failure_at() to inject E...

dovecot at dovecot.org dovecot at dovecot.org
Tue Jun 16 13:43:09 UTC 2015


details:   http://hg.dovecot.org/dovecot-2.2/rev/99827acc1888
changeset: 18865:99827acc1888
user:      Timo Sirainen <tss at iki.fi>
date:      Tue Jun 16 16:21:56 2015 +0300
description:
lib: Added i_stream_create_failure_at() to inject EIO at given offset in istream.

diffstat:

 src/lib/Makefile.am               |   3 +
 src/lib/istream-failure-at.c      |  88 +++++++++++++++++++++++++++++++++++++++
 src/lib/istream-failure-at.h      |  10 ++++
 src/lib/test-istream-failure-at.c |  46 ++++++++++++++++++++
 src/lib/test-lib.c                |   1 +
 src/lib/test-lib.h                |   1 +
 6 files changed, 149 insertions(+), 0 deletions(-)

diffs (205 lines):

diff -r 80c1be850fdc -r 99827acc1888 src/lib/Makefile.am
--- a/src/lib/Makefile.am	Tue Jun 16 14:12:59 2015 +0300
+++ b/src/lib/Makefile.am	Tue Jun 16 16:21:56 2015 +0300
@@ -65,6 +65,7 @@
 	istream-concat.c \
 	istream-crlf.c \
 	istream-data.c \
+	istream-failure-at.c \
 	istream-file.c \
 	istream-hash.c \
 	istream-jsonstr.c \
@@ -203,6 +204,7 @@
 	istream-chain.h \
 	istream-concat.h \
 	istream-crlf.h \
+	istream-failure-at.h \
 	istream-file-private.h \
 	istream-hash.h \
 	istream-jsonstr.h \
@@ -306,6 +308,7 @@
 	test-istream-base64-encoder.c \
 	test-istream-concat.c \
 	test-istream-crlf.c \
+	test-istream-failure-at.c \
 	test-istream-seekable.c \
 	test-istream-tee.c \
 	test-istream-unix.c \
diff -r 80c1be850fdc -r 99827acc1888 src/lib/istream-failure-at.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/istream-failure-at.c	Tue Jun 16 16:21:56 2015 +0300
@@ -0,0 +1,88 @@
+/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "istream-private.h"
+#include "istream-failure-at.h"
+
+struct failure_at_istream {
+	struct istream_private istream;
+	char *error_string;
+	uoff_t failure_offset;
+};
+
+static void i_stream_failure_at_destroy(struct iostream_private *stream)
+{
+	struct failure_at_istream *fstream =
+		(struct failure_at_istream *)stream;
+
+	i_free(fstream->error_string);
+}
+
+static ssize_t
+i_stream_failure_at_read(struct istream_private *stream)
+{
+	struct failure_at_istream *fstream = (struct failure_at_istream *)stream;
+	uoff_t new_offset;
+	ssize_t ret;
+
+	i_stream_seek(stream->parent, stream->parent_start_offset +
+		      stream->istream.v_offset);
+
+	ret = i_stream_read_copy_from_parent(&stream->istream);
+	new_offset = stream->istream.v_offset + (stream->pos - stream->skip);
+	if (ret >= 0 && new_offset >= fstream->failure_offset) {
+		if (stream->istream.v_offset >= fstream->failure_offset) {
+			/* we already passed the wanted failure offset,
+			   return error immediately. */
+			stream->pos = stream->skip;
+			stream->istream.stream_errno = errno = EIO;
+			io_stream_set_error(&stream->iostream, "%s",
+					    fstream->error_string);
+			ret = -1;
+		} else {
+			/* return data up to the wanted failure offset and
+			   on the next read() call return failure */
+			size_t new_pos = fstream->failure_offset -
+				stream->istream.v_offset + stream->skip;
+			i_assert(new_pos >= stream->skip &&
+				 stream->pos >= new_pos);
+			ret -= stream->pos - new_pos;
+			stream->pos = new_pos;
+		}
+	} else if (ret < 0 && stream->istream.stream_errno == 0 &&
+		   fstream->failure_offset == (uoff_t)-1) {
+		/* failure at EOF */
+		stream->istream.stream_errno = errno = EIO;
+		io_stream_set_error(&stream->iostream, "%s",
+				    fstream->error_string);
+	}
+	return ret;
+}
+
+struct istream *
+i_stream_create_failure_at(struct istream *input, uoff_t failure_offset,
+			   const char *error_string)
+{
+	struct failure_at_istream *fstream;
+
+	fstream = i_new(struct failure_at_istream, 1);
+	fstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
+	fstream->istream.stream_size_passthrough = TRUE;
+
+	fstream->istream.read = i_stream_failure_at_read;
+	fstream->istream.iostream.destroy = i_stream_failure_at_destroy;
+
+	fstream->istream.istream.blocking = input->blocking;
+	fstream->istream.istream.seekable = input->seekable;
+
+	fstream->error_string = i_strdup(error_string);
+	fstream->failure_offset = failure_offset;
+	return i_stream_create(&fstream->istream, input,
+			       i_stream_get_fd(input));
+}
+
+struct istream *
+i_stream_create_failure_at_eof(struct istream *input, const char *error_string)
+{
+	return i_stream_create_failure_at(input, (uoff_t)-1, error_string);
+}
diff -r 80c1be850fdc -r 99827acc1888 src/lib/istream-failure-at.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/istream-failure-at.h	Tue Jun 16 16:21:56 2015 +0300
@@ -0,0 +1,10 @@
+#ifndef ISTREAM_FAILURE_AT_H
+#define ISTREAM_FAILURE_AT_H
+
+struct istream *
+i_stream_create_failure_at(struct istream *input, uoff_t failure_offset,
+			   const char *error_string);
+struct istream *
+i_stream_create_failure_at_eof(struct istream *input, const char *error_string);
+
+#endif
diff -r 80c1be850fdc -r 99827acc1888 src/lib/test-istream-failure-at.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/test-istream-failure-at.c	Tue Jun 16 16:21:56 2015 +0300
@@ -0,0 +1,46 @@
+/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */
+
+#include "test-lib.h"
+#include "istream.h"
+#include "istream-failure-at.h"
+
+#define TEST_DATA_LENGTH 128
+#define TEST_ERRMSG "test-istream-failure-at error triggered"
+
+void test_istream_failure_at(void)
+{
+	struct istream *input, *data_input;
+	unsigned char test_data[TEST_DATA_LENGTH];
+	unsigned int i;
+	ssize_t ret;
+
+	test_begin("istream failure at");
+	for (i = 0; i < sizeof(test_data); i++)
+		test_data[i] = i;
+	data_input = i_stream_create_from_data(test_data, sizeof(test_data));
+	for (i = 0; i < TEST_DATA_LENGTH; i++) {
+		i_stream_seek(data_input, 0);
+		input = i_stream_create_failure_at(data_input, i, TEST_ERRMSG);
+		while ((ret = i_stream_read(input)) > 0)
+			i_stream_skip(input, ret);
+		test_assert_idx(ret == -1 && input->v_offset == i &&
+				input->stream_errno == EIO &&
+				strcmp(i_stream_get_error(input), TEST_ERRMSG) == 0, i);
+		i_stream_destroy(&input);
+	}
+	/* shouldn't fail */
+	i_stream_seek(data_input, 0);
+	input = i_stream_create_failure_at(data_input, TEST_DATA_LENGTH, TEST_ERRMSG);
+	while ((ret = i_stream_read(input)) > 0)
+		i_stream_skip(input, ret);
+	test_assert(ret == -1 && input->stream_errno == 0);
+	/* fail at EOF */
+	i_stream_seek(data_input, 0);
+	input = i_stream_create_failure_at_eof(data_input, TEST_ERRMSG);
+	while ((ret = i_stream_read(input)) > 0)
+		i_stream_skip(input, ret);
+	test_assert_idx(ret == -1 && input->v_offset == TEST_DATA_LENGTH &&
+			input->stream_errno == EIO &&
+			strcmp(i_stream_get_error(input), TEST_ERRMSG) == 0, i);
+	test_end();
+}
diff -r 80c1be850fdc -r 99827acc1888 src/lib/test-lib.c
--- a/src/lib/test-lib.c	Tue Jun 16 14:12:59 2015 +0300
+++ b/src/lib/test-lib.c	Tue Jun 16 16:21:56 2015 +0300
@@ -26,6 +26,7 @@
 		test_istream_base64_encoder,
 		test_istream_concat,
 		test_istream_crlf,
+		test_istream_failure_at,
 		test_istream_seekable,
 		test_istream_tee,
 		test_istream_unix,
diff -r 80c1be850fdc -r 99827acc1888 src/lib/test-lib.h
--- a/src/lib/test-lib.h	Tue Jun 16 14:12:59 2015 +0300
+++ b/src/lib/test-lib.h	Tue Jun 16 16:21:56 2015 +0300
@@ -27,6 +27,7 @@
 void test_istream_base64_encoder(void);
 void test_istream_concat(void);
 void test_istream_crlf(void);
+void test_istream_failure_at(void);
 void test_istream_seekable(void);
 void test_istream_tee(void);
 void test_istream_unix(void);


More information about the dovecot-cvs mailing list