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