1/*	$OpenBSD: compress_gzip.c,v 1.13 2021/06/14 17:58:15 eric Exp $	*/
2
3/*
4 * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org>
5 * Copyright (c) 2012 Charles Longeau <chl@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include <stdlib.h>
21#include <zlib.h>
22
23#include "smtpd.h"
24
25#define	GZIP_BUFFER_SIZE	16384
26
27
28static size_t	compress_gzip_chunk(void *, size_t, void *, size_t);
29static size_t	uncompress_gzip_chunk(void *, size_t, void *, size_t);
30static int	compress_gzip_file(FILE *, FILE *);
31static int	uncompress_gzip_file(FILE *, FILE *);
32
33
34struct compress_backend	compress_gzip = {
35	compress_gzip_chunk,
36	uncompress_gzip_chunk,
37
38	compress_gzip_file,
39	uncompress_gzip_file,
40};
41
42static size_t
43compress_gzip_chunk(void *ib, size_t ibsz, void *ob, size_t obsz)
44{
45	z_stream       *strm;
46	size_t		ret = 0;
47
48	if ((strm = calloc(1, sizeof *strm)) == NULL)
49		return 0;
50
51	strm->zalloc = Z_NULL;
52	strm->zfree = Z_NULL;
53	strm->opaque = Z_NULL;
54	if (deflateInit2(strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
55		(15+16), 8, Z_DEFAULT_STRATEGY) != Z_OK)
56		goto end;
57
58	strm->avail_in  = ibsz;
59	strm->next_in   = (unsigned char *)ib;
60	strm->avail_out = obsz;
61	strm->next_out  = (unsigned char *)ob;
62	if (deflate(strm, Z_FINISH) != Z_STREAM_END)
63		goto end;
64
65	ret = strm->total_out;
66
67end:
68	deflateEnd(strm);
69	free(strm);
70	return ret;
71}
72
73
74static size_t
75uncompress_gzip_chunk(void *ib, size_t ibsz, void *ob, size_t obsz)
76{
77	z_stream       *strm;
78	size_t		ret = 0;
79
80	if ((strm = calloc(1, sizeof *strm)) == NULL)
81		return 0;
82
83	strm->zalloc   = Z_NULL;
84	strm->zfree    = Z_NULL;
85	strm->opaque   = Z_NULL;
86	strm->avail_in = 0;
87	strm->next_in  = Z_NULL;
88
89	if (inflateInit2(strm, (15+16)) != Z_OK)
90		goto end;
91
92	strm->avail_in  = ibsz;
93	strm->next_in   = (unsigned char *)ib;
94	strm->avail_out = obsz;
95	strm->next_out  = (unsigned char *)ob;
96
97	if (inflate(strm, Z_FINISH) != Z_STREAM_END)
98		goto end;
99
100	ret = strm->total_out;
101
102end:
103	deflateEnd(strm);
104	free(strm);
105	return ret;
106}
107
108
109static int
110compress_gzip_file(FILE *in, FILE *out)
111{
112	gzFile  gzf;
113	char  ibuf[GZIP_BUFFER_SIZE];
114	int  r;
115	int  ret = 0;
116
117	if (in == NULL || out == NULL)
118		return (0);
119
120	gzf = gzdopen(fileno(out), "wb");
121	if (gzf == NULL)
122		return (0);
123
124	while ((r = fread(ibuf, 1, GZIP_BUFFER_SIZE, in)) != 0) {
125		if (gzwrite(gzf, ibuf, r) != r)
126			goto end;
127	}
128	if (!feof(in))
129		goto end;
130
131	ret = 1;
132
133end:
134	gzclose(gzf);
135	return (ret);
136}
137
138
139static int
140uncompress_gzip_file(FILE *in, FILE *out)
141{
142	gzFile  gzf;
143	char  obuf[GZIP_BUFFER_SIZE];
144	int  r;
145	int  ret = 0;
146
147	if (in == NULL || out == NULL)
148		return (0);
149
150	gzf = gzdopen(fileno(in), "r");
151	if (gzf == NULL)
152		return (0);
153
154	while ((r = gzread(gzf, obuf, sizeof(obuf))) > 0) {
155		if  (fwrite(obuf, r, 1, out) != 1)
156			goto end;
157	}
158	if (!gzeof(gzf))
159		goto end;
160
161	ret = 1;
162
163end:
164	gzclose(gzf);
165	return (ret);
166}
167