From 04e17b6a6d4dc7240741d2d080bdf877b3623a4a Mon Sep 17 00:00:00 2001 From: Alex Kozlov Date: Fri, 11 Dec 2015 23:52:08 +0000 Subject: - 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 --- usr.bin/unzip/unzip.1 | 6 ++- usr.bin/unzip/unzip.c | 103 ++++++++++++++++++++++++++++++++++---------------- 2 files changed, 75 insertions(+), 34 deletions(-) (limited to 'usr.bin/unzip') diff --git a/usr.bin/unzip/unzip.1 b/usr.bin/unzip/unzip.1 index fd9b10fa6555..163fbaeea9ce 100644 --- a/usr.bin/unzip/unzip.1 +++ b/usr.bin/unzip/unzip.1 @@ -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 diff --git a/usr.bin/unzip/unzip.c b/usr.bin/unzip/unzip.c index fa35400194c1..74c1542a12f2 100644 --- a/usr.bin/unzip/unzip.c +++ b/usr.bin/unzip/unzip.c @@ -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 */ @@ -460,6 +461,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. */ @@ -472,6 +501,7 @@ extract_file(struct archive *a, struct archive_entry *e, char **path) 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 archive_entry *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); @@ -695,7 +730,7 @@ extract_stdout(struct archive *a, struct archive_entry *e) 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 archive_entry *e) * 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 archive_entry *e) /* 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_entry *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; -- cgit v1.2.3