Line data Source code
1 : /* compress.c - compress filter
2 : * Copyright (C) 1998, 1999, 2000, 2001, 2002,
3 : * 2003, 2006, 2010 Free Software Foundation, Inc.
4 : *
5 : * This file is part of GnuPG.
6 : *
7 : * GnuPG is free software; you can redistribute it and/or modify
8 : * it under the terms of the GNU General Public License as published by
9 : * the Free Software Foundation; either version 3 of the License, or
10 : * (at your option) any later version.
11 : *
12 : * GnuPG is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : * GNU General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU General Public License
18 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : /* Note that the code in compress-bz2.c is nearly identical to the
22 : code here, so if you fix a bug here, look there to see if a
23 : matching bug needs to be fixed. I tried to have one set of
24 : functions that could do ZIP, ZLIB, and BZIP2, but it became
25 : dangerously unreadable with #ifdefs and if(algo) -dshaw */
26 :
27 : #include <config.h>
28 : #include <stdio.h>
29 : #include <stdlib.h>
30 : #include <string.h>
31 : #include <unistd.h>
32 : #include <assert.h>
33 : #include <errno.h>
34 : #ifdef HAVE_ZIP
35 : # include <zlib.h>
36 : # if defined(__riscos__) && defined(USE_ZLIBRISCOS)
37 : # include "zlib-riscos.h"
38 : # endif
39 : #endif
40 :
41 : #include "gpg.h"
42 : #include "util.h"
43 : #include "packet.h"
44 : #include "filter.h"
45 : #include "main.h"
46 : #include "options.h"
47 :
48 :
49 : #ifdef __riscos__
50 : #define BYTEF_CAST(a) ((Bytef *)(a))
51 : #else
52 : #define BYTEF_CAST(a) (a)
53 : #endif
54 :
55 :
56 :
57 : int compress_filter_bz2( void *opaque, int control,
58 : IOBUF a, byte *buf, size_t *ret_len);
59 :
60 : #ifdef HAVE_ZIP
61 : static void
62 510 : init_compress( compress_filter_context_t *zfx, z_stream *zs )
63 : {
64 : int rc;
65 : int level;
66 :
67 : #if defined(__riscos__) && defined(USE_ZLIBRISCOS)
68 : static int zlib_initialized = 0;
69 :
70 : if (!zlib_initialized)
71 : zlib_initialized = riscos_load_module("ZLib", zlib_path, 1);
72 : #endif
73 :
74 510 : if( opt.compress_level >= 1 && opt.compress_level <= 9 )
75 0 : level = opt.compress_level;
76 510 : else if( opt.compress_level == -1 )
77 510 : level = Z_DEFAULT_COMPRESSION;
78 : else {
79 0 : log_error("invalid compression level; using default level\n");
80 0 : level = Z_DEFAULT_COMPRESSION;
81 : }
82 :
83 1020 : if( (rc = zfx->algo == 1? deflateInit2( zs, level, Z_DEFLATED,
84 : -13, 8, Z_DEFAULT_STRATEGY)
85 510 : : deflateInit( zs, level )
86 : ) != Z_OK ) {
87 0 : log_fatal("zlib problem: %s\n", zs->msg? zs->msg :
88 0 : rc == Z_MEM_ERROR ? "out of core" :
89 0 : rc == Z_VERSION_ERROR ? "invalid lib version" :
90 : "unknown error" );
91 : }
92 :
93 510 : zfx->outbufsize = 8192;
94 510 : zfx->outbuf = xmalloc( zfx->outbufsize );
95 510 : }
96 :
97 : static int
98 2124 : do_compress( compress_filter_context_t *zfx, z_stream *zs, int flush, IOBUF a )
99 : {
100 : int rc;
101 : int zrc;
102 : unsigned n;
103 :
104 : do {
105 2124 : zs->next_out = BYTEF_CAST (zfx->outbuf);
106 2124 : zs->avail_out = zfx->outbufsize;
107 2124 : if( DBG_FILTER )
108 0 : log_debug("enter deflate: avail_in=%u, avail_out=%u, flush=%d\n",
109 : (unsigned)zs->avail_in, (unsigned)zs->avail_out, flush );
110 2124 : zrc = deflate( zs, flush );
111 2124 : if( zrc == Z_STREAM_END && flush == Z_FINISH )
112 : ;
113 1614 : else if( zrc != Z_OK ) {
114 0 : if( zs->msg )
115 0 : log_fatal("zlib deflate problem: %s\n", zs->msg );
116 : else
117 0 : log_fatal("zlib deflate problem: rc=%d\n", zrc );
118 : }
119 2124 : n = zfx->outbufsize - zs->avail_out;
120 2124 : if( DBG_FILTER )
121 0 : log_debug("leave deflate: "
122 : "avail_in=%u, avail_out=%u, n=%u, zrc=%d\n",
123 : (unsigned)zs->avail_in, (unsigned)zs->avail_out,
124 : (unsigned)n, zrc );
125 :
126 2124 : if( (rc=iobuf_write( a, zfx->outbuf, n )) ) {
127 0 : log_debug("deflate: iobuf_write failed\n");
128 0 : return rc;
129 : }
130 2124 : } while( zs->avail_in || (flush == Z_FINISH && zrc != Z_STREAM_END) );
131 1714 : return 0;
132 : }
133 :
134 : static void
135 539 : init_uncompress( compress_filter_context_t *zfx, z_stream *zs )
136 : {
137 : int rc;
138 :
139 : /****************
140 : * PGP uses a windowsize of 13 bits. Using a negative value for
141 : * it forces zlib not to expect a zlib header. This is a
142 : * undocumented feature Peter Gutmann told me about.
143 : *
144 : * We must use 15 bits for the inflator because CryptoEx uses 15
145 : * bits thus the output would get scrambled w/o error indication
146 : * if we would use 13 bits. For the uncompressing this does not
147 : * matter at all.
148 : */
149 1078 : if( (rc = zfx->algo == 1? inflateInit2( zs, -15)
150 539 : : inflateInit( zs )) != Z_OK ) {
151 0 : log_fatal("zlib problem: %s\n", zs->msg? zs->msg :
152 0 : rc == Z_MEM_ERROR ? "out of core" :
153 0 : rc == Z_VERSION_ERROR ? "invalid lib version" :
154 : "unknown error" );
155 : }
156 :
157 539 : zfx->inbufsize = 2048;
158 539 : zfx->inbuf = xmalloc( zfx->inbufsize );
159 539 : zs->avail_in = 0;
160 539 : }
161 :
162 : static int
163 1254 : do_uncompress( compress_filter_context_t *zfx, z_stream *zs,
164 : IOBUF a, size_t *ret_len )
165 : {
166 : int zrc;
167 1254 : int rc = 0;
168 1254 : int leave = 0;
169 : size_t n;
170 : int nread, count;
171 1254 : int refill = !zs->avail_in;
172 :
173 1254 : if( DBG_FILTER )
174 0 : log_debug("begin inflate: avail_in=%u, avail_out=%u, inbuf=%u\n",
175 : (unsigned)zs->avail_in, (unsigned)zs->avail_out,
176 : (unsigned)zfx->inbufsize );
177 : do {
178 4317 : if( zs->avail_in < zfx->inbufsize && refill ) {
179 3602 : n = zs->avail_in;
180 3602 : if( !n )
181 3602 : zs->next_in = BYTEF_CAST (zfx->inbuf);
182 3602 : count = zfx->inbufsize - n;
183 3602 : nread = iobuf_read( a, zfx->inbuf + n, count );
184 3602 : if( nread == -1 ) nread = 0;
185 3602 : n += nread;
186 : /* Algo 1 has no zlib header which requires us to to give
187 : * inflate an extra dummy byte to read. To be on the safe
188 : * side we allow for up to 4 ff bytes. */
189 3602 : if( nread < count && zfx->algo == 1 && zfx->algo1hack < 4) {
190 381 : *(zfx->inbuf + n) = 0xFF;
191 381 : zfx->algo1hack++;
192 381 : n++;
193 381 : leave = 1;
194 : }
195 3602 : zs->avail_in = n;
196 : }
197 4317 : refill = 1;
198 4317 : if( DBG_FILTER )
199 0 : log_debug("enter inflate: avail_in=%u, avail_out=%u\n",
200 : (unsigned)zs->avail_in, (unsigned)zs->avail_out);
201 4317 : zrc = inflate ( zs, Z_SYNC_FLUSH );
202 4317 : if( DBG_FILTER )
203 0 : log_debug("leave inflate: avail_in=%u, avail_out=%u, zrc=%d\n",
204 : (unsigned)zs->avail_in, (unsigned)zs->avail_out, zrc);
205 4317 : if( zrc == Z_STREAM_END )
206 539 : rc = -1; /* eof */
207 3778 : else if( zrc != Z_OK && zrc != Z_BUF_ERROR ) {
208 0 : if( zs->msg )
209 0 : log_fatal("zlib inflate problem: %s\n", zs->msg );
210 : else
211 0 : log_fatal("zlib inflate problem: rc=%d\n", zrc );
212 : }
213 7919 : } while (zs->avail_out && zrc != Z_STREAM_END && zrc != Z_BUF_ERROR
214 7380 : && !leave);
215 :
216 1254 : *ret_len = zfx->outbufsize - zs->avail_out;
217 1254 : if( DBG_FILTER )
218 0 : log_debug("do_uncompress: returning %u bytes (%u ignored)\n",
219 0 : (unsigned int)*ret_len, (unsigned int)zs->avail_in );
220 1254 : return rc;
221 : }
222 :
223 : static int
224 4556 : compress_filter( void *opaque, int control,
225 : IOBUF a, byte *buf, size_t *ret_len)
226 : {
227 4556 : size_t size = *ret_len;
228 4556 : compress_filter_context_t *zfx = opaque;
229 4556 : z_stream *zs = zfx->opaque;
230 4556 : int rc=0;
231 :
232 4556 : if( control == IOBUFCTRL_UNDERFLOW ) {
233 1254 : if( !zfx->status ) {
234 539 : zs = zfx->opaque = xmalloc_clear( sizeof *zs );
235 539 : init_uncompress( zfx, zs );
236 539 : zfx->status = 1;
237 : }
238 :
239 1254 : zs->next_out = BYTEF_CAST (buf);
240 1254 : zs->avail_out = size;
241 1254 : zfx->outbufsize = size; /* needed only for calculation */
242 1254 : rc = do_uncompress( zfx, zs, a, ret_len );
243 : }
244 3302 : else if( control == IOBUFCTRL_FLUSH ) {
245 1204 : if( !zfx->status ) {
246 : PACKET pkt;
247 : PKT_compressed cd;
248 510 : if(zfx->algo != COMPRESS_ALGO_ZIP
249 143 : && zfx->algo != COMPRESS_ALGO_ZLIB)
250 0 : BUG();
251 510 : memset( &cd, 0, sizeof cd );
252 510 : cd.len = 0;
253 510 : cd.algorithm = zfx->algo;
254 : /* Fixme: We should force a new CTB here:
255 : cd.new_ctb = zfx->new_ctb;
256 : */
257 510 : init_packet( &pkt );
258 510 : pkt.pkttype = PKT_COMPRESSED;
259 510 : pkt.pkt.compressed = &cd;
260 510 : if( build_packet( a, &pkt ))
261 0 : log_bug("build_packet(PKT_COMPRESSED) failed\n");
262 510 : zs = zfx->opaque = xmalloc_clear( sizeof *zs );
263 510 : init_compress( zfx, zs );
264 510 : zfx->status = 2;
265 : }
266 :
267 1204 : zs->next_in = BYTEF_CAST (buf);
268 1204 : zs->avail_in = size;
269 1204 : rc = do_compress( zfx, zs, Z_NO_FLUSH, a );
270 : }
271 2098 : else if( control == IOBUFCTRL_FREE ) {
272 1049 : if( zfx->status == 1 ) {
273 539 : inflateEnd(zs);
274 539 : xfree(zs);
275 539 : zfx->opaque = NULL;
276 539 : xfree(zfx->outbuf); zfx->outbuf = NULL;
277 : }
278 510 : else if( zfx->status == 2 ) {
279 510 : zs->next_in = BYTEF_CAST (buf);
280 510 : zs->avail_in = 0;
281 510 : do_compress( zfx, zs, Z_FINISH, a );
282 510 : deflateEnd(zs);
283 510 : xfree(zs);
284 510 : zfx->opaque = NULL;
285 510 : xfree(zfx->outbuf); zfx->outbuf = NULL;
286 : }
287 1049 : if (zfx->release)
288 539 : zfx->release (zfx);
289 : }
290 1049 : else if( control == IOBUFCTRL_DESC )
291 0 : *(char**)buf = "compress_filter";
292 4556 : return rc;
293 : }
294 : #endif /*HAVE_ZIP*/
295 :
296 : static void
297 540 : release_context (compress_filter_context_t *ctx)
298 : {
299 540 : xfree (ctx);
300 540 : }
301 :
302 : /****************
303 : * Handle a compressed packet
304 : */
305 : int
306 540 : handle_compressed (ctrl_t ctrl, void *procctx, PKT_compressed *cd,
307 : int (*callback)(IOBUF, void *), void *passthru )
308 : {
309 : compress_filter_context_t *cfx;
310 : int rc;
311 :
312 540 : if(check_compress_algo(cd->algorithm))
313 0 : return GPG_ERR_COMPR_ALGO;
314 540 : cfx = xmalloc_clear (sizeof *cfx);
315 540 : cfx->release = release_context;
316 540 : cfx->algo = cd->algorithm;
317 540 : push_compress_filter(cd->buf,cfx,cd->algorithm);
318 540 : if( callback )
319 10 : rc = callback(cd->buf, passthru );
320 : else
321 530 : rc = proc_packets (ctrl,procctx, cd->buf);
322 540 : cd->buf = NULL;
323 540 : return rc;
324 : }
325 :
326 : void
327 1050 : push_compress_filter(IOBUF out,compress_filter_context_t *zfx,int algo)
328 : {
329 1050 : push_compress_filter2(out,zfx,algo,0);
330 1050 : }
331 :
332 : void
333 1050 : push_compress_filter2(IOBUF out,compress_filter_context_t *zfx,
334 : int algo,int rel)
335 : {
336 1050 : if(algo>=0)
337 1050 : zfx->algo=algo;
338 : else
339 0 : zfx->algo=DEFAULT_COMPRESS_ALGO;
340 :
341 1050 : switch(zfx->algo)
342 : {
343 : case COMPRESS_ALGO_NONE:
344 0 : break;
345 :
346 : #ifdef HAVE_ZIP
347 : case COMPRESS_ALGO_ZIP:
348 : case COMPRESS_ALGO_ZLIB:
349 1049 : iobuf_push_filter2(out,compress_filter,zfx,rel);
350 1049 : break;
351 : #endif
352 :
353 : #ifdef HAVE_BZIP2
354 : case COMPRESS_ALGO_BZIP2:
355 1 : iobuf_push_filter2(out,compress_filter_bz2,zfx,rel);
356 1 : break;
357 : #endif
358 :
359 : default:
360 0 : BUG();
361 : }
362 1050 : }
|