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