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
28 static size_t compress_gzip_chunk(void *, size_t, void *, size_t);
29 static size_t uncompress_gzip_chunk(void *, size_t, void *, size_t);
30 static int compress_gzip_file(FILE *, FILE *);
31 static int uncompress_gzip_file(FILE *, FILE *);
32
33
34 struct compress_backend compress_gzip = {
35 compress_gzip_chunk,
36 uncompress_gzip_chunk,
37
38 compress_gzip_file,
39 uncompress_gzip_file,
40 };
41
42 static size_t
compress_gzip_chunk(void * ib,size_t ibsz,void * ob,size_t obsz)43 compress_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
67 end:
68 deflateEnd(strm);
69 free(strm);
70 return ret;
71 }
72
73
74 static size_t
uncompress_gzip_chunk(void * ib,size_t ibsz,void * ob,size_t obsz)75 uncompress_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
102 end:
103 deflateEnd(strm);
104 free(strm);
105 return ret;
106 }
107
108
109 static int
compress_gzip_file(FILE * in,FILE * out)110 compress_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
133 end:
134 gzclose(gzf);
135 return (ret);
136 }
137
138
139 static int
uncompress_gzip_file(FILE * in,FILE * out)140 uncompress_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
163 end:
164 gzclose(gzf);
165 return (ret);
166 }
167