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