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