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