From 997ad2c64abbe931dffa3598b015c5de04e515cf Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 20 Jul 2017 20:04:49 +0200 Subject: [PATCH] unzip: implement -j, closes 9126 function old new delta unzip_main 2642 2703 +61 packed_usage 31747 31770 +23 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 84/0) Total: 84 bytes Signed-off-by: Denys Vlasenko --- archival/unzip.c | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/archival/unzip.c b/archival/unzip.c index 21ba172b5..d5bca08d4 100644 --- a/archival/unzip.c +++ b/archival/unzip.c @@ -62,6 +62,7 @@ //usage: "\n -l List contents (with -q for short form)" //usage: "\n -n Never overwrite files (default: ask)" //usage: "\n -o Overwrite" +//usage: "\n -j Do not restore paths" //usage: "\n -p Print to stdout" //usage: "\n -q Quiet" //usage: "\n -x FILE Exclude FILEs" @@ -455,13 +456,16 @@ static int get_lstat_mode(const char *dst_fn) int unzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int unzip_main(int argc, char **argv) { - enum { O_PROMPT, O_NEVER, O_ALWAYS }; - + enum { + OPT_l = (1 << 0), + OPT_x = (1 << 1), + OPT_j = (1 << 2), + }; + unsigned opts; smallint quiet = 0; IF_NOT_FEATURE_UNZIP_CDF(const) smallint verbose = 0; - smallint listing = 0; + enum { O_PROMPT, O_NEVER, O_ALWAYS }; smallint overwrite = O_PROMPT; - smallint x_opt_seen; uint32_t cdf_offset; unsigned long total_usize; unsigned long total_size; @@ -472,7 +476,7 @@ int unzip_main(int argc, char **argv) llist_t *zaccept = NULL; llist_t *zreject = NULL; char *base_dir = NULL; - int i, opt; + int i; char key_buf[80]; /* must match size used by my_fgets80 */ /* -q, -l and -v: UnZip 5.52 of 28 February 2005, by Info-ZIP: @@ -516,16 +520,16 @@ int unzip_main(int argc, char **argv) * 204372 1 file */ - x_opt_seen = 0; + opts = 0; /* '-' makes getopt return 1 for non-options */ - while ((opt = getopt(argc, argv, "-d:lnopqxv")) != -1) { - switch (opt) { + while ((i = getopt(argc, argv, "-d:lnopqxjv")) != -1) { + switch (i) { case 'd': /* Extract to base directory */ base_dir = optarg; break; case 'l': /* List */ - listing = 1; + opts |= OPT_l; break; case 'n': /* Never overwrite existing files */ @@ -545,11 +549,15 @@ int unzip_main(int argc, char **argv) case 'v': /* Verbose list */ IF_FEATURE_UNZIP_CDF(verbose++;) - listing = 1; + opts |= OPT_l; break; case 'x': - x_opt_seen = 1; + opts |= OPT_x; + break; + + case 'j': + opts |= OPT_j; break; case 1: @@ -558,7 +566,7 @@ int unzip_main(int argc, char **argv) /* +5: space for ".zip" and NUL */ src_fn = xmalloc(strlen(optarg) + 5); strcpy(src_fn, optarg); - } else if (!x_opt_seen) { + } else if (!(opts & OPT_x)) { /* Include files */ llist_add_to(&zaccept, optarg); } else { @@ -626,7 +634,7 @@ int unzip_main(int argc, char **argv) if (quiet <= 1) { /* not -qq */ if (quiet == 0) printf("Archive: %s\n", src_fn); - if (listing) { + if (opts & OPT_l) { puts(verbose ? " Length Method Size Cmpr Date Time CRC-32 Name\n" "-------- ------ ------- ---- ---------- ----- -------- ----" @@ -778,13 +786,19 @@ int unzip_main(int argc, char **argv) free(dst_fn); dst_fn = xzalloc(zip.fmt.filename_len + 1); xread(zip_fd, dst_fn, zip.fmt.filename_len); - /* Skip extra header bytes */ unzip_skip(zip.fmt.extra_len); /* Guard against "/abspath", "/../" and similar attacks */ overlapping_strcpy(dst_fn, strip_unsafe_prefix(dst_fn)); + if (opts & OPT_j) /* Strip paths? */ + overlapping_strcpy(dst_fn, bb_basename(dst_fn)); + + /* Did this strip everything ("DIR/" case)? Then skip */ + if (!dst_fn[0]) + goto skip_cmpsize; + /* Filter zip entries */ if (find_list_entry(zreject, dst_fn) || (zaccept && !find_list_entry(zaccept, dst_fn)) @@ -792,7 +806,7 @@ int unzip_main(int argc, char **argv) goto skip_cmpsize; } - if (listing) { + if (opts & OPT_l) { /* List entry */ char dtbuf[sizeof("mm-dd-yyyy hh:mm")]; sprintf(dtbuf, "%02u-%02u-%04u %02u:%02u", @@ -960,7 +974,7 @@ int unzip_main(int argc, char **argv) total_entries++; } - if (listing && quiet <= 1) { + if ((opts & OPT_l) && quiet <= 1) { if (!verbose) { // " Length Date Time Name\n" // "--------- ---------- ----- ----"