]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-compression: Use i_stream_nonseekable_try_seek() instead of reimplementing it
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Tue, 5 Jun 2018 10:57:26 +0000 (13:57 +0300)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Wed, 6 Jun 2018 13:25:09 +0000 (16:25 +0300)
src/lib-compression/istream-bzlib.c
src/lib-compression/istream-lz4.c
src/lib-compression/istream-lzma.c
src/lib-compression/istream-zlib.c
src/lib-compression/test-compression.c

index 092fcb5c5bbe5255734d42c9ee40f7401de5196a..88e8652a104328abada91fdc9181385d1eeeecba 100644 (file)
@@ -15,7 +15,6 @@ struct bzlib_istream {
 
        bz_stream zs;
        uoff_t eof_offset;
-       size_t high_pos;
        struct stat last_parent_statbuf;
 
        bool log_errors:1;
@@ -56,28 +55,10 @@ static ssize_t i_stream_bzlib_read(struct istream_private *stream)
 
        high_offset = stream->istream.v_offset + (stream->pos - stream->skip);
        if (zstream->eof_offset == high_offset) {
-               i_assert(zstream->high_pos == 0 ||
-                        zstream->high_pos == stream->pos);
                stream->istream.eof = TRUE;
                return -1;
        }
 
-       if (stream->pos < zstream->high_pos) {
-               /* we're here because we seeked back within the read buffer. */
-               ret = zstream->high_pos - stream->pos;
-               stream->pos = zstream->high_pos;
-               zstream->high_pos = 0;
-
-               if (zstream->eof_offset != (uoff_t)-1) {
-                       high_offset = stream->istream.v_offset +
-                               (stream->pos - stream->skip);
-                       i_assert(zstream->eof_offset == high_offset);
-                       stream->istream.eof = TRUE;
-               }
-               return ret;
-       }
-       zstream->high_pos = 0;
-
        if (!zstream->marked) {
                if (!i_stream_try_alloc(stream, CHUNK_SIZE, &out_size))
                        return -2; /* buffer full */
@@ -183,7 +164,7 @@ static void i_stream_bzlib_reset(struct bzlib_istream *zstream)
        stream->parent_expected_offset = stream->parent_start_offset;
        stream->skip = stream->pos = 0;
        stream->istream.v_offset = 0;
-       zstream->high_pos = 0;
+       stream->high_pos = 0;
 
        (void)BZ2_bzDecompressEnd(&zstream->zs);
        i_stream_bzlib_init(zstream);
@@ -193,56 +174,14 @@ static void
 i_stream_bzlib_seek(struct istream_private *stream, uoff_t v_offset, bool mark)
 {
        struct bzlib_istream *zstream = (struct bzlib_istream *) stream;
-       uoff_t start_offset = stream->istream.v_offset - stream->skip;
-
-       if (v_offset < start_offset) {
-               /* have to seek backwards */
-               i_stream_bzlib_reset(zstream);
-               start_offset = 0;
-       } else if (zstream->high_pos != 0) {
-               stream->pos = zstream->high_pos;
-               zstream->high_pos = 0;
-       }
 
-       if (v_offset <= start_offset + stream->pos) {
-               /* seeking backwards within what's already cached */
-               stream->skip = v_offset - start_offset;
-               stream->istream.v_offset = v_offset;
-               zstream->high_pos = stream->pos;
-               stream->pos = stream->skip;
-       } else {
-               /* read and cache forward */
-               ssize_t ret;
-
-               do {
-                       size_t avail = stream->pos - stream->skip;
-
-                       if (stream->istream.v_offset + avail >= v_offset) {
-                               i_stream_skip(&stream->istream,
-                                             v_offset -
-                                             stream->istream.v_offset);
-                               ret = -1;
-                               break;
-                       }
-
-                       i_stream_skip(&stream->istream, avail);
-               } while ((ret = i_stream_read(&stream->istream)) > 0);
-               i_assert(ret == -1);
-
-               if (stream->istream.v_offset != v_offset) {
-                       /* some failure, we've broken it */
-                       if (stream->istream.stream_errno != 0) {
-                               i_error("bzlib_istream.seek(%s) failed: %s",
-                                       i_stream_get_name(&stream->istream),
-                                       strerror(stream->istream.stream_errno));
-                               i_stream_close(&stream->istream);
-                       } else {
-                               /* unexpected EOF. allow it since we may just
-                                  want to check if there's anything.. */
-                               i_assert(stream->istream.eof);
-                       }
-               }
-       }
+       if (i_stream_nonseekable_try_seek(stream, v_offset))
+               return;
+
+       /* have to seek backwards - reset state and retry */
+       i_stream_bzlib_reset(zstream);
+       if (!i_stream_nonseekable_try_seek(stream, v_offset))
+               i_unreached();
 
        if (mark)
                zstream->marked = TRUE;
index 2a7551b47523e4723599fc72d607a5ecb7f4a636..6bde36ee7ea38d755622bf4bbaef0839a6a87d79 100644 (file)
@@ -180,52 +180,14 @@ static void
 i_stream_lz4_seek(struct istream_private *stream, uoff_t v_offset, bool mark)
 {
        struct lz4_istream *zstream = (struct lz4_istream *) stream;
-       uoff_t start_offset = stream->istream.v_offset - stream->skip;
 
-       if (v_offset < start_offset) {
-               /* have to seek backwards */
-               i_stream_lz4_reset(zstream);
-               start_offset = 0;
-       }
-
-       if (v_offset <= start_offset + stream->pos) {
-               /* seeking backwards within what's already cached */
-               stream->skip = v_offset - start_offset;
-               stream->istream.v_offset = v_offset;
-               stream->pos = stream->skip;
-       } else {
-               /* read and cache forward */
-               ssize_t ret;
-
-               do {
-                       size_t avail = stream->pos - stream->skip;
-
-                       if (stream->istream.v_offset + avail >= v_offset) {
-                               i_stream_skip(&stream->istream,
-                                             v_offset -
-                                             stream->istream.v_offset);
-                               ret = -1;
-                               break;
-                       }
+       if (i_stream_nonseekable_try_seek(stream, v_offset))
+               return;
 
-                       i_stream_skip(&stream->istream, avail);
-               } while ((ret = i_stream_read(&stream->istream)) > 0);
-               i_assert(ret == -1);
-
-               if (stream->istream.v_offset != v_offset) {
-                       /* some failure, we've broken it */
-                       if (stream->istream.stream_errno != 0) {
-                               i_error("lz4_istream.seek(%s) failed: %s",
-                                       i_stream_get_name(&stream->istream),
-                                       strerror(stream->istream.stream_errno));
-                               i_stream_close(&stream->istream);
-                       } else {
-                               /* unexpected EOF. allow it since we may just
-                                  want to check if there's anything.. */
-                               i_assert(stream->istream.eof);
-                       }
-               }
-       }
+       /* have to seek backwards - reset state and retry */
+       i_stream_lz4_reset(zstream);
+       if (!i_stream_nonseekable_try_seek(stream, v_offset))
+               i_unreached();
 
        if (mark)
                zstream->marked = TRUE;
index a47f7b0c7dfb4d15ab49668284fa2429e4b2f503..34068902069cfde35015de6c09cf0dbb2f59dc7c 100644 (file)
@@ -17,7 +17,6 @@ struct lzma_istream {
 
        lzma_stream strm;
        uoff_t eof_offset;
-       size_t high_pos;
        struct stat last_parent_statbuf;
 
        bool log_errors:1;
@@ -65,28 +64,10 @@ static ssize_t i_stream_lzma_read(struct istream_private *stream)
 
        high_offset = stream->istream.v_offset + (stream->pos - stream->skip);
        if (zstream->eof_offset == high_offset) {
-               i_assert(zstream->high_pos == 0 ||
-                        zstream->high_pos == stream->pos);
                stream->istream.eof = TRUE;
                return -1;
        }
 
-       if (stream->pos < zstream->high_pos) {
-               /* we're here because we seeked back within the read buffer. */
-               ret = zstream->high_pos - stream->pos;
-               stream->pos = zstream->high_pos;
-               zstream->high_pos = 0;
-
-               if (zstream->eof_offset != (uoff_t)-1) {
-                       high_offset = stream->istream.v_offset +
-                               (stream->pos - stream->skip);
-                       i_assert(zstream->eof_offset == high_offset);
-                       stream->istream.eof = TRUE;
-               }
-               return ret;
-       }
-       zstream->high_pos = 0;
-
        if (!zstream->marked) {
                if (!i_stream_try_alloc(stream, CHUNK_SIZE, &out_size))
                        return -2; /* buffer full */
@@ -192,7 +173,6 @@ static void i_stream_lzma_reset(struct lzma_istream *zstream)
        stream->parent_expected_offset = stream->parent_start_offset;
        stream->skip = stream->pos = 0;
        stream->istream.v_offset = 0;
-       zstream->high_pos = 0;
 
        lzma_end(&zstream->strm);
        i_stream_lzma_init(zstream);
@@ -202,56 +182,14 @@ static void
 i_stream_lzma_seek(struct istream_private *stream, uoff_t v_offset, bool mark)
 {
        struct lzma_istream *zstream = (struct lzma_istream *) stream;
-       uoff_t start_offset = stream->istream.v_offset - stream->skip;
-
-       if (v_offset < start_offset) {
-               /* have to seek backwards */
-               i_stream_lzma_reset(zstream);
-               start_offset = 0;
-       } else if (zstream->high_pos != 0) {
-               stream->pos = zstream->high_pos;
-               zstream->high_pos = 0;
-       }
 
-       if (v_offset <= start_offset + stream->pos) {
-               /* seeking backwards within what's already cached */
-               stream->skip = v_offset - start_offset;
-               stream->istream.v_offset = v_offset;
-               zstream->high_pos = stream->pos;
-               stream->pos = stream->skip;
-       } else {
-               /* read and cache forward */
-               ssize_t ret;
-
-               do {
-                       size_t avail = stream->pos - stream->skip;
-
-                       if (stream->istream.v_offset + avail >= v_offset) {
-                               i_stream_skip(&stream->istream,
-                                             v_offset -
-                                             stream->istream.v_offset);
-                               ret = -1;
-                               break;
-                       }
-
-                       i_stream_skip(&stream->istream, avail);
-               } while ((ret = i_stream_read(&stream->istream)) > 0);
-               i_assert(ret == -1);
-
-               if (stream->istream.v_offset != v_offset) {
-                       /* some failure, we've broken it */
-                       if (stream->istream.stream_errno != 0) {
-                               i_error("lzma_istream.seek(%s) failed: %s",
-                                       i_stream_get_name(&stream->istream),
-                                       strerror(stream->istream.stream_errno));
-                               i_stream_close(&stream->istream);
-                       } else {
-                               /* unexpected EOF. allow it since we may just
-                                  want to check if there's anything.. */
-                               i_assert(stream->istream.eof);
-                       }
-               }
-       }
+       if (i_stream_nonseekable_try_seek(stream, v_offset))
+               return;
+
+       /* have to seek backwards - reset state and retry */
+       i_stream_lzma_reset(zstream);
+       if (!i_stream_nonseekable_try_seek(stream, v_offset))
+               i_unreached();
 
        if (mark)
                zstream->marked = TRUE;
index 8adf57e22ad7fe1b412b88dc62167c00030c80f4..7de770c307559cda2118441a50f5282f999c1b63 100644 (file)
@@ -26,7 +26,7 @@ struct zlib_istream {
 
        z_stream zs;
        uoff_t eof_offset;
-       size_t prev_size, high_pos;
+       size_t prev_size;
        uint32_t crc32;
        struct stat last_parent_statbuf;
 
@@ -174,8 +174,6 @@ static ssize_t i_stream_zlib_read(struct istream_private *stream)
 
        high_offset = stream->istream.v_offset + (stream->pos - stream->skip);
        if (zstream->eof_offset == high_offset) {
-               i_assert(zstream->high_pos == 0 ||
-                        zstream->high_pos == stream->pos);
                if (!zstream->trailer_read) {
                        do {
                                ret = i_stream_zlib_read_trailer(zstream);
@@ -226,21 +224,6 @@ static ssize_t i_stream_zlib_read(struct istream_private *stream)
                zstream->header_read = TRUE;
        }
 
-       if (stream->pos < zstream->high_pos) {
-               /* we're here because we seeked back within the read buffer. */
-               ret = zstream->high_pos - stream->pos;
-               stream->pos = zstream->high_pos;
-               zstream->high_pos = 0;
-               if (zstream->trailer_read) {
-                       high_offset = stream->istream.v_offset +
-                               (stream->pos - stream->skip);
-                       i_assert(zstream->eof_offset == high_offset);
-                       stream->istream.eof = TRUE;
-               }
-               return ret;
-       }
-       zstream->high_pos = 0;
-
        if (!zstream->marked) {
                if (!i_stream_try_alloc(stream, CHUNK_SIZE, &out_size))
                        return -2; /* buffer full */
@@ -354,7 +337,7 @@ static void i_stream_zlib_reset(struct zlib_istream *zstream)
        stream->parent_expected_offset = stream->parent_start_offset;
        stream->skip = stream->pos = 0;
        stream->istream.v_offset = 0;
-       zstream->high_pos = 0;
+       stream->high_pos = 0;
        zstream->prev_size = 0;
 
        (void)inflateEnd(&zstream->zs);
@@ -365,56 +348,14 @@ static void
 i_stream_zlib_seek(struct istream_private *stream, uoff_t v_offset, bool mark)
 {
        struct zlib_istream *zstream = (struct zlib_istream *) stream;
-       uoff_t start_offset = stream->istream.v_offset - stream->skip;
-
-       if (v_offset < start_offset) {
-               /* have to seek backwards */
-               i_stream_zlib_reset(zstream);
-               start_offset = 0;
-       } else if (zstream->high_pos != 0) {
-               stream->pos = zstream->high_pos;
-               zstream->high_pos = 0;
-       }
-
-       if (v_offset <= start_offset + stream->pos) {
-               /* seeking backwards within what's already cached */
-               stream->skip = v_offset - start_offset;
-               stream->istream.v_offset = v_offset;
-               zstream->high_pos = stream->pos;
-               stream->pos = stream->skip;
-       } else {
-               /* read and cache forward */
-               ssize_t ret;
 
-               do {
-                       size_t avail = stream->pos - stream->skip;
-
-                       if (stream->istream.v_offset + avail >= v_offset) {
-                               i_stream_skip(&stream->istream,
-                                             v_offset -
-                                             stream->istream.v_offset);
-                               ret = -1;
-                               break;
-                       }
+       if (i_stream_nonseekable_try_seek(stream, v_offset))
+               return;
 
-                       i_stream_skip(&stream->istream, avail);
-               } while ((ret = i_stream_read(&stream->istream)) > 0);
-               i_assert(ret == -1);
-
-               if (stream->istream.v_offset != v_offset) {
-                       /* some failure, we've broken it */
-                       if (stream->istream.stream_errno != 0) {
-                               i_error("zlib_istream.seek(%s) failed: %s",
-                                       i_stream_get_name(&stream->istream),
-                                       strerror(stream->istream.stream_errno));
-                               i_stream_close(&stream->istream);
-                       } else {
-                               /* unexpected EOF. allow it since we may just
-                                  want to check if there's anything.. */
-                               i_assert(stream->istream.eof);
-                       }
-               }
-       }
+       /* have to seek backwards - reset state and retry */
+       i_stream_zlib_reset(zstream);
+       if (!i_stream_nonseekable_try_seek(stream, v_offset))
+               i_unreached();
 
        if (mark)
                zstream->marked = TRUE;
index 718d05b81754c09736bbb4af8adcb6a544c52b11..0f7df3d1fef7bbb16e17c2ae108fe5ec9d1afbbd 100644 (file)
@@ -70,7 +70,6 @@ static void test_compression_handler(const struct compression_handler *handler)
        sha1_result(&sha1, output_sha1);
 
        /* read and uncompress the data */
-       sha1_init(&sha1);
        file_input = i_stream_create_fd(fd, IO_BLOCK_SIZE);
        input = handler->create_istream(file_input, FALSE);
 
@@ -80,17 +79,25 @@ static void test_compression_handler(const struct compression_handler *handler)
        test_assert(i_stream_get_size(input, TRUE, &size) == 1);
        test_assert(size == uncompressed_size);
 
-       while ((ret = i_stream_read_more(input, &data, &size)) > 0) {
-               sha1_loop(&sha1, data, size);
-               i_stream_skip(input, size);
+       sha1_init(&sha1);
+       for (bool seeked = FALSE;;) {
+               sha1_init(&sha1);
+               while ((ret = i_stream_read_more(input, &data, &size)) > 0) {
+                       sha1_loop(&sha1, data, size);
+                       i_stream_skip(input, size);
+               }
+               test_assert(ret == -1);
+               test_assert(input->stream_errno == 0);
+               sha1_result(&sha1, input_sha1);
+               test_assert(memcmp(input_sha1, output_sha1, sizeof(input_sha1)) == 0);
+               if (seeked)
+                       break;
+               seeked = TRUE;
+               i_stream_seek(input, 0);
        }
-       test_assert(ret == -1);
-       test_assert(input->stream_errno == 0);
        i_stream_destroy(&input);
        i_stream_destroy(&file_input);
-       sha1_result(&sha1, input_sha1);
 
-       test_assert(memcmp(input_sha1, output_sha1, sizeof(input_sha1)) == 0);
        i_unlink(path);
        i_close_fd(&fd);