1 /* gzwrite.c -- zlib functions for writing gzip files 2 * Copyright (C) 2004-2026 Mark Adler 3 * For conditions of distribution and use, see copyright notice in zlib.h 4 */ 5 6 #include "gzguts.h" 7 #include <unistd.h> 8 9 /* Initialize state for writing a gzip file. Mark initialization by setting 10 state->size to non-zero. Return -1 on a memory allocation failure, or 0 on 11 success. */ 12 local int gz_init(gz_statep state) { 13 int ret; 14 z_streamp strm = &(state->strm); 15 16 /* allocate input buffer (double size for gzprintf) */ 17 state->in = (unsigned char *)malloc(state->want << 1); 18 if (state->in == NULL) { 19 gz_error(state, Z_MEM_ERROR, "out of memory"); 20 return -1; 21 } 22 23 /* only need output buffer and deflate state if compressing */ 24 if (!state->direct) { 25 /* allocate output buffer */ 26 state->out = (unsigned char *)malloc(state->want); 27 if (state->out == NULL) { 28 free(state->in); 29 gz_error(state, Z_MEM_ERROR, "out of memory"); 30 return -1; 31 } 32 33 /* allocate deflate memory, set up for gzip compression */ 34 strm->zalloc = Z_NULL; 35 strm->zfree = Z_NULL; 36 strm->opaque = Z_NULL; 37 ret = deflateInit2(strm, state->level, Z_DEFLATED, 38 MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy); 39 if (ret != Z_OK) { 40 free(state->out); 41 free(state->in); 42 gz_error(state, Z_MEM_ERROR, "out of memory"); 43 return -1; 44 } 45 strm->next_in = NULL; 46 } 47 48 /* mark state as initialized */ 49 state->size = state->want; 50 51 /* initialize write buffer if compressing */ 52 if (!state->direct) { 53 strm->avail_out = state->size; 54 strm->next_out = state->out; 55 state->x.next = strm->next_out; 56 } 57 return 0; 58 } 59 60 /* Compress whatever is at avail_in and next_in and write to the output file. 61 Return -1 if there is an error writing to the output file or if gz_init() 62 fails to allocate memory, otherwise 0. flush is assumed to be a valid 63 deflate() flush value. If flush is Z_FINISH, then the deflate() state is 64 reset to start a new gzip stream. If gz->direct is true, then simply write 65 to the output file without compressing, and ignore flush. */ 66 local int gz_comp(gz_statep state, int flush) { 67 int ret, writ; 68 unsigned have, put, max = ((unsigned)-1 >> 2) + 1; 69 z_streamp strm = &(state->strm); 70 71 /* allocate memory if this is the first time through */ 72 if (state->size == 0 && gz_init(state) == -1) 73 return -1; 74 75 /* write directly if requested */ 76 if (state->direct) { 77 while (strm->avail_in) { 78 errno = 0; 79 state->again = 0; 80 put = strm->avail_in > max ? max : strm->avail_in; 81 writ = (int)write(state->fd, strm->next_in, put); 82 if (writ < 0) { 83 if (errno == EAGAIN || errno == EWOULDBLOCK) 84 state->again = 1; 85 gz_error(state, Z_ERRNO, zstrerror()); 86 return -1; 87 } 88 strm->avail_in -= (unsigned)writ; 89 strm->next_in += writ; 90 } 91 return 0; 92 } 93 94 /* check for a pending reset */ 95 if (state->reset) { 96 /* don't start a new gzip member unless there is data to write and 97 we're not flushing */ 98 if (strm->avail_in == 0 && flush == Z_NO_FLUSH) 99 return 0; 100 deflateReset(strm); 101 state->reset = 0; 102 } 103 104 /* run deflate() on provided input until it produces no more output */ 105 ret = Z_OK; 106 do { 107 /* write out current buffer contents if full, or if flushing, but if 108 doing Z_FINISH then don't write until we get to Z_STREAM_END */ 109 if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && 110 (flush != Z_FINISH || ret == Z_STREAM_END))) { 111 while (strm->next_out > state->x.next) { 112 errno = 0; 113 state->again = 0; 114 put = strm->next_out - state->x.next > (int)max ? max : 115 (unsigned)(strm->next_out - state->x.next); 116 writ = (int)write(state->fd, state->x.next, put); 117 if (writ < 0) { 118 if (errno == EAGAIN || errno == EWOULDBLOCK) 119 state->again = 1; 120 gz_error(state, Z_ERRNO, zstrerror()); 121 return -1; 122 } 123 state->x.next += writ; 124 } 125 if (strm->avail_out == 0) { 126 strm->avail_out = state->size; 127 strm->next_out = state->out; 128 state->x.next = state->out; 129 } 130 } 131 132 /* compress */ 133 have = strm->avail_out; 134 ret = deflate(strm, flush); 135 if (ret == Z_STREAM_ERROR) { 136 gz_error(state, Z_STREAM_ERROR, 137 "internal error: deflate stream corrupt"); 138 return -1; 139 } 140 have -= strm->avail_out; 141 } while (have); 142 143 /* if that completed a deflate stream, allow another to start */ 144 if (flush == Z_FINISH) 145 state->reset = 1; 146 147 /* all done, no errors */ 148 return 0; 149 } 150 151 /* Compress state->skip (> 0) zeros to output. Return -1 on a write error or 152 memory allocation failure by gz_comp(), or 0 on success. state->skip is 153 updated with the number of successfully written zeros, in case there is a 154 stall on a non-blocking write destination. */ 155 local int gz_zero(gz_statep state) { 156 int first, ret; 157 unsigned n; 158 z_streamp strm = &(state->strm); 159 160 /* consume whatever's left in the input buffer */ 161 if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) 162 return -1; 163 164 /* compress state->skip zeros */ 165 first = 1; 166 do { 167 n = GT_OFF(state->size) || (z_off64_t)state->size > state->skip ? 168 (unsigned)state->skip : state->size; 169 if (first) { 170 memset(state->in, 0, n); 171 first = 0; 172 } 173 strm->avail_in = n; 174 strm->next_in = state->in; 175 ret = gz_comp(state, Z_NO_FLUSH); 176 n -= strm->avail_in; 177 state->x.pos += n; 178 state->skip -= n; 179 if (ret == -1) 180 return -1; 181 } while (state->skip); 182 return 0; 183 } 184 185 /* Write len bytes from buf to file. Return the number of bytes written. If 186 the returned value is less than len, then there was an error. If the error 187 was a non-blocking stall, then the number of bytes consumed is returned. 188 For any other error, 0 is returned. */ 189 local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) { 190 z_size_t put = len; 191 int ret; 192 193 /* if len is zero, avoid unnecessary operations */ 194 if (len == 0) 195 return 0; 196 197 /* allocate memory if this is the first time through */ 198 if (state->size == 0 && gz_init(state) == -1) 199 return 0; 200 201 /* check for seek request */ 202 if (state->skip && gz_zero(state) == -1) 203 return 0; 204 205 /* for small len, copy to input buffer, otherwise compress directly */ 206 if (len < state->size) { 207 /* copy to input buffer, compress when full */ 208 for (;;) { 209 unsigned have, copy; 210 211 if (state->strm.avail_in == 0) 212 state->strm.next_in = state->in; 213 have = (unsigned)((state->strm.next_in + state->strm.avail_in) - 214 state->in); 215 copy = state->size - have; 216 if (copy > len) 217 copy = (unsigned)len; 218 memcpy(state->in + have, buf, copy); 219 state->strm.avail_in += copy; 220 state->x.pos += copy; 221 buf = (const char *)buf + copy; 222 len -= copy; 223 if (len == 0) 224 break; 225 if (gz_comp(state, Z_NO_FLUSH) == -1) 226 return state->again ? put - len : 0; 227 } 228 } 229 else { 230 /* consume whatever's left in the input buffer */ 231 if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1) 232 return 0; 233 234 /* directly compress user buffer to file */ 235 state->strm.next_in = (z_const Bytef *)buf; 236 do { 237 unsigned n = (unsigned)-1; 238 239 if (n > len) 240 n = (unsigned)len; 241 state->strm.avail_in = n; 242 ret = gz_comp(state, Z_NO_FLUSH); 243 n -= state->strm.avail_in; 244 state->x.pos += n; 245 len -= n; 246 if (ret == -1) { 247 state->strm.avail_in = 0; 248 state->strm.next_in = state->in; 249 return state->again ? put - len : 0; 250 } 251 } while (len); 252 } 253 254 /* input was all buffered or compressed */ 255 return put; 256 } 257 258 /* -- see zlib.h -- */ 259 int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len) { 260 gz_statep state; 261 262 /* get internal structure */ 263 if (file == NULL) 264 return 0; 265 state = (gz_statep)file; 266 267 /* check that we're writing and that there's no (serious) error */ 268 if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again)) 269 return 0; 270 gz_error(state, Z_OK, NULL); 271 272 /* since an int is returned, make sure len fits in one, otherwise return 273 with an error (this avoids a flaw in the interface) */ 274 if ((int)len < 0) { 275 gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); 276 return 0; 277 } 278 279 /* write len bytes from buf (the return value will fit in an int) */ 280 return (int)gz_write(state, buf, len); 281 } 282 283 /* -- see zlib.h -- */ 284 z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, z_size_t nitems, 285 gzFile file) { 286 z_size_t len; 287 gz_statep state; 288 289 /* get internal structure */ 290 if (file == NULL) 291 return 0; 292 state = (gz_statep)file; 293 294 /* check that we're writing and that there's no (serious) error */ 295 if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again)) 296 return 0; 297 gz_error(state, Z_OK, NULL); 298 299 /* compute bytes to read -- error on overflow */ 300 len = nitems * size; 301 if (size && len / size != nitems) { 302 gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); 303 return 0; 304 } 305 306 /* write len bytes to buf, return the number of full items written */ 307 return len ? gz_write(state, buf, len) / size : 0; 308 } 309 310 /* -- see zlib.h -- */ 311 int ZEXPORT gzputc(gzFile file, int c) { 312 unsigned have; 313 unsigned char buf[1]; 314 gz_statep state; 315 z_streamp strm; 316 317 /* get internal structure */ 318 if (file == NULL) 319 return -1; 320 state = (gz_statep)file; 321 strm = &(state->strm); 322 323 /* check that we're writing and that there's no (serious) error */ 324 if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again)) 325 return -1; 326 gz_error(state, Z_OK, NULL); 327 328 /* check for seek request */ 329 if (state->skip && gz_zero(state) == -1) 330 return -1; 331 332 /* try writing to input buffer for speed (state->size == 0 if buffer not 333 initialized) */ 334 if (state->size) { 335 if (strm->avail_in == 0) 336 strm->next_in = state->in; 337 have = (unsigned)((strm->next_in + strm->avail_in) - state->in); 338 if (have < state->size) { 339 state->in[have] = (unsigned char)c; 340 strm->avail_in++; 341 state->x.pos++; 342 return c & 0xff; 343 } 344 } 345 346 /* no room in buffer or not initialized, use gz_write() */ 347 buf[0] = (unsigned char)c; 348 if (gz_write(state, buf, 1) != 1) 349 return -1; 350 return c & 0xff; 351 } 352 353 /* -- see zlib.h -- */ 354 int ZEXPORT gzputs(gzFile file, const char *s) { 355 z_size_t len, put; 356 gz_statep state; 357 358 /* get internal structure */ 359 if (file == NULL) 360 return -1; 361 state = (gz_statep)file; 362 363 /* check that we're writing and that there's no (serious) error */ 364 if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again)) 365 return -1; 366 gz_error(state, Z_OK, NULL); 367 368 /* write string */ 369 len = strlen(s); 370 if ((int)len < 0 || (unsigned)len != len) { 371 gz_error(state, Z_STREAM_ERROR, "string length does not fit in int"); 372 return -1; 373 } 374 put = gz_write(state, s, len); 375 return len && put == 0 ? -1 : (int)put; 376 } 377 378 #if (((!defined(STDC) && !defined(Z_HAVE_STDARG_H)) || !defined(NO_vsnprintf)) && \ 379 (defined(STDC) || defined(Z_HAVE_STDARG_H) || !defined(NO_snprintf))) || \ 380 defined(ZLIB_INSECURE) 381 /* If the second half of the input buffer is occupied, write out the contents. 382 If there is any input remaining due to a non-blocking stall on write, move 383 it to the start of the buffer. Return true if this did not open up the 384 second half of the buffer. state->err should be checked after this to 385 handle a gz_comp() error. */ 386 local int gz_vacate(gz_statep state) { 387 z_streamp strm; 388 389 strm = &(state->strm); 390 if (strm->next_in + strm->avail_in <= state->in + state->size) 391 return 0; 392 (void)gz_comp(state, Z_NO_FLUSH); 393 if (strm->avail_in == 0) { 394 strm->next_in = state->in; 395 return 0; 396 } 397 memmove(state->in, strm->next_in, strm->avail_in); 398 strm->next_in = state->in; 399 return strm->avail_in > state->size; 400 } 401 #endif 402 403 #if defined(STDC) || defined(Z_HAVE_STDARG_H) 404 #include <stdarg.h> 405 406 /* -- see zlib.h -- */ 407 int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) { 408 #if defined(NO_vsnprintf) && !defined(ZLIB_INSECURE) 409 #warning "vsnprintf() not available -- gzprintf() stub returns Z_STREAM_ERROR" 410 #warning "you can recompile with ZLIB_INSECURE defined to use vsprintf()" 411 /* prevent use of insecure vsprintf(), unless purposefully requested */ 412 (void)file, (void)format, (void)va; 413 return Z_STREAM_ERROR; 414 #else 415 int len, ret; 416 char *next; 417 gz_statep state; 418 z_streamp strm; 419 420 /* get internal structure */ 421 if (file == NULL) 422 return Z_STREAM_ERROR; 423 state = (gz_statep)file; 424 strm = &(state->strm); 425 426 /* check that we're writing and that there's no (serious) error */ 427 if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again)) 428 return Z_STREAM_ERROR; 429 gz_error(state, Z_OK, NULL); 430 431 /* make sure we have some buffer space */ 432 if (state->size == 0 && gz_init(state) == -1) 433 return state->err; 434 435 /* check for seek request */ 436 if (state->skip && gz_zero(state) == -1) 437 return state->err; 438 439 /* do the printf() into the input buffer, put length in len -- the input 440 buffer is double-sized just for this function, so there should be 441 state->size bytes available after the current contents */ 442 ret = gz_vacate(state); 443 if (state->err) { 444 if (ret && state->again) { 445 /* There was a non-blocking stall on write, resulting in the part 446 of the second half of the output buffer being occupied. Return 447 a Z_BUF_ERROR to let the application know that this gzprintf() 448 needs to be retried. */ 449 gz_error(state, Z_BUF_ERROR, "stalled write on gzprintf"); 450 } 451 if (!state->again) 452 return state->err; 453 } 454 if (strm->avail_in == 0) 455 strm->next_in = state->in; 456 next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in); 457 next[state->size - 1] = 0; 458 #ifdef NO_vsnprintf 459 # ifdef HAS_vsprintf_void 460 (void)vsprintf(next, format, va); 461 for (len = 0; len < state->size; len++) 462 if (next[len] == 0) break; 463 # else 464 len = vsprintf(next, format, va); 465 # endif 466 #else 467 # ifdef HAS_vsnprintf_void 468 (void)vsnprintf(next, state->size, format, va); 469 len = strlen(next); 470 # else 471 len = vsnprintf(next, state->size, format, va); 472 # endif 473 #endif 474 475 /* check that printf() results fit in buffer */ 476 if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0) 477 return 0; 478 479 /* update buffer and position */ 480 strm->avail_in += (unsigned)len; 481 state->x.pos += len; 482 483 /* write out buffer if more than half is occupied */ 484 ret = gz_vacate(state); 485 if (state->err && !state->again) 486 return state->err; 487 return len; 488 #endif 489 } 490 491 int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) { 492 va_list va; 493 int ret; 494 495 va_start(va, format); 496 ret = gzvprintf(file, format, va); 497 va_end(va); 498 return ret; 499 } 500 501 #else /* !STDC && !Z_HAVE_STDARG_H */ 502 503 /* -- see zlib.h -- */ 504 int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3, 505 int a4, int a5, int a6, int a7, int a8, int a9, int a10, 506 int a11, int a12, int a13, int a14, int a15, int a16, 507 int a17, int a18, int a19, int a20) { 508 #if defined(NO_snprintf) && !defined(ZLIB_INSECURE) 509 #warning "snprintf() not available -- gzprintf() stub returns Z_STREAM_ERROR" 510 #warning "you can recompile with ZLIB_INSECURE defined to use sprintf()" 511 /* prevent use of insecure sprintf(), unless purposefully requested */ 512 (void)file, (void)format, (void)a1, (void)a2, (void)a3, (void)a4, (void)a5, 513 (void)a6, (void)a7, (void)a8, (void)a9, (void)a10, (void)a11, (void)a12, 514 (void)a13, (void)a14, (void)a15, (void)a16, (void)a17, (void)a18, 515 (void)a19, (void)a20; 516 return Z_STREAM_ERROR; 517 #else 518 int ret; 519 unsigned len, left; 520 char *next; 521 gz_statep state; 522 z_streamp strm; 523 524 /* get internal structure */ 525 if (file == NULL) 526 return Z_STREAM_ERROR; 527 state = (gz_statep)file; 528 strm = &(state->strm); 529 530 /* check that can really pass pointer in ints */ 531 if (sizeof(int) != sizeof(void *)) 532 return Z_STREAM_ERROR; 533 534 /* check that we're writing and that there's no (serious) error */ 535 if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again)) 536 return Z_STREAM_ERROR; 537 gz_error(state, Z_OK, NULL); 538 539 /* make sure we have some buffer space */ 540 if (state->size == 0 && gz_init(state) == -1) 541 return state->err; 542 543 /* check for seek request */ 544 if (state->skip && gz_zero(state) == -1) 545 return state->err; 546 547 /* do the printf() into the input buffer, put length in len -- the input 548 buffer is double-sized just for this function, so there is guaranteed to 549 be state->size bytes available after the current contents */ 550 ret = gz_vacate(state); 551 if (state->err) { 552 if (ret && state->again) { 553 /* There was a non-blocking stall on write, resulting in the part 554 of the second half of the output buffer being occupied. Return 555 a Z_BUF_ERROR to let the application know that this gzprintf() 556 needs to be retried. */ 557 gz_error(state, Z_BUF_ERROR, "stalled write on gzprintf"); 558 } 559 if (!state->again) 560 return state->err; 561 } 562 if (strm->avail_in == 0) 563 strm->next_in = state->in; 564 next = (char *)(strm->next_in + strm->avail_in); 565 next[state->size - 1] = 0; 566 #ifdef NO_snprintf 567 # ifdef HAS_sprintf_void 568 sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, 569 a13, a14, a15, a16, a17, a18, a19, a20); 570 for (len = 0; len < size; len++) 571 if (next[len] == 0) 572 break; 573 # else 574 len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, 575 a12, a13, a14, a15, a16, a17, a18, a19, a20); 576 # endif 577 #else 578 # ifdef HAS_snprintf_void 579 snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, 580 a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); 581 len = strlen(next); 582 # else 583 len = snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, 584 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); 585 # endif 586 #endif 587 588 /* check that printf() results fit in buffer */ 589 if (len == 0 || len >= state->size || next[state->size - 1] != 0) 590 return 0; 591 592 /* update buffer and position, compress first half if past that */ 593 strm->avail_in += len; 594 state->x.pos += len; 595 596 /* write out buffer if more than half is occupied */ 597 ret = gz_vacate(state); 598 if (state->err && !state->again) 599 return state->err; 600 return (int)len; 601 #endif 602 } 603 604 #endif 605 606 /* -- see zlib.h -- */ 607 int ZEXPORT gzflush(gzFile file, int flush) { 608 gz_statep state; 609 610 /* get internal structure */ 611 if (file == NULL) 612 return Z_STREAM_ERROR; 613 state = (gz_statep)file; 614 615 /* check that we're writing and that there's no (serious) error */ 616 if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again)) 617 return Z_STREAM_ERROR; 618 gz_error(state, Z_OK, NULL); 619 620 /* check flush parameter */ 621 if (flush < 0 || flush > Z_FINISH) 622 return Z_STREAM_ERROR; 623 624 /* check for seek request */ 625 if (state->skip && gz_zero(state) == -1) 626 return state->err; 627 628 /* compress remaining data with requested flush */ 629 (void)gz_comp(state, flush); 630 return state->err; 631 } 632 633 /* -- see zlib.h -- */ 634 int ZEXPORT gzsetparams(gzFile file, int level, int strategy) { 635 gz_statep state; 636 z_streamp strm; 637 638 /* get internal structure */ 639 if (file == NULL) 640 return Z_STREAM_ERROR; 641 state = (gz_statep)file; 642 strm = &(state->strm); 643 644 /* check that we're compressing and that there's no (serious) error */ 645 if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again) || 646 state->direct) 647 return Z_STREAM_ERROR; 648 gz_error(state, Z_OK, NULL); 649 650 /* if no change is requested, then do nothing */ 651 if (level == state->level && strategy == state->strategy) 652 return Z_OK; 653 654 /* check for seek request */ 655 if (state->skip && gz_zero(state) == -1) 656 return state->err; 657 658 /* change compression parameters for subsequent input */ 659 if (state->size) { 660 /* flush previous input with previous parameters before changing */ 661 if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1) 662 return state->err; 663 deflateParams(strm, level, strategy); 664 } 665 state->level = level; 666 state->strategy = strategy; 667 return Z_OK; 668 } 669 670 /* -- see zlib.h -- */ 671 int ZEXPORT gzclose_w(gzFile file) { 672 int ret = Z_OK; 673 gz_statep state; 674 675 /* get internal structure */ 676 if (file == NULL) 677 return Z_STREAM_ERROR; 678 state = (gz_statep)file; 679 680 /* check that we're writing */ 681 if (state->mode != GZ_WRITE) 682 return Z_STREAM_ERROR; 683 684 /* check for seek request */ 685 if (state->skip && gz_zero(state) == -1) 686 ret = state->err; 687 688 /* flush, free memory, and close file */ 689 if (gz_comp(state, Z_FINISH) == -1) 690 ret = state->err; 691 if (state->size) { 692 if (!state->direct) { 693 (void)deflateEnd(&(state->strm)); 694 free(state->out); 695 } 696 free(state->in); 697 } 698 gz_error(state, Z_OK, NULL); 699 free(state->path); 700 if (close(state->fd) == -1) 701 ret = Z_ERRNO; 702 free(state); 703 return ret; 704 } 705