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++]);