Bug Summary

File:jdk/src/java.base/share/native/libjli/parse_manifest.c
Warning:line 704, column 10
Although the value stored to 'rc' is used in the enclosing expression, the value is never actually read from 'rc'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name parse_manifest.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mthread-model posix -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-10/lib/clang/10.0.0 -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/modules_include/java.base -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/modules_include/java.base/linux -I /home/daniel/Projects/java/jdk/src/java.base/share/native/libjava -I /home/daniel/Projects/java/jdk/src/java.base/unix/native/libjava -I /home/daniel/Projects/java/jdk/src/hotspot/share/include -I /home/daniel/Projects/java/jdk/src/hotspot/os/posix/include -D LIBC=gnu -D _GNU_SOURCE -D _REENTRANT -D _LARGEFILE64_SOURCE -D LINUX -D DEBUG -D _LITTLE_ENDIAN -D ARCH="amd64" -D amd64 -D _LP64=1 -I /home/daniel/Projects/java/jdk/src/java.base/unix/native/libjli -I /home/daniel/Projects/java/jdk/src/java.base/share/native/libjli -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/headers/java.base -D _FORTIFY_SOURCE=2 -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-10/lib/clang/10.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-unused -Wno-unused-function -Wno-implicit-fallthrough -std=c99 -fdebug-compilation-dir /home/daniel/Projects/java/jdk/make -ferror-limit 19 -fmessage-length 0 -fvisibility hidden -stack-protector 1 -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o /home/daniel/Projects/java/scan/2021-12-21-193737-8510-1 -x c /home/daniel/Projects/java/jdk/src/java.base/share/native/libjli/parse_manifest.c
1/*
2 * Copyright (c) 2003, 2019, 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#include <sys/types.h>
27#include <sys/stat.h>
28#include <fcntl.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include "jni.h"
33#include "jli_util.h"
34
35#include <zlib.h>
36#include "manifest_info.h"
37
38static char *manifest;
39
40static const char *manifest_name = "META-INF/MANIFEST.MF";
41
42/*
43 * Inflate the manifest file (or any file for that matter).
44 *
45 * fd: File descriptor of the jar file.
46 * entry: Contains the information necessary to perform the inflation
47 * (the compressed and uncompressed sizes and the offset in
48 * the file where the compressed data is located).
49 * size_out: Returns the size of the inflated file.
50 *
51 * Upon success, it returns a pointer to a NUL-terminated malloc'd buffer
52 * containing the inflated manifest file. When the caller is done with it,
53 * this buffer should be released by a call to free(). Upon failure,
54 * returns NULL.
55 */
56static char *
57inflate_file(int fd, zentry *entry, int *size_out)
58{
59 char *in;
60 char *out;
61 z_stream zs;
62
63 if (entry->csize == (size_t) -1 || entry->isize == (size_t) -1 )
64 return (NULL((void*)0));
65 if (JLI_Lseeklseek64(fd, entry->offset, SEEK_SET0) < (jlong)0)
66 return (NULL((void*)0));
67 if ((in = malloc(entry->csize + 1)) == NULL((void*)0))
68 return (NULL((void*)0));
69 if ((size_t)(read(fd, in, (unsigned int)entry->csize)) != entry->csize) {
70 free(in);
71 return (NULL((void*)0));
72 }
73 if (entry->how == STORED0) {
74 *(char *)((size_t)in + entry->csize) = '\0';
75 if (size_out) {
76 *size_out = (int)entry->csize;
77 }
78 return (in);
79 } else if (entry->how == DEFLATED8) {
80 zs.zalloc = (alloc_func)Z_NULL0;
81 zs.zfree = (free_func)Z_NULL0;
82 zs.opaque = (voidpf)Z_NULL0;
83 zs.next_in = (Byte*)in;
84 zs.avail_in = (uInt)entry->csize;
85 if (inflateInit2(&zs, -MAX_WBITS)inflateInit2_((&zs), (-15), "1.2.11", (int)sizeof(z_stream
))
< 0) {
86 free(in);
87 return (NULL((void*)0));
88 }
89 if ((out = malloc(entry->isize + 1)) == NULL((void*)0)) {
90 free(in);
91 return (NULL((void*)0));
92 }
93 zs.next_out = (Byte*)out;
94 zs.avail_out = (uInt)entry->isize;
95 if (inflate(&zs, Z_PARTIAL_FLUSH1) < 0) {
96 free(in);
97 free(out);
98 return (NULL((void*)0));
99 }
100 *(char *)((size_t)out + entry->isize) = '\0';
101 free(in);
102 if (inflateEnd(&zs) < 0) {
103 free(out);
104 return (NULL((void*)0));
105 }
106 if (size_out) {
107 *size_out = (int)entry->isize;
108 }
109 return (out);
110 }
111 free(in);
112 return (NULL((void*)0));
113}
114
115/*
116 * Implementation notes:
117 *
118 * This is a zip format reader for seekable files, that tolerates
119 * leading and trailing garbage, and tolerates having had internal
120 * offsets adjusted for leading garbage (as with Info-Zip's zip -A).
121 *
122 * We find the end header by scanning backwards from the end of the
123 * file for the end signature. This may fail in the presence of
124 * trailing garbage or a ZIP file comment that contains binary data.
125 * Similarly, the ZIP64 end header may need to be located by scanning
126 * backwards from the end header. It may be misidentified, but this
127 * is very unlikely to happen in practice without adversarial input.
128 *
129 * The zip file format is documented at:
130 * https://www.pkware.com/documents/casestudies/APPNOTE.TXT
131 *
132 * TODO: more informative error messages
133 */
134
135/** Reads count bytes from fd at position pos into given buffer. */
136static jboolean
137readAt(int fd, jlong pos, unsigned int count, void *buf) {
138 return (pos >= 0
139 && JLI_Lseeklseek64(fd, pos, SEEK_SET0) == pos
140 && read(fd, buf, count) == (jlong) count);
141}
142
143
144/*
145 * Tells whether given header values (obtained from either ZIP64 or
146 * non-ZIP64 header) appear to be correct, by checking the first LOC
147 * and CEN headers.
148 */
149static jboolean
150is_valid_end_header(int fd, jlong endpos,
151 jlong censiz, jlong cenoff, jlong entries) {
152 Byte cenhdr[CENHDR46];
153 Byte lochdr[LOCHDR30];
154 // Expected offset of the first central directory header
155 jlong censtart = endpos - censiz;
156 // Expected position within the file that offsets are relative to
157 jlong base_offset = endpos - (censiz + cenoff);
158 return censtart >= 0 && cenoff >= 0 &&
159 (censiz == 0 ||
160 // Validate first CEN and LOC header signatures.
161 // Central directory must come directly before the end header.
162 (readAt(fd, censtart, CENHDR46, cenhdr)
163 && CENSIG_AT(cenhdr)(((cenhdr)[0] == 'P') & ((cenhdr)[1] == 'K') & ((cenhdr
)[2] == 1) & ((cenhdr)[3] == 2))
164 && readAt(fd, base_offset + CENOFF(cenhdr)((((((unsigned char *)(cenhdr))[42]) | ((((unsigned char *)(cenhdr
))[42 +1]) << 8)) | (((((unsigned char *)(cenhdr))[42 +
2]) | ((((unsigned char *)(cenhdr))[42 +2 +1]) << 8)) <<
16)) &0xffffffffUL)
, LOCHDR30, lochdr)
165 && LOCSIG_AT(lochdr)(((lochdr)[0] == 'P') & ((lochdr)[1] == 'K') & ((lochdr
)[2] == 3) & ((lochdr)[3] == 4))
166 && CENNAM(cenhdr)((((unsigned char *)(cenhdr))[28]) | ((((unsigned char *)(cenhdr
))[28 +1]) << 8))
== LOCNAM(lochdr)((((unsigned char *)(lochdr))[26]) | ((((unsigned char *)(lochdr
))[26 +1]) << 8))
));
167}
168
169/*
170 * Tells whether p appears to be pointing at a valid ZIP64 end header.
171 * Values censiz, cenoff, and entries are the corresponding values
172 * from the non-ZIP64 end header. We perform extra checks to avoid
173 * misidentifying data from the last entry as a ZIP64 end header.
174 */
175static jboolean
176is_zip64_endhdr(int fd, const Byte *p, jlong end64pos,
177 jlong censiz, jlong cenoff, jlong entries) {
178 if (ZIP64_ENDSIG_AT(p)(((p)[0] == 'P') & ((p)[1] == 'K') & ((p)[2] == 6) &
((p)[3] == 6))
) {
179 jlong censiz64 = ZIP64_ENDSIZ(p)(((jlong)((((((unsigned char *)(p))[40]) | ((((unsigned char *
)(p))[40 +1]) << 8)) | (((((unsigned char *)(p))[40 +2]
) | ((((unsigned char *)(p))[40 +2 +1]) << 8)) <<
16)) &0xffffffffUL)) | (((jlong)((((((unsigned char *)(p
))[40 +4]) | ((((unsigned char *)(p))[40 +4 +1]) << 8))
| (((((unsigned char *)(p))[40 +4 +2]) | ((((unsigned char *
)(p))[40 +4 +2 +1]) << 8)) << 16)) &0xffffffffUL
)) << 32))
;
180 jlong cenoff64 = ZIP64_ENDOFF(p)(((jlong)((((((unsigned char *)(p))[48]) | ((((unsigned char *
)(p))[48 +1]) << 8)) | (((((unsigned char *)(p))[48 +2]
) | ((((unsigned char *)(p))[48 +2 +1]) << 8)) <<
16)) &0xffffffffUL)) | (((jlong)((((((unsigned char *)(p
))[48 +4]) | ((((unsigned char *)(p))[48 +4 +1]) << 8))
| (((((unsigned char *)(p))[48 +4 +2]) | ((((unsigned char *
)(p))[48 +4 +2 +1]) << 8)) << 16)) &0xffffffffUL
)) << 32))
;
181 jlong entries64 = ZIP64_ENDTOT(p)(((jlong)((((((unsigned char *)(p))[32]) | ((((unsigned char *
)(p))[32 +1]) << 8)) | (((((unsigned char *)(p))[32 +2]
) | ((((unsigned char *)(p))[32 +2 +1]) << 8)) <<
16)) &0xffffffffUL)) | (((jlong)((((((unsigned char *)(p
))[32 +4]) | ((((unsigned char *)(p))[32 +4 +1]) << 8))
| (((((unsigned char *)(p))[32 +4 +2]) | ((((unsigned char *
)(p))[32 +4 +2 +1]) << 8)) << 16)) &0xffffffffUL
)) << 32))
;
182 return (censiz64 == censiz || censiz == ZIP64_MAGICVAL0xffffffffLL)
183 && (cenoff64 == cenoff || cenoff == ZIP64_MAGICVAL0xffffffffLL)
184 && (entries64 == entries || entries == ZIP64_MAGICCOUNT0xffff)
185 && is_valid_end_header(fd, end64pos, censiz64, cenoff64, entries64);
186 }
187 return JNI_FALSE0;
188}
189
190/*
191 * Given a non-ZIP64 end header located at endhdr and endpos, look for
192 * an adjacent ZIP64 end header, finding the base offset and censtart
193 * from the ZIP64 header if available, else from the non-ZIP64 header.
194 * @return 0 if successful, -1 in case of failure
195 */
196static int
197find_positions64(int fd, const Byte * const endhdr, const jlong endpos,
198 jlong* base_offset, jlong* censtart)
199{
200 jlong censiz = ENDSIZ(endhdr)((((((unsigned char *)(endhdr))[12]) | ((((unsigned char *)(endhdr
))[12 +1]) << 8)) | (((((unsigned char *)(endhdr))[12 +
2]) | ((((unsigned char *)(endhdr))[12 +2 +1]) << 8)) <<
16)) &0xffffffffUL)
;
201 jlong cenoff = ENDOFF(endhdr)((((((unsigned char *)(endhdr))[16]) | ((((unsigned char *)(endhdr
))[16 +1]) << 8)) | (((((unsigned char *)(endhdr))[16 +
2]) | ((((unsigned char *)(endhdr))[16 +2 +1]) << 8)) <<
16)) &0xffffffffUL)
;
202 jlong entries = ENDTOT(endhdr)((((unsigned char *)(endhdr))[10]) | ((((unsigned char *)(endhdr
))[10 +1]) << 8))
;
203 jlong end64pos;
204 Byte buf[ZIP64_ENDHDR56 + ZIP64_LOCHDR20];
205 if (censiz + cenoff != endpos
206 && (end64pos = endpos - sizeof(buf)) >= (jlong)0
207 && readAt(fd, end64pos, sizeof(buf), buf)
208 && ZIP64_LOCSIG_AT(buf + ZIP64_ENDHDR)(((buf + 56)[0] == 'P') & ((buf + 56)[1] == 'K') & ((
buf + 56)[2] == 6) & ((buf + 56)[3] == 7))
209 && (jlong) ZIP64_LOCDSK(buf + ZIP64_ENDHDR)((((((unsigned char *)(buf + 56))[4]) | ((((unsigned char *)(
buf + 56))[4 +1]) << 8)) | (((((unsigned char *)(buf + 56
))[4 +2]) | ((((unsigned char *)(buf + 56))[4 +2 +1]) <<
8)) << 16)) &0xffffffffUL)
== ENDDSK(endhdr)((((unsigned char *)(endhdr))[6]) | ((((unsigned char *)(endhdr
))[6 +1]) << 8))
210 && (is_zip64_endhdr(fd, buf, end64pos, censiz, cenoff, entries)
211 || // A variable sized "zip64 extensible data sector" ?
212 ((end64pos = ZIP64_LOCOFF(buf + ZIP64_ENDHDR)(((jlong)((((((unsigned char *)(buf + 56))[8]) | ((((unsigned
char *)(buf + 56))[8 +1]) << 8)) | (((((unsigned char *
)(buf + 56))[8 +2]) | ((((unsigned char *)(buf + 56))[8 +2 +1
]) << 8)) << 16)) &0xffffffffUL)) | (((jlong)
((((((unsigned char *)(buf + 56))[8 +4]) | ((((unsigned char *
)(buf + 56))[8 +4 +1]) << 8)) | (((((unsigned char *)(buf
+ 56))[8 +4 +2]) | ((((unsigned char *)(buf + 56))[8 +4 +2 +
1]) << 8)) << 16)) &0xffffffffUL)) << 32
))
) >= (jlong)0
213 && readAt(fd, end64pos, ZIP64_ENDHDR56, buf)
214 && is_zip64_endhdr(fd, buf, end64pos, censiz, cenoff, entries)))
215 ) {
216 *censtart = end64pos - ZIP64_ENDSIZ(buf)(((jlong)((((((unsigned char *)(buf))[40]) | ((((unsigned char
*)(buf))[40 +1]) << 8)) | (((((unsigned char *)(buf))[
40 +2]) | ((((unsigned char *)(buf))[40 +2 +1]) << 8)) <<
16)) &0xffffffffUL)) | (((jlong)((((((unsigned char *)(buf
))[40 +4]) | ((((unsigned char *)(buf))[40 +4 +1]) << 8
)) | (((((unsigned char *)(buf))[40 +4 +2]) | ((((unsigned char
*)(buf))[40 +4 +2 +1]) << 8)) << 16)) &0xffffffffUL
)) << 32))
;
217 *base_offset = *censtart - ZIP64_ENDOFF(buf)(((jlong)((((((unsigned char *)(buf))[48]) | ((((unsigned char
*)(buf))[48 +1]) << 8)) | (((((unsigned char *)(buf))[
48 +2]) | ((((unsigned char *)(buf))[48 +2 +1]) << 8)) <<
16)) &0xffffffffUL)) | (((jlong)((((((unsigned char *)(buf
))[48 +4]) | ((((unsigned char *)(buf))[48 +4 +1]) << 8
)) | (((((unsigned char *)(buf))[48 +4 +2]) | ((((unsigned char
*)(buf))[48 +4 +2 +1]) << 8)) << 16)) &0xffffffffUL
)) << 32))
;
218 } else {
219 if (!is_valid_end_header(fd, endpos, censiz, cenoff, entries))
220 return -1;
221 *censtart = endpos - censiz;
222 *base_offset = *censtart - cenoff;
223 }
224 return 0;
225}
226
227/*
228 * Finds the base offset and censtart of the zip file.
229 *
230 * @param fd file descriptor of the jar file
231 * @param eb scratch buffer
232 * @return 0 if successful, -1 in case of failure
233 */
234static int
235find_positions(int fd, Byte *eb, jlong* base_offset, jlong* censtart)
236{
237 jlong len;
238 jlong pos;
239 jlong flen;
240 int bytes;
241 Byte *cp;
242 Byte *endpos;
243 Byte *buffer;
244
245 /*
246 * 99.44% (or more) of the time, there will be no comment at the
247 * end of the zip file. Try reading just enough to read the END
248 * record from the end of the file, at this time we should also
249 * check to see if we have a ZIP64 archive.
250 */
251 if ((pos = JLI_Lseeklseek64(fd, -ENDHDR22, SEEK_END2)) < (jlong)0)
252 return (-1);
253 if (read(fd, eb, ENDHDR22) < 0)
254 return (-1);
255 if (ENDSIG_AT(eb)(((eb)[0] == 'P') & ((eb)[1] == 'K') & ((eb)[2] == 5)
& ((eb)[3] == 6))
) {
256 return find_positions64(fd, eb, pos, base_offset, censtart);
257 }
258
259 /*
260 * Shucky-Darn,... There is a comment at the end of the zip file.
261 *
262 * Allocate and fill a buffer with enough of the zip file
263 * to meet the specification for a maximal comment length.
264 */
265 if ((flen = JLI_Lseeklseek64(fd, 0, SEEK_END2)) < (jlong)0)
266 return (-1);
267 len = (flen < END_MAXLEN(0xFFFF + 22)) ? flen : END_MAXLEN(0xFFFF + 22);
268 if (JLI_Lseeklseek64(fd, -len, SEEK_END2) < (jlong)0)
269 return (-1);
270 if ((buffer = malloc(END_MAXLEN(0xFFFF + 22))) == NULL((void*)0))
271 return (-1);
272
273 /*
274 * read() on windows takes an unsigned int for count. Casting len
275 * to an unsigned int here is safe since it is guaranteed to be
276 * less than END_MAXLEN.
277 */
278 if ((bytes = read(fd, buffer, (unsigned int)len)) < 0) {
279 free(buffer);
280 return (-1);
281 }
282
283 /*
284 * Search backwards from the end of file stopping when the END header
285 * signature is found.
286 */
287 endpos = &buffer[bytes];
288 for (cp = &buffer[bytes - ENDHDR22]; cp >= &buffer[0]; cp--)
289 if (ENDSIG_AT(cp)(((cp)[0] == 'P') & ((cp)[1] == 'K') & ((cp)[2] == 5)
& ((cp)[3] == 6))
&& (cp + ENDHDR22 + ENDCOM(cp)((((unsigned char *)(cp))[20]) | ((((unsigned char *)(cp))[20
+1]) << 8))
== endpos)) {
290 (void) memcpy(eb, cp, ENDHDR22);
291 free(buffer);
292 pos = flen - (endpos - cp);
293 return find_positions64(fd, eb, pos, base_offset, censtart);
294 }
295 free(buffer);
296 return (-1);
297}
298
299#define BUFSIZE(3 * 65536 + 46 + 4) (3 * 65536 + CENHDR46 + SIGSIZ4)
300#define MINREAD1024 1024
301
302/*
303 * Locate the manifest file with the zip/jar file.
304 *
305 * fd: File descriptor of the jar file.
306 * entry: To be populated with the information necessary to perform
307 * the inflation (the compressed and uncompressed sizes and
308 * the offset in the file where the compressed data is located).
309 *
310 * Returns zero upon success. Returns a negative value upon failure.
311 *
312 * The buffer for reading the Central Directory if the zip/jar file needs
313 * to be large enough to accommodate the largest possible single record
314 * and the signature of the next record which is:
315 *
316 * 3*2**16 + CENHDR + SIGSIZ
317 *
318 * Each of the three variable sized fields (name, comment and extension)
319 * has a maximum possible size of 64k.
320 *
321 * Typically, only a small bit of this buffer is used with bytes shuffled
322 * down to the beginning of the buffer. It is one thing to allocate such
323 * a large buffer and another thing to actually start faulting it in.
324 *
325 * In most cases, all that needs to be read are the first two entries in
326 * a typical jar file (META-INF and META-INF/MANIFEST.MF). Keep this factoid
327 * in mind when optimizing this code.
328 */
329static int
330find_file(int fd, zentry *entry, const char *file_name)
331{
332 int bytes;
333 int res;
334 int entry_size;
335 int read_size;
336
337 /*
338 * The (imaginary) position within the file relative to which
339 * offsets within the zip file refer. This is usually the
340 * location of the first local header (the start of the zip data)
341 * (which in turn is usually 0), but if the zip file has content
342 * prepended, then it will be either 0 or the length of the
343 * prepended content, depending on whether or not internal offsets
344 * have been adjusted (via e.g. zip -A). May be negative if
345 * content is prepended, zip -A is run, then the prefix is
346 * detached!
347 */
348 jlong base_offset;
349
350 /** The position within the file of the start of the central directory. */
351 jlong censtart;
352
353 Byte *p;
354 Byte *bp;
355 Byte *buffer;
356 Byte locbuf[LOCHDR30];
357
358 if ((buffer = (Byte*)malloc(BUFSIZE(3 * 65536 + 46 + 4))) == NULL((void*)0)) {
359 return(-1);
360 }
361
362 bp = buffer;
363
364 if (find_positions(fd, bp, &base_offset, &censtart) == -1) {
365 free(buffer);
366 return -1;
367 }
368 if (JLI_Lseeklseek64(fd, censtart, SEEK_SET0) < (jlong) 0) {
369 free(buffer);
370 return -1;
371 }
372
373 if ((bytes = read(fd, bp, MINREAD1024)) < 0) {
374 free(buffer);
375 return (-1);
376 }
377 p = bp;
378 /*
379 * Loop through the Central Directory Headers. Note that a valid zip/jar
380 * must have an ENDHDR (with ENDSIG) after the Central Directory.
381 */
382 while (CENSIG_AT(p)(((p)[0] == 'P') & ((p)[1] == 'K') & ((p)[2] == 1) &
((p)[3] == 2))
) {
383
384 /*
385 * If a complete header isn't in the buffer, shift the contents
386 * of the buffer down and refill the buffer. Note that the check
387 * for "bytes < CENHDR" must be made before the test for the entire
388 * size of the header, because if bytes is less than CENHDR, the
389 * actual size of the header can't be determined. The addition of
390 * SIGSIZ guarantees that the next signature is also in the buffer
391 * for proper loop termination.
392 */
393 if (bytes < CENHDR46) {
394 p = memmove(bp, p, bytes);
395 if ((res = read(fd, bp + bytes, MINREAD1024)) <= 0) {
396 free(buffer);
397 return (-1);
398 }
399 bytes += res;
400 }
401 entry_size = CENHDR46 + CENNAM(p)((((unsigned char *)(p))[28]) | ((((unsigned char *)(p))[28 +
1]) << 8))
+ CENEXT(p)((((unsigned char *)(p))[30]) | ((((unsigned char *)(p))[30 +
1]) << 8))
+ CENCOM(p)((((unsigned char *)(p))[32]) | ((((unsigned char *)(p))[32 +
1]) << 8))
;
402 if (bytes < entry_size + SIGSIZ4) {
403 if (p != bp)
404 p = memmove(bp, p, bytes);
405 read_size = entry_size - bytes + SIGSIZ4;
406 read_size = (read_size < MINREAD1024) ? MINREAD1024 : read_size;
407 if ((res = read(fd, bp + bytes, read_size)) <= 0) {
408 free(buffer);
409 return (-1);
410 }
411 bytes += res;
412 }
413
414 /*
415 * Check if the name is the droid we are looking for; the jar file
416 * manifest. If so, build the entry record from the data found in
417 * the header located and return success.
418 */
419 if ((size_t)CENNAM(p)((((unsigned char *)(p))[28]) | ((((unsigned char *)(p))[28 +
1]) << 8))
== JLI_StrLen(file_name)strlen((file_name)) &&
420 memcmp((p + CENHDR46), file_name, JLI_StrLen(file_name)strlen((file_name))) == 0) {
421 if (JLI_Lseeklseek64(fd, base_offset + CENOFF(p)((((((unsigned char *)(p))[42]) | ((((unsigned char *)(p))[42
+1]) << 8)) | (((((unsigned char *)(p))[42 +2]) | ((((
unsigned char *)(p))[42 +2 +1]) << 8)) << 16)) &
0xffffffffUL)
, SEEK_SET0) < (jlong)0) {
422 free(buffer);
423 return (-1);
424 }
425 if (read(fd, locbuf, LOCHDR30) < 0) {
426 free(buffer);
427 return (-1);
428 }
429 if (!LOCSIG_AT(locbuf)(((locbuf)[0] == 'P') & ((locbuf)[1] == 'K') & ((locbuf
)[2] == 3) & ((locbuf)[3] == 4))
) {
430 free(buffer);
431 return (-1);
432 }
433 entry->isize = CENLEN(p)((((((unsigned char *)(p))[24]) | ((((unsigned char *)(p))[24
+1]) << 8)) | (((((unsigned char *)(p))[24 +2]) | ((((
unsigned char *)(p))[24 +2 +1]) << 8)) << 16)) &
0xffffffffUL)
;
434 entry->csize = CENSIZ(p)((((((unsigned char *)(p))[20]) | ((((unsigned char *)(p))[20
+1]) << 8)) | (((((unsigned char *)(p))[20 +2]) | ((((
unsigned char *)(p))[20 +2 +1]) << 8)) << 16)) &
0xffffffffUL)
;
435 entry->offset = base_offset + CENOFF(p)((((((unsigned char *)(p))[42]) | ((((unsigned char *)(p))[42
+1]) << 8)) | (((((unsigned char *)(p))[42 +2]) | ((((
unsigned char *)(p))[42 +2 +1]) << 8)) << 16)) &
0xffffffffUL)
+ LOCHDR30 +
436 LOCNAM(locbuf)((((unsigned char *)(locbuf))[26]) | ((((unsigned char *)(locbuf
))[26 +1]) << 8))
+ LOCEXT(locbuf)((((unsigned char *)(locbuf))[28]) | ((((unsigned char *)(locbuf
))[28 +1]) << 8))
;
437 entry->how = CENHOW(p)((((unsigned char *)(p))[10]) | ((((unsigned char *)(p))[10 +
1]) << 8))
;
438 free(buffer);
439 return (0);
440 }
441
442 /*
443 * Point to the next entry and decrement the count of valid remaining
444 * bytes.
445 */
446 bytes -= entry_size;
447 p += entry_size;
448 }
449 free(buffer);
450 return (-1); /* Fell off the end the loop without a Manifest */
451}
452
453/*
454 * Parse a Manifest file header entry into a distinct "name" and "value".
455 * Continuation lines are joined into a single "value". The documented
456 * syntax for a header entry is:
457 *
458 * header: name ":" value
459 *
460 * name: alphanum *headerchar
461 *
462 * value: SPACE *otherchar newline *continuation
463 *
464 * continuation: SPACE *otherchar newline
465 *
466 * newline: CR LF | LF | CR (not followed by LF)
467 *
468 * alphanum: {"A"-"Z"} | {"a"-"z"} | {"0"-"9"}
469 *
470 * headerchar: alphanum | "-" | "_"
471 *
472 * otherchar: any UTF-8 character except NUL, CR and LF
473 *
474 * Note that a manifest file may be composed of multiple sections,
475 * each of which may contain multiple headers.
476 *
477 * section: *header +newline
478 *
479 * nonempty-section: +header +newline
480 *
481 * (Note that the point of "nonempty-section" is unclear, because it isn't
482 * referenced elsewhere in the full specification for the Manifest file.)
483 *
484 * Arguments:
485 * lp pointer to a character pointer which points to the start
486 * of a valid header.
487 * name pointer to a character pointer which will be set to point
488 * to the name portion of the header (nul terminated).
489 * value pointer to a character pointer which will be set to point
490 * to the value portion of the header (nul terminated).
491 *
492 * Returns:
493 * 1 Successful parsing of an NV pair. lp is updated to point to the
494 * next character after the terminating newline in the string
495 * representing the Manifest file. name and value are updated to
496 * point to the strings parsed.
497 * 0 A valid end of section indicator was encountered. lp, name, and
498 * value are not modified.
499 * -1 lp does not point to a valid header. Upon return, the values of
500 * lp, name, and value are undefined.
501 */
502static int
503parse_nv_pair(char **lp, char **name, char **value)
504{
505 char *nl;
506 char *cp;
507
508 /*
509 * End of the section - return 0. The end of section condition is
510 * indicated by either encountering a blank line or the end of the
511 * Manifest "string" (EOF).
512 */
513 if (**lp == '\0' || **lp == '\n' || **lp == '\r')
514 return (0);
515
516 /*
517 * Getting to here, indicates that *lp points to an "otherchar".
518 * Turn the "header" into a string on its own.
519 */
520 nl = JLI_StrPBrk(*lp, "\n\r")strpbrk((*lp), ("\n\r"));
521 if (nl == NULL((void*)0)) {
522 nl = JLI_StrChr(*lp, (int)'\0')strchr((*lp), ((int)'\0'));
523 } else {
524 cp = nl; /* For merging continuation lines */
525 if (*nl == '\r' && *(nl+1) == '\n')
526 *nl++ = '\0';
527 *nl++ = '\0';
528
529 /*
530 * Process any "continuation" line(s), by making them part of the
531 * "header" line. Yes, I know that we are "undoing" the NULs we
532 * just placed here, but continuation lines are the fairly rare
533 * case, so we shouldn't unnecessarily complicate the code above.
534 *
535 * Note that an entire continuation line is processed each iteration
536 * through the outer while loop.
537 */
538 while (*nl == ' ') {
539 nl++; /* First character to be moved */
540 while (*nl != '\n' && *nl != '\r' && *nl != '\0')
541 *cp++ = *nl++; /* Shift string */
542 if (*nl == '\0')
543 return (-1); /* Error: newline required */
544 *cp = '\0';
545 if (*nl == '\r' && *(nl+1) == '\n')
546 *nl++ = '\0';
547 *nl++ = '\0';
548 }
549 }
550
551 /*
552 * Separate the name from the value;
553 */
554 cp = JLI_StrChr(*lp, (int)':')strchr((*lp), ((int)':'));
555 if (cp == NULL((void*)0))
556 return (-1);
557 *cp++ = '\0'; /* The colon terminates the name */
558 if (*cp != ' ')
559 return (-1);
560 *cp++ = '\0'; /* Eat the required space */
561 *name = *lp;
562 *value = cp;
563 *lp = nl;
564 return (1);
565}
566
567/*
568 * Read the manifest from the specified jar file and fill in the manifest_info
569 * structure with the information found within.
570 *
571 * Error returns are as follows:
572 * 0 Success
573 * -1 Unable to open jarfile
574 * -2 Error accessing the manifest from within the jarfile (most likely
575 * a manifest is not present, or this isn't a valid zip/jar file).
576 */
577int
578JLI_ParseManifest(char *jarfile, manifest_info *info)
579{
580 int fd;
581 zentry entry;
582 char *lp;
583 char *name;
584 char *value;
585 int rc;
586 char *splashscreen_name = NULL((void*)0);
587
588 if ((fd = JLI_Openopen(jarfile, O_RDONLY00
589#ifdef O_LARGEFILE0
590 | O_LARGEFILE0 /* large file mode */
591#endif
592#ifdef O_BINARY
593 | O_BINARY /* use binary mode on windows */
594#endif
595 )) == -1) {
596 return (-1);
597 }
598 info->manifest_version = NULL((void*)0);
599 info->main_class = NULL((void*)0);
600 info->jre_version = NULL((void*)0);
601 info->jre_restrict_search = 0;
602 info->splashscreen_image_file_name = NULL((void*)0);
603 if ((rc = find_file(fd, &entry, manifest_name)) != 0) {
604 close(fd);
605 return (-2);
606 }
607 manifest = inflate_file(fd, &entry, NULL((void*)0));
608 if (manifest == NULL((void*)0)) {
609 close(fd);
610 return (-2);
611 }
612 lp = manifest;
613 while ((rc = parse_nv_pair(&lp, &name, &value)) > 0) {
614 if (JLI_StrCaseCmp(name, "Manifest-Version")strcasecmp((name), ("Manifest-Version")) == 0) {
615 info->manifest_version = value;
616 } else if (JLI_StrCaseCmp(name, "Main-Class")strcasecmp((name), ("Main-Class")) == 0) {
617 info->main_class = value;
618 } else if (JLI_StrCaseCmp(name, "JRE-Version")strcasecmp((name), ("JRE-Version")) == 0) {
619 /*
620 * Manifest specification overridden by command line option
621 * so we will silently override there with no specification.
622 */
623 info->jre_version = 0;
624 } else if (JLI_StrCaseCmp(name, "Splashscreen-Image")strcasecmp((name), ("Splashscreen-Image")) == 0) {
625 info->splashscreen_image_file_name = value;
626 }
627 }
628 close(fd);
629 if (rc == 0)
630 return (0);
631 else
632 return (-2);
633}
634
635/*
636 * Opens the jar file and unpacks the specified file from its contents.
637 * Returns NULL on failure.
638 */
639void *
640JLI_JarUnpackFile(const char *jarfile, const char *filename, int *size) {
641 int fd;
642 zentry entry;
643 void *data = NULL((void*)0);
644
645 if ((fd = JLI_Openopen(jarfile, O_RDONLY00
646#ifdef O_LARGEFILE0
647 | O_LARGEFILE0 /* large file mode */
648#endif
649#ifdef O_BINARY
650 | O_BINARY /* use binary mode on windows */
651#endif
652 )) == -1) {
653 return NULL((void*)0);
654 }
655 if (find_file(fd, &entry, filename) == 0) {
656 data = inflate_file(fd, &entry, size);
657 }
658 close(fd);
659 return (data);
660}
661
662/*
663 * Specialized "free" function.
664 */
665void
666JLI_FreeManifest()
667{
668 if (manifest)
669 free(manifest);
670}
671
672/*
673 * Iterate over the manifest of the specified jar file and invoke the provided
674 * closure function for each attribute encountered.
675 *
676 * Error returns are as follows:
677 * 0 Success
678 * -1 Unable to open jarfile
679 * -2 Error accessing the manifest from within the jarfile (most likely
680 * this means a manifest is not present, or it isn't a valid zip/jar file).
681 */
682JNIEXPORT__attribute__((visibility("default"))) int JNICALL
683JLI_ManifestIterate(const char *jarfile, attribute_closure ac, void *user_data)
684{
685 int fd;
686 zentry entry;
687 char *mp; /* manifest pointer */
688 char *lp; /* pointer into manifest, updated during iteration */
689 char *name;
690 char *value;
691 int rc;
692
693 if ((fd = JLI_Openopen(jarfile, O_RDONLY00
694#ifdef O_LARGEFILE0
695 | O_LARGEFILE0 /* large file mode */
696#endif
697#ifdef O_BINARY
698 | O_BINARY /* use binary mode on windows */
699#endif
700 )) == -1) {
701 return (-1);
702 }
703
704 if ((rc = find_file(fd, &entry, manifest_name)) != 0) {
Although the value stored to 'rc' is used in the enclosing expression, the value is never actually read from 'rc'
705 close(fd);
706 return (-2);
707 }
708
709 mp = inflate_file(fd, &entry, NULL((void*)0));
710 if (mp == NULL((void*)0)) {
711 close(fd);
712 return (-2);
713 }
714
715 lp = mp;
716 while ((rc = parse_nv_pair(&lp, &name, &value)) > 0) {
717 (*ac)(name, value, user_data);
718 }
719 free(mp);
720 close(fd);
721 return (rc == 0) ? 0 : -2;
722}