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