aboutsummaryrefslogtreecommitdiff
path: root/usr.bin/unzip
diff options
context:
space:
mode:
authorAlex Kozlov <ak@FreeBSD.org>2015-12-11 23:52:08 +0000
committerAlex Kozlov <ak@FreeBSD.org>2015-12-11 23:52:08 +0000
commit04e17b6a6d4dc7240741d2d080bdf877b3623a4a (patch)
tree2fb1d3bc31b86eb57bac9034bc6611bbba518bd5 /usr.bin/unzip
parent2aa7d573a08dd834f5ad030503e6031bc9afbea3 (diff)
downloadsrc-04e17b6a6d4dc7240741d2d080bdf877b3623a4a.tar.gz
src-04e17b6a6d4dc7240741d2d080bdf877b3623a4a.zip
Notes
Diffstat (limited to 'usr.bin/unzip')
-rw-r--r--usr.bin/unzip/unzip.16
-rw-r--r--usr.bin/unzip/unzip.c103
2 files changed, 75 insertions, 34 deletions
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 <joerg@NetBSD.org>
+ * Copyright (c) 2009, 2010 Joerg Sonnenberger <joerg@NetBSD.org>
* 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 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;