1*3ab258a1Smillert /* $OpenBSD: zipopen.c,v 1.1 2022/10/22 14:41:27 millert Exp $ */
2*3ab258a1Smillert
3*3ab258a1Smillert /*
4*3ab258a1Smillert * Copyright (c) 2022 Todd C. Miller <Todd.Miller@sudo.ws>
5*3ab258a1Smillert *
6*3ab258a1Smillert * Permission to use, copy, modify, and distribute this software for any
7*3ab258a1Smillert * purpose with or without fee is hereby granted, provided that the above
8*3ab258a1Smillert * copyright notice and this permission notice appear in all copies.
9*3ab258a1Smillert *
10*3ab258a1Smillert * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*3ab258a1Smillert * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*3ab258a1Smillert * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*3ab258a1Smillert * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*3ab258a1Smillert * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15*3ab258a1Smillert * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16*3ab258a1Smillert * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*3ab258a1Smillert */
18*3ab258a1Smillert
19*3ab258a1Smillert #include <stdio.h>
20*3ab258a1Smillert #include <stdlib.h>
21*3ab258a1Smillert #include <string.h>
22*3ab258a1Smillert #include <errno.h>
23*3ab258a1Smillert #include <unistd.h>
24*3ab258a1Smillert #include <limits.h>
25*3ab258a1Smillert #include <zlib.h>
26*3ab258a1Smillert #include "compress.h"
27*3ab258a1Smillert
28*3ab258a1Smillert #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
29*3ab258a1Smillert
30*3ab258a1Smillert /* Signatures for zip file headers we use. */
31*3ab258a1Smillert #define ZIPMAG 0x4b50 /* first two bytes of the zip signature */
32*3ab258a1Smillert #define LOCREM 0x0403 /* remaining two bytes in zip signature */
33*3ab258a1Smillert #define LOCSIG 0x04034b50 /* local file header signature */
34*3ab258a1Smillert #define EXTSIG 0x08074b50 /* extended local header signature */
35*3ab258a1Smillert
36*3ab258a1Smillert /* Header sizes. */
37*3ab258a1Smillert #define LOCHDR 30 /* size of local header, including signature */
38*3ab258a1Smillert #define EXTHDR 16 /* size of extended local header, inc sig */
39*3ab258a1Smillert
40*3ab258a1Smillert /* General purpose flag bits. */
41*3ab258a1Smillert #define CRPFLG 1 /* flag bit for encrypted entry */
42*3ab258a1Smillert #define EXTFLG 8 /* flag bit for extended local header */
43*3ab258a1Smillert
44*3ab258a1Smillert /* Extra field definitions */
45*3ab258a1Smillert #define EF_ZIP64 0x0001 /* zip64 support */
46*3ab258a1Smillert #define EF_TIME 0x5455 /* mtime, atime, ctime in UTC ("UT") */
47*3ab258a1Smillert #define EF_IZUNIX 0x5855 /* UNIX extra field ID ("UX") */
48*3ab258a1Smillert
49*3ab258a1Smillert #define Z_STORED 0 /* Stored uncompressed in .zip */
50*3ab258a1Smillert
51*3ab258a1Smillert struct zip_state {
52*3ab258a1Smillert z_stream z_stream; /* libz stream */
53*3ab258a1Smillert uint8_t z_buf[Z_BUFSIZE]; /* I/O buffer */
54*3ab258a1Smillert uint8_t z_eof; /* set if end of input file */
55*3ab258a1Smillert uint8_t z_zip64; /* 64-bit file sizes */
56*3ab258a1Smillert uint16_t z_method; /* Z_DEFLATE or Z_STORED */
57*3ab258a1Smillert uint16_t z_flags; /* general purpose flags */
58*3ab258a1Smillert int z_fd; /* zip file descriptor */
59*3ab258a1Smillert uint32_t z_time; /* timestamp (mtime) */
60*3ab258a1Smillert uint32_t z_crc; /* crc32 of uncompressed data */
61*3ab258a1Smillert uint32_t z_ocrc; /* crc32 of uncompressed data (from header) */
62*3ab258a1Smillert uint32_t z_hlen; /* length of the zip header */
63*3ab258a1Smillert uint64_t z_ulen; /* uncompressed data length (from header) */
64*3ab258a1Smillert uint64_t z_total_in; /* # bytes in */
65*3ab258a1Smillert uint64_t z_total_out; /* # bytes out */
66*3ab258a1Smillert };
67*3ab258a1Smillert
68*3ab258a1Smillert static int
get_byte(struct zip_state * s)69*3ab258a1Smillert get_byte(struct zip_state *s)
70*3ab258a1Smillert {
71*3ab258a1Smillert if (s->z_eof)
72*3ab258a1Smillert return EOF;
73*3ab258a1Smillert
74*3ab258a1Smillert if (s->z_stream.avail_in == 0) {
75*3ab258a1Smillert ssize_t nread = read(s->z_fd, s->z_buf, Z_BUFSIZE);
76*3ab258a1Smillert if (nread <= 0) {
77*3ab258a1Smillert s->z_eof = 1;
78*3ab258a1Smillert return EOF;
79*3ab258a1Smillert }
80*3ab258a1Smillert s->z_stream.avail_in = nread;
81*3ab258a1Smillert s->z_stream.next_in = s->z_buf;
82*3ab258a1Smillert }
83*3ab258a1Smillert s->z_stream.avail_in--;
84*3ab258a1Smillert return *s->z_stream.next_in++;
85*3ab258a1Smillert }
86*3ab258a1Smillert
87*3ab258a1Smillert static uint16_t
get_uint16(struct zip_state * s)88*3ab258a1Smillert get_uint16(struct zip_state *s)
89*3ab258a1Smillert {
90*3ab258a1Smillert uint16_t x;
91*3ab258a1Smillert
92*3ab258a1Smillert x = ((uint16_t)(get_byte(s) & 0xff));
93*3ab258a1Smillert x |= ((uint16_t)(get_byte(s) & 0xff))<<8;
94*3ab258a1Smillert return x;
95*3ab258a1Smillert }
96*3ab258a1Smillert
97*3ab258a1Smillert static uint32_t
get_uint32(struct zip_state * s)98*3ab258a1Smillert get_uint32(struct zip_state *s)
99*3ab258a1Smillert {
100*3ab258a1Smillert uint32_t x;
101*3ab258a1Smillert
102*3ab258a1Smillert x = ((uint32_t)(get_byte(s) & 0xff));
103*3ab258a1Smillert x |= ((uint32_t)(get_byte(s) & 0xff))<<8;
104*3ab258a1Smillert x |= ((uint32_t)(get_byte(s) & 0xff))<<16;
105*3ab258a1Smillert x |= ((uint32_t)(get_byte(s) & 0xff))<<24;
106*3ab258a1Smillert return x;
107*3ab258a1Smillert }
108*3ab258a1Smillert
109*3ab258a1Smillert static uint64_t
get_uint64(struct zip_state * s)110*3ab258a1Smillert get_uint64(struct zip_state *s)
111*3ab258a1Smillert {
112*3ab258a1Smillert uint64_t x;
113*3ab258a1Smillert
114*3ab258a1Smillert x = ((uint64_t)(get_byte(s) & 0xff));
115*3ab258a1Smillert x |= ((uint64_t)(get_byte(s) & 0xff))<<8;
116*3ab258a1Smillert x |= ((uint64_t)(get_byte(s) & 0xff))<<16;
117*3ab258a1Smillert x |= ((uint64_t)(get_byte(s) & 0xff))<<24;
118*3ab258a1Smillert x |= ((uint64_t)(get_byte(s) & 0xff))<<32;
119*3ab258a1Smillert x |= ((uint64_t)(get_byte(s) & 0xff))<<40;
120*3ab258a1Smillert x |= ((uint64_t)(get_byte(s) & 0xff))<<48;
121*3ab258a1Smillert x |= ((uint64_t)(get_byte(s) & 0xff))<<56;
122*3ab258a1Smillert return x;
123*3ab258a1Smillert }
124*3ab258a1Smillert
125*3ab258a1Smillert static int
get_header(struct zip_state * s,char * name,int gotmagic)126*3ab258a1Smillert get_header(struct zip_state *s, char *name, int gotmagic)
127*3ab258a1Smillert {
128*3ab258a1Smillert int c, got_mtime = 0;
129*3ab258a1Smillert uint16_t namelen, extlen;
130*3ab258a1Smillert uint32_t sig;
131*3ab258a1Smillert
132*3ab258a1Smillert /* Check the zip local file header signature. */
133*3ab258a1Smillert if (!gotmagic) {
134*3ab258a1Smillert sig = get_uint32(s);
135*3ab258a1Smillert if (sig != LOCSIG) {
136*3ab258a1Smillert errno = EFTYPE;
137*3ab258a1Smillert return -1;
138*3ab258a1Smillert }
139*3ab258a1Smillert } else {
140*3ab258a1Smillert sig = get_uint16(s);
141*3ab258a1Smillert if (sig != LOCREM) {
142*3ab258a1Smillert errno = EFTYPE;
143*3ab258a1Smillert return -1;
144*3ab258a1Smillert }
145*3ab258a1Smillert }
146*3ab258a1Smillert
147*3ab258a1Smillert /* Read the local header fields. */
148*3ab258a1Smillert get_uint16(s); /* min version */
149*3ab258a1Smillert s->z_flags = get_uint16(s); /* general purpose flags */
150*3ab258a1Smillert s->z_method = get_uint16(s); /* compression method */
151*3ab258a1Smillert get_uint32(s); /* DOS format mtime */
152*3ab258a1Smillert s->z_ocrc = get_uint32(s); /* 32-bit CRC */
153*3ab258a1Smillert get_uint32(s); /* compressed size */
154*3ab258a1Smillert s->z_ulen = get_uint32(s); /* uncompressed size */
155*3ab258a1Smillert namelen = get_uint16(s); /* file name length */
156*3ab258a1Smillert extlen = get_uint16(s); /* length of extra fields */
157*3ab258a1Smillert s->z_hlen = LOCHDR;
158*3ab258a1Smillert
159*3ab258a1Smillert /* Encrypted files not supported. */
160*3ab258a1Smillert if (s->z_flags & CRPFLG) {
161*3ab258a1Smillert errno = EFTYPE;
162*3ab258a1Smillert return -1;
163*3ab258a1Smillert }
164*3ab258a1Smillert
165*3ab258a1Smillert /* Supported compression methods are deflate and store. */
166*3ab258a1Smillert if (s->z_method != Z_DEFLATED && s->z_method != Z_STORED) {
167*3ab258a1Smillert errno = EFTYPE;
168*3ab258a1Smillert return -1;
169*3ab258a1Smillert }
170*3ab258a1Smillert
171*3ab258a1Smillert /* Store the original file name if present. */
172*3ab258a1Smillert if (namelen != 0 && name != NULL) {
173*3ab258a1Smillert const char *ep = name + PATH_MAX - 1;
174*3ab258a1Smillert for (; namelen > 0; namelen--) {
175*3ab258a1Smillert if ((c = get_byte(s)) == EOF)
176*3ab258a1Smillert break;
177*3ab258a1Smillert s->z_hlen++;
178*3ab258a1Smillert if (c == '\0')
179*3ab258a1Smillert break;
180*3ab258a1Smillert if (name < ep)
181*3ab258a1Smillert *name++ = c;
182*3ab258a1Smillert }
183*3ab258a1Smillert *name = '\0';
184*3ab258a1Smillert }
185*3ab258a1Smillert
186*3ab258a1Smillert /* Parse extra fields, if any. */
187*3ab258a1Smillert while (extlen >= 4) {
188*3ab258a1Smillert uint16_t sig;
189*3ab258a1Smillert int fieldlen;
190*3ab258a1Smillert
191*3ab258a1Smillert sig = get_uint16(s);
192*3ab258a1Smillert fieldlen = get_uint16(s);
193*3ab258a1Smillert s->z_hlen += 4;
194*3ab258a1Smillert extlen -= 4;
195*3ab258a1Smillert
196*3ab258a1Smillert switch (sig) {
197*3ab258a1Smillert case EF_ZIP64:
198*3ab258a1Smillert /* 64-bit file sizes */
199*3ab258a1Smillert s->z_zip64 = 1;
200*3ab258a1Smillert if (fieldlen >= 8) {
201*3ab258a1Smillert s->z_ulen = get_uint64(s);
202*3ab258a1Smillert s->z_hlen += 8;
203*3ab258a1Smillert extlen -= 8;
204*3ab258a1Smillert fieldlen -= 8;
205*3ab258a1Smillert }
206*3ab258a1Smillert break;
207*3ab258a1Smillert case EF_TIME:
208*3ab258a1Smillert /* UTC timestamps */
209*3ab258a1Smillert if ((c = get_byte(s)) == EOF)
210*3ab258a1Smillert break;
211*3ab258a1Smillert s->z_hlen++;
212*3ab258a1Smillert extlen--;
213*3ab258a1Smillert fieldlen--;
214*3ab258a1Smillert if (c & 1) {
215*3ab258a1Smillert got_mtime = 1;
216*3ab258a1Smillert s->z_time = get_uint32(s);
217*3ab258a1Smillert s->z_hlen += 4;
218*3ab258a1Smillert extlen -= 4;
219*3ab258a1Smillert fieldlen -= 4;
220*3ab258a1Smillert }
221*3ab258a1Smillert break;
222*3ab258a1Smillert case EF_IZUNIX:
223*3ab258a1Smillert /* We prefer EF_TIME if it is present. */
224*3ab258a1Smillert if (got_mtime)
225*3ab258a1Smillert break;
226*3ab258a1Smillert
227*3ab258a1Smillert /* skip atime, store mtime. */
228*3ab258a1Smillert (void)get_uint32(s);
229*3ab258a1Smillert s->z_time = get_uint32(s);
230*3ab258a1Smillert s->z_hlen += 8;
231*3ab258a1Smillert extlen -= 8;
232*3ab258a1Smillert fieldlen -= 8;
233*3ab258a1Smillert break;
234*3ab258a1Smillert default:
235*3ab258a1Smillert break;
236*3ab258a1Smillert }
237*3ab258a1Smillert
238*3ab258a1Smillert /* Consume any unparsed bytes in the field. */
239*3ab258a1Smillert for (; fieldlen > 0; fieldlen--) {
240*3ab258a1Smillert if (get_byte(s) == EOF)
241*3ab258a1Smillert break;
242*3ab258a1Smillert s->z_hlen++;
243*3ab258a1Smillert extlen--;
244*3ab258a1Smillert }
245*3ab258a1Smillert }
246*3ab258a1Smillert for (; extlen > 0; extlen--) {
247*3ab258a1Smillert if (get_byte(s) == EOF)
248*3ab258a1Smillert break;
249*3ab258a1Smillert s->z_hlen++;
250*3ab258a1Smillert }
251*3ab258a1Smillert
252*3ab258a1Smillert return 0;
253*3ab258a1Smillert }
254*3ab258a1Smillert
255*3ab258a1Smillert void *
zip_ropen(int fd,char * name,int gotmagic)256*3ab258a1Smillert zip_ropen(int fd, char *name, int gotmagic)
257*3ab258a1Smillert {
258*3ab258a1Smillert struct zip_state *s;
259*3ab258a1Smillert
260*3ab258a1Smillert if (fd < 0)
261*3ab258a1Smillert return NULL;
262*3ab258a1Smillert
263*3ab258a1Smillert if ((s = calloc(1, sizeof(*s))) == NULL)
264*3ab258a1Smillert return NULL;
265*3ab258a1Smillert
266*3ab258a1Smillert s->z_fd = fd;
267*3ab258a1Smillert s->z_crc = crc32(0, NULL, 0);
268*3ab258a1Smillert
269*3ab258a1Smillert /* Request a raw inflate, there is no zlib/gzip header present. */
270*3ab258a1Smillert if (inflateInit2(&s->z_stream, -MAX_WBITS) != Z_OK) {
271*3ab258a1Smillert free(s);
272*3ab258a1Smillert return NULL;
273*3ab258a1Smillert }
274*3ab258a1Smillert s->z_stream.next_in = s->z_buf;
275*3ab258a1Smillert s->z_stream.avail_out = sizeof(s->z_buf);
276*3ab258a1Smillert
277*3ab258a1Smillert /* Read the zip header. */
278*3ab258a1Smillert if (get_header(s, name, gotmagic) != 0) {
279*3ab258a1Smillert zip_close(s, NULL, NULL, NULL);
280*3ab258a1Smillert s = NULL;
281*3ab258a1Smillert }
282*3ab258a1Smillert
283*3ab258a1Smillert return s;
284*3ab258a1Smillert }
285*3ab258a1Smillert
286*3ab258a1Smillert static int
zip_store(struct zip_state * s)287*3ab258a1Smillert zip_store(struct zip_state *s)
288*3ab258a1Smillert {
289*3ab258a1Smillert int error = Z_OK;
290*3ab258a1Smillert uLong copy_len;
291*3ab258a1Smillert
292*3ab258a1Smillert if ((int)s->z_stream.avail_in <= 0)
293*3ab258a1Smillert return s->z_stream.avail_in == 0 ? Z_STREAM_END : Z_DATA_ERROR;
294*3ab258a1Smillert
295*3ab258a1Smillert /* For stored files we rely on z_ulen being set. */
296*3ab258a1Smillert copy_len = MINIMUM(s->z_stream.avail_out, s->z_stream.avail_in);
297*3ab258a1Smillert if (copy_len >= s->z_ulen - s->z_total_out) {
298*3ab258a1Smillert /* Don't copy past the end of the file. */
299*3ab258a1Smillert copy_len = s->z_ulen - s->z_total_out;
300*3ab258a1Smillert error = Z_STREAM_END;
301*3ab258a1Smillert }
302*3ab258a1Smillert
303*3ab258a1Smillert memcpy(s->z_stream.next_out, s->z_stream.next_in, copy_len);
304*3ab258a1Smillert s->z_stream.next_out += copy_len;
305*3ab258a1Smillert s->z_stream.avail_out -= copy_len;
306*3ab258a1Smillert s->z_stream.next_in += copy_len;
307*3ab258a1Smillert s->z_stream.avail_in -= copy_len;
308*3ab258a1Smillert s->z_total_in += copy_len;
309*3ab258a1Smillert s->z_total_out += copy_len;
310*3ab258a1Smillert
311*3ab258a1Smillert return error;
312*3ab258a1Smillert }
313*3ab258a1Smillert
314*3ab258a1Smillert int
zip_read(void * cookie,char * buf,int len)315*3ab258a1Smillert zip_read(void *cookie, char *buf, int len)
316*3ab258a1Smillert {
317*3ab258a1Smillert struct zip_state *s = cookie;
318*3ab258a1Smillert Bytef *ubuf = buf;
319*3ab258a1Smillert int error = Z_OK;
320*3ab258a1Smillert
321*3ab258a1Smillert s->z_stream.next_out = ubuf;
322*3ab258a1Smillert s->z_stream.avail_out = len;
323*3ab258a1Smillert
324*3ab258a1Smillert while (error == Z_OK && !s->z_eof && s->z_stream.avail_out != 0) {
325*3ab258a1Smillert if (s->z_stream.avail_in == 0) {
326*3ab258a1Smillert ssize_t nread = read(s->z_fd, s->z_buf, Z_BUFSIZE);
327*3ab258a1Smillert switch (nread) {
328*3ab258a1Smillert case -1:
329*3ab258a1Smillert goto bad;
330*3ab258a1Smillert case 0:
331*3ab258a1Smillert s->z_eof = 1;
332*3ab258a1Smillert continue;
333*3ab258a1Smillert default:
334*3ab258a1Smillert s->z_stream.avail_in = nread;
335*3ab258a1Smillert s->z_stream.next_in = s->z_buf;
336*3ab258a1Smillert }
337*3ab258a1Smillert }
338*3ab258a1Smillert
339*3ab258a1Smillert if (s->z_method == Z_DEFLATED) {
340*3ab258a1Smillert /*
341*3ab258a1Smillert * Prevent overflow of z_stream.total_{in,out}
342*3ab258a1Smillert * which may be 32-bit.
343*3ab258a1Smillert */
344*3ab258a1Smillert uLong prev_total_in = s->z_stream.total_in;
345*3ab258a1Smillert uLong prev_total_out = s->z_stream.total_out;
346*3ab258a1Smillert error = inflate(&s->z_stream, Z_NO_FLUSH);
347*3ab258a1Smillert s->z_total_in += s->z_stream.total_in - prev_total_in;
348*3ab258a1Smillert s->z_total_out += s->z_stream.total_out - prev_total_out;
349*3ab258a1Smillert } else {
350*3ab258a1Smillert /* File stored uncompressed. */
351*3ab258a1Smillert error = zip_store(s);
352*3ab258a1Smillert }
353*3ab258a1Smillert }
354*3ab258a1Smillert
355*3ab258a1Smillert switch (error) {
356*3ab258a1Smillert case Z_OK:
357*3ab258a1Smillert s->z_crc = crc32(s->z_crc, ubuf,
358*3ab258a1Smillert (uInt)(s->z_stream.next_out - ubuf));
359*3ab258a1Smillert break;
360*3ab258a1Smillert case Z_STREAM_END:
361*3ab258a1Smillert s->z_eof = 1;
362*3ab258a1Smillert
363*3ab258a1Smillert /*
364*3ab258a1Smillert * Check CRC and original size.
365*3ab258a1Smillert * These may be found in the local header or, if
366*3ab258a1Smillert * EXTFLG is set, immediately following the file.
367*3ab258a1Smillert */
368*3ab258a1Smillert s->z_crc = crc32(s->z_crc, ubuf,
369*3ab258a1Smillert (uInt)(s->z_stream.next_out - ubuf));
370*3ab258a1Smillert
371*3ab258a1Smillert if (s->z_flags & EXTFLG) {
372*3ab258a1Smillert /*
373*3ab258a1Smillert * Read data descriptor:
374*3ab258a1Smillert * signature 0x08074b50: 4 bytes
375*3ab258a1Smillert * CRC-32: 4 bytes
376*3ab258a1Smillert * compressed size: 4 or 8 bytes
377*3ab258a1Smillert * uncompressed size: 4 or 8 bytes
378*3ab258a1Smillert */
379*3ab258a1Smillert get_uint32(s);
380*3ab258a1Smillert s->z_ocrc = get_uint32(s);
381*3ab258a1Smillert if (s->z_zip64) {
382*3ab258a1Smillert get_uint64(s);
383*3ab258a1Smillert s->z_ulen = get_uint64(s);
384*3ab258a1Smillert s->z_hlen += 8;
385*3ab258a1Smillert } else {
386*3ab258a1Smillert get_uint32(s);
387*3ab258a1Smillert s->z_ulen = get_uint32(s);
388*3ab258a1Smillert }
389*3ab258a1Smillert s->z_hlen += EXTHDR;
390*3ab258a1Smillert }
391*3ab258a1Smillert if (s->z_ulen != s->z_total_out) {
392*3ab258a1Smillert errno = EIO;
393*3ab258a1Smillert goto bad;
394*3ab258a1Smillert }
395*3ab258a1Smillert if (s->z_ocrc != s->z_crc) {
396*3ab258a1Smillert errno = EINVAL;
397*3ab258a1Smillert goto bad;
398*3ab258a1Smillert }
399*3ab258a1Smillert break;
400*3ab258a1Smillert case Z_DATA_ERROR:
401*3ab258a1Smillert errno = EINVAL;
402*3ab258a1Smillert goto bad;
403*3ab258a1Smillert case Z_BUF_ERROR:
404*3ab258a1Smillert errno = EIO;
405*3ab258a1Smillert goto bad;
406*3ab258a1Smillert default:
407*3ab258a1Smillert goto bad;
408*3ab258a1Smillert }
409*3ab258a1Smillert
410*3ab258a1Smillert return len - s->z_stream.avail_out;
411*3ab258a1Smillert bad:
412*3ab258a1Smillert return -1;
413*3ab258a1Smillert }
414*3ab258a1Smillert
415*3ab258a1Smillert int
zip_close(void * cookie,struct z_info * info,const char * name,struct stat * sb)416*3ab258a1Smillert zip_close(void *cookie, struct z_info *info, const char *name, struct stat *sb)
417*3ab258a1Smillert {
418*3ab258a1Smillert struct zip_state *s = cookie;
419*3ab258a1Smillert int error = 0;
420*3ab258a1Smillert
421*3ab258a1Smillert if (s == NULL) {
422*3ab258a1Smillert errno = EINVAL;
423*3ab258a1Smillert return -1;
424*3ab258a1Smillert }
425*3ab258a1Smillert
426*3ab258a1Smillert if (info != NULL) {
427*3ab258a1Smillert info->mtime = s->z_time;
428*3ab258a1Smillert info->crc = s->z_crc;
429*3ab258a1Smillert info->hlen = s->z_hlen;
430*3ab258a1Smillert info->total_in = s->z_total_in;
431*3ab258a1Smillert info->total_out = s->z_total_out;
432*3ab258a1Smillert }
433*3ab258a1Smillert
434*3ab258a1Smillert if (s->z_stream.state != NULL) {
435*3ab258a1Smillert /* inflateEnd() overwrites errno. */
436*3ab258a1Smillert (void)inflateEnd(&s->z_stream);
437*3ab258a1Smillert }
438*3ab258a1Smillert
439*3ab258a1Smillert /*
440*3ab258a1Smillert * Check for the presence of additional files in the .zip.
441*3ab258a1Smillert * Do not remove the original if we cannot extract all the files.
442*3ab258a1Smillert */
443*3ab258a1Smillert s->z_eof = 0;
444*3ab258a1Smillert if (get_header(s, NULL, 0) == 0) {
445*3ab258a1Smillert errno = EEXIST;
446*3ab258a1Smillert error = -1;
447*3ab258a1Smillert }
448*3ab258a1Smillert
449*3ab258a1Smillert (void)close(s->z_fd);
450*3ab258a1Smillert
451*3ab258a1Smillert free(s);
452*3ab258a1Smillert
453*3ab258a1Smillert return error;
454*3ab258a1Smillert }
455