1 |
|
|
/* $OpenBSD: compress_gzip.c,v 1.10 2015/12/28 22:08:30 jung 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 <sys/types.h> |
21 |
|
|
#include <sys/queue.h> |
22 |
|
|
#include <sys/tree.h> |
23 |
|
|
#include <sys/socket.h> |
24 |
|
|
#include <sys/stat.h> |
25 |
|
|
|
26 |
|
|
#include <ctype.h> |
27 |
|
|
#include <err.h> |
28 |
|
|
#include <fcntl.h> |
29 |
|
|
#include <imsg.h> |
30 |
|
|
#include <pwd.h> |
31 |
|
|
#include <stdio.h> |
32 |
|
|
#include <stdlib.h> |
33 |
|
|
#include <string.h> |
34 |
|
|
#include <unistd.h> |
35 |
|
|
#include <limits.h> |
36 |
|
|
|
37 |
|
|
#include <zlib.h> |
38 |
|
|
|
39 |
|
|
#include "smtpd.h" |
40 |
|
|
#include "log.h" |
41 |
|
|
|
42 |
|
|
|
43 |
|
|
#define GZIP_BUFFER_SIZE 16384 |
44 |
|
|
|
45 |
|
|
|
46 |
|
|
static size_t compress_gzip_chunk(void *, size_t, void *, size_t); |
47 |
|
|
static size_t uncompress_gzip_chunk(void *, size_t, void *, size_t); |
48 |
|
|
static int compress_gzip_file(FILE *, FILE *); |
49 |
|
|
static int uncompress_gzip_file(FILE *, FILE *); |
50 |
|
|
|
51 |
|
|
|
52 |
|
|
struct compress_backend compress_gzip = { |
53 |
|
|
compress_gzip_chunk, |
54 |
|
|
uncompress_gzip_chunk, |
55 |
|
|
|
56 |
|
|
compress_gzip_file, |
57 |
|
|
uncompress_gzip_file, |
58 |
|
|
}; |
59 |
|
|
|
60 |
|
|
static size_t |
61 |
|
|
compress_gzip_chunk(void *ib, size_t ibsz, void *ob, size_t obsz) |
62 |
|
|
{ |
63 |
|
|
z_stream *strm; |
64 |
|
|
size_t ret = 0; |
65 |
|
|
|
66 |
|
|
if ((strm = calloc(1, sizeof *strm)) == NULL) |
67 |
|
|
return 0; |
68 |
|
|
|
69 |
|
|
strm->zalloc = Z_NULL; |
70 |
|
|
strm->zfree = Z_NULL; |
71 |
|
|
strm->opaque = Z_NULL; |
72 |
|
|
if (deflateInit2(strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, |
73 |
|
|
(15+16), 8, Z_DEFAULT_STRATEGY) != Z_OK) |
74 |
|
|
goto end; |
75 |
|
|
|
76 |
|
|
strm->avail_in = ibsz; |
77 |
|
|
strm->next_in = (unsigned char *)ib; |
78 |
|
|
strm->avail_out = obsz; |
79 |
|
|
strm->next_out = (unsigned char *)ob; |
80 |
|
|
if (deflate(strm, Z_FINISH) != Z_STREAM_END) |
81 |
|
|
goto end; |
82 |
|
|
|
83 |
|
|
ret = strm->total_out; |
84 |
|
|
|
85 |
|
|
end: |
86 |
|
|
deflateEnd(strm); |
87 |
|
|
free(strm); |
88 |
|
|
return ret; |
89 |
|
|
} |
90 |
|
|
|
91 |
|
|
|
92 |
|
|
static size_t |
93 |
|
|
uncompress_gzip_chunk(void *ib, size_t ibsz, void *ob, size_t obsz) |
94 |
|
|
{ |
95 |
|
|
z_stream *strm; |
96 |
|
|
size_t ret = 0; |
97 |
|
|
|
98 |
|
|
if ((strm = calloc(1, sizeof *strm)) == NULL) |
99 |
|
|
return 0; |
100 |
|
|
|
101 |
|
|
strm->zalloc = Z_NULL; |
102 |
|
|
strm->zfree = Z_NULL; |
103 |
|
|
strm->opaque = Z_NULL; |
104 |
|
|
strm->avail_in = 0; |
105 |
|
|
strm->next_in = Z_NULL; |
106 |
|
|
|
107 |
|
|
if (inflateInit2(strm, (15+16)) != Z_OK) |
108 |
|
|
goto end; |
109 |
|
|
|
110 |
|
|
strm->avail_in = ibsz; |
111 |
|
|
strm->next_in = (unsigned char *)ib; |
112 |
|
|
strm->avail_out = obsz; |
113 |
|
|
strm->next_out = (unsigned char *)ob; |
114 |
|
|
|
115 |
|
|
if (inflate(strm, Z_FINISH) != Z_STREAM_END) |
116 |
|
|
goto end; |
117 |
|
|
|
118 |
|
|
ret = strm->total_out; |
119 |
|
|
|
120 |
|
|
end: |
121 |
|
|
deflateEnd(strm); |
122 |
|
|
free(strm); |
123 |
|
|
return ret; |
124 |
|
|
} |
125 |
|
|
|
126 |
|
|
|
127 |
|
|
static int |
128 |
|
|
compress_gzip_file(FILE *in, FILE *out) |
129 |
|
|
{ |
130 |
|
|
gzFile gzf; |
131 |
|
|
char ibuf[GZIP_BUFFER_SIZE]; |
132 |
|
|
int r, w; |
133 |
|
|
int ret = 0; |
134 |
|
|
|
135 |
|
|
if (in == NULL || out == NULL) |
136 |
|
|
return (0); |
137 |
|
|
|
138 |
|
|
gzf = gzdopen(fileno(out), "wb"); |
139 |
|
|
if (gzf == NULL) |
140 |
|
|
return (0); |
141 |
|
|
|
142 |
|
|
while ((r = fread(ibuf, 1, GZIP_BUFFER_SIZE, in)) != 0) { |
143 |
|
|
if ((w = gzwrite(gzf, ibuf, r)) != r) |
144 |
|
|
goto end; |
145 |
|
|
} |
146 |
|
|
if (!feof(in)) |
147 |
|
|
goto end; |
148 |
|
|
|
149 |
|
|
ret = 1; |
150 |
|
|
|
151 |
|
|
end: |
152 |
|
|
gzclose(gzf); |
153 |
|
|
return (ret); |
154 |
|
|
} |
155 |
|
|
|
156 |
|
|
|
157 |
|
|
static int |
158 |
|
|
uncompress_gzip_file(FILE *in, FILE *out) |
159 |
|
|
{ |
160 |
|
|
gzFile gzf; |
161 |
|
|
char obuf[GZIP_BUFFER_SIZE]; |
162 |
|
|
int r, w; |
163 |
|
|
int ret = 0; |
164 |
|
|
|
165 |
|
|
if (in == NULL || out == NULL) |
166 |
|
|
return (0); |
167 |
|
|
|
168 |
|
|
gzf = gzdopen(fileno(in), "r"); |
169 |
|
|
if (gzf == NULL) |
170 |
|
|
return (0); |
171 |
|
|
|
172 |
|
|
while ((r = gzread(gzf, obuf, sizeof(obuf))) > 0) { |
173 |
|
|
if ((w = fwrite(obuf, r, 1, out)) != 1) |
174 |
|
|
goto end; |
175 |
|
|
} |
176 |
|
|
if (!gzeof(gzf)) |
177 |
|
|
goto end; |
178 |
|
|
|
179 |
|
|
ret = 1; |
180 |
|
|
|
181 |
|
|
end: |
182 |
|
|
gzclose(gzf); |
183 |
|
|
return (ret); |
184 |
|
|
} |