zlib: zlib can only process 4GB at a time
[git/git.git] / zlib.c
CommitLineData
b0613ce0
JN
1/*
2 * zlib wrappers to make sure we don't silently miss errors
3 * at init time.
4 */
5#include "cache.h"
6
1a507fc1 7static const char *zerr_to_string(int status)
b0613ce0 8{
1a507fc1 9 switch (status) {
b0613ce0 10 case Z_MEM_ERROR:
1a507fc1 11 return "out of memory";
b0613ce0 12 case Z_VERSION_ERROR:
1a507fc1
JH
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";
b0613ce0 20 default:
1a507fc1 21 return "unknown error";
b0613ce0 22 }
b0613ce0
JN
23}
24
ef49a7a0
JH
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 */
30#define ZLIB_BUF_MAX ((uInt)-1)
31static inline uInt zlib_buf_cap(unsigned long len)
32{
33 if (ZLIB_BUF_MAX < len)
34 die("working buffer for zlib too large");
35 return len;
36}
37
38static 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
48static void zlib_post_call(git_zstream *s)
49{
50 s->next_in = s->z.next_in;
51 s->next_out = s->z.next_out;
52 s->total_in = s->z.total_in;
53 s->total_out = s->z.total_out;
54 s->avail_in = s->z.avail_in;
55 s->avail_out = s->z.avail_out;
56}
57
58void git_inflate_init(git_zstream *strm)
b0613ce0 59{
ef49a7a0 60 int status;
1a507fc1 61
ef49a7a0
JH
62 zlib_pre_call(strm);
63 status = inflateInit(&strm->z);
64 zlib_post_call(strm);
1a507fc1
JH
65 if (status == Z_OK)
66 return;
67 die("inflateInit: %s (%s)", zerr_to_string(status),
ef49a7a0 68 strm->z.msg ? strm->z.msg : "no message");
b0613ce0
JN
69}
70
ef49a7a0 71void git_inflate_init_gzip_only(git_zstream *strm)
5e86c1fb
JH
72{
73 /*
74 * Use default 15 bits, +16 is to accept only gzip and to
75 * yield Z_DATA_ERROR when fed zlib format.
76 */
77 const int windowBits = 15 + 16;
ef49a7a0 78 int status;
5e86c1fb 79
ef49a7a0
JH
80 zlib_pre_call(strm);
81 status = inflateInit2(&strm->z, windowBits);
82 zlib_post_call(strm);
5e86c1fb
JH
83 if (status == Z_OK)
84 return;
85 die("inflateInit2: %s (%s)", zerr_to_string(status),
ef49a7a0 86 strm->z.msg ? strm->z.msg : "no message");
5e86c1fb
JH
87}
88
ef49a7a0 89void git_inflate_end(git_zstream *strm)
b0613ce0 90{
ef49a7a0 91 int status;
b0613ce0 92
ef49a7a0
JH
93 zlib_pre_call(strm);
94 status = inflateEnd(&strm->z);
95 zlib_post_call(strm);
1a507fc1
JH
96 if (status == Z_OK)
97 return;
98 error("inflateEnd: %s (%s)", zerr_to_string(status),
ef49a7a0 99 strm->z.msg ? strm->z.msg : "no message");
1a507fc1 100}
b0613ce0 101
ef49a7a0 102int git_inflate(git_zstream *strm, int flush)
1a507fc1 103{
ef49a7a0 104 int status;
b0613ce0 105
ef49a7a0
JH
106 zlib_pre_call(strm);
107 status = inflate(&strm->z, flush);
108 zlib_post_call(strm);
1a507fc1 109 switch (status) {
b0613ce0
JN
110 /* Z_BUF_ERROR: normal, needs more space in the output buffer */
111 case Z_BUF_ERROR:
112 case Z_OK:
113 case Z_STREAM_END:
1a507fc1
JH
114 return status;
115
116 case Z_MEM_ERROR:
117 die("inflate: out of memory");
118 default:
119 break;
b0613ce0 120 }
1a507fc1 121 error("inflate: %s (%s)", zerr_to_string(status),
ef49a7a0 122 strm->z.msg ? strm->z.msg : "no message");
1a507fc1 123 return status;
b0613ce0 124}
55bb5c91 125
225a6f10
JH
126#if defined(NO_DEFLATE_BOUND) || ZLIB_VERNUM < 0x1200
127#define deflateBound(c,s) ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11)
128#endif
129
ef49a7a0 130unsigned long git_deflate_bound(git_zstream *strm, unsigned long size)
225a6f10 131{
ef49a7a0 132 return deflateBound(&strm->z, size);
225a6f10
JH
133}
134
ef49a7a0 135void git_deflate_init(git_zstream *strm, int level)
55bb5c91 136{
ef49a7a0 137 int status;
55bb5c91 138
ef49a7a0
JH
139 zlib_pre_call(strm);
140 status = deflateInit(&strm->z, level);
141 zlib_post_call(strm);
55bb5c91
JH
142 if (status == Z_OK)
143 return;
144 die("deflateInit: %s (%s)", zerr_to_string(status),
ef49a7a0 145 strm->z.msg ? strm->z.msg : "no message");
55bb5c91
JH
146}
147
ef49a7a0 148void git_deflate_init_gzip(git_zstream *strm, int level)
55bb5c91
JH
149{
150 /*
151 * Use default 15 bits, +16 is to generate gzip header/trailer
152 * instead of the zlib wrapper.
153 */
154 const int windowBits = 15 + 16;
ef49a7a0
JH
155 int status;
156
157 zlib_pre_call(strm);
158 status = deflateInit2(&strm->z, level,
55bb5c91
JH
159 Z_DEFLATED, windowBits,
160 8, Z_DEFAULT_STRATEGY);
ef49a7a0 161 zlib_post_call(strm);
55bb5c91
JH
162 if (status == Z_OK)
163 return;
164 die("deflateInit2: %s (%s)", zerr_to_string(status),
ef49a7a0 165 strm->z.msg ? strm->z.msg : "no message");
55bb5c91
JH
166}
167
ef49a7a0 168void git_deflate_end(git_zstream *strm)
55bb5c91 169{
ef49a7a0 170 int status;
55bb5c91 171
ef49a7a0
JH
172 zlib_pre_call(strm);
173 status = deflateEnd(&strm->z);
174 zlib_post_call(strm);
55bb5c91
JH
175 if (status == Z_OK)
176 return;
177 error("deflateEnd: %s (%s)", zerr_to_string(status),
ef49a7a0 178 strm->z.msg ? strm->z.msg : "no message");
55bb5c91
JH
179}
180
ef49a7a0 181int git_deflate_end_gently(git_zstream *strm)
55bb5c91 182{
ef49a7a0
JH
183 int status;
184
185 zlib_pre_call(strm);
186 status = deflateEnd(&strm->z);
187 zlib_post_call(strm);
188 return status;
55bb5c91
JH
189}
190
ef49a7a0 191int git_deflate(git_zstream *strm, int flush)
55bb5c91 192{
ef49a7a0 193 int status;
55bb5c91 194
ef49a7a0
JH
195 zlib_pre_call(strm);
196 status = deflate(&strm->z, flush);
197 zlib_post_call(strm);
55bb5c91
JH
198 switch (status) {
199 /* Z_BUF_ERROR: normal, needs more space in the output buffer */
200 case Z_BUF_ERROR:
201 case Z_OK:
202 case Z_STREAM_END:
203 return status;
204
205 case Z_MEM_ERROR:
206 die("deflate: out of memory");
207 default:
208 break;
209 }
210 error("deflate: %s (%s)", zerr_to_string(status),
ef49a7a0 211 strm->z.msg ? strm->z.msg : "no message");
55bb5c91
JH
212 return status;
213}