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