Module Name:    src
Committed By:   christos
Date:           Mon Dec 21 17:17:02 UTC 2015

Modified Files:
        src/usr.bin/unzip: unzip.1 unzip.c

Log Message:
>From FreeBSD:
- Whitespace cleanup
- Pass a filename rather than fd to libarchive (should work with 2.8+)
- Accept zipfiles from stdin
- Extract common code from extract()/extract_stdout() to extract2fd() (pending)


To generate a diff of this commit:
cvs rdiff -u -r1.10 -r1.11 src/usr.bin/unzip/unzip.1
cvs rdiff -u -r1.21 -r1.22 src/usr.bin/unzip/unzip.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/unzip/unzip.1
diff -u src/usr.bin/unzip/unzip.1:1.10 src/usr.bin/unzip/unzip.1:1.11
--- src/usr.bin/unzip/unzip.1:1.10	Tue Mar 18 14:20:45 2014
+++ src/usr.bin/unzip/unzip.1	Mon Dec 21 12:17:02 2015
@@ -25,9 +25,9 @@
 .\" SUCH DAMAGE.
 .\"
 .\" $FreeBSD: revision 180125$
-.\" $NetBSD: unzip.1,v 1.10 2014/03/18 18:20:45 riastradh Exp $
+.\" $NetBSD: unzip.1,v 1.11 2015/12/21 17:17:02 christos Exp $
 .\"
-.Dd August 18, 2011
+.Dd December 21, 2015
 .Dt UNZIP 1
 .Os
 .Sh NAME
@@ -142,8 +142,8 @@ option should only affect files which ar
 zipfile's central directory.
 Since the
 .Xr archive 3
-library reads zipfiles sequentially, and does not use the central
-directory, that information is not available to the
+library does not provide access to that information, it is not available
+to the
 .Nm
 utility.
 Instead, the

Index: src/usr.bin/unzip/unzip.c
diff -u src/usr.bin/unzip/unzip.c:1.21 src/usr.bin/unzip/unzip.c:1.22
--- src/usr.bin/unzip/unzip.c:1.21	Thu Dec  3 15:01:19 2015
+++ src/usr.bin/unzip/unzip.c	Mon Dec 21 12:17:02 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: unzip.c,v 1.21 2015/12/03 20:01:19 christos Exp $ */
+/* $NetBSD: unzip.c,v 1.22 2015/12/21 17:17:02 christos Exp $ */
 
 /*-
  * Copyright (c) 2009, 2010 Joerg Sonnenberger <jo...@netbsd.org>
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: unzip.c,v 1.21 2015/12/03 20:01:19 christos Exp $");
+__RCSID("$NetBSD: unzip.c,v 1.22 2015/12/21 17:17:02 christos Exp $");
 
 #include <sys/queue.h>
 #include <sys/stat.h>
@@ -436,7 +436,7 @@ handle_existing_file(char **path)
 			(void)unlink(*path);
 			return 1;
 		case 'N':
-			n_opt = 1;			
+			n_opt = 1;
 			/* FALL THROUGH */
 		case 'n':
 			return -1;
@@ -486,6 +486,92 @@ check_binary(const unsigned char *buf, s
 }
 
 /*
+ * Extract to a file descriptor
+ */
+static int
+extract2fd(struct archive *a, char *pathname, int fd)
+{
+	int cr, text, warn;
+	ssize_t len;
+	unsigned char *p, *q, *end;
+
+	text = a_opt;
+	warn = 0;
+	cr = 0;
+
+	/* loop over file contents and write to fd */
+	for (int n = 0; ; n++) {
+		if (fd != STDOUT_FILENO)
+			if (tty && (n % 4) == 0)
+				info(" %c\b\b", spinner[(n / 4) % sizeof spinner]);
+
+		len = archive_read_data(a, buffer, sizeof buffer);
+
+		if (len < 0)
+			ac(len);
+
+		/* left over CR from previous buffer */
+		if (a_opt && cr) {
+			if (len == 0 || buffer[0] != '\n')
+				if (write(fd, "\r", 1) != 1)
+					error("write('%s')", pathname);
+			cr = 0;
+		}
+
+		/* EOF */
+		if (len == 0)
+			break;
+		end = buffer + len;
+
+		/*
+		 * Detect whether this is a text file.  The correct way to
+		 * do this is to check the least significant bit of the
+		 * "internal file attributes" field of the corresponding
+		 * file header in the central directory, but libarchive
+		 * does not provide access to this field, so we have to
+		 * guess by looking for non-ASCII characters in the
+		 * buffer.  Hopefully we won't guess wrong.  If we do
+		 * guess wrong, we print a warning message later.
+		 */
+		if (a_opt && n == 0) {
+			if (check_binary(buffer, len))
+				text = 0;
+		}
+
+		/* simple case */
+		if (!a_opt || !text) {
+			if (write(fd, buffer, len) != len)
+				error("write('%s')", pathname);
+			continue;
+		}
+
+		/* hard case: convert \r\n to \n (sigh...) */
+		for (p = buffer; p < end; p = q + 1) {
+			for (q = p; q < end; q++) {
+				if (!warn && BYTE_IS_BINARY(*q)) {
+					warningx("%s may be corrupted due"
+					    " to weak text file detection"
+					    " heuristic", pathname);
+					warn = 1;
+				}
+				if (q[0] != '\r')
+					continue;
+				if (&q[1] == end) {
+					cr = 1;
+					break;
+				}
+				if (q[1] == '\n')
+					break;
+			}
+			if (write(fd, p, q - p) != q - p)
+				error("write('%s')", pathname);
+		}
+	}
+
+	return text;
+}
+
+/*
  * Extract a regular file.
  */
 static void
@@ -495,9 +581,7 @@ extract_file(struct archive *a, struct a
 	time_t mtime;
 	struct stat sb;
 	struct timeval tv[2];
-	int cr, fd, text, warn, check;
-	ssize_t len;
-	unsigned char *p, *q, *end;
+	int fd, check, text;
 	const char *linkname;
 
 	mode = archive_entry_mode(e) & 0777;
@@ -561,77 +645,10 @@ recheck:
 	if ((fd = open(*path, O_RDWR|O_CREAT|O_TRUNC, mode)) < 0)
 		error("open('%s')", *path);
 
-	/* loop over file contents and write to disk */
 	info(" extracting: %s", *path);
-	text = a_opt;
-	warn = 0;
-	cr = 0;
-	for (int n = 0; ; n++) {
-		if (tty && (n % 4) == 0)
-			info(" %c\b\b", spinner[(n / 4) % sizeof spinner]);
-
-		len = archive_read_data(a, buffer, sizeof buffer);
-
-		if (len < 0)
-			ac(len);
-
-		/* left over CR from previous buffer */
-		if (a_opt && cr) {
-			if (len == 0 || buffer[0] != '\n')
-				if (write(fd, "\r", 1) != 1)
-					error("write('%s')", *path);
-			cr = 0;
-		}
-
-		/* EOF */
-		if (len == 0)
-			break;
-		end = buffer + len;
-
-		/*
-		 * Detect whether this is a text file.  The correct way to
-		 * do this is to check the least significant bit of the
-		 * "internal file attributes" field of the corresponding
-		 * file header in the central directory, but libarchive
-		 * does not read the central directory, so we have to
-		 * guess by looking for non-ASCII characters in the
-		 * buffer.  Hopefully we won't guess wrong.  If we do
-		 * guess wrong, we print a warning message later.
-		 */
-		if (a_opt && n == 0) {
-			if (check_binary(buffer, len))
-				text = 0;
-		}
 
-		/* simple case */
-		if (!a_opt || !text) {
-			if (write(fd, buffer, len) != len)
-				error("write('%s')", *path);
-			continue;
-		}
+	text = extract2fd(a, *path, fd);
 
-		/* hard case: convert \r\n to \n (sigh...) */
-		for (p = buffer; p < end; p = q + 1) {
-			for (q = p; q < end; q++) {
-				if (!warn && BYTE_IS_BINARY(*q)) {
-					warningx("%s may be corrupted due"
-					    " to weak text file detection"
-					    " heuristic", *path);
-					warn = 1;
-				}
-				if (q[0] != '\r')
-					continue;
-				if (&q[1] == end) {
-					cr = 1;
-					break;
-				}
-				if (q[1] == '\n')
-					break;
-			}
-			if (write(fd, p, q - p) != q - p)
-				error("write('%s')", *path);
-		}
-	}
 	if (tty)
 		info("  \b\b");
 	if (text)
@@ -729,9 +746,6 @@ extract_stdout(struct archive *a, struct
 {
 	char *pathname;
 	mode_t filetype;
-	int cr, text, warn;
-	ssize_t len;
-	unsigned char *p, *q, *end;
 
 	pathname = pathdup(archive_entry_pathname(e));
 	filetype = archive_entry_filetype(e);
@@ -761,77 +775,7 @@ extract_stdout(struct archive *a, struct
 	if (c_opt)
 		info("x %s\n", pathname);
 
-	text = a_opt;
-	warn = 0;
-	cr = 0;
-	for (int n = 0; ; n++) {
-		len = archive_read_data(a, buffer, sizeof buffer);
-
-		if (len < 0)
-			ac(len);
-
-		/* left over CR from previous buffer */
-		if (a_opt && cr) {
-			if (len == 0 || buffer[0] != '\n') {
-				if (fwrite("\r", 1, 1, stderr) != 1)
-					error("write('%s')", pathname);
-			}
-			cr = 0;
-		}
-
-		/* EOF */
-		if (len == 0)
-			break;
-		end = buffer + len;
-
-		/*
-		 * Detect whether this is a text file.  The correct way to
-		 * do this is to check the least significant bit of the
-		 * "internal file attributes" field of the corresponding
-		 * file header in the central directory, but libarchive
-		 * does not read the central directory, so we have to
-		 * guess by looking for non-ASCII characters in the
-		 * buffer.  Hopefully we won't guess wrong.  If we do
-		 * guess wrong, we print a warning message later.
-		 */
-		if (a_opt && n == 0) {
-			for (p = buffer; p < end; ++p) {
-				if (!isascii((unsigned char)*p)) {
-					text = 0;
-					break;
-				}
-			}
-		}
-
-		/* simple case */
-		if (!a_opt || !text) {
-			if (fwrite(buffer, 1, len, stdout) != (size_t)len)
-				error("write('%s')", pathname);
-			continue;
-		}
-
-		/* hard case: convert \r\n to \n (sigh...) */
-		for (p = buffer; p < end; p = q + 1) {
-			for (q = p; q < end; q++) {
-				if (!warn && !isascii(*q)) {
-					warningx("%s may be corrupted due"
-					    " to weak text file detection"
-					    " heuristic", pathname);
-					warn = 1;
-				}
-				if (q[0] != '\r')
-					continue;
-				if (&q[1] == end) {
-					cr = 1;
-					break;
-				}
-				if (q[1] == '\n')
-					break;
-			}
-			if (fwrite(p, 1, q - p, stdout) != (size_t)(q - p))
-				error("write('%s')", pathname);
-		}
-	}
+	(void)extract2fd(a, pathname, STDOUT_FILENO);
 
 	free(pathname);
 }
@@ -897,7 +841,6 @@ test(struct archive *a, struct archive_e
 	return error_count;
 }
 
-
 /*
  * Main loop: open the zipfile, iterate over its contents and decide what
  * to do with each entry.
@@ -907,15 +850,14 @@ unzip(const char *fn)
 {
 	struct archive *a;
 	struct archive_entry *e;
-	int fd, ret;
+	int ret;
 	uintmax_t total_size, file_count, error_count;
 
-	if ((fd = open(fn, O_RDONLY)) < 0)
-		error("%s", fn);
+	if ((a = archive_read_new()) == NULL)
+		error("archive_read_new failed");
 
-	a = archive_read_new();
 	ac(archive_read_support_format_zip(a));
-	ac(archive_read_open_fd(a, fd, 8192));
+	ac(archive_read_open_filename(a, fn, 8192));
 
 	if (!q_opt && !p_opt)
 	    printf("Archive:  %s\n", fn);
@@ -963,9 +905,6 @@ unzip(const char *fn)
 	ac(archive_read_close(a));
 	(void)archive_read_finish(a);
 
-	if (close(fd) != 0)
-		error("%s", fn);
-
 	if (t_opt) {
 		if (error_count > 0) {
 			errorx("%ju checksum error(s) found.", error_count);
@@ -1080,6 +1019,9 @@ main(int argc, char *argv[])
 		usage();
 	zipfile = argv[nopts++];
 
+	if (strcmp(zipfile, "-") == 0)
+		zipfile = NULL; /* STDIN */
+
 	while (nopts < argc && *argv[nopts] != '-')
 		add_pattern(&include, argv[nopts++]);
 

Reply via email to