bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen#include "lib.h"
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen#ifdef HAVE_LZMA
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen#include "ostream-private.h"
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen#include "ostream-zlib.h"
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen#include <lzma.h>
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen#define CHUNK_SIZE (1024*64)
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainenstruct lzma_ostream {
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen struct ostream_private ostream;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen lzma_stream strm;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen unsigned char outbuf[CHUNK_SIZE];
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen unsigned int outbuf_offset, outbuf_used;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool flushed:1;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen};
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainenstatic void o_stream_lzma_close(struct iostream_private *stream,
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen bool close_parent)
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen{
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen struct lzma_ostream *zstream = (struct lzma_ostream *)stream;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen lzma_end(&zstream->strm);
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen if (close_parent)
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen o_stream_close(zstream->ostream.parent);
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen}
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainenstatic int o_stream_zlib_send_outbuf(struct lzma_ostream *zstream)
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen{
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen ssize_t ret;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen size_t size;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen if (zstream->outbuf_used == 0)
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen return 1;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen size = zstream->outbuf_used - zstream->outbuf_offset;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen i_assert(size > 0);
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen ret = o_stream_send(zstream->ostream.parent,
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen zstream->outbuf + zstream->outbuf_offset, size);
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen if (ret < 0) {
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen o_stream_copy_error_from_parent(&zstream->ostream);
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen return -1;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen }
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen if ((size_t)ret != size) {
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen zstream->outbuf_offset += ret;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen return 0;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen }
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen zstream->outbuf_offset = 0;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen zstream->outbuf_used = 0;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen return 1;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen}
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainenstatic ssize_t
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Siraineno_stream_lzma_send_chunk(struct lzma_ostream *zstream,
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen const void *data, size_t size)
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen{
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen lzma_stream *zs = &zstream->strm;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen int ret;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen i_assert(zstream->outbuf_used == 0);
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen zs->next_in = (void *)data;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen zs->avail_in = size;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen while (zs->avail_in > 0) {
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen if (zs->avail_out == 0) {
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen /* previous block was compressed. send it and start
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen compression for a new block. */
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen zs->next_out = zstream->outbuf;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen zs->avail_out = sizeof(zstream->outbuf);
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen zstream->outbuf_used = sizeof(zstream->outbuf);
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen if ((ret = o_stream_zlib_send_outbuf(zstream)) < 0)
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen return -1;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen if (ret == 0) {
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen /* parent stream's buffer full */
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen break;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen }
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen }
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
38ec64f181318ba87481fe820abba6caa86d1ca6Timo Sirainen ret = lzma_code(zs, LZMA_RUN);
38ec64f181318ba87481fe820abba6caa86d1ca6Timo Sirainen switch (ret) {
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen case LZMA_OK:
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen break;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen case LZMA_MEM_ERROR:
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen i_fatal_status(FATAL_OUTOFMEM,
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen "lzma.write(%s): Out of memory",
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen o_stream_get_name(&zstream->ostream.ostream));
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen default:
38ec64f181318ba87481fe820abba6caa86d1ca6Timo Sirainen i_panic("lzma.write(%s) failed with unexpected code %d",
38ec64f181318ba87481fe820abba6caa86d1ca6Timo Sirainen o_stream_get_name(&zstream->ostream.ostream), ret);
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen }
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen }
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen size -= zs->avail_in;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen zstream->flushed = FALSE;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen return size;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen}
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainenstatic int o_stream_lzma_send_flush(struct lzma_ostream *zstream)
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen{
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen lzma_stream *zs = &zstream->strm;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t len;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen bool done = FALSE;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen int ret;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
08ab0b21d9da8881280071016a4475ee95f16c17Timo Sirainen i_assert(zs->avail_in == 0);
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen if (zstream->flushed)
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen return 0;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
b045cb4df9b00beb812f664c0f98344e743029acTimo Sirainen if ((ret = o_stream_flush_parent_if_needed(&zstream->ostream)) <= 0)
b045cb4df9b00beb812f664c0f98344e743029acTimo Sirainen return ret;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen if ((ret = o_stream_zlib_send_outbuf(zstream)) <= 0)
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen return ret;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen i_assert(zstream->outbuf_used == 0);
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen do {
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen ret = lzma_code(zs, LZMA_FINISH);
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen switch (ret) {
38ec64f181318ba87481fe820abba6caa86d1ca6Timo Sirainen case LZMA_OK:
38ec64f181318ba87481fe820abba6caa86d1ca6Timo Sirainen break;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen case LZMA_STREAM_END:
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen done = TRUE;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen break;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen case LZMA_MEM_ERROR:
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen i_fatal_status(FATAL_OUTOFMEM,
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen "lzma.write(%s): Out of memory",
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen o_stream_get_name(&zstream->ostream.ostream));
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen default:
38ec64f181318ba87481fe820abba6caa86d1ca6Timo Sirainen i_panic("lzma.write(%s) flush failed with unexpected code %d",
38ec64f181318ba87481fe820abba6caa86d1ca6Timo Sirainen o_stream_get_name(&zstream->ostream.ostream), ret);
38ec64f181318ba87481fe820abba6caa86d1ca6Timo Sirainen }
38ec64f181318ba87481fe820abba6caa86d1ca6Timo Sirainen if (zs->avail_out == 0 || done) {
38ec64f181318ba87481fe820abba6caa86d1ca6Timo Sirainen len = sizeof(zstream->outbuf) - zs->avail_out;
38ec64f181318ba87481fe820abba6caa86d1ca6Timo Sirainen zs->next_out = zstream->outbuf;
38ec64f181318ba87481fe820abba6caa86d1ca6Timo Sirainen zs->avail_out = sizeof(zstream->outbuf);
38ec64f181318ba87481fe820abba6caa86d1ca6Timo Sirainen
38ec64f181318ba87481fe820abba6caa86d1ca6Timo Sirainen zstream->outbuf_used = len;
38ec64f181318ba87481fe820abba6caa86d1ca6Timo Sirainen if ((ret = o_stream_zlib_send_outbuf(zstream)) <= 0)
38ec64f181318ba87481fe820abba6caa86d1ca6Timo Sirainen return ret;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen }
38ec64f181318ba87481fe820abba6caa86d1ca6Timo Sirainen } while (!done);
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen zstream->flushed = TRUE;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen return 0;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen}
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainenstatic int o_stream_lzma_flush(struct ostream_private *stream)
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen{
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen struct lzma_ostream *zstream = (struct lzma_ostream *)stream;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen if (o_stream_lzma_send_flush(zstream) < 0)
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen return -1;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
8109f3187f5ece5565de1813209af42dc7bb768bTimo Sirainen return o_stream_flush_parent(stream);
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen}
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainenstatic ssize_t
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Siraineno_stream_lzma_sendv(struct ostream_private *stream,
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen const struct const_iovec *iov, unsigned int iov_count)
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen{
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen struct lzma_ostream *zstream = (struct lzma_ostream *)stream;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen ssize_t ret, bytes = 0;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen unsigned int i;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen if ((ret = o_stream_zlib_send_outbuf(zstream)) <= 0) {
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen /* error / we still couldn't flush existing data to
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen parent stream. */
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen return ret;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen }
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen for (i = 0; i < iov_count; i++) {
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen ret = o_stream_lzma_send_chunk(zstream, iov[i].iov_base,
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen iov[i].iov_len);
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen if (ret < 0)
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen return -1;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen bytes += ret;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen if ((size_t)ret != iov[i].iov_len)
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen break;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen }
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen stream->ostream.offset += bytes;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen /* avail_in!=0 check is used to detect errors. if it's non-zero here
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen it simply means we didn't send all the data */
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen zstream->strm.avail_in = 0;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen return bytes;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen}
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainenstruct ostream *o_stream_create_lzma(struct ostream *output, int level)
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen{
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen struct lzma_ostream *zstream;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen lzma_ret ret;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen i_assert(level >= 1 && level <= 9);
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen zstream = i_new(struct lzma_ostream, 1);
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen zstream->ostream.sendv = o_stream_lzma_sendv;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen zstream->ostream.flush = o_stream_lzma_flush;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen zstream->ostream.iostream.close = o_stream_lzma_close;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen ret = lzma_easy_encoder(&zstream->strm, level, LZMA_CHECK_CRC64);
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen switch (ret) {
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen case LZMA_OK:
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen break;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen case LZMA_MEM_ERROR:
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen i_fatal_status(FATAL_OUTOFMEM, "lzma: Out of memory");
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen case LZMA_OPTIONS_ERROR:
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen i_fatal("lzma: Invalid level");
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen default:
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen i_fatal("lzma_easy_encoder() failed with %d", ret);
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen }
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen zstream->strm.next_out = zstream->outbuf;
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen zstream->strm.avail_out = sizeof(zstream->outbuf);
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen return o_stream_create(&zstream->ostream, output,
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen o_stream_get_fd(output));
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen}
12983e9d3b4ebdfb1e14f197c153304b3af44b59Timo Sirainen#endif