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