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