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