istream-zlib.c revision 0757cf450c35c2fe848106b652487785579a5162
/* Copyright (c) 2010-2016 Dovecot authors, see the included COPYING file */
#include "lib.h"
#ifdef HAVE_ZLIB
#include "crc32.h"
#include "istream-private.h"
#include "istream-zlib.h"
#include <zlib.h>
#define GZ_HEADER_MIN_SIZE 10
#define GZ_TRAILER_SIZE 8
#define GZ_MAGIC1 0x1f
#define GZ_MAGIC2 0x8b
#define GZ_FLAG_FHCRC 0x02
#define GZ_FLAG_FEXTRA 0x04
#define GZ_FLAG_FNAME 0x08
#define GZ_FLAG_FCOMMENT 0x10
struct zlib_istream {
struct istream_private istream;
struct stat last_parent_statbuf;
bool gz:1;
bool log_errors:1;
bool marked:1;
bool header_read:1;
bool trailer_read:1;
bool zs_closed:1;
bool starting_concated_output:1;
};
bool close_parent)
{
}
if (close_parent)
}
{
"zlib.read(%s): %s at %"PRIuUOFF_T,
if (zstream->log_errors)
}
{
const unsigned char *data;
unsigned int pos, fextra_size;
int ret;
}
return ret;
}
if (size < GZ_HEADER_MIN_SIZE)
return 0;
/* missing gzip magic header */
return -1;
}
return 0;
pos += 2;
return 0;
pos += fextra_size;
}
do {
return 0;
}
do {
return 0;
}
return 0;
pos += 2;
}
return 1;
}
{
}
{
const unsigned char *data;
int ret;
}
return ret;
}
if (size < GZ_TRAILER_SIZE)
return 0;
return -1;
}
return 1;
}
{
const unsigned char *data;
int ret;
if (!zstream->trailer_read) {
do {
if (ret <= 0)
return ret;
}
return -1;
}
}
if (zstream->starting_concated_output) {
/* make sure there actually is something in parent stream.
we don't want to reset the stream unless we actually see
some concated output. */
if (ret <= 0) {
if (ret == 0)
return 0;
}
return -1;
}
/* gzip file with concatenated content */
}
if (!zstream->header_read) {
do {
if (ret <= 0)
return ret;
}
/* we're here because we seeked back within the read buffer. */
if (zstream->trailer_read) {
}
return ret;
}
/* try to keep at least CHUNK_SIZE available */
/* don't try to keep anything cached if we don't
have a seek mark. */
}
/* lose our buffer cache */
}
return -2; /* buffer full */
}
}
} else {
}
return -1;
}
if (size == 0) {
/* no more input */
return 0;
}
out_size);
switch (ret) {
case Z_OK:
break;
case Z_NEED_DICT:
return -1;
case Z_DATA_ERROR:
return -1;
case Z_MEM_ERROR:
case Z_STREAM_END:
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:
}
if (out_size == 0) {
/* read more input */
return i_stream_zlib_read(stream);
}
return out_size;
}
{
int ret;
switch (ret) {
case Z_OK:
break;
case Z_MEM_ERROR:
case Z_VERSION_ERROR:
i_fatal("Wrong zlib library version (broken compilation)");
case Z_STREAM_ERROR:
i_fatal("zlib: Invalid parameters");
default:
}
}
{
}
static void
{
if (v_offset < start_offset) {
/* have to seek backwards */
start_offset = 0;
}
/* seeking backwards within what's already cached */
} else {
/* read and cache forward */
do {
v_offset -
break;
}
/* some failure, we've broken it */
i_error("zlib_istream.seek(%s) failed: %s",
} else {
/* unexpected EOF. allow it since we may just
want to check if there's anything.. */
}
}
}
if (mark)
}
static int
{
return -1;
}
/* when exact=FALSE always return the parent stat's size, even if we
know the exact value. this is necessary because otherwise e.g. mbox
code can see two different values and think that a compressed mbox
file keeps changing. */
if (!exact)
return 0;
do {
return -1;
}
return 0;
}
{
/* a compressed file doesn't change unexpectedly,
don't clear our caches unnecessarily */
return;
}
}
}
static struct istream *
{
struct zlib_istream *zstream;
}
{
}
{
}
#endif