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