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