- 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
This commit is contained in:
parent
2aa7d573a0
commit
04e17b6a6d
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=292127
@ -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
|
||||
|
@ -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 */
|
||||
@ -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 @@ extract_file(struct archive *a, struct archive_entry *e, char **path)
|
||||
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 @@ extract_file(struct archive *a, struct archive_entry *e, char **path)
|
||||
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 @@ extract_file(struct archive *a, struct archive_entry *e, char **path)
|
||||
* 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 @@ extract_file(struct archive *a, struct archive_entry *e, char **path)
|
||||
/* 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;
|
||||
|
Loading…
Reference in New Issue
Block a user