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