1 /* 2 * Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * Support for reading ZIP/JAR files. 28 */ 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <stddef.h> 33 #include <string.h> 34 #include <fcntl.h> 35 #include <limits.h> 36 #include <time.h> 37 #include <ctype.h> 38 #include <assert.h> 39 40 #include "jni.h" 41 #include "jni_util.h" 42 #include "jlong.h" 43 #include "jvm.h" 44 #include "io_util.h" 45 #include "io_util_md.h" 46 #include "zip_util.h" 47 #include <zlib.h> 48 49 #ifdef _ALLBSD_SOURCE 50 #define off64_t off_t 51 #define mmap64 mmap 52 #endif 53 54 /* USE_MMAP means mmap the CEN & ENDHDR part of the zip file. */ 55 #ifdef USE_MMAP 56 #include <sys/mman.h> 57 #endif 58 59 #define MAXREFS 0xFFFF /* max number of open zip file references */ 60 61 #define MCREATE() JVM_RawMonitorCreate() 62 #define MLOCK(lock) JVM_RawMonitorEnter(lock) 63 #define MUNLOCK(lock) JVM_RawMonitorExit(lock) 64 #define MDESTROY(lock) JVM_RawMonitorDestroy(lock) 65 66 #define CENSIZE(cen) (CENHDR + CENNAM(cen) + CENEXT(cen) + CENCOM(cen)) 67 68 static jzfile *zfiles = 0; /* currently open zip files */ 69 static void *zfiles_lock = 0; 70 71 static void freeCEN(jzfile *); 72 73 #ifndef PATH_MAX 74 #define PATH_MAX 1024 75 #endif 76 77 static jint INITIAL_META_COUNT = 2; /* initial number of entries in meta name array */ 78 79 /* 80 * Declare library specific JNI_Onload entry if static build 81 */ 82 #ifdef STATIC_BUILD 83 DEF_STATIC_JNI_OnLoad 84 #endif 85 86 /* 87 * The ZFILE_* functions exist to provide some platform-independence with 88 * respect to file access needs. 89 */ 90 91 /* 92 * Opens the named file for reading, returning a ZFILE. 93 * 94 * Compare this with winFileHandleOpen in windows/native/java/io/io_util_md.c. 95 * This function does not take JNIEnv* and uses CreateFile (instead of 96 * CreateFileW). The expectation is that this function will be called only 97 * from ZIP_Open_Generic, which in turn is used by the JVM, where we do not 98 * need to concern ourselves with wide chars. 99 */ 100 static ZFILE 101 ZFILE_Open(const char *fname, int flags) { 102 #ifdef WIN32 103 WCHAR *wfname, *wprefixed_fname; 104 size_t converted_chars, fname_length; 105 jlong fhandle; 106 const DWORD access = 107 (flags & O_RDWR) ? (GENERIC_WRITE | GENERIC_READ) : 108 (flags & O_WRONLY) ? GENERIC_WRITE : 109 GENERIC_READ; 110 const DWORD sharing = 111 FILE_SHARE_READ | FILE_SHARE_WRITE; 112 const DWORD disposition = 113 /* Note: O_TRUNC overrides O_CREAT */ 114 (flags & O_TRUNC) ? CREATE_ALWAYS : 115 (flags & O_CREAT) ? OPEN_ALWAYS : 116 OPEN_EXISTING; 117 const DWORD maybeWriteThrough = 118 (flags & (O_SYNC | O_DSYNC)) ? 119 FILE_FLAG_WRITE_THROUGH : 120 FILE_ATTRIBUTE_NORMAL; 121 const DWORD maybeDeleteOnClose = 122 (flags & O_TEMPORARY) ? 123 FILE_FLAG_DELETE_ON_CLOSE : 124 FILE_ATTRIBUTE_NORMAL; 125 const DWORD flagsAndAttributes = maybeWriteThrough | maybeDeleteOnClose; 126 127 fname_length = strlen(fname); 128 if (fname_length < MAX_PATH) { 129 return (jlong)CreateFile( 130 fname, /* path name in multibyte char */ 131 access, /* Read and/or write permission */ 132 sharing, /* File sharing flags */ 133 NULL, /* Security attributes */ 134 disposition, /* creation disposition */ 135 flagsAndAttributes, /* flags and attributes */ 136 NULL); 137 } else { 138 if ((wfname = (WCHAR*)malloc((fname_length + 1) * sizeof(WCHAR))) == NULL) 139 return (jlong)INVALID_HANDLE_VALUE; 140 141 if (mbstowcs_s(&converted_chars, wfname, fname_length + 1, fname, fname_length) != 0) { 142 free(wfname); 143 return (jlong)INVALID_HANDLE_VALUE; 144 } 145 wprefixed_fname = getPrefixed(wfname, (int)fname_length); 146 fhandle = (jlong)CreateFileW( 147 wprefixed_fname, /* Wide char path name */ 148 access, /* Read and/or write permission */ 149 sharing, /* File sharing flags */ 150 NULL, /* Security attributes */ 151 disposition, /* creation disposition */ 152 flagsAndAttributes, /* flags and attributes */ 153 NULL); 154 free(wfname); 155 free(wprefixed_fname); 156 return fhandle; 157 } 158 #else 159 return open(fname, flags, 0); 160 #endif 161 } 162 163 /* 164 * The io_util_md.h files do not provide IO_CLOSE, hence we use platform 165 * specifics. 166 */ 167 static void 168 ZFILE_Close(ZFILE zfd) { 169 #ifdef WIN32 170 CloseHandle((HANDLE) zfd); 171 #else 172 close(zfd); 173 #endif 174 } 175 176 static int 177 ZFILE_read(ZFILE zfd, char *buf, jint nbytes) { 178 #ifdef WIN32 179 return (int) IO_Read(zfd, buf, nbytes); 180 #else 181 return read(zfd, buf, nbytes); 182 #endif 183 } 184 185 /* 186 * Initialize zip file support. Return 0 if successful otherwise -1 187 * if could not be initialized. 188 */ 189 static jint 190 InitializeZip() 191 { 192 static jboolean inited = JNI_FALSE; 193 194 // Initialize errno to 0. It may be set later (e.g. during memory 195 // allocation) but we can disregard previous values. 196 errno = 0; 197 198 if (inited) 199 return 0; 200 zfiles_lock = MCREATE(); 201 if (zfiles_lock == 0) { 202 return -1; 203 } 204 inited = JNI_TRUE; 205 206 return 0; 207 } 208 209 /* 210 * Reads len bytes of data into buf. 211 * Returns 0 if all bytes could be read, otherwise returns -1. 212 */ 213 static int 214 readFully(ZFILE zfd, void *buf, jlong len) { 215 char *bp = (char *) buf; 216 217 while (len > 0) { 218 jlong limit = ((((jlong) 1) << 31) - 1); 219 jint count = (len < limit) ? 220 (jint) len : 221 (jint) limit; 222 jint n = ZFILE_read(zfd, bp, count); 223 if (n > 0) { 224 bp += n; 225 len -= n; 226 } else if (n == -1 && errno == EINTR) { 227 /* Retry after EINTR (interrupted by signal). */ 228 continue; 229 } else { /* EOF or IO error */ 230 return -1; 231 } 232 } 233 return 0; 234 } 235 236 /* 237 * Reads len bytes of data from the specified offset into buf. 238 * Returns 0 if all bytes could be read, otherwise returns -1. 239 */ 240 static int 241 readFullyAt(ZFILE zfd, void *buf, jlong len, jlong offset) 242 { 243 if (IO_Lseek(zfd, offset, SEEK_SET) == -1) { 244 return -1; /* lseek failure. */ 245 } 246 247 return readFully(zfd, buf, len); 248 } 249 250 /* 251 * Allocates a new zip file object for the specified file name. 252 * Returns the zip file object or NULL if not enough memory. 253 */ 254 static jzfile * 255 allocZip(const char *name) 256 { 257 jzfile *zip; 258 if (((zip = calloc(1, sizeof(jzfile))) != NULL) && 259 ((zip->name = strdup(name)) != NULL) && 260 ((zip->lock = MCREATE()) != NULL)) { 261 zip->zfd = -1; 262 return zip; 263 } 264 265 if (zip != NULL) { 266 free(zip->name); 267 free(zip); 268 } 269 return NULL; 270 } 271 272 /* 273 * Frees all native resources owned by the specified zip file object. 274 */ 275 static void 276 freeZip(jzfile *zip) 277 { 278 /* First free any cached jzentry */ 279 ZIP_FreeEntry(zip,0); 280 if (zip->lock != NULL) MDESTROY(zip->lock); 281 free(zip->name); 282 freeCEN(zip); 283 284 #ifdef USE_MMAP 285 if (zip->usemmap) { 286 if (zip->maddr != NULL) 287 munmap((char *)zip->maddr, zip->mlen); 288 } else 289 #endif 290 { 291 free(zip->cencache.data); 292 } 293 if (zip->comment != NULL) 294 free(zip->comment); 295 if (zip->zfd != -1) ZFILE_Close(zip->zfd); 296 free(zip); 297 } 298 299 /* The END header is followed by a variable length comment of size < 64k. */ 300 static const jlong END_MAXLEN = 0xFFFF + ENDHDR; 301 302 #define READBLOCKSZ 128 303 304 static jboolean verifyEND(jzfile *zip, jlong endpos, char *endbuf) { 305 /* ENDSIG matched, however the size of file comment in it does not 306 match the real size. One "common" cause for this problem is some 307 "extra" bytes are padded at the end of the zipfile. 308 Let's do some extra verification, we don't care about the performance 309 in this situation. 310 */ 311 jlong cenpos = endpos - ENDSIZ(endbuf); 312 jlong locpos = cenpos - ENDOFF(endbuf); 313 char buf[4]; 314 return (cenpos >= 0 && 315 locpos >= 0 && 316 readFullyAt(zip->zfd, buf, sizeof(buf), cenpos) != -1 && 317 CENSIG_AT(buf) && 318 readFullyAt(zip->zfd, buf, sizeof(buf), locpos) != -1 && 319 LOCSIG_AT(buf)); 320 } 321 322 /* 323 * Searches for end of central directory (END) header. The contents of 324 * the END header will be read and placed in endbuf. Returns the file 325 * position of the END header, otherwise returns -1 if the END header 326 * was not found or an error occurred. 327 */ 328 static jlong 329 findEND(jzfile *zip, void *endbuf) 330 { 331 char buf[READBLOCKSZ]; 332 jlong pos; 333 const jlong len = zip->len; 334 const ZFILE zfd = zip->zfd; 335 const jlong minHDR = len - END_MAXLEN > 0 ? len - END_MAXLEN : 0; 336 const jlong minPos = minHDR - (sizeof(buf)-ENDHDR); 337 jint clen; 338 339 for (pos = len - sizeof(buf); pos >= minPos; pos -= (sizeof(buf)-ENDHDR)) { 340 341 int i; 342 jlong off = 0; 343 if (pos < 0) { 344 /* Pretend there are some NUL bytes before start of file */ 345 off = -pos; 346 memset(buf, '\0', (size_t)off); 347 } 348 349 if (readFullyAt(zfd, buf + off, sizeof(buf) - off, 350 pos + off) == -1) { 351 return -1; /* System error */ 352 } 353 354 /* Now scan the block backwards for END header signature */ 355 for (i = sizeof(buf) - ENDHDR; i >= 0; i--) { 356 if (buf[i+0] == 'P' && 357 buf[i+1] == 'K' && 358 buf[i+2] == '\005' && 359 buf[i+3] == '\006' && 360 ((pos + i + ENDHDR + ENDCOM(buf + i) == len) 361 || verifyEND(zip, pos + i, buf + i))) { 362 /* Found END header */ 363 memcpy(endbuf, buf + i, ENDHDR); 364 365 clen = ENDCOM(endbuf); 366 if (clen != 0) { 367 zip->comment = malloc(clen + 1); 368 if (zip->comment == NULL) { 369 return -1; 370 } 371 if (readFullyAt(zfd, zip->comment, clen, pos + i + ENDHDR) 372 == -1) { 373 free(zip->comment); 374 zip->comment = NULL; 375 return -1; 376 } 377 zip->comment[clen] = '\0'; 378 zip->clen = clen; 379 } 380 return pos + i; 381 } 382 } 383 } 384 385 return -1; /* END header not found */ 386 } 387 388 /* 389 * Searches for the ZIP64 end of central directory (END) header. The 390 * contents of the ZIP64 END header will be read and placed in end64buf. 391 * Returns the file position of the ZIP64 END header, otherwise returns 392 * -1 if the END header was not found or an error occurred. 393 * 394 * The ZIP format specifies the "position" of each related record as 395 * ... 396 * [central directory] 397 * [zip64 end of central directory record] 398 * [zip64 end of central directory locator] 399 * [end of central directory record] 400 * 401 * The offset of zip64 end locator can be calculated from endpos as 402 * "endpos - ZIP64_LOCHDR". 403 * The "offset" of zip64 end record is stored in zip64 end locator. 404 */ 405 static jlong 406 findEND64(jzfile *zip, void *end64buf, jlong endpos) 407 { 408 char loc64[ZIP64_LOCHDR]; 409 jlong end64pos; 410 if (readFullyAt(zip->zfd, loc64, ZIP64_LOCHDR, endpos - ZIP64_LOCHDR) == -1) { 411 return -1; // end64 locator not found 412 } 413 end64pos = ZIP64_LOCOFF(loc64); 414 if (readFullyAt(zip->zfd, end64buf, ZIP64_ENDHDR, end64pos) == -1) { 415 return -1; // end64 record not found 416 } 417 return end64pos; 418 } 419 420 /* 421 * Returns a hash code value for a C-style NUL-terminated string. 422 */ 423 static unsigned int 424 hash(const char *s) 425 { 426 int h = 0; 427 while (*s != '\0') 428 h = 31*h + *s++; 429 return h; 430 } 431 432 /* 433 * Returns a hash code value for a string of a specified length. 434 */ 435 static unsigned int 436 hashN(const char *s, int length) 437 { 438 int h = 0; 439 while (length-- > 0) 440 h = 31*h + *s++; 441 return h; 442 } 443 444 static unsigned int 445 hash_append(unsigned int hash, char c) 446 { 447 return ((int)hash)*31 + c; 448 } 449 450 /* 451 * Returns true if the specified entry's name begins with the string 452 * "META-INF/" irrespective of case. 453 */ 454 static int 455 isMetaName(const char *name, int length) 456 { 457 const char *s; 458 if (length < (int)sizeof("META-INF/") - 1) 459 return 0; 460 for (s = "META-INF/"; *s != '\0'; s++) { 461 char c = *name++; 462 // Avoid toupper; it's locale-dependent 463 if (c >= 'a' && c <= 'z') c += 'A' - 'a'; 464 if (*s != c) 465 return 0; 466 } 467 return 1; 468 } 469 470 /* 471 * Increases the capacity of zip->metanames. 472 * Returns non-zero in case of allocation error. 473 */ 474 static int 475 growMetaNames(jzfile *zip) 476 { 477 jint i; 478 /* double the meta names array */ 479 const jint new_metacount = zip->metacount << 1; 480 zip->metanames = 481 realloc(zip->metanames, new_metacount * sizeof(zip->metanames[0])); 482 if (zip->metanames == NULL) return -1; 483 for (i = zip->metacount; i < new_metacount; i++) 484 zip->metanames[i] = NULL; 485 zip->metacurrent = zip->metacount; 486 zip->metacount = new_metacount; 487 return 0; 488 } 489 490 /* 491 * Adds name to zip->metanames. 492 * Returns non-zero in case of allocation error. 493 */ 494 static int 495 addMetaName(jzfile *zip, const char *name, int length) 496 { 497 jint i; 498 if (zip->metanames == NULL) { 499 zip->metacount = INITIAL_META_COUNT; 500 zip->metanames = calloc(zip->metacount, sizeof(zip->metanames[0])); 501 if (zip->metanames == NULL) return -1; 502 zip->metacurrent = 0; 503 } 504 505 i = zip->metacurrent; 506 507 /* current meta name array isn't full yet. */ 508 if (i < zip->metacount) { 509 zip->metanames[i] = (char *) malloc(length+1); 510 if (zip->metanames[i] == NULL) return -1; 511 memcpy(zip->metanames[i], name, length); 512 zip->metanames[i][length] = '\0'; 513 zip->metacurrent++; 514 return 0; 515 } 516 517 /* No free entries in zip->metanames? */ 518 if (growMetaNames(zip) != 0) return -1; 519 return addMetaName(zip, name, length); 520 } 521 522 static void 523 freeMetaNames(jzfile *zip) 524 { 525 if (zip->metanames) { 526 jint i; 527 for (i = 0; i < zip->metacount; i++) 528 free(zip->metanames[i]); 529 free(zip->metanames); 530 zip->metanames = NULL; 531 } 532 } 533 534 /* Free Zip data allocated by readCEN() */ 535 static void 536 freeCEN(jzfile *zip) 537 { 538 free(zip->entries); zip->entries = NULL; 539 free(zip->table); zip->table = NULL; 540 freeMetaNames(zip); 541 } 542 543 /* 544 * Counts the number of CEN headers in a central directory extending 545 * from BEG to END. Might return a bogus answer if the zip file is 546 * corrupt, but will not crash. 547 */ 548 static jint 549 countCENHeaders(unsigned char *beg, unsigned char *end) 550 { 551 jint count = 0; 552 ptrdiff_t i; 553 for (i = 0; i + CENHDR <= end - beg; i += CENSIZE(beg + i)) 554 count++; 555 return count; 556 } 557 558 #define ZIP_FORMAT_ERROR(message) \ 559 if (1) { zip->msg = message; goto Catch; } else ((void)0) 560 561 /* 562 * Reads zip file central directory. Returns the file position of first 563 * CEN header, otherwise returns -1 if an error occurred. If zip->msg != NULL 564 * then the error was a zip format error and zip->msg has the error text. 565 * Always pass in -1 for knownTotal; it's used for a recursive call. 566 */ 567 static jlong 568 readCEN(jzfile *zip, jint knownTotal) 569 { 570 /* Following are unsigned 32-bit */ 571 jlong endpos, end64pos, cenpos, cenlen, cenoff; 572 /* Following are unsigned 16-bit */ 573 jint total, tablelen, i, j; 574 unsigned char *cenbuf = NULL; 575 unsigned char *cenend; 576 unsigned char *cp; 577 #ifdef USE_MMAP 578 static jlong pagesize; 579 jlong offset; 580 #endif 581 unsigned char endbuf[ENDHDR]; 582 jint endhdrlen = ENDHDR; 583 jzcell *entries; 584 jint *table; 585 586 /* Clear previous zip error */ 587 zip->msg = NULL; 588 /* Get position of END header */ 589 if ((endpos = findEND(zip, endbuf)) == -1) 590 return -1; /* no END header or system error */ 591 592 if (endpos == 0) return 0; /* only END header present */ 593 594 freeCEN(zip); 595 /* Get position and length of central directory */ 596 cenlen = ENDSIZ(endbuf); 597 cenoff = ENDOFF(endbuf); 598 total = ENDTOT(endbuf); 599 if (cenlen == ZIP64_MAGICVAL || cenoff == ZIP64_MAGICVAL || 600 total == ZIP64_MAGICCOUNT) { 601 unsigned char end64buf[ZIP64_ENDHDR]; 602 if ((end64pos = findEND64(zip, end64buf, endpos)) != -1) { 603 cenlen = ZIP64_ENDSIZ(end64buf); 604 cenoff = ZIP64_ENDOFF(end64buf); 605 total = (jint)ZIP64_ENDTOT(end64buf); 606 endpos = end64pos; 607 endhdrlen = ZIP64_ENDHDR; 608 } 609 } 610 611 if (cenlen > endpos) { 612 ZIP_FORMAT_ERROR("invalid END header (bad central directory size)"); 613 } 614 cenpos = endpos - cenlen; 615 616 /* Get position of first local file (LOC) header, taking into 617 * account that there may be a stub prefixed to the zip file. */ 618 zip->locpos = cenpos - cenoff; 619 if (zip->locpos < 0) { 620 ZIP_FORMAT_ERROR("invalid END header (bad central directory offset)"); 621 } 622 #ifdef USE_MMAP 623 if (zip->usemmap) { 624 /* On Solaris & Linux prior to JDK 6, we used to mmap the whole jar file to 625 * read the jar file contents. However, this greatly increased the perceived 626 * footprint numbers because the mmap'ed pages were adding into the totals shown 627 * by 'ps' and 'top'. We switched to mmaping only the central directory of jar 628 * file while calling 'read' to read the rest of jar file. Here are a list of 629 * reasons apart from above of why we are doing so: 630 * 1. Greatly reduces mmap overhead after startup complete; 631 * 2. Avoids dual path code maintainance; 632 * 3. Greatly reduces risk of address space (not virtual memory) exhaustion. 633 */ 634 if (pagesize == 0) { 635 pagesize = (jlong)sysconf(_SC_PAGESIZE); 636 if (pagesize == 0) goto Catch; 637 } 638 if (cenpos > pagesize) { 639 offset = cenpos & ~(pagesize - 1); 640 } else { 641 offset = 0; 642 } 643 /* When we are not calling recursively, knownTotal is -1. */ 644 if (knownTotal == -1) { 645 void* mappedAddr; 646 /* Mmap the CEN and END part only. We have to figure 647 out the page size in order to make offset to be multiples of 648 page size. 649 */ 650 zip->mlen = cenpos - offset + cenlen + endhdrlen; 651 zip->offset = offset; 652 mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset); 653 zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL : 654 (unsigned char*)mappedAddr; 655 656 if (zip->maddr == NULL) { 657 jio_fprintf(stderr, "mmap failed for CEN and END part of zip file\n"); 658 goto Catch; 659 } 660 } 661 cenbuf = zip->maddr + cenpos - offset; 662 } else 663 #endif 664 { 665 if ((cenbuf = malloc((size_t) cenlen)) == NULL || 666 (readFullyAt(zip->zfd, cenbuf, cenlen, cenpos) == -1)) 667 goto Catch; 668 } 669 670 cenend = cenbuf + cenlen; 671 672 /* Initialize zip file data structures based on the total number 673 * of central directory entries as stored in ENDTOT. Since this 674 * is a 2-byte field, but we (and other zip implementations) 675 * support approx. 2**31 entries, we do not trust ENDTOT, but 676 * treat it only as a strong hint. When we call ourselves 677 * recursively, knownTotal will have the "true" value. 678 * 679 * Keep this path alive even with the Zip64 END support added, just 680 * for zip files that have more than 0xffff entries but don't have 681 * the Zip64 enabled. 682 */ 683 total = (knownTotal != -1) ? knownTotal : total; 684 entries = zip->entries = calloc(total, sizeof(entries[0])); 685 tablelen = zip->tablelen = ((total/2) | 1); // Odd -> fewer collisions 686 table = zip->table = malloc(tablelen * sizeof(table[0])); 687 /* According to ISO C it is perfectly legal for malloc to return zero 688 * if called with a zero argument. We check this for 'entries' but not 689 * for 'table' because 'tablelen' can't be zero (see computation above). */ 690 if ((entries == NULL && total != 0) || table == NULL) goto Catch; 691 for (j = 0; j < tablelen; j++) 692 table[j] = ZIP_ENDCHAIN; 693 694 /* Iterate through the entries in the central directory */ 695 for (i = 0, cp = cenbuf; cp <= cenend - CENHDR; i++, cp += CENSIZE(cp)) { 696 /* Following are unsigned 16-bit */ 697 jint method, nlen; 698 unsigned int hsh; 699 700 if (i >= total) { 701 /* This will only happen if the zip file has an incorrect 702 * ENDTOT field, which usually means it contains more than 703 * 65535 entries. */ 704 cenpos = readCEN(zip, countCENHeaders(cenbuf, cenend)); 705 goto Finally; 706 } 707 708 method = CENHOW(cp); 709 nlen = CENNAM(cp); 710 711 if (!CENSIG_AT(cp)) { 712 ZIP_FORMAT_ERROR("invalid CEN header (bad signature)"); 713 } 714 if (CENFLG(cp) & 1) { 715 ZIP_FORMAT_ERROR("invalid CEN header (encrypted entry)"); 716 } 717 if (method != STORED && method != DEFLATED) { 718 ZIP_FORMAT_ERROR("invalid CEN header (bad compression method)"); 719 } 720 if (cp + CENHDR + nlen > cenend) { 721 ZIP_FORMAT_ERROR("invalid CEN header (bad header size)"); 722 } 723 /* if the entry is metadata add it to our metadata names */ 724 if (isMetaName((char *)cp+CENHDR, nlen)) 725 if (addMetaName(zip, (char *)cp+CENHDR, nlen) != 0) 726 goto Catch; 727 728 /* Record the CEN offset and the name hash in our hash cell. */ 729 entries[i].cenpos = cenpos + (cp - cenbuf); 730 entries[i].hash = hashN((char *)cp+CENHDR, nlen); 731 732 /* Add the entry to the hash table */ 733 hsh = entries[i].hash % tablelen; 734 entries[i].next = table[hsh]; 735 table[hsh] = i; 736 } 737 if (cp != cenend) { 738 ZIP_FORMAT_ERROR("invalid CEN header (bad header size)"); 739 } 740 zip->total = i; 741 goto Finally; 742 743 Catch: 744 freeCEN(zip); 745 cenpos = -1; 746 747 Finally: 748 #ifdef USE_MMAP 749 if (!zip->usemmap) 750 #endif 751 free(cenbuf); 752 753 return cenpos; 754 } 755 756 /* 757 * Opens a zip file with the specified mode. Returns the jzfile object 758 * or NULL if an error occurred. If a zip error occurred then *pmsg will 759 * be set to the error message text if pmsg != 0. Otherwise, *pmsg will be 760 * set to NULL. Caller is responsible to free the error message. 761 */ 762 jzfile * 763 ZIP_Open_Generic(const char *name, char **pmsg, int mode, jlong lastModified) 764 { 765 jzfile *zip = NULL; 766 767 /* Clear zip error message */ 768 if (pmsg != NULL) { 769 *pmsg = NULL; 770 } 771 772 zip = ZIP_Get_From_Cache(name, pmsg, lastModified); 773 774 if (zip == NULL && pmsg != NULL && *pmsg == NULL) { 775 ZFILE zfd = ZFILE_Open(name, mode); 776 zip = ZIP_Put_In_Cache(name, zfd, pmsg, lastModified); 777 } 778 return zip; 779 } 780 781 /* 782 * Returns the jzfile corresponding to the given file name from the cache of 783 * zip files, or NULL if the file is not in the cache. If the name is longer 784 * than PATH_MAX or a zip error occurred then *pmsg will be set to the error 785 * message text if pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller 786 * is responsible to free the error message. 787 */ 788 jzfile * 789 ZIP_Get_From_Cache(const char *name, char **pmsg, jlong lastModified) 790 { 791 char buf[PATH_MAX]; 792 jzfile *zip; 793 794 if (InitializeZip()) { 795 return NULL; 796 } 797 798 /* Clear zip error message */ 799 if (pmsg != 0) { 800 *pmsg = NULL; 801 } 802 803 if (strlen(name) >= PATH_MAX) { 804 if (pmsg) { 805 *pmsg = strdup("zip file name too long"); 806 } 807 return NULL; 808 } 809 strcpy(buf, name); 810 JVM_NativePath(buf); 811 name = buf; 812 813 MLOCK(zfiles_lock); 814 for (zip = zfiles; zip != NULL; zip = zip->next) { 815 if (strcmp(name, zip->name) == 0 816 && (zip->lastModified == lastModified || zip->lastModified == 0) 817 && zip->refs < MAXREFS) { 818 zip->refs++; 819 break; 820 } 821 } 822 MUNLOCK(zfiles_lock); 823 return zip; 824 } 825 826 /* 827 * Reads data from the given file descriptor to create a jzfile, puts the 828 * jzfile in a cache, and returns that jzfile. Returns NULL in case of error. 829 * If a zip error occurs, then *pmsg will be set to the error message text if 830 * pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller is responsible to 831 * free the error message. 832 */ 833 834 jzfile * 835 ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified) 836 { 837 return ZIP_Put_In_Cache0(name, zfd, pmsg, lastModified, JNI_TRUE); 838 } 839 840 jzfile * 841 ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified, 842 jboolean usemmap) 843 { 844 char errbuf[256]; 845 jlong len; 846 jzfile *zip; 847 848 if ((zip = allocZip(name)) == NULL) { 849 return NULL; 850 } 851 852 #ifdef USE_MMAP 853 zip->usemmap = usemmap; 854 #endif 855 zip->refs = 1; 856 zip->lastModified = lastModified; 857 858 if (zfd == -1) { 859 if (pmsg && getLastErrorString(errbuf, sizeof(errbuf)) > 0) 860 *pmsg = strdup(errbuf); 861 freeZip(zip); 862 return NULL; 863 } 864 865 // Assumption, zfd refers to start of file. Trivially, reuse errbuf. 866 if (readFully(zfd, errbuf, 4) != -1) { // errors will be handled later 867 zip->locsig = LOCSIG_AT(errbuf) ? JNI_TRUE : JNI_FALSE; 868 } 869 870 len = zip->len = IO_Lseek(zfd, 0, SEEK_END); 871 if (len <= 0) { 872 if (len == 0) { /* zip file is empty */ 873 if (pmsg) { 874 *pmsg = strdup("zip file is empty"); 875 } 876 } else { /* error */ 877 if (pmsg && getLastErrorString(errbuf, sizeof(errbuf)) > 0) 878 *pmsg = strdup(errbuf); 879 } 880 ZFILE_Close(zfd); 881 freeZip(zip); 882 return NULL; 883 } 884 885 zip->zfd = zfd; 886 if (readCEN(zip, -1) < 0) { 887 /* An error occurred while trying to read the zip file */ 888 if (pmsg != 0) { 889 /* Set the zip error message */ 890 if (zip->msg != NULL) 891 *pmsg = strdup(zip->msg); 892 } 893 freeZip(zip); 894 return NULL; 895 } 896 MLOCK(zfiles_lock); 897 zip->next = zfiles; 898 zfiles = zip; 899 MUNLOCK(zfiles_lock); 900 901 return zip; 902 } 903 904 /* 905 * Opens a zip file for reading. Returns the jzfile object or NULL 906 * if an error occurred. If a zip error occurred then *msg will be 907 * set to the error message text if msg != 0. Otherwise, *msg will be 908 * set to NULL. Caller doesn't need to free the error message. 909 */ 910 JNIEXPORT jzfile * 911 ZIP_Open(const char *name, char **pmsg) 912 { 913 jzfile *file = ZIP_Open_Generic(name, pmsg, O_RDONLY, 0); 914 if (file == NULL && pmsg != NULL && *pmsg != NULL) { 915 free(*pmsg); 916 *pmsg = "Zip file open error"; 917 } 918 return file; 919 } 920 921 /* 922 * Closes the specified zip file object. 923 */ 924 JNIEXPORT void 925 ZIP_Close(jzfile *zip) 926 { 927 MLOCK(zfiles_lock); 928 if (--zip->refs > 0) { 929 /* Still more references so just return */ 930 MUNLOCK(zfiles_lock); 931 return; 932 } 933 /* No other references so close the file and remove from list */ 934 if (zfiles == zip) { 935 zfiles = zfiles->next; 936 } else { 937 jzfile *zp; 938 for (zp = zfiles; zp->next != 0; zp = zp->next) { 939 if (zp->next == zip) { 940 zp->next = zip->next; 941 break; 942 } 943 } 944 } 945 MUNLOCK(zfiles_lock); 946 freeZip(zip); 947 return; 948 } 949 950 /* Empirically, most CEN headers are smaller than this. */ 951 #define AMPLE_CEN_HEADER_SIZE 160 952 953 /* A good buffer size when we want to read CEN headers sequentially. */ 954 #define CENCACHE_PAGESIZE 8192 955 956 static char * 957 readCENHeader(jzfile *zip, jlong cenpos, jint bufsize) 958 { 959 jint censize; 960 ZFILE zfd = zip->zfd; 961 char *cen; 962 if (bufsize > zip->len - cenpos) 963 bufsize = (jint)(zip->len - cenpos); 964 if ((cen = malloc(bufsize)) == NULL) goto Catch; 965 if (readFullyAt(zfd, cen, bufsize, cenpos) == -1) goto Catch; 966 censize = CENSIZE(cen); 967 if (censize <= bufsize) return cen; 968 if ((cen = realloc(cen, censize)) == NULL) goto Catch; 969 if (readFully(zfd, cen+bufsize, censize-bufsize) == -1) goto Catch; 970 return cen; 971 972 Catch: 973 free(cen); 974 return NULL; 975 } 976 977 static char * 978 sequentialAccessReadCENHeader(jzfile *zip, jlong cenpos) 979 { 980 cencache *cache = &zip->cencache; 981 char *cen; 982 if (cache->data != NULL 983 && (cenpos >= cache->pos) 984 && (cenpos + CENHDR <= cache->pos + CENCACHE_PAGESIZE)) 985 { 986 cen = cache->data + cenpos - cache->pos; 987 if (cenpos + CENSIZE(cen) <= cache->pos + CENCACHE_PAGESIZE) 988 /* A cache hit */ 989 return cen; 990 } 991 992 if ((cen = readCENHeader(zip, cenpos, CENCACHE_PAGESIZE)) == NULL) 993 return NULL; 994 free(cache->data); 995 cache->data = cen; 996 cache->pos = cenpos; 997 return cen; 998 } 999 1000 typedef enum { ACCESS_RANDOM, ACCESS_SEQUENTIAL } AccessHint; 1001 1002 /* 1003 * Return a new initialized jzentry corresponding to a given hash cell. 1004 * In case of error, returns NULL. 1005 * We already sanity-checked all the CEN headers for ZIP format errors 1006 * in readCEN(), so we don't check them again here. 1007 * The ZIP lock should be held here. 1008 */ 1009 static jzentry * 1010 newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint) 1011 { 1012 jlong locoff; 1013 jint nlen, elen, clen; 1014 jzentry *ze; 1015 char *cen; 1016 1017 if ((ze = (jzentry *) malloc(sizeof(jzentry))) == NULL) return NULL; 1018 ze->name = NULL; 1019 ze->extra = NULL; 1020 ze->comment = NULL; 1021 1022 #ifdef USE_MMAP 1023 if (zip->usemmap) { 1024 cen = (char*) zip->maddr + zc->cenpos - zip->offset; 1025 } else 1026 #endif 1027 { 1028 if (accessHint == ACCESS_RANDOM) 1029 cen = readCENHeader(zip, zc->cenpos, AMPLE_CEN_HEADER_SIZE); 1030 else 1031 cen = sequentialAccessReadCENHeader(zip, zc->cenpos); 1032 if (cen == NULL) goto Catch; 1033 } 1034 1035 nlen = CENNAM(cen); 1036 elen = CENEXT(cen); 1037 clen = CENCOM(cen); 1038 ze->time = CENTIM(cen); 1039 ze->size = CENLEN(cen); 1040 ze->csize = (CENHOW(cen) == STORED) ? 0 : CENSIZ(cen); 1041 ze->crc = CENCRC(cen); 1042 locoff = CENOFF(cen); 1043 ze->pos = -(zip->locpos + locoff); 1044 ze->flag = CENFLG(cen); 1045 1046 if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch; 1047 memcpy(ze->name, cen + CENHDR, nlen); 1048 ze->name[nlen] = '\0'; 1049 ze->nlen = nlen; 1050 if (elen > 0) { 1051 char *extra = cen + CENHDR + nlen; 1052 1053 /* This entry has "extra" data */ 1054 if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch; 1055 ze->extra[0] = (unsigned char) elen; 1056 ze->extra[1] = (unsigned char) (elen >> 8); 1057 memcpy(ze->extra+2, extra, elen); 1058 if (ze->csize == ZIP64_MAGICVAL || ze->size == ZIP64_MAGICVAL || 1059 locoff == ZIP64_MAGICVAL) { 1060 jint off = 0; 1061 while ((off + 4) < elen) { // spec: HeaderID+DataSize+Data 1062 jint sz = SH(extra, off + 2); 1063 if (SH(extra, off) == ZIP64_EXTID) { 1064 off += 4; 1065 if (ze->size == ZIP64_MAGICVAL) { 1066 // if invalid zip64 extra fields, just skip 1067 if (sz < 8 || (off + 8) > elen) 1068 break; 1069 ze->size = LL(extra, off); 1070 sz -= 8; 1071 off += 8; 1072 } 1073 if (ze->csize == ZIP64_MAGICVAL) { 1074 if (sz < 8 || (off + 8) > elen) 1075 break; 1076 ze->csize = LL(extra, off); 1077 sz -= 8; 1078 off += 8; 1079 } 1080 if (locoff == ZIP64_MAGICVAL) { 1081 if (sz < 8 || (off + 8) > elen) 1082 break; 1083 ze->pos = -(zip->locpos + LL(extra, off)); 1084 sz -= 8; 1085 off += 8; 1086 } 1087 break; 1088 } 1089 off += (sz + 4); 1090 } 1091 } 1092 } 1093 1094 if (clen > 0) { 1095 /* This entry has a comment */ 1096 if ((ze->comment = malloc(clen + 1)) == NULL) goto Catch; 1097 memcpy(ze->comment, cen + CENHDR + nlen + elen, clen); 1098 ze->comment[clen] = '\0'; 1099 } 1100 goto Finally; 1101 1102 Catch: 1103 free(ze->name); 1104 free(ze->extra); 1105 free(ze->comment); 1106 free(ze); 1107 ze = NULL; 1108 1109 Finally: 1110 #ifdef USE_MMAP 1111 if (!zip->usemmap) 1112 #endif 1113 if (cen != NULL && accessHint == ACCESS_RANDOM) free(cen); 1114 return ze; 1115 } 1116 1117 /* 1118 * Free the given jzentry. 1119 * In fact we maintain a one-entry cache of the most recently used 1120 * jzentry for each zip. This optimizes a common access pattern. 1121 */ 1122 1123 void 1124 ZIP_FreeEntry(jzfile *jz, jzentry *ze) 1125 { 1126 jzentry *last; 1127 ZIP_Lock(jz); 1128 last = jz->cache; 1129 jz->cache = ze; 1130 ZIP_Unlock(jz); 1131 if (last != NULL) { 1132 /* Free the previously cached jzentry */ 1133 free(last->name); 1134 if (last->extra) free(last->extra); 1135 if (last->comment) free(last->comment); 1136 free(last); 1137 } 1138 } 1139 1140 /* 1141 * Returns the zip entry corresponding to the specified name, or 1142 * NULL if not found. 1143 */ 1144 jzentry * 1145 ZIP_GetEntry(jzfile *zip, char *name, jint ulen) 1146 { 1147 if (ulen == 0) { 1148 return ZIP_GetEntry2(zip, name, (jint)strlen(name), JNI_FALSE); 1149 } 1150 return ZIP_GetEntry2(zip, name, ulen, JNI_TRUE); 1151 } 1152 1153 jboolean equals(char* name1, int len1, char* name2, int len2) { 1154 if (len1 != len2) { 1155 return JNI_FALSE; 1156 } 1157 while (len1-- > 0) { 1158 if (*name1++ != *name2++) { 1159 return JNI_FALSE; 1160 } 1161 } 1162 return JNI_TRUE; 1163 } 1164 1165 /* 1166 * Returns the zip entry corresponding to the specified name, or 1167 * NULL if not found. 1168 * This method supports embedded null character in "name", use ulen 1169 * for the length of "name". 1170 */ 1171 jzentry * 1172 ZIP_GetEntry2(jzfile *zip, char *name, jint ulen, jboolean addSlash) 1173 { 1174 unsigned int hsh = hashN(name, ulen); 1175 jint idx; 1176 jzentry *ze = 0; 1177 1178 ZIP_Lock(zip); 1179 if (zip->total == 0) { 1180 goto Finally; 1181 } 1182 1183 idx = zip->table[hsh % zip->tablelen]; 1184 1185 /* 1186 * This while loop is an optimization where a double lookup 1187 * for name and name+/ is being performed. The name char 1188 * array has enough room at the end to try again with a 1189 * slash appended if the first table lookup does not succeed. 1190 */ 1191 while(1) { 1192 1193 /* Check the cached entry first */ 1194 ze = zip->cache; 1195 if (ze && equals(ze->name, ze->nlen, name, ulen)) { 1196 /* Cache hit! Remove and return the cached entry. */ 1197 zip->cache = 0; 1198 ZIP_Unlock(zip); 1199 return ze; 1200 } 1201 ze = 0; 1202 1203 /* 1204 * Search down the target hash chain for a cell whose 1205 * 32 bit hash matches the hashed name. 1206 */ 1207 while (idx != ZIP_ENDCHAIN) { 1208 jzcell *zc = &zip->entries[idx]; 1209 1210 if (zc->hash == hsh) { 1211 /* 1212 * OK, we've found a ZIP entry whose 32 bit hashcode 1213 * matches the name we're looking for. Try to read 1214 * its entry information from the CEN. If the CEN 1215 * name matches the name we're looking for, we're 1216 * done. 1217 * If the names don't match (which should be very rare) 1218 * we keep searching. 1219 */ 1220 ze = newEntry(zip, zc, ACCESS_RANDOM); 1221 if (ze && equals(ze->name, ze->nlen, name, ulen)) { 1222 break; 1223 } 1224 if (ze != 0) { 1225 /* We need to release the lock across the free call */ 1226 ZIP_Unlock(zip); 1227 ZIP_FreeEntry(zip, ze); 1228 ZIP_Lock(zip); 1229 } 1230 ze = 0; 1231 } 1232 idx = zc->next; 1233 } 1234 1235 /* Entry found, return it */ 1236 if (ze != 0) { 1237 break; 1238 } 1239 1240 /* If no need to try appending slash, we are done */ 1241 if (!addSlash) { 1242 break; 1243 } 1244 1245 /* Slash is already there? */ 1246 if (ulen > 0 && name[ulen - 1] == '/') { 1247 break; 1248 } 1249 1250 /* Add slash and try once more */ 1251 name[ulen++] = '/'; 1252 name[ulen] = '\0'; 1253 hsh = hash_append(hsh, '/'); 1254 idx = zip->table[hsh % zip->tablelen]; 1255 addSlash = JNI_FALSE; 1256 } 1257 1258 Finally: 1259 ZIP_Unlock(zip); 1260 return ze; 1261 } 1262 1263 /* 1264 * Returns the n'th (starting at zero) zip file entry, or NULL if the 1265 * specified index was out of range. 1266 */ 1267 JNIEXPORT jzentry * 1268 ZIP_GetNextEntry(jzfile *zip, jint n) 1269 { 1270 jzentry *result; 1271 if (n < 0 || n >= zip->total) { 1272 return 0; 1273 } 1274 ZIP_Lock(zip); 1275 result = newEntry(zip, &zip->entries[n], ACCESS_SEQUENTIAL); 1276 ZIP_Unlock(zip); 1277 return result; 1278 } 1279 1280 /* 1281 * Locks the specified zip file for reading. 1282 */ 1283 void 1284 ZIP_Lock(jzfile *zip) 1285 { 1286 MLOCK(zip->lock); 1287 } 1288 1289 /* 1290 * Unlocks the specified zip file. 1291 */ 1292 void 1293 ZIP_Unlock(jzfile *zip) 1294 { 1295 MUNLOCK(zip->lock); 1296 } 1297 1298 /* 1299 * Returns the offset of the entry data within the zip file. 1300 * Returns -1 if an error occurred, in which case zip->msg will 1301 * contain the error text. 1302 */ 1303 jlong 1304 ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry) 1305 { 1306 /* The Zip file spec explicitly allows the LOC extra data size to 1307 * be different from the CEN extra data size, although the JDK 1308 * never creates such zip files. Since we cannot trust the CEN 1309 * extra data size, we need to read the LOC to determine the entry 1310 * data offset. We do this lazily to avoid touching the virtual 1311 * memory page containing the LOC when initializing jzentry 1312 * objects. (This speeds up javac by a factor of 10 when the JDK 1313 * is installed on a very slow filesystem.) 1314 */ 1315 if (entry->pos <= 0) { 1316 unsigned char loc[LOCHDR]; 1317 if (readFullyAt(zip->zfd, loc, LOCHDR, -(entry->pos)) == -1) { 1318 zip->msg = "error reading zip file"; 1319 return -1; 1320 } 1321 if (!LOCSIG_AT(loc)) { 1322 zip->msg = "invalid LOC header (bad signature)"; 1323 return -1; 1324 } 1325 entry->pos = (- entry->pos) + LOCHDR + LOCNAM(loc) + LOCEXT(loc); 1326 } 1327 return entry->pos; 1328 } 1329 1330 /* 1331 * Reads bytes from the specified zip entry. Assumes that the zip 1332 * file had been previously locked with ZIP_Lock(). Returns the 1333 * number of bytes read, or -1 if an error occurred. If zip->msg != 0 1334 * then a zip error occurred and zip->msg contains the error text. 1335 * 1336 * The current implementation does not support reading an entry that 1337 * has the size bigger than 2**32 bytes in ONE invocation. 1338 */ 1339 jint 1340 ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len) 1341 { 1342 jlong entry_size; 1343 jlong start; 1344 1345 if (zip == 0) { 1346 return -1; 1347 } 1348 1349 /* Clear previous zip error */ 1350 zip->msg = NULL; 1351 1352 if (entry == 0) { 1353 zip->msg = "ZIP_Read: jzentry is NULL"; 1354 return -1; 1355 } 1356 1357 entry_size = (entry->csize != 0) ? entry->csize : entry->size; 1358 1359 /* Check specified position */ 1360 if (pos < 0 || pos > entry_size - 1) { 1361 zip->msg = "ZIP_Read: specified offset out of range"; 1362 return -1; 1363 } 1364 1365 /* Check specified length */ 1366 if (len <= 0) 1367 return 0; 1368 if (len > entry_size - pos) 1369 len = (jint)(entry_size - pos); 1370 1371 /* Get file offset to start reading data */ 1372 start = ZIP_GetEntryDataOffset(zip, entry); 1373 if (start < 0) 1374 return -1; 1375 start += pos; 1376 1377 if (start + len > zip->len) { 1378 zip->msg = "ZIP_Read: corrupt zip file: invalid entry size"; 1379 return -1; 1380 } 1381 1382 if (readFullyAt(zip->zfd, buf, len, start) == -1) { 1383 zip->msg = "ZIP_Read: error reading zip file"; 1384 return -1; 1385 } 1386 return len; 1387 } 1388 1389 1390 /* The maximum size of a stack-allocated buffer. 1391 */ 1392 #define BUF_SIZE 4096 1393 1394 /* 1395 * This function is used by the runtime system to load compressed entries 1396 * from ZIP/JAR files specified in the class path. It is defined here 1397 * so that it can be dynamically loaded by the runtime if the zip library 1398 * is found. 1399 * 1400 * The current implementation does not support reading an entry that 1401 * has the size bigger than 2**32 bytes in ONE invocation. 1402 */ 1403 jboolean 1404 InflateFully(jzfile *zip, jzentry *entry, void *buf, char **msg) 1405 { 1406 z_stream strm; 1407 char tmp[BUF_SIZE]; 1408 jlong pos = 0; 1409 jlong count = entry->csize; 1410 1411 *msg = 0; /* Reset error message */ 1412 1413 if (count == 0) { 1414 *msg = "inflateFully: entry not compressed"; 1415 return JNI_FALSE; 1416 } 1417 1418 memset(&strm, 0, sizeof(z_stream)); 1419 if (inflateInit2(&strm, -MAX_WBITS) != Z_OK) { 1420 *msg = strm.msg; 1421 return JNI_FALSE; 1422 } 1423 1424 strm.next_out = buf; 1425 strm.avail_out = (uInt)entry->size; 1426 1427 while (count > 0) { 1428 jint n = count > (jlong)sizeof(tmp) ? (jint)sizeof(tmp) : (jint)count; 1429 ZIP_Lock(zip); 1430 n = ZIP_Read(zip, entry, pos, tmp, n); 1431 ZIP_Unlock(zip); 1432 if (n <= 0) { 1433 if (n == 0) { 1434 *msg = "inflateFully: Unexpected end of file"; 1435 } 1436 inflateEnd(&strm); 1437 return JNI_FALSE; 1438 } 1439 pos += n; 1440 count -= n; 1441 strm.next_in = (Bytef *)tmp; 1442 strm.avail_in = n; 1443 do { 1444 switch (inflate(&strm, Z_PARTIAL_FLUSH)) { 1445 case Z_OK: 1446 break; 1447 case Z_STREAM_END: 1448 if (count != 0 || strm.total_out != (uInt)entry->size) { 1449 *msg = "inflateFully: Unexpected end of stream"; 1450 inflateEnd(&strm); 1451 return JNI_FALSE; 1452 } 1453 break; 1454 default: 1455 break; 1456 } 1457 } while (strm.avail_in > 0); 1458 } 1459 1460 inflateEnd(&strm); 1461 return JNI_TRUE; 1462 } 1463 1464 /* 1465 * The current implementation does not support reading an entry that 1466 * has the size bigger than 2**32 bytes in ONE invocation. 1467 */ 1468 JNIEXPORT jzentry * 1469 ZIP_FindEntry(jzfile *zip, char *name, jint *sizeP, jint *nameLenP) 1470 { 1471 jzentry *entry = ZIP_GetEntry(zip, name, 0); 1472 if (entry) { 1473 *sizeP = (jint)entry->size; 1474 *nameLenP = (jint)strlen(entry->name); 1475 } 1476 return entry; 1477 } 1478 1479 /* 1480 * Reads a zip file entry into the specified byte array 1481 * When the method completes, it releases the jzentry. 1482 * Note: this is called from the separately delivered VM (hotspot/classic) 1483 * so we have to be careful to maintain the expected behaviour. 1484 */ 1485 JNIEXPORT jboolean 1486 ZIP_ReadEntry(jzfile *zip, jzentry *entry, unsigned char *buf, char *entryname) 1487 { 1488 char *msg; 1489 char tmpbuf[1024]; 1490 1491 if (entry == 0) { 1492 jio_fprintf(stderr, "jzentry was invalid"); 1493 return JNI_FALSE; 1494 } 1495 1496 strcpy(entryname, entry->name); 1497 if (entry->csize == 0) { 1498 /* Entry is stored */ 1499 jlong pos = 0; 1500 jlong size = entry->size; 1501 while (pos < size) { 1502 jint n; 1503 jlong limit = ((((jlong) 1) << 31) - 1); 1504 jint count = (size - pos < limit) ? 1505 /* These casts suppress a VC++ Internal Compiler Error */ 1506 (jint) (size - pos) : 1507 (jint) limit; 1508 ZIP_Lock(zip); 1509 n = ZIP_Read(zip, entry, pos, buf, count); 1510 msg = zip->msg; 1511 ZIP_Unlock(zip); 1512 if (n == -1) { 1513 if (msg == 0) { 1514 getErrorString(errno, tmpbuf, sizeof(tmpbuf)); 1515 msg = tmpbuf; 1516 } 1517 jio_fprintf(stderr, "%s: %s\n", zip->name, msg); 1518 return JNI_FALSE; 1519 } 1520 buf += n; 1521 pos += n; 1522 } 1523 } else { 1524 /* Entry is compressed */ 1525 int ok = InflateFully(zip, entry, buf, &msg); 1526 if (!ok) { 1527 if ((msg == NULL) || (*msg == 0)) { 1528 msg = zip->msg; 1529 } 1530 if (msg == 0) { 1531 getErrorString(errno, tmpbuf, sizeof(tmpbuf)); 1532 msg = tmpbuf; 1533 } 1534 jio_fprintf(stderr, "%s: %s\n", zip->name, msg); 1535 return JNI_FALSE; 1536 } 1537 } 1538 1539 ZIP_FreeEntry(zip, entry); 1540 1541 return JNI_TRUE; 1542 } 1543 1544 JNIEXPORT jboolean 1545 ZIP_InflateFully(void *inBuf, jlong inLen, void *outBuf, jlong outLen, char **pmsg) 1546 { 1547 z_stream strm; 1548 int i = 0; 1549 memset(&strm, 0, sizeof(z_stream)); 1550 1551 *pmsg = 0; /* Reset error message */ 1552 1553 if (inflateInit2(&strm, MAX_WBITS) != Z_OK) { 1554 *pmsg = strm.msg; 1555 return JNI_FALSE; 1556 } 1557 1558 strm.next_out = (Bytef *) outBuf; 1559 strm.avail_out = (uInt)outLen; 1560 strm.next_in = (Bytef *) inBuf; 1561 strm.avail_in = (uInt)inLen; 1562 1563 do { 1564 switch (inflate(&strm, Z_PARTIAL_FLUSH)) { 1565 case Z_OK: 1566 break; 1567 case Z_STREAM_END: 1568 if (strm.total_out != (uInt)outLen) { 1569 *pmsg = "INFLATER_inflateFully: Unexpected end of stream"; 1570 inflateEnd(&strm); 1571 return JNI_FALSE; 1572 } 1573 break; 1574 case Z_DATA_ERROR: 1575 *pmsg = "INFLATER_inflateFully: Compressed data corrupted"; 1576 inflateEnd(&strm); 1577 return JNI_FALSE; 1578 case Z_MEM_ERROR: 1579 *pmsg = "INFLATER_inflateFully: out of memory"; 1580 inflateEnd(&strm); 1581 return JNI_FALSE; 1582 default: 1583 *pmsg = "INFLATER_inflateFully: internal error"; 1584 inflateEnd(&strm); 1585 return JNI_FALSE; 1586 } 1587 } while (strm.avail_in > 0); 1588 1589 inflateEnd(&strm); 1590 return JNI_TRUE; 1591 }