xref: /openbsd-src/usr.sbin/smtpd/compress_gzip.c (revision d3140113bef2b86d3af61dd20c05a8630ff966c2)
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