xref: /openbsd-src/usr.bin/compress/zipopen.c (revision 3ab258a16e35bc5259bb711e9cca5c9e26d26fc9)
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