]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-mail: istream-header-filter: Fixed stat() with HEADER_FILTER_END_BODY_WITH_LF
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Tue, 3 May 2016 14:08:24 +0000 (17:08 +0300)
committerGitLab <gitlab@git.dovecot.net>
Tue, 3 May 2016 16:44:37 +0000 (19:44 +0300)
src/lib-mail/istream-header-filter.c
src/lib-mail/test-istream-header-filter.c

index 2e0f8cfd8ee79a5ff77a9f0963158244de483e33..0a6c9a2fe196fc446c3a751d2ed0006e1d037768 100644 (file)
@@ -546,6 +546,28 @@ i_stream_header_filter_stat(struct istream_private *stream, bool exact)
        if (skip_header(mstream) < 0)
                return -1;
 
+       if (!mstream->end_body_with_lf) {
+               /* no last-LF */
+       } else if (mstream->last_lf_added) {
+               /* yes, we have added LF */
+               stream->statbuf.st_size += mstream->crlf ? 2 : 1;
+       } else if (mstream->last_lf_offset != (uoff_t)-1) {
+               /* no, we didn't need to add LF */
+       } else {
+               /* check if we need to add LF */
+               i_stream_seek(stream->parent, st->st_size - 1);
+               (void)i_stream_read(stream->parent);
+               if (stream->parent->stream_errno != 0) {
+                       stream->istream.stream_errno =
+                               stream->parent->stream_errno;
+                       return -1;
+               }
+               i_assert(stream->parent->eof);
+               ssize_t ret = handle_end_body_with_lf(mstream, -1);
+               if (ret > 0)
+                       stream->statbuf.st_size += ret;
+       }
+
        stream->statbuf.st_size -=
                (off_t)mstream->header_size.physical_size -
                (off_t)mstream->header_size.virtual_size;
@@ -600,6 +622,7 @@ i_stream_create_header_filter(struct istream *input,
        mstream->add_missing_eoh = (flags & HEADER_FILTER_ADD_MISSING_EOH) != 0;
        mstream->end_body_with_lf =
                (flags & HEADER_FILTER_END_BODY_WITH_LF) != 0;
+       mstream->last_lf_offset = (uoff_t)-1;
 
        mstream->istream.iostream.destroy = i_stream_header_filter_destroy;
        mstream->istream.read = i_stream_header_filter_read;
index cfa544ccb59cfdecd73812020118a3dd443923d0..6c1357c52470701c9731ab48b939111e044551d8 100644 (file)
@@ -12,6 +12,7 @@ test_istream_run(struct istream *test_istream, struct istream *filter,
                 unsigned int input_len, const char *output)
 {
        unsigned int i, output_len = strlen(output);
+       const struct stat *st;
        const unsigned char *data;
        size_t size;
 
@@ -32,6 +33,8 @@ test_istream_run(struct istream *test_istream, struct istream *filter,
        while (i_stream_read(filter) > 0) ;
        data = i_stream_get_data(filter, &size);
        test_assert(size == output_len && memcmp(data, output, size) == 0);
+       test_assert(i_stream_stat(filter, TRUE, &st) == 0 &&
+                   (uoff_t)st->st_size == size);
 }
 
 static void ATTR_NULL(3)
@@ -55,6 +58,7 @@ static void test_istream_filter(void)
        unsigned int i, input_len = strlen(input);
        unsigned int output_len = strlen(output);
        const unsigned char *data;
+       const struct stat *st;
        size_t size;
 
        test_begin("i_stream_create_header_filter(exclude)");
@@ -86,11 +90,16 @@ static void test_istream_filter(void)
        data = i_stream_get_data(filter, &size);
        test_assert(size == output_len && memcmp(data, output, size) == 0);
 
+       test_assert(i_stream_stat(filter, TRUE, &st) == 0 &&
+                   (uoff_t)st->st_size == size);
+
        i_stream_skip(filter, size);
        i_stream_seek(filter, 0);
        while (i_stream_read(filter) > 0) ;
        data = i_stream_get_data(filter, &size);
        test_assert(size == output_len && memcmp(data, output, size) == 0);
+       test_assert(i_stream_stat(filter, TRUE, &st) == 0 &&
+                   (uoff_t)st->st_size == size);
 
        i_stream_unref(&filter);
        i_stream_unref(&istream);
@@ -119,6 +128,7 @@ static void test_istream_filter_large_buffer(void)
 {
        string_t *input, *output;
        struct istream *istream, *filter;
+       const struct stat *st;
        const unsigned char *data;
        size_t size, prefix_len;
        const char *p;
@@ -172,6 +182,9 @@ static void test_istream_filter_large_buffer(void)
                i_assert(p != NULL);
                test_assert(strcmp(p+1, str_c(output) + prefix_len) == 0);
 
+               test_assert(i_stream_stat(filter, TRUE, &st) == 0 &&
+                           (uoff_t)st->st_size == filter->v_offset + size);
+
                /* seek back and retry once with caching and different
                   buffer size */
                i_stream_seek(filter, 0);
@@ -199,6 +212,7 @@ filter3_callback(struct header_filter_istream *input ATTR_UNUSED,
 static void test_istream_callbacks(void)
 {
        string_t *input, *output;
+       const struct stat *st;
        struct istream *istream, *filter;
        unsigned int i;
 
@@ -230,6 +244,8 @@ static void test_istream_callbacks(void)
                        i_stream_skip(filter, i_stream_get_data_size(filter));
        }
 
+       test_assert(i_stream_stat(filter, TRUE, &st) == 0 &&
+                   (uoff_t)st->st_size == str_len(output));
        test_assert(strcmp(str_c(output), str_c(input)) == 0);
        str_free(&input);
        str_free(&output);
@@ -276,6 +292,7 @@ static void test_istream_end_body_with_lf(void)
 {
        const char *input = "From: foo\n\nhello world";
        const char *output = "From: foo\n\nhello world\n";
+       const struct stat *st;
        struct istream *istream, *filter;
        unsigned int i, input_len = strlen(input);
        unsigned int output_len = strlen(output);
@@ -304,6 +321,8 @@ static void test_istream_end_body_with_lf(void)
 
        data = i_stream_get_data(filter, &size);
        test_assert(size == output_len && memcmp(data, output, size) == 0);
+       test_assert(i_stream_stat(filter, TRUE, &st) == 0 &&
+                   (uoff_t)st->st_size == filter->v_offset + size);
 
        i_stream_skip(filter, size);
        i_stream_seek(filter, 0);