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 <[email protected]>
@@ -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++]);