istream-lzma.c revision 9dadffcd2545eab4b251e83b60cee78ceb1e8362
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher/* Copyright (c) 2010-2017 Dovecot authors, see the included COPYING file */
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozekstatic void i_stream_lzma_close(struct iostream_private *stream,
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek struct lzma_istream *zstream = (struct lzma_istream *)stream;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagherstatic void lzma_read_error(struct lzma_istream *zstream, const char *error)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher io_stream_set_error(&zstream->istream.iostream,
2ea6196484055397cc4bc011c5960f790431fa9dStephen Gallagher i_stream_get_name(&zstream->istream.istream), error,
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek i_stream_get_absolute_offset(&zstream->istream.istream));
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan i_error("%s", zstream->istream.iostream.error);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstatic void lzma_stream_end(struct lzma_istream *zstream)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan zstream->eof_offset = zstream->istream.istream.v_offset +
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan (zstream->istream.pos - zstream->istream.skip);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher zstream->stream_size = zstream->eof_offset;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagherstatic ssize_t i_stream_lzma_read(struct istream_private *stream)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher struct lzma_istream *zstream = (struct lzma_istream *)stream;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan const unsigned char *data;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher high_offset = stream->istream.v_offset + (stream->pos - stream->skip);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan /* we're here because we seeked back within the read buffer. */
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan i_assert(zstream->eof_offset == high_offset);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if (stream->pos + CHUNK_SIZE > stream->buffer_size) {
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozek /* try to keep at least CHUNK_SIZE available */
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan /* don't try to keep anything cached if we don't
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan have a seek mark. */
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (stream->buffer_size < i_stream_get_max_buffer_size(&stream->istream))
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher /* lose our buffer cache */
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (i_stream_read_more(stream->parent, &data, &size) < 0) {
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher /* no more input */
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher out_size = stream->buffer_size - stream->pos;
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher zstream->strm.next_out = stream->w_buffer + stream->pos;
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher ret = lzma_code(&zstream->strm, LZMA_RUN);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher i_stream_skip(stream->parent, size - zstream->strm.avail_in);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher lzma_read_error(zstream, "corrupted data");
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan lzma_read_error(zstream, "wrong magic in header (not xz file?)");
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan lzma_read_error(zstream, "Unsupported xz options");
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan i_fatal_status(FATAL_OUTOFMEM, "lzma.read(%s): Out of memory",
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan /* read more input */
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstatic void i_stream_lzma_init(struct lzma_istream *zstream)
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan ret = lzma_stream_decoder(&zstream->strm, LZMA_MEMORY_LIMIT,
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher i_fatal_status(FATAL_OUTOFMEM, "lzma: Out of memory");
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan i_fatal("lzma_stream_decoder() failed with ret=%d", ret);
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivanstatic void i_stream_lzma_reset(struct lzma_istream *zstream)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan struct istream_private *stream = &zstream->istream;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan i_stream_seek(stream->parent, stream->parent_start_offset);
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher stream->parent_expected_offset = stream->parent_start_offset;
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagheri_stream_lzma_seek(struct istream_private *stream, uoff_t v_offset, bool mark)
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher struct lzma_istream *zstream = (struct lzma_istream *) stream;
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher uoff_t start_offset = stream->istream.v_offset - stream->skip;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan /* have to seek backwards */
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan if (v_offset <= start_offset + stream->pos) {
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan /* seeking backwards within what's already cached */
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan /* read and cache forward */
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher if (stream->istream.v_offset + avail >= v_offset) {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan } while ((ret = i_stream_read(&stream->istream)) > 0);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan /* some failure, we've broken it */
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher i_error("lzma_istream.seek(%s) failed: %s",
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher /* unexpected EOF. allow it since we may just
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan want to check if there's anything.. */
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagheri_stream_lzma_stat(struct istream_private *stream, bool exact)
056302a92862fda16351d7192600746746f38e5dStephen Gallagher struct lzma_istream *zstream = (struct lzma_istream *) stream;
7797e361155f7ce937085fd98e360469d7baf1b6Jakub Hrozek if (i_stream_stat(stream->parent, exact, &st) < 0) {
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan stream->istream.stream_errno = stream->parent->stream_errno;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan /* when exact=FALSE always return the parent stat's size, even if we
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher know the exact value. this is necessary because otherwise e.g. mbox
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek code can see two different values and think that a compressed mbox
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan file keeps changing. */
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher uoff_t old_offset = stream->istream.v_offset;
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek size = i_stream_get_data_size(&stream->istream);
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan } while ((ret = i_stream_read(&stream->istream)) > 0);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher i_stream_seek(&stream->istream, old_offset);
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagher stream->statbuf.st_size = zstream->stream_size;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivanstatic void i_stream_lzma_sync(struct istream_private *stream)
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek struct lzma_istream *zstream = (struct lzma_istream *) stream;
f9fdc87c80f2744780c6a0f2bf5b1b57bcbb095aYuri Chornoivan if (i_stream_stat(stream->parent, FALSE, &st) < 0) {
c938f4ba417328fe62eded0806b2d9ca053f34a5Stephen Gallagher /* a compressed file doesn't change unexpectedly,
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek don't clear our caches unnecessarily */
cbe7c54c2caf718bdea7ca6660ba8193d759d2d5Stephen Gallagherstruct istream *i_stream_create_lzma(struct istream *input, bool log_errors)
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan zstream->istream.iostream.close = i_stream_lzma_close;
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek zstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
e5c33e0bd03a2deb8e5011deeb3ae93f960910eeJakub Hrozek zstream->istream.istream.blocking = input->blocking;
bde69429374859acff41273c0771d2b5f5c199b1Yuri Chornoivan zstream->istream.istream.seekable = input->seekable;