aboutsummaryrefslogtreecommitdiff
path: root/gzwrite.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 /gzwrite.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 'gzwrite.c')
-rw-r--r--gzwrite.c167
1 files changed, 116 insertions, 51 deletions
diff --git a/gzwrite.c b/gzwrite.c
index ab29bf4..e7864cb 100644
--- a/gzwrite.c
+++ b/gzwrite.c
@@ -74,9 +74,13 @@ local int gz_comp(gz_statep state, int flush) {
74 /* write directly if requested */ 74 /* write directly if requested */
75 if (state->direct) { 75 if (state->direct) {
76 while (strm->avail_in) { 76 while (strm->avail_in) {
77 errno = 0;
78 state->again = 0;
77 put = strm->avail_in > max ? max : strm->avail_in; 79 put = strm->avail_in > max ? max : strm->avail_in;
78 writ = write(state->fd, strm->next_in, put); 80 writ = write(state->fd, strm->next_in, put);
79 if (writ < 0) { 81 if (writ < 0) {
82 if (errno == EAGAIN || errno == EWOULDBLOCK)
83 state->again = 1;
80 gz_error(state, Z_ERRNO, zstrerror()); 84 gz_error(state, Z_ERRNO, zstrerror());
81 return -1; 85 return -1;
82 } 86 }
@@ -104,10 +108,14 @@ local int gz_comp(gz_statep state, int flush) {
104 if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && 108 if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
105 (flush != Z_FINISH || ret == Z_STREAM_END))) { 109 (flush != Z_FINISH || ret == Z_STREAM_END))) {
106 while (strm->next_out > state->x.next) { 110 while (strm->next_out > state->x.next) {
111 errno = 0;
112 state->again = 0;
107 put = strm->next_out - state->x.next > (int)max ? max : 113 put = strm->next_out - state->x.next > (int)max ? max :
108 (unsigned)(strm->next_out - state->x.next); 114 (unsigned)(strm->next_out - state->x.next);
109 writ = write(state->fd, state->x.next, put); 115 writ = write(state->fd, state->x.next, put);
110 if (writ < 0) { 116 if (writ < 0) {
117 if (errno == EAGAIN || errno == EWOULDBLOCK)
118 state->again = 1;
111 gz_error(state, Z_ERRNO, zstrerror()); 119 gz_error(state, Z_ERRNO, zstrerror());
112 return -1; 120 return -1;
113 } 121 }
@@ -140,9 +148,11 @@ local int gz_comp(gz_statep state, int flush) {
140} 148}
141 149
142/* Compress state->skip (> 0) zeros to output. Return -1 on a write error or 150/* Compress state->skip (> 0) zeros to output. Return -1 on a write error or
143 memory allocation failure by gz_comp(), or 0 on success. */ 151 memory allocation failure by gz_comp(), or 0 on success. state->skip is
152 updated with the number of successfully written zeros, in case there is a
153 stall on a non-blocking write destination. */
144local int gz_zero(gz_statep state) { 154local int gz_zero(gz_statep state) {
145 int first; 155 int first, ret;
146 unsigned n; 156 unsigned n;
147 z_streamp strm = &(state->strm); 157 z_streamp strm = &(state->strm);
148 158
@@ -161,18 +171,23 @@ local int gz_zero(gz_statep state) {
161 } 171 }
162 strm->avail_in = n; 172 strm->avail_in = n;
163 strm->next_in = state->in; 173 strm->next_in = state->in;
174 ret = gz_comp(state, Z_NO_FLUSH);
175 n -= strm->avail_in;
164 state->x.pos += n; 176 state->x.pos += n;
165 if (gz_comp(state, Z_NO_FLUSH) == -1)
166 return -1;
167 state->skip -= n; 177 state->skip -= n;
178 if (ret == -1)
179 return -1;
168 } while (state->skip); 180 } while (state->skip);
169 return 0; 181 return 0;
170} 182}
171 183
172/* Write len bytes from buf to file. Return the number of bytes written. If 184/* Write len bytes from buf to file. Return the number of bytes written. If
173 the returned value is less than len, then there was an error. */ 185 the returned value is less than len, then there was an error. If the error
186 was a non-blocking stall, then the number of bytes consumed is returned.
187 For any other error, 0 is returned. */
174local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) { 188local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
175 z_size_t put = len; 189 z_size_t put = len;
190 int ret;
176 191
177 /* if len is zero, avoid unnecessary operations */ 192 /* if len is zero, avoid unnecessary operations */
178 if (len == 0) 193 if (len == 0)
@@ -189,7 +204,7 @@ local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
189 /* for small len, copy to input buffer, otherwise compress directly */ 204 /* for small len, copy to input buffer, otherwise compress directly */
190 if (len < state->size) { 205 if (len < state->size) {
191 /* copy to input buffer, compress when full */ 206 /* copy to input buffer, compress when full */
192 do { 207 for (;;) {
193 unsigned have, copy; 208 unsigned have, copy;
194 209
195 if (state->strm.avail_in == 0) 210 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) {
204 state->x.pos += copy; 219 state->x.pos += copy;
205 buf = (const char *)buf + copy; 220 buf = (const char *)buf + copy;
206 len -= copy; 221 len -= copy;
207 if (len && gz_comp(state, Z_NO_FLUSH) == -1) 222 if (len == 0)
208 return 0; 223 break;
209 } while (len); 224 if (gz_comp(state, Z_NO_FLUSH) == -1)
225 return state->again ? put - len : 0;
226 }
210 } 227 }
211 else { 228 else {
212 /* consume whatever's left in the input buffer */ 229 /* 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) {
217 state->strm.next_in = (z_const Bytef *)buf; 234 state->strm.next_in = (z_const Bytef *)buf;
218 do { 235 do {
219 unsigned n = (unsigned)-1; 236 unsigned n = (unsigned)-1;
237
220 if (n > len) 238 if (n > len)
221 n = (unsigned)len; 239 n = (unsigned)len;
222 state->strm.avail_in = n; 240 state->strm.avail_in = n;
241 ret = gz_comp(state, Z_NO_FLUSH);
242 n -= state->strm.avail_in;
223 state->x.pos += n; 243 state->x.pos += n;
224 if (gz_comp(state, Z_NO_FLUSH) == -1)
225 return 0;
226 len -= n; 244 len -= n;
245 if (ret == -1)
246 return state->again ? put - len : 0;
227 } while (len); 247 } while (len);
228 } 248 }
229 249
@@ -240,9 +260,10 @@ int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len) {
240 return 0; 260 return 0;
241 state = (gz_statep)file; 261 state = (gz_statep)file;
242 262
243 /* check that we're writing and that there's no error */ 263 /* check that we're writing and that there's no (serious) error */
244 if (state->mode != GZ_WRITE || state->err != Z_OK) 264 if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
245 return 0; 265 return 0;
266 gz_error(state, Z_OK, NULL);
246 267
247 /* since an int is returned, make sure len fits in one, otherwise return 268 /* since an int is returned, make sure len fits in one, otherwise return
248 with an error (this avoids a flaw in the interface) */ 269 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,
266 return 0; 287 return 0;
267 state = (gz_statep)file; 288 state = (gz_statep)file;
268 289
269 /* check that we're writing and that there's no error */ 290 /* check that we're writing and that there's no (serious) error */
270 if (state->mode != GZ_WRITE || state->err != Z_OK) 291 if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
271 return 0; 292 return 0;
293 gz_error(state, Z_OK, NULL);
272 294
273 /* compute bytes to read -- error on overflow */ 295 /* compute bytes to read -- error on overflow */
274 len = nitems * size; 296 len = nitems * size;
@@ -294,9 +316,10 @@ int ZEXPORT gzputc(gzFile file, int c) {
294 state = (gz_statep)file; 316 state = (gz_statep)file;
295 strm = &(state->strm); 317 strm = &(state->strm);
296 318
297 /* check that we're writing and that there's no error */ 319 /* check that we're writing and that there's no (serious) error */
298 if (state->mode != GZ_WRITE || state->err != Z_OK) 320 if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
299 return -1; 321 return -1;
322 gz_error(state, Z_OK, NULL);
300 323
301 /* check for seek request */ 324 /* check for seek request */
302 if (state->skip && gz_zero(state) == -1) 325 if (state->skip && gz_zero(state) == -1)
@@ -333,9 +356,10 @@ int ZEXPORT gzputs(gzFile file, const char *s) {
333 return -1; 356 return -1;
334 state = (gz_statep)file; 357 state = (gz_statep)file;
335 358
336 /* check that we're writing and that there's no error */ 359 /* check that we're writing and that there's no (serious) error */
337 if (state->mode != GZ_WRITE || state->err != Z_OK) 360 if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
338 return -1; 361 return -1;
362 gz_error(state, Z_OK, NULL);
339 363
340 /* write string */ 364 /* write string */
341 len = strlen(s); 365 len = strlen(s);
@@ -344,7 +368,28 @@ int ZEXPORT gzputs(gzFile file, const char *s) {
344 return -1; 368 return -1;
345 } 369 }
346 put = gz_write(state, s, len); 370 put = gz_write(state, s, len);
347 return put < len ? -1 : (int)len; 371 return len && put == 0 ? -1 : (int)put;
372}
373
374/* If the second half of the input buffer is occupied, write out the contents.
375 If there is any input remaining due to a non-blocking stall on write, move
376 it to the start of the buffer. Return true if this did not open up the
377 second half of the buffer. state->err should be checked after this to
378 handle a gz_comp() error. */
379local int gz_vacate(gz_statep state) {
380 z_streamp strm;
381
382 strm = &(state->strm);
383 if ((strm->next_in + strm->avail_in) - state->in <= state->size)
384 return 0;
385 (void)gz_comp(state, Z_NO_FLUSH);
386 if (strm->avail_in == 0) {
387 strm->next_in = state->in;
388 return 0;
389 }
390 memmove(state->in, strm->next_in, strm->avail_in);
391 strm->next_in = state->in;
392 return strm->avail_in > state->size;
348} 393}
349 394
350#if defined(STDC) || defined(Z_HAVE_STDARG_H) 395#if defined(STDC) || defined(Z_HAVE_STDARG_H)
@@ -352,8 +397,7 @@ int ZEXPORT gzputs(gzFile file, const char *s) {
352 397
353/* -- see zlib.h -- */ 398/* -- see zlib.h -- */
354int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) { 399int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) {
355 int len; 400 int len, ret;
356 unsigned left;
357 char *next; 401 char *next;
358 gz_statep state; 402 gz_statep state;
359 z_streamp strm; 403 z_streamp strm;
@@ -364,9 +408,10 @@ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) {
364 state = (gz_statep)file; 408 state = (gz_statep)file;
365 strm = &(state->strm); 409 strm = &(state->strm);
366 410
367 /* check that we're writing and that there's no error */ 411 /* check that we're writing and that there's no (serious) error */
368 if (state->mode != GZ_WRITE || state->err != Z_OK) 412 if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
369 return Z_STREAM_ERROR; 413 return Z_STREAM_ERROR;
414 gz_error(state, Z_OK, NULL);
370 415
371 /* make sure we have some buffer space */ 416 /* make sure we have some buffer space */
372 if (state->size == 0 && gz_init(state) == -1) 417 if (state->size == 0 && gz_init(state) == -1)
@@ -377,8 +422,20 @@ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) {
377 return state->err; 422 return state->err;
378 423
379 /* do the printf() into the input buffer, put length in len -- the input 424 /* do the printf() into the input buffer, put length in len -- the input
380 buffer is double-sized just for this function, so there is guaranteed to 425 buffer is double-sized just for this function, so there should be
381 be state->size bytes available after the current contents */ 426 state->size bytes available after the current contents */
427 ret = gz_vacate(state);
428 if (state->err) {
429 if (ret && state->again) {
430 /* There was a non-blocking stall on write, resulting in the part
431 of the second half of the output buffer being occupied. Return
432 a Z_BUF_ERROR to let the application know that this gzprintf()
433 needs to be retried. */
434 gz_error(state, Z_BUF_ERROR, "stalled write on gzprintf");
435 }
436 if (!state->again)
437 return state->err;
438 }
382 if (strm->avail_in == 0) 439 if (strm->avail_in == 0)
383 strm->next_in = state->in; 440 strm->next_in = state->in;
384 next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in); 441 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) {
404 if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0) 461 if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0)
405 return 0; 462 return 0;
406 463
407 /* update buffer and position, compress first half if past that */ 464 /* update buffer and position */
408 strm->avail_in += (unsigned)len; 465 strm->avail_in += (unsigned)len;
409 state->x.pos += len; 466 state->x.pos += len;
410 if (strm->avail_in >= state->size) { 467
411 left = strm->avail_in - state->size; 468 /* write out buffer if more than half is occupied */
412 strm->avail_in = state->size; 469 ret = gz_vacate(state);
413 if (gz_comp(state, Z_NO_FLUSH) == -1) 470 if (state->err && !state->again)
414 return state->err; 471 return state->err;
415 memmove(state->in, state->in + state->size, left);
416 strm->next_in = state->in;
417 strm->avail_in = left;
418 }
419 return len; 472 return len;
420} 473}
421 474
@@ -451,9 +504,10 @@ int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3,
451 if (sizeof(int) != sizeof(void *)) 504 if (sizeof(int) != sizeof(void *))
452 return Z_STREAM_ERROR; 505 return Z_STREAM_ERROR;
453 506
454 /* check that we're writing and that there's no error */ 507 /* check that we're writing and that there's no (serious) error */
455 if (state->mode != GZ_WRITE || state->err != Z_OK) 508 if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
456 return Z_STREAM_ERROR; 509 return Z_STREAM_ERROR;
510 gz_error(state, Z_OK, NULL);
457 511
458 /* make sure we have some buffer space */ 512 /* make sure we have some buffer space */
459 if (state->size == 0 && gz_init(state) == -1) 513 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,
466 /* do the printf() into the input buffer, put length in len -- the input 520 /* do the printf() into the input buffer, put length in len -- the input
467 buffer is double-sized just for this function, so there is guaranteed to 521 buffer is double-sized just for this function, so there is guaranteed to
468 be state->size bytes available after the current contents */ 522 be state->size bytes available after the current contents */
523 ret = gz_vacate(state);
524 if (state->err) {
525 if (ret && state->again) {
526 /* There was a non-blocking stall on write, resulting in the part
527 of the second half of the output buffer being occupied. Return
528 a Z_BUF_ERROR to let the application know that this gzprintf()
529 needs to be retried. */
530 gz_error(state, Z_BUF_ERROR, "stalled write on gzprintf");
531 }
532 if (!state->again)
533 return state->err;
534 }
469 if (strm->avail_in == 0) 535 if (strm->avail_in == 0)
470 strm->next_in = state->in; 536 strm->next_in = state->in;
471 next = (char *)(strm->next_in + strm->avail_in); 537 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,
499 /* update buffer and position, compress first half if past that */ 565 /* update buffer and position, compress first half if past that */
500 strm->avail_in += len; 566 strm->avail_in += len;
501 state->x.pos += len; 567 state->x.pos += len;
502 if (strm->avail_in >= state->size) { 568
503 left = strm->avail_in - state->size; 569 /* write out buffer if more than half is occupied */
504 strm->avail_in = state->size; 570 ret = gz_vacate(state);
505 if (gz_comp(state, Z_NO_FLUSH) == -1) 571 if (state->err && !state->again)
506 return state->err; 572 return state->err;
507 memmove(state->in, state->in + state->size, left);
508 strm->next_in = state->in;
509 strm->avail_in = left;
510 }
511 return (int)len; 573 return (int)len;
512} 574}
513 575
@@ -522,9 +584,10 @@ int ZEXPORT gzflush(gzFile file, int flush) {
522 return Z_STREAM_ERROR; 584 return Z_STREAM_ERROR;
523 state = (gz_statep)file; 585 state = (gz_statep)file;
524 586
525 /* check that we're writing and that there's no error */ 587 /* check that we're writing and that there's no (serious) error */
526 if (state->mode != GZ_WRITE || state->err != Z_OK) 588 if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
527 return Z_STREAM_ERROR; 589 return Z_STREAM_ERROR;
590 gz_error(state, Z_OK, NULL);
528 591
529 /* check flush parameter */ 592 /* check flush parameter */
530 if (flush < 0 || flush > Z_FINISH) 593 if (flush < 0 || flush > Z_FINISH)
@@ -550,9 +613,11 @@ int ZEXPORT gzsetparams(gzFile file, int level, int strategy) {
550 state = (gz_statep)file; 613 state = (gz_statep)file;
551 strm = &(state->strm); 614 strm = &(state->strm);
552 615
553 /* check that we're writing and that there's no error */ 616 /* check that we're compressing and that there's no (serious) error */
554 if (state->mode != GZ_WRITE || state->err != Z_OK || state->direct) 617 if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again) ||
618 state->direct)
555 return Z_STREAM_ERROR; 619 return Z_STREAM_ERROR;
620 gz_error(state, Z_OK, NULL);
556 621
557 /* if no change is requested, then do nothing */ 622 /* if no change is requested, then do nothing */
558 if (level == state->level && strategy == state->strategy) 623 if (level == state->level && strategy == state->strategy)