Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/src/java.base/share/native/libjli/parse_manifest.c
67707 views
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
38
static char *manifest;
39
40
static 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
*/
56
static char *
57
inflate_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);
65
if (JLI_Lseek(fd, entry->offset, SEEK_SET) < (jlong)0)
66
return (NULL);
67
if ((in = malloc(entry->csize + 1)) == NULL)
68
return (NULL);
69
if ((size_t)(read(fd, in, (unsigned int)entry->csize)) != entry->csize) {
70
free(in);
71
return (NULL);
72
}
73
if (entry->how == STORED) {
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 == DEFLATED) {
80
zs.zalloc = (alloc_func)Z_NULL;
81
zs.zfree = (free_func)Z_NULL;
82
zs.opaque = (voidpf)Z_NULL;
83
zs.next_in = (Byte*)in;
84
zs.avail_in = (uInt)entry->csize;
85
if (inflateInit2(&zs, -MAX_WBITS) < 0) {
86
free(in);
87
return (NULL);
88
}
89
if ((out = malloc(entry->isize + 1)) == NULL) {
90
free(in);
91
return (NULL);
92
}
93
zs.next_out = (Byte*)out;
94
zs.avail_out = (uInt)entry->isize;
95
if (inflate(&zs, Z_PARTIAL_FLUSH) < 0) {
96
free(in);
97
free(out);
98
return (NULL);
99
}
100
*(char *)((size_t)out + entry->isize) = '\0';
101
free(in);
102
if (inflateEnd(&zs) < 0) {
103
free(out);
104
return (NULL);
105
}
106
if (size_out) {
107
*size_out = (int)entry->isize;
108
}
109
return (out);
110
}
111
free(in);
112
return (NULL);
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. */
136
static jboolean
137
readAt(int fd, jlong pos, unsigned int count, void *buf) {
138
return (pos >= 0
139
&& JLI_Lseek(fd, pos, SEEK_SET) == 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
*/
149
static jboolean
150
is_valid_end_header(int fd, jlong endpos,
151
jlong censiz, jlong cenoff, jlong entries) {
152
Byte cenhdr[CENHDR];
153
Byte lochdr[LOCHDR];
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, CENHDR, cenhdr)
163
&& CENSIG_AT(cenhdr)
164
&& readAt(fd, base_offset + CENOFF(cenhdr), LOCHDR, lochdr)
165
&& LOCSIG_AT(lochdr)
166
&& CENNAM(cenhdr) == LOCNAM(lochdr)));
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
*/
175
static jboolean
176
is_zip64_endhdr(int fd, const Byte *p, jlong end64pos,
177
jlong censiz, jlong cenoff, jlong entries) {
178
if (ZIP64_ENDSIG_AT(p)) {
179
jlong censiz64 = ZIP64_ENDSIZ(p);
180
jlong cenoff64 = ZIP64_ENDOFF(p);
181
jlong entries64 = ZIP64_ENDTOT(p);
182
return (censiz64 == censiz || censiz == ZIP64_MAGICVAL)
183
&& (cenoff64 == cenoff || cenoff == ZIP64_MAGICVAL)
184
&& (entries64 == entries || entries == ZIP64_MAGICCOUNT)
185
&& is_valid_end_header(fd, end64pos, censiz64, cenoff64, entries64);
186
}
187
return JNI_FALSE;
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
*/
196
static int
197
find_positions64(int fd, const Byte * const endhdr, const jlong endpos,
198
jlong* base_offset, jlong* censtart)
199
{
200
jlong censiz = ENDSIZ(endhdr);
201
jlong cenoff = ENDOFF(endhdr);
202
jlong entries = ENDTOT(endhdr);
203
jlong end64pos;
204
Byte buf[ZIP64_ENDHDR + ZIP64_LOCHDR];
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)
209
&& (jlong) ZIP64_LOCDSK(buf + ZIP64_ENDHDR) == ENDDSK(endhdr)
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)0
213
&& readAt(fd, end64pos, ZIP64_ENDHDR, buf)
214
&& is_zip64_endhdr(fd, buf, end64pos, censiz, cenoff, entries)))
215
) {
216
*censtart = end64pos - ZIP64_ENDSIZ(buf);
217
*base_offset = *censtart - ZIP64_ENDOFF(buf);
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
*/
234
static int
235
find_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_Lseek(fd, -ENDHDR, SEEK_END)) < (jlong)0)
252
return (-1);
253
if (read(fd, eb, ENDHDR) < 0)
254
return (-1);
255
if (ENDSIG_AT(eb)) {
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_Lseek(fd, 0, SEEK_END)) < (jlong)0)
266
return (-1);
267
len = (flen < END_MAXLEN) ? flen : END_MAXLEN;
268
if (JLI_Lseek(fd, -len, SEEK_END) < (jlong)0)
269
return (-1);
270
if ((buffer = malloc(END_MAXLEN)) == NULL)
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 - ENDHDR]; cp >= &buffer[0]; cp--)
289
if (ENDSIG_AT(cp) && (cp + ENDHDR + ENDCOM(cp) == endpos)) {
290
(void) memcpy(eb, cp, ENDHDR);
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 + CENHDR + SIGSIZ)
300
#define MINREAD 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
*/
329
static int
330
find_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[LOCHDR];
357
358
if ((buffer = (Byte*)malloc(BUFSIZE)) == NULL) {
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_Lseek(fd, censtart, SEEK_SET) < (jlong) 0) {
369
free(buffer);
370
return -1;
371
}
372
373
if ((bytes = read(fd, bp, MINREAD)) < 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)) {
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 < CENHDR) {
394
p = memmove(bp, p, bytes);
395
if ((res = read(fd, bp + bytes, MINREAD)) <= 0) {
396
free(buffer);
397
return (-1);
398
}
399
bytes += res;
400
}
401
entry_size = CENHDR + CENNAM(p) + CENEXT(p) + CENCOM(p);
402
if (bytes < entry_size + SIGSIZ) {
403
if (p != bp)
404
p = memmove(bp, p, bytes);
405
read_size = entry_size - bytes + SIGSIZ;
406
read_size = (read_size < MINREAD) ? MINREAD : 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) == JLI_StrLen(file_name) &&
420
memcmp((p + CENHDR), file_name, JLI_StrLen(file_name)) == 0) {
421
if (JLI_Lseek(fd, base_offset + CENOFF(p), SEEK_SET) < (jlong)0) {
422
free(buffer);
423
return (-1);
424
}
425
if (read(fd, locbuf, LOCHDR) < 0) {
426
free(buffer);
427
return (-1);
428
}
429
if (!LOCSIG_AT(locbuf)) {
430
free(buffer);
431
return (-1);
432
}
433
entry->isize = CENLEN(p);
434
entry->csize = CENSIZ(p);
435
entry->offset = base_offset + CENOFF(p) + LOCHDR +
436
LOCNAM(locbuf) + LOCEXT(locbuf);
437
entry->how = CENHOW(p);
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
*/
502
static int
503
parse_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");
521
if (nl == NULL) {
522
nl = JLI_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)':');
555
if (cp == NULL)
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
*/
577
int
578
JLI_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;
587
588
if ((fd = JLI_Open(jarfile, O_RDONLY
589
#ifdef O_LARGEFILE
590
| O_LARGEFILE /* 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;
599
info->main_class = NULL;
600
info->jre_version = NULL;
601
info->jre_restrict_search = 0;
602
info->splashscreen_image_file_name = NULL;
603
if ((rc = find_file(fd, &entry, manifest_name)) != 0) {
604
close(fd);
605
return (-2);
606
}
607
manifest = inflate_file(fd, &entry, NULL);
608
if (manifest == NULL) {
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") == 0) {
615
info->manifest_version = value;
616
} else if (JLI_StrCaseCmp(name, "Main-Class") == 0) {
617
info->main_class = value;
618
} else if (JLI_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") == 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
*/
639
void *
640
JLI_JarUnpackFile(const char *jarfile, const char *filename, int *size) {
641
int fd;
642
zentry entry;
643
void *data = NULL;
644
645
if ((fd = JLI_Open(jarfile, O_RDONLY
646
#ifdef O_LARGEFILE
647
| O_LARGEFILE /* large file mode */
648
#endif
649
#ifdef O_BINARY
650
| O_BINARY /* use binary mode on windows */
651
#endif
652
)) == -1) {
653
return NULL;
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
*/
665
void
666
JLI_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
*/
682
JNIEXPORT int JNICALL
683
JLI_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_Open(jarfile, O_RDONLY
694
#ifdef O_LARGEFILE
695
| O_LARGEFILE /* 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) {
705
close(fd);
706
return (-2);
707
}
708
709
mp = inflate_file(fd, &entry, NULL);
710
if (mp == NULL) {
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
}
723
724