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