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