Jonathan Nieder | b0613ce | 2010-11-06 06:47:34 -0500 | [diff] [blame] | 1 | /* |
| 2 | * zlib wrappers to make sure we don't silently miss errors |
| 3 | * at init time. |
| 4 | */ |
Elijah Newren | d88dbaa | 2023-04-11 00:41:51 -0700 | [diff] [blame] | 5 | #include "git-compat-util.h" |
| 6 | #include "git-zlib.h" |
Jonathan Nieder | b0613ce | 2010-11-06 06:47:34 -0500 | [diff] [blame] | 7 | |
Junio C Hamano | 1a507fc | 2011-06-10 10:31:34 -0700 | [diff] [blame] | 8 | static const char *zerr_to_string(int status) |
| 9 | { |
| 10 | switch (status) { |
| 11 | case Z_MEM_ERROR: |
| 12 | return "out of memory"; |
| 13 | case Z_VERSION_ERROR: |
| 14 | return "wrong version"; |
| 15 | case Z_NEED_DICT: |
| 16 | return "needs dictionary"; |
| 17 | case Z_DATA_ERROR: |
| 18 | return "data stream error"; |
| 19 | case Z_STREAM_ERROR: |
| 20 | return "stream consistency error"; |
| 21 | default: |
| 22 | return "unknown error"; |
| 23 | } |
| 24 | } |
| 25 | |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 26 | /* |
| 27 | * avail_in and avail_out in zlib are counted in uInt, which typically |
| 28 | * limits the size of the buffer we can use to 4GB when interacting |
| 29 | * with zlib in a single call to inflate/deflate. |
| 30 | */ |
Junio C Hamano | e01503b | 2011-06-10 12:15:17 -0700 | [diff] [blame] | 31 | /* #define ZLIB_BUF_MAX ((uInt)-1) */ |
| 32 | #define ZLIB_BUF_MAX ((uInt) 1024 * 1024 * 1024) /* 1GB */ |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 33 | static inline uInt zlib_buf_cap(unsigned long len) |
Jonathan Nieder | b0613ce | 2010-11-06 06:47:34 -0500 | [diff] [blame] | 34 | { |
Junio C Hamano | e01503b | 2011-06-10 12:15:17 -0700 | [diff] [blame] | 35 | return (ZLIB_BUF_MAX < len) ? ZLIB_BUF_MAX : len; |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 36 | } |
Jonathan Nieder | b0613ce | 2010-11-06 06:47:34 -0500 | [diff] [blame] | 37 | |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 38 | static void zlib_pre_call(git_zstream *s) |
| 39 | { |
| 40 | s->z.next_in = s->next_in; |
| 41 | s->z.next_out = s->next_out; |
| 42 | s->z.total_in = s->total_in; |
| 43 | s->z.total_out = s->total_out; |
| 44 | s->z.avail_in = zlib_buf_cap(s->avail_in); |
| 45 | s->z.avail_out = zlib_buf_cap(s->avail_out); |
| 46 | } |
| 47 | |
| 48 | static void zlib_post_call(git_zstream *s) |
| 49 | { |
Junio C Hamano | e01503b | 2011-06-10 12:15:17 -0700 | [diff] [blame] | 50 | unsigned long bytes_consumed; |
| 51 | unsigned long bytes_produced; |
| 52 | |
| 53 | bytes_consumed = s->z.next_in - s->next_in; |
| 54 | bytes_produced = s->z.next_out - s->next_out; |
| 55 | if (s->z.total_out != s->total_out + bytes_produced) |
Johannes Schindelin | 033abf9 | 2018-05-02 11:38:39 +0200 | [diff] [blame] | 56 | BUG("total_out mismatch"); |
Junio C Hamano | e01503b | 2011-06-10 12:15:17 -0700 | [diff] [blame] | 57 | if (s->z.total_in != s->total_in + bytes_consumed) |
Johannes Schindelin | 033abf9 | 2018-05-02 11:38:39 +0200 | [diff] [blame] | 58 | BUG("total_in mismatch"); |
Junio C Hamano | e01503b | 2011-06-10 12:15:17 -0700 | [diff] [blame] | 59 | |
| 60 | s->total_out = s->z.total_out; |
| 61 | s->total_in = s->z.total_in; |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 62 | s->next_in = s->z.next_in; |
| 63 | s->next_out = s->z.next_out; |
Junio C Hamano | e01503b | 2011-06-10 12:15:17 -0700 | [diff] [blame] | 64 | s->avail_in -= bytes_consumed; |
| 65 | s->avail_out -= bytes_produced; |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 66 | } |
| 67 | |
| 68 | void git_inflate_init(git_zstream *strm) |
| 69 | { |
| 70 | int status; |
| 71 | |
| 72 | zlib_pre_call(strm); |
| 73 | status = inflateInit(&strm->z); |
| 74 | zlib_post_call(strm); |
Junio C Hamano | 1a507fc | 2011-06-10 10:31:34 -0700 | [diff] [blame] | 75 | if (status == Z_OK) |
Jonathan Nieder | b0613ce | 2010-11-06 06:47:34 -0500 | [diff] [blame] | 76 | return; |
Junio C Hamano | 1a507fc | 2011-06-10 10:31:34 -0700 | [diff] [blame] | 77 | die("inflateInit: %s (%s)", zerr_to_string(status), |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 78 | strm->z.msg ? strm->z.msg : "no message"); |
Jonathan Nieder | b0613ce | 2010-11-06 06:47:34 -0500 | [diff] [blame] | 79 | } |
| 80 | |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 81 | void git_inflate_init_gzip_only(git_zstream *strm) |
Junio C Hamano | 5e86c1f | 2011-06-10 10:45:29 -0700 | [diff] [blame] | 82 | { |
| 83 | /* |
| 84 | * Use default 15 bits, +16 is to accept only gzip and to |
| 85 | * yield Z_DATA_ERROR when fed zlib format. |
| 86 | */ |
| 87 | const int windowBits = 15 + 16; |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 88 | int status; |
Junio C Hamano | 5e86c1f | 2011-06-10 10:45:29 -0700 | [diff] [blame] | 89 | |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 90 | zlib_pre_call(strm); |
| 91 | status = inflateInit2(&strm->z, windowBits); |
| 92 | zlib_post_call(strm); |
Junio C Hamano | 5e86c1f | 2011-06-10 10:45:29 -0700 | [diff] [blame] | 93 | if (status == Z_OK) |
| 94 | return; |
| 95 | die("inflateInit2: %s (%s)", zerr_to_string(status), |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 96 | strm->z.msg ? strm->z.msg : "no message"); |
Junio C Hamano | 5e86c1f | 2011-06-10 10:45:29 -0700 | [diff] [blame] | 97 | } |
| 98 | |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 99 | void git_inflate_end(git_zstream *strm) |
Jonathan Nieder | b0613ce | 2010-11-06 06:47:34 -0500 | [diff] [blame] | 100 | { |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 101 | int status; |
Junio C Hamano | 1a507fc | 2011-06-10 10:31:34 -0700 | [diff] [blame] | 102 | |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 103 | zlib_pre_call(strm); |
| 104 | status = inflateEnd(&strm->z); |
| 105 | zlib_post_call(strm); |
Junio C Hamano | 1a507fc | 2011-06-10 10:31:34 -0700 | [diff] [blame] | 106 | if (status == Z_OK) |
| 107 | return; |
| 108 | error("inflateEnd: %s (%s)", zerr_to_string(status), |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 109 | strm->z.msg ? strm->z.msg : "no message"); |
Jonathan Nieder | b0613ce | 2010-11-06 06:47:34 -0500 | [diff] [blame] | 110 | } |
| 111 | |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 112 | int git_inflate(git_zstream *strm, int flush) |
Jonathan Nieder | b0613ce | 2010-11-06 06:47:34 -0500 | [diff] [blame] | 113 | { |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 114 | int status; |
Jonathan Nieder | b0613ce | 2010-11-06 06:47:34 -0500 | [diff] [blame] | 115 | |
Junio C Hamano | e01503b | 2011-06-10 12:15:17 -0700 | [diff] [blame] | 116 | for (;;) { |
| 117 | zlib_pre_call(strm); |
| 118 | /* Never say Z_FINISH unless we are feeding everything */ |
| 119 | status = inflate(&strm->z, |
| 120 | (strm->z.avail_in != strm->avail_in) |
| 121 | ? 0 : flush); |
| 122 | if (status == Z_MEM_ERROR) |
| 123 | die("inflate: out of memory"); |
| 124 | zlib_post_call(strm); |
| 125 | |
| 126 | /* |
| 127 | * Let zlib work another round, while we can still |
| 128 | * make progress. |
| 129 | */ |
| 130 | if ((strm->avail_out && !strm->z.avail_out) && |
| 131 | (status == Z_OK || status == Z_BUF_ERROR)) |
| 132 | continue; |
| 133 | break; |
| 134 | } |
| 135 | |
Junio C Hamano | 1a507fc | 2011-06-10 10:31:34 -0700 | [diff] [blame] | 136 | switch (status) { |
Jonathan Nieder | b0613ce | 2010-11-06 06:47:34 -0500 | [diff] [blame] | 137 | /* Z_BUF_ERROR: normal, needs more space in the output buffer */ |
| 138 | case Z_BUF_ERROR: |
| 139 | case Z_OK: |
| 140 | case Z_STREAM_END: |
Junio C Hamano | 1a507fc | 2011-06-10 10:31:34 -0700 | [diff] [blame] | 141 | return status; |
Junio C Hamano | 1a507fc | 2011-06-10 10:31:34 -0700 | [diff] [blame] | 142 | default: |
| 143 | break; |
Jonathan Nieder | b0613ce | 2010-11-06 06:47:34 -0500 | [diff] [blame] | 144 | } |
Junio C Hamano | 1a507fc | 2011-06-10 10:31:34 -0700 | [diff] [blame] | 145 | error("inflate: %s (%s)", zerr_to_string(status), |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 146 | strm->z.msg ? strm->z.msg : "no message"); |
Junio C Hamano | 1a507fc | 2011-06-10 10:31:34 -0700 | [diff] [blame] | 147 | return status; |
Jonathan Nieder | b0613ce | 2010-11-06 06:47:34 -0500 | [diff] [blame] | 148 | } |
Junio C Hamano | 55bb5c9 | 2011-06-10 10:55:10 -0700 | [diff] [blame] | 149 | |
Junio C Hamano | 225a6f1 | 2011-06-10 11:18:17 -0700 | [diff] [blame] | 150 | #if defined(NO_DEFLATE_BOUND) || ZLIB_VERNUM < 0x1200 |
| 151 | #define deflateBound(c,s) ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11) |
| 152 | #endif |
| 153 | |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 154 | unsigned long git_deflate_bound(git_zstream *strm, unsigned long size) |
Junio C Hamano | 225a6f1 | 2011-06-10 11:18:17 -0700 | [diff] [blame] | 155 | { |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 156 | return deflateBound(&strm->z, size); |
Junio C Hamano | 225a6f1 | 2011-06-10 11:18:17 -0700 | [diff] [blame] | 157 | } |
| 158 | |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 159 | void git_deflate_init(git_zstream *strm, int level) |
Junio C Hamano | 55bb5c9 | 2011-06-10 10:55:10 -0700 | [diff] [blame] | 160 | { |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 161 | int status; |
Junio C Hamano | 55bb5c9 | 2011-06-10 10:55:10 -0700 | [diff] [blame] | 162 | |
René Scharfe | 9a6f128 | 2015-03-05 23:49:46 +0100 | [diff] [blame] | 163 | memset(strm, 0, sizeof(*strm)); |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 164 | zlib_pre_call(strm); |
| 165 | status = deflateInit(&strm->z, level); |
| 166 | zlib_post_call(strm); |
Junio C Hamano | 55bb5c9 | 2011-06-10 10:55:10 -0700 | [diff] [blame] | 167 | if (status == Z_OK) |
| 168 | return; |
| 169 | die("deflateInit: %s (%s)", zerr_to_string(status), |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 170 | strm->z.msg ? strm->z.msg : "no message"); |
Junio C Hamano | 55bb5c9 | 2011-06-10 10:55:10 -0700 | [diff] [blame] | 171 | } |
| 172 | |
René Scharfe | c3c2e1a | 2013-03-15 23:21:51 +0100 | [diff] [blame] | 173 | static void do_git_deflate_init(git_zstream *strm, int level, int windowBits) |
Junio C Hamano | 55bb5c9 | 2011-06-10 10:55:10 -0700 | [diff] [blame] | 174 | { |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 175 | int status; |
| 176 | |
René Scharfe | 9a6f128 | 2015-03-05 23:49:46 +0100 | [diff] [blame] | 177 | memset(strm, 0, sizeof(*strm)); |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 178 | zlib_pre_call(strm); |
| 179 | status = deflateInit2(&strm->z, level, |
Junio C Hamano | 55bb5c9 | 2011-06-10 10:55:10 -0700 | [diff] [blame] | 180 | Z_DEFLATED, windowBits, |
| 181 | 8, Z_DEFAULT_STRATEGY); |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 182 | zlib_post_call(strm); |
Junio C Hamano | 55bb5c9 | 2011-06-10 10:55:10 -0700 | [diff] [blame] | 183 | if (status == Z_OK) |
| 184 | return; |
| 185 | die("deflateInit2: %s (%s)", zerr_to_string(status), |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 186 | strm->z.msg ? strm->z.msg : "no message"); |
Junio C Hamano | 55bb5c9 | 2011-06-10 10:55:10 -0700 | [diff] [blame] | 187 | } |
| 188 | |
René Scharfe | c3c2e1a | 2013-03-15 23:21:51 +0100 | [diff] [blame] | 189 | void git_deflate_init_gzip(git_zstream *strm, int level) |
| 190 | { |
| 191 | /* |
| 192 | * Use default 15 bits, +16 is to generate gzip header/trailer |
| 193 | * instead of the zlib wrapper. |
| 194 | */ |
Stefano Lattarini | 7f49036 | 2013-04-22 18:18:40 +0200 | [diff] [blame] | 195 | do_git_deflate_init(strm, level, 15 + 16); |
René Scharfe | c3c2e1a | 2013-03-15 23:21:51 +0100 | [diff] [blame] | 196 | } |
| 197 | |
| 198 | void git_deflate_init_raw(git_zstream *strm, int level) |
| 199 | { |
| 200 | /* |
| 201 | * Use default 15 bits, negate the value to get raw compressed |
| 202 | * data without zlib header and trailer. |
| 203 | */ |
Stefano Lattarini | 7f49036 | 2013-04-22 18:18:40 +0200 | [diff] [blame] | 204 | do_git_deflate_init(strm, level, -15); |
René Scharfe | c3c2e1a | 2013-03-15 23:21:51 +0100 | [diff] [blame] | 205 | } |
| 206 | |
Junio C Hamano | 568508e | 2011-10-28 14:48:40 -0700 | [diff] [blame] | 207 | int git_deflate_abort(git_zstream *strm) |
Junio C Hamano | 55bb5c9 | 2011-06-10 10:55:10 -0700 | [diff] [blame] | 208 | { |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 209 | int status; |
Junio C Hamano | 55bb5c9 | 2011-06-10 10:55:10 -0700 | [diff] [blame] | 210 | |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 211 | zlib_pre_call(strm); |
| 212 | status = deflateEnd(&strm->z); |
| 213 | zlib_post_call(strm); |
Junio C Hamano | 568508e | 2011-10-28 14:48:40 -0700 | [diff] [blame] | 214 | return status; |
| 215 | } |
| 216 | |
| 217 | void git_deflate_end(git_zstream *strm) |
| 218 | { |
| 219 | int status = git_deflate_abort(strm); |
| 220 | |
Junio C Hamano | 55bb5c9 | 2011-06-10 10:55:10 -0700 | [diff] [blame] | 221 | if (status == Z_OK) |
| 222 | return; |
| 223 | error("deflateEnd: %s (%s)", zerr_to_string(status), |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 224 | strm->z.msg ? strm->z.msg : "no message"); |
Junio C Hamano | 55bb5c9 | 2011-06-10 10:55:10 -0700 | [diff] [blame] | 225 | } |
| 226 | |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 227 | int git_deflate_end_gently(git_zstream *strm) |
Junio C Hamano | 55bb5c9 | 2011-06-10 10:55:10 -0700 | [diff] [blame] | 228 | { |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 229 | int status; |
| 230 | |
| 231 | zlib_pre_call(strm); |
| 232 | status = deflateEnd(&strm->z); |
| 233 | zlib_post_call(strm); |
| 234 | return status; |
Junio C Hamano | 55bb5c9 | 2011-06-10 10:55:10 -0700 | [diff] [blame] | 235 | } |
| 236 | |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 237 | int git_deflate(git_zstream *strm, int flush) |
Junio C Hamano | 55bb5c9 | 2011-06-10 10:55:10 -0700 | [diff] [blame] | 238 | { |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 239 | int status; |
Junio C Hamano | 55bb5c9 | 2011-06-10 10:55:10 -0700 | [diff] [blame] | 240 | |
Junio C Hamano | e01503b | 2011-06-10 12:15:17 -0700 | [diff] [blame] | 241 | for (;;) { |
| 242 | zlib_pre_call(strm); |
| 243 | |
| 244 | /* Never say Z_FINISH unless we are feeding everything */ |
| 245 | status = deflate(&strm->z, |
| 246 | (strm->z.avail_in != strm->avail_in) |
| 247 | ? 0 : flush); |
| 248 | if (status == Z_MEM_ERROR) |
| 249 | die("deflate: out of memory"); |
| 250 | zlib_post_call(strm); |
| 251 | |
| 252 | /* |
| 253 | * Let zlib work another round, while we can still |
| 254 | * make progress. |
| 255 | */ |
| 256 | if ((strm->avail_out && !strm->z.avail_out) && |
| 257 | (status == Z_OK || status == Z_BUF_ERROR)) |
| 258 | continue; |
| 259 | break; |
| 260 | } |
| 261 | |
Junio C Hamano | 55bb5c9 | 2011-06-10 10:55:10 -0700 | [diff] [blame] | 262 | switch (status) { |
| 263 | /* Z_BUF_ERROR: normal, needs more space in the output buffer */ |
| 264 | case Z_BUF_ERROR: |
| 265 | case Z_OK: |
| 266 | case Z_STREAM_END: |
| 267 | return status; |
Junio C Hamano | 55bb5c9 | 2011-06-10 10:55:10 -0700 | [diff] [blame] | 268 | default: |
| 269 | break; |
| 270 | } |
| 271 | error("deflate: %s (%s)", zerr_to_string(status), |
Junio C Hamano | ef49a7a | 2011-06-10 11:52:15 -0700 | [diff] [blame] | 272 | strm->z.msg ? strm->z.msg : "no message"); |
Junio C Hamano | 55bb5c9 | 2011-06-10 10:55:10 -0700 | [diff] [blame] | 273 | return status; |
| 274 | } |