unzip: implement -j, closes 9126
authorDenys Vlasenko <vda.linux@googlemail.com>
Thu, 20 Jul 2017 18:04:49 +0000 (20:04 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Thu, 20 Jul 2017 18:04:49 +0000 (20:04 +0200)
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 <vda.linux@googlemail.com>
archival/unzip.c

index 21ba172b5607ad10f7087de4de51aa5a43f82304..d5bca08d4c1756b78e04c67b3846374211b6a798 100644 (file)
@@ -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"
                        //      "---------  ---------- -----   ----"