aboutsummaryrefslogtreecommitdiff
path: root/gzread.c
diff options
context:
space:
mode:
authorMark Adler <git@madler.net>2025-05-25 19:01:36 -0700
committerMark Adler <git@madler.net>2025-12-08 03:52:25 -0800
commit81cc0bebedd935daeb81b0b6e475d8786b51af3d (patch)
treedbd05e0ccc349d0ab90d20374716fb400d383e68 /gzread.c
parent598130fd078f7b712498d348cf94b4b9806c4435 (diff)
downloadzlib-81cc0bebedd935daeb81b0b6e475d8786b51af3d.tar.gz
zlib-81cc0bebedd935daeb81b0b6e475d8786b51af3d.tar.bz2
zlib-81cc0bebedd935daeb81b0b6e475d8786b51af3d.zip
Support non-blocking devices in the gz* routines.
Diffstat (limited to 'gzread.c')
-rw-r--r--gzread.c117
1 files changed, 79 insertions, 38 deletions
diff --git a/gzread.c b/gzread.c
index aca4186c..025657a4 100644
--- a/gzread.c
+++ b/gzread.c
@@ -8,12 +8,20 @@
8/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from 8/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from
9 state->fd, and update state->eof, state->err, and state->msg as appropriate. 9 state->fd, and update state->eof, state->err, and state->msg as appropriate.
10 This function needs to loop on read(), since read() is not guaranteed to 10 This function needs to loop on read(), since read() is not guaranteed to
11 read the number of bytes requested, depending on the type of descriptor. */ 11 read the number of bytes requested, depending on the type of descriptor. It
12 also needs to loop to manage the fact that read() returns an int. If the
13 descriptor is non-blocking and read() returns with no data in order to avoid
14 blocking, then gz_load() will return 0 if some data has been read, or -1 if
15 no data has been read. Either way, state->again is set true to indicate a
16 non-blocking event. If errno is non-zero on return, then there was an error
17 signaled from read(). *have is set to the number of bytes read. */
12local int gz_load(gz_statep state, unsigned char *buf, unsigned len, 18local int gz_load(gz_statep state, unsigned char *buf, unsigned len,
13 unsigned *have) { 19 unsigned *have) {
14 int ret; 20 int ret;
15 unsigned get, max = ((unsigned)-1 >> 2) + 1; 21 unsigned get, max = ((unsigned)-1 >> 2) + 1;
16 22
23 state->again = 0;
24 errno = 0;
17 *have = 0; 25 *have = 0;
18 do { 26 do {
19 get = len - *have; 27 get = len - *have;
@@ -25,6 +33,11 @@ local int gz_load(gz_statep state, unsigned char *buf, unsigned len,
25 *have += (unsigned)ret; 33 *have += (unsigned)ret;
26 } while (*have < len); 34 } while (*have < len);
27 if (ret < 0) { 35 if (ret < 0) {
36 if (errno == EAGAIN || errno == EWOULDBLOCK) {
37 state->again = 1;
38 if (*have != 0)
39 return 0;
40 }
28 gz_error(state, Z_ERRNO, zstrerror()); 41 gz_error(state, Z_ERRNO, zstrerror());
29 return -1; 42 return -1;
30 } 43 }
@@ -50,8 +63,10 @@ local int gz_avail(gz_statep state) {
50 if (strm->avail_in) { /* copy what's there to the start */ 63 if (strm->avail_in) { /* copy what's there to the start */
51 unsigned char *p = state->in; 64 unsigned char *p = state->in;
52 unsigned const char *q = strm->next_in; 65 unsigned const char *q = strm->next_in;
66
53 if (q != p) { 67 if (q != p) {
54 unsigned n = strm->avail_in; 68 unsigned n = strm->avail_in;
69
55 do { 70 do {
56 *p++ = *q++; 71 *p++ = *q++;
57 } while (--n); 72 } while (--n);
@@ -125,7 +140,9 @@ local int gz_look(gz_statep state) {
125 then it's not an error as this is a transparent read of zero bytes */ 140 then it's not an error as this is a transparent read of zero bytes */
126 if (gz_avail(state) == -1) 141 if (gz_avail(state) == -1)
127 return -1; 142 return -1;
128 if (strm->avail_in == 0) 143 if (strm->avail_in == 0 || (state->again && strm->avail_in < 4))
144 /* if non-blocking input stalled before getting four bytes, then
145 return and wait until a later call has accumulated enough */
129 return 0; 146 return 0;
130 147
131 /* see if this is (likely) gzip input -- if the first four bytes are 148 /* see if this is (likely) gzip input -- if the first four bytes are
@@ -154,9 +171,12 @@ local int gz_look(gz_statep state) {
154 171
155/* Decompress from input to the provided next_out and avail_out in the state. 172/* Decompress from input to the provided next_out and avail_out in the state.
156 On return, state->x.have and state->x.next point to the just decompressed 173 On return, state->x.have and state->x.next point to the just decompressed
157 data. If the gzip stream completes, state->how is reset to LOOK to look for 174 data. If the gzip stream completes, state->how is reset to LOOK to look for
158 the next gzip stream or raw data, once state->x.have is depleted. Returns 0 175 the next gzip stream or raw data, once state->x.have is depleted. Returns 0
159 on success, -1 on failure. */ 176 on success, -1 on failure. If EOF is reached when looking for more input to
177 complete the gzip member, then an unexpected end of file error is raised.
178 If there is no more input, but state->again is true, then EOF has not been
179 reached, and no error is raised. */
160local int gz_decomp(gz_statep state) { 180local int gz_decomp(gz_statep state) {
161 int ret = Z_OK; 181 int ret = Z_OK;
162 unsigned had; 182 unsigned had;
@@ -171,7 +191,8 @@ local int gz_decomp(gz_statep state) {
171 break; 191 break;
172 } 192 }
173 if (strm->avail_in == 0) { 193 if (strm->avail_in == 0) {
174 gz_error(state, Z_BUF_ERROR, "unexpected end of file"); 194 if (!state->again)
195 gz_error(state, Z_BUF_ERROR, "unexpected end of file");
175 break; 196 break;
176 } 197 }
177 198
@@ -371,15 +392,17 @@ local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) {
371int ZEXPORT gzread(gzFile file, voidp buf, unsigned len) { 392int ZEXPORT gzread(gzFile file, voidp buf, unsigned len) {
372 gz_statep state; 393 gz_statep state;
373 394
374 /* get internal structure */ 395 /* get internal structure and check that it's for reading */
375 if (file == NULL) 396 if (file == NULL)
376 return -1; 397 return -1;
377 state = (gz_statep)file; 398 state = (gz_statep)file;
399 if (state->mode != GZ_READ)
400 return -1;
378 401
379 /* check that we're reading and that there's no (serious) error */ 402 /* check that there was no (serious) error */
380 if (state->mode != GZ_READ || 403 if (state->err != Z_OK && state->err != Z_BUF_ERROR && !state->again)
381 (state->err != Z_OK && state->err != Z_BUF_ERROR))
382 return -1; 404 return -1;
405 gz_error(state, Z_OK, NULL);
383 406
384 /* since an int is returned, make sure len fits in one, otherwise return 407 /* since an int is returned, make sure len fits in one, otherwise return
385 with an error (this avoids a flaw in the interface) */ 408 with an error (this avoids a flaw in the interface) */
@@ -389,13 +412,22 @@ int ZEXPORT gzread(gzFile file, voidp buf, unsigned len) {
389 } 412 }
390 413
391 /* read len or fewer bytes to buf */ 414 /* read len or fewer bytes to buf */
392 len = (unsigned)gz_read(state, buf, len); 415 len = gz_read(state, buf, len);
393 416
394 /* check for an error */ 417 /* check for an error */
395 if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR) 418 if (len == 0) {
396 return -1; 419 if (state->err != Z_OK && state->err != Z_BUF_ERROR)
420 return -1;
421 if (state->again) {
422 /* non-blocking input stalled after some input was read, but no
423 uncompressed bytes were produced -- let the application know
424 this isn't EOF */
425 gz_error(state, Z_ERRNO, zstrerror());
426 return -1;
427 }
428 }
397 429
398 /* return the number of bytes read (this is assured to fit in an int) */ 430 /* return the number of bytes read */
399 return (int)len; 431 return (int)len;
400} 432}
401 433
@@ -405,15 +437,17 @@ z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems,
405 z_size_t len; 437 z_size_t len;
406 gz_statep state; 438 gz_statep state;
407 439
408 /* get internal structure */ 440 /* get internal structure and check that it's for reading */
409 if (file == NULL) 441 if (file == NULL)
410 return 0; 442 return 0;
411 state = (gz_statep)file; 443 state = (gz_statep)file;
444 if (state->mode != GZ_READ)
445 return 0;
412 446
413 /* check that we're reading and that there's no (serious) error */ 447 /* check that there was no (serious) error */
414 if (state->mode != GZ_READ || 448 if (state->err != Z_OK && state->err != Z_BUF_ERROR && !state->again)
415 (state->err != Z_OK && state->err != Z_BUF_ERROR))
416 return 0; 449 return 0;
450 gz_error(state, Z_OK, NULL);
417 451
418 /* compute bytes to read -- error on overflow */ 452 /* compute bytes to read -- error on overflow */
419 len = nitems * size; 453 len = nitems * size;
@@ -436,15 +470,17 @@ int ZEXPORT gzgetc(gzFile file) {
436 unsigned char buf[1]; 470 unsigned char buf[1];
437 gz_statep state; 471 gz_statep state;
438 472
439 /* get internal structure */ 473 /* get internal structure and check that it's for reading */
440 if (file == NULL) 474 if (file == NULL)
441 return -1; 475 return -1;
442 state = (gz_statep)file; 476 state = (gz_statep)file;
477 if (state->mode != GZ_READ)
478 return -1;
443 479
444 /* check that we're reading and that there's no (serious) error */ 480 /* check that there was no (serious) error */
445 if (state->mode != GZ_READ || 481 if (state->err != Z_OK && state->err != Z_BUF_ERROR && !state->again)
446 (state->err != Z_OK && state->err != Z_BUF_ERROR))
447 return -1; 482 return -1;
483 gz_error(state, Z_OK, NULL);
448 484
449 /* try output buffer (no need to check for skip request) */ 485 /* try output buffer (no need to check for skip request) */
450 if (state->x.have) { 486 if (state->x.have) {
@@ -465,19 +501,21 @@ int ZEXPORT gzgetc_(gzFile file) {
465int ZEXPORT gzungetc(int c, gzFile file) { 501int ZEXPORT gzungetc(int c, gzFile file) {
466 gz_statep state; 502 gz_statep state;
467 503
468 /* get internal structure */ 504 /* get internal structure and check that it's for reading */
469 if (file == NULL) 505 if (file == NULL)
470 return -1; 506 return -1;
471 state = (gz_statep)file; 507 state = (gz_statep)file;
508 if (state->mode != GZ_READ)
509 return -1;
472 510
473 /* in case this was just opened, set up the input buffer */ 511 /* in case this was just opened, set up the input buffer */
474 if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) 512 if (state->how == LOOK && state->x.have == 0)
475 (void)gz_look(state); 513 (void)gz_look(state);
476 514
477 /* check that we're reading and that there's no (serious) error */ 515 /* check that there was no (serious) error */
478 if (state->mode != GZ_READ || 516 if (state->err != Z_OK && state->err != Z_BUF_ERROR && !state->again)
479 (state->err != Z_OK && state->err != Z_BUF_ERROR))
480 return -1; 517 return -1;
518 gz_error(state, Z_OK, NULL);
481 519
482 /* process a skip request */ 520 /* process a skip request */
483 if (state->skip && gz_skip(state) == -1) 521 if (state->skip && gz_skip(state) == -1)
@@ -507,6 +545,7 @@ int ZEXPORT gzungetc(int c, gzFile file) {
507 if (state->x.next == state->out) { 545 if (state->x.next == state->out) {
508 unsigned char *src = state->out + state->x.have; 546 unsigned char *src = state->out + state->x.have;
509 unsigned char *dest = state->out + (state->size << 1); 547 unsigned char *dest = state->out + (state->size << 1);
548
510 while (src > state->out) 549 while (src > state->out)
511 *--dest = *--src; 550 *--dest = *--src;
512 state->x.next = dest; 551 state->x.next = dest;
@@ -526,23 +565,25 @@ char * ZEXPORT gzgets(gzFile file, char *buf, int len) {
526 unsigned char *eol; 565 unsigned char *eol;
527 gz_statep state; 566 gz_statep state;
528 567
529 /* check parameters and get internal structure */ 568 /* check parameters, get internal structure, and check that it's for
569 reading */
530 if (file == NULL || buf == NULL || len < 1) 570 if (file == NULL || buf == NULL || len < 1)
531 return NULL; 571 return NULL;
532 state = (gz_statep)file; 572 state = (gz_statep)file;
573 if (state->mode != GZ_READ)
574 return NULL;
533 575
534 /* check that we're reading and that there's no (serious) error */ 576 /* check that there was no (serious) error */
535 if (state->mode != GZ_READ || 577 if (state->err != Z_OK && state->err != Z_BUF_ERROR && !state->again)
536 (state->err != Z_OK && state->err != Z_BUF_ERROR))
537 return NULL; 578 return NULL;
579 gz_error(state, Z_OK, NULL);
538 580
539 /* process a skip request */ 581 /* process a skip request */
540 if (state->skip && gz_skip(state) == -1) 582 if (state->skip && gz_skip(state) == -1)
541 return NULL; 583 return NULL;
542 584
543 /* copy output bytes up to new line or len - 1, whichever comes first -- 585 /* copy output up to a new line, len-1 bytes, or there is no more output,
544 append a terminating zero to the string (we don't check for a zero in 586 whichever comes first */
545 the contents, let the user worry about that) */
546 str = buf; 587 str = buf;
547 left = (unsigned)len - 1; 588 left = (unsigned)len - 1;
548 if (left) do { 589 if (left) do {
@@ -569,7 +610,9 @@ char * ZEXPORT gzgets(gzFile file, char *buf, int len) {
569 buf += n; 610 buf += n;
570 } while (left && eol == NULL); 611 } while (left && eol == NULL);
571 612
572 /* return terminated string, or if nothing, end of file */ 613 /* append a terminating zero to the string (we don't check for a zero in
614 the contents, let the user worry about that) -- return the terminated
615 string, or if nothing was read, NULL */
573 if (buf == str) 616 if (buf == str)
574 return NULL; 617 return NULL;
575 buf[0] = 0; 618 buf[0] = 0;
@@ -599,12 +642,10 @@ int ZEXPORT gzclose_r(gzFile file) {
599 int ret, err; 642 int ret, err;
600 gz_statep state; 643 gz_statep state;
601 644
602 /* get internal structure */ 645 /* get internal structure and check that it's for reading */
603 if (file == NULL) 646 if (file == NULL)
604 return Z_STREAM_ERROR; 647 return Z_STREAM_ERROR;
605 state = (gz_statep)file; 648 state = (gz_statep)file;
606
607 /* check that we're reading */
608 if (state->mode != GZ_READ) 649 if (state->mode != GZ_READ)
609 return Z_STREAM_ERROR; 650 return Z_STREAM_ERROR;
610 651