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