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