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 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 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 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 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