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