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