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