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