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