changeset 10523:5d7ee047667f HEAD

istream-seekable: If we're immediately at EOF after copying buffer to file, don't corrupt the buffer.
author Timo Sirainen <tss@iki.fi>
date Tue, 22 Dec 2009 14:19:40 -0500
parents 19787c343ef1
children 824b7072c6d9
files src/lib/istream-seekable.c src/lib/test-istream-seekable.c
diffstat 2 files changed, 55 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib/istream-seekable.c	Tue Dec 22 14:19:15 2009 -0500
+++ b/src/lib/istream-seekable.c	Tue Dec 22 14:19:40 2009 -0500
@@ -72,7 +72,10 @@
 
 static int copy_to_temp_file(struct seekable_istream *sstream)
 {
+	struct istream_private *stream = &sstream->istream;
 	const char *path;
+	const unsigned char *buffer;
+	size_t size;
 	int fd;
 
 	fd = sstream->fd_callback(&path, sstream->context);
@@ -89,11 +92,27 @@
 	sstream->temp_path = i_strdup(path);
 	sstream->write_peak = sstream->buffer->used;
 
-	buffer_free(&sstream->buffer);
-
 	sstream->fd = fd;
 	sstream->fd_input =
 		i_stream_create_fd(fd, sstream->istream.max_buffer_size, TRUE);
+
+	/* read back the data we just had in our buffer */
+	i_stream_seek(sstream->fd_input, stream->istream.v_offset);
+	for (;;) {
+		buffer = i_stream_get_data(sstream->fd_input, &size);
+		if (size >= stream->pos)
+			break;
+
+		if (i_stream_read(sstream->fd_input) <= 0) {
+			i_error("istream-seekable: Couldn't read back "
+				"in-memory input");
+			i_stream_destroy(&sstream->fd_input);
+			return -1;
+		}
+	}
+	stream->buffer = buffer;
+	stream->pos = size;
+	buffer_free(&sstream->buffer);
 	return 0;
 }
 
@@ -341,6 +360,7 @@
 	sstream->context = context;
 	sstream->buffer = buffer_create_dynamic(default_pool, BUF_INITIAL_SIZE);
         sstream->istream.max_buffer_size = max_buffer_size;
+	sstream->fd = -1;
 
 	sstream->input = i_new(struct istream *, count + 1);
 	memcpy(sstream->input, input, sizeof(*input) * count);
--- a/src/lib/test-istream-seekable.c	Tue Dec 22 14:19:15 2009 -0500
+++ b/src/lib/test-istream-seekable.c	Tue Dec 22 14:19:40 2009 -0500
@@ -121,6 +121,37 @@
 	i_stream_unref(&input);
 }
 
+static void test_istream_seekable_eof(void)
+{
+	static const char *in_str = "foo";
+	unsigned int in_str_len = strlen(in_str);
+	struct istream *streams[2], *input;
+	const unsigned char *data;
+	size_t size;
+
+	test_begin("istream seekable eof");
+
+	streams[0] = i_stream_create_from_data(in_str, in_str_len);
+	streams[0]->seekable = FALSE;
+	streams[1] = NULL;
+
+	input = i_stream_create_seekable(streams, in_str_len, fd_callback, NULL);
+	i_stream_unref(&streams[0]);
+
+	test_assert(i_stream_read(input) == (ssize_t)in_str_len);
+	data = i_stream_get_data(input, &size);
+	test_assert(size == in_str_len);
+	test_assert(memcmp(data, in_str, in_str_len) == 0);
+
+	test_assert(i_stream_read(input) == -1);
+	data = i_stream_get_data(input, &size);
+	test_assert(size == in_str_len);
+	test_assert(memcmp(data, in_str, in_str_len) == 0);
+
+	i_stream_unref(&input);
+	test_end();
+}
+
 void test_istream_seekable(void)
 {
 	unsigned int i;
@@ -135,4 +166,6 @@
 		test_istream_seekable_random();
 	} T_END;
 	test_end();
+
+	test_istream_seekable_eof();
 }