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