From: Timo Sirainen Date: Fri, 23 Dec 2016 17:51:41 +0000 (-0500) Subject: lib: istream-sized - set stream_errno=EPIPE if stream is too small X-Git-Tag: 2.3.0.rc1~2359 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=574d36db88f15662529fb65da6fc8c5e4c8f12fa;p=thirdparty%2Fdovecot%2Fcore.git lib: istream-sized - set stream_errno=EPIPE if stream is too small --- diff --git a/src/lib/istream-sized.c b/src/lib/istream-sized.c index 6f54c5317b..e5b4cf136b 100644 --- a/src/lib/istream-sized.c +++ b/src/lib/istream-sized.c @@ -98,9 +98,10 @@ static ssize_t i_stream_sized_read(struct istream_private *stream) } else if (stream->istream.stream_errno == ENOENT) { /* lost the file */ } else { + /* EOF before we reached the wanted size */ error = sstream->error_callback(&data, sstream->error_context); io_stream_set_error(&stream->iostream, "%s", error); - stream->istream.stream_errno = EINVAL; + stream->istream.stream_errno = EPIPE; } ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) : diff --git a/src/lib/istream-sized.h b/src/lib/istream-sized.h index 61a78eb5d1..3c71877db8 100644 --- a/src/lib/istream-sized.h +++ b/src/lib/istream-sized.h @@ -16,8 +16,9 @@ typedef const char * istream_sized_callback_t(const struct istream_sized_error_data *data, void *context); -/* Assume that input is exactly the given size. If it's smaller, log an error - and fail with EINVAL error. If it's larger, log an error but don't fail. */ +/* Assume that input stream is exactly the given size. If the stream is too + small, fail with stream_errno=EPIPE. If stream is too large, fail with + stream_errno=EINVAL. */ struct istream *i_stream_create_sized(struct istream *input, uoff_t size); /* Same as i_stream_create_sized(), but set the error message via the callback. */ diff --git a/src/lib/test-istream-sized.c b/src/lib/test-istream-sized.c new file mode 100644 index 0000000000..cf8b30bde9 --- /dev/null +++ b/src/lib/test-istream-sized.c @@ -0,0 +1,66 @@ +/* Copyright (c) 2016 Dovecot authors, see the included COPYING file */ + +#include "test-lib.h" +#include "str.h" +#include "istream-private.h" +#include "istream-sized.h" + +static const struct { + const char *input; + uoff_t size; + int stream_errno; +} tests[] = { + { "", 0, 0 }, + { "", 1, EPIPE }, + { "a", 1, 0 }, + { "ab", 1, EINVAL }, + { "ab", 0, EINVAL }, + { "ab", (uoff_t)-1, EPIPE }, +}; + +static void +run_test(const char *sized_input, uoff_t sized_size, int stream_errno) +{ + unsigned int sized_input_len = strlen(sized_input); + struct istream *input_data, *input; + const unsigned char *data; + size_t i, size; + int ret = 0; + + input_data = test_istream_create_data(sized_input, sized_input_len); + test_istream_set_allow_eof(input_data, FALSE); + input = i_stream_create_sized(input_data, sized_size); + + for (i = 1; i < sized_input_len; i++) { + test_istream_set_size(input_data, i); + while ((ret = i_stream_read(input)) > 0) ; + if (ret == -1 && stream_errno != 0) + break; + test_assert(ret == 0); + } + if (ret == 0) { + test_istream_set_allow_eof(input_data, TRUE); + test_istream_set_size(input_data, i); + while ((ret = i_stream_read(input)) > 0) ; + } + test_assert(ret == -1); + test_assert(input->stream_errno == stream_errno); + + data = i_stream_get_data(input, &size); + test_assert(size == I_MIN(sized_input_len, sized_size)); + if (size > 0) + test_assert(memcmp(data, sized_input, size) == 0); + i_stream_unref(&input); + i_stream_unref(&input_data); +} + +void test_istream_sized(void) +{ + unsigned int i; + + for (i = 0; i < N_ELEMENTS(tests); i++) { + test_begin(t_strdup_printf("istream sized %u", i+1)); + run_test(tests[i].input, tests[i].size, tests[i].stream_errno); + test_end(); + } +}