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