diff --git a/g10/ChangeLog b/g10/ChangeLog index 5ebaaaad5..d8eb0670b 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,30 @@ +2003-10-30 David Shaw + + * misc.c (compress_algo_to_string, check_compress_algo): Add + bzip2. + + * g10.c (main): Add read-only warning. + + * compress.c (compress_filter): Make static to help force the use + of push_compress_filter. Remove default algorithm setting since + that is done in push_compress_filter now. + + * main.h: Use named algorithm. + + * filter.h, compress.c (push_compress_filter, + push_compress_filter2): New. Figure out which is the appropriate + compression filter to use, and push it into place. + + * compress.c (handle_compressed), encode.c (encode_simple, + encode_crypt), sign.c (sign_file, sign_symencrypt_file), import.c + (read_block), export.c (do_export): Use push_compress_filter + instead of pushing the compression filter ourselves. + + * compress-bz2.c: New. Bzlib versions of the compression filter + routines. + + * Makefile.am: Include compress-bz2.c if bz2lib is available. + 2003-10-26 David Shaw * mainproc.c (proc_symkey_enc, proc_encrypted): Keep a count of diff --git a/g10/Makefile.am b/g10/Makefile.am index 04de3dacd..6bfbea3f6 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -31,10 +31,17 @@ needed_libs = ../cipher/libcipher.a ../mpi/libmpi.a ../util/libutil.a #noinst_PROGRAMS = gpgd bin_PROGRAMS = gpg gpgv +if ENABLE_BZIP2_SUPPORT +bzip2_source = compress-bz2.c +else +bzip2_source = +endif + common_source = \ global.h \ build-packet.c \ compress.c \ + $(bzip2_source) \ filter.h \ free-packet.c \ getkey.c \ diff --git a/g10/compress-bz2.c b/g10/compress-bz2.c new file mode 100644 index 000000000..a8497c154 --- /dev/null +++ b/g10/compress-bz2.c @@ -0,0 +1,242 @@ +/* compress.c - bzip2 compress filter + * Copyright (C) 2003 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include +#include + +#include "util.h" +#include "memory.h" +#include "packet.h" +#include "filter.h" +#include "main.h" +#include "options.h" + +/* Note that the code in compress.c is nearly identical to the code + here, so if you fix a bug here, look there to see if the matching + bug needs to be fixed. I tried to have one set of functions that + could do ZIP, ZLIB, and BZIP2, but it became dangerously unreadable + with #ifdefs and if(algo) -dshaw */ + +static void +init_compress( compress_filter_context_t *zfx, bz_stream *bzs ) +{ + int rc; + int level; + + if( opt.compress >= 0 && opt.compress <= 9 ) + level = opt.compress; + else if( opt.compress == -1 ) + level = 6; /* no particular reason, but it seems reasonable */ + else if( opt.compress == 10 ) /* remove this ! */ + level = 0; + else + { + log_error("invalid compression level; using default level\n"); + level = 6; + } + + if((rc=BZ2_bzCompressInit(bzs,level,0,0))!=BZ_OK) + log_fatal("bz2lib problem: %d\n",rc); + + zfx->outbufsize = 8192; + zfx->outbuf = m_alloc( zfx->outbufsize ); +} + +static int +do_compress(compress_filter_context_t *zfx, bz_stream *bzs, int flush, IOBUF a) +{ + int zrc; + unsigned n; + + do + { + bzs->next_out = zfx->outbuf; + bzs->avail_out = zfx->outbufsize; + if( DBG_FILTER ) + log_debug("enter bzCompress: avail_in=%u, avail_out=%u, flush=%d\n", + (unsigned)bzs->avail_in, (unsigned)bzs->avail_out, flush ); + zrc = BZ2_bzCompress( bzs, flush ); + if( zrc == BZ_STREAM_END && flush == BZ_FINISH ) + ; + else if( zrc != BZ_RUN_OK && zrc != BZ_FINISH_OK ) + log_fatal("bz2lib deflate problem: rc=%d\n", zrc ); + + n = zfx->outbufsize - bzs->avail_out; + if( DBG_FILTER ) + log_debug("leave bzCompress:" + " avail_in=%u, avail_out=%u, n=%u, zrc=%d\n", + (unsigned)bzs->avail_in, (unsigned)bzs->avail_out, + (unsigned)n, zrc ); + + if( iobuf_write( a, zfx->outbuf, n ) ) + { + log_debug("bzCompress: iobuf_write failed\n"); + return G10ERR_WRITE_FILE; + } + } + while( bzs->avail_in || (flush == BZ_FINISH && zrc != BZ_STREAM_END) ); + + return 0; +} + +static void +init_uncompress( compress_filter_context_t *zfx, bz_stream *bzs ) +{ + int rc; + + if((rc=BZ2_bzDecompressInit(bzs,0,0))!=BZ_OK) + log_fatal("bz2lib problem: %d\n",rc); + + zfx->inbufsize = 2048; + zfx->inbuf = m_alloc( zfx->inbufsize ); + bzs->avail_in = 0; +} + +static int +do_uncompress( compress_filter_context_t *zfx, bz_stream *bzs, + IOBUF a, size_t *ret_len ) +{ + int zrc; + int rc=0; + size_t n; + int nread, count; + int refill = !bzs->avail_in; + + if( DBG_FILTER ) + log_debug("begin bzDecompress: avail_in=%u, avail_out=%u, inbuf=%u\n", + (unsigned)bzs->avail_in, (unsigned)bzs->avail_out, + (unsigned)zfx->inbufsize ); + do + { + if( bzs->avail_in < zfx->inbufsize && refill ) + { + n = bzs->avail_in; + if( !n ) + bzs->next_in = zfx->inbuf; + count = zfx->inbufsize - n; + nread = iobuf_read( a, zfx->inbuf + n, count ); + if( nread == -1 ) nread = 0; + n += nread; + bzs->avail_in = n; + } + + refill = 1; + + if( DBG_FILTER ) + log_debug("enter bzDecompress: avail_in=%u, avail_out=%u\n", + (unsigned)bzs->avail_in, (unsigned)bzs->avail_out); + + zrc=BZ2_bzDecompress(bzs); + if( DBG_FILTER ) + log_debug("leave bzDecompress: avail_in=%u, avail_out=%u, zrc=%d\n", + (unsigned)bzs->avail_in, (unsigned)bzs->avail_out, zrc); + if( zrc == BZ_STREAM_END ) + rc = -1; /* eof */ + else if( zrc != BZ_OK && zrc != BZ_PARAM_ERROR ) + log_fatal("bz2lib inflate problem: rc=%d\n", zrc ); + } + while( bzs->avail_out && zrc != BZ_STREAM_END && zrc != BZ_PARAM_ERROR ); + + /* I'm not completely happy with the two uses of BZ_PARAM_ERROR + here. The corresponding zlib function is Z_BUF_ERROR, which + covers a narrower scope than BZ_PARAM_ERROR. -dshaw */ + + *ret_len = zfx->outbufsize - bzs->avail_out; + if( DBG_FILTER ) + log_debug("do_uncompress: returning %u bytes\n", (unsigned)*ret_len ); + return rc; +} + +int +compress_filter_bz2( void *opaque, int control, + IOBUF a, byte *buf, size_t *ret_len) +{ + size_t size = *ret_len; + compress_filter_context_t *zfx = opaque; + bz_stream *bzs = zfx->opaque; + int rc=0; + + if( control == IOBUFCTRL_UNDERFLOW ) + { + if( !zfx->status ) + { + bzs = zfx->opaque = m_alloc_clear( sizeof *bzs ); + init_uncompress( zfx, bzs ); + zfx->status = 1; + } + + bzs->next_out = buf; + bzs->avail_out = size; + zfx->outbufsize = size; /* needed only for calculation */ + rc = do_uncompress( zfx, bzs, a, ret_len ); + } + else if( control == IOBUFCTRL_FLUSH ) + { + if( !zfx->status ) + { + PACKET pkt; + PKT_compressed cd; + + if( zfx->algo != COMPRESS_ALGO_BZIP2 ) + BUG(); + memset( &cd, 0, sizeof cd ); + cd.len = 0; + cd.algorithm = zfx->algo; + init_packet( &pkt ); + pkt.pkttype = PKT_COMPRESSED; + pkt.pkt.compressed = &cd; + if( build_packet( a, &pkt )) + log_bug("build_packet(PKT_COMPRESSED) failed\n"); + bzs = zfx->opaque = m_alloc_clear( sizeof *bzs ); + init_compress( zfx, bzs ); + zfx->status = 2; + } + + bzs->next_in = buf; + bzs->avail_in = size; + rc = do_compress( zfx, bzs, BZ_RUN, a ); + } + else if( control == IOBUFCTRL_FREE ) + { + if( zfx->status == 1 ) + { + BZ2_bzDecompressEnd(bzs); + m_free(bzs); + zfx->opaque = NULL; + m_free(zfx->outbuf); zfx->outbuf = NULL; + } + else if( zfx->status == 2 ) + { + bzs->next_in = buf; + bzs->avail_in = 0; + do_compress( zfx, bzs, BZ_FINISH, a ); + BZ2_bzCompressEnd(bzs); + m_free(bzs); + zfx->opaque = NULL; + m_free(zfx->outbuf); zfx->outbuf = NULL; + } + if (zfx->release) + zfx->release (zfx); + } + else if( control == IOBUFCTRL_DESC ) + *(char**)buf = "compress_filter"; + return rc; +} diff --git a/g10/compress.c b/g10/compress.c index 8e535f064..c6a61ebe5 100644 --- a/g10/compress.c +++ b/g10/compress.c @@ -1,5 +1,6 @@ /* compress.c - compress filter - * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2002, + * 2003 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -18,6 +19,12 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ +/* Note that the code in compress-bz2.c is nearly identical to the + code here, so if you fix a bug here, look there to see if the + matching bug needs to be fixed. I tried to have one set of + functions that could do ZIP, ZLIB, and BZIP2, but it became + dangerously unreadable with #ifdefs and if(algo) -dshaw */ + #include #include #include @@ -34,6 +41,8 @@ #include "main.h" #include "options.h" +int compress_filter_bz2( void *opaque, int control, + IOBUF a, byte *buf, size_t *ret_len); static void init_compress( compress_filter_context_t *zfx, z_stream *zs ) @@ -199,7 +208,7 @@ do_uncompress( compress_filter_context_t *zfx, z_stream *zs, return rc; } -int +static int compress_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { @@ -228,10 +237,8 @@ compress_filter( void *opaque, int control, if( !zfx->status ) { PACKET pkt; PKT_compressed cd; - - if( !zfx->algo ) - zfx->algo = DEFAULT_COMPRESS_ALGO; - if( zfx->algo != 1 && zfx->algo != 2 ) + if(zfx->algo != COMPRESS_ALGO_ZIP + && zfx->algo != COMPRESS_ALGO_ZLIB) BUG(); memset( &cd, 0, sizeof cd ); cd.len = 0; @@ -299,12 +306,12 @@ handle_compressed( void *procctx, PKT_compressed *cd, compress_filter_context_t *cfx; int rc; - if( cd->algorithm < 1 || cd->algorithm > 2 ) - return G10ERR_COMPR_ALGO; + if(check_compress_algo(cd->algorithm)) + return G10ERR_COMPR_ALGO; cfx = m_alloc_clear (sizeof *cfx); - cfx->algo = cd->algorithm; cfx->release = release_context; - iobuf_push_filter( cd->buf, compress_filter, cfx ); + cfx->algo = cd->algorithm; + push_compress_filter(cd->buf,cfx,cd->algorithm); if( callback ) rc = callback(cd->buf, passthru ); else @@ -313,3 +320,35 @@ handle_compressed( void *procctx, PKT_compressed *cd, return rc; } +void +push_compress_filter(IOBUF out,compress_filter_context_t *zfx,int algo) +{ + push_compress_filter2(out,zfx,algo,0); +} + +void +push_compress_filter2(IOBUF out,compress_filter_context_t *zfx, + int algo,int rel) +{ + if(algo>0) + zfx->algo=algo; + else + zfx->algo=DEFAULT_COMPRESS_ALGO; + + switch(zfx->algo) + { + case COMPRESS_ALGO_ZIP: + case COMPRESS_ALGO_ZLIB: + iobuf_push_filter2(out,compress_filter,zfx,rel); + break; + +#ifdef HAVE_BZIP2 + case COMPRESS_ALGO_BZIP2: + iobuf_push_filter2(out,compress_filter_bz2,zfx,rel); + break; +#endif + + default: + BUG(); + } +} diff --git a/g10/encode.c b/g10/encode.c index 0fb9c5cd8..ad93a3aaf 100644 --- a/g10/encode.c +++ b/g10/encode.c @@ -333,10 +333,7 @@ encode_simple( const char *filename, int mode, int use_seskey ) { if (cfx.dek && cfx.dek->use_mdc) zfx.new_ctb = 1; - zfx.algo=opt.def_compress_algo; - if(zfx.algo==-1) - zfx.algo=DEFAULT_COMPRESS_ALGO; - iobuf_push_filter( out, compress_filter, &zfx ); + push_compress_filter(out,&zfx,opt.def_compress_algo); } /* do the work */ @@ -578,8 +575,7 @@ encode_crypt( const char *filename, STRLIST remusr ) { if (cfx.dek && cfx.dek->use_mdc) zfx.new_ctb = 1; - zfx.algo = compr_algo; - iobuf_push_filter( out, compress_filter, &zfx ); + push_compress_filter(out,&zfx,compr_algo); } } diff --git a/g10/export.c b/g10/export.c index b4c87d4dc..44edf7925 100644 --- a/g10/export.c +++ b/g10/export.c @@ -112,7 +112,7 @@ do_export( STRLIST users, int secret, unsigned int options ) iobuf_push_filter( out, armor_filter, &afx ); } if( opt.compress_keys && opt.compress ) - iobuf_push_filter( out, compress_filter, &zfx ); + push_compress_filter(out,&zfx,opt.def_compress_algo); rc = do_export_stream( out, users, secret, options, &any ); if( rc || !any ) diff --git a/g10/filter.h b/g10/filter.h index 9f235fd6b..fed70c25c 100644 --- a/g10/filter.h +++ b/g10/filter.h @@ -132,8 +132,9 @@ void unarmor_pump_release (UnarmorPump x); int unarmor_pump (UnarmorPump x, int c); /*-- compress.c --*/ -int compress_filter( void *opaque, int control, - IOBUF chain, byte *buf, size_t *ret_len); +void push_compress_filter(IOBUF out,compress_filter_context_t *zfx,int algo); +void push_compress_filter2(IOBUF out,compress_filter_context_t *zfx, + int algo,int rel); /*-- cipher.c --*/ int cipher_filter( void *opaque, int control, diff --git a/g10/g10.c b/g10/g10.c index 71f3a8414..f1318529f 100644 --- a/g10/g10.c +++ b/g10/g10.c @@ -1920,6 +1920,11 @@ main( int argc, char **argv ) if( check_digest_algo(opt.s2k_digest_algo) ) log_error(_("selected digest algorithm is invalid\n")); } +#ifdef HAVE_BZIP2 + if(opt.def_compress_algo==3) + log_info(_("compress algorithm `%s' is read-only in this release\n"), + "BZIP2"); +#endif if( opt.def_compress_algo < -1 || opt.def_compress_algo > 2 ) log_error(_("compress algorithm must be in range %d..%d\n"), 0, 2); if( opt.completes_needed < 1 ) diff --git a/g10/import.c b/g10/import.c index 23de38295..6be0dd68e 100644 --- a/g10/import.c +++ b/g10/import.c @@ -351,17 +351,17 @@ read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root ) /* make a linked list of all packets */ switch( pkt->pkttype ) { case PKT_COMPRESSED: - if( pkt->pkt.compressed->algorithm < 1 - || pkt->pkt.compressed->algorithm > 2 ) { + if(check_compress_algo(pkt->pkt.compressed->algorithm)) + { rc = G10ERR_COMPR_ALGO; goto ready; - } - { + } + else + { compress_filter_context_t *cfx = m_alloc_clear( sizeof *cfx ); - cfx->algo = pkt->pkt.compressed->algorithm; pkt->pkt.compressed->buf = NULL; - iobuf_push_filter2( a, compress_filter, cfx, 1 ); - } + push_compress_filter2(a,cfx,pkt->pkt.compressed->algorithm,1); + } free_packet( pkt ); init_packet(pkt); break; diff --git a/g10/main.h b/g10/main.h index d48798921..a51a0d7e8 100644 --- a/g10/main.h +++ b/g10/main.h @@ -30,7 +30,7 @@ (i.e. uncompressed) rather than 1 (zip). */ #define DEFAULT_CIPHER_ALGO CIPHER_ALGO_CAST5 #define DEFAULT_DIGEST_ALGO DIGEST_ALGO_SHA1 -#define DEFAULT_COMPRESS_ALGO 1 +#define DEFAULT_COMPRESS_ALGO COMPRESS_ALGO_ZIP typedef struct { int header_okay; diff --git a/g10/misc.c b/g10/misc.c index 67ec5cc2b..eadfe7ef9 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -546,17 +546,23 @@ compress_algo_to_string(int algo) switch(algo) { - case 0: + case COMPRESS_ALGO_NONE: s="Uncompressed"; break; - case 1: + case COMPRESS_ALGO_ZIP: s="ZIP"; break; - case 2: + case COMPRESS_ALGO_ZLIB: s="ZLIB"; break; + +#ifdef HAVE_BZIP2 + case COMPRESS_ALGO_BZIP2: + s="BZIP2"; + break; +#endif } return s; @@ -565,8 +571,13 @@ compress_algo_to_string(int algo) int check_compress_algo(int algo) { +#ifdef HAVE_BZIP2 + if(algo>=0 && algo<=3) + return 0; +#else if(algo>=0 && algo<=2) return 0; +#endif return G10ERR_COMPR_ALGO; } diff --git a/g10/sign.c b/g10/sign.c index 06d1db100..017d6800c 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -773,10 +773,7 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr, /* algo 0 means no compression */ if( compr_algo ) - { - zfx.algo = compr_algo; - iobuf_push_filter( out, compress_filter, &zfx ); - } + push_compress_filter(out,&zfx,compr_algo); } /* Write the one-pass signature packets if needed */ @@ -1096,19 +1093,7 @@ sign_symencrypt_file (const char *fname, STRLIST locusr) /* Push the Zip filter */ if (opt.compress) - { - int compr_algo=opt.def_compress_algo; - - /* Default */ - if(compr_algo==-1) - compr_algo=DEFAULT_COMPRESS_ALGO; - - if (compr_algo) - { - zfx.algo = compr_algo; - iobuf_push_filter( out, compress_filter, &zfx ); - } - } + push_compress_filter(out,&zfx,opt.def_compress_algo); /* Write the one-pass signature packets */ /*(current filters: zip - encrypt - armor)*/