883N/A/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
883N/A
883N/A#include "lib.h"
883N/A#include "istream.h"
883N/A#include "istream-zlib.h"
883N/A#include "ostream-zlib.h"
883N/A#include "iostream-lz4.h"
883N/A#include "compression.h"
883N/A
883N/A#ifndef HAVE_ZLIB
883N/A# define i_stream_create_gz NULL
883N/A# define o_stream_create_gz NULL
883N/A# define i_stream_create_deflate NULL
883N/A# define o_stream_create_deflate NULL
883N/A#endif
883N/A#ifndef HAVE_BZLIB
883N/A# define i_stream_create_bz2 NULL
883N/A# define o_stream_create_bz2 NULL
883N/A#endif
883N/A#ifndef HAVE_LZMA
883N/A# define i_stream_create_lzma NULL
883N/A# define o_stream_create_lzma NULL
3996N/A#endif
883N/A#ifndef HAVE_LZ4
883N/A# define i_stream_create_lz4 NULL
883N/A# define o_stream_create_lz4 NULL
883N/A#endif
883N/A
883N/Astatic bool is_compressed_zlib(struct istream *input)
883N/A{
883N/A const unsigned char *data;
883N/A size_t size;
1273N/A
883N/A /* Peek in to the stream and see if it looks like it's compressed
4561N/A (based on its header). This also means that users can try to exploit
4561N/A security holes in the uncompression library by APPENDing a specially
4561N/A crafted mail. So let's hope zlib is free of holes. */
4561N/A if (i_stream_read_bytes(input, &data, &size, 2) <= 0)
4561N/A return FALSE;
4561N/A i_assert(size >= 2);
4561N/A
883N/A return data[0] == 31 && data[1] == 139;
883N/A}
883N/A
883N/Astatic bool is_compressed_bzlib(struct istream *input)
883N/A{
883N/A const unsigned char *data;
883N/A size_t size;
1653N/A
883N/A if (i_stream_read_bytes(input, &data, &size, 4+6) <= 0)
883N/A return FALSE;
883N/A if (data[0] != 'B' || data[1] != 'Z')
883N/A return FALSE;
883N/A if (data[2] != 'h' && data[2] != '0')
883N/A return FALSE;
883N/A if (data[3] < '1' || data[3] > '9')
883N/A return FALSE;
883N/A return memcmp(data + 4, "\x31\x41\x59\x26\x53\x59", 6) == 0;
1574N/A}
1574N/A
1574N/Astatic bool is_compressed_xz(struct istream *input)
883N/A{
883N/A const unsigned char *data;
883N/A size_t size;
883N/A
883N/A if (i_stream_read_bytes(input, &data, &size, 6) <= 0)
883N/A return FALSE;
883N/A return memcmp(data, "\xfd\x37\x7a\x58\x5a", 6) == 0;
883N/A}
883N/A
883N/Astatic bool is_compressed_lz4(struct istream *input)
887N/A{
887N/A const unsigned char *data;
887N/A size_t size;
913N/A
913N/A if (i_stream_read_bytes(input, &data, &size, IOSTREAM_LZ4_MAGIC_LEN) <= 0)
913N/A return FALSE;
913N/A /* there is no standard LZ4 header, so we've created our own */
883N/A return memcmp(data, IOSTREAM_LZ4_MAGIC, IOSTREAM_LZ4_MAGIC_LEN) == 0;
3996N/A}
const struct compression_handler *compression_lookup_handler(const char *name)
{
unsigned int i;
for (i = 0; compression_handlers[i].name != NULL; i++) {
if (strcmp(name, compression_handlers[i].name) == 0)
return &compression_handlers[i];
}
return NULL;
}
const struct compression_handler *
compression_detect_handler(struct istream *input)
{
unsigned int i;
for (i = 0; compression_handlers[i].name != NULL; i++) {
if (compression_handlers[i].is_compressed != NULL &&
compression_handlers[i].is_compressed(input))
return &compression_handlers[i];
}
return NULL;
}
const struct compression_handler *
compression_lookup_handler_from_ext(const char *path)
{
unsigned int i;
size_t len, path_len = strlen(path);
for (i = 0; compression_handlers[i].name != NULL; i++) {
if (compression_handlers[i].ext == NULL)
continue;
len = strlen(compression_handlers[i].ext);
if (path_len > len &&
strcmp(path + path_len - len, compression_handlers[i].ext) == 0)
return &compression_handlers[i];
}
return NULL;
}
const struct compression_handler compression_handlers[] = {
{ "gz", ".gz", is_compressed_zlib,
i_stream_create_gz, o_stream_create_gz },
{ "bz2", ".bz2", is_compressed_bzlib,
i_stream_create_bz2, o_stream_create_bz2 },
{ "deflate", NULL, NULL,
i_stream_create_deflate, o_stream_create_deflate },
{ "xz", ".xz", is_compressed_xz,
i_stream_create_lzma, o_stream_create_lzma },
{ "lz4", ".lz4", is_compressed_lz4,
i_stream_create_lz4, o_stream_create_lz4 },
{ NULL, NULL, NULL, NULL, NULL }
};