Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/native/java/util/zip/zip_util.c
38830 views
/*1* Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26* Support for reading ZIP/JAR files.27*/2829#include <stdio.h>30#include <stdlib.h>31#include <stddef.h>32#include <string.h>33#include <fcntl.h>34#include <limits.h>35#include <time.h>36#include <ctype.h>37#include <assert.h>3839#include "jni.h"40#include "jni_util.h"41#include "jlong.h"42#include "jvm.h"43#include "io_util.h"44#include "io_util_md.h"45#include "zip_util.h"46#include <zlib.h>4748#ifdef _ALLBSD_SOURCE49#define off64_t off_t50#define mmap64 mmap51#endif5253/* USE_MMAP means mmap the CEN & ENDHDR part of the zip file. */54#ifdef USE_MMAP55#include <sys/mman.h>56#endif5758#define MAXREFS 0xFFFF /* max number of open zip file references */5960#define MCREATE() JVM_RawMonitorCreate()61#define MLOCK(lock) JVM_RawMonitorEnter(lock)62#define MUNLOCK(lock) JVM_RawMonitorExit(lock)63#define MDESTROY(lock) JVM_RawMonitorDestroy(lock)6465#define CENSIZE(cen) (CENHDR + CENNAM(cen) + CENEXT(cen) + CENCOM(cen))6667static jzfile *zfiles = 0; /* currently open zip files */68static void *zfiles_lock = 0;6970static void freeCEN(jzfile *);7172#ifndef PATH_MAX73#define PATH_MAX 102474#endif7576static jint INITIAL_META_COUNT = 2; /* initial number of entries in meta name array */7778/*79* The ZFILE_* functions exist to provide some platform-independence with80* respect to file access needs.81*/8283/*84* Opens the named file for reading, returning a ZFILE.85*86* Compare this with winFileHandleOpen in windows/native/java/io/io_util_md.c.87* This function does not take JNIEnv* and uses CreateFile (instead of88* CreateFileW). The expectation is that this function will be called only89* from ZIP_Open_Generic, which in turn is used by the JVM, where we do not90* need to concern ourselves with wide chars.91*/92static ZFILE93ZFILE_Open(const char *fname, int flags) {94#ifdef WIN3295const DWORD access =96(flags & O_RDWR) ? (GENERIC_WRITE | GENERIC_READ) :97(flags & O_WRONLY) ? GENERIC_WRITE :98GENERIC_READ;99const DWORD sharing =100FILE_SHARE_READ | FILE_SHARE_WRITE;101const DWORD disposition =102/* Note: O_TRUNC overrides O_CREAT */103(flags & O_TRUNC) ? CREATE_ALWAYS :104(flags & O_CREAT) ? OPEN_ALWAYS :105OPEN_EXISTING;106const DWORD maybeWriteThrough =107(flags & (O_SYNC | O_DSYNC)) ?108FILE_FLAG_WRITE_THROUGH :109FILE_ATTRIBUTE_NORMAL;110const DWORD maybeDeleteOnClose =111(flags & O_TEMPORARY) ?112FILE_FLAG_DELETE_ON_CLOSE :113FILE_ATTRIBUTE_NORMAL;114const DWORD flagsAndAttributes = maybeWriteThrough | maybeDeleteOnClose;115116return (jlong) CreateFile(117fname, /* Wide char path name */118access, /* Read and/or write permission */119sharing, /* File sharing flags */120NULL, /* Security attributes */121disposition, /* creation disposition */122flagsAndAttributes, /* flags and attributes */123NULL);124#else125return JVM_Open(fname, flags, 0);126#endif127}128129/*130* The io_util_md.h files do not provide IO_CLOSE, hence we use platform131* specifics.132*/133static void134ZFILE_Close(ZFILE zfd) {135#ifdef WIN32136CloseHandle((HANDLE) zfd);137#else138JVM_Close(zfd);139#endif140}141142static int143ZFILE_read(ZFILE zfd, char *buf, jint nbytes) {144#ifdef WIN32145return (int) IO_Read(zfd, buf, nbytes);146#else147/*148* Calling JVM_Read will return JVM_IO_INTR when Thread.interrupt is called149* only on Solaris. Continue reading jar file in this case is the best150* thing to do since zip file reading is relatively fast and it is very onerous151* for a interrupted thread to deal with this kind of hidden I/O. However, handling152* JVM_IO_INTR is tricky and could cause undesired side effect. So we decided153* to simply call "read" on Solaris/Linux. See details in bug 6304463.154*/155return read(zfd, buf, nbytes);156#endif157}158159/*160* Initialize zip file support. Return 0 if successful otherwise -1161* if could not be initialized.162*/163static jint164InitializeZip()165{166static jboolean inited = JNI_FALSE;167168// Initialize errno to 0. It may be set later (e.g. during memory169// allocation) but we can disregard previous values.170errno = 0;171172if (inited)173return 0;174zfiles_lock = MCREATE();175if (zfiles_lock == 0) {176return -1;177}178inited = JNI_TRUE;179180return 0;181}182183/*184* Reads len bytes of data into buf.185* Returns 0 if all bytes could be read, otherwise returns -1.186*/187static int188readFully(ZFILE zfd, void *buf, jlong len) {189char *bp = (char *) buf;190191while (len > 0) {192jlong limit = ((((jlong) 1) << 31) - 1);193jint count = (len < limit) ?194(jint) len :195(jint) limit;196jint n = ZFILE_read(zfd, bp, count);197if (n > 0) {198bp += n;199len -= n;200} else if (n == JVM_IO_ERR && errno == EINTR) {201/* Retry after EINTR (interrupted by signal).202We depend on the fact that JVM_IO_ERR == -1. */203continue;204} else { /* EOF or IO error */205return -1;206}207}208return 0;209}210211/*212* Reads len bytes of data from the specified offset into buf.213* Returns 0 if all bytes could be read, otherwise returns -1.214*/215static int216readFullyAt(ZFILE zfd, void *buf, jlong len, jlong offset)217{218if (IO_Lseek(zfd, offset, SEEK_SET) == -1) {219return -1; /* lseek failure. */220}221222return readFully(zfd, buf, len);223}224225/*226* Allocates a new zip file object for the specified file name.227* Returns the zip file object or NULL if not enough memory.228*/229static jzfile *230allocZip(const char *name)231{232jzfile *zip;233if (((zip = calloc(1, sizeof(jzfile))) != NULL) &&234((zip->name = strdup(name)) != NULL) &&235((zip->lock = MCREATE()) != NULL)) {236zip->zfd = -1;237return zip;238}239240if (zip != NULL) {241free(zip->name);242free(zip);243}244return NULL;245}246247/*248* Frees all native resources owned by the specified zip file object.249*/250static void251freeZip(jzfile *zip)252{253/* First free any cached jzentry */254ZIP_FreeEntry(zip,0);255if (zip->lock != NULL) MDESTROY(zip->lock);256free(zip->name);257freeCEN(zip);258259#ifdef USE_MMAP260if (zip->usemmap) {261if (zip->maddr != NULL)262munmap((char *)zip->maddr, zip->mlen);263} else264#endif265{266free(zip->cencache.data);267}268if (zip->comment != NULL)269free(zip->comment);270if (zip->zfd != -1) ZFILE_Close(zip->zfd);271free(zip);272}273274/* The END header is followed by a variable length comment of size < 64k. */275static const jlong END_MAXLEN = 0xFFFF + ENDHDR;276277#define READBLOCKSZ 128278279static jboolean verifyEND(jzfile *zip, jlong endpos, char *endbuf) {280/* ENDSIG matched, however the size of file comment in it does not281match the real size. One "common" cause for this problem is some282"extra" bytes are padded at the end of the zipfile.283Let's do some extra verification, we don't care about the performance284in this situation.285*/286jlong cenpos = endpos - ENDSIZ(endbuf);287jlong locpos = cenpos - ENDOFF(endbuf);288char buf[4];289return (cenpos >= 0 &&290locpos >= 0 &&291readFullyAt(zip->zfd, buf, sizeof(buf), cenpos) != -1 &&292GETSIG(buf) == CENSIG &&293readFullyAt(zip->zfd, buf, sizeof(buf), locpos) != -1 &&294GETSIG(buf) == LOCSIG);295}296297/*298* Searches for end of central directory (END) header. The contents of299* the END header will be read and placed in endbuf. Returns the file300* position of the END header, otherwise returns -1 if the END header301* was not found or an error occurred.302*/303static jlong304findEND(jzfile *zip, void *endbuf)305{306char buf[READBLOCKSZ];307jlong pos;308const jlong len = zip->len;309const ZFILE zfd = zip->zfd;310const jlong minHDR = len - END_MAXLEN > 0 ? len - END_MAXLEN : 0;311const jlong minPos = minHDR - (sizeof(buf)-ENDHDR);312jint clen;313314for (pos = len - sizeof(buf); pos >= minPos; pos -= (sizeof(buf)-ENDHDR)) {315316int i;317jlong off = 0;318if (pos < 0) {319/* Pretend there are some NUL bytes before start of file */320off = -pos;321memset(buf, '\0', (size_t)off);322}323324if (readFullyAt(zfd, buf + off, sizeof(buf) - off,325pos + off) == -1) {326return -1; /* System error */327}328329/* Now scan the block backwards for END header signature */330for (i = sizeof(buf) - ENDHDR; i >= 0; i--) {331if (buf[i+0] == 'P' &&332buf[i+1] == 'K' &&333buf[i+2] == '\005' &&334buf[i+3] == '\006' &&335((pos + i + ENDHDR + ENDCOM(buf + i) == len)336|| verifyEND(zip, pos + i, buf + i))) {337/* Found END header */338memcpy(endbuf, buf + i, ENDHDR);339340clen = ENDCOM(endbuf);341if (clen != 0) {342zip->comment = malloc(clen + 1);343if (zip->comment == NULL) {344return -1;345}346if (readFullyAt(zfd, zip->comment, clen, pos + i + ENDHDR)347== -1) {348free(zip->comment);349zip->comment = NULL;350return -1;351}352zip->comment[clen] = '\0';353zip->clen = clen;354}355return pos + i;356}357}358}359360return -1; /* END header not found */361}362363/*364* Searches for the ZIP64 end of central directory (END) header. The365* contents of the ZIP64 END header will be read and placed in end64buf.366* Returns the file position of the ZIP64 END header, otherwise returns367* -1 if the END header was not found or an error occurred.368*369* The ZIP format specifies the "position" of each related record as370* ...371* [central directory]372* [zip64 end of central directory record]373* [zip64 end of central directory locator]374* [end of central directory record]375*376* The offset of zip64 end locator can be calculated from endpos as377* "endpos - ZIP64_LOCHDR".378* The "offset" of zip64 end record is stored in zip64 end locator.379*/380static jlong381findEND64(jzfile *zip, void *end64buf, jlong endpos)382{383char loc64[ZIP64_LOCHDR];384jlong end64pos;385if (readFullyAt(zip->zfd, loc64, ZIP64_LOCHDR, endpos - ZIP64_LOCHDR) == -1) {386return -1; // end64 locator not found387}388end64pos = ZIP64_LOCOFF(loc64);389if (readFullyAt(zip->zfd, end64buf, ZIP64_ENDHDR, end64pos) == -1) {390return -1; // end64 record not found391}392return end64pos;393}394395/*396* Returns a hash code value for a C-style NUL-terminated string.397*/398static unsigned int399hash(const char *s)400{401int h = 0;402while (*s != '\0')403h = 31*h + *s++;404return h;405}406407/*408* Returns a hash code value for a string of a specified length.409*/410static unsigned int411hashN(const char *s, int length)412{413int h = 0;414while (length-- > 0)415h = 31*h + *s++;416return h;417}418419static unsigned int420hash_append(unsigned int hash, char c)421{422return ((int)hash)*31 + c;423}424425/*426* Returns true if the specified entry's name begins with the string427* "META-INF/" irrespective of case.428*/429static int430isMetaName(const char *name, int length)431{432const char *s;433if (length < (int)sizeof("META-INF/") - 1)434return 0;435for (s = "META-INF/"; *s != '\0'; s++) {436char c = *name++;437// Avoid toupper; it's locale-dependent438if (c >= 'a' && c <= 'z') c += 'A' - 'a';439if (*s != c)440return 0;441}442return 1;443}444445/*446* Increases the capacity of zip->metanames.447* Returns non-zero in case of allocation error.448*/449static int450growMetaNames(jzfile *zip)451{452jint i;453/* double the meta names array */454const jint new_metacount = zip->metacount << 1;455zip->metanames =456realloc(zip->metanames, new_metacount * sizeof(zip->metanames[0]));457if (zip->metanames == NULL) return -1;458for (i = zip->metacount; i < new_metacount; i++)459zip->metanames[i] = NULL;460zip->metacurrent = zip->metacount;461zip->metacount = new_metacount;462return 0;463}464465/*466* Adds name to zip->metanames.467* Returns non-zero in case of allocation error.468*/469static int470addMetaName(jzfile *zip, const char *name, int length)471{472jint i;473if (zip->metanames == NULL) {474zip->metacount = INITIAL_META_COUNT;475zip->metanames = calloc(zip->metacount, sizeof(zip->metanames[0]));476if (zip->metanames == NULL) return -1;477zip->metacurrent = 0;478}479480i = zip->metacurrent;481482/* current meta name array isn't full yet. */483if (i < zip->metacount) {484zip->metanames[i] = (char *) malloc(length+1);485if (zip->metanames[i] == NULL) return -1;486memcpy(zip->metanames[i], name, length);487zip->metanames[i][length] = '\0';488zip->metacurrent++;489return 0;490}491492/* No free entries in zip->metanames? */493if (growMetaNames(zip) != 0) return -1;494return addMetaName(zip, name, length);495}496497static void498freeMetaNames(jzfile *zip)499{500if (zip->metanames) {501jint i;502for (i = 0; i < zip->metacount; i++)503free(zip->metanames[i]);504free(zip->metanames);505zip->metanames = NULL;506}507}508509/* Free Zip data allocated by readCEN() */510static void511freeCEN(jzfile *zip)512{513free(zip->entries); zip->entries = NULL;514free(zip->table); zip->table = NULL;515freeMetaNames(zip);516}517518/*519* Counts the number of CEN headers in a central directory extending520* from BEG to END. Might return a bogus answer if the zip file is521* corrupt, but will not crash.522*/523static jint524countCENHeaders(unsigned char *beg, unsigned char *end)525{526jint count = 0;527ptrdiff_t i;528for (i = 0; i + CENHDR <= end - beg; i += CENSIZE(beg + i))529count++;530return count;531}532533#define ZIP_FORMAT_ERROR(message) \534if (1) { zip->msg = message; goto Catch; } else ((void)0)535536/*537* Reads zip file central directory. Returns the file position of first538* CEN header, otherwise returns -1 if an error occurred. If zip->msg != NULL539* then the error was a zip format error and zip->msg has the error text.540* Always pass in -1 for knownTotal; it's used for a recursive call.541*/542static jlong543readCEN(jzfile *zip, jint knownTotal)544{545/* Following are unsigned 32-bit */546jlong endpos, end64pos, cenpos, cenlen, cenoff;547/* Following are unsigned 16-bit */548jint total, tablelen, i, j;549unsigned char *cenbuf = NULL;550unsigned char *cenend;551unsigned char *cp;552#ifdef USE_MMAP553static jlong pagesize;554jlong offset;555#endif556unsigned char endbuf[ENDHDR];557jint endhdrlen = ENDHDR;558jzcell *entries;559jint *table;560561/* Clear previous zip error */562zip->msg = NULL;563/* Get position of END header */564if ((endpos = findEND(zip, endbuf)) == -1)565return -1; /* no END header or system error */566567if (endpos == 0) return 0; /* only END header present */568569freeCEN(zip);570/* Get position and length of central directory */571cenlen = ENDSIZ(endbuf);572cenoff = ENDOFF(endbuf);573total = ENDTOT(endbuf);574if (cenlen == ZIP64_MAGICVAL || cenoff == ZIP64_MAGICVAL ||575total == ZIP64_MAGICCOUNT) {576unsigned char end64buf[ZIP64_ENDHDR];577if ((end64pos = findEND64(zip, end64buf, endpos)) != -1) {578cenlen = ZIP64_ENDSIZ(end64buf);579cenoff = ZIP64_ENDOFF(end64buf);580total = (jint)ZIP64_ENDTOT(end64buf);581endpos = end64pos;582endhdrlen = ZIP64_ENDHDR;583}584}585586if (cenlen > endpos)587ZIP_FORMAT_ERROR("invalid END header (bad central directory size)");588cenpos = endpos - cenlen;589590/* Get position of first local file (LOC) header, taking into591* account that there may be a stub prefixed to the zip file. */592zip->locpos = cenpos - cenoff;593if (zip->locpos < 0)594ZIP_FORMAT_ERROR("invalid END header (bad central directory offset)");595596#ifdef USE_MMAP597if (zip->usemmap) {598/* On Solaris & Linux prior to JDK 6, we used to mmap the whole jar file to599* read the jar file contents. However, this greatly increased the perceived600* footprint numbers because the mmap'ed pages were adding into the totals shown601* by 'ps' and 'top'. We switched to mmaping only the central directory of jar602* file while calling 'read' to read the rest of jar file. Here are a list of603* reasons apart from above of why we are doing so:604* 1. Greatly reduces mmap overhead after startup complete;605* 2. Avoids dual path code maintainance;606* 3. Greatly reduces risk of address space (not virtual memory) exhaustion.607*/608if (pagesize == 0) {609pagesize = (jlong)sysconf(_SC_PAGESIZE);610if (pagesize == 0) goto Catch;611}612if (cenpos > pagesize) {613offset = cenpos & ~(pagesize - 1);614} else {615offset = 0;616}617/* When we are not calling recursively, knownTotal is -1. */618if (knownTotal == -1) {619void* mappedAddr;620/* Mmap the CEN and END part only. We have to figure621out the page size in order to make offset to be multiples of622page size.623*/624zip->mlen = cenpos - offset + cenlen + endhdrlen;625zip->offset = offset;626mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset);627zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL :628(unsigned char*)mappedAddr;629630if (zip->maddr == NULL) {631jio_fprintf(stderr, "mmap failed for CEN and END part of zip file\n");632goto Catch;633}634}635cenbuf = zip->maddr + cenpos - offset;636} else637#endif638{639if ((cenbuf = malloc((size_t) cenlen)) == NULL ||640(readFullyAt(zip->zfd, cenbuf, cenlen, cenpos) == -1))641goto Catch;642}643644cenend = cenbuf + cenlen;645646/* Initialize zip file data structures based on the total number647* of central directory entries as stored in ENDTOT. Since this648* is a 2-byte field, but we (and other zip implementations)649* support approx. 2**31 entries, we do not trust ENDTOT, but650* treat it only as a strong hint. When we call ourselves651* recursively, knownTotal will have the "true" value.652*653* Keep this path alive even with the Zip64 END support added, just654* for zip files that have more than 0xffff entries but don't have655* the Zip64 enabled.656*/657total = (knownTotal != -1) ? knownTotal : total;658entries = zip->entries = calloc(total, sizeof(entries[0]));659tablelen = zip->tablelen = ((total/2) | 1); // Odd -> fewer collisions660table = zip->table = malloc(tablelen * sizeof(table[0]));661/* According to ISO C it is perfectly legal for malloc to return zero662* if called with a zero argument. We check this for 'entries' but not663* for 'table' because 'tablelen' can't be zero (see computation above). */664if ((entries == NULL && total != 0) || table == NULL) goto Catch;665for (j = 0; j < tablelen; j++)666table[j] = ZIP_ENDCHAIN;667668/* Iterate through the entries in the central directory */669for (i = 0, cp = cenbuf; cp <= cenend - CENHDR; i++, cp += CENSIZE(cp)) {670/* Following are unsigned 16-bit */671jint method, nlen;672unsigned int hsh;673674if (i >= total) {675/* This will only happen if the zip file has an incorrect676* ENDTOT field, which usually means it contains more than677* 65535 entries. */678cenpos = readCEN(zip, countCENHeaders(cenbuf, cenend));679goto Finally;680}681682method = CENHOW(cp);683nlen = CENNAM(cp);684685if (GETSIG(cp) != CENSIG)686ZIP_FORMAT_ERROR("invalid CEN header (bad signature)");687if (CENFLG(cp) & 1)688ZIP_FORMAT_ERROR("invalid CEN header (encrypted entry)");689if (method != STORED && method != DEFLATED)690ZIP_FORMAT_ERROR("invalid CEN header (bad compression method)");691if (cp + CENHDR + nlen > cenend)692ZIP_FORMAT_ERROR("invalid CEN header (bad header size)");693694/* if the entry is metadata add it to our metadata names */695if (isMetaName((char *)cp+CENHDR, nlen))696if (addMetaName(zip, (char *)cp+CENHDR, nlen) != 0)697goto Catch;698699/* Record the CEN offset and the name hash in our hash cell. */700entries[i].cenpos = cenpos + (cp - cenbuf);701entries[i].hash = hashN((char *)cp+CENHDR, nlen);702703/* Add the entry to the hash table */704hsh = entries[i].hash % tablelen;705entries[i].next = table[hsh];706table[hsh] = i;707}708if (cp != cenend)709ZIP_FORMAT_ERROR("invalid CEN header (bad header size)");710711zip->total = i;712goto Finally;713714Catch:715freeCEN(zip);716cenpos = -1;717718Finally:719#ifdef USE_MMAP720if (!zip->usemmap)721#endif722free(cenbuf);723724return cenpos;725}726727/*728* Opens a zip file with the specified mode. Returns the jzfile object729* or NULL if an error occurred. If a zip error occurred then *pmsg will730* be set to the error message text if pmsg != 0. Otherwise, *pmsg will be731* set to NULL. Caller is responsible to free the error message.732*/733jzfile *734ZIP_Open_Generic(const char *name, char **pmsg, int mode, jlong lastModified)735{736jzfile *zip = NULL;737738/* Clear zip error message */739if (pmsg != 0) {740*pmsg = NULL;741}742743zip = ZIP_Get_From_Cache(name, pmsg, lastModified);744745if (zip == NULL && *pmsg == NULL) {746ZFILE zfd = ZFILE_Open(name, mode);747zip = ZIP_Put_In_Cache(name, zfd, pmsg, lastModified);748}749return zip;750}751752/*753* Returns the jzfile corresponding to the given file name from the cache of754* zip files, or NULL if the file is not in the cache. If the name is longer755* than PATH_MAX or a zip error occurred then *pmsg will be set to the error756* message text if pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller757* is responsible to free the error message.758*/759jzfile *760ZIP_Get_From_Cache(const char *name, char **pmsg, jlong lastModified)761{762char buf[PATH_MAX];763jzfile *zip;764765if (InitializeZip()) {766return NULL;767}768769/* Clear zip error message */770if (pmsg != 0) {771*pmsg = NULL;772}773774if (strlen(name) >= PATH_MAX) {775if (pmsg) {776*pmsg = strdup("zip file name too long");777}778return NULL;779}780strcpy(buf, name);781JVM_NativePath(buf);782name = buf;783784MLOCK(zfiles_lock);785for (zip = zfiles; zip != NULL; zip = zip->next) {786if (strcmp(name, zip->name) == 0787&& (zip->lastModified == lastModified || zip->lastModified == 0)788&& zip->refs < MAXREFS) {789zip->refs++;790break;791}792}793MUNLOCK(zfiles_lock);794return zip;795}796797/*798* Reads data from the given file descriptor to create a jzfile, puts the799* jzfile in a cache, and returns that jzfile. Returns NULL in case of error.800* If a zip error occurs, then *pmsg will be set to the error message text if801* pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller is responsible to802* free the error message.803*/804805jzfile *806ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified)807{808return ZIP_Put_In_Cache0(name, zfd, pmsg, lastModified, JNI_TRUE);809}810811jzfile *812ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified,813jboolean usemmap)814{815char errbuf[256];816jlong len;817jzfile *zip;818819if ((zip = allocZip(name)) == NULL) {820return NULL;821}822823#ifdef USE_MMAP824zip->usemmap = usemmap;825#endif826zip->refs = 1;827zip->lastModified = lastModified;828829if (zfd == -1) {830if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0)831*pmsg = strdup(errbuf);832freeZip(zip);833return NULL;834}835836// Assumption, zfd refers to start of file. Trivially, reuse errbuf.837if (readFully(zfd, errbuf, 4) != -1) { // errors will be handled later838if (GETSIG(errbuf) == LOCSIG)839zip->locsig = JNI_TRUE;840else841zip->locsig = JNI_FALSE;842}843844len = zip->len = IO_Lseek(zfd, 0, SEEK_END);845if (len <= 0) {846if (len == 0) { /* zip file is empty */847if (pmsg) {848*pmsg = strdup("zip file is empty");849}850} else { /* error */851if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0)852*pmsg = strdup(errbuf);853}854ZFILE_Close(zfd);855freeZip(zip);856return NULL;857}858859zip->zfd = zfd;860if (readCEN(zip, -1) < 0) {861/* An error occurred while trying to read the zip file */862if (pmsg != 0) {863/* Set the zip error message */864if (zip->msg != NULL)865*pmsg = strdup(zip->msg);866}867freeZip(zip);868return NULL;869}870MLOCK(zfiles_lock);871zip->next = zfiles;872zfiles = zip;873MUNLOCK(zfiles_lock);874875return zip;876}877878/*879* Opens a zip file for reading. Returns the jzfile object or NULL880* if an error occurred. If a zip error occurred then *msg will be881* set to the error message text if msg != 0. Otherwise, *msg will be882* set to NULL. Caller doesn't need to free the error message.883*/884jzfile * JNICALL885ZIP_Open(const char *name, char **pmsg)886{887jzfile *file = ZIP_Open_Generic(name, pmsg, O_RDONLY, 0);888if (file == NULL && pmsg != NULL && *pmsg != NULL) {889free(*pmsg);890*pmsg = "Zip file open error";891}892return file;893}894895/*896* Closes the specified zip file object.897*/898void JNICALL899ZIP_Close(jzfile *zip)900{901MLOCK(zfiles_lock);902if (--zip->refs > 0) {903/* Still more references so just return */904MUNLOCK(zfiles_lock);905return;906}907/* No other references so close the file and remove from list */908if (zfiles == zip) {909zfiles = zfiles->next;910} else {911jzfile *zp;912for (zp = zfiles; zp->next != 0; zp = zp->next) {913if (zp->next == zip) {914zp->next = zip->next;915break;916}917}918}919MUNLOCK(zfiles_lock);920freeZip(zip);921return;922}923924/* Empirically, most CEN headers are smaller than this. */925#define AMPLE_CEN_HEADER_SIZE 160926927/* A good buffer size when we want to read CEN headers sequentially. */928#define CENCACHE_PAGESIZE 8192929930static char *931readCENHeader(jzfile *zip, jlong cenpos, jint bufsize)932{933jint censize;934ZFILE zfd = zip->zfd;935char *cen;936if (bufsize > zip->len - cenpos)937bufsize = (jint)(zip->len - cenpos);938if ((cen = malloc(bufsize)) == NULL) goto Catch;939if (readFullyAt(zfd, cen, bufsize, cenpos) == -1) goto Catch;940censize = CENSIZE(cen);941if (censize <= bufsize) return cen;942if ((cen = realloc(cen, censize)) == NULL) goto Catch;943if (readFully(zfd, cen+bufsize, censize-bufsize) == -1) goto Catch;944return cen;945946Catch:947free(cen);948return NULL;949}950951static char *952sequentialAccessReadCENHeader(jzfile *zip, jlong cenpos)953{954cencache *cache = &zip->cencache;955char *cen;956if (cache->data != NULL957&& (cenpos >= cache->pos)958&& (cenpos + CENHDR <= cache->pos + CENCACHE_PAGESIZE))959{960cen = cache->data + cenpos - cache->pos;961if (cenpos + CENSIZE(cen) <= cache->pos + CENCACHE_PAGESIZE)962/* A cache hit */963return cen;964}965966if ((cen = readCENHeader(zip, cenpos, CENCACHE_PAGESIZE)) == NULL)967return NULL;968free(cache->data);969cache->data = cen;970cache->pos = cenpos;971return cen;972}973974typedef enum { ACCESS_RANDOM, ACCESS_SEQUENTIAL } AccessHint;975976/*977* Return a new initialized jzentry corresponding to a given hash cell.978* In case of error, returns NULL.979* We already sanity-checked all the CEN headers for ZIP format errors980* in readCEN(), so we don't check them again here.981* The ZIP lock should be held here.982*/983static jzentry *984newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint)985{986jlong locoff;987jint nlen, elen, clen;988jzentry *ze;989char *cen;990991if ((ze = (jzentry *) malloc(sizeof(jzentry))) == NULL) return NULL;992ze->name = NULL;993ze->extra = NULL;994ze->comment = NULL;995996#ifdef USE_MMAP997if (zip->usemmap) {998cen = (char*) zip->maddr + zc->cenpos - zip->offset;999} else1000#endif1001{1002if (accessHint == ACCESS_RANDOM)1003cen = readCENHeader(zip, zc->cenpos, AMPLE_CEN_HEADER_SIZE);1004else1005cen = sequentialAccessReadCENHeader(zip, zc->cenpos);1006if (cen == NULL) goto Catch;1007}10081009nlen = CENNAM(cen);1010elen = CENEXT(cen);1011clen = CENCOM(cen);1012ze->time = CENTIM(cen);1013ze->size = CENLEN(cen);1014ze->csize = (CENHOW(cen) == STORED) ? 0 : CENSIZ(cen);1015ze->crc = CENCRC(cen);1016locoff = CENOFF(cen);1017ze->pos = -(zip->locpos + locoff);1018ze->flag = CENFLG(cen);10191020if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch;1021memcpy(ze->name, cen + CENHDR, nlen);1022ze->name[nlen] = '\0';1023ze->nlen = nlen;1024if (elen > 0) {1025char *extra = cen + CENHDR + nlen;10261027/* This entry has "extra" data */1028if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch;1029ze->extra[0] = (unsigned char) elen;1030ze->extra[1] = (unsigned char) (elen >> 8);1031memcpy(ze->extra+2, extra, elen);1032if (ze->csize == ZIP64_MAGICVAL || ze->size == ZIP64_MAGICVAL ||1033locoff == ZIP64_MAGICVAL) {1034jint off = 0;1035while ((off + 4) < elen) { // spec: HeaderID+DataSize+Data1036jint sz = SH(extra, off + 2);1037if (SH(extra, off) == ZIP64_EXTID) {1038off += 4;1039if (ze->size == ZIP64_MAGICVAL) {1040// if invalid zip64 extra fields, just skip1041if (sz < 8 || (off + 8) > elen)1042break;1043ze->size = LL(extra, off);1044sz -= 8;1045off += 8;1046}1047if (ze->csize == ZIP64_MAGICVAL) {1048if (sz < 8 || (off + 8) > elen)1049break;1050ze->csize = LL(extra, off);1051sz -= 8;1052off += 8;1053}1054if (locoff == ZIP64_MAGICVAL) {1055if (sz < 8 || (off + 8) > elen)1056break;1057ze->pos = -(zip->locpos + LL(extra, off));1058sz -= 8;1059off += 8;1060}1061break;1062}1063off += (sz + 4);1064}1065}1066}10671068if (clen > 0) {1069/* This entry has a comment */1070if ((ze->comment = malloc(clen + 1)) == NULL) goto Catch;1071memcpy(ze->comment, cen + CENHDR + nlen + elen, clen);1072ze->comment[clen] = '\0';1073}1074goto Finally;10751076Catch:1077free(ze->name);1078free(ze->extra);1079free(ze->comment);1080free(ze);1081ze = NULL;10821083Finally:1084#ifdef USE_MMAP1085if (!zip->usemmap)1086#endif1087if (cen != NULL && accessHint == ACCESS_RANDOM) free(cen);1088return ze;1089}10901091/*1092* Free the given jzentry.1093* In fact we maintain a one-entry cache of the most recently used1094* jzentry for each zip. This optimizes a common access pattern.1095*/10961097void1098ZIP_FreeEntry(jzfile *jz, jzentry *ze)1099{1100jzentry *last;1101ZIP_Lock(jz);1102last = jz->cache;1103jz->cache = ze;1104ZIP_Unlock(jz);1105if (last != NULL) {1106/* Free the previously cached jzentry */1107free(last->name);1108if (last->extra) free(last->extra);1109if (last->comment) free(last->comment);1110free(last);1111}1112}11131114/*1115* Returns the zip entry corresponding to the specified name, or1116* NULL if not found.1117*/1118jzentry *1119ZIP_GetEntry(jzfile *zip, char *name, jint ulen)1120{1121if (ulen == 0) {1122return ZIP_GetEntry2(zip, name, strlen(name), JNI_FALSE);1123}1124return ZIP_GetEntry2(zip, name, ulen, JNI_TRUE);1125}11261127jboolean equals(char* name1, int len1, char* name2, int len2) {1128if (len1 != len2) {1129return JNI_FALSE;1130}1131while (len1-- > 0) {1132if (*name1++ != *name2++) {1133return JNI_FALSE;1134}1135}1136return JNI_TRUE;1137}11381139/*1140* Returns the zip entry corresponding to the specified name, or1141* NULL if not found.1142* This method supports embedded null character in "name", use ulen1143* for the length of "name".1144*/1145jzentry *1146ZIP_GetEntry2(jzfile *zip, char *name, jint ulen, jboolean addSlash)1147{1148unsigned int hsh = hashN(name, ulen);1149jint idx;1150jzentry *ze = 0;11511152ZIP_Lock(zip);1153if (zip->total == 0) {1154goto Finally;1155}11561157idx = zip->table[hsh % zip->tablelen];11581159/*1160* This while loop is an optimization where a double lookup1161* for name and name+/ is being performed. The name char1162* array has enough room at the end to try again with a1163* slash appended if the first table lookup does not succeed.1164*/1165while(1) {11661167/* Check the cached entry first */1168ze = zip->cache;1169if (ze && equals(ze->name, ze->nlen, name, ulen)) {1170/* Cache hit! Remove and return the cached entry. */1171zip->cache = 0;1172ZIP_Unlock(zip);1173return ze;1174}1175ze = 0;11761177/*1178* Search down the target hash chain for a cell whose1179* 32 bit hash matches the hashed name.1180*/1181while (idx != ZIP_ENDCHAIN) {1182jzcell *zc = &zip->entries[idx];11831184if (zc->hash == hsh) {1185/*1186* OK, we've found a ZIP entry whose 32 bit hashcode1187* matches the name we're looking for. Try to read1188* its entry information from the CEN. If the CEN1189* name matches the name we're looking for, we're1190* done.1191* If the names don't match (which should be very rare)1192* we keep searching.1193*/1194ze = newEntry(zip, zc, ACCESS_RANDOM);1195if (ze && equals(ze->name, ze->nlen, name, ulen)) {1196break;1197}1198if (ze != 0) {1199/* We need to release the lock across the free call */1200ZIP_Unlock(zip);1201ZIP_FreeEntry(zip, ze);1202ZIP_Lock(zip);1203}1204ze = 0;1205}1206idx = zc->next;1207}12081209/* Entry found, return it */1210if (ze != 0) {1211break;1212}12131214/* If no need to try appending slash, we are done */1215if (!addSlash) {1216break;1217}12181219/* Slash is already there? */1220if (name[ulen-1] == '/') {1221break;1222}12231224/* Add slash and try once more */1225name[ulen++] = '/';1226name[ulen] = '\0';1227hsh = hash_append(hsh, '/');1228idx = zip->table[hsh % zip->tablelen];1229addSlash = JNI_FALSE;1230}12311232Finally:1233ZIP_Unlock(zip);1234return ze;1235}12361237/*1238* Returns the n'th (starting at zero) zip file entry, or NULL if the1239* specified index was out of range.1240*/1241jzentry * JNICALL1242ZIP_GetNextEntry(jzfile *zip, jint n)1243{1244jzentry *result;1245if (n < 0 || n >= zip->total) {1246return 0;1247}1248ZIP_Lock(zip);1249result = newEntry(zip, &zip->entries[n], ACCESS_SEQUENTIAL);1250ZIP_Unlock(zip);1251return result;1252}12531254/*1255* Locks the specified zip file for reading.1256*/1257void1258ZIP_Lock(jzfile *zip)1259{1260MLOCK(zip->lock);1261}12621263/*1264* Unlocks the specified zip file.1265*/1266void1267ZIP_Unlock(jzfile *zip)1268{1269MUNLOCK(zip->lock);1270}12711272/*1273* Returns the offset of the entry data within the zip file.1274* Returns -1 if an error occurred, in which case zip->msg will1275* contain the error text.1276*/1277jlong1278ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry)1279{1280/* The Zip file spec explicitly allows the LOC extra data size to1281* be different from the CEN extra data size, although the JDK1282* never creates such zip files. Since we cannot trust the CEN1283* extra data size, we need to read the LOC to determine the entry1284* data offset. We do this lazily to avoid touching the virtual1285* memory page containing the LOC when initializing jzentry1286* objects. (This speeds up javac by a factor of 10 when the JDK1287* is installed on a very slow filesystem.)1288*/1289if (entry->pos <= 0) {1290unsigned char loc[LOCHDR];1291if (readFullyAt(zip->zfd, loc, LOCHDR, -(entry->pos)) == -1) {1292zip->msg = "error reading zip file";1293return -1;1294}1295if (GETSIG(loc) != LOCSIG) {1296zip->msg = "invalid LOC header (bad signature)";1297return -1;1298}1299entry->pos = (- entry->pos) + LOCHDR + LOCNAM(loc) + LOCEXT(loc);1300}1301return entry->pos;1302}13031304/*1305* Reads bytes from the specified zip entry. Assumes that the zip1306* file had been previously locked with ZIP_Lock(). Returns the1307* number of bytes read, or -1 if an error occurred. If zip->msg != 01308* then a zip error occurred and zip->msg contains the error text.1309*1310* The current implementation does not support reading an entry that1311* has the size bigger than 2**32 bytes in ONE invocation.1312*/1313jint1314ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len)1315{1316jlong entry_size;1317jlong start;13181319if (zip == 0) {1320return -1;1321}13221323/* Clear previous zip error */1324zip->msg = NULL;13251326if (entry == 0) {1327zip->msg = "ZIP_Read: jzentry is NULL";1328return -1;1329}13301331entry_size = (entry->csize != 0) ? entry->csize : entry->size;13321333/* Check specified position */1334if (pos < 0 || pos > entry_size - 1) {1335zip->msg = "ZIP_Read: specified offset out of range";1336return -1;1337}13381339/* Check specified length */1340if (len <= 0)1341return 0;1342if (len > entry_size - pos)1343len = (jint)(entry_size - pos);13441345/* Get file offset to start reading data */1346start = ZIP_GetEntryDataOffset(zip, entry);1347if (start < 0)1348return -1;1349start += pos;13501351if (start + len > zip->len) {1352zip->msg = "ZIP_Read: corrupt zip file: invalid entry size";1353return -1;1354}13551356if (readFullyAt(zip->zfd, buf, len, start) == -1) {1357zip->msg = "ZIP_Read: error reading zip file";1358return -1;1359}1360return len;1361}136213631364/* The maximum size of a stack-allocated buffer.1365*/1366#define BUF_SIZE 409613671368/*1369* This function is used by the runtime system to load compressed entries1370* from ZIP/JAR files specified in the class path. It is defined here1371* so that it can be dynamically loaded by the runtime if the zip library1372* is found.1373*1374* The current implementation does not support reading an entry that1375* has the size bigger than 2**32 bytes in ONE invocation.1376*/1377jboolean1378InflateFully(jzfile *zip, jzentry *entry, void *buf, char **msg)1379{1380z_stream strm;1381char tmp[BUF_SIZE];1382jlong pos = 0;1383jlong count = entry->csize;13841385*msg = 0; /* Reset error message */13861387if (count == 0) {1388*msg = "inflateFully: entry not compressed";1389return JNI_FALSE;1390}13911392memset(&strm, 0, sizeof(z_stream));1393if (inflateInit2(&strm, -MAX_WBITS) != Z_OK) {1394*msg = strm.msg;1395return JNI_FALSE;1396}13971398strm.next_out = buf;1399strm.avail_out = (uInt)entry->size;14001401while (count > 0) {1402jint n = count > (jlong)sizeof(tmp) ? (jint)sizeof(tmp) : (jint)count;1403ZIP_Lock(zip);1404n = ZIP_Read(zip, entry, pos, tmp, n);1405ZIP_Unlock(zip);1406if (n <= 0) {1407if (n == 0) {1408*msg = "inflateFully: Unexpected end of file";1409}1410inflateEnd(&strm);1411return JNI_FALSE;1412}1413pos += n;1414count -= n;1415strm.next_in = (Bytef *)tmp;1416strm.avail_in = n;1417do {1418switch (inflate(&strm, Z_PARTIAL_FLUSH)) {1419case Z_OK:1420break;1421case Z_STREAM_END:1422if (count != 0 || strm.total_out != entry->size) {1423*msg = "inflateFully: Unexpected end of stream";1424inflateEnd(&strm);1425return JNI_FALSE;1426}1427break;1428default:1429break;1430}1431} while (strm.avail_in > 0);1432}1433inflateEnd(&strm);1434return JNI_TRUE;1435}14361437/*1438* The current implementation does not support reading an entry that1439* has the size bigger than 2**32 bytes in ONE invocation.1440*/1441jzentry * JNICALL1442ZIP_FindEntry(jzfile *zip, char *name, jint *sizeP, jint *nameLenP)1443{1444jzentry *entry = ZIP_GetEntry(zip, name, 0);1445if (entry) {1446*sizeP = (jint)entry->size;1447*nameLenP = strlen(entry->name);1448}1449return entry;1450}14511452/*1453* Reads a zip file entry into the specified byte array1454* When the method completes, it releases the jzentry.1455* Note: this is called from the separately delivered VM (hotspot/classic)1456* so we have to be careful to maintain the expected behaviour.1457*/1458jboolean JNICALL1459ZIP_ReadEntry(jzfile *zip, jzentry *entry, unsigned char *buf, char *entryname)1460{1461char *msg;1462char tmpbuf[1024];14631464if (entry == 0) {1465jio_fprintf(stderr, "jzentry was invalid");1466return JNI_FALSE;1467}14681469strcpy(entryname, entry->name);1470if (entry->csize == 0) {1471/* Entry is stored */1472jlong pos = 0;1473jlong size = entry->size;1474while (pos < size) {1475jint n;1476jlong limit = ((((jlong) 1) << 31) - 1);1477jint count = (size - pos < limit) ?1478/* These casts suppress a VC++ Internal Compiler Error */1479(jint) (size - pos) :1480(jint) limit;1481ZIP_Lock(zip);1482n = ZIP_Read(zip, entry, pos, buf, count);1483msg = zip->msg;1484ZIP_Unlock(zip);1485if (n == -1) {1486if (msg == 0) {1487getErrorString(errno, tmpbuf, sizeof(tmpbuf));1488msg = tmpbuf;1489}1490jio_fprintf(stderr, "%s: %s\n", zip->name, msg);1491return JNI_FALSE;1492}1493buf += n;1494pos += n;1495}1496} else {1497/* Entry is compressed */1498int ok = InflateFully(zip, entry, buf, &msg);1499if (!ok) {1500if ((msg == NULL) || (*msg == 0)) {1501msg = zip->msg;1502}1503if (msg == 0) {1504getErrorString(errno, tmpbuf, sizeof(tmpbuf));1505msg = tmpbuf;1506}1507jio_fprintf(stderr, "%s: %s\n", zip->name, msg);1508return JNI_FALSE;1509}1510}15111512ZIP_FreeEntry(zip, entry);15131514return JNI_TRUE;1515}151615171518