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