mirror of
https://github.com/madler/zlib.git
synced 2026-01-26 08:17:53 +00:00
Support non-blocking devices in the gz* routines.
This commit is contained in:
parent
598130fd07
commit
81cc0bebed
1
gzguts.h
1
gzguts.h
@ -185,6 +185,7 @@ typedef struct {
|
||||
/* just for reading */
|
||||
int junk; /* -1 = start, 1 = junk candidate, 0 = in gzip */
|
||||
int how; /* 0: get header, 1: copy, 2: decompress */
|
||||
int again; /* true if EAGAIN or EWOULDBLOCK on last i/o */
|
||||
z_off64_t start; /* where the gzip data started, for rewinding */
|
||||
int eof; /* true if end of input file reached */
|
||||
int past; /* true if read requested past end */
|
||||
|
||||
34
gzlib.c
34
gzlib.c
@ -52,7 +52,7 @@ char ZLIB_INTERNAL *gz_strwinerror(DWORD error) {
|
||||
msgbuf[chars] = 0;
|
||||
}
|
||||
|
||||
wcstombs(buf, msgbuf, chars + 1); // assumes buf is big enough
|
||||
wcstombs(buf, msgbuf, chars + 1); /* assumes buf is big enough */
|
||||
LocalFree(msgbuf);
|
||||
}
|
||||
else {
|
||||
@ -76,6 +76,7 @@ local void gz_reset(gz_statep state) {
|
||||
}
|
||||
else /* for writing ... */
|
||||
state->reset = 0; /* no deflateReset 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 */
|
||||
@ -86,10 +87,7 @@ 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
|
||||
@ -135,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
|
||||
@ -158,6 +156,11 @@ local gzFile gz_open(const void *path, int fd, const char *mode) {
|
||||
case 'G':
|
||||
state->direct = -1;
|
||||
break;
|
||||
#ifdef O_NONBLOCK
|
||||
case 'N':
|
||||
oflag |= O_NONBLOCK;
|
||||
break;
|
||||
#endif
|
||||
case 'T':
|
||||
state->direct = 1;
|
||||
break;
|
||||
@ -223,15 +226,12 @@ local gzFile gz_open(const void *path, int fd, const char *mode) {
|
||||
}
|
||||
|
||||
/* 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 :
|
||||
@ -250,8 +250,17 @@ local gzFile gz_open(const void *path, int fd, const char *mode) {
|
||||
else if (fd == -2)
|
||||
state->fd = _wopen(path, oflag, _S_IREAD | _S_IWRITE);
|
||||
#endif
|
||||
else
|
||||
else {
|
||||
#ifdef O_NONBLOCK
|
||||
if (oflag & O_NONBLOCK)
|
||||
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
|
||||
#endif
|
||||
#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);
|
||||
@ -552,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 */
|
||||
@ -589,6 +598,7 @@ unsigned ZLIB_INTERNAL gz_intmax(void) {
|
||||
return INT_MAX;
|
||||
#else
|
||||
unsigned p = 1, q;
|
||||
|
||||
do {
|
||||
q = p;
|
||||
p <<= 1;
|
||||
|
||||
125
gzread.c
125
gzread.c
@ -8,12 +8,20 @@
|
||||
/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from
|
||||
state->fd, and update state->eof, state->err, and state->msg as appropriate.
|
||||
This function needs to loop on read(), since read() is not guaranteed to
|
||||
read the number of bytes requested, depending on the type of descriptor. */
|
||||
read the number of bytes requested, depending on the type of descriptor. It
|
||||
also needs to loop to manage the fact that read() returns an int. If the
|
||||
descriptor is non-blocking and read() returns with no data in order to avoid
|
||||
blocking, then gz_load() will return 0 if some data has been read, or -1 if
|
||||
no data has been read. Either way, state->again is set true to indicate a
|
||||
non-blocking event. If errno is non-zero on return, then there was an error
|
||||
signaled from read(). *have is set to the number of bytes read. */
|
||||
local int gz_load(gz_statep state, unsigned char *buf, unsigned len,
|
||||
unsigned *have) {
|
||||
int ret;
|
||||
unsigned get, max = ((unsigned)-1 >> 2) + 1;
|
||||
|
||||
state->again = 0;
|
||||
errno = 0;
|
||||
*have = 0;
|
||||
do {
|
||||
get = len - *have;
|
||||
@ -25,6 +33,11 @@ local int gz_load(gz_statep state, unsigned char *buf, unsigned len,
|
||||
*have += (unsigned)ret;
|
||||
} while (*have < len);
|
||||
if (ret < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
state->again = 1;
|
||||
if (*have != 0)
|
||||
return 0;
|
||||
}
|
||||
gz_error(state, Z_ERRNO, zstrerror());
|
||||
return -1;
|
||||
}
|
||||
@ -50,8 +63,10 @@ local int gz_avail(gz_statep state) {
|
||||
if (strm->avail_in) { /* copy what's there to the start */
|
||||
unsigned char *p = state->in;
|
||||
unsigned const char *q = strm->next_in;
|
||||
|
||||
if (q != p) {
|
||||
unsigned n = strm->avail_in;
|
||||
|
||||
do {
|
||||
*p++ = *q++;
|
||||
} while (--n);
|
||||
@ -125,7 +140,9 @@ local int gz_look(gz_statep state) {
|
||||
then it's not an error as this is a transparent read of zero bytes */
|
||||
if (gz_avail(state) == -1)
|
||||
return -1;
|
||||
if (strm->avail_in == 0)
|
||||
if (strm->avail_in == 0 || (state->again && strm->avail_in < 4))
|
||||
/* if non-blocking input stalled before getting four bytes, then
|
||||
return and wait until a later call has accumulated enough */
|
||||
return 0;
|
||||
|
||||
/* see if this is (likely) gzip input -- if the first four bytes are
|
||||
@ -154,9 +171,12 @@ local int gz_look(gz_statep state) {
|
||||
|
||||
/* Decompress from input to the provided next_out and avail_out in the state.
|
||||
On return, state->x.have and state->x.next point to the just decompressed
|
||||
data. If the gzip stream completes, state->how is reset to LOOK to look for
|
||||
the next gzip stream or raw data, once state->x.have is depleted. Returns 0
|
||||
on success, -1 on failure. */
|
||||
data. If the gzip stream completes, state->how is reset to LOOK to look for
|
||||
the next gzip stream or raw data, once state->x.have is depleted. Returns 0
|
||||
on success, -1 on failure. If EOF is reached when looking for more input to
|
||||
complete the gzip member, then an unexpected end of file error is raised.
|
||||
If there is no more input, but state->again is true, then EOF has not been
|
||||
reached, and no error is raised. */
|
||||
local int gz_decomp(gz_statep state) {
|
||||
int ret = Z_OK;
|
||||
unsigned had;
|
||||
@ -171,7 +191,8 @@ local int gz_decomp(gz_statep state) {
|
||||
break;
|
||||
}
|
||||
if (strm->avail_in == 0) {
|
||||
gz_error(state, Z_BUF_ERROR, "unexpected end of file");
|
||||
if (!state->again)
|
||||
gz_error(state, Z_BUF_ERROR, "unexpected end of file");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -371,16 +392,18 @@ local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) {
|
||||
int ZEXPORT gzread(gzFile file, voidp buf, unsigned len) {
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure */
|
||||
/* get internal structure and check that it's for reading */
|
||||
if (file == NULL)
|
||||
return -1;
|
||||
state = (gz_statep)file;
|
||||
|
||||
/* check that we're reading and that there's no (serious) error */
|
||||
if (state->mode != GZ_READ ||
|
||||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
|
||||
if (state->mode != GZ_READ)
|
||||
return -1;
|
||||
|
||||
/* check that there was no (serious) error */
|
||||
if (state->err != Z_OK && state->err != Z_BUF_ERROR && !state->again)
|
||||
return -1;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* since an int is returned, make sure len fits in one, otherwise return
|
||||
with an error (this avoids a flaw in the interface) */
|
||||
if ((int)len < 0) {
|
||||
@ -389,13 +412,22 @@ int ZEXPORT gzread(gzFile file, voidp buf, unsigned len) {
|
||||
}
|
||||
|
||||
/* read len or fewer bytes to buf */
|
||||
len = (unsigned)gz_read(state, buf, len);
|
||||
len = gz_read(state, buf, len);
|
||||
|
||||
/* check for an error */
|
||||
if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR)
|
||||
return -1;
|
||||
if (len == 0) {
|
||||
if (state->err != Z_OK && state->err != Z_BUF_ERROR)
|
||||
return -1;
|
||||
if (state->again) {
|
||||
/* non-blocking input stalled after some input was read, but no
|
||||
uncompressed bytes were produced -- let the application know
|
||||
this isn't EOF */
|
||||
gz_error(state, Z_ERRNO, zstrerror());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* return the number of bytes read (this is assured to fit in an int) */
|
||||
/* return the number of bytes read */
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
@ -405,16 +437,18 @@ z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems,
|
||||
z_size_t len;
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure */
|
||||
/* get internal structure and check that it's for reading */
|
||||
if (file == NULL)
|
||||
return 0;
|
||||
state = (gz_statep)file;
|
||||
|
||||
/* check that we're reading and that there's no (serious) error */
|
||||
if (state->mode != GZ_READ ||
|
||||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
|
||||
if (state->mode != GZ_READ)
|
||||
return 0;
|
||||
|
||||
/* check that there was no (serious) error */
|
||||
if (state->err != Z_OK && state->err != Z_BUF_ERROR && !state->again)
|
||||
return 0;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* compute bytes to read -- error on overflow */
|
||||
len = nitems * size;
|
||||
if (size && len / size != nitems) {
|
||||
@ -436,16 +470,18 @@ int ZEXPORT gzgetc(gzFile file) {
|
||||
unsigned char buf[1];
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure */
|
||||
/* get internal structure and check that it's for reading */
|
||||
if (file == NULL)
|
||||
return -1;
|
||||
state = (gz_statep)file;
|
||||
|
||||
/* check that we're reading and that there's no (serious) error */
|
||||
if (state->mode != GZ_READ ||
|
||||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
|
||||
if (state->mode != GZ_READ)
|
||||
return -1;
|
||||
|
||||
/* check that there was no (serious) error */
|
||||
if (state->err != Z_OK && state->err != Z_BUF_ERROR && !state->again)
|
||||
return -1;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* try output buffer (no need to check for skip request) */
|
||||
if (state->x.have) {
|
||||
state->x.have--;
|
||||
@ -465,19 +501,21 @@ int ZEXPORT gzgetc_(gzFile file) {
|
||||
int ZEXPORT gzungetc(int c, gzFile file) {
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure */
|
||||
/* get internal structure and check that it's for reading */
|
||||
if (file == NULL)
|
||||
return -1;
|
||||
state = (gz_statep)file;
|
||||
if (state->mode != GZ_READ)
|
||||
return -1;
|
||||
|
||||
/* in case this was just opened, set up the input buffer */
|
||||
if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
|
||||
if (state->how == LOOK && state->x.have == 0)
|
||||
(void)gz_look(state);
|
||||
|
||||
/* check that we're reading and that there's no (serious) error */
|
||||
if (state->mode != GZ_READ ||
|
||||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
|
||||
/* check that there was no (serious) error */
|
||||
if (state->err != Z_OK && state->err != Z_BUF_ERROR && !state->again)
|
||||
return -1;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* process a skip request */
|
||||
if (state->skip && gz_skip(state) == -1)
|
||||
@ -507,6 +545,7 @@ int ZEXPORT gzungetc(int c, gzFile file) {
|
||||
if (state->x.next == state->out) {
|
||||
unsigned char *src = state->out + state->x.have;
|
||||
unsigned char *dest = state->out + (state->size << 1);
|
||||
|
||||
while (src > state->out)
|
||||
*--dest = *--src;
|
||||
state->x.next = dest;
|
||||
@ -526,23 +565,25 @@ char * ZEXPORT gzgets(gzFile file, char *buf, int len) {
|
||||
unsigned char *eol;
|
||||
gz_statep state;
|
||||
|
||||
/* check parameters and get internal structure */
|
||||
/* check parameters, get internal structure, and check that it's for
|
||||
reading */
|
||||
if (file == NULL || buf == NULL || len < 1)
|
||||
return NULL;
|
||||
state = (gz_statep)file;
|
||||
|
||||
/* check that we're reading and that there's no (serious) error */
|
||||
if (state->mode != GZ_READ ||
|
||||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
|
||||
if (state->mode != GZ_READ)
|
||||
return NULL;
|
||||
|
||||
/* check that there was no (serious) error */
|
||||
if (state->err != Z_OK && state->err != Z_BUF_ERROR && !state->again)
|
||||
return NULL;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* process a skip request */
|
||||
if (state->skip && gz_skip(state) == -1)
|
||||
return NULL;
|
||||
|
||||
/* copy output bytes up to new line or len - 1, whichever comes first --
|
||||
append a terminating zero to the string (we don't check for a zero in
|
||||
the contents, let the user worry about that) */
|
||||
/* copy output up to a new line, len-1 bytes, or there is no more output,
|
||||
whichever comes first */
|
||||
str = buf;
|
||||
left = (unsigned)len - 1;
|
||||
if (left) do {
|
||||
@ -569,7 +610,9 @@ char * ZEXPORT gzgets(gzFile file, char *buf, int len) {
|
||||
buf += n;
|
||||
} while (left && eol == NULL);
|
||||
|
||||
/* return terminated string, or if nothing, end of file */
|
||||
/* append a terminating zero to the string (we don't check for a zero in
|
||||
the contents, let the user worry about that) -- return the terminated
|
||||
string, or if nothing was read, NULL */
|
||||
if (buf == str)
|
||||
return NULL;
|
||||
buf[0] = 0;
|
||||
@ -599,12 +642,10 @@ int ZEXPORT gzclose_r(gzFile file) {
|
||||
int ret, err;
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure */
|
||||
/* get internal structure and check that it's for reading */
|
||||
if (file == NULL)
|
||||
return Z_STREAM_ERROR;
|
||||
state = (gz_statep)file;
|
||||
|
||||
/* check that we're reading */
|
||||
if (state->mode != GZ_READ)
|
||||
return Z_STREAM_ERROR;
|
||||
|
||||
|
||||
167
gzwrite.c
167
gzwrite.c
@ -74,9 +74,13 @@ local int gz_comp(gz_statep state, int flush) {
|
||||
/* write directly if requested */
|
||||
if (state->direct) {
|
||||
while (strm->avail_in) {
|
||||
errno = 0;
|
||||
state->again = 0;
|
||||
put = strm->avail_in > max ? max : strm->avail_in;
|
||||
writ = write(state->fd, strm->next_in, put);
|
||||
if (writ < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
state->again = 1;
|
||||
gz_error(state, Z_ERRNO, zstrerror());
|
||||
return -1;
|
||||
}
|
||||
@ -104,10 +108,14 @@ local int gz_comp(gz_statep state, int flush) {
|
||||
if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
|
||||
(flush != Z_FINISH || ret == Z_STREAM_END))) {
|
||||
while (strm->next_out > state->x.next) {
|
||||
errno = 0;
|
||||
state->again = 0;
|
||||
put = strm->next_out - state->x.next > (int)max ? max :
|
||||
(unsigned)(strm->next_out - state->x.next);
|
||||
writ = write(state->fd, state->x.next, put);
|
||||
if (writ < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
state->again = 1;
|
||||
gz_error(state, Z_ERRNO, zstrerror());
|
||||
return -1;
|
||||
}
|
||||
@ -140,9 +148,11 @@ local int gz_comp(gz_statep state, int flush) {
|
||||
}
|
||||
|
||||
/* Compress state->skip (> 0) zeros to output. Return -1 on a write error or
|
||||
memory allocation failure by gz_comp(), or 0 on success. */
|
||||
memory allocation failure by gz_comp(), or 0 on success. state->skip is
|
||||
updated with the number of successfully written zeros, in case there is a
|
||||
stall on a non-blocking write destination. */
|
||||
local int gz_zero(gz_statep state) {
|
||||
int first;
|
||||
int first, ret;
|
||||
unsigned n;
|
||||
z_streamp strm = &(state->strm);
|
||||
|
||||
@ -161,18 +171,23 @@ local int gz_zero(gz_statep state) {
|
||||
}
|
||||
strm->avail_in = n;
|
||||
strm->next_in = state->in;
|
||||
ret = gz_comp(state, Z_NO_FLUSH);
|
||||
n -= strm->avail_in;
|
||||
state->x.pos += n;
|
||||
if (gz_comp(state, Z_NO_FLUSH) == -1)
|
||||
return -1;
|
||||
state->skip -= n;
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
} while (state->skip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write len bytes from buf to file. Return the number of bytes written. If
|
||||
the returned value is less than len, then there was an error. */
|
||||
the returned value is less than len, then there was an error. If the error
|
||||
was a non-blocking stall, then the number of bytes consumed is returned.
|
||||
For any other error, 0 is returned. */
|
||||
local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
|
||||
z_size_t put = len;
|
||||
int ret;
|
||||
|
||||
/* if len is zero, avoid unnecessary operations */
|
||||
if (len == 0)
|
||||
@ -189,7 +204,7 @@ local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
|
||||
/* for small len, copy to input buffer, otherwise compress directly */
|
||||
if (len < state->size) {
|
||||
/* copy to input buffer, compress when full */
|
||||
do {
|
||||
for (;;) {
|
||||
unsigned have, copy;
|
||||
|
||||
if (state->strm.avail_in == 0)
|
||||
@ -204,9 +219,11 @@ local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
|
||||
state->x.pos += copy;
|
||||
buf = (const char *)buf + copy;
|
||||
len -= copy;
|
||||
if (len && gz_comp(state, Z_NO_FLUSH) == -1)
|
||||
return 0;
|
||||
} while (len);
|
||||
if (len == 0)
|
||||
break;
|
||||
if (gz_comp(state, Z_NO_FLUSH) == -1)
|
||||
return state->again ? put - len : 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* consume whatever's left in the input buffer */
|
||||
@ -217,13 +234,16 @@ local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
|
||||
state->strm.next_in = (z_const Bytef *)buf;
|
||||
do {
|
||||
unsigned n = (unsigned)-1;
|
||||
|
||||
if (n > len)
|
||||
n = (unsigned)len;
|
||||
state->strm.avail_in = n;
|
||||
ret = gz_comp(state, Z_NO_FLUSH);
|
||||
n -= state->strm.avail_in;
|
||||
state->x.pos += n;
|
||||
if (gz_comp(state, Z_NO_FLUSH) == -1)
|
||||
return 0;
|
||||
len -= n;
|
||||
if (ret == -1)
|
||||
return state->again ? put - len : 0;
|
||||
} while (len);
|
||||
}
|
||||
|
||||
@ -240,9 +260,10 @@ int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len) {
|
||||
return 0;
|
||||
state = (gz_statep)file;
|
||||
|
||||
/* check that we're writing and that there's no error */
|
||||
if (state->mode != GZ_WRITE || state->err != Z_OK)
|
||||
/* check that we're writing and that there's no (serious) error */
|
||||
if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
|
||||
return 0;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* since an int is returned, make sure len fits in one, otherwise return
|
||||
with an error (this avoids a flaw in the interface) */
|
||||
@ -266,9 +287,10 @@ z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, z_size_t nitems,
|
||||
return 0;
|
||||
state = (gz_statep)file;
|
||||
|
||||
/* check that we're writing and that there's no error */
|
||||
if (state->mode != GZ_WRITE || state->err != Z_OK)
|
||||
/* check that we're writing and that there's no (serious) error */
|
||||
if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
|
||||
return 0;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* compute bytes to read -- error on overflow */
|
||||
len = nitems * size;
|
||||
@ -294,9 +316,10 @@ int ZEXPORT gzputc(gzFile file, int c) {
|
||||
state = (gz_statep)file;
|
||||
strm = &(state->strm);
|
||||
|
||||
/* check that we're writing and that there's no error */
|
||||
if (state->mode != GZ_WRITE || state->err != Z_OK)
|
||||
/* check that we're writing and that there's no (serious) error */
|
||||
if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
|
||||
return -1;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* check for seek request */
|
||||
if (state->skip && gz_zero(state) == -1)
|
||||
@ -333,9 +356,10 @@ int ZEXPORT gzputs(gzFile file, const char *s) {
|
||||
return -1;
|
||||
state = (gz_statep)file;
|
||||
|
||||
/* check that we're writing and that there's no error */
|
||||
if (state->mode != GZ_WRITE || state->err != Z_OK)
|
||||
/* check that we're writing and that there's no (serious) error */
|
||||
if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
|
||||
return -1;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* write string */
|
||||
len = strlen(s);
|
||||
@ -344,7 +368,28 @@ int ZEXPORT gzputs(gzFile file, const char *s) {
|
||||
return -1;
|
||||
}
|
||||
put = gz_write(state, s, len);
|
||||
return put < len ? -1 : (int)len;
|
||||
return len && put == 0 ? -1 : (int)put;
|
||||
}
|
||||
|
||||
/* If the second half of the input buffer is occupied, write out the contents.
|
||||
If there is any input remaining due to a non-blocking stall on write, move
|
||||
it to the start of the buffer. Return true if this did not open up the
|
||||
second half of the buffer. state->err should be checked after this to
|
||||
handle a gz_comp() error. */
|
||||
local int gz_vacate(gz_statep state) {
|
||||
z_streamp strm;
|
||||
|
||||
strm = &(state->strm);
|
||||
if ((strm->next_in + strm->avail_in) - state->in <= state->size)
|
||||
return 0;
|
||||
(void)gz_comp(state, Z_NO_FLUSH);
|
||||
if (strm->avail_in == 0) {
|
||||
strm->next_in = state->in;
|
||||
return 0;
|
||||
}
|
||||
memmove(state->in, strm->next_in, strm->avail_in);
|
||||
strm->next_in = state->in;
|
||||
return strm->avail_in > state->size;
|
||||
}
|
||||
|
||||
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
|
||||
@ -352,8 +397,7 @@ int ZEXPORT gzputs(gzFile file, const char *s) {
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) {
|
||||
int len;
|
||||
unsigned left;
|
||||
int len, ret;
|
||||
char *next;
|
||||
gz_statep state;
|
||||
z_streamp strm;
|
||||
@ -364,9 +408,10 @@ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) {
|
||||
state = (gz_statep)file;
|
||||
strm = &(state->strm);
|
||||
|
||||
/* check that we're writing and that there's no error */
|
||||
if (state->mode != GZ_WRITE || state->err != Z_OK)
|
||||
/* check that we're writing and that there's no (serious) error */
|
||||
if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
|
||||
return Z_STREAM_ERROR;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* make sure we have some buffer space */
|
||||
if (state->size == 0 && gz_init(state) == -1)
|
||||
@ -377,8 +422,20 @@ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) {
|
||||
return state->err;
|
||||
|
||||
/* do the printf() into the input buffer, put length in len -- the input
|
||||
buffer is double-sized just for this function, so there is guaranteed to
|
||||
be state->size bytes available after the current contents */
|
||||
buffer is double-sized just for this function, so there should be
|
||||
state->size bytes available after the current contents */
|
||||
ret = gz_vacate(state);
|
||||
if (state->err) {
|
||||
if (ret && state->again) {
|
||||
/* There was a non-blocking stall on write, resulting in the part
|
||||
of the second half of the output buffer being occupied. Return
|
||||
a Z_BUF_ERROR to let the application know that this gzprintf()
|
||||
needs to be retried. */
|
||||
gz_error(state, Z_BUF_ERROR, "stalled write on gzprintf");
|
||||
}
|
||||
if (!state->again)
|
||||
return state->err;
|
||||
}
|
||||
if (strm->avail_in == 0)
|
||||
strm->next_in = state->in;
|
||||
next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in);
|
||||
@ -404,18 +461,14 @@ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) {
|
||||
if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0)
|
||||
return 0;
|
||||
|
||||
/* update buffer and position, compress first half if past that */
|
||||
/* update buffer and position */
|
||||
strm->avail_in += (unsigned)len;
|
||||
state->x.pos += len;
|
||||
if (strm->avail_in >= state->size) {
|
||||
left = strm->avail_in - state->size;
|
||||
strm->avail_in = state->size;
|
||||
if (gz_comp(state, Z_NO_FLUSH) == -1)
|
||||
return state->err;
|
||||
memmove(state->in, state->in + state->size, left);
|
||||
strm->next_in = state->in;
|
||||
strm->avail_in = left;
|
||||
}
|
||||
|
||||
/* write out buffer if more than half is occupied */
|
||||
ret = gz_vacate(state);
|
||||
if (state->err && !state->again)
|
||||
return state->err;
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -451,9 +504,10 @@ int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3,
|
||||
if (sizeof(int) != sizeof(void *))
|
||||
return Z_STREAM_ERROR;
|
||||
|
||||
/* check that we're writing and that there's no error */
|
||||
if (state->mode != GZ_WRITE || state->err != Z_OK)
|
||||
/* check that we're writing and that there's no (serious) error */
|
||||
if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
|
||||
return Z_STREAM_ERROR;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* make sure we have some buffer space */
|
||||
if (state->size == 0 && gz_init(state) == -1)
|
||||
@ -466,6 +520,18 @@ int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3,
|
||||
/* do the printf() into the input buffer, put length in len -- the input
|
||||
buffer is double-sized just for this function, so there is guaranteed to
|
||||
be state->size bytes available after the current contents */
|
||||
ret = gz_vacate(state);
|
||||
if (state->err) {
|
||||
if (ret && state->again) {
|
||||
/* There was a non-blocking stall on write, resulting in the part
|
||||
of the second half of the output buffer being occupied. Return
|
||||
a Z_BUF_ERROR to let the application know that this gzprintf()
|
||||
needs to be retried. */
|
||||
gz_error(state, Z_BUF_ERROR, "stalled write on gzprintf");
|
||||
}
|
||||
if (!state->again)
|
||||
return state->err;
|
||||
}
|
||||
if (strm->avail_in == 0)
|
||||
strm->next_in = state->in;
|
||||
next = (char *)(strm->next_in + strm->avail_in);
|
||||
@ -499,15 +565,11 @@ int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3,
|
||||
/* update buffer and position, compress first half if past that */
|
||||
strm->avail_in += len;
|
||||
state->x.pos += len;
|
||||
if (strm->avail_in >= state->size) {
|
||||
left = strm->avail_in - state->size;
|
||||
strm->avail_in = state->size;
|
||||
if (gz_comp(state, Z_NO_FLUSH) == -1)
|
||||
return state->err;
|
||||
memmove(state->in, state->in + state->size, left);
|
||||
strm->next_in = state->in;
|
||||
strm->avail_in = left;
|
||||
}
|
||||
|
||||
/* write out buffer if more than half is occupied */
|
||||
ret = gz_vacate(state);
|
||||
if (state->err && !state->again)
|
||||
return state->err;
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
@ -522,9 +584,10 @@ int ZEXPORT gzflush(gzFile file, int flush) {
|
||||
return Z_STREAM_ERROR;
|
||||
state = (gz_statep)file;
|
||||
|
||||
/* check that we're writing and that there's no error */
|
||||
if (state->mode != GZ_WRITE || state->err != Z_OK)
|
||||
/* check that we're writing and that there's no (serious) error */
|
||||
if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
|
||||
return Z_STREAM_ERROR;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* check flush parameter */
|
||||
if (flush < 0 || flush > Z_FINISH)
|
||||
@ -550,9 +613,11 @@ int ZEXPORT gzsetparams(gzFile file, int level, int strategy) {
|
||||
state = (gz_statep)file;
|
||||
strm = &(state->strm);
|
||||
|
||||
/* check that we're writing and that there's no error */
|
||||
if (state->mode != GZ_WRITE || state->err != Z_OK || state->direct)
|
||||
/* check that we're compressing and that there's no (serious) error */
|
||||
if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again) ||
|
||||
state->direct)
|
||||
return Z_STREAM_ERROR;
|
||||
gz_error(state, Z_OK, NULL);
|
||||
|
||||
/* if no change is requested, then do nothing */
|
||||
if (level == state->level && strategy == state->strategy)
|
||||
|
||||
73
zlib.h
73
zlib.h
@ -1349,13 +1349,13 @@ ZEXTERN gzFile ZEXPORT gzopen(const char *path, const char *mode);
|
||||
used to force transparent reading. Transparent reading is automatically
|
||||
performed if there is no gzip header at the start. Transparent reading can
|
||||
be disabled with the 'G' option, which will instead return an error if there
|
||||
is no gzip header.
|
||||
is no gzip header. 'N' will open the file in non-blocking mode.
|
||||
|
||||
"a" can be used instead of "w" to request that the gzip stream that will
|
||||
be written be appended to the file. "+" will result in an error, since
|
||||
'a' can be used instead of 'w' to request that the gzip stream that will
|
||||
be written be appended to the file. '+' will result in an error, since
|
||||
reading and writing to the same gzip file is not supported. The addition of
|
||||
"x" when writing will create the file exclusively, which fails if the file
|
||||
already exists. On systems that support it, the addition of "e" when
|
||||
'x' when writing will create the file exclusively, which fails if the file
|
||||
already exists. On systems that support it, the addition of 'e' when
|
||||
reading or writing will set the flag to close the file on an execve() call.
|
||||
|
||||
These functions, as well as gzip, will read and decode a sequence of gzip
|
||||
@ -1374,14 +1374,22 @@ ZEXTERN gzFile ZEXPORT gzopen(const char *path, const char *mode);
|
||||
insufficient memory to allocate the gzFile state, or if an invalid mode was
|
||||
specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
|
||||
errno can be checked to determine if the reason gzopen failed was that the
|
||||
file could not be opened.
|
||||
file could not be opened. Note that if 'N' is in mode for non-blocking, the
|
||||
open() itself can fail in order to not block. In that case gzopen() will
|
||||
return NULL and errno will be EAGAIN or ENONBLOCK. The call to gzopen() can
|
||||
then be re-tried. If the application would like to block on opening the
|
||||
file, then it can use open() without O_NONBLOCK, and then gzdopen() with the
|
||||
resulting file descriptor and 'N' in the mode, which will set it to non-
|
||||
blocking.
|
||||
*/
|
||||
|
||||
ZEXTERN gzFile ZEXPORT gzdopen(int fd, const char *mode);
|
||||
/*
|
||||
Associate a gzFile with the file descriptor fd. File descriptors are
|
||||
obtained from calls like open, dup, creat, pipe or fileno (if the file has
|
||||
been previously opened with fopen). The mode parameter is as in gzopen.
|
||||
been previously opened with fopen). The mode parameter is as in gzopen. An
|
||||
'e' in mode will set fd's flag to close the file on an execve() call. An 'N'
|
||||
in mode will set fd's non-blocking flag.
|
||||
|
||||
The next call of gzclose on the returned gzFile will also close the file
|
||||
descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
|
||||
@ -1451,6 +1459,11 @@ ZEXTERN int ZEXPORT gzread(gzFile file, voidp buf, unsigned len);
|
||||
stream. Alternatively, gzerror can be used before gzclose to detect this
|
||||
case.
|
||||
|
||||
gzread can be used to read a gzip file on a non-blocking device. If the
|
||||
input stalls and there is no uncompressed data to return, then gzread() will
|
||||
return -1, and errno will be EAGAIN or EWOULDBLOCK. gzread() can then be
|
||||
called again.
|
||||
|
||||
gzread returns the number of uncompressed bytes actually read, less than
|
||||
len for end of file, or -1 for error. If len is too large to fit in an int,
|
||||
then nothing is read, -1 is returned, and the error state is set to
|
||||
@ -1479,15 +1492,20 @@ ZEXTERN z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems,
|
||||
multiple of size, then the final partial item is nevertheless read into buf
|
||||
and the end-of-file flag is set. The length of the partial item read is not
|
||||
provided, but could be inferred from the result of gztell(). This behavior
|
||||
is the same as the behavior of fread() implementations in common libraries,
|
||||
but it prevents the direct use of gzfread() to read a concurrently written
|
||||
file, resetting and retrying on end-of-file, when size is not 1.
|
||||
is the same as that of fread() implementations in common libraries. This
|
||||
could result in data loss if used with size != 1 when reading a concurrently
|
||||
written file or a non-blocking file. In that case, use size == 1 or gzread()
|
||||
instead.
|
||||
*/
|
||||
|
||||
ZEXTERN int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len);
|
||||
/*
|
||||
Compress and write the len uncompressed bytes at buf to file. gzwrite
|
||||
returns the number of uncompressed bytes written or 0 in case of error.
|
||||
returns the number of uncompressed bytes written, or 0 in case of error or
|
||||
if len is 0. If the write destination is non-blocking, then gzwrite() may
|
||||
return a number of bytes written that is not 0 and less than len.
|
||||
|
||||
If len does not fit in an int, then 0 is returned and nothing is written.
|
||||
*/
|
||||
|
||||
ZEXTERN z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size,
|
||||
@ -1502,6 +1520,11 @@ ZEXTERN z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size,
|
||||
if there was an error. If the multiplication of size and nitems overflows,
|
||||
i.e. the product does not fit in a z_size_t, then nothing is written, zero
|
||||
is returned, and the error state is set to Z_STREAM_ERROR.
|
||||
|
||||
If writing a concurrently read file or a non-blocking file with size != 1,
|
||||
a partial item could be written, with no way of knowing how much of it was
|
||||
not written, resulting in data loss. In that case, use size == 1 or
|
||||
gzwrite() instead.
|
||||
*/
|
||||
|
||||
ZEXTERN int ZEXPORTVA gzprintf(gzFile file, const char *format, ...);
|
||||
@ -1517,6 +1540,9 @@ ZEXTERN int ZEXPORTVA gzprintf(gzFile file, const char *format, ...);
|
||||
zlib was compiled with the insecure functions sprintf() or vsprintf(),
|
||||
because the secure snprintf() or vsnprintf() functions were not available.
|
||||
This can be determined using zlibCompileFlags().
|
||||
|
||||
If a Z_BUF_ERROR is returned, then nothing was written due to a stall on
|
||||
the non-blocking write destination.
|
||||
*/
|
||||
|
||||
ZEXTERN int ZEXPORT gzputs(gzFile file, const char *s);
|
||||
@ -1525,6 +1551,11 @@ ZEXTERN int ZEXPORT gzputs(gzFile file, const char *s);
|
||||
the terminating null character.
|
||||
|
||||
gzputs returns the number of characters written, or -1 in case of error.
|
||||
The number of characters written may be less than the length of the string
|
||||
if the write destination is non-blocking.
|
||||
|
||||
If the length of the string does not fit in an int, then -1 is returned
|
||||
and nothing is written.
|
||||
*/
|
||||
|
||||
ZEXTERN char * ZEXPORT gzgets(gzFile file, char *buf, int len);
|
||||
@ -1540,6 +1571,10 @@ ZEXTERN char * ZEXPORT gzgets(gzFile file, char *buf, int len);
|
||||
for end-of-file or in case of error. If some data was read before an error,
|
||||
then that data is returned until exhausted, after which the next call will
|
||||
return NULL to signal the error.
|
||||
|
||||
gzgets can be used on a file being concurrently written, and on a non-
|
||||
blocking device, both as for gzread(). However lines may be broken in the
|
||||
middle, leaving it up to the application to reassemble them as needed.
|
||||
*/
|
||||
|
||||
ZEXTERN int ZEXPORT gzputc(gzFile file, int c);
|
||||
@ -1550,14 +1585,19 @@ ZEXTERN int ZEXPORT gzputc(gzFile file, int c);
|
||||
|
||||
ZEXTERN int ZEXPORT gzgetc(gzFile file);
|
||||
/*
|
||||
Read and decompress one byte from file. gzgetc returns this byte or -1 in
|
||||
Read and decompress one byte from file. gzgetc returns this byte or -1 in
|
||||
case of end of file or error. If some data was read before an error, then
|
||||
that data is returned until exhausted, after which the next call will return
|
||||
-1 to signal the error.
|
||||
|
||||
This is implemented as a macro for speed. As such, it does not do all of
|
||||
This is implemented as a macro for speed. As such, it does not do all of
|
||||
the checking the other functions do. I.e. it does not check to see if file
|
||||
is NULL, nor whether the structure file points to has been clobbered or not.
|
||||
|
||||
gzgetc can be used to read a gzip file on a non-blocking device. If the
|
||||
input stalls and there is no uncompressed data to return, then gzgetc() will
|
||||
return -1, and errno will be EAGAIN or EWOULDBLOCK. gzread() can then be
|
||||
called again.
|
||||
*/
|
||||
|
||||
ZEXTERN int ZEXPORT gzungetc(int c, gzFile file);
|
||||
@ -1666,8 +1706,11 @@ ZEXTERN int ZEXPORT gzdirect(gzFile file);
|
||||
|
||||
If gzdirect() is used immediately after gzopen() or gzdopen() it will
|
||||
cause buffers to be allocated to allow reading the file to determine if it
|
||||
is a gzip file. Therefore if gzbuffer() is used, it should be called before
|
||||
gzdirect().
|
||||
is a gzip file. Therefore if gzbuffer() is used, it should be called before
|
||||
gzdirect(). If the input is being written concurrently or the device is non-
|
||||
blocking, then gzdirect() may give a different answer once four bytes of
|
||||
input have been accumulated, which is what is needed to confirm or deny a
|
||||
gzip header. Before this, gzdirect() will return true (1).
|
||||
|
||||
When writing, gzdirect() returns true (1) if transparent writing was
|
||||
requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user