1 /* $OpenBSD: compress_gzip.c,v 1.11 2021/01/23 16:11:11 rob 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; 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 (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; 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 (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 } 185