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);
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. */
136static jboolean
137readAt(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 */
149static jboolean
150is_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 */
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)) {
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 */
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);
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 */
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_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 */
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[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 */
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");
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 */
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;
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 */
639void *
640JLI_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 */
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 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_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