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 <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 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 */ 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 if (entries == NULL || table == NULL) goto Catch; 663 for (j = 0; j < tablelen; j++) 664 table[j] = ZIP_ENDCHAIN; 665 666 /* Iterate through the entries in the central directory */ 667 for (i = 0, cp = cenbuf; cp <= cenend - CENHDR; i++, cp += CENSIZE(cp)) { 668 /* Following are unsigned 16-bit */ 669 jint method, nlen; 670 unsigned int hsh; 671 672 if (i >= total) { 673 /* This will only happen if the zip file has an incorrect 674 * ENDTOT field, which usually means it contains more than 675 * 65535 entries. */ 676 cenpos = readCEN(zip, countCENHeaders(cenbuf, cenend)); 677 goto Finally; 678 } 679 680 method = CENHOW(cp); 681 nlen = CENNAM(cp); 682 683 if (GETSIG(cp) != CENSIG) 684 ZIP_FORMAT_ERROR("invalid CEN header (bad signature)"); 685 if (CENFLG(cp) & 1) 686 ZIP_FORMAT_ERROR("invalid CEN header (encrypted entry)"); 687 if (method != STORED && method != DEFLATED) 688 ZIP_FORMAT_ERROR("invalid CEN header (bad compression method)"); 689 if (cp + CENHDR + nlen > cenend) 690 ZIP_FORMAT_ERROR("invalid CEN header (bad header size)"); 691 692 /* if the entry is metadata add it to our metadata names */ 693 if (isMetaName((char *)cp+CENHDR, nlen)) 694 if (addMetaName(zip, (char *)cp+CENHDR, nlen) != 0) 695 goto Catch; 696 697 /* Record the CEN offset and the name hash in our hash cell. */ 698 entries[i].cenpos = cenpos + (cp - cenbuf); 699 entries[i].hash = hashN((char *)cp+CENHDR, nlen); 700 701 /* Add the entry to the hash table */ 702 hsh = entries[i].hash % tablelen; 703 entries[i].next = table[hsh]; 704 table[hsh] = i; 705 } 706 if (cp != cenend) 707 ZIP_FORMAT_ERROR("invalid CEN header (bad header size)"); 708 709 zip->total = i; 710 goto Finally; 711 712 Catch: 713 freeCEN(zip); 714 cenpos = -1; 715 716 Finally: 717 #ifdef USE_MMAP 718 if (!zip->usemmap) 719 #endif 720 free(cenbuf); 721 722 return cenpos; 723 } 724 725 /* 726 * Opens a zip file with the specified mode. Returns the jzfile object 727 * or NULL if an error occurred. If a zip error occurred then *pmsg will 728 * be set to the error message text if pmsg != 0. Otherwise, *pmsg will be 729 * set to NULL. Caller is responsible to free the error message. 730 */ 731 jzfile * 732 ZIP_Open_Generic(const char *name, char **pmsg, int mode, jlong lastModified) 733 { 734 jzfile *zip = NULL; 735 736 /* Clear zip error message */ 737 if (pmsg != 0) { 738 *pmsg = NULL; 739 } 740 741 zip = ZIP_Get_From_Cache(name, pmsg, lastModified); 742 743 if (zip == NULL && *pmsg == NULL) { 744 ZFILE zfd = ZFILE_Open(name, mode); 745 zip = ZIP_Put_In_Cache(name, zfd, pmsg, lastModified); 746 } 747 return zip; 748 } 749 750 /* 751 * Returns the jzfile corresponding to the given file name from the cache of 752 * zip files, or NULL if the file is not in the cache. If the name is longer 753 * than PATH_MAX or a zip error occurred then *pmsg will be set to the error 754 * message text if pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller 755 * is responsible to free the error message. 756 */ 757 jzfile * 758 ZIP_Get_From_Cache(const char *name, char **pmsg, jlong lastModified) 759 { 760 char buf[PATH_MAX]; 761 jzfile *zip; 762 763 if (InitializeZip()) { 764 return NULL; 765 } 766 767 /* Clear zip error message */ 768 if (pmsg != 0) { 769 *pmsg = NULL; 770 } 771 772 if (strlen(name) >= PATH_MAX) { 773 if (pmsg) { 774 *pmsg = strdup("zip file name too long"); 775 } 776 return NULL; 777 } 778 strcpy(buf, name); 779 JVM_NativePath(buf); 780 name = buf; 781 782 MLOCK(zfiles_lock); 783 for (zip = zfiles; zip != NULL; zip = zip->next) { 784 if (strcmp(name, zip->name) == 0 785 && (zip->lastModified == lastModified || zip->lastModified == 0) 786 && zip->refs < MAXREFS) { 787 zip->refs++; 788 break; 789 } 790 } 791 MUNLOCK(zfiles_lock); 792 return zip; 793 } 794 795 /* 796 * Reads data from the given file descriptor to create a jzfile, puts the 797 * jzfile in a cache, and returns that jzfile. Returns NULL in case of error. 798 * If a zip error occurs, then *pmsg will be set to the error message text if 799 * pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller is responsible to 800 * free the error message. 801 */ 802 803 jzfile * 804 ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified) 805 { 806 return ZIP_Put_In_Cache0(name, zfd, pmsg, lastModified, JNI_TRUE); 807 } 808 809 jzfile * 810 ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified, 811 jboolean usemmap) 812 { 813 char errbuf[256]; 814 jlong len; 815 jzfile *zip; 816 817 if ((zip = allocZip(name)) == NULL) { 818 return NULL; 819 } 820 821 #ifdef USE_MMAP 822 zip->usemmap = usemmap; 823 #endif 824 zip->refs = 1; 825 zip->lastModified = lastModified; 826 827 if (zfd == -1) { 828 if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0) 829 *pmsg = strdup(errbuf); 830 freeZip(zip); 831 return NULL; 832 } 833 834 len = zip->len = IO_Lseek(zfd, 0, SEEK_END); 835 if (len <= 0) { 836 if (len == 0) { /* zip file is empty */ 837 if (pmsg) { 838 *pmsg = strdup("zip file is empty"); 839 } 840 } else { /* error */ 841 if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0) 842 *pmsg = strdup(errbuf); 843 } 844 ZFILE_Close(zfd); 845 freeZip(zip); 846 return NULL; 847 } 848 849 zip->zfd = zfd; 850 if (readCEN(zip, -1) < 0) { 851 /* An error occurred while trying to read the zip file */ 852 if (pmsg != 0) { 853 /* Set the zip error message */ 854 if (zip->msg != NULL) 855 *pmsg = strdup(zip->msg); 856 } 857 freeZip(zip); 858 return NULL; 859 } 860 MLOCK(zfiles_lock); 861 zip->next = zfiles; 862 zfiles = zip; 863 MUNLOCK(zfiles_lock); 864 865 return zip; 866 } 867 868 /* 869 * Opens a zip file for reading. Returns the jzfile object or NULL 870 * if an error occurred. If a zip error occurred then *msg will be 871 * set to the error message text if msg != 0. Otherwise, *msg will be 872 * set to NULL. Caller doesn't need to free the error message. 873 */ 874 jzfile * JNICALL 875 ZIP_Open(const char *name, char **pmsg) 876 { 877 jzfile *file = ZIP_Open_Generic(name, pmsg, O_RDONLY, 0); 878 if (file == NULL && pmsg != NULL && *pmsg != NULL) { 879 free(*pmsg); 880 *pmsg = "Zip file open error"; 881 } 882 return file; 883 } 884 885 /* 886 * Closes the specified zip file object. 887 */ 888 void JNICALL 889 ZIP_Close(jzfile *zip) 890 { 891 MLOCK(zfiles_lock); 892 if (--zip->refs > 0) { 893 /* Still more references so just return */ 894 MUNLOCK(zfiles_lock); 895 return; 896 } 897 /* No other references so close the file and remove from list */ 898 if (zfiles == zip) { 899 zfiles = zfiles->next; 900 } else { 901 jzfile *zp; 902 for (zp = zfiles; zp->next != 0; zp = zp->next) { 903 if (zp->next == zip) { 904 zp->next = zip->next; 905 break; 906 } 907 } 908 } 909 MUNLOCK(zfiles_lock); 910 freeZip(zip); 911 return; 912 } 913 914 /* Empirically, most CEN headers are smaller than this. */ 915 #define AMPLE_CEN_HEADER_SIZE 160 916 917 /* A good buffer size when we want to read CEN headers sequentially. */ 918 #define CENCACHE_PAGESIZE 8192 919 920 static char * 921 readCENHeader(jzfile *zip, jlong cenpos, jint bufsize) 922 { 923 jint censize; 924 ZFILE zfd = zip->zfd; 925 char *cen; 926 if (bufsize > zip->len - cenpos) 927 bufsize = (jint)(zip->len - cenpos); 928 if ((cen = malloc(bufsize)) == NULL) goto Catch; 929 if (readFullyAt(zfd, cen, bufsize, cenpos) == -1) goto Catch; 930 censize = CENSIZE(cen); 931 if (censize <= bufsize) return cen; 932 if ((cen = realloc(cen, censize)) == NULL) goto Catch; 933 if (readFully(zfd, cen+bufsize, censize-bufsize) == -1) goto Catch; 934 return cen; 935 936 Catch: 937 free(cen); 938 return NULL; 939 } 940 941 static char * 942 sequentialAccessReadCENHeader(jzfile *zip, jlong cenpos) 943 { 944 cencache *cache = &zip->cencache; 945 char *cen; 946 if (cache->data != NULL 947 && (cenpos >= cache->pos) 948 && (cenpos + CENHDR <= cache->pos + CENCACHE_PAGESIZE)) 949 { 950 cen = cache->data + cenpos - cache->pos; 951 if (cenpos + CENSIZE(cen) <= cache->pos + CENCACHE_PAGESIZE) 952 /* A cache hit */ 953 return cen; 954 } 955 956 if ((cen = readCENHeader(zip, cenpos, CENCACHE_PAGESIZE)) == NULL) 957 return NULL; 958 free(cache->data); 959 cache->data = cen; 960 cache->pos = cenpos; 961 return cen; 962 } 963 964 typedef enum { ACCESS_RANDOM, ACCESS_SEQUENTIAL } AccessHint; 965 966 /* 967 * Return a new initialized jzentry corresponding to a given hash cell. 968 * In case of error, returns NULL. 969 * We already sanity-checked all the CEN headers for ZIP format errors 970 * in readCEN(), so we don't check them again here. 971 * The ZIP lock should be held here. 972 */ 973 static jzentry * 974 newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint) 975 { 976 jlong locoff; 977 jint nlen, elen, clen; 978 jzentry *ze; 979 char *cen; 980 981 if ((ze = (jzentry *) malloc(sizeof(jzentry))) == NULL) return NULL; 982 ze->name = NULL; 983 ze->extra = NULL; 984 ze->comment = NULL; 985 986 #ifdef USE_MMAP 987 if (zip->usemmap) { 988 cen = (char*) zip->maddr + zc->cenpos - zip->offset; 989 } else 990 #endif 991 { 992 if (accessHint == ACCESS_RANDOM) 993 cen = readCENHeader(zip, zc->cenpos, AMPLE_CEN_HEADER_SIZE); 994 else 995 cen = sequentialAccessReadCENHeader(zip, zc->cenpos); 996 if (cen == NULL) goto Catch; 997 } 998 999 nlen = CENNAM(cen); 1000 elen = CENEXT(cen); 1001 clen = CENCOM(cen); 1002 ze->time = CENTIM(cen); 1003 ze->size = CENLEN(cen); 1004 ze->csize = (CENHOW(cen) == STORED) ? 0 : CENSIZ(cen); 1005 ze->crc = CENCRC(cen); 1006 locoff = CENOFF(cen); 1007 ze->pos = -(zip->locpos + locoff); 1008 ze->flag = CENFLG(cen); 1009 1010 if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch; 1011 memcpy(ze->name, cen + CENHDR, nlen); 1012 ze->name[nlen] = '\0'; 1013 if (elen > 0) { 1014 char *extra = cen + CENHDR + nlen; 1015 1016 /* This entry has "extra" data */ 1017 if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch; 1018 ze->extra[0] = (unsigned char) elen; 1019 ze->extra[1] = (unsigned char) (elen >> 8); 1020 memcpy(ze->extra+2, extra, elen); 1021 if (ze->csize == ZIP64_MAGICVAL || ze->size == ZIP64_MAGICVAL || 1022 locoff == ZIP64_MAGICVAL) { 1023 jint off = 0; 1024 while ((off + 4) < elen) { // spec: HeaderID+DataSize+Data 1025 jint sz = SH(extra, off + 2); 1026 if (SH(extra, off) == ZIP64_EXTID) { 1027 off += 4; 1028 if (ze->size == ZIP64_MAGICVAL) { 1029 // if invalid zip64 extra fields, just skip 1030 if (sz < 8 || (off + 8) > elen) 1031 break; 1032 ze->size = LL(extra, off); 1033 sz -= 8; 1034 off += 8; 1035 } 1036 if (ze->csize == ZIP64_MAGICVAL) { 1037 if (sz < 8 || (off + 8) > elen) 1038 break; 1039 ze->csize = LL(extra, off); 1040 sz -= 8; 1041 off += 8; 1042 } 1043 if (locoff == ZIP64_MAGICVAL) { 1044 if (sz < 8 || (off + 8) > elen) 1045 break; 1046 ze->pos = -(zip->locpos + LL(extra, off)); 1047 sz -= 8; 1048 off += 8; 1049 } 1050 break; 1051 } 1052 off += (sz + 4); 1053 } 1054 } 1055 } 1056 1057 if (clen > 0) { 1058 /* This entry has a comment */ 1059 if ((ze->comment = malloc(clen + 1)) == NULL) goto Catch; 1060 memcpy(ze->comment, cen + CENHDR + nlen + elen, clen); 1061 ze->comment[clen] = '\0'; 1062 } 1063 goto Finally; 1064 1065 Catch: 1066 free(ze->name); 1067 free(ze->extra); 1068 free(ze->comment); 1069 free(ze); 1070 ze = NULL; 1071 1072 Finally: 1073 #ifdef USE_MMAP 1074 if (!zip->usemmap) 1075 #endif 1076 if (cen != NULL && accessHint == ACCESS_RANDOM) free(cen); 1077 return ze; 1078 } 1079 1080 /* 1081 * Free the given jzentry. 1082 * In fact we maintain a one-entry cache of the most recently used 1083 * jzentry for each zip. This optimizes a common access pattern. 1084 */ 1085 1086 void 1087 ZIP_FreeEntry(jzfile *jz, jzentry *ze) 1088 { 1089 jzentry *last; 1090 ZIP_Lock(jz); 1091 last = jz->cache; 1092 jz->cache = ze; 1093 ZIP_Unlock(jz); 1094 if (last != NULL) { 1095 /* Free the previously cached jzentry */ 1096 free(last->name); 1097 if (last->extra) free(last->extra); 1098 if (last->comment) free(last->comment); 1099 free(last); 1100 } 1101 } 1102 1103 /* 1104 * Returns the zip entry corresponding to the specified name, or 1105 * NULL if not found. 1106 */ 1107 jzentry * 1108 ZIP_GetEntry(jzfile *zip, char *name, jint ulen) 1109 { 1110 unsigned int hsh = hash(name); 1111 jint idx; 1112 jzentry *ze = 0; 1113 1114 ZIP_Lock(zip); 1115 if (zip->total == 0) { 1116 goto Finally; 1117 } 1118 1119 idx = zip->table[hsh % zip->tablelen]; 1120 1121 /* 1122 * This while loop is an optimization where a double lookup 1123 * for name and name+/ is being performed. The name char 1124 * array has enough room at the end to try again with a 1125 * slash appended if the first table lookup does not succeed. 1126 */ 1127 while(1) { 1128 1129 /* Check the cached entry first */ 1130 ze = zip->cache; 1131 if (ze && strcmp(ze->name,name) == 0) { 1132 /* Cache hit! Remove and return the cached entry. */ 1133 zip->cache = 0; 1134 ZIP_Unlock(zip); 1135 return ze; 1136 } 1137 ze = 0; 1138 1139 /* 1140 * Search down the target hash chain for a cell whose 1141 * 32 bit hash matches the hashed name. 1142 */ 1143 while (idx != ZIP_ENDCHAIN) { 1144 jzcell *zc = &zip->entries[idx]; 1145 1146 if (zc->hash == hsh) { 1147 /* 1148 * OK, we've found a ZIP entry whose 32 bit hashcode 1149 * matches the name we're looking for. Try to read 1150 * its entry information from the CEN. If the CEN 1151 * name matches the name we're looking for, we're 1152 * done. 1153 * If the names don't match (which should be very rare) 1154 * we keep searching. 1155 */ 1156 ze = newEntry(zip, zc, ACCESS_RANDOM); 1157 if (ze && strcmp(ze->name, name)==0) { 1158 break; 1159 } 1160 if (ze != 0) { 1161 /* We need to release the lock across the free call */ 1162 ZIP_Unlock(zip); 1163 ZIP_FreeEntry(zip, ze); 1164 ZIP_Lock(zip); 1165 } 1166 ze = 0; 1167 } 1168 idx = zc->next; 1169 } 1170 1171 /* Entry found, return it */ 1172 if (ze != 0) { 1173 break; 1174 } 1175 1176 /* If no real length was passed in, we are done */ 1177 if (ulen == 0) { 1178 break; 1179 } 1180 1181 /* Slash is already there? */ 1182 if (name[ulen-1] == '/') { 1183 break; 1184 } 1185 1186 /* Add slash and try once more */ 1187 name[ulen] = '/'; 1188 name[ulen+1] = '\0'; 1189 hsh = hash_append(hsh, '/'); 1190 idx = zip->table[hsh % zip->tablelen]; 1191 ulen = 0; 1192 } 1193 1194 Finally: 1195 ZIP_Unlock(zip); 1196 return ze; 1197 } 1198 1199 /* 1200 * Returns the n'th (starting at zero) zip file entry, or NULL if the 1201 * specified index was out of range. 1202 */ 1203 jzentry * JNICALL 1204 ZIP_GetNextEntry(jzfile *zip, jint n) 1205 { 1206 jzentry *result; 1207 if (n < 0 || n >= zip->total) { 1208 return 0; 1209 } 1210 ZIP_Lock(zip); 1211 result = newEntry(zip, &zip->entries[n], ACCESS_SEQUENTIAL); 1212 ZIP_Unlock(zip); 1213 return result; 1214 } 1215 1216 /* 1217 * Locks the specified zip file for reading. 1218 */ 1219 void 1220 ZIP_Lock(jzfile *zip) 1221 { 1222 MLOCK(zip->lock); 1223 } 1224 1225 /* 1226 * Unlocks the specified zip file. 1227 */ 1228 void 1229 ZIP_Unlock(jzfile *zip) 1230 { 1231 MUNLOCK(zip->lock); 1232 } 1233 1234 /* 1235 * Returns the offset of the entry data within the zip file. 1236 * Returns -1 if an error occurred, in which case zip->msg will 1237 * contain the error text. 1238 */ 1239 jlong 1240 ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry) 1241 { 1242 /* The Zip file spec explicitly allows the LOC extra data size to 1243 * be different from the CEN extra data size, although the JDK 1244 * never creates such zip files. Since we cannot trust the CEN 1245 * extra data size, we need to read the LOC to determine the entry 1246 * data offset. We do this lazily to avoid touching the virtual 1247 * memory page containing the LOC when initializing jzentry 1248 * objects. (This speeds up javac by a factor of 10 when the JDK 1249 * is installed on a very slow filesystem.) 1250 */ 1251 if (entry->pos <= 0) { 1252 unsigned char loc[LOCHDR]; 1253 if (readFullyAt(zip->zfd, loc, LOCHDR, -(entry->pos)) == -1) { 1254 zip->msg = "error reading zip file"; 1255 return -1; 1256 } 1257 if (GETSIG(loc) != LOCSIG) { 1258 zip->msg = "invalid LOC header (bad signature)"; 1259 return -1; 1260 } 1261 entry->pos = (- entry->pos) + LOCHDR + LOCNAM(loc) + LOCEXT(loc); 1262 } 1263 return entry->pos; 1264 } 1265 1266 /* 1267 * Reads bytes from the specified zip entry. Assumes that the zip 1268 * file had been previously locked with ZIP_Lock(). Returns the 1269 * number of bytes read, or -1 if an error occurred. If zip->msg != 0 1270 * then a zip error occurred and zip->msg contains the error text. 1271 * 1272 * The current implementation does not support reading an entry that 1273 * has the size bigger than 2**32 bytes in ONE invocation. 1274 */ 1275 jint 1276 ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len) 1277 { 1278 jlong entry_size = (entry->csize != 0) ? entry->csize : entry->size; 1279 jlong start; 1280 1281 /* Clear previous zip error */ 1282 zip->msg = NULL; 1283 1284 /* Check specified position */ 1285 if (pos < 0 || pos > entry_size - 1) { 1286 zip->msg = "ZIP_Read: specified offset out of range"; 1287 return -1; 1288 } 1289 1290 /* Check specified length */ 1291 if (len <= 0) 1292 return 0; 1293 if (len > entry_size - pos) 1294 len = (jint)(entry_size - pos); 1295 1296 /* Get file offset to start reading data */ 1297 start = ZIP_GetEntryDataOffset(zip, entry); 1298 if (start < 0) 1299 return -1; 1300 start += pos; 1301 1302 if (start + len > zip->len) { 1303 zip->msg = "ZIP_Read: corrupt zip file: invalid entry size"; 1304 return -1; 1305 } 1306 1307 if (readFullyAt(zip->zfd, buf, len, start) == -1) { 1308 zip->msg = "ZIP_Read: error reading zip file"; 1309 return -1; 1310 } 1311 return len; 1312 } 1313 1314 1315 /* The maximum size of a stack-allocated buffer. 1316 */ 1317 #define BUF_SIZE 4096 1318 1319 /* 1320 * This function is used by the runtime system to load compressed entries 1321 * from ZIP/JAR files specified in the class path. It is defined here 1322 * so that it can be dynamically loaded by the runtime if the zip library 1323 * is found. 1324 * 1325 * The current implementation does not support reading an entry that 1326 * has the size bigger than 2**32 bytes in ONE invocation. 1327 */ 1328 jboolean 1329 InflateFully(jzfile *zip, jzentry *entry, void *buf, char **msg) 1330 { 1331 z_stream strm; 1332 char tmp[BUF_SIZE]; 1333 jlong pos = 0; 1334 jlong count = entry->csize; 1335 1336 *msg = 0; /* Reset error message */ 1337 1338 if (count == 0) { 1339 *msg = "inflateFully: entry not compressed"; 1340 return JNI_FALSE; 1341 } 1342 1343 memset(&strm, 0, sizeof(z_stream)); 1344 if (inflateInit2(&strm, -MAX_WBITS) != Z_OK) { 1345 *msg = strm.msg; 1346 return JNI_FALSE; 1347 } 1348 1349 strm.next_out = buf; 1350 strm.avail_out = (uInt)entry->size; 1351 1352 while (count > 0) { 1353 jint n = count > (jlong)sizeof(tmp) ? (jint)sizeof(tmp) : (jint)count; 1354 ZIP_Lock(zip); 1355 n = ZIP_Read(zip, entry, pos, tmp, n); 1356 ZIP_Unlock(zip); 1357 if (n <= 0) { 1358 if (n == 0) { 1359 *msg = "inflateFully: Unexpected end of file"; 1360 } 1361 inflateEnd(&strm); 1362 return JNI_FALSE; 1363 } 1364 pos += n; 1365 count -= n; 1366 strm.next_in = (Bytef *)tmp; 1367 strm.avail_in = n; 1368 do { 1369 switch (inflate(&strm, Z_PARTIAL_FLUSH)) { 1370 case Z_OK: 1371 break; 1372 case Z_STREAM_END: 1373 if (count != 0 || strm.total_out != entry->size) { 1374 *msg = "inflateFully: Unexpected end of stream"; 1375 inflateEnd(&strm); 1376 return JNI_FALSE; 1377 } 1378 break; 1379 default: 1380 break; 1381 } 1382 } while (strm.avail_in > 0); 1383 } 1384 inflateEnd(&strm); 1385 return JNI_TRUE; 1386 } 1387 1388 /* 1389 * The current implementation does not support reading an entry that 1390 * has the size bigger than 2**32 bytes in ONE invocation. 1391 */ 1392 jzentry * JNICALL 1393 ZIP_FindEntry(jzfile *zip, char *name, jint *sizeP, jint *nameLenP) 1394 { 1395 jzentry *entry = ZIP_GetEntry(zip, name, 0); 1396 if (entry) { 1397 *sizeP = (jint)entry->size; 1398 *nameLenP = strlen(entry->name); 1399 } 1400 return entry; 1401 } 1402 1403 /* 1404 * Reads a zip file entry into the specified byte array 1405 * When the method completes, it releases the jzentry. 1406 * Note: this is called from the separately delivered VM (hotspot/classic) 1407 * so we have to be careful to maintain the expected behaviour. 1408 */ 1409 jboolean JNICALL 1410 ZIP_ReadEntry(jzfile *zip, jzentry *entry, unsigned char *buf, char *entryname) 1411 { 1412 char *msg; 1413 1414 strcpy(entryname, entry->name); 1415 if (entry->csize == 0) { 1416 /* Entry is stored */ 1417 jlong pos = 0; 1418 jlong size = entry->size; 1419 while (pos < size) { 1420 jint n; 1421 jlong limit = ((((jlong) 1) << 31) - 1); 1422 jint count = (size - pos < limit) ? 1423 /* These casts suppress a VC++ Internal Compiler Error */ 1424 (jint) (size - pos) : 1425 (jint) limit; 1426 ZIP_Lock(zip); 1427 n = ZIP_Read(zip, entry, pos, buf, count); 1428 msg = zip->msg; 1429 ZIP_Unlock(zip); 1430 if (n == -1) { 1431 jio_fprintf(stderr, "%s: %s\n", zip->name, 1432 msg != 0 ? msg : strerror(errno)); 1433 return JNI_FALSE; 1434 } 1435 buf += n; 1436 pos += n; 1437 } 1438 } else { 1439 /* Entry is compressed */ 1440 int ok = InflateFully(zip, entry, buf, &msg); 1441 if (!ok) { 1442 if ((msg == NULL) || (*msg == 0)) { 1443 msg = zip->msg; 1444 } 1445 jio_fprintf(stderr, "%s: %s\n", zip->name, 1446 msg != 0 ? msg : strerror(errno)); 1447 return JNI_FALSE; 1448 } 1449 } 1450 1451 ZIP_FreeEntry(zip, entry); 1452 1453 return JNI_TRUE; 1454 }