static ssize_t o_stream_zlib_send_chunk(struct zlib_ostream *zstream, const void *data, size_t size) { z_stream *zs = &zstream->zs; int ret, flush; i_assert(zstream->outbuf_used == 0); flush = zstream->ostream.corked || zstream->gz ? Z_NO_FLUSH : Z_SYNC_FLUSH; if (!zstream->header_sent) { if (o_stream_zlib_send_gz_header(zstream) < 0) return -1; } zs->next_in = (void *)data; zs->avail_in = size; while (zs->avail_in > 0) { if (zs->avail_out == 0) { /* previous block was compressed. send it and start compression for a new block. */ zs->next_out = zstream->outbuf; zs->avail_out = sizeof(zstream->outbuf); zstream->outbuf_used = sizeof(zstream->outbuf); if ((ret = o_stream_zlib_send_outbuf(zstream)) < 0) return -1; if (ret == 0) { /* parent stream's buffer full */ break; } } ret = deflate(zs, flush); switch (ret) { case Z_OK: case Z_BUF_ERROR: break; case Z_STREAM_ERROR: i_assert(zstream->gz); i_panic("zlib.write(%s) failed: Can't write more data to .gz after flushing", o_stream_get_name(&zstream->ostream.ostream)); default: i_panic("zlib.write(%s) failed with unexpected code %d", o_stream_get_name(&zstream->ostream.ostream), ret); } } size -= zs->avail_in; zstream->crc = crc32_data_more(zstream->crc, data, size); zstream->bytes32 += size; zstream->flushed = flush == Z_SYNC_FLUSH && zs->avail_in == 0 && zs->avail_out == sizeof(zstream->outbuf); return size; }
static int o_stream_zlib_send_chunk(struct zlib_ostream *zstream, const void *data, size_t size) { z_stream *zs = &zstream->zs; ssize_t ret; int flush; flush = zstream->ostream.corked || zstream->gz ? Z_NO_FLUSH : Z_SYNC_FLUSH; if (!zstream->header_sent) o_stream_zlib_send_gz_header(zstream); zs->next_in = (void *)data; zs->avail_in = size; while (zs->avail_in > 0) { if (zs->avail_out == 0) { zs->next_out = zstream->outbuf; zs->avail_out = sizeof(zstream->outbuf); ret = o_stream_send(zstream->output, zstream->outbuf, sizeof(zstream->outbuf)); if (ret != (ssize_t)sizeof(zstream->outbuf)) { zstream_copy_error(zstream); return -1; } } switch (deflate(zs, flush)) { case Z_OK: case Z_BUF_ERROR: break; default: i_unreached(); } } zstream->crc = crc32_data_more(zstream->crc, data, size); zstream->bytes32 += size; zstream->flushed = FALSE; return 0; }
static ssize_t i_stream_zlib_read(struct istream_private *stream) { struct zlib_istream *zstream = (struct zlib_istream *)stream; const unsigned char *data; uoff_t high_offset; size_t size, out_size; int ret; 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); } while (ret == 0 && stream->istream.blocking); if (ret <= 0) return ret; } if (!zstream->gz || i_stream_is_eof(stream->parent)) { stream->istream.eof = TRUE; return -1; } /* gzip file with concatenated content */ zstream->eof_offset = (uoff_t)-1; zstream->stream_size = (uoff_t)-1; zstream->header_read = FALSE; zstream->trailer_read = FALSE; zstream->crc32 = 0; (void)inflateEnd(&zstream->zs); i_stream_zlib_init(zstream); } if (!zstream->header_read) { do { ret = i_stream_zlib_read_header(stream); } while (ret == 0 && stream->istream.blocking); if (ret <= 0) return ret; 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 (stream->pos + CHUNK_SIZE > stream->buffer_size) { /* try to keep at least CHUNK_SIZE available */ if (!zstream->marked && stream->skip > 0) { /* don't try to keep anything cached if we don't have a seek mark. */ i_stream_compress(stream); } if (stream->buffer_size < i_stream_get_max_buffer_size(&stream->istream)) i_stream_grow_buffer(stream, CHUNK_SIZE); if (stream->pos == stream->buffer_size) { if (stream->skip > 0) { /* lose our buffer cache */ i_stream_compress(stream); } if (stream->pos == stream->buffer_size) return -2; /* buffer full */ } } if (i_stream_read_more(stream->parent, &data, &size) < 0) { if (stream->parent->stream_errno != 0) { stream->istream.stream_errno = stream->parent->stream_errno; } else { i_assert(stream->parent->eof); zlib_read_error(zstream, "unexpected EOF"); stream->istream.stream_errno = EPIPE; } return -1; } if (size == 0) { /* no more input */ i_assert(!stream->istream.blocking); return 0; } zstream->zs.next_in = (void *)data; zstream->zs.avail_in = size; out_size = stream->buffer_size - stream->pos; zstream->zs.next_out = stream->w_buffer + stream->pos; zstream->zs.avail_out = out_size; ret = inflate(&zstream->zs, Z_SYNC_FLUSH); out_size -= zstream->zs.avail_out; zstream->crc32 = crc32_data_more(zstream->crc32, stream->w_buffer + stream->pos, out_size); stream->pos += out_size; i_stream_skip(stream->parent, size - zstream->zs.avail_in); switch (ret) { case Z_OK: break; case Z_NEED_DICT: zlib_read_error(zstream, "can't read file without dict"); stream->istream.stream_errno = EINVAL; return -1; case Z_DATA_ERROR: zlib_read_error(zstream, "corrupted data"); stream->istream.stream_errno = EINVAL; return -1; case Z_MEM_ERROR: i_fatal_status(FATAL_OUTOFMEM, "zlib.read(%s): Out of memory", i_stream_get_name(&stream->istream)); case Z_STREAM_END: zstream->eof_offset = stream->istream.v_offset + (stream->pos - stream->skip); zstream->stream_size = zstream->eof_offset; zstream->zs.avail_in = 0; if (!zstream->trailer_read) { /* try to read and verify the trailer, we might not be called again. */ if (i_stream_zlib_read_trailer(zstream) < 0) return -1; } break; default: i_fatal("inflate() failed with %d", ret); } if (out_size == 0) { /* read more input */ return i_stream_zlib_read(stream); } return out_size; }