Mercurial > dovecot > core-2.2
changeset 18865:99827acc1888
lib: Added i_stream_create_failure_at() to inject EIO at given offset in istream.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 16 Jun 2015 16:21:56 +0300 |
parents | 80c1be850fdc |
children | 1c7288c054b1 |
files | src/lib/Makefile.am src/lib/istream-failure-at.c src/lib/istream-failure-at.h src/lib/test-istream-failure-at.c src/lib/test-lib.c src/lib/test-lib.h |
diffstat | 6 files changed, 149 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- 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 \
--- /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); +}
--- /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
--- /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(); +}
--- 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,
--- 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);