Mercurial > dovecot > core-2.2
changeset 18866:1c7288c054b1
lib: Added o_stream_create_failure_at() to inject EIO at given offset in ostream
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 16 Jun 2015 16:22:18 +0300 |
parents | 99827acc1888 |
children | c6ed48c7f2a0 |
files | src/lib/Makefile.am src/lib/ostream-failure-at.c src/lib/ostream-failure-at.h src/lib/test-lib.c src/lib/test-lib.h src/lib/test-ostream-failure-at.c |
diffstat | 6 files changed, 175 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib/Makefile.am Tue Jun 16 16:21:56 2015 +0300 +++ b/src/lib/Makefile.am Tue Jun 16 16:22:18 2015 +0300 @@ -109,6 +109,7 @@ numpack.c \ ostream.c \ ostream-buffer.c \ + ostream-failure-at.c \ ostream-file.c \ ostream-hash.c \ ostream-rawlog.c \ @@ -237,6 +238,7 @@ nfs-workarounds.h \ numpack.h \ ostream.h \ + ostream-failure-at.h \ ostream-hash.h \ ostream-private.h \ ostream-rawlog.h \ @@ -318,6 +320,7 @@ test-mempool-alloconly.c \ test-net.c \ test-numpack.c \ + test-ostream-failure-at.c \ test-ostream-file.c \ test-primes.c \ test-printf-format-fix.c \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/ostream-failure-at.c Tue Jun 16 16:22:18 2015 +0300 @@ -0,0 +1,108 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "buffer.h" +#include "ostream-private.h" +#include "ostream-failure-at.h" + +struct failure_at_ostream { + struct ostream_private ostream; + char *error_string; + uoff_t failure_offset; + bool failed; +}; + +static void o_stream_failure_at_destroy(struct iostream_private *stream) +{ + struct failure_at_ostream *fstream = + (struct failure_at_ostream *)stream; + + i_free(fstream->error_string); +} + +static ssize_t +o_stream_failure_at_sendv(struct ostream_private *stream, + const struct const_iovec *iov, unsigned int iov_count) +{ + struct failure_at_ostream *fstream = + (struct failure_at_ostream *)stream; + unsigned int i; + struct const_iovec *iov_dup; + unsigned int iov_dup_count; + uoff_t bytes_until_failure; + ssize_t ret; + + if (fstream->failure_offset <= stream->ostream.offset) { + io_stream_set_error(&stream->iostream, "%s", + fstream->error_string); + stream->ostream.stream_errno = errno = EIO; + fstream->failed = TRUE; + return -1; + } + bytes_until_failure = fstream->failure_offset - stream->ostream.offset; + + iov_dup = i_new(struct const_iovec, iov_count); + iov_dup_count = iov_count; + for (i = 0; i < iov_count; i++) { + iov_dup[i] = iov[i]; + if (iov_dup[i].iov_len >= bytes_until_failure) { + iov_dup[i].iov_len = bytes_until_failure; + iov_dup_count = i+1; + break; + } + } + ret = o_stream_sendv(stream->parent, iov_dup, iov_dup_count); + i_free(iov_dup); + + if (ret < 0) { + o_stream_copy_error_from_parent(stream); + return -1; + } + stream->ostream.offset += ret; + return ret; +} + +static int +o_stream_failure_at_flush(struct ostream_private *stream) +{ + struct failure_at_ostream *fstream = + (struct failure_at_ostream *)stream; + + if (fstream->failed) { + io_stream_set_error(&stream->iostream, "%s", + fstream->error_string); + stream->ostream.stream_errno = errno = EIO; + return -1; + } + return o_stream_flush(stream->parent); +} + +struct ostream * +o_stream_create_failure_at(struct ostream *output, uoff_t failure_offset, + const char *error_string) +{ + struct failure_at_ostream *fstream; + + fstream = i_new(struct failure_at_ostream, 1); + fstream->ostream.sendv = o_stream_failure_at_sendv; + fstream->ostream.flush = o_stream_failure_at_flush; + fstream->ostream.iostream.destroy = o_stream_failure_at_destroy; + fstream->failure_offset = failure_offset; + fstream->error_string = i_strdup(error_string); + return o_stream_create(&fstream->ostream, output, + o_stream_get_fd(output)); +} + +struct ostream * +o_stream_create_failure_at_flush(struct ostream *output, const char *error_string) +{ + struct failure_at_ostream *fstream; + + fstream = i_new(struct failure_at_ostream, 1); + fstream->ostream.flush = o_stream_failure_at_flush; + fstream->ostream.iostream.destroy = o_stream_failure_at_destroy; + fstream->error_string = i_strdup(error_string); + fstream->failed = TRUE; + return o_stream_create(&fstream->ostream, output, + o_stream_get_fd(output)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/ostream-failure-at.h Tue Jun 16 16:22:18 2015 +0300 @@ -0,0 +1,10 @@ +#ifndef OSTREAM_FAILURE_AT_H +#define OSTREAM_FAILURE_AT_H + +struct ostream * +o_stream_create_failure_at(struct ostream *output, uoff_t failure_offset, + const char *error_string); +struct ostream * +o_stream_create_failure_at_flush(struct ostream *output, const char *error_string); + +#endif
--- a/src/lib/test-lib.c Tue Jun 16 16:21:56 2015 +0300 +++ b/src/lib/test-lib.c Tue Jun 16 16:22:18 2015 +0300 @@ -36,6 +36,7 @@ test_mempool_alloconly, test_net, test_numpack, + test_ostream_failure_at, test_ostream_file, test_primes, test_printf_format_fix,
--- a/src/lib/test-lib.h Tue Jun 16 16:21:56 2015 +0300 +++ b/src/lib/test-lib.h Tue Jun 16 16:22:18 2015 +0300 @@ -38,6 +38,7 @@ enum fatal_test_state fatal_mempool(int); void test_net(void); void test_numpack(void); +void test_ostream_failure_at(void); void test_ostream_file(void); void test_primes(void); void test_printf_format_fix(void);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/test-ostream-failure-at.c Tue Jun 16 16:22:18 2015 +0300 @@ -0,0 +1,52 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "test-lib.h" +#include "buffer.h" +#include "ostream.h" +#include "ostream-failure-at.h" + +#define TEST_DATA_LENGTH 128 +#define TEST_ERRMSG "test-ostream-failure-at error triggered" + +void test_ostream_failure_at(void) +{ + unsigned char test_data[TEST_DATA_LENGTH]; + struct ostream *output, *buf_output; + buffer_t *buf = buffer_create_dynamic(pool_datastack_create(), 256); + unsigned int i; + + test_begin("ostream failure at"); + for (i = 0; i < sizeof(test_data); i++) + test_data[i] = i; + for (i = 0; i < TEST_DATA_LENGTH; i++) { + buf_output = o_stream_create_buffer(buf); + output = o_stream_create_failure_at(buf_output, i, TEST_ERRMSG); + if (i > 0) + test_assert(o_stream_send(output, test_data, sizeof(test_data)) == i); + test_assert_idx(o_stream_send(output, test_data, sizeof(test_data)) == -1 && + output->offset == i && + output->stream_errno == EIO && + strcmp(o_stream_get_error(output), TEST_ERRMSG) == 0, i); + o_stream_destroy(&output); + o_stream_destroy(&buf_output); + } + /* shouldn't fail */ + buf_output = o_stream_create_buffer(buf); + output = o_stream_create_failure_at(buf_output, TEST_DATA_LENGTH, TEST_ERRMSG); + test_assert(o_stream_send(output, test_data, sizeof(test_data)) == TEST_DATA_LENGTH); + test_assert(o_stream_flush(output) > 0 && + output->offset == TEST_DATA_LENGTH && + output->stream_errno == 0); + o_stream_destroy(&output); + o_stream_destroy(&buf_output); + + /* fail at flush */ + buf_output = o_stream_create_buffer(buf); + output = o_stream_create_failure_at_flush(buf_output, TEST_ERRMSG); + test_assert(o_stream_send(output, test_data, sizeof(test_data)) == TEST_DATA_LENGTH); + test_assert(o_stream_flush(output) < 0 && output->stream_errno == EIO && + strcmp(o_stream_get_error(output), TEST_ERRMSG) == 0); + o_stream_destroy(&output); + o_stream_destroy(&buf_output); + test_end(); +}