unzip.c revision 214137
1/*-
2 * Copyright (c) 2009 Joerg Sonnenberger <joerg@NetBSD.org>
3 * Copyright (c) 2007-2008 Dag-Erling Co�dan Sm�rgrav
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer
11 *    in this position and unchanged.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD: head/usr.bin/unzip/unzip.c 214137 2010-10-21 17:05:15Z glebius $
29 *
30 * This file would be much shorter if we didn't care about command-line
31 * compatibility with Info-ZIP's UnZip, which requires us to duplicate
32 * parts of libarchive in order to gain more detailed control of its
33 * behaviour for the purpose of implementing the -n, -o, -L and -a
34 * options.
35 */
36
37#include <sys/queue.h>
38#include <sys/stat.h>
39
40#include <ctype.h>
41#include <errno.h>
42#include <fcntl.h>
43#include <fnmatch.h>
44#include <stdarg.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <unistd.h>
49
50#include <archive.h>
51#include <archive_entry.h>
52
53/* command-line options */
54static int		 a_opt;		/* convert EOL */
55static int		 C_opt;		/* match case-insensitively */
56static int		 c_opt;		/* extract to stdout */
57static const char	*d_arg;		/* directory */
58static int		 f_opt;		/* update existing files only */
59static int		 j_opt;		/* junk directories */
60static int		 L_opt;		/* lowercase names */
61static int		 n_opt;		/* never overwrite */
62static int		 o_opt;		/* always overwrite */
63static int		 p_opt;		/* extract to stdout, quiet */
64static int		 q_opt;		/* quiet */
65static int		 t_opt;		/* test */
66static int		 u_opt;		/* update */
67static int		 v_opt;		/* verbose/list */
68
69/* time when unzip started */
70static time_t		 now;
71
72/* debug flag */
73static int		 unzip_debug;
74
75/* running on tty? */
76static int		 tty;
77
78/* convenience macro */
79/* XXX should differentiate between ARCHIVE_{WARN,FAIL,RETRY} */
80#define ac(call)						\
81	do {							\
82		int acret = (call);				\
83		if (acret != ARCHIVE_OK)			\
84			errorx("%s", archive_error_string(a));	\
85	} while (0)
86
87/*
88 * Indicates that last info() did not end with EOL.  This helps error() et
89 * al. avoid printing an error message on the same line as an incomplete
90 * informational message.
91 */
92static int noeol;
93
94/* fatal error message + errno */
95static void
96error(const char *fmt, ...)
97{
98	va_list ap;
99
100	if (noeol)
101		fprintf(stdout, "\n");
102	fflush(stdout);
103	fprintf(stderr, "unzip: ");
104	va_start(ap, fmt);
105	vfprintf(stderr, fmt, ap);
106	va_end(ap);
107	fprintf(stderr, ": %s\n", strerror(errno));
108	exit(1);
109}
110
111/* fatal error message, no errno */
112static void
113errorx(const char *fmt, ...)
114{
115	va_list ap;
116
117	if (noeol)
118		fprintf(stdout, "\n");
119	fflush(stdout);
120	fprintf(stderr, "unzip: ");
121	va_start(ap, fmt);
122	vfprintf(stderr, fmt, ap);
123	va_end(ap);
124	fprintf(stderr, "\n");
125	exit(1);
126}
127
128#if 0
129/* non-fatal error message + errno */
130static void
131warning(const char *fmt, ...)
132{
133	va_list ap;
134
135	if (noeol)
136		fprintf(stdout, "\n");
137	fflush(stdout);
138	fprintf(stderr, "unzip: ");
139	va_start(ap, fmt);
140	vfprintf(stderr, fmt, ap);
141	va_end(ap);
142	fprintf(stderr, ": %s\n", strerror(errno));
143}
144#endif
145
146/* non-fatal error message, no errno */
147static void
148warningx(const char *fmt, ...)
149{
150	va_list ap;
151
152	if (noeol)
153		fprintf(stdout, "\n");
154	fflush(stdout);
155	fprintf(stderr, "unzip: ");
156	va_start(ap, fmt);
157	vfprintf(stderr, fmt, ap);
158	va_end(ap);
159	fprintf(stderr, "\n");
160}
161
162/* informational message (if not -q) */
163static void
164info(const char *fmt, ...)
165{
166	va_list ap;
167
168	if (q_opt && !unzip_debug)
169		return;
170	va_start(ap, fmt);
171	vfprintf(stdout, fmt, ap);
172	va_end(ap);
173	fflush(stdout);
174
175	if (*fmt == '\0')
176		noeol = 1;
177	else
178		noeol = fmt[strlen(fmt) - 1] != '\n';
179}
180
181/* debug message (if unzip_debug) */
182static void
183debug(const char *fmt, ...)
184{
185	va_list ap;
186
187	if (!unzip_debug)
188		return;
189	va_start(ap, fmt);
190	vfprintf(stderr, fmt, ap);
191	va_end(ap);
192	fflush(stderr);
193
194	if (*fmt == '\0')
195		noeol = 1;
196	else
197		noeol = fmt[strlen(fmt) - 1] != '\n';
198}
199
200/* duplicate a path name, possibly converting to lower case */
201static char *
202pathdup(const char *path)
203{
204	char *str;
205	size_t i, len;
206
207	len = strlen(path);
208	while (len && path[len - 1] == '/')
209		len--;
210	if ((str = malloc(len + 1)) == NULL) {
211		errno = ENOMEM;
212		error("malloc()");
213	}
214	if (L_opt) {
215		for (i = 0; i < len; ++i)
216			str[i] = tolower((unsigned char)path[i]);
217	} else {
218		memcpy(str, path, len);
219	}
220	str[len] = '\0';
221
222	return (str);
223}
224
225/* concatenate two path names */
226static char *
227pathcat(const char *prefix, const char *path)
228{
229	char *str;
230	size_t prelen, len;
231
232	prelen = prefix ? strlen(prefix) + 1 : 0;
233	len = strlen(path) + 1;
234	if ((str = malloc(prelen + len)) == NULL) {
235		errno = ENOMEM;
236		error("malloc()");
237	}
238	if (prefix) {
239		memcpy(str, prefix, prelen);	/* includes zero */
240		str[prelen - 1] = '/';		/* splat zero */
241	}
242	memcpy(str + prelen, path, len);	/* includes zero */
243
244	return (str);
245}
246
247/*
248 * Pattern lists for include / exclude processing
249 */
250struct pattern {
251	STAILQ_ENTRY(pattern) link;
252	char pattern[];
253};
254
255STAILQ_HEAD(pattern_list, pattern);
256static struct pattern_list include = STAILQ_HEAD_INITIALIZER(include);
257static struct pattern_list exclude = STAILQ_HEAD_INITIALIZER(exclude);
258
259/*
260 * Add an entry to a pattern list
261 */
262static void
263add_pattern(struct pattern_list *list, const char *pattern)
264{
265	struct pattern *entry;
266	size_t len;
267
268	debug("adding pattern '%s'\n", pattern);
269	len = strlen(pattern);
270	if ((entry = malloc(sizeof *entry + len + 1)) == NULL) {
271		errno = ENOMEM;
272		error("malloc()");
273	}
274	memcpy(entry->pattern, pattern, len + 1);
275	STAILQ_INSERT_TAIL(list, entry, link);
276}
277
278/*
279 * Match a string against a list of patterns
280 */
281static int
282match_pattern(struct pattern_list *list, const char *str)
283{
284	struct pattern *entry;
285
286	STAILQ_FOREACH(entry, list, link) {
287		if (fnmatch(entry->pattern, str, C_opt ? FNM_CASEFOLD : 0) == 0)
288			return (1);
289	}
290	return (0);
291}
292
293/*
294 * Verify that a given pathname is in the include list and not in the
295 * exclude list.
296 */
297static int
298accept_pathname(const char *pathname)
299{
300
301	if (!STAILQ_EMPTY(&include) && !match_pattern(&include, pathname))
302		return (0);
303	if (!STAILQ_EMPTY(&exclude) && match_pattern(&exclude, pathname))
304		return (0);
305	return (1);
306}
307
308/*
309 * Create the specified directory with the specified mode, taking certain
310 * precautions on they way.
311 */
312static void
313make_dir(const char *path, int mode)
314{
315	struct stat sb;
316
317	if (lstat(path, &sb) == 0) {
318		if (S_ISDIR(sb.st_mode))
319			return;
320		/*
321		 * Normally, we should either ask the user about removing
322		 * the non-directory of the same name as a directory we
323		 * wish to create, or respect the -n or -o command-line
324		 * options.  However, this may lead to a later failure or
325		 * even compromise (if this non-directory happens to be a
326		 * symlink to somewhere unsafe), so we don't.
327		 */
328
329		/*
330		 * Don't check unlink() result; failure will cause mkdir()
331		 * to fail later, which we will catch.
332		 */
333		(void)unlink(path);
334	}
335	if (mkdir(path, mode) != 0 && errno != EEXIST)
336		error("mkdir('%s')", path);
337}
338
339/*
340 * Ensure that all directories leading up to (but not including) the
341 * specified path exist.
342 *
343 * XXX inefficient + modifies the file in-place
344 */
345static void
346make_parent(char *path)
347{
348	struct stat sb;
349	char *sep;
350
351	sep = strrchr(path, '/');
352	if (sep == NULL || sep == path)
353		return;
354	*sep = '\0';
355	if (lstat(path, &sb) == 0) {
356		if (S_ISDIR(sb.st_mode)) {
357			*sep = '/';
358			return;
359		}
360		unlink(path);
361	}
362	make_parent(path);
363	mkdir(path, 0755);
364	*sep = '/';
365
366#if 0
367	for (sep = path; (sep = strchr(sep, '/')) != NULL; sep++) {
368		/* root in case of absolute d_arg */
369		if (sep == path)
370			continue;
371		*sep = '\0';
372		make_dir(path, 0755);
373		*sep = '/';
374	}
375#endif
376}
377
378/*
379 * Extract a directory.
380 */
381static void
382extract_dir(struct archive *a, struct archive_entry *e, const char *path)
383{
384	int mode;
385
386	mode = archive_entry_mode(e) & 0777;
387	if (mode == 0)
388		mode = 0755;
389
390	/*
391	 * Some zipfiles contain directories with weird permissions such
392	 * as 0644 or 0444.  This can cause strange issues such as being
393	 * unable to extract files into the directory we just created, or
394	 * the user being unable to remove the directory later without
395	 * first manually changing its permissions.  Therefore, we whack
396	 * the permissions into shape, assuming that the user wants full
397	 * access and that anyone who gets read access also gets execute
398	 * access.
399	 */
400	mode |= 0700;
401	if (mode & 0040)
402		mode |= 0010;
403	if (mode & 0004)
404		mode |= 0001;
405
406	info("d %s\n", path);
407	make_dir(path, mode);
408	ac(archive_read_data_skip(a));
409}
410
411static unsigned char buffer[8192];
412static char spinner[] = { '|', '/', '-', '\\' };
413
414static int
415handle_existing_file(char **path)
416{
417	size_t alen;
418	ssize_t len;
419	char buf[4];
420
421	for (;;) {
422		fprintf(stderr,
423		    "replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ",
424		    *path);
425		if (fgets(buf, sizeof(buf), stdin) == 0) {
426			clearerr(stdin);
427			printf("NULL\n(EOF or read error, "
428			    "treating as \"[N]one\"...)\n");
429			n_opt = 1;
430			return -1;
431		}
432		switch (*buf) {
433		case 'A':
434			o_opt = 1;
435			/* FALLTHROUGH */
436		case 'y':
437		case 'Y':
438			(void)unlink(*path);
439			return 1;
440		case 'N':
441			n_opt = 1;
442			/* FALLTHROUGH */
443		case 'n':
444			return -1;
445		case 'r':
446		case 'R':
447			printf("New name: ");
448			fflush(stdout);
449			free(*path);
450			*path = NULL;
451			alen = 0;
452			len = getdelim(path, &alen, '\n', stdin);
453			if ((*path)[len - 1] == '\n')
454				(*path)[len - 1] = '\0';
455			return 0;
456		default:
457			break;
458		}
459	}
460}
461
462/*
463 * Extract a regular file.
464 */
465static void
466extract_file(struct archive *a, struct archive_entry *e, char **path)
467{
468	int mode;
469	time_t mtime;
470	struct stat sb;
471	struct timeval tv[2];
472	int cr, fd, text, warn, check;
473	ssize_t len;
474	unsigned char *p, *q, *end;
475
476	mode = archive_entry_mode(e) & 0777;
477	if (mode == 0)
478		mode = 0644;
479	mtime = archive_entry_mtime(e);
480
481	/* look for existing file of same name */
482recheck:
483	if (lstat(*path, &sb) == 0) {
484		if (u_opt || f_opt) {
485			/* check if up-to-date */
486			if (S_ISREG(sb.st_mode) && sb.st_mtime >= mtime)
487				return;
488			(void)unlink(*path);
489		} else if (o_opt) {
490			/* overwrite */
491			(void)unlink(*path);
492		} else if (n_opt) {
493			/* do not overwrite */
494			return;
495		} else {
496			check = handle_existing_file(path);
497			if (check == 0)
498				goto recheck;
499			if (check == -1)
500				return; /* do not overwrite */
501		}
502	} else {
503		if (f_opt)
504			return;
505	}
506
507	if ((fd = open(*path, O_RDWR|O_CREAT|O_TRUNC, mode)) < 0)
508		error("open('%s')", *path);
509
510	/* loop over file contents and write to disk */
511	info(" extracting: %s", *path);
512	text = a_opt;
513	warn = 0;
514	cr = 0;
515	for (int n = 0; ; n++) {
516		if (tty && (n % 4) == 0)
517			info(" %c\b\b", spinner[(n / 4) % sizeof spinner]);
518
519		len = archive_read_data(a, buffer, sizeof buffer);
520
521		if (len < 0)
522			ac(len);
523
524		/* left over CR from previous buffer */
525		if (a_opt && cr) {
526			if (len == 0 || buffer[0] != '\n')
527				if (write(fd, "\r", 1) != 1)
528					error("write('%s')", *path);
529			cr = 0;
530		}
531
532		/* EOF */
533		if (len == 0)
534			break;
535		end = buffer + len;
536
537		/*
538		 * Detect whether this is a text file.  The correct way to
539		 * do this is to check the least significant bit of the
540		 * "internal file attributes" field of the corresponding
541		 * file header in the central directory, but libarchive
542		 * does not read the central directory, so we have to
543		 * guess by looking for non-ASCII characters in the
544		 * buffer.  Hopefully we won't guess wrong.  If we do
545		 * guess wrong, we print a warning message later.
546		 */
547		if (a_opt && n == 0) {
548			for (p = buffer; p < end; ++p) {
549				if (!isascii((unsigned char)*p)) {
550					text = 0;
551					break;
552				}
553			}
554		}
555
556		/* simple case */
557		if (!a_opt || !text) {
558			if (write(fd, buffer, len) != len)
559				error("write('%s')", *path);
560			continue;
561		}
562
563		/* hard case: convert \r\n to \n (sigh...) */
564		for (p = buffer; p < end; p = q + 1) {
565			for (q = p; q < end; q++) {
566				if (!warn && !isascii(*q)) {
567					warningx("%s may be corrupted due"
568					    " to weak text file detection"
569					    " heuristic", *path);
570					warn = 1;
571				}
572				if (q[0] != '\r')
573					continue;
574				if (&q[1] == end) {
575					cr = 1;
576					break;
577				}
578				if (q[1] == '\n')
579					break;
580			}
581			if (write(fd, p, q - p) != q - p)
582				error("write('%s')", *path);
583		}
584	}
585	if (tty)
586		info("  \b\b");
587	if (text)
588		info(" (text)");
589	info("\n");
590
591	/* set access and modification time */
592	tv[0].tv_sec = now;
593	tv[0].tv_usec = 0;
594	tv[1].tv_sec = mtime;
595	tv[1].tv_usec = 0;
596	if (futimes(fd, tv) != 0)
597		error("utimes('%s')", *path);
598	if (close(fd) != 0)
599		error("close('%s')", *path);
600}
601
602/*
603 * Extract a zipfile entry: first perform some sanity checks to ensure
604 * that it is either a directory or a regular file and that the path is
605 * not absolute and does not try to break out of the current directory;
606 * then call either extract_dir() or extract_file() as appropriate.
607 *
608 * This is complicated a bit by the various ways in which we need to
609 * manipulate the path name.  Case conversion (if requested by the -L
610 * option) happens first, but the include / exclude patterns are applied
611 * to the full converted path name, before the directory part of the path
612 * is removed in accordance with the -j option.  Sanity checks are
613 * intentionally done earlier than they need to be, so the user will get a
614 * warning about insecure paths even for files or directories which
615 * wouldn't be extracted anyway.
616 */
617static void
618extract(struct archive *a, struct archive_entry *e)
619{
620	char *pathname, *realpathname;
621	mode_t filetype;
622	char *p, *q;
623
624	pathname = pathdup(archive_entry_pathname(e));
625	filetype = archive_entry_filetype(e);
626
627	/* sanity checks */
628	if (pathname[0] == '/' ||
629	    strncmp(pathname, "../", 3) == 0 ||
630	    strstr(pathname, "/../") != NULL) {
631		warningx("skipping insecure entry '%s'", pathname);
632		ac(archive_read_data_skip(a));
633		free(pathname);
634		return;
635	}
636
637	/* I don't think this can happen in a zipfile.. */
638	if (!S_ISDIR(filetype) && !S_ISREG(filetype)) {
639		warningx("skipping non-regular entry '%s'", pathname);
640		ac(archive_read_data_skip(a));
641		free(pathname);
642		return;
643	}
644
645	/* skip directories in -j case */
646	if (S_ISDIR(filetype) && j_opt) {
647		ac(archive_read_data_skip(a));
648		free(pathname);
649		return;
650	}
651
652	/* apply include / exclude patterns */
653	if (!accept_pathname(pathname)) {
654		ac(archive_read_data_skip(a));
655		free(pathname);
656		return;
657	}
658
659	/* apply -j and -d */
660	if (j_opt) {
661		for (p = q = pathname; *p; ++p)
662			if (*p == '/')
663				q = p + 1;
664		realpathname = pathcat(d_arg, q);
665	} else {
666		realpathname = pathcat(d_arg, pathname);
667	}
668
669	/* ensure that parent directory exists */
670	make_parent(realpathname);
671
672	if (S_ISDIR(filetype))
673		extract_dir(a, e, realpathname);
674	else
675		extract_file(a, e, &realpathname);
676
677	free(realpathname);
678	free(pathname);
679}
680
681static void
682extract_stdout(struct archive *a, struct archive_entry *e)
683{
684	char *pathname;
685	mode_t filetype;
686	int cr, text, warn;
687	ssize_t len;
688	unsigned char *p, *q, *end;
689
690	pathname = pathdup(archive_entry_pathname(e));
691	filetype = archive_entry_filetype(e);
692
693	/* I don't think this can happen in a zipfile.. */
694	if (!S_ISDIR(filetype) && !S_ISREG(filetype)) {
695		warningx("skipping non-regular entry '%s'", pathname);
696		ac(archive_read_data_skip(a));
697		free(pathname);
698		return;
699	}
700
701	/* skip directories in -j case */
702	if (S_ISDIR(filetype)) {
703		ac(archive_read_data_skip(a));
704		free(pathname);
705		return;
706	}
707
708	/* apply include / exclude patterns */
709	if (!accept_pathname(pathname)) {
710		ac(archive_read_data_skip(a));
711		free(pathname);
712		return;
713	}
714
715	if (c_opt)
716		info("x %s\n", pathname);
717
718	text = a_opt;
719	warn = 0;
720	cr = 0;
721	for (int n = 0; ; n++) {
722		len = archive_read_data(a, buffer, sizeof buffer);
723
724		if (len < 0)
725			ac(len);
726
727		/* left over CR from previous buffer */
728		if (a_opt && cr) {
729			if (len == 0 || buffer[0] != '\n') {
730				if (fwrite("\r", 1, 1, stderr) != 1)
731					error("write('%s')", pathname);
732			}
733			cr = 0;
734		}
735
736		/* EOF */
737		if (len == 0)
738			break;
739		end = buffer + len;
740
741		/*
742		 * Detect whether this is a text file.  The correct way to
743		 * do this is to check the least significant bit of the
744		 * "internal file attributes" field of the corresponding
745		 * file header in the central directory, but libarchive
746		 * does not read the central directory, so we have to
747		 * guess by looking for non-ASCII characters in the
748		 * buffer.  Hopefully we won't guess wrong.  If we do
749		 * guess wrong, we print a warning message later.
750		 */
751		if (a_opt && n == 0) {
752			for (p = buffer; p < end; ++p) {
753				if (!isascii((unsigned char)*p)) {
754					text = 0;
755					break;
756				}
757			}
758		}
759
760		/* simple case */
761		if (!a_opt || !text) {
762			if (fwrite(buffer, 1, len, stdout) != (size_t)len)
763				error("write('%s')", pathname);
764			continue;
765		}
766
767		/* hard case: convert \r\n to \n (sigh...) */
768		for (p = buffer; p < end; p = q + 1) {
769			for (q = p; q < end; q++) {
770				if (!warn && !isascii(*q)) {
771					warningx("%s may be corrupted due"
772					    " to weak text file detection"
773					    " heuristic", pathname);
774					warn = 1;
775				}
776				if (q[0] != '\r')
777					continue;
778				if (&q[1] == end) {
779					cr = 1;
780					break;
781				}
782				if (q[1] == '\n')
783					break;
784			}
785			if (fwrite(p, 1, q - p, stdout) != (size_t)(q - p))
786				error("write('%s')", pathname);
787		}
788	}
789
790	free(pathname);
791}
792
793/*
794 * Print the name of an entry to stdout.
795 */
796static void
797list(struct archive *a, struct archive_entry *e)
798{
799	char buf[20];
800	time_t mtime;
801
802	mtime = archive_entry_mtime(e);
803	strftime(buf, sizeof(buf), "%m-%d-%g %R", localtime(&mtime));
804
805	if (v_opt == 1) {
806		printf(" %8ju  %s   %s\n",
807		    (uintmax_t)archive_entry_size(e),
808		    buf, archive_entry_pathname(e));
809	} else if (v_opt == 2) {
810		printf("%8ju  Stored  %7ju   0%%  %s  %08x  %s\n",
811		    (uintmax_t)archive_entry_size(e),
812		    (uintmax_t)archive_entry_size(e),
813		    buf,
814		    0U,
815		    archive_entry_pathname(e));
816	}
817	ac(archive_read_data_skip(a));
818}
819
820/*
821 * Extract to memory to check CRC
822 */
823static int
824test(struct archive *a, struct archive_entry *e)
825{
826	ssize_t len;
827	int error_count;
828
829	error_count = 0;
830	if (S_ISDIR(archive_entry_filetype(e)))
831		return 0;
832
833	info("    testing: %s\t", archive_entry_pathname(e));
834	while ((len = archive_read_data(a, buffer, sizeof buffer)) > 0)
835		/* nothing */;
836	if (len < 0) {
837		info(" %s\n", archive_error_string(a));
838		++error_count;
839	} else {
840		info(" OK\n");
841	}
842
843	/* shouldn't be necessary, but it doesn't hurt */
844	ac(archive_read_data_skip(a));
845
846	return error_count;
847}
848
849
850/*
851 * Main loop: open the zipfile, iterate over its contents and decide what
852 * to do with each entry.
853 */
854static void
855unzip(const char *fn)
856{
857	struct archive *a;
858	struct archive_entry *e;
859	int fd, ret;
860	uintmax_t total_size, file_count, error_count;
861
862	if (strcmp(fn, "-") == 0)
863		fd = STDIN_FILENO;
864	else if ((fd = open(fn, O_RDONLY)) < 0)
865		error("%s", fn);
866
867	if ((a = archive_read_new()) == NULL)
868		error("archive_read_new failed");
869
870	ac(archive_read_support_format_zip(a));
871	ac(archive_read_open_fd(a, fd, 8192));
872
873	if (!p_opt && !q_opt)
874		printf("Archive:  %s\n", fn);
875	if (v_opt == 1) {
876		printf("  Length     Date   Time    Name\n");
877		printf(" --------    ----   ----    ----\n");
878	} else if (v_opt == 2) {
879		printf(" Length   Method    Size  Ratio   Date   Time   CRC-32    Name\n");
880		printf("--------  ------  ------- -----   ----   ----   ------    ----\n");
881	}
882
883	total_size = 0;
884	file_count = 0;
885	error_count = 0;
886	for (;;) {
887		ret = archive_read_next_header(a, &e);
888		if (ret == ARCHIVE_EOF)
889			break;
890		ac(ret);
891		if (t_opt)
892			error_count += test(a, e);
893		else if (v_opt)
894			list(a, e);
895		else if (p_opt || c_opt)
896			extract_stdout(a, e);
897		else
898			extract(a, e);
899
900		total_size += archive_entry_size(e);
901		++file_count;
902	}
903
904	if (v_opt == 1) {
905		printf(" --------                   -------\n");
906		printf(" %8ju                   %ju file%s\n",
907		    total_size, file_count, file_count != 1 ? "s" : "");
908	} else if (v_opt == 2) {
909		printf("--------          -------  ---                            -------\n");
910		printf("%8ju          %7ju   0%%                            %ju file%s\n",
911		    total_size, total_size, file_count,
912		    file_count != 1 ? "s" : "");
913	}
914
915	ac(archive_read_close(a));
916	(void)archive_read_finish(a);
917
918	if (fd != STDIN_FILENO && close(fd) != 0)
919		error("%s", fn);
920
921	if (t_opt) {
922		if (error_count > 0) {
923			errorx("%d checksum error(s) found.", error_count);
924		}
925		else {
926			printf("No errors detected in compressed data of %s.\n",
927			       fn);
928		}
929	}
930}
931
932static void
933usage(void)
934{
935
936	fprintf(stderr, "usage: unzip [-aCcfjLlnopqtuv] [-d dir] [-x pattern] zipfile\n");
937	exit(1);
938}
939
940static int
941getopts(int argc, char *argv[])
942{
943	int opt;
944
945	optreset = optind = 1;
946	while ((opt = getopt(argc, argv, "aCcd:fjLlnopqtuvx:")) != -1)
947		switch (opt) {
948		case 'a':
949			a_opt = 1;
950			break;
951		case 'C':
952			C_opt = 1;
953			break;
954		case 'c':
955			c_opt = 1;
956			break;
957		case 'd':
958			d_arg = optarg;
959			break;
960		case 'f':
961			f_opt = 1;
962			break;
963		case 'j':
964			j_opt = 1;
965			break;
966		case 'L':
967			L_opt = 1;
968			break;
969		case 'l':
970			if (v_opt == 0)
971				v_opt = 1;
972			break;
973		case 'n':
974			n_opt = 1;
975			break;
976		case 'o':
977			o_opt = 1;
978			q_opt = 1;
979			break;
980		case 'p':
981			p_opt = 1;
982			break;
983		case 'q':
984			q_opt = 1;
985			break;
986		case 't':
987			t_opt = 1;
988			break;
989		case 'u':
990			u_opt = 1;
991			break;
992		case 'v':
993			v_opt = 2;
994			break;
995		case 'x':
996			add_pattern(&exclude, optarg);
997			break;
998		default:
999			usage();
1000		}
1001
1002	return (optind);
1003}
1004
1005int
1006main(int argc, char *argv[])
1007{
1008	const char *zipfile;
1009	int nopts;
1010
1011	if (isatty(STDOUT_FILENO))
1012		tty = 1;
1013
1014	if (getenv("UNZIP_DEBUG") != NULL)
1015		unzip_debug = 1;
1016	for (int i = 0; i < argc; ++i)
1017		debug("%s%c", argv[i], (i < argc - 1) ? ' ' : '\n');
1018
1019	/*
1020	 * Info-ZIP's unzip(1) expects certain options to come before the
1021	 * zipfile name, and others to come after - though it does not
1022	 * enforce this.  For simplicity, we accept *all* options both
1023	 * before and after the zipfile name.
1024	 */
1025	nopts = getopts(argc, argv);
1026
1027	if (argc <= nopts)
1028		usage();
1029	zipfile = argv[nopts++];
1030
1031	while (nopts < argc && *argv[nopts] != '-')
1032		add_pattern(&include, argv[nopts++]);
1033
1034	nopts--; /* fake argv[0] */
1035	nopts += getopts(argc - nopts, argv + nopts);
1036
1037	if (n_opt + o_opt + u_opt > 1)
1038		errorx("-n, -o and -u are contradictory");
1039
1040	time(&now);
1041
1042	unzip(zipfile);
1043
1044	exit(0);
1045}
1046