File: | jdk/src/java.base/share/native/libzip/zip_util.c |
Warning: | line 1091, column 25 Value stored to 'sz' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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_MMAP1 |
56 | #include <sys/mman.h> |
57 | #endif |
58 | |
59 | #define MAXREFS0xFFFF 0xFFFF /* max number of open zip file references */ |
60 | |
61 | #define MCREATE()JVM_RawMonitorCreate() JVM_RawMonitorCreate() |
62 | #define MLOCK(lock)JVM_RawMonitorEnter(lock) JVM_RawMonitorEnter(lock) |
63 | #define MUNLOCK(lock)JVM_RawMonitorExit(lock) JVM_RawMonitorExit(lock) |
64 | #define MDESTROY(lock)JVM_RawMonitorDestroy(lock) JVM_RawMonitorDestroy(lock) |
65 | |
66 | #define CENSIZE(cen)(46 + ((((unsigned char *)(cen))[28]) | ((((unsigned char *)( cen))[28 +1]) << 8)) + ((((unsigned char *)(cen))[30]) | ((((unsigned char *)(cen))[30 +1]) << 8)) + ((((unsigned char *)(cen))[32]) | ((((unsigned char *)(cen))[32 +1]) << 8))) (CENHDR46 + CENNAM(cen)((((unsigned char *)(cen))[28]) | ((((unsigned char *)(cen))[ 28 +1]) << 8)) + CENEXT(cen)((((unsigned char *)(cen))[30]) | ((((unsigned char *)(cen))[ 30 +1]) << 8)) + CENCOM(cen)((((unsigned char *)(cen))[32]) | ((((unsigned char *)(cen))[ 32 +1]) << 8))) |
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_MAX4096 |
74 | #define PATH_MAX4096 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 ZFILEint |
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_RDWR02) ? (GENERIC_WRITE | GENERIC_READ) : |
108 | (flags & O_WRONLY01) ? 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_TRUNC01000) ? CREATE_ALWAYS : |
115 | (flags & O_CREAT0100) ? OPEN_ALWAYS : |
116 | OPEN_EXISTING; |
117 | const DWORD maybeWriteThrough = |
118 | (flags & (O_SYNC04010000 | O_DSYNC010000)) ? |
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((void*)0), /* Security attributes */ |
134 | disposition, /* creation disposition */ |
135 | flagsAndAttributes, /* flags and attributes */ |
136 | NULL((void*)0)); |
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((void*)0), 0); |
141 | if (wfname_len == 0) { |
142 | return (jlong)INVALID_HANDLE_VALUE; |
143 | } |
144 | if ((wfname = (WCHAR*)malloc(wfname_len * sizeof(WCHAR))) == NULL((void*)0)) { |
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((void*)0), /* Security attributes */ |
158 | disposition, /* creation disposition */ |
159 | flagsAndAttributes, /* flags and attributes */ |
160 | NULL((void*)0)); |
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(ZFILEint zfd) { |
176 | #ifdef WIN32 |
177 | CloseHandle((HANDLE) zfd); |
178 | #else |
179 | close(zfd); |
180 | #endif |
181 | } |
182 | |
183 | static int |
184 | ZFILE_read(ZFILEint zfd, char *buf, jint nbytes) { |
185 | #ifdef WIN32 |
186 | return (int) IO_ReadhandleRead(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_FALSE0; |
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(*__errno_location ()) = 0; |
204 | |
205 | if (inited) |
206 | return 0; |
207 | zfiles_lock = MCREATE()JVM_RawMonitorCreate(); |
208 | if (zfiles_lock == 0) { |
209 | return -1; |
210 | } |
211 | inited = JNI_TRUE1; |
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(ZFILEint 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(*__errno_location ()) == EINTR4) { |
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(ZFILEint zfd, void *buf, jlong len, jlong offset) |
249 | { |
250 | if (IO_Lseeklseek64(zfd, offset, SEEK_SET0) == -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((void*)0)) && |
266 | ((zip->name = strdup(name)) != NULL((void*)0)) && |
267 | ((zip->lock = MCREATE()JVM_RawMonitorCreate()) != NULL((void*)0))) { |
268 | zip->zfd = -1; |
269 | return zip; |
270 | } |
271 | |
272 | if (zip != NULL((void*)0)) { |
273 | free(zip->name); |
274 | free(zip); |
275 | } |
276 | return NULL((void*)0); |
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((void*)0)) MDESTROY(zip->lock)JVM_RawMonitorDestroy(zip->lock); |
288 | free(zip->name); |
289 | freeCEN(zip); |
290 | |
291 | #ifdef USE_MMAP1 |
292 | if (zip->usemmap) { |
293 | if (zip->maddr != NULL((void*)0)) |
294 | munmap((char *)zip->maddr, zip->mlen); |
295 | } else |
296 | #endif |
297 | { |
298 | free(zip->cencache.data); |
299 | } |
300 | if (zip->comment != NULL((void*)0)) |
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 + ENDHDR22; |
308 | |
309 | #define READBLOCKSZ128 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)((((((unsigned char *)(endbuf))[12]) | ((((unsigned char *)(endbuf ))[12 +1]) << 8)) | (((((unsigned char *)(endbuf))[12 + 2]) | ((((unsigned char *)(endbuf))[12 +2 +1]) << 8)) << 16)) &0xffffffffUL); |
319 | jlong locpos = cenpos - ENDOFF(endbuf)((((((unsigned char *)(endbuf))[16]) | ((((unsigned char *)(endbuf ))[16 +1]) << 8)) | (((((unsigned char *)(endbuf))[16 + 2]) | ((((unsigned char *)(endbuf))[16 +2 +1]) << 8)) << 16)) &0xffffffffUL); |
320 | char buf[4]; |
321 | return (cenpos >= 0 && |
322 | locpos >= 0 && |
323 | readFullyAt(zip->zfd, buf, sizeof(buf), cenpos) != -1 && |
324 | CENSIG_AT(buf)(((buf)[0] == 'P') & ((buf)[1] == 'K') & ((buf)[2] == 1) & ((buf)[3] == 2)) && |
325 | readFullyAt(zip->zfd, buf, sizeof(buf), locpos) != -1 && |
326 | LOCSIG_AT(buf)(((buf)[0] == 'P') & ((buf)[1] == 'K') & ((buf)[2] == 3) & ((buf)[3] == 4))); |
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[READBLOCKSZ128]; |
339 | jlong pos; |
340 | const jlong len = zip->len; |
341 | const ZFILEint zfd = zip->zfd; |
342 | const jlong minHDR = len - END_MAXLEN > 0 ? len - END_MAXLEN : 0; |
343 | const jlong minPos = minHDR - (sizeof(buf)-ENDHDR22); |
344 | jint clen; |
345 | |
346 | for (pos = len - sizeof(buf); pos >= minPos; pos -= (sizeof(buf)-ENDHDR22)) { |
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) - ENDHDR22; 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 + ENDHDR22 + ENDCOM(buf + i)((((unsigned char *)(buf + i))[20]) | ((((unsigned char *)(buf + i))[20 +1]) << 8)) == len) |
368 | || verifyEND(zip, pos + i, buf + i))) { |
369 | /* Found END header */ |
370 | memcpy(endbuf, buf + i, ENDHDR22); |
371 | |
372 | clen = ENDCOM(endbuf)((((unsigned char *)(endbuf))[20]) | ((((unsigned char *)(endbuf ))[20 +1]) << 8)); |
373 | if (clen != 0) { |
374 | zip->comment = malloc(clen + 1); |
375 | if (zip->comment == NULL((void*)0)) { |
376 | return -1; |
377 | } |
378 | if (readFullyAt(zfd, zip->comment, clen, pos + i + ENDHDR22) |
379 | == -1) { |
380 | free(zip->comment); |
381 | zip->comment = NULL((void*)0); |
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_LOCHDR20]; |
416 | jlong end64pos; |
417 | if (readFullyAt(zip->zfd, loc64, ZIP64_LOCHDR20, endpos - ZIP64_LOCHDR20) == -1) { |
418 | return -1; // end64 locator not found |
419 | } |
420 | end64pos = ZIP64_LOCOFF(loc64)(((jlong)((((((unsigned char *)(loc64))[8]) | ((((unsigned char *)(loc64))[8 +1]) << 8)) | (((((unsigned char *)(loc64 ))[8 +2]) | ((((unsigned char *)(loc64))[8 +2 +1]) << 8 )) << 16)) &0xffffffffUL)) | (((jlong)((((((unsigned char *)(loc64))[8 +4]) | ((((unsigned char *)(loc64))[8 +4 + 1]) << 8)) | (((((unsigned char *)(loc64))[8 +4 +2]) | ( (((unsigned char *)(loc64))[8 +4 +2 +1]) << 8)) << 16)) &0xffffffffUL)) << 32)); |
421 | if (readFullyAt(zip->zfd, end64buf, ZIP64_ENDHDR56, 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((void*)0)) return -1; |
490 | for (i = zip->metacount; i < new_metacount; i++) |
491 | zip->metanames[i] = NULL((void*)0); |
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((void*)0)) { |
506 | zip->metacount = INITIAL_META_COUNT; |
507 | zip->metanames = calloc(zip->metacount, sizeof(zip->metanames[0])); |
508 | if (zip->metanames == NULL((void*)0)) 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((void*)0)) 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((void*)0); |
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((void*)0); |
546 | free(zip->table); zip->table = NULL((void*)0); |
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 + CENHDR46 <= end - beg; i += CENSIZE(beg + i)(46 + ((((unsigned char *)(beg + i))[28]) | ((((unsigned char *)(beg + i))[28 +1]) << 8)) + ((((unsigned char *)(beg + i))[30]) | ((((unsigned char *)(beg + i))[30 +1]) << 8)) + ((((unsigned char *)(beg + i))[32]) | ((((unsigned char *)(beg + i))[32 +1]) << 8)))) |
561 | count++; |
562 | return count; |
563 | } |
564 | |
565 | #define ZIP_FORMAT_ERROR(message)if (1) { zip->msg = message; goto Catch; } else ((void)0) \ |
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((void*)0); |
582 | unsigned char *cenend; |
583 | unsigned char *cp; |
584 | #ifdef USE_MMAP1 |
585 | static jlong pagesize; |
586 | jlong offset; |
587 | #endif |
588 | unsigned char endbuf[ENDHDR22]; |
589 | jint endhdrlen = ENDHDR22; |
590 | jzcell *entries; |
591 | jint *table; |
592 | |
593 | /* Clear previous zip error */ |
594 | zip->msg = NULL((void*)0); |
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)((((((unsigned char *)(endbuf))[12]) | ((((unsigned char *)(endbuf ))[12 +1]) << 8)) | (((((unsigned char *)(endbuf))[12 + 2]) | ((((unsigned char *)(endbuf))[12 +2 +1]) << 8)) << 16)) &0xffffffffUL); |
604 | cenoff = ENDOFF(endbuf)((((((unsigned char *)(endbuf))[16]) | ((((unsigned char *)(endbuf ))[16 +1]) << 8)) | (((((unsigned char *)(endbuf))[16 + 2]) | ((((unsigned char *)(endbuf))[16 +2 +1]) << 8)) << 16)) &0xffffffffUL); |
605 | total = ENDTOT(endbuf)((((unsigned char *)(endbuf))[10]) | ((((unsigned char *)(endbuf ))[10 +1]) << 8)); |
606 | if (cenlen == ZIP64_MAGICVAL0xffffffffLL || cenoff == ZIP64_MAGICVAL0xffffffffLL || |
607 | total == ZIP64_MAGICCOUNT0xffff) { |
608 | unsigned char end64buf[ZIP64_ENDHDR56]; |
609 | if ((end64pos = findEND64(zip, end64buf, endpos)) != -1) { |
610 | cenlen = ZIP64_ENDSIZ(end64buf)(((jlong)((((((unsigned char *)(end64buf))[40]) | ((((unsigned char *)(end64buf))[40 +1]) << 8)) | (((((unsigned char *)(end64buf))[40 +2]) | ((((unsigned char *)(end64buf))[40 + 2 +1]) << 8)) << 16)) &0xffffffffUL)) | (((jlong )((((((unsigned char *)(end64buf))[40 +4]) | ((((unsigned char *)(end64buf))[40 +4 +1]) << 8)) | (((((unsigned char * )(end64buf))[40 +4 +2]) | ((((unsigned char *)(end64buf))[40 + 4 +2 +1]) << 8)) << 16)) &0xffffffffUL)) << 32)); |
611 | cenoff = ZIP64_ENDOFF(end64buf)(((jlong)((((((unsigned char *)(end64buf))[48]) | ((((unsigned char *)(end64buf))[48 +1]) << 8)) | (((((unsigned char *)(end64buf))[48 +2]) | ((((unsigned char *)(end64buf))[48 + 2 +1]) << 8)) << 16)) &0xffffffffUL)) | (((jlong )((((((unsigned char *)(end64buf))[48 +4]) | ((((unsigned char *)(end64buf))[48 +4 +1]) << 8)) | (((((unsigned char * )(end64buf))[48 +4 +2]) | ((((unsigned char *)(end64buf))[48 + 4 +2 +1]) << 8)) << 16)) &0xffffffffUL)) << 32)); |
612 | total = (jint)ZIP64_ENDTOT(end64buf)(((jlong)((((((unsigned char *)(end64buf))[32]) | ((((unsigned char *)(end64buf))[32 +1]) << 8)) | (((((unsigned char *)(end64buf))[32 +2]) | ((((unsigned char *)(end64buf))[32 + 2 +1]) << 8)) << 16)) &0xffffffffUL)) | (((jlong )((((((unsigned char *)(end64buf))[32 +4]) | ((((unsigned char *)(end64buf))[32 +4 +1]) << 8)) | (((((unsigned char * )(end64buf))[32 +4 +2]) | ((((unsigned char *)(end64buf))[32 + 4 +2 +1]) << 8)) << 16)) &0xffffffffUL)) << 32)); |
613 | endpos = end64pos; |
614 | endhdrlen = ZIP64_ENDHDR56; |
615 | } |
616 | } |
617 | |
618 | if (cenlen > endpos) { |
619 | ZIP_FORMAT_ERROR("invalid END header (bad central directory size)")if (1) { zip->msg = "invalid END header (bad central directory size)" ; goto Catch; } else ((void)0); |
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)")if (1) { zip->msg = "invalid END header (bad central directory offset)" ; goto Catch; } else ((void)0); |
628 | } |
629 | #ifdef USE_MMAP1 |
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_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_READ0x1, MAP_SHARED0x01, zip->zfd, (off64_t) offset); |
660 | zip->maddr = (mappedAddr == (void*) MAP_FAILED((void *) -1)) ? NULL((void*)0) : |
661 | (unsigned char*)mappedAddr; |
662 | |
663 | if (zip->maddr == NULL((void*)0)) { |
664 | jio_fprintf(stderrstderr, "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((void*)0) || |
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((void*)0) && total != 0) || table == NULL((void*)0)) goto Catch; |
698 | for (j = 0; j < tablelen; j++) |
699 | table[j] = ZIP_ENDCHAIN((jint)-1); |
700 | |
701 | /* Iterate through the entries in the central directory */ |
702 | for (i = 0, cp = cenbuf; cp <= cenend - CENHDR46; i++, cp += CENSIZE(cp)(46 + ((((unsigned char *)(cp))[28]) | ((((unsigned char *)(cp ))[28 +1]) << 8)) + ((((unsigned char *)(cp))[30]) | (( ((unsigned char *)(cp))[30 +1]) << 8)) + ((((unsigned char *)(cp))[32]) | ((((unsigned char *)(cp))[32 +1]) << 8) ))) { |
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)((((unsigned char *)(cp))[10]) | ((((unsigned char *)(cp))[10 +1]) << 8)); |
716 | nlen = CENNAM(cp)((((unsigned char *)(cp))[28]) | ((((unsigned char *)(cp))[28 +1]) << 8)); |
717 | |
718 | if (!CENSIG_AT(cp)(((cp)[0] == 'P') & ((cp)[1] == 'K') & ((cp)[2] == 1) & ((cp)[3] == 2))) { |
719 | ZIP_FORMAT_ERROR("invalid CEN header (bad signature)")if (1) { zip->msg = "invalid CEN header (bad signature)"; goto Catch; } else ((void)0); |
720 | } |
721 | if (CENFLG(cp)((((unsigned char *)(cp))[8]) | ((((unsigned char *)(cp))[8 + 1]) << 8)) & 1) { |
722 | ZIP_FORMAT_ERROR("invalid CEN header (encrypted entry)")if (1) { zip->msg = "invalid CEN header (encrypted entry)" ; goto Catch; } else ((void)0); |
723 | } |
724 | if (method != STORED0 && method != DEFLATED8) { |
725 | ZIP_FORMAT_ERROR("invalid CEN header (bad compression method)")if (1) { zip->msg = "invalid CEN header (bad compression method)" ; goto Catch; } else ((void)0); |
726 | } |
727 | if (cp + CENHDR46 + nlen > cenend) { |
728 | ZIP_FORMAT_ERROR("invalid CEN header (bad header size)")if (1) { zip->msg = "invalid CEN header (bad header size)" ; goto Catch; } else ((void)0); |
729 | } |
730 | /* if the entry is metadata add it to our metadata names */ |
731 | if (isMetaName((char *)cp+CENHDR46, nlen)) |
732 | if (addMetaName(zip, (char *)cp+CENHDR46, 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+CENHDR46, 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)")if (1) { zip->msg = "invalid CEN header (bad header size)" ; goto Catch; } else ((void)0); |
746 | } |
747 | zip->total = i; |
748 | goto Finally; |
749 | |
750 | Catch: |
751 | freeCEN(zip); |
752 | cenpos = -1; |
753 | |
754 | Finally: |
755 | #ifdef USE_MMAP1 |
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((void*)0); |
773 | |
774 | /* Clear zip error message */ |
775 | if (pmsg != NULL((void*)0)) { |
776 | *pmsg = NULL((void*)0); |
777 | } |
778 | |
779 | zip = ZIP_Get_From_Cache(name, pmsg, lastModified); |
780 | |
781 | if (zip == NULL((void*)0) && pmsg != NULL((void*)0) && *pmsg == NULL((void*)0)) { |
782 | ZFILEint 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_MAX4096]; |
799 | jzfile *zip; |
800 | |
801 | if (InitializeZip()) { |
802 | return NULL((void*)0); |
803 | } |
804 | |
805 | /* Clear zip error message */ |
806 | if (pmsg != 0) { |
807 | *pmsg = NULL((void*)0); |
808 | } |
809 | |
810 | if (strlen(name) >= PATH_MAX4096) { |
811 | if (pmsg) { |
812 | *pmsg = strdup("zip file name too long"); |
813 | } |
814 | return NULL((void*)0); |
815 | } |
816 | strcpy(buf, name); |
817 | JVM_NativePath(buf); |
818 | name = buf; |
819 | |
820 | MLOCK(zfiles_lock)JVM_RawMonitorEnter(zfiles_lock); |
821 | for (zip = zfiles; zip != NULL((void*)0); zip = zip->next) { |
822 | if (strcmp(name, zip->name) == 0 |
823 | && (zip->lastModified == lastModified || zip->lastModified == 0) |
824 | && zip->refs < MAXREFS0xFFFF) { |
825 | zip->refs++; |
826 | break; |
827 | } |
828 | } |
829 | MUNLOCK(zfiles_lock)JVM_RawMonitorExit(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, ZFILEint zfd, char **pmsg, jlong lastModified) |
843 | { |
844 | return ZIP_Put_In_Cache0(name, zfd, pmsg, lastModified, JNI_TRUE1); |
845 | } |
846 | |
847 | jzfile * |
848 | ZIP_Put_In_Cache0(const char *name, ZFILEint 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((void*)0)) { |
856 | return NULL((void*)0); |
857 | } |
858 | |
859 | #ifdef USE_MMAP1 |
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((void*)0); |
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)(((errbuf)[0] == 'P') & ((errbuf)[1] == 'K') & ((errbuf )[2] == 3) & ((errbuf)[3] == 4)) ? JNI_TRUE1 : JNI_FALSE0; |
875 | } |
876 | |
877 | len = zip->len = IO_Lseeklseek64(zfd, 0, SEEK_END2); |
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((void*)0); |
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((void*)0)) |
898 | *pmsg = strdup(zip->msg); |
899 | } |
900 | freeZip(zip); |
901 | return NULL((void*)0); |
902 | } |
903 | MLOCK(zfiles_lock)JVM_RawMonitorEnter(zfiles_lock); |
904 | zip->next = zfiles; |
905 | zfiles = zip; |
906 | MUNLOCK(zfiles_lock)JVM_RawMonitorExit(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__attribute__((visibility("default"))) jzfile * |
918 | ZIP_Open(const char *name, char **pmsg) |
919 | { |
920 | jzfile *file = ZIP_Open_Generic(name, pmsg, O_RDONLY00, 0); |
921 | if (file == NULL((void*)0) && pmsg != NULL((void*)0) && *pmsg != NULL((void*)0)) { |
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__attribute__((visibility("default"))) void |
932 | ZIP_Close(jzfile *zip) |
933 | { |
934 | MLOCK(zfiles_lock)JVM_RawMonitorEnter(zfiles_lock); |
935 | if (--zip->refs > 0) { |
936 | /* Still more references so just return */ |
937 | MUNLOCK(zfiles_lock)JVM_RawMonitorExit(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)JVM_RawMonitorExit(zfiles_lock); |
953 | freeZip(zip); |
954 | return; |
955 | } |
956 | |
957 | /* Empirically, most CEN headers are smaller than this. */ |
958 | #define AMPLE_CEN_HEADER_SIZE160 160 |
959 | |
960 | /* A good buffer size when we want to read CEN headers sequentially. */ |
961 | #define CENCACHE_PAGESIZE8192 8192 |
962 | |
963 | static char * |
964 | readCENHeader(jzfile *zip, jlong cenpos, jint bufsize) |
965 | { |
966 | jint censize; |
967 | ZFILEint zfd = zip->zfd; |
968 | char *cen; |
969 | if (bufsize > zip->len - cenpos) |
970 | bufsize = (jint)(zip->len - cenpos); |
971 | if ((cen = malloc(bufsize)) == NULL((void*)0)) goto Catch; |
972 | if (readFullyAt(zfd, cen, bufsize, cenpos) == -1) goto Catch; |
973 | censize = CENSIZE(cen)(46 + ((((unsigned char *)(cen))[28]) | ((((unsigned char *)( cen))[28 +1]) << 8)) + ((((unsigned char *)(cen))[30]) | ((((unsigned char *)(cen))[30 +1]) << 8)) + ((((unsigned char *)(cen))[32]) | ((((unsigned char *)(cen))[32 +1]) << 8))); |
974 | if (censize <= bufsize) return cen; |
975 | if ((cen = realloc(cen, censize)) == NULL((void*)0)) 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((void*)0); |
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((void*)0) |
990 | && (cenpos >= cache->pos) |
991 | && (cenpos + CENHDR46 <= cache->pos + CENCACHE_PAGESIZE8192)) |
992 | { |
993 | cen = cache->data + cenpos - cache->pos; |
994 | if (cenpos + CENSIZE(cen)(46 + ((((unsigned char *)(cen))[28]) | ((((unsigned char *)( cen))[28 +1]) << 8)) + ((((unsigned char *)(cen))[30]) | ((((unsigned char *)(cen))[30 +1]) << 8)) + ((((unsigned char *)(cen))[32]) | ((((unsigned char *)(cen))[32 +1]) << 8))) <= cache->pos + CENCACHE_PAGESIZE8192) |
995 | /* A cache hit */ |
996 | return cen; |
997 | } |
998 | |
999 | if ((cen = readCENHeader(zip, cenpos, CENCACHE_PAGESIZE8192)) == NULL((void*)0)) |
1000 | return NULL((void*)0); |
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((void*)0)) return NULL((void*)0); |
1025 | ze->name = NULL((void*)0); |
1026 | ze->extra = NULL((void*)0); |
1027 | ze->comment = NULL((void*)0); |
1028 | |
1029 | #ifdef USE_MMAP1 |
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_SIZE160); |
1037 | else |
1038 | cen = sequentialAccessReadCENHeader(zip, zc->cenpos); |
1039 | if (cen == NULL((void*)0)) goto Catch; |
1040 | } |
1041 | |
1042 | nlen = CENNAM(cen)((((unsigned char *)(cen))[28]) | ((((unsigned char *)(cen))[ 28 +1]) << 8)); |
1043 | elen = CENEXT(cen)((((unsigned char *)(cen))[30]) | ((((unsigned char *)(cen))[ 30 +1]) << 8)); |
1044 | clen = CENCOM(cen)((((unsigned char *)(cen))[32]) | ((((unsigned char *)(cen))[ 32 +1]) << 8)); |
1045 | ze->time = CENTIM(cen)((((((unsigned char *)(cen))[12]) | ((((unsigned char *)(cen) )[12 +1]) << 8)) | (((((unsigned char *)(cen))[12 +2]) | ((((unsigned char *)(cen))[12 +2 +1]) << 8)) << 16 )) &0xffffffffUL); |
1046 | ze->size = CENLEN(cen)((((((unsigned char *)(cen))[24]) | ((((unsigned char *)(cen) )[24 +1]) << 8)) | (((((unsigned char *)(cen))[24 +2]) | ((((unsigned char *)(cen))[24 +2 +1]) << 8)) << 16 )) &0xffffffffUL); |
1047 | ze->csize = (CENHOW(cen)((((unsigned char *)(cen))[10]) | ((((unsigned char *)(cen))[ 10 +1]) << 8)) == STORED0) ? 0 : CENSIZ(cen)((((((unsigned char *)(cen))[20]) | ((((unsigned char *)(cen) )[20 +1]) << 8)) | (((((unsigned char *)(cen))[20 +2]) | ((((unsigned char *)(cen))[20 +2 +1]) << 8)) << 16 )) &0xffffffffUL); |
1048 | ze->crc = CENCRC(cen)((((((unsigned char *)(cen))[16]) | ((((unsigned char *)(cen) )[16 +1]) << 8)) | (((((unsigned char *)(cen))[16 +2]) | ((((unsigned char *)(cen))[16 +2 +1]) << 8)) << 16 )) &0xffffffffUL); |
1049 | locoff = CENOFF(cen)((((((unsigned char *)(cen))[42]) | ((((unsigned char *)(cen) )[42 +1]) << 8)) | (((((unsigned char *)(cen))[42 +2]) | ((((unsigned char *)(cen))[42 +2 +1]) << 8)) << 16 )) &0xffffffffUL); |
1050 | ze->pos = -(zip->locpos + locoff); |
1051 | ze->flag = CENFLG(cen)((((unsigned char *)(cen))[8]) | ((((unsigned char *)(cen))[8 +1]) << 8)); |
1052 | |
1053 | if ((ze->name = malloc(nlen + 1)) == NULL((void*)0)) goto Catch; |
1054 | memcpy(ze->name, cen + CENHDR46, nlen); |
1055 | ze->name[nlen] = '\0'; |
1056 | ze->nlen = nlen; |
1057 | if (elen > 0) { |
1058 | char *extra = cen + CENHDR46 + nlen; |
1059 | |
1060 | /* This entry has "extra" data */ |
1061 | if ((ze->extra = malloc(elen + 2)) == NULL((void*)0)) 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_MAGICVAL0xffffffffLL || ze->size == ZIP64_MAGICVAL0xffffffffLL || |
1066 | locoff == ZIP64_MAGICVAL0xffffffffLL) { |
1067 | jint off = 0; |
1068 | while ((off + 4) < elen) { // spec: HeaderID+DataSize+Data |
1069 | jint sz = SH(extra, off + 2)((((unsigned char *)(extra))[off + 2]) | ((((unsigned char *) (extra))[off + 2 +1]) << 8)); |
1070 | if (SH(extra, off)((((unsigned char *)(extra))[off]) | ((((unsigned char *)(extra ))[off+1]) << 8)) == ZIP64_EXTID1) { |
1071 | off += 4; |
1072 | if (ze->size == ZIP64_MAGICVAL0xffffffffLL) { |
1073 | // if invalid zip64 extra fields, just skip |
1074 | if (sz < 8 || (off + 8) > elen) |
1075 | break; |
1076 | ze->size = LL(extra, off)(((jlong)((((((unsigned char *)(extra))[off]) | ((((unsigned char *)(extra))[off+1]) << 8)) | (((((unsigned char *)(extra ))[off+2]) | ((((unsigned char *)(extra))[off+2 +1]) << 8)) << 16)) &0xffffffffUL)) | (((jlong)((((((unsigned char *)(extra))[off+4]) | ((((unsigned char *)(extra))[off+4 +1]) << 8)) | (((((unsigned char *)(extra))[off+4 +2]) | ((((unsigned char *)(extra))[off+4 +2 +1]) << 8)) << 16)) &0xffffffffUL)) << 32)); |
1077 | sz -= 8; |
1078 | off += 8; |
1079 | } |
1080 | if (ze->csize == ZIP64_MAGICVAL0xffffffffLL) { |
1081 | if (sz < 8 || (off + 8) > elen) |
1082 | break; |
1083 | ze->csize = LL(extra, off)(((jlong)((((((unsigned char *)(extra))[off]) | ((((unsigned char *)(extra))[off+1]) << 8)) | (((((unsigned char *)(extra ))[off+2]) | ((((unsigned char *)(extra))[off+2 +1]) << 8)) << 16)) &0xffffffffUL)) | (((jlong)((((((unsigned char *)(extra))[off+4]) | ((((unsigned char *)(extra))[off+4 +1]) << 8)) | (((((unsigned char *)(extra))[off+4 +2]) | ((((unsigned char *)(extra))[off+4 +2 +1]) << 8)) << 16)) &0xffffffffUL)) << 32)); |
1084 | sz -= 8; |
1085 | off += 8; |
1086 | } |
1087 | if (locoff == ZIP64_MAGICVAL0xffffffffLL) { |
1088 | if (sz < 8 || (off + 8) > elen) |
1089 | break; |
1090 | ze->pos = -(zip->locpos + LL(extra, off)(((jlong)((((((unsigned char *)(extra))[off]) | ((((unsigned char *)(extra))[off+1]) << 8)) | (((((unsigned char *)(extra ))[off+2]) | ((((unsigned char *)(extra))[off+2 +1]) << 8)) << 16)) &0xffffffffUL)) | (((jlong)((((((unsigned char *)(extra))[off+4]) | ((((unsigned char *)(extra))[off+4 +1]) << 8)) | (((((unsigned char *)(extra))[off+4 +2]) | ((((unsigned char *)(extra))[off+4 +2 +1]) << 8)) << 16)) &0xffffffffUL)) << 32))); |
1091 | sz -= 8; |
Value stored to 'sz' is never read | |
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((void*)0)) goto Catch; |
1104 | memcpy(ze->comment, cen + CENHDR46 + 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((void*)0); |
1115 | |
1116 | Finally: |
1117 | #ifdef USE_MMAP1 |
1118 | if (!zip->usemmap) |
1119 | #endif |
1120 | if (cen != NULL((void*)0) && 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((void*)0)) { |
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_FALSE0); |
1156 | } |
1157 | return ZIP_GetEntry2(zip, name, ulen, JNI_TRUE1); |
1158 | } |
1159 | |
1160 | jboolean equals(char* name1, int len1, char* name2, int len2) { |
1161 | if (len1 != len2) { |
1162 | return JNI_FALSE0; |
1163 | } |
1164 | while (len1-- > 0) { |
1165 | if (*name1++ != *name2++) { |
1166 | return JNI_FALSE0; |
1167 | } |
1168 | } |
1169 | return JNI_TRUE1; |
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((jint)-1)) { |
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_FALSE0; |
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__attribute__((visibility("default"))) 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)JVM_RawMonitorEnter(zip->lock); |
1294 | } |
1295 | |
1296 | /* |
1297 | * Unlocks the specified zip file. |
1298 | */ |
1299 | void |
1300 | ZIP_Unlock(jzfile *zip) |
1301 | { |
1302 | MUNLOCK(zip->lock)JVM_RawMonitorExit(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[LOCHDR30]; |
1324 | if (readFullyAt(zip->zfd, loc, LOCHDR30, -(entry->pos)) == -1) { |
1325 | zip->msg = "error reading zip file"; |
1326 | return -1; |
1327 | } |
1328 | if (!LOCSIG_AT(loc)(((loc)[0] == 'P') & ((loc)[1] == 'K') & ((loc)[2] == 3) & ((loc)[3] == 4))) { |
1329 | zip->msg = "invalid LOC header (bad signature)"; |
1330 | return -1; |
1331 | } |
1332 | entry->pos = (- entry->pos) + LOCHDR30 + LOCNAM(loc)((((unsigned char *)(loc))[26]) | ((((unsigned char *)(loc))[ 26 +1]) << 8)) + LOCEXT(loc)((((unsigned char *)(loc))[28]) | ((((unsigned char *)(loc))[ 28 +1]) << 8)); |
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((void*)0); |
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_SIZE4096 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_SIZE4096]; |
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_FALSE0; |
1423 | } |
1424 | |
1425 | memset(&strm, 0, sizeof(z_stream)); |
1426 | if (inflateInit2(&strm, -MAX_WBITS)inflateInit2_((&strm), (-15), "1.2.11", (int)sizeof(z_stream )) != Z_OK0) { |
1427 | *msg = strm.msg; |
1428 | return JNI_FALSE0; |
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_FALSE0; |
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_FLUSH1)) { |
1452 | case Z_OK0: |
1453 | break; |
1454 | case Z_STREAM_END1: |
1455 | if (count != 0 || strm.total_out != (uInt)entry->size) { |
1456 | *msg = "inflateFully: Unexpected end of stream"; |
1457 | inflateEnd(&strm); |
1458 | return JNI_FALSE0; |
1459 | } |
1460 | break; |
1461 | default: |
1462 | break; |
1463 | } |
1464 | } while (strm.avail_in > 0); |
1465 | } |
1466 | |
1467 | inflateEnd(&strm); |
1468 | return JNI_TRUE1; |
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__attribute__((visibility("default"))) 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__attribute__((visibility("default"))) 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(stderrstderr, "jzentry was invalid"); |
1500 | return JNI_FALSE0; |
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(*__errno_location ()), tmpbuf, sizeof(tmpbuf)); |
1522 | msg = tmpbuf; |
1523 | } |
1524 | jio_fprintf(stderrstderr, "%s: %s\n", zip->name, msg); |
1525 | return JNI_FALSE0; |
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((void*)0)) || (*msg == 0)) { |
1535 | msg = zip->msg; |
1536 | } |
1537 | if (msg == 0) { |
1538 | getErrorString(errno(*__errno_location ()), tmpbuf, sizeof(tmpbuf)); |
1539 | msg = tmpbuf; |
1540 | } |
1541 | jio_fprintf(stderrstderr, "%s: %s\n", zip->name, msg); |
1542 | return JNI_FALSE0; |
1543 | } |
1544 | } |
1545 | |
1546 | ZIP_FreeEntry(zip, entry); |
1547 | |
1548 | return JNI_TRUE1; |
1549 | } |
1550 | |
1551 | JNIEXPORT__attribute__((visibility("default"))) 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)inflateInit2_((&strm), (15), "1.2.11", (int)sizeof(z_stream )) != Z_OK0) { |
1561 | *pmsg = strm.msg; |
1562 | return JNI_FALSE0; |
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_FLUSH1)) { |
1572 | case Z_OK0: |
1573 | break; |
1574 | case Z_STREAM_END1: |
1575 | if (strm.total_out != (uInt)outLen) { |
1576 | *pmsg = "INFLATER_inflateFully: Unexpected end of stream"; |
1577 | inflateEnd(&strm); |
1578 | return JNI_FALSE0; |
1579 | } |
1580 | break; |
1581 | case Z_DATA_ERROR(-3): |
1582 | *pmsg = "INFLATER_inflateFully: Compressed data corrupted"; |
1583 | inflateEnd(&strm); |
1584 | return JNI_FALSE0; |
1585 | case Z_MEM_ERROR(-4): |
1586 | *pmsg = "INFLATER_inflateFully: out of memory"; |
1587 | inflateEnd(&strm); |
1588 | return JNI_FALSE0; |
1589 | default: |
1590 | *pmsg = "INFLATER_inflateFully: internal error"; |
1591 | inflateEnd(&strm); |
1592 | return JNI_FALSE0; |
1593 | } |
1594 | } while (strm.avail_in > 0); |
1595 | |
1596 | inflateEnd(&strm); |
1597 | return JNI_TRUE1; |
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((void*)0); |
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,deflateInit2_((strm),(level >= 0 && level <= 9 ? level : (-1)),(8),(31),(8), (0), "1.2.11", (int)sizeof(z_stream )) |
1629 | Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY)deflateInit2_((strm),(level >= 0 && level <= 9 ? level : (-1)),(8),(31),(8), (0), "1.2.11", (int)sizeof(z_stream )); |
1630 | if (err == Z_MEM_ERROR(-4)) { |
1631 | return "Out of memory in deflateInit2"; |
1632 | } |
1633 | |
1634 | if (err != Z_OK0) { |
1635 | return "Internal error in deflateInit2"; |
1636 | } |
1637 | |
1638 | return NULL((void*)0); |
1639 | } |
1640 | |
1641 | JNIEXPORT__attribute__((visibility("default"))) 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((void*)0)) { |
1655 | *outLen = (size_t) deflateBound(&strm, (uLong) inLen); |
1656 | deflateEnd(&strm); |
1657 | } |
1658 | |
1659 | return errorMsg; |
1660 | } |
1661 | |
1662 | JNIEXPORT__attribute__((visibility("default"))) 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((void*)0)) { |
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((void*)0)) { |
1685 | memset(&hdr, 0, sizeof(hdr)); |
1686 | hdr.comment = (Bytef*) comment; |
1687 | deflateSetHeader(&strm, &hdr); |
1688 | } |
1689 | |
1690 | err = deflate(&strm, Z_FINISH4); |
1691 | |
1692 | if (err == Z_OK0 || err == Z_BUF_ERROR(-5)) { |
1693 | *pmsg = "Buffer too small"; |
1694 | } else if (err != Z_STREAM_END1) { |
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 | } |