From owner-svn-src-all@freebsd.org Fri Dec 11 23:52:09 2015 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id CC1FC9D7464; Fri, 11 Dec 2015 23:52:09 +0000 (UTC) (envelope-from ak@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id A77091534; Fri, 11 Dec 2015 23:52:09 +0000 (UTC) (envelope-from ak@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id tBBNq8f3055010; Fri, 11 Dec 2015 23:52:08 GMT (envelope-from ak@FreeBSD.org) Received: (from ak@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id tBBNq8x7055008; Fri, 11 Dec 2015 23:52:08 GMT (envelope-from ak@FreeBSD.org) Message-Id: <201512112352.tBBNq8x7055008@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: ak set sender to ak@FreeBSD.org using -f From: Alex Kozlov Date: Fri, 11 Dec 2015 23:52:08 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r292127 - head/usr.bin/unzip X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 11 Dec 2015 23:52:10 -0000 Author: ak (ports committer) Date: Fri Dec 11 23:52:08 2015 New Revision: 292127 URL: https://svnweb.freebsd.org/changeset/base/292127 Log: - Allow to extract symlinks - Implement 4-digit year format listing (-y option) - Improve detection of text files - Use %ju for error_count as it is unsigned Obtained from: NetBSD Approved by: des Modified: head/usr.bin/unzip/unzip.1 head/usr.bin/unzip/unzip.c Modified: head/usr.bin/unzip/unzip.1 ============================================================================== --- head/usr.bin/unzip/unzip.1 Fri Dec 11 23:46:33 2015 (r292126) +++ head/usr.bin/unzip/unzip.1 Fri Dec 11 23:52:08 2015 (r292127) @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 10, 2012 +.Dd December 12, 2015 .Dt UNZIP 1 .Os .Sh NAME @@ -33,7 +33,7 @@ .Nd extract files from a ZIP archive .Sh SYNOPSIS .Nm -.Op Fl aCcfjLlnopqtuv +.Op Fl aCcfjLlnopqtuvy .Op Fl d Ar dir .Ar zipfile .Sh DESCRIPTION @@ -102,6 +102,8 @@ content of the archive. .It Fl x Ar pattern Exclude files matching the pattern .Ar pattern . +.It Fl y +Print four digit years in listings instead of two. .It Fl Z Ar mode Emulate .Xr zipinfo 1L Modified: head/usr.bin/unzip/unzip.c ============================================================================== --- head/usr.bin/unzip/unzip.c Fri Dec 11 23:46:33 2015 (r292126) +++ head/usr.bin/unzip/unzip.c Fri Dec 11 23:52:08 2015 (r292127) @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2009 Joerg Sonnenberger + * Copyright (c) 2009, 2010 Joerg Sonnenberger * Copyright (c) 2007-2008 Dag-Erling Smørgrav * All rights reserved. * @@ -65,6 +65,7 @@ static int q_opt; /* quiet */ static int t_opt; /* test */ static int u_opt; /* update */ static int v_opt; /* verbose/list */ +static const char *y_str = ""; /* 4 digit year */ static int Z1_opt; /* zipinfo mode list files only */ /* debug flag */ @@ -461,6 +462,34 @@ handle_existing_file(char **path) } /* + * Detect binary files by a combination of character white list and + * black list. NUL bytes and other control codes without use in text files + * result directly in switching the file to binary mode. Otherwise, at least + * one white-listed byte has to be found. + * + * Black-listed: 0..6, 14..25, 28..31 + * White-listed: 9..10, 13, >= 32 + * + * See the proginfo/txtvsbin.txt in the zip sources for a detailed discussion. + */ +#define BYTE_IS_BINARY(x) ((x) < 32 && (0xf3ffc07fU & (1U << (x)))) +#define BYTE_IS_TEXT(x) ((x) >= 32 || (0x00002600U & (1U << (x)))) + +static int +check_binary(const unsigned char *buf, size_t len) +{ + int rv; + for (rv = 1; len--; ++buf) { + if (BYTE_IS_BINARY(*buf)) + return 1; + if (BYTE_IS_TEXT(*buf)) + rv = 0; + } + + return rv; +} + +/* * Extract a regular file. */ static void @@ -472,6 +501,7 @@ extract_file(struct archive *a, struct a struct timespec ts[2]; int cr, fd, text, warn, check; ssize_t len; + const char *linkname; unsigned char *p, *q, *end; mode = archive_entry_mode(e) & 0777; @@ -485,7 +515,7 @@ recheck: if (lstat(*path, &sb) == 0) { if (u_opt || f_opt) { /* check if up-to-date */ - if (S_ISREG(sb.st_mode) && + if ((S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) && (sb.st_mtim.tv_sec > mtime.tv_sec || (sb.st_mtim.tv_sec == mtime.tv_sec && sb.st_mtim.tv_nsec >= mtime.tv_nsec))) @@ -509,6 +539,15 @@ recheck: return; } + /* process symlinks */ + linkname = archive_entry_symlink(e); + if (linkname != NULL) { + if (symlink(linkname, *path) < 0) + error("symlink('%s')", *path); + info(" extracting: %s -> %s\n", *path, linkname); + return; + } + if ((fd = open(*path, O_RDWR|O_CREAT|O_TRUNC, mode)) < 0) error("open('%s')", *path); @@ -550,12 +589,8 @@ recheck: * 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; - } - } + if (check_binary(buffer, len)) + text = 0; } /* simple case */ @@ -568,7 +603,7 @@ recheck: /* 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)) { + if (!warn && BYTE_IS_BINARY(*q)) { warningx("%s may be corrupted due" " to weak text file detection" " heuristic", *path); @@ -639,7 +674,7 @@ extract(struct archive *a, struct archiv } /* I don't think this can happen in a zipfile.. */ - if (!S_ISDIR(filetype) && !S_ISREG(filetype)) { + if (!S_ISDIR(filetype) && !S_ISREG(filetype) && !S_ISLNK(filetype)) { warningx("skipping non-regular entry '%s'", pathname); ac(archive_read_data_skip(a)); free(pathname); @@ -695,7 +730,7 @@ extract_stdout(struct archive *a, struct filetype = archive_entry_filetype(e); /* I don't think this can happen in a zipfile.. */ - if (!S_ISDIR(filetype) && !S_ISREG(filetype)) { + if (!S_ISDIR(filetype) && !S_ISREG(filetype) && !S_ISLNK(filetype)) { warningx("skipping non-regular entry '%s'", pathname); ac(archive_read_data_skip(a)); free(pathname); @@ -753,12 +788,8 @@ extract_stdout(struct archive *a, struct * 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; - } - } + if (check_binary(buffer, len)) + text = 0; } /* simple case */ @@ -771,7 +802,7 @@ extract_stdout(struct archive *a, struct /* 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)) { + if (!warn && BYTE_IS_BINARY(*q)) { warningx("%s may be corrupted due" " to weak text file detection" " heuristic", pathname); @@ -802,9 +833,14 @@ list(struct archive *a, struct archive_e { char buf[20]; time_t mtime; + struct tm *tm; mtime = archive_entry_mtime(e); - strftime(buf, sizeof(buf), "%m-%d-%g %R", localtime(&mtime)); + tm = localtime(&mtime); + if (*y_str) + strftime(buf, sizeof(buf), "%m-%d-%G %R", tm); + else + strftime(buf, sizeof(buf), "%m-%d-%g %R", tm); if (!zipinfo_mode) { if (v_opt == 1) { @@ -877,11 +913,11 @@ unzip(const char *fn) if (!p_opt && !q_opt) printf("Archive: %s\n", fn); if (v_opt == 1) { - printf(" Length Date Time Name\n"); - printf(" -------- ---- ---- ----\n"); + printf(" Length %sDate Time Name\n", y_str); + printf(" -------- %s---- ---- ----\n", y_str); } else if (v_opt == 2) { - printf(" Length Method Size Ratio Date Time CRC-32 Name\n"); - printf("-------- ------ ------- ----- ---- ---- ------ ----\n"); + printf(" Length Method Size Ratio %sDate Time CRC-32 Name\n", y_str); + printf("-------- ------ ------- ----- %s---- ---- ------ ----\n", y_str); } } @@ -913,13 +949,13 @@ unzip(const char *fn) if (zipinfo_mode) { if (v_opt == 1) { - printf(" -------- -------\n"); - printf(" %8ju %ju file%s\n", - total_size, file_count, file_count != 1 ? "s" : ""); + printf(" -------- %s-------\n", y_str); + printf(" %8ju %s%ju file%s\n", + total_size, y_str, file_count, file_count != 1 ? "s" : ""); } else if (v_opt == 2) { - printf("-------- ------- --- -------\n"); - printf("%8ju %7ju 0%% %ju file%s\n", - total_size, total_size, file_count, + printf("-------- ------- --- %s-------\n", y_str); + printf("%8ju %7ju 0%% %s%ju file%s\n", + total_size, total_size, y_str, file_count, file_count != 1 ? "s" : ""); } } @@ -929,7 +965,7 @@ unzip(const char *fn) if (t_opt) { if (error_count > 0) { - errorx("%d checksum error(s) found.", error_count); + errorx("%ju checksum error(s) found.", error_count); } else { printf("No errors detected in compressed data of %s.\n", @@ -942,7 +978,7 @@ static void usage(void) { - fprintf(stderr, "usage: unzip [-aCcfjLlnopqtuvZ1] [-d dir] [-x pattern] zipfile\n"); + fprintf(stderr, "Usage: unzip [-aCcfjLlnopqtuvyZ1] [-d dir] [-x pattern] zipfile\n"); exit(1); } @@ -952,7 +988,7 @@ getopts(int argc, char *argv[]) int opt; optreset = optind = 1; - while ((opt = getopt(argc, argv, "aCcd:fjLlnopqtuvx:Z1")) != -1) + while ((opt = getopt(argc, argv, "aCcd:fjLlnopqtuvx:yZ1")) != -1) switch (opt) { case '1': Z1_opt = 1; @@ -1007,6 +1043,9 @@ getopts(int argc, char *argv[]) case 'x': add_pattern(&exclude, optarg); break; + case 'y': + y_str = " "; + break; case 'Z': zipinfo_mode = 1; break;