1*d3140113Seric /* $OpenBSD: compress_gzip.c,v 1.13 2021/06/14 17:58:15 eric Exp $ */
2858abddcSgilles
3858abddcSgilles /*
465c4fdfbSgilles * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org>
5858abddcSgilles * Copyright (c) 2012 Charles Longeau <chl@openbsd.org>
6858abddcSgilles *
7858abddcSgilles * Permission to use, copy, modify, and distribute this software for any
8858abddcSgilles * purpose with or without fee is hereby granted, provided that the above
9858abddcSgilles * copyright notice and this permission notice appear in all copies.
10858abddcSgilles *
11858abddcSgilles * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12858abddcSgilles * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13858abddcSgilles * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14858abddcSgilles * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15858abddcSgilles * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16858abddcSgilles * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17858abddcSgilles * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18858abddcSgilles */
19858abddcSgilles
20858abddcSgilles #include <stdlib.h>
21858abddcSgilles #include <zlib.h>
22858abddcSgilles
23858abddcSgilles #include "smtpd.h"
24299c4efeSeric
25299c4efeSeric #define GZIP_BUFFER_SIZE 16384
26299c4efeSeric
27299c4efeSeric
28299c4efeSeric static size_t compress_gzip_chunk(void *, size_t, void *, size_t);
29299c4efeSeric static size_t uncompress_gzip_chunk(void *, size_t, void *, size_t);
30299c4efeSeric static int compress_gzip_file(FILE *, FILE *);
31299c4efeSeric static int uncompress_gzip_file(FILE *, FILE *);
32299c4efeSeric
33858abddcSgilles
34858abddcSgilles struct compress_backend compress_gzip = {
3565c4fdfbSgilles compress_gzip_chunk,
3665c4fdfbSgilles uncompress_gzip_chunk,
37299c4efeSeric
38299c4efeSeric compress_gzip_file,
39299c4efeSeric uncompress_gzip_file,
40858abddcSgilles };
41858abddcSgilles
42299c4efeSeric static size_t
compress_gzip_chunk(void * ib,size_t ibsz,void * ob,size_t obsz)43299c4efeSeric compress_gzip_chunk(void *ib, size_t ibsz, void *ob, size_t obsz)
44858abddcSgilles {
45299c4efeSeric z_stream *strm;
46299c4efeSeric size_t ret = 0;
47299c4efeSeric
48299c4efeSeric if ((strm = calloc(1, sizeof *strm)) == NULL)
49299c4efeSeric return 0;
50299c4efeSeric
51299c4efeSeric strm->zalloc = Z_NULL;
52299c4efeSeric strm->zfree = Z_NULL;
53299c4efeSeric strm->opaque = Z_NULL;
54299c4efeSeric if (deflateInit2(strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
55299c4efeSeric (15+16), 8, Z_DEFAULT_STRATEGY) != Z_OK)
56299c4efeSeric goto end;
57299c4efeSeric
58299c4efeSeric strm->avail_in = ibsz;
59299c4efeSeric strm->next_in = (unsigned char *)ib;
60299c4efeSeric strm->avail_out = obsz;
61299c4efeSeric strm->next_out = (unsigned char *)ob;
62299c4efeSeric if (deflate(strm, Z_FINISH) != Z_STREAM_END)
63299c4efeSeric goto end;
64299c4efeSeric
65299c4efeSeric ret = strm->total_out;
66299c4efeSeric
67299c4efeSeric end:
68299c4efeSeric deflateEnd(strm);
69299c4efeSeric free(strm);
70299c4efeSeric return ret;
71858abddcSgilles }
72858abddcSgilles
73299c4efeSeric
74858abddcSgilles static size_t
uncompress_gzip_chunk(void * ib,size_t ibsz,void * ob,size_t obsz)75299c4efeSeric uncompress_gzip_chunk(void *ib, size_t ibsz, void *ob, size_t obsz)
76858abddcSgilles {
77299c4efeSeric z_stream *strm;
78299c4efeSeric size_t ret = 0;
79299c4efeSeric
80299c4efeSeric if ((strm = calloc(1, sizeof *strm)) == NULL)
81299c4efeSeric return 0;
82299c4efeSeric
83299c4efeSeric strm->zalloc = Z_NULL;
84299c4efeSeric strm->zfree = Z_NULL;
85299c4efeSeric strm->opaque = Z_NULL;
86299c4efeSeric strm->avail_in = 0;
87299c4efeSeric strm->next_in = Z_NULL;
88299c4efeSeric
89299c4efeSeric if (inflateInit2(strm, (15+16)) != Z_OK)
90299c4efeSeric goto end;
91299c4efeSeric
92299c4efeSeric strm->avail_in = ibsz;
93299c4efeSeric strm->next_in = (unsigned char *)ib;
94299c4efeSeric strm->avail_out = obsz;
95299c4efeSeric strm->next_out = (unsigned char *)ob;
96299c4efeSeric
97299c4efeSeric if (inflate(strm, Z_FINISH) != Z_STREAM_END)
98299c4efeSeric goto end;
99299c4efeSeric
100299c4efeSeric ret = strm->total_out;
101299c4efeSeric
102299c4efeSeric end:
103299c4efeSeric deflateEnd(strm);
104299c4efeSeric free(strm);
105299c4efeSeric return ret;
106858abddcSgilles }
107858abddcSgilles
108299c4efeSeric
109299c4efeSeric static int
compress_gzip_file(FILE * in,FILE * out)110299c4efeSeric compress_gzip_file(FILE *in, FILE *out)
111858abddcSgilles {
112299c4efeSeric gzFile gzf;
113299c4efeSeric char ibuf[GZIP_BUFFER_SIZE];
1141997d66fSrob int r;
115299c4efeSeric int ret = 0;
116299c4efeSeric
117299c4efeSeric if (in == NULL || out == NULL)
118299c4efeSeric return (0);
119299c4efeSeric
120299c4efeSeric gzf = gzdopen(fileno(out), "wb");
121299c4efeSeric if (gzf == NULL)
122299c4efeSeric return (0);
123299c4efeSeric
124299c4efeSeric while ((r = fread(ibuf, 1, GZIP_BUFFER_SIZE, in)) != 0) {
1251997d66fSrob if (gzwrite(gzf, ibuf, r) != r)
126299c4efeSeric goto end;
127299c4efeSeric }
128299c4efeSeric if (!feof(in))
129299c4efeSeric goto end;
130299c4efeSeric
131299c4efeSeric ret = 1;
132299c4efeSeric
133299c4efeSeric end:
134299c4efeSeric gzclose(gzf);
135299c4efeSeric return (ret);
13665c4fdfbSgilles }
137858abddcSgilles
138858abddcSgilles
139299c4efeSeric static int
uncompress_gzip_file(FILE * in,FILE * out)140299c4efeSeric uncompress_gzip_file(FILE *in, FILE *out)
14165c4fdfbSgilles {
142299c4efeSeric gzFile gzf;
143299c4efeSeric char obuf[GZIP_BUFFER_SIZE];
1441997d66fSrob int r;
145299c4efeSeric int ret = 0;
146858abddcSgilles
147299c4efeSeric if (in == NULL || out == NULL)
148299c4efeSeric return (0);
149299c4efeSeric
150299c4efeSeric gzf = gzdopen(fileno(in), "r");
151299c4efeSeric if (gzf == NULL)
152299c4efeSeric return (0);
153299c4efeSeric
154299c4efeSeric while ((r = gzread(gzf, obuf, sizeof(obuf))) > 0) {
1551997d66fSrob if (fwrite(obuf, r, 1, out) != 1)
156299c4efeSeric goto end;
157299c4efeSeric }
158299c4efeSeric if (!gzeof(gzf))
159299c4efeSeric goto end;
160299c4efeSeric
161299c4efeSeric ret = 1;
162299c4efeSeric
163299c4efeSeric end:
164299c4efeSeric gzclose(gzf);
165299c4efeSeric return (ret);
166858abddcSgilles }
167