diff --git a/src/lib/iostream-temp.c b/src/lib/iostream-temp.c index 9660361133..f3776c6af8 100644 --- a/src/lib/iostream-temp.c +++ b/src/lib/iostream-temp.c @@ -131,8 +131,11 @@ static int o_stream_temp_dup_cancel(struct temp_ostream *tstream) int ret = -1; i_stream_seek(tstream->dupstream, tstream->dupstream_start_offset); + tstream->ostream.ostream.offset = 0; input = i_stream_create_limit(tstream->dupstream, size); + i_stream_unref(&tstream->dupstream); + if (io_stream_copy(&tstream->ostream.ostream, input) > 0) { /* everything copied */ ret = 0; @@ -141,7 +144,6 @@ static int o_stream_temp_dup_cancel(struct temp_ostream *tstream) tstream->ostream.ostream.stream_errno = input->stream_errno; } i_stream_destroy(&input); - i_stream_unref(&tstream->dupstream); return ret; } @@ -170,7 +172,12 @@ static int o_stream_temp_dup_istream(struct temp_ostream *outstream, return o_stream_temp_dup_cancel(outstream); } i_stream_seek(instream, in_size); + /* we should be at EOF now. o_stream_send_istream() asserts if + eof isn't set. */ + instream->eof = TRUE; outstream->dupstream_offset = instream->v_offset; + outstream->ostream.ostream.offset = + outstream->dupstream_offset - outstream->dupstream_start_offset; return 1; } diff --git a/src/lib/test-iostream-temp.c b/src/lib/test-iostream-temp.c index 7cfae398c3..d2978a6e24 100644 --- a/src/lib/test-iostream-temp.c +++ b/src/lib/test-iostream-temp.c @@ -1,9 +1,13 @@ /* Copyright (c) 2016 Dovecot authors, see the included COPYING file */ #include "test-lib.h" +#include "istream.h" #include "ostream.h" #include "iostream-temp.h" +#include +#include + static void test_iostream_temp_create_sized_memory(void) { struct ostream *output; @@ -39,8 +43,60 @@ static void test_iostream_temp_create_sized_disk(void) test_end(); } +static void test_iostream_temp_istream(void) +{ + struct istream *input, *input2, *temp_input; + struct ostream *output; + int fd; + + test_begin("iostream_temp istream"); + + fd = open(".temp.istream", O_RDWR | O_CREAT | O_TRUNC, 0600); + if (fd == -1) + i_fatal("create(.temp.istream) failed: %m"); + test_assert(write(fd, "foobar", 6) == 6); + test_assert(lseek(fd, 0, SEEK_SET) == 0); + + input = i_stream_create_fd(fd, 1024, TRUE); + /* a working fd-dup */ + output = iostream_temp_create_sized(".nonexistent/", + IOSTREAM_TEMP_FLAG_TRY_FD_DUP, "test", 1); + test_assert(o_stream_send_istream(output, input) > 0); + temp_input = iostream_temp_finish(&output, 128); + test_assert(i_stream_read(temp_input) == 6); + i_stream_destroy(&temp_input); + + /* non-working fd-dup: write data before sending istream */ + i_stream_seek(input, 0); + output = iostream_temp_create_sized(".intentional-nonexistent-error/", + IOSTREAM_TEMP_FLAG_TRY_FD_DUP, "test", 4); + test_assert(o_stream_send(output, "1234", 4) == 4); + test_expect_errors(1); + test_assert(o_stream_send_istream(output, input) > 0); + test_expect_no_more_errors(); + o_stream_destroy(&output); + + /* non-working fd-dup: send two istreams */ + i_stream_seek(input, 0); + input2 = i_stream_create_limit(input, (uoff_t)-1); + output = iostream_temp_create_sized(".intentional-nonexistent-error/", + IOSTREAM_TEMP_FLAG_TRY_FD_DUP, "test", 4); + test_assert(o_stream_send_istream(output, input) > 0); + test_expect_errors(1); + test_assert(o_stream_send_istream(output, input2) > 0); + test_expect_no_more_errors(); + o_stream_destroy(&output); + i_stream_unref(&input2); + + i_stream_destroy(&input); + + i_unlink(".temp.istream"); + test_end(); +} + void test_iostream_temp(void) { test_iostream_temp_create_sized_memory(); test_iostream_temp_create_sized_disk(); + test_iostream_temp_istream(); }