Line | Count | Source |
1 | | /* gzlib.c -- zlib functions common to reading and writing gzip files |
2 | | * Copyright (C) 2004-2024 Mark Adler |
3 | | * For conditions of distribution and use, see copyright notice in zlib.h |
4 | | */ |
5 | | |
6 | | #include "zbuild.h" |
7 | | #include "zutil.h" |
8 | | #include "zutil_p.h" |
9 | | #include "gzguts.h" |
10 | | |
11 | | #if defined(_WIN32) |
12 | | # define LSEEK _lseeki64 |
13 | | #else |
14 | | #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 |
15 | 6.10k | # define LSEEK lseek64 |
16 | | #else |
17 | | # define LSEEK lseek |
18 | | #endif |
19 | | #endif |
20 | | |
21 | | /* Local functions */ |
22 | | static gzFile gz_state_init(void); |
23 | | static void gz_reset(gz_state *); |
24 | | static gzFile gz_open(const void *, int, const char *); |
25 | | |
26 | | /* Initialize struct for gzFile state */ |
27 | 12.2k | static gzFile gz_state_init(void) { |
28 | | /* allocate gzFile structure to return */ |
29 | 12.2k | gz_state *state = (gz_state *)zng_alloc(sizeof(gz_state)); |
30 | 12.2k | if (state == NULL) |
31 | 0 | return NULL; |
32 | | |
33 | 12.2k | state->strm.zalloc = NULL; |
34 | 12.2k | state->strm.zfree = NULL; |
35 | 12.2k | state->strm.opaque = NULL; |
36 | 12.2k | state->strm.next_in = NULL; |
37 | | |
38 | 12.2k | state->size = 0; |
39 | 12.2k | state->want = GZBUFSIZE; |
40 | 12.2k | state->in = NULL; |
41 | 12.2k | state->out = NULL; |
42 | 12.2k | state->direct = 0; |
43 | 12.2k | state->mode = GZ_NONE; |
44 | 12.2k | state->level = Z_DEFAULT_COMPRESSION; |
45 | 12.2k | state->strategy = Z_DEFAULT_STRATEGY; |
46 | 12.2k | state->msg = NULL; |
47 | 12.2k | return (gzFile)state; |
48 | 12.2k | } |
49 | | |
50 | 6.11k | void Z_INTERNAL gz_state_free(gz_state *state) { |
51 | 6.11k | zng_free(state); |
52 | 6.11k | } |
53 | | |
54 | | /* Reset gzip file state */ |
55 | 12.2k | static void gz_reset(gz_state *state) { |
56 | 12.2k | state->x.have = 0; /* no output data available */ |
57 | 12.2k | if (state->mode == GZ_READ) { /* for reading ... */ |
58 | 6.10k | state->eof = 0; /* not at end of file */ |
59 | 6.10k | state->past = 0; /* have not read past end yet */ |
60 | 6.10k | state->how = LOOK; /* look for gzip header */ |
61 | 6.10k | } |
62 | 6.11k | else /* for writing ... */ |
63 | 6.11k | state->reset = 0; /* no deflateReset pending */ |
64 | 12.2k | state->seek = 0; /* no seek request pending */ |
65 | 12.2k | gz_error(state, Z_OK, NULL); /* clear error */ |
66 | 12.2k | state->x.pos = 0; /* no uncompressed data yet */ |
67 | 12.2k | state->strm.avail_in = 0; /* no input data yet */ |
68 | 12.2k | } |
69 | | |
70 | | /* Allocate in/out buffers for gzFile */ |
71 | 12.2k | int Z_INTERNAL gz_buffer_alloc(gz_state *state) { |
72 | 12.2k | int want = state->want; |
73 | 12.2k | int in_size = want, out_size = want; |
74 | | |
75 | 12.2k | if (state->mode == GZ_WRITE) { |
76 | 6.11k | in_size = want * 2; // double input buffer for compression (ref: gzprintf) |
77 | 6.11k | if (state->direct) |
78 | 5 | out_size = 0; // output buffer not needed in write + direct mode |
79 | 6.11k | } else if (state->mode == GZ_READ) { |
80 | 6.10k | out_size = want * 2; // double output buffer for decompression |
81 | 6.10k | } |
82 | | |
83 | 12.2k | state->buffers = (unsigned char *)zng_alloc_aligned((in_size + out_size), 64); |
84 | 12.2k | state->in = state->buffers; |
85 | 12.2k | if (out_size) { |
86 | 12.2k | state->out = state->buffers + (in_size); // Outbuffer goes after inbuffer |
87 | 12.2k | } |
88 | | |
89 | | /* Return error if memory allocation failed */ |
90 | 12.2k | if (state->in == NULL || (out_size && state->out == NULL)) { |
91 | 0 | gz_buffer_free(state); |
92 | 0 | gz_error(state, Z_MEM_ERROR, "out of memory"); |
93 | 0 | return -1; |
94 | 0 | } |
95 | | |
96 | 12.2k | state->size = want; // mark state as initialized |
97 | 12.2k | return 0; |
98 | 12.2k | } |
99 | | |
100 | 12.2k | void Z_INTERNAL gz_buffer_free(gz_state *state) { |
101 | 12.2k | zng_free_aligned(state->buffers); |
102 | 12.2k | state->buffers = NULL; |
103 | 12.2k | state->out = NULL; |
104 | 12.2k | state->in = NULL; |
105 | 12.2k | state->size = 0; |
106 | 12.2k | } |
107 | | |
108 | | /* Open a gzip file either by name or file descriptor. */ |
109 | 12.2k | static gzFile gz_open(const void *path, int fd, const char *mode) { |
110 | 12.2k | gz_state *state; |
111 | 12.2k | size_t len; |
112 | 12.2k | int oflag; |
113 | 12.2k | #ifdef O_CLOEXEC |
114 | 12.2k | int cloexec = 0; |
115 | 12.2k | #endif |
116 | 12.2k | #ifdef O_EXCL |
117 | 12.2k | int exclusive = 0; |
118 | 12.2k | #endif |
119 | | |
120 | | /* check input */ |
121 | 12.2k | if (path == NULL) |
122 | 0 | return NULL; |
123 | | |
124 | | /* Initialize gzFile state */ |
125 | 12.2k | state = (gz_state *)gz_state_init(); |
126 | 12.2k | if (state == NULL) |
127 | 0 | return NULL; |
128 | | |
129 | | /* interpret mode */ |
130 | 47.0k | while (*mode) { |
131 | 34.8k | if (*mode >= '0' && *mode <= '9') { |
132 | 6.11k | state->level = *mode - '0'; |
133 | 28.7k | } else { |
134 | 28.7k | switch (*mode) { |
135 | 6.10k | case 'r': |
136 | 6.10k | state->mode = GZ_READ; |
137 | 6.10k | break; |
138 | 0 | #ifndef NO_GZCOMPRESS |
139 | 6.11k | case 'w': |
140 | 6.11k | state->mode = GZ_WRITE; |
141 | 6.11k | break; |
142 | 0 | case 'a': |
143 | 0 | state->mode = GZ_APPEND; |
144 | 0 | break; |
145 | 0 | #endif |
146 | 0 | case '+': /* can't read and write at the same time */ |
147 | 0 | gz_state_free(state); |
148 | 0 | return NULL; |
149 | 12.2k | case 'b': /* ignore -- will request binary anyway */ |
150 | 12.2k | break; |
151 | 0 | #ifdef O_CLOEXEC |
152 | 0 | case 'e': |
153 | 0 | cloexec = 1; |
154 | 0 | break; |
155 | 0 | #endif |
156 | 0 | #ifdef O_EXCL |
157 | 0 | case 'x': |
158 | 0 | exclusive = 1; |
159 | 0 | break; |
160 | 0 | #endif |
161 | 992 | case 'f': |
162 | 992 | state->strategy = Z_FILTERED; |
163 | 992 | break; |
164 | 627 | case 'h': |
165 | 627 | state->strategy = Z_HUFFMAN_ONLY; |
166 | 627 | break; |
167 | 1.76k | case 'R': |
168 | 1.76k | state->strategy = Z_RLE; |
169 | 1.76k | break; |
170 | 885 | case 'F': |
171 | 885 | state->strategy = Z_FIXED; |
172 | 885 | break; |
173 | 5 | case 'T': |
174 | 5 | state->direct = 1; |
175 | 5 | break; |
176 | 0 | default: /* could consider as an error, but just ignore */ |
177 | 0 | {} |
178 | 28.7k | } |
179 | 28.7k | } |
180 | 34.8k | mode++; |
181 | 34.8k | } |
182 | | |
183 | | /* must provide an "r", "w", or "a" */ |
184 | 12.2k | if (state->mode == GZ_NONE) { |
185 | 0 | gz_state_free(state); |
186 | 0 | return NULL; |
187 | 0 | } |
188 | | |
189 | | /* can't force transparent read */ |
190 | 12.2k | if (state->mode == GZ_READ) { |
191 | 6.10k | if (state->direct) { |
192 | 0 | gz_state_free(state); |
193 | 0 | return NULL; |
194 | 0 | } |
195 | 6.10k | state->direct = 1; /* for empty file */ |
196 | 6.10k | } |
197 | | |
198 | | /* save the path name for error messages */ |
199 | | #ifdef WIDECHAR |
200 | | if (fd == -2) { |
201 | | len = wcstombs(NULL, (const wchar_t *)path, 0); |
202 | | if (len == (size_t)-1) |
203 | | len = 0; |
204 | | } else |
205 | | #endif |
206 | 12.2k | len = strlen((const char *)path); |
207 | 12.2k | state->path = (char *)malloc(len + 1); |
208 | 12.2k | if (state->path == NULL) { |
209 | 0 | gz_state_free(state); |
210 | 0 | return NULL; |
211 | 0 | } |
212 | | #ifdef WIDECHAR |
213 | | if (fd == -2) |
214 | | if (len) { |
215 | | wcstombs(state->path, (const wchar_t *)path, len + 1); |
216 | | } else { |
217 | | *(state->path) = 0; |
218 | | } |
219 | | else |
220 | | #endif |
221 | 12.2k | (void)snprintf(state->path, len + 1, "%s", (const char *)path); |
222 | | |
223 | | /* compute the flags for open() */ |
224 | 12.2k | oflag = |
225 | 12.2k | #ifdef O_LARGEFILE |
226 | 12.2k | O_LARGEFILE | |
227 | 12.2k | #endif |
228 | | #ifdef O_BINARY |
229 | | O_BINARY | |
230 | | #endif |
231 | 12.2k | #ifdef O_CLOEXEC |
232 | 12.2k | (cloexec ? O_CLOEXEC : 0) | |
233 | 12.2k | #endif |
234 | 12.2k | (state->mode == GZ_READ ? |
235 | 12.2k | O_RDONLY : |
236 | 12.2k | (O_WRONLY | O_CREAT | |
237 | 6.11k | #ifdef O_EXCL |
238 | 6.11k | (exclusive ? O_EXCL : 0) | |
239 | 6.11k | #endif |
240 | 6.11k | (state->mode == GZ_WRITE ? |
241 | 6.11k | O_TRUNC : |
242 | 6.11k | O_APPEND))); |
243 | | |
244 | | /* open the file with the appropriate flags (or just use fd) */ |
245 | 12.2k | state->fd = fd > -1 ? fd : ( |
246 | | #if defined(_WIN32) |
247 | | fd == -2 ? _wopen((const wchar_t *)path, oflag, 0666) : |
248 | | #elif __CYGWIN__ |
249 | | fd == -2 ? open(state->path, oflag, 0666) : |
250 | | #endif |
251 | 12.2k | open((const char *)path, oflag, 0666)); |
252 | 12.2k | if (state->fd == -1) { |
253 | 0 | free(state->path); |
254 | 0 | gz_state_free(state); |
255 | 0 | return NULL; |
256 | 0 | } |
257 | 12.2k | if (state->mode == GZ_APPEND) { |
258 | 0 | LSEEK(state->fd, 0, SEEK_END); /* so gzoffset() is correct */ |
259 | 0 | state->mode = GZ_WRITE; /* simplify later checks */ |
260 | 0 | } |
261 | | |
262 | | /* save the current position for rewinding (only if reading) */ |
263 | 12.2k | if (state->mode == GZ_READ) { |
264 | 6.10k | state->start = LSEEK(state->fd, 0, SEEK_CUR); |
265 | 6.10k | if (state->start == -1) state->start = 0; |
266 | 6.10k | } |
267 | | |
268 | | /* initialize stream */ |
269 | 12.2k | gz_reset(state); |
270 | | |
271 | | /* return stream */ |
272 | 12.2k | return (gzFile)state; |
273 | 12.2k | } |
274 | | |
275 | | /* -- see zlib.h -- */ |
276 | 12.2k | gzFile Z_EXPORT PREFIX(gzopen)(const char *path, const char *mode) { |
277 | 12.2k | return gz_open(path, -1, mode); |
278 | 12.2k | } |
279 | | |
280 | | #ifdef ZLIB_COMPAT |
281 | | gzFile Z_EXPORT PREFIX4(gzopen)(const char *path, const char *mode) { |
282 | | return gz_open(path, -1, mode); |
283 | | } |
284 | | #endif |
285 | | |
286 | | /* -- see zlib.h -- */ |
287 | 0 | gzFile Z_EXPORT PREFIX(gzdopen)(int fd, const char *mode) { |
288 | 0 | gzFile gz; |
289 | 0 | char path[32]; /* identifier for error messages */ |
290 | |
|
291 | 0 | if (fd == -1) |
292 | 0 | return NULL; |
293 | 0 | (void)snprintf(path, 32, "<fd:%d>", fd); /* for debugging */ |
294 | 0 | gz = gz_open(path, fd, mode); |
295 | 0 | return gz; |
296 | 0 | } |
297 | | |
298 | | /* -- see zlib.h -- */ |
299 | | #ifdef WIDECHAR |
300 | | gzFile Z_EXPORT PREFIX(gzopen_w)(const wchar_t *path, const char *mode) { |
301 | | return gz_open(path, -2, mode); |
302 | | } |
303 | | #endif |
304 | | |
305 | 12.2k | z_int32_t Z_EXPORT PREFIX(gzclose)(gzFile file) { |
306 | 12.2k | #ifndef NO_GZCOMPRESS |
307 | 12.2k | gz_state *state; |
308 | | |
309 | 12.2k | if (file == NULL) |
310 | 0 | return Z_STREAM_ERROR; |
311 | 12.2k | state = (gz_state *)file; |
312 | | |
313 | 12.2k | return state->mode == GZ_READ ? PREFIX(gzclose_r)(file) : PREFIX(gzclose_w)(file); |
314 | | #else |
315 | | return PREFIX(gzclose_r)(file); |
316 | | #endif |
317 | 12.2k | } |
318 | | |
319 | | /* -- see zlib.h -- */ |
320 | 0 | z_int32_t Z_EXPORT PREFIX(gzbuffer)(gzFile file, z_uint32_t size) { |
321 | 0 | gz_state *state; |
322 | | |
323 | | /* get internal structure and check integrity */ |
324 | 0 | if (file == NULL) |
325 | 0 | return -1; |
326 | 0 | state = (gz_state *)file; |
327 | 0 | if (state->mode != GZ_READ && state->mode != GZ_WRITE) |
328 | 0 | return -1; |
329 | | |
330 | | /* make sure we haven't already allocated memory */ |
331 | 0 | if (state->size != 0) |
332 | 0 | return -1; |
333 | | |
334 | | /* check and set requested size */ |
335 | 0 | if ((size << 1) < size) |
336 | 0 | return -1; /* need to be able to double it */ |
337 | 0 | if (size < 8) |
338 | 0 | size = 8; /* needed to behave well with flushing */ |
339 | 0 | state->want = size; |
340 | 0 | return 0; |
341 | 0 | } |
342 | | |
343 | | /* -- see zlib.h -- */ |
344 | 0 | z_int32_t Z_EXPORT PREFIX(gzrewind)(gzFile file) { |
345 | 0 | gz_state *state; |
346 | | |
347 | | /* get internal structure */ |
348 | 0 | if (file == NULL) |
349 | 0 | return -1; |
350 | 0 | state = (gz_state *)file; |
351 | | |
352 | | /* check that we're reading and that there's no error */ |
353 | 0 | if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) |
354 | 0 | return -1; |
355 | | |
356 | | /* back up and start over */ |
357 | 0 | if (LSEEK(state->fd, state->start, SEEK_SET) == -1) |
358 | 0 | return -1; |
359 | 0 | gz_reset(state); |
360 | 0 | return 0; |
361 | 0 | } |
362 | | |
363 | | /* -- see zlib.h -- */ |
364 | 0 | z_off64_t Z_EXPORT PREFIX4(gzseek)(gzFile file, z_off64_t offset, int whence) { |
365 | 0 | unsigned n; |
366 | 0 | z_off64_t ret; |
367 | 0 | gz_state *state; |
368 | | |
369 | | /* get internal structure and check integrity */ |
370 | 0 | if (file == NULL) |
371 | 0 | return -1; |
372 | 0 | state = (gz_state *)file; |
373 | 0 | if (state->mode != GZ_READ && state->mode != GZ_WRITE) |
374 | 0 | return -1; |
375 | | |
376 | | /* check that there's no error */ |
377 | 0 | if (state->err != Z_OK && state->err != Z_BUF_ERROR) |
378 | 0 | return -1; |
379 | | |
380 | | /* can only seek from start or relative to current position */ |
381 | 0 | if (whence != SEEK_SET && whence != SEEK_CUR) |
382 | 0 | return -1; |
383 | | |
384 | | /* normalize offset to a SEEK_CUR specification */ |
385 | 0 | if (whence == SEEK_SET) |
386 | 0 | offset -= state->x.pos; |
387 | 0 | else if (state->seek) |
388 | 0 | offset += state->skip; |
389 | 0 | state->seek = 0; |
390 | | |
391 | | /* if within raw area while reading, just go there */ |
392 | 0 | if (state->mode == GZ_READ && state->how == COPY && state->x.pos + offset >= 0) { |
393 | 0 | ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR); |
394 | 0 | if (ret == -1) |
395 | 0 | return -1; |
396 | 0 | state->x.have = 0; |
397 | 0 | state->eof = 0; |
398 | 0 | state->past = 0; |
399 | 0 | state->seek = 0; |
400 | 0 | gz_error(state, Z_OK, NULL); |
401 | 0 | state->strm.avail_in = 0; |
402 | 0 | state->x.pos += offset; |
403 | 0 | return state->x.pos; |
404 | 0 | } |
405 | | |
406 | | /* calculate skip amount, rewinding if needed for back seek when reading */ |
407 | 0 | if (offset < 0) { |
408 | 0 | if (state->mode != GZ_READ) /* writing -- can't go backwards */ |
409 | 0 | return -1; |
410 | 0 | offset += state->x.pos; |
411 | 0 | if (offset < 0) /* before start of file! */ |
412 | 0 | return -1; |
413 | 0 | if (PREFIX(gzrewind)(file) == -1) /* rewind, then skip to offset */ |
414 | 0 | return -1; |
415 | 0 | } |
416 | | |
417 | | /* if reading, skip what's in output buffer (one less gzgetc() check) */ |
418 | 0 | if (state->mode == GZ_READ) { |
419 | 0 | n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? (unsigned)offset : state->x.have; |
420 | 0 | state->x.have -= n; |
421 | 0 | state->x.next += n; |
422 | 0 | state->x.pos += n; |
423 | 0 | offset -= n; |
424 | 0 | } |
425 | | |
426 | | /* request skip (if not zero) */ |
427 | 0 | if (offset) { |
428 | 0 | state->seek = 1; |
429 | 0 | state->skip = offset; |
430 | 0 | } |
431 | 0 | return state->x.pos + offset; |
432 | 0 | } |
433 | | |
434 | | /* -- see zlib.h -- */ |
435 | | #ifdef ZLIB_COMPAT |
436 | | z_off_t Z_EXPORT PREFIX(gzseek)(gzFile file, z_off_t offset, int whence) { |
437 | | z_off64_t ret; |
438 | | |
439 | | ret = PREFIX4(gzseek)(file, (z_off64_t)offset, whence); |
440 | | return ret == (z_off_t)ret ? (z_off_t)ret : -1; |
441 | | } |
442 | | #endif |
443 | | |
444 | | /* -- see zlib.h -- */ |
445 | 0 | z_off64_t Z_EXPORT PREFIX4(gztell)(gzFile file) { |
446 | 0 | gz_state *state; |
447 | | |
448 | | /* get internal structure and check integrity */ |
449 | 0 | if (file == NULL) |
450 | 0 | return -1; |
451 | 0 | state = (gz_state *)file; |
452 | 0 | if (state->mode != GZ_READ && state->mode != GZ_WRITE) |
453 | 0 | return -1; |
454 | | |
455 | | /* return position */ |
456 | 0 | return state->x.pos + (state->seek ? state->skip : 0); |
457 | 0 | } |
458 | | |
459 | | /* -- see zlib.h -- */ |
460 | | #ifdef ZLIB_COMPAT |
461 | | z_off_t Z_EXPORT PREFIX(gztell)(gzFile file) { |
462 | | |
463 | | z_off64_t ret; |
464 | | |
465 | | ret = PREFIX4(gztell)(file); |
466 | | return ret == (z_off_t)ret ? (z_off_t)ret : -1; |
467 | | } |
468 | | #endif |
469 | | |
470 | | /* -- see zlib.h -- */ |
471 | 0 | z_off64_t Z_EXPORT PREFIX4(gzoffset)(gzFile file) { |
472 | 0 | z_off64_t offset; |
473 | 0 | gz_state *state; |
474 | | |
475 | | /* get internal structure and check integrity */ |
476 | 0 | if (file == NULL) |
477 | 0 | return -1; |
478 | 0 | state = (gz_state *)file; |
479 | 0 | if (state->mode != GZ_READ && state->mode != GZ_WRITE) |
480 | 0 | return -1; |
481 | | |
482 | | /* compute and return effective offset in file */ |
483 | 0 | offset = LSEEK(state->fd, 0, SEEK_CUR); |
484 | 0 | if (offset == -1) |
485 | 0 | return -1; |
486 | 0 | if (state->mode == GZ_READ) /* reading */ |
487 | 0 | offset -= state->strm.avail_in; /* don't count buffered input */ |
488 | 0 | return offset; |
489 | 0 | } |
490 | | |
491 | | /* -- see zlib.h -- */ |
492 | | #ifdef ZLIB_COMPAT |
493 | | z_off_t Z_EXPORT PREFIX(gzoffset)(gzFile file) { |
494 | | z_off64_t ret; |
495 | | |
496 | | ret = PREFIX4(gzoffset)(file); |
497 | | return ret == (z_off_t)ret ? (z_off_t)ret : -1; |
498 | | } |
499 | | #endif |
500 | | |
501 | | /* -- see zlib.h -- */ |
502 | 0 | z_int32_t Z_EXPORT PREFIX(gzeof)(gzFile file) { |
503 | 0 | gz_state *state; |
504 | | |
505 | | /* get internal structure and check integrity */ |
506 | 0 | if (file == NULL) |
507 | 0 | return 0; |
508 | 0 | state = (gz_state *)file; |
509 | 0 | if (state->mode != GZ_READ && state->mode != GZ_WRITE) |
510 | 0 | return 0; |
511 | | |
512 | | /* return end-of-file state */ |
513 | 0 | return state->mode == GZ_READ ? state->past : 0; |
514 | 0 | } |
515 | | |
516 | | /* -- see zlib.h -- */ |
517 | 0 | const char * Z_EXPORT PREFIX(gzerror)(gzFile file, z_int32_t *errnum) { |
518 | 0 | gz_state *state; |
519 | | |
520 | | /* get internal structure and check integrity */ |
521 | 0 | if (file == NULL) |
522 | 0 | return NULL; |
523 | 0 | state = (gz_state *)file; |
524 | 0 | if (state->mode != GZ_READ && state->mode != GZ_WRITE) |
525 | 0 | return NULL; |
526 | | |
527 | | /* return error information */ |
528 | 0 | if (errnum != NULL) |
529 | 0 | *errnum = state->err; |
530 | 0 | return state->err == Z_MEM_ERROR ? "out of memory" : (state->msg == NULL ? "" : state->msg); |
531 | 0 | } |
532 | | |
533 | | /* -- see zlib.h -- */ |
534 | 0 | void Z_EXPORT PREFIX(gzclearerr)(gzFile file) { |
535 | 0 | gz_state *state; |
536 | | |
537 | | /* get internal structure and check integrity */ |
538 | 0 | if (file == NULL) |
539 | 0 | return; |
540 | 0 | state = (gz_state *)file; |
541 | 0 | if (state->mode != GZ_READ && state->mode != GZ_WRITE) |
542 | 0 | return; |
543 | | |
544 | | /* clear error and end-of-file */ |
545 | 0 | if (state->mode == GZ_READ) { |
546 | 0 | state->eof = 0; |
547 | 0 | state->past = 0; |
548 | 0 | } |
549 | 0 | gz_error(state, Z_OK, NULL); |
550 | 0 | } |
551 | | |
552 | | /* Create an error message in allocated memory and set state->err and |
553 | | state->msg accordingly. Free any previous error message already there. Do |
554 | | not try to free or allocate space if the error is Z_MEM_ERROR (out of |
555 | | memory). Simply save the error message as a static string. If there is an |
556 | | allocation failure constructing the error message, then convert the error to |
557 | | out of memory. */ |
558 | 24.4k | void Z_INTERNAL gz_error(gz_state *state, int err, const char *msg) { |
559 | | /* free previously allocated message and clear */ |
560 | 24.4k | if (state->msg != NULL) { |
561 | 0 | if (state->err != Z_MEM_ERROR) |
562 | 0 | free(state->msg); |
563 | 0 | state->msg = NULL; |
564 | 0 | } |
565 | | |
566 | | /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */ |
567 | 24.4k | if (err != Z_OK && err != Z_BUF_ERROR) |
568 | 0 | state->x.have = 0; |
569 | | |
570 | | /* set error code, and if no message, then done */ |
571 | 24.4k | state->err = err; |
572 | 24.4k | if (msg == NULL) |
573 | 24.4k | return; |
574 | | |
575 | | /* for an out of memory error, return literal string when requested */ |
576 | 0 | if (err == Z_MEM_ERROR) |
577 | 0 | return; |
578 | | |
579 | | /* construct error message with path */ |
580 | 0 | if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) { |
581 | 0 | state->err = Z_MEM_ERROR; |
582 | 0 | return; |
583 | 0 | } |
584 | 0 | (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, "%s%s%s", state->path, ": ", msg); |
585 | 0 | } |
586 | | |
587 | | #ifdef ZLIB_COMPAT |
588 | | unsigned Z_INTERNAL gz_intmax(void) { |
589 | | return INT_MAX; |
590 | | } |
591 | | #endif |