unzip: fix content listing and filtering when -j is used
authorEugene Rudoy <gene.devel@gmail.com>
Tue, 7 Nov 2017 07:03:36 +0000 (08:03 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Thu, 9 Nov 2017 11:45:50 +0000 (12:45 +0100)
Original Info-ZIP's unzip uses unstripped filenames
while doing content listing and filtering, i.e.
 - in content listing mode -j is ignored completely
 - filtering is applied to non-stripped names, -j
   takes effect first while extracting the files

997ad2c64abbe931dffa3598b015c5de04e515cf strips path
components a little bit too early resulting in behavior
deviations.

Fix it by doing stripping after listing/filtering.

p.s. Info-ZIP's unzip behavior is the same as
     that of tar in --strip-components=NUM mode

Signed-off-by: Eugene Rudoy <gene.devel@gmail.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
archival/unzip.c

index 60416606397ed72fbb645db4f9dc16394b201f97..1ef4406d61f86e74e5e910bd08e70117ea77926e 100644 (file)
@@ -805,13 +805,6 @@ int unzip_main(int argc, char **argv)
                /* 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))
@@ -876,6 +869,14 @@ int unzip_main(int argc, char **argv)
                        /* Extracting to STDOUT */
                        goto do_extract;
                }
+
+               /* Strip paths (after -l: unzip -lj a.zip lists full names) */
+               if (opts & OPT_j)
+                       overlapping_strcpy(dst_fn, bb_basename(dst_fn));
+               /* Did this strip everything ("DIR/" case)? Then skip */
+               if (!dst_fn[0])
+                       goto skip_cmpsize;
+
                if (last_char_is(dst_fn, '/')) {
                        int mode;