istream-lzma.c revision ad31916e2ad230d0e553203a5461bf7a8dc0d816
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2010-2016 Dovecot authors, see the included COPYING file */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void i_stream_lzma_close(struct iostream_private *stream,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct lzma_istream *zstream = (struct lzma_istream *)stream;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void lzma_read_error(struct lzma_istream *zstream, const char *error)
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen io_stream_set_error(&zstream->istream.iostream,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_stream_get_name(&zstream->istream.istream), error,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_stream_get_absolute_offset(&zstream->istream.istream));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("%s", zstream->istream.iostream.error);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void lzma_stream_end(struct lzma_istream *zstream)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen zstream->eof_offset = zstream->istream.istream.v_offset +
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen (zstream->istream.pos - zstream->istream.skip);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainenstatic ssize_t i_stream_lzma_read(struct istream_private *stream)
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen struct lzma_istream *zstream = (struct lzma_istream *)stream;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen const unsigned char *data;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen high_offset = stream->istream.v_offset + (stream->pos - stream->skip);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen /* we're here because we seeked back within the read buffer. */
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen if (stream->pos + CHUNK_SIZE > stream->buffer_size) {
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen /* try to keep at least CHUNK_SIZE available */
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen /* don't try to keep anything cached if we don't
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen have a seek mark. */
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen if (stream->buffer_size < i_stream_get_max_buffer_size(&stream->istream))
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* lose our buffer cache */
efc5c69c572e83db7bf7eab5d4698c0ab0d3d886Timo Sirainen if (i_stream_read_more(stream->parent, &data, &size) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* no more input */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen zstream->strm.next_out = stream->w_buffer + stream->pos;
601b455f4d5e780044b9e4fac5f687c1b07ae145Timo Sirainen i_stream_skip(stream->parent, size - zstream->strm.avail_in);
e1f866daa1bd1a5cd7516f3b19c6f197bcf6cc8aTimo Sirainen lzma_read_error(zstream, "wrong magic in header (not xz file?)");
6ec925f52d04ec8700e47cb005bd7ddc65ac5614Timo Sirainen lzma_read_error(zstream, "Unsupported xz options");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal_status(FATAL_OUTOFMEM, "lzma.read(%s): Out of memory",
72cc352b25ad401b923436c6ed0f1f3adaffa737Timo Sirainen /* read more input */
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainenstatic void i_stream_lzma_init(struct lzma_istream *zstream)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = lzma_stream_decoder(&zstream->strm, LZMA_MEMORY_LIMIT,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal_status(FATAL_OUTOFMEM, "lzma: Out of memory");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal("lzma_stream_decoder() failed with ret=%d", ret);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void i_stream_lzma_reset(struct lzma_istream *zstream)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct istream_private *stream = &zstream->istream;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_stream_seek(stream->parent, stream->parent_start_offset);
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen stream->parent_expected_offset = stream->parent_start_offset;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Siraineni_stream_lzma_seek(struct istream_private *stream, uoff_t v_offset, bool mark)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct lzma_istream *zstream = (struct lzma_istream *) stream;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uoff_t start_offset = stream->istream.v_offset - stream->skip;
43d7e7ce608f5451e4907b5f5c48c00beb265802Timo Sirainen /* have to seek backwards */
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen /* seeking backwards within what's already cached */
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen /* read and cache forward */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (stream->istream.v_offset + avail >= v_offset) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } while (i_stream_read(&stream->istream) >= 0);
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen /* some failure, we've broken it */
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen /* unexpected EOF. allow it since we may just
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen want to check if there's anything.. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Siraineni_stream_lzma_stat(struct istream_private *stream, bool exact)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct lzma_istream *zstream = (struct lzma_istream *) stream;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (i_stream_stat(stream->parent, exact, &st) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->istream.stream_errno = stream->parent->stream_errno;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* when exact=FALSE always return the parent stat's size, even if we
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen know the exact value. this is necessary because otherwise e.g. mbox
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen code can see two different values and think that a compressed mbox
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen file keeps changing. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen size = i_stream_get_data_size(&stream->istream);
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen } while (i_stream_read(&stream->istream) > 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen stream->statbuf.st_size = zstream->stream_size;
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainenstatic void i_stream_lzma_sync(struct istream_private *stream)
2cd2518bab14292a67cf8a490b58ab9ef89879daTimo Sirainen struct lzma_istream *zstream = (struct lzma_istream *) stream;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (i_stream_stat(stream->parent, FALSE, &st) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* a compressed file doesn't change unexpectedly,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen don't clear our caches unnecessarily */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstruct istream *i_stream_create_lzma(struct istream *input, bool log_errors)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen zstream->istream.iostream.close = i_stream_lzma_close;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen zstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen zstream->istream.istream.blocking = input->blocking;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen zstream->istream.istream.seekable = input->seekable;