aboutsummaryrefslogtreecommitdiff
path: root/gzlib.c
diff options
context:
space:
mode:
Diffstat (limited to 'gzlib.c')
-rw-r--r--gzlib.c103
1 files changed, 65 insertions, 38 deletions
diff --git a/gzlib.c b/gzlib.c
index 983153cc8e49..7a37a96cf0a3 100644
--- a/gzlib.c
+++ b/gzlib.c
@@ -1,19 +1,19 @@
/* gzlib.c -- zlib functions common to reading and writing gzip files
- * Copyright (C) 2004-2024 Mark Adler
+ * Copyright (C) 2004-2026 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "gzguts.h"
-#if defined(_WIN32) && !defined(__BORLANDC__)
+#if defined(__DJGPP__)
+# define LSEEK llseek
+#elif defined(_WIN32) && !defined(__BORLANDC__) && !defined(UNDER_CE)
# define LSEEK _lseeki64
-#else
-#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
+#elif defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
# define LSEEK lseek64
#else
# define LSEEK lseek
#endif
-#endif
#if defined UNDER_CE
@@ -52,7 +52,7 @@ char ZLIB_INTERNAL *gz_strwinerror(DWORD error) {
msgbuf[chars] = 0;
}
- wcstombs(buf, msgbuf, chars + 1);
+ wcstombs(buf, msgbuf, chars + 1); /* assumes buf is big enough */
LocalFree(msgbuf);
}
else {
@@ -72,10 +72,12 @@ local void gz_reset(gz_statep state) {
state->eof = 0; /* not at end of file */
state->past = 0; /* have not read past end yet */
state->how = LOOK; /* look for gzip header */
+ state->junk = -1; /* mark first member */
}
else /* for writing ... */
state->reset = 0; /* no deflateReset pending */
- state->seek = 0; /* no seek request pending */
+ state->again = 0; /* no stalled i/o yet */
+ state->skip = 0; /* no seek request pending */
gz_error(state, Z_OK, NULL); /* clear error */
state->x.pos = 0; /* no uncompressed data yet */
state->strm.avail_in = 0; /* no input data yet */
@@ -85,16 +87,13 @@ local void gz_reset(gz_statep state) {
local gzFile gz_open(const void *path, int fd, const char *mode) {
gz_statep state;
z_size_t len;
- int oflag;
-#ifdef O_CLOEXEC
- int cloexec = 0;
-#endif
+ int oflag = 0;
#ifdef O_EXCL
int exclusive = 0;
#endif
/* check input */
- if (path == NULL)
+ if (path == NULL || mode == NULL)
return NULL;
/* allocate gzFile structure to return */
@@ -103,6 +102,7 @@ local gzFile gz_open(const void *path, int fd, const char *mode) {
return NULL;
state->size = 0; /* no buffers allocated yet */
state->want = GZBUFSIZE; /* requested buffer size */
+ state->err = Z_OK; /* no error yet */
state->msg = NULL; /* no error message yet */
/* interpret mode */
@@ -133,7 +133,7 @@ local gzFile gz_open(const void *path, int fd, const char *mode) {
break;
#ifdef O_CLOEXEC
case 'e':
- cloexec = 1;
+ oflag |= O_CLOEXEC;
break;
#endif
#ifdef O_EXCL
@@ -153,6 +153,14 @@ local gzFile gz_open(const void *path, int fd, const char *mode) {
case 'F':
state->strategy = Z_FIXED;
break;
+ case 'G':
+ state->direct = -1;
+ break;
+#ifdef O_NONBLOCK
+ case 'N':
+ oflag |= O_NONBLOCK;
+ break;
+#endif
case 'T':
state->direct = 1;
break;
@@ -168,22 +176,30 @@ local gzFile gz_open(const void *path, int fd, const char *mode) {
return NULL;
}
- /* can't force transparent read */
+ /* direct is 0, 1 if "T", or -1 if "G" (last "G" or "T" wins) */
if (state->mode == GZ_READ) {
- if (state->direct) {
+ if (state->direct == 1) {
+ /* can't force a transparent read */
free(state);
return NULL;
}
- state->direct = 1; /* for empty file */
+ if (state->direct == 0)
+ /* default when reading is auto-detect of gzip vs. transparent --
+ start with a transparent assumption in case of an empty file */
+ state->direct = 1;
}
+ else if (state->direct == -1) {
+ /* "G" has no meaning when writing -- disallow it */
+ free(state);
+ return NULL;
+ }
+ /* if reading, direct == 1 for auto-detect, -1 for gzip only; if writing or
+ appending, direct == 0 for gzip, 1 for transparent (copy in to out) */
/* save the path name for error messages */
#ifdef WIDECHAR
- if (fd == -2) {
+ if (fd == -2)
len = wcstombs(NULL, path, 0);
- if (len == (z_size_t)-1)
- len = 0;
- }
else
#endif
len = strlen((const char *)path);
@@ -193,30 +209,30 @@ local gzFile gz_open(const void *path, int fd, const char *mode) {
return NULL;
}
#ifdef WIDECHAR
- if (fd == -2)
+ if (fd == -2) {
if (len)
wcstombs(state->path, path, len + 1);
else
*(state->path) = 0;
+ }
else
#endif
+ {
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
(void)snprintf(state->path, len + 1, "%s", (const char *)path);
#else
strcpy(state->path, path);
#endif
+ }
/* compute the flags for open() */
- oflag =
+ oflag |=
#ifdef O_LARGEFILE
O_LARGEFILE |
#endif
#ifdef O_BINARY
O_BINARY |
#endif
-#ifdef O_CLOEXEC
- (cloexec ? O_CLOEXEC : 0) |
-#endif
(state->mode == GZ_READ ?
O_RDONLY :
(O_WRONLY | O_CREAT |
@@ -228,11 +244,23 @@ local gzFile gz_open(const void *path, int fd, const char *mode) {
O_APPEND)));
/* open the file with the appropriate flags (or just use fd) */
- state->fd = fd > -1 ? fd : (
+ if (fd == -1)
+ state->fd = open((const char *)path, oflag, 0666);
#ifdef WIDECHAR
- fd == -2 ? _wopen(path, oflag, 0666) :
+ else if (fd == -2)
+ state->fd = _wopen(path, oflag, _S_IREAD | _S_IWRITE);
+#endif
+ else {
+#ifdef O_NONBLOCK
+ if (oflag & O_NONBLOCK)
+ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
#endif
- open((const char *)path, oflag, 0666));
+#ifdef O_CLOEXEC
+ if (oflag & O_CLOEXEC)
+ fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | O_CLOEXEC);
+#endif
+ state->fd = fd;
+ }
if (state->fd == -1) {
free(state->path);
free(state);
@@ -359,9 +387,10 @@ z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
/* normalize offset to a SEEK_CUR specification */
if (whence == SEEK_SET)
offset -= state->x.pos;
- else if (state->seek)
- offset += state->skip;
- state->seek = 0;
+ else {
+ offset += state->past ? 0 : state->skip;
+ state->skip = 0;
+ }
/* if within raw area while reading, just go there */
if (state->mode == GZ_READ && state->how == COPY &&
@@ -372,7 +401,7 @@ z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
state->x.have = 0;
state->eof = 0;
state->past = 0;
- state->seek = 0;
+ state->skip = 0;
gz_error(state, Z_OK, NULL);
state->strm.avail_in = 0;
state->x.pos += offset;
@@ -401,10 +430,7 @@ z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
}
/* request skip (if not zero) */
- if (offset) {
- state->seek = 1;
- state->skip = offset;
- }
+ state->skip = offset;
return state->x.pos + offset;
}
@@ -428,7 +454,7 @@ z_off64_t ZEXPORT gztell64(gzFile file) {
return -1;
/* return position */
- return state->x.pos + (state->seek ? state->skip : 0);
+ return state->x.pos + (state->past ? 0 : state->skip);
}
/* -- see zlib.h -- */
@@ -535,7 +561,7 @@ void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) {
}
/* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
- if (err != Z_OK && err != Z_BUF_ERROR)
+ if (err != Z_OK && err != Z_BUF_ERROR && !state->again)
state->x.have = 0;
/* set error code, and if no message, then done */
@@ -572,6 +598,7 @@ unsigned ZLIB_INTERNAL gz_intmax(void) {
return INT_MAX;
#else
unsigned p = 1, q;
+
do {
q = p;
p <<= 1;