test-compression.c revision 8e8b9d01d454fc3dc81dbe3fd1cca772d1d2c381
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2014-2017 Dovecot authors, see the included COPYING file */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "lib.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "buffer.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "istream.h"
31d32d39dd09be0625a6d92ee715155f5d679515Timo Sirainen#include "ostream.h"
9bbfe7f5ff821cac11d1d2550a91b148f389d82cTimo Sirainen#include "sha1.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "randgen.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "test-common.h"
31d32d39dd09be0625a6d92ee715155f5d679515Timo Sirainen#include "compression.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include <unistd.h>
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include <fcntl.h>
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainenstatic void test_compression_handler(const struct compression_handler *handler)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *path = "test-compression.tmp";
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainen struct istream *file_input, *input;
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainen struct ostream *file_output, *output;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned char buf[IO_BLOCK_SIZE];
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const unsigned char *data;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen size_t size;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct sha1_ctxt sha1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned char output_sha1[SHA1_RESULTLEN], input_sha1[SHA1_RESULTLEN];
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int i;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen int fd;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ssize_t ret;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_begin(t_strdup_printf("compression handler %s", handler->name));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* write compressed data */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen fd = open(path, O_TRUNC | O_CREAT | O_RDWR, 0600);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (fd == -1)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_fatal("creat(%s) failed: %m", path);
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen file_output = o_stream_create_fd_file(fd, 0, FALSE);
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen output = handler->create_ostream(file_output, 1);
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen sha1_init(&sha1);
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen /* 1) write lots of easily compressible data */
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen memset(buf, 0, sizeof(buf));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (i = 0; i < 1024*1024*4 / sizeof(buf); i++) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen sha1_loop(&sha1, buf, sizeof(buf));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_assert(o_stream_send(output, buf, sizeof(buf)) == sizeof(buf));
0c47c2096714b50880d48d00ce0bf28349eb4aceTimo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* 2) write uncompressible data */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (i = 0; i < 1024*128 / sizeof(buf); i++) {
9eef11df882f9c14d164f42cb438f32fe724041cTimo Sirainen random_fill(buf, sizeof(buf));
9eef11df882f9c14d164f42cb438f32fe724041cTimo Sirainen sha1_loop(&sha1, buf, sizeof(buf));
9eef11df882f9c14d164f42cb438f32fe724041cTimo Sirainen test_assert(o_stream_send(output, buf, sizeof(buf)) == sizeof(buf));
9eef11df882f9c14d164f42cb438f32fe724041cTimo Sirainen }
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen /* 3) write semi-compressible data */
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen for (i = 0; i < sizeof(buf); i++) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (i_rand_limit(3) == 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen buf[i] = i_rand_limit(4);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen else
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen buf[i] = i;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (i = 0; i < 1024*128 / sizeof(buf); i++) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen sha1_loop(&sha1, buf, sizeof(buf));
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen test_assert(o_stream_send(output, buf, sizeof(buf)) == sizeof(buf));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_assert(o_stream_finish(output) > 0);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen o_stream_destroy(&output);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen o_stream_destroy(&file_output);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen sha1_result(&sha1, output_sha1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
975a784c2e02ecdcb56efb7a1db5e4769c7756d8Timo Sirainen /* read and uncompress the data */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen sha1_init(&sha1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen file_input = i_stream_create_fd(fd, IO_BLOCK_SIZE);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen input = handler->create_istream(file_input, FALSE);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen while ((ret = i_stream_read_more(input, &data, &size)) > 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen sha1_loop(&sha1, data, size);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_stream_skip(input, size);
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_assert(ret == -1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_stream_destroy(&input);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen i_stream_destroy(&file_input);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen sha1_result(&sha1, input_sha1);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_assert(memcmp(input_sha1, output_sha1, sizeof(input_sha1)) == 0);
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen i_unlink(path);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_close_fd(&fd);
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainen
8b3a4836da0b032673918941cb49c956d3b89b25Timo Sirainen test_end();
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void test_compression(void)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int i;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen
47255691575e06a1c95ce78ff0a1b502199de3abTimo Sirainen for (i = 0; compression_handlers[i].name != NULL; i++) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (compression_handlers[i].create_istream != NULL)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_compression_handler(&compression_handlers[i]);
307ec6c2c319e3335ddb1a7aca2d2884fe17fae0Timo Sirainen }
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void test_gz(const char *str1, const char *str2)
471a6b2b4e64eca5d5779ae20a477312b32c89eeTimo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct compression_handler *gz = compression_lookup_handler("gz");
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct ostream *buf_output, *output;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct istream *test_input, *input;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen buffer_t *buf = buffer_create_dynamic(pool_datastack_create(), 512);
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen
975a784c2e02ecdcb56efb7a1db5e4769c7756d8Timo Sirainen if (gz == NULL || gz->create_ostream == NULL)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return; /* not compiled in */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen /* write concated output */
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen buf_output = o_stream_create_buffer(buf);
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen o_stream_set_finish_via_child(buf_output, FALSE);
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainen
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainen output = gz->create_ostream(buf_output, 6);
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen o_stream_nsend_str(output, str1);
31d32d39dd09be0625a6d92ee715155f5d679515Timo Sirainen test_assert(o_stream_finish(output) > 0);
31d32d39dd09be0625a6d92ee715155f5d679515Timo Sirainen o_stream_destroy(&output);
31d32d39dd09be0625a6d92ee715155f5d679515Timo Sirainen
31d32d39dd09be0625a6d92ee715155f5d679515Timo Sirainen if (str2[0] != '\0') {
31d32d39dd09be0625a6d92ee715155f5d679515Timo Sirainen output = gz->create_ostream(buf_output, 6);
31d32d39dd09be0625a6d92ee715155f5d679515Timo Sirainen o_stream_nsend_str(output, "world");
31d32d39dd09be0625a6d92ee715155f5d679515Timo Sirainen test_assert(o_stream_finish(output) > 0);
31d32d39dd09be0625a6d92ee715155f5d679515Timo Sirainen o_stream_destroy(&output);
31d32d39dd09be0625a6d92ee715155f5d679515Timo Sirainen }
31d32d39dd09be0625a6d92ee715155f5d679515Timo Sirainen
31d32d39dd09be0625a6d92ee715155f5d679515Timo Sirainen o_stream_destroy(&buf_output);
31d32d39dd09be0625a6d92ee715155f5d679515Timo Sirainen
31d32d39dd09be0625a6d92ee715155f5d679515Timo Sirainen /* read concated input */
31d32d39dd09be0625a6d92ee715155f5d679515Timo Sirainen const unsigned char *data;
31d32d39dd09be0625a6d92ee715155f5d679515Timo Sirainen size_t size;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_input = test_istream_create_data(buf->data, buf->used);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_istream_set_allow_eof(test_input, FALSE);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen input = gz->create_istream(test_input, TRUE);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (size_t i = 0; i <= buf->used; i++) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_istream_set_size(test_input, i);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_assert(i_stream_read(input) >= 0);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_istream_set_allow_eof(test_input, TRUE);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_assert(i_stream_read(input) == -1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_assert(input->stream_errno == 0);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen data = i_stream_get_data(input, &size);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_assert(size == strlen(str1)+strlen(str2) &&
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen memcmp(data, str1, strlen(str1)) == 0 &&
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen memcmp(data+strlen(str1), str2, strlen(str2)) == 0);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_stream_unref(&input);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_stream_unref(&test_input);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void test_gz_concat(void)
471a6b2b4e64eca5d5779ae20a477312b32c89eeTimo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_begin("gz concat");
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_gz("hello", "world");
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainen test_end();
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainen}
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainen
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainenstatic void test_gz_no_concat(void)
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainen{
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainen test_begin("gz no concat");
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainen test_gz("hello", "");
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainen test_end();
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainen}
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainen
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainenstatic void test_gz_large_header(void)
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainen{
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainen const struct compression_handler *gz = compression_lookup_handler("gz");
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainen static const unsigned char gz_input[] = {
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainen 0x1f, 0x8b, 0x08, 0x08,
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainen 'a','a','a','a','a','a','a','a','a','a','a',
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen 0
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen };
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct istream *file_input, *input;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen size_t i;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen if (gz == NULL || gz->create_istream == NULL)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return; /* not compiled in */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_begin("gz large header");
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* max buffer size smaller than gz header */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (i = 1; i < sizeof(gz_input); i++) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen file_input = test_istream_create_data(gz_input, sizeof(gz_input));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_istream_set_size(file_input, i);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_istream_set_max_buffer_size(file_input, i);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen input = gz->create_istream(file_input, FALSE);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_assert_idx(i_stream_read(input) == 0, i);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_assert_idx(i_stream_read(input) == -1 &&
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen input->stream_errno == EINVAL, i);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_stream_unref(&input);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_stream_unref(&file_input);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* max buffer size is exactly the gz header */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen file_input = test_istream_create_data(gz_input, sizeof(gz_input));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen input = gz->create_istream(file_input, FALSE);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_istream_set_size(input, i);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_istream_set_allow_eof(input, FALSE);
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen test_istream_set_max_buffer_size(input, i);
d9b9687bf8cae9cfb070b1b7aadefa683220269fTimo Sirainen test_assert(i_stream_read(input) == 0);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_stream_unref(&input);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen i_stream_unref(&file_input);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen test_end();
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void test_uncompress_file(const char *path)
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct compression_handler *handler;
ec0cc8fa647794e44a1afaa448f495a713048dc4Timo Sirainen struct istream *input, *file_input;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const unsigned char *data;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen size_t size;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen handler = compression_lookup_handler_from_ext(path);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (handler == NULL)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_fatal("Can't detect compression algorithm from path %s", path);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (handler->create_istream == NULL)
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen i_fatal("Support not compiled in for %s", handler->name);
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen
307ec6c2c319e3335ddb1a7aca2d2884fe17fae0Timo Sirainen file_input = i_stream_create_file(path, IO_BLOCK_SIZE);
975a784c2e02ecdcb56efb7a1db5e4769c7756d8Timo Sirainen input = handler->create_istream(file_input, TRUE);
975a784c2e02ecdcb56efb7a1db5e4769c7756d8Timo Sirainen while (i_stream_read_more(input, &data, &size) > 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (write(STDOUT_FILENO, data, size) < 0)
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen break;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen i_stream_skip(input, size);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_stream_destroy(&input);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void test_compress_file(const char *in_path, const char *out_path)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
08e9fec5ba9e1a26e658c4224207d666b6ced27dTimo Sirainen const struct compression_handler *handler;
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen struct istream *input, *file_input;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct ostream *output, *file_output;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen int fd_in, fd_out;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct sha1_ctxt sha1;
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen unsigned char output_sha1[SHA1_RESULTLEN], input_sha1[SHA1_RESULTLEN];
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen const unsigned char *data;
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen size_t size;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen ssize_t ret;
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen handler = compression_lookup_handler_from_ext(out_path);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen if (handler == NULL)
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen i_fatal("Can't detect compression algorithm from path %s", out_path);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen if (handler->create_ostream == NULL)
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen i_fatal("Support not compiled in for %s", handler->name);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen /* write the compressed output file */
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen fd_in = open(in_path, O_RDONLY);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen if (fd_in == -1)
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen i_fatal("open(%s) failed: %m", in_path);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen fd_out = open(out_path, O_TRUNC | O_CREAT | O_RDWR, 0600);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen if (fd_out == -1)
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen i_fatal("creat(%s) failed: %m", out_path);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen sha1_init(&sha1);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen file_output = o_stream_create_fd_file(fd_out, 0, FALSE);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen output = handler->create_ostream(file_output, 1);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen input = i_stream_create_fd_autoclose(&fd_in, IO_BLOCK_SIZE);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen while (i_stream_read_more(input, &data, &size) > 0) {
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen sha1_loop(&sha1, data, size);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen o_stream_nsend(output, data, size);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen i_stream_skip(input, size);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen }
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen if (o_stream_finish(output) < 0) {
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen i_fatal("write(%s) failed: %s",
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen out_path, o_stream_get_error(output));
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen }
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen i_stream_destroy(&input);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen o_stream_destroy(&output);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen o_stream_destroy(&file_output);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen sha1_result(&sha1, output_sha1);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen /* verify that we can read the compressed file */
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen sha1_init(&sha1);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen file_input = i_stream_create_fd(fd_out, IO_BLOCK_SIZE);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen input = handler->create_istream(file_input, FALSE);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen while ((ret = i_stream_read_more(input, &data, &size)) > 0) {
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen sha1_loop(&sha1, data, size);
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen i_stream_skip(input, size);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen }
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen i_stream_destroy(&input);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen i_stream_destroy(&file_input);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen sha1_result(&sha1, input_sha1);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen if (memcmp(input_sha1, output_sha1, sizeof(input_sha1)) != 0)
5e32f3d9e2c58b6db53cc3b063c9ee73949207caTimo Sirainen i_fatal("Decompression couldn't get the original input");
5e32f3d9e2c58b6db53cc3b063c9ee73949207caTimo Sirainen i_close_fd(&fd_out);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen}
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainenint main(int argc, char *argv[])
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen{
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen static void (*const test_functions[])(void) = {
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen test_compression,
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen test_gz_concat,
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen test_gz_no_concat,
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen test_gz_large_header,
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen NULL
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen };
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen if (argc == 2) {
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen test_uncompress_file(argv[1]);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen return 0;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen }
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen if (argc == 3) {
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen test_compress_file(argv[1], argv[2]);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen return 0;
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen }
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen return test_run(test_functions);
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen}
41e51b972f02e8b16c19fab9160294ea0a07c343Timo Sirainen