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