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