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