compression.c revision 5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2010-2013 Dovecot authors, see the included COPYING file */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "lib.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "istream.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "istream-zlib.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "ostream-zlib.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "compression.h"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#ifndef HAVE_ZLIB
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch# define i_stream_create_gz NULL
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch# define o_stream_create_gz NULL
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#endif
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#ifndef HAVE_BZLIB
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch# define i_stream_create_bz2 NULL
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch# define o_stream_create_bz2 NULL
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#endif
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic bool is_compressed_zlib(struct istream *input)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch const unsigned char *data;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch size_t size;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch /* Peek in to the stream and see if it looks like it's compressed
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch (based on its header). This also means that users can try to exploit
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch security holes in the uncompression library by APPENDing a specially
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch crafted mail. So let's hope zlib is free of holes. */
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch if (i_stream_read_data(input, &data, &size, 1) <= 0)
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch return FALSE;
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch i_assert(size >= 2);
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch return data[0] == 31 && data[1] == 139;
d67f004ebf944adca3ba09ed547febfa75442476Stephan Bosch}
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Boschstatic bool is_compressed_bzlib(struct istream *input)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch{
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch const unsigned char *data;
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch size_t size;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
d67f004ebf944adca3ba09ed547febfa75442476Stephan Bosch if (i_stream_read_data(input, &data, &size, 4+6 - 1) <= 0)
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch return FALSE;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch if (data[0] != 'B' || data[1] != 'Z')
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch return FALSE;
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch if (data[2] != 'h' && data[2] != '0')
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch return FALSE;
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch if (data[3] < '1' || data[3] > '9')
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch return FALSE;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch return memcmp(data + 4, "\x31\x41\x59\x26\x53\x59", 6) == 0;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch}
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch
6776cc851a593b2a893103833e08ed3902ce1933Stephan Boschconst struct compression_handler *compression_lookup_handler(const char *name)
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch{
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch unsigned int i;
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch for (i = 0; compression_handlers[i].name != NULL; i++) {
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch if (strcmp(name, compression_handlers[i].name) == 0)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch return &compression_handlers[i];
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch }
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch return NULL;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch}
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Boschconst struct compression_handler *
6776cc851a593b2a893103833e08ed3902ce1933Stephan Boschcompression_detect_handler(struct istream *input)
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch{
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch unsigned int i;
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch for (i = 0; compression_handlers[i].name != NULL; i++) {
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch if (compression_handlers[i].is_compressed != NULL &&
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch compression_handlers[i].is_compressed(input))
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch return &compression_handlers[i];
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch }
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch return NULL;
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch}
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch
6776cc851a593b2a893103833e08ed3902ce1933Stephan Boschconst struct compression_handler *
6776cc851a593b2a893103833e08ed3902ce1933Stephan Boschcompression_lookup_handler_from_ext(const char *path)
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch{
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch unsigned int i, len, path_len = strlen(path);
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch
6776cc851a593b2a893103833e08ed3902ce1933Stephan Bosch for (i = 0; compression_handlers[i].name != NULL; i++) {
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch if (compression_handlers[i].ext == NULL)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch continue;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch len = strlen(compression_handlers[i].ext);
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch if (path_len > len &&
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch strcmp(path + path_len - len, compression_handlers[i].ext) == 0)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch return &compression_handlers[i];
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch return NULL;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschconst struct compression_handler compression_handlers[] = {
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch { "gz", ".gz", is_compressed_zlib,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_stream_create_gz, o_stream_create_gz },
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch { "bz2", ".bz2", is_compressed_bzlib,
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch i_stream_create_bz2, o_stream_create_bz2 },
fab1a1c57f467c19c728d2391ff5e5025bb832f7Stephan Bosch { "deflate", NULL, NULL,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_stream_create_deflate, o_stream_create_deflate },
fd30e54bd56f0869f5c2e14b42fd53f7b36cff45Stephan Bosch { NULL, NULL, NULL, NULL, NULL }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch};
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen