git

Форк
0
/
git-zlib.c 
274 строки · 6.2 Кб
1
/*
2
 * zlib wrappers to make sure we don't silently miss errors
3
 * at init time.
4
 */
5
#include "git-compat-util.h"
6
#include "git-zlib.h"
7

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

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
 */
31
/* #define ZLIB_BUF_MAX ((uInt)-1) */
32
#define ZLIB_BUF_MAX ((uInt) 1024 * 1024 * 1024) /* 1GB */
33
static inline uInt zlib_buf_cap(unsigned long len)
34
{
35
	return (ZLIB_BUF_MAX < len) ? ZLIB_BUF_MAX : len;
36
}
37

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
{
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)
56
		BUG("total_out mismatch");
57
	if (s->z.total_in != s->total_in + bytes_consumed)
58
		BUG("total_in mismatch");
59

60
	s->total_out = s->z.total_out;
61
	s->total_in = s->z.total_in;
62
	s->next_in = s->z.next_in;
63
	s->next_out = s->z.next_out;
64
	s->avail_in -= bytes_consumed;
65
	s->avail_out -= bytes_produced;
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);
75
	if (status == Z_OK)
76
		return;
77
	die("inflateInit: %s (%s)", zerr_to_string(status),
78
	    strm->z.msg ? strm->z.msg : "no message");
79
}
80

81
void git_inflate_init_gzip_only(git_zstream *strm)
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;
88
	int status;
89

90
	zlib_pre_call(strm);
91
	status = inflateInit2(&strm->z, windowBits);
92
	zlib_post_call(strm);
93
	if (status == Z_OK)
94
		return;
95
	die("inflateInit2: %s (%s)", zerr_to_string(status),
96
	    strm->z.msg ? strm->z.msg : "no message");
97
}
98

99
void git_inflate_end(git_zstream *strm)
100
{
101
	int status;
102

103
	zlib_pre_call(strm);
104
	status = inflateEnd(&strm->z);
105
	zlib_post_call(strm);
106
	if (status == Z_OK)
107
		return;
108
	error("inflateEnd: %s (%s)", zerr_to_string(status),
109
	      strm->z.msg ? strm->z.msg : "no message");
110
}
111

112
int git_inflate(git_zstream *strm, int flush)
113
{
114
	int status;
115

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

136
	switch (status) {
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:
141
		return status;
142
	default:
143
		break;
144
	}
145
	error("inflate: %s (%s)", zerr_to_string(status),
146
	      strm->z.msg ? strm->z.msg : "no message");
147
	return status;
148
}
149

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

154
unsigned long git_deflate_bound(git_zstream *strm, unsigned long size)
155
{
156
	return deflateBound(&strm->z, size);
157
}
158

159
void git_deflate_init(git_zstream *strm, int level)
160
{
161
	int status;
162

163
	memset(strm, 0, sizeof(*strm));
164
	zlib_pre_call(strm);
165
	status = deflateInit(&strm->z, level);
166
	zlib_post_call(strm);
167
	if (status == Z_OK)
168
		return;
169
	die("deflateInit: %s (%s)", zerr_to_string(status),
170
	    strm->z.msg ? strm->z.msg : "no message");
171
}
172

173
static void do_git_deflate_init(git_zstream *strm, int level, int windowBits)
174
{
175
	int status;
176

177
	memset(strm, 0, sizeof(*strm));
178
	zlib_pre_call(strm);
179
	status = deflateInit2(&strm->z, level,
180
				  Z_DEFLATED, windowBits,
181
				  8, Z_DEFAULT_STRATEGY);
182
	zlib_post_call(strm);
183
	if (status == Z_OK)
184
		return;
185
	die("deflateInit2: %s (%s)", zerr_to_string(status),
186
	    strm->z.msg ? strm->z.msg : "no message");
187
}
188

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
	 */
195
	do_git_deflate_init(strm, level, 15 + 16);
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
	 */
204
	do_git_deflate_init(strm, level, -15);
205
}
206

207
int git_deflate_abort(git_zstream *strm)
208
{
209
	int status;
210

211
	zlib_pre_call(strm);
212
	status = deflateEnd(&strm->z);
213
	zlib_post_call(strm);
214
	return status;
215
}
216

217
void git_deflate_end(git_zstream *strm)
218
{
219
	int status = git_deflate_abort(strm);
220

221
	if (status == Z_OK)
222
		return;
223
	error("deflateEnd: %s (%s)", zerr_to_string(status),
224
	      strm->z.msg ? strm->z.msg : "no message");
225
}
226

227
int git_deflate_end_gently(git_zstream *strm)
228
{
229
	int status;
230

231
	zlib_pre_call(strm);
232
	status = deflateEnd(&strm->z);
233
	zlib_post_call(strm);
234
	return status;
235
}
236

237
int git_deflate(git_zstream *strm, int flush)
238
{
239
	int status;
240

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

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;
268
	default:
269
		break;
270
	}
271
	error("deflate: %s (%s)", zerr_to_string(status),
272
	      strm->z.msg ? strm->z.msg : "no message");
273
	return status;
274
}
275

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.