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