1 /* gzlib.c -- zlib functions common to reading and 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 "zutil.h" 10 #include <unistd.h> 11 12 #if defined(_WIN32) && !defined(__BORLANDC__) 13 # define LSEEK _lseeki64 14 #else 15 #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 16 # define LSEEK lseek64 17 #else 18 # define LSEEK lseek 19 #endif 20 #endif 21 22 /* Local functions */ 23 local void gz_reset OF((gz_statep)); 24 local gzFile gz_open OF((const void *, int, const char *)); 25 26 #if defined UNDER_CE 27 28 /* Map the Windows error number in ERROR to a locale-dependent error message 29 string and return a pointer to it. Typically, the values for ERROR come 30 from GetLastError. 31 32 The string pointed to shall not be modified by the application, but may be 33 overwritten by a subsequent call to gz_strwinerror 34 35 The gz_strwinerror function does not change the current setting of 36 GetLastError. */ 37 char ZLIB_INTERNAL *gz_strwinerror (error) 38 DWORD error; 39 { 40 static char buf[1024]; 41 42 wchar_t *msgbuf; 43 DWORD lasterr = GetLastError(); 44 DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM 45 | FORMAT_MESSAGE_ALLOCATE_BUFFER, 46 NULL, 47 error, 48 0, /* Default language */ 49 (LPVOID)&msgbuf, 50 0, 51 NULL); 52 if (chars != 0) { 53 /* If there is an \r\n appended, zap it. */ 54 if (chars >= 2 55 && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { 56 chars -= 2; 57 msgbuf[chars] = 0; 58 } 59 60 if (chars > sizeof (buf) - 1) { 61 chars = sizeof (buf) - 1; 62 msgbuf[chars] = 0; 63 } 64 65 wcstombs(buf, msgbuf, chars + 1); 66 LocalFree(msgbuf); 67 } 68 else { 69 sprintf(buf, "unknown win32 error (%ld)", error); 70 } 71 72 SetLastError(lasterr); 73 return buf; 74 } 75 76 #endif /* UNDER_CE */ 77 78 /* Reset gzip file state */ 79 local void gz_reset(state) 80 gz_statep state; 81 { 82 state->x.have = 0; /* no output data available */ 83 if (state->mode == GZ_READ) { /* for reading ... */ 84 state->eof = 0; /* not at end of file */ 85 state->past = 0; /* have not read past end yet */ 86 state->how = LOOK; /* look for gzip header */ 87 } 88 else /* for writing ... */ 89 state->reset = 0; /* no deflateReset pending */ 90 state->seek = 0; /* no seek request pending */ 91 gz_error(state, Z_OK, NULL); /* clear error */ 92 state->x.pos = 0; /* no uncompressed data yet */ 93 state->strm.avail_in = 0; /* no input data yet */ 94 } 95 96 /* Open a gzip file either by name or file descriptor. */ 97 local gzFile gz_open(path, fd, mode) 98 const void *path; 99 int fd; 100 const char *mode; 101 { 102 gz_statep state; 103 z_size_t len; 104 int oflag; 105 #ifdef O_CLOEXEC 106 int cloexec = 0; 107 #endif 108 #ifdef O_EXCL 109 int exclusive = 0; 110 #endif 111 112 /* check input */ 113 if (path == NULL) 114 return NULL; 115 116 /* allocate gzFile structure to return */ 117 state = (gz_statep)malloc(sizeof(gz_state)); 118 if (state == NULL) 119 return NULL; 120 state->size = 0; /* no buffers allocated yet */ 121 state->want = GZBUFSIZE; /* requested buffer size */ 122 state->msg = NULL; /* no error message yet */ 123 124 /* interpret mode */ 125 state->mode = GZ_NONE; 126 state->level = Z_DEFAULT_COMPRESSION; 127 state->strategy = Z_DEFAULT_STRATEGY; 128 state->direct = 0; 129 while (*mode) { 130 if (*mode >= '0' && *mode <= '9') 131 state->level = *mode - '0'; 132 else 133 switch (*mode) { 134 case 'r': 135 state->mode = GZ_READ; 136 break; 137 #ifndef NO_GZCOMPRESS 138 case 'w': 139 state->mode = GZ_WRITE; 140 break; 141 case 'a': 142 state->mode = GZ_APPEND; 143 break; 144 #endif 145 case '+': /* can't read and write at the same time */ 146 free(state); 147 return NULL; 148 case 'b': /* ignore -- will request binary anyway */ 149 break; 150 #ifdef O_CLOEXEC 151 case 'e': 152 cloexec = 1; 153 break; 154 #endif 155 #ifdef O_EXCL 156 case 'x': 157 exclusive = 1; 158 break; 159 #endif 160 case 'f': 161 state->strategy = Z_FILTERED; 162 break; 163 case 'h': 164 state->strategy = Z_HUFFMAN_ONLY; 165 break; 166 case 'R': 167 state->strategy = Z_RLE; 168 break; 169 case 'F': 170 state->strategy = Z_FIXED; 171 break; 172 case 'T': 173 state->direct = 1; 174 break; 175 default: /* could consider as an error, but just ignore */ 176 ; 177 } 178 mode++; 179 } 180 181 /* must provide an "r", "w", or "a" */ 182 if (state->mode == GZ_NONE) { 183 free(state); 184 return NULL; 185 } 186 187 /* can't force transparent read */ 188 if (state->mode == GZ_READ) { 189 if (state->direct) { 190 free(state); 191 return NULL; 192 } 193 state->direct = 1; /* for empty file */ 194 } 195 196 /* save the path name for error messages */ 197 #ifdef WIDECHAR 198 if (fd == -2) { 199 len = wcstombs(NULL, path, 0); 200 if (len == (z_size_t)-1) 201 len = 0; 202 } 203 else 204 #endif 205 len = strlen((const char *)path); 206 state->path = (char *)malloc(len + 1); 207 if (state->path == NULL) { 208 free(state); 209 return NULL; 210 } 211 #ifdef WIDECHAR 212 if (fd == -2) 213 if (len) 214 wcstombs(state->path, path, len + 1); 215 else 216 *(state->path) = 0; 217 else 218 #endif 219 #if !defined(NO_snprintf) && !defined(NO_vsnprintf) 220 (void)snprintf(state->path, len + 1, "%s", (const char *)path); 221 #else 222 strcpy(state->path, path); 223 #endif 224 225 /* compute the flags for open() */ 226 oflag = 227 #ifdef O_LARGEFILE 228 O_LARGEFILE | 229 #endif 230 #ifdef O_BINARY 231 O_BINARY | 232 #endif 233 #ifdef O_CLOEXEC 234 (cloexec ? O_CLOEXEC : 0) | 235 #endif 236 (state->mode == GZ_READ ? 237 O_RDONLY : 238 (O_WRONLY | O_CREAT | 239 #ifdef O_EXCL 240 (exclusive ? O_EXCL : 0) | 241 #endif 242 (state->mode == GZ_WRITE ? 243 O_TRUNC : 244 O_APPEND))); 245 246 /* open the file with the appropriate flags (or just use fd) */ 247 state->fd = fd > -1 ? fd : ( 248 #ifdef WIDECHAR 249 fd == -2 ? _wopen(path, oflag, 0666) : 250 #endif 251 open((const char *)path, oflag, 0666)); 252 if (state->fd == -1) { 253 free(state->path); 254 free(state); 255 return NULL; 256 } 257 if (state->mode == GZ_APPEND) { 258 LSEEK(state->fd, 0, SEEK_END); /* so gzoffset() is correct */ 259 state->mode = GZ_WRITE; /* simplify later checks */ 260 } 261 262 /* save the current position for rewinding (only if reading) */ 263 if (state->mode == GZ_READ) { 264 state->start = LSEEK(state->fd, 0, SEEK_CUR); 265 if (state->start == -1) state->start = 0; 266 } 267 268 /* initialize stream */ 269 gz_reset(state); 270 271 /* return stream */ 272 return (gzFile)state; 273 } 274 275 /* -- see zlib.h -- */ 276 gzFile ZEXPORT gzopen(path, mode) 277 const char *path; 278 const char *mode; 279 { 280 return gz_open(path, -1, mode); 281 } 282 283 /* -- see zlib.h -- */ 284 gzFile ZEXPORT gzopen64(path, mode) 285 const char *path; 286 const char *mode; 287 { 288 return gz_open(path, -1, mode); 289 } 290 291 /* -- see zlib.h -- */ 292 gzFile ZEXPORT gzdopen(fd, mode) 293 int fd; 294 const char *mode; 295 { 296 char *path; /* identifier for error messages */ 297 gzFile gz; 298 299 if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL) 300 return NULL; 301 #if !defined(NO_snprintf) && !defined(NO_vsnprintf) 302 (void)snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd); 303 #else 304 sprintf(path, "<fd:%d>", fd); /* for debugging */ 305 #endif 306 gz = gz_open(path, fd, mode); 307 free(path); 308 return gz; 309 } 310 311 /* -- see zlib.h -- */ 312 #ifdef WIDECHAR 313 gzFile ZEXPORT gzopen_w(path, mode) 314 const wchar_t *path; 315 const char *mode; 316 { 317 return gz_open(path, -2, mode); 318 } 319 #endif 320 321 /* -- see zlib.h -- */ 322 int ZEXPORT gzbuffer(file, size) 323 gzFile file; 324 unsigned size; 325 { 326 gz_statep state; 327 328 /* get internal structure and check integrity */ 329 if (file == NULL) 330 return -1; 331 state = (gz_statep)file; 332 if (state->mode != GZ_READ && state->mode != GZ_WRITE) 333 return -1; 334 335 /* make sure we haven't already allocated memory */ 336 if (state->size != 0) 337 return -1; 338 339 /* check and set requested size */ 340 if ((size << 1) < size) 341 return -1; /* need to be able to double it */ 342 if (size < 2) 343 size = 2; /* need two bytes to check magic header */ 344 state->want = size; 345 return 0; 346 } 347 348 /* -- see zlib.h -- */ 349 int ZEXPORT gzrewind(file) 350 gzFile file; 351 { 352 gz_statep state; 353 354 /* get internal structure */ 355 if (file == NULL) 356 return -1; 357 state = (gz_statep)file; 358 359 /* check that we're reading and that there's no error */ 360 if (state->mode != GZ_READ || 361 (state->err != Z_OK && state->err != Z_BUF_ERROR)) 362 return -1; 363 364 /* back up and start over */ 365 if (LSEEK(state->fd, state->start, SEEK_SET) == -1) 366 return -1; 367 gz_reset(state); 368 return 0; 369 } 370 371 /* -- see zlib.h -- */ 372 z_off64_t ZEXPORT gzseek64(file, offset, whence) 373 gzFile file; 374 z_off64_t offset; 375 int whence; 376 { 377 unsigned n; 378 z_off64_t ret; 379 gz_statep state; 380 381 /* get internal structure and check integrity */ 382 if (file == NULL) 383 return -1; 384 state = (gz_statep)file; 385 if (state->mode != GZ_READ && state->mode != GZ_WRITE) 386 return -1; 387 388 /* check that there's no error */ 389 if (state->err != Z_OK && state->err != Z_BUF_ERROR) 390 return -1; 391 392 /* can only seek from start or relative to current position */ 393 if (whence != SEEK_SET && whence != SEEK_CUR) 394 return -1; 395 396 /* normalize offset to a SEEK_CUR specification */ 397 if (whence == SEEK_SET) 398 offset -= state->x.pos; 399 else if (state->seek) 400 offset += state->skip; 401 state->seek = 0; 402 403 /* if within raw area while reading, just go there */ 404 if (state->mode == GZ_READ && state->how == COPY && 405 state->x.pos + offset >= 0) { 406 ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR); 407 if (ret == -1) 408 return -1; 409 state->x.have = 0; 410 state->eof = 0; 411 state->past = 0; 412 state->seek = 0; 413 gz_error(state, Z_OK, NULL); 414 state->strm.avail_in = 0; 415 state->x.pos += offset; 416 return state->x.pos; 417 } 418 419 /* calculate skip amount, rewinding if needed for back seek when reading */ 420 if (offset < 0) { 421 if (state->mode != GZ_READ) /* writing -- can't go backwards */ 422 return -1; 423 offset += state->x.pos; 424 if (offset < 0) /* before start of file! */ 425 return -1; 426 if (gzrewind(file) == -1) /* rewind, then skip to offset */ 427 return -1; 428 } 429 430 /* if reading, skip what's in output buffer (one less gzgetc() check) */ 431 if (state->mode == GZ_READ) { 432 n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? 433 (unsigned)offset : state->x.have; 434 state->x.have -= n; 435 state->x.next += n; 436 state->x.pos += n; 437 offset -= n; 438 } 439 440 /* request skip (if not zero) */ 441 if (offset) { 442 state->seek = 1; 443 state->skip = offset; 444 } 445 return state->x.pos + offset; 446 } 447 448 /* -- see zlib.h -- */ 449 z_off_t ZEXPORT gzseek(file, offset, whence) 450 gzFile file; 451 z_off_t offset; 452 int whence; 453 { 454 z_off64_t ret; 455 456 ret = gzseek64(file, (z_off64_t)offset, whence); 457 return ret == (z_off_t)ret ? (z_off_t)ret : -1; 458 } 459 460 /* -- see zlib.h -- */ 461 z_off64_t ZEXPORT gztell64(file) 462 gzFile file; 463 { 464 gz_statep state; 465 466 /* get internal structure and check integrity */ 467 if (file == NULL) 468 return -1; 469 state = (gz_statep)file; 470 if (state->mode != GZ_READ && state->mode != GZ_WRITE) 471 return -1; 472 473 /* return position */ 474 return state->x.pos + (state->seek ? state->skip : 0); 475 } 476 477 /* -- see zlib.h -- */ 478 z_off_t ZEXPORT gztell(file) 479 gzFile file; 480 { 481 z_off64_t ret; 482 483 ret = gztell64(file); 484 return ret == (z_off_t)ret ? (z_off_t)ret : -1; 485 } 486 487 /* -- see zlib.h -- */ 488 z_off64_t ZEXPORT gzoffset64(file) 489 gzFile file; 490 { 491 z_off64_t offset; 492 gz_statep state; 493 494 /* get internal structure and check integrity */ 495 if (file == NULL) 496 return -1; 497 state = (gz_statep)file; 498 if (state->mode != GZ_READ && state->mode != GZ_WRITE) 499 return -1; 500 501 /* compute and return effective offset in file */ 502 offset = LSEEK(state->fd, 0, SEEK_CUR); 503 if (offset == -1) 504 return -1; 505 if (state->mode == GZ_READ) /* reading */ 506 offset -= state->strm.avail_in; /* don't count buffered input */ 507 return offset; 508 } 509 510 /* -- see zlib.h -- */ 511 z_off_t ZEXPORT gzoffset(file) 512 gzFile file; 513 { 514 z_off64_t ret; 515 516 ret = gzoffset64(file); 517 return ret == (z_off_t)ret ? (z_off_t)ret : -1; 518 } 519 520 /* -- see zlib.h -- */ 521 int ZEXPORT gzeof(file) 522 gzFile file; 523 { 524 gz_statep state; 525 526 /* get internal structure and check integrity */ 527 if (file == NULL) 528 return 0; 529 state = (gz_statep)file; 530 if (state->mode != GZ_READ && state->mode != GZ_WRITE) 531 return 0; 532 533 /* return end-of-file state */ 534 return state->mode == GZ_READ ? state->past : 0; 535 } 536 537 /* -- see zlib.h -- */ 538 const char * ZEXPORT gzerror(file, errnum) 539 gzFile file; 540 int *errnum; 541 { 542 gz_statep state; 543 544 /* get internal structure and check integrity */ 545 if (file == NULL) 546 return NULL; 547 state = (gz_statep)file; 548 if (state->mode != GZ_READ && state->mode != GZ_WRITE) 549 return NULL; 550 551 /* return error information */ 552 if (errnum != NULL) 553 *errnum = state->err; 554 return state->err == Z_MEM_ERROR ? "out of memory" : 555 (state->msg == NULL ? "" : state->msg); 556 } 557 558 /* -- see zlib.h -- */ 559 void ZEXPORT gzclearerr(file) 560 gzFile file; 561 { 562 gz_statep state; 563 564 /* get internal structure and check integrity */ 565 if (file == NULL) 566 return; 567 state = (gz_statep)file; 568 if (state->mode != GZ_READ && state->mode != GZ_WRITE) 569 return; 570 571 /* clear error and end-of-file */ 572 if (state->mode == GZ_READ) { 573 state->eof = 0; 574 state->past = 0; 575 } 576 gz_error(state, Z_OK, NULL); 577 } 578 579 /* Create an error message in allocated memory and set state->err and 580 state->msg accordingly. Free any previous error message already there. Do 581 not try to free or allocate space if the error is Z_MEM_ERROR (out of 582 memory). Simply save the error message as a static string. If there is an 583 allocation failure constructing the error message, then convert the error to 584 out of memory. */ 585 void ZLIB_INTERNAL gz_error(state, err, msg) 586 gz_statep state; 587 int err; 588 const char *msg; 589 { 590 /* free previously allocated message and clear */ 591 if (state->msg != NULL) { 592 if (state->err != Z_MEM_ERROR) 593 free(state->msg); 594 state->msg = NULL; 595 } 596 597 /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */ 598 if (err != Z_OK && err != Z_BUF_ERROR) 599 state->x.have = 0; 600 601 /* set error code, and if no message, then done */ 602 state->err = err; 603 if (msg == NULL) 604 return; 605 606 /* for an out of memory error, return literal string when requested */ 607 if (err == Z_MEM_ERROR) 608 return; 609 610 /* construct error message with path */ 611 if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) == 612 NULL) { 613 state->err = Z_MEM_ERROR; 614 return; 615 } 616 #if !defined(NO_snprintf) && !defined(NO_vsnprintf) 617 (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, 618 "%s%s%s", state->path, ": ", msg); 619 #else 620 strcpy(state->msg, state->path); 621 strcat(state->msg, ": "); 622 strcat(state->msg, msg); 623 #endif 624 } 625 626 #ifndef INT_MAX 627 /* portably return maximum value for an int (when limits.h presumed not 628 available) -- we need to do this to cover cases where 2's complement not 629 used, since C standard permits 1's complement and sign-bit representations, 630 otherwise we could just use ((unsigned)-1) >> 1 */ 631 unsigned ZLIB_INTERNAL gz_intmax() 632 { 633 unsigned p, q; 634 635 p = 1; 636 do { 637 q = p; 638 p <<= 1; 639 p++; 640 } while (p > q); 641 return q >> 1; 642 } 643 #endif 644