fe537e3ff69880f2d5c69575c2c2575bac503323
1/*
2 * zlib wrappers to make sure we don't silently miss errors
3 * at init time.
4 */
5#include "cache.h"
6
7static 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
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)
59{
60 int status;
61
62 zlib_pre_call(strm);
63 status = inflateInit(&strm->z);
64 zlib_post_call(strm);
65 if (status == Z_OK)
66 return;
67 die("inflateInit: %s (%s)", zerr_to_string(status),
68 strm->z.msg ? strm->z.msg : "no message");
69}
70
71void git_inflate_init_gzip_only(git_zstream *strm)
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;
78 int status;
79
80 zlib_pre_call(strm);
81 status = inflateInit2(&strm->z, windowBits);
82 zlib_post_call(strm);
83 if (status == Z_OK)
84 return;
85 die("inflateInit2: %s (%s)", zerr_to_string(status),
86 strm->z.msg ? strm->z.msg : "no message");
87}
88
89void git_inflate_end(git_zstream *strm)
90{
91 int status;
92
93 zlib_pre_call(strm);
94 status = inflateEnd(&strm->z);
95 zlib_post_call(strm);
96 if (status == Z_OK)
97 return;
98 error("inflateEnd: %s (%s)", zerr_to_string(status),
99 strm->z.msg ? strm->z.msg : "no message");
100}
101
102int git_inflate(git_zstream *strm, int flush)
103{
104 int status;
105
106 zlib_pre_call(strm);
107 status = inflate(&strm->z, flush);
108 zlib_post_call(strm);
109 switch (status) {
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:
114 return status;
115
116 case Z_MEM_ERROR:
117 die("inflate: out of memory");
118 default:
119 break;
120 }
121 error("inflate: %s (%s)", zerr_to_string(status),
122 strm->z.msg ? strm->z.msg : "no message");
123 return status;
124}
125
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
130unsigned long git_deflate_bound(git_zstream *strm, unsigned long size)
131{
132 return deflateBound(&strm->z, size);
133}
134
135void git_deflate_init(git_zstream *strm, int level)
136{
137 int status;
138
139 zlib_pre_call(strm);
140 status = deflateInit(&strm->z, level);
141 zlib_post_call(strm);
142 if (status == Z_OK)
143 return;
144 die("deflateInit: %s (%s)", zerr_to_string(status),
145 strm->z.msg ? strm->z.msg : "no message");
146}
147
148void git_deflate_init_gzip(git_zstream *strm, int level)
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;
155 int status;
156
157 zlib_pre_call(strm);
158 status = deflateInit2(&strm->z, level,
159 Z_DEFLATED, windowBits,
160 8, Z_DEFAULT_STRATEGY);
161 zlib_post_call(strm);
162 if (status == Z_OK)
163 return;
164 die("deflateInit2: %s (%s)", zerr_to_string(status),
165 strm->z.msg ? strm->z.msg : "no message");
166}
167
168void git_deflate_end(git_zstream *strm)
169{
170 int status;
171
172 zlib_pre_call(strm);
173 status = deflateEnd(&strm->z);
174 zlib_post_call(strm);
175 if (status == Z_OK)
176 return;
177 error("deflateEnd: %s (%s)", zerr_to_string(status),
178 strm->z.msg ? strm->z.msg : "no message");
179}
180
181int git_deflate_end_gently(git_zstream *strm)
182{
183 int status;
184
185 zlib_pre_call(strm);
186 status = deflateEnd(&strm->z);
187 zlib_post_call(strm);
188 return status;
189}
190
191int git_deflate(git_zstream *strm, int flush)
192{
193 int status;
194
195 zlib_pre_call(strm);
196 status = deflate(&strm->z, flush);
197 zlib_post_call(strm);
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),
211 strm->z.msg ? strm->z.msg : "no message");
212 return status;
213}