Its behavior is the same as that of tar's --strip-components=NUM.

Based on 
https://git.busybox.net/busybox/commit?id=6c563e370d0f2f3cf36f3b274e8fe1392ca7125f

function                                             old     new   delta
unzip_main                                          2964    3088    +124
.rodata                                            17268   17295     +27
packed_usage                                        1808    1833     +25
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/0 up/down: 176/0)             Total: 176 bytes

Signed-off-by: Eugene Rudoy <[email protected]>
---
 archival/unzip.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 54 insertions(+), 2 deletions(-)

diff --git a/archival/unzip.c b/archival/unzip.c
index 50205eb6e..d5a601a24 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -51,18 +51,29 @@
 //config:      bool "Support compression method 95 (xz)"
 //config:      default y
 //config:      depends on FEATURE_UNZIP_CDF && DESKTOP
+//config:
+//config:config FEATURE_UNZIP_J_NUM
+//config:      bool "Provide non-standard -J NUM option"
+//config:      default n
+//config:      depends on UNZIP
+//config:      help
+//config:      Add support for a non-standard (busybox only) -J NUM option.
+//config:      Its behavior is the same as that of tar's 
--strip-components=NUM.
 
 //applet:IF_UNZIP(APPLET(unzip, BB_DIR_USR_BIN, BB_SUID_DROP))
 //kbuild:lib-$(CONFIG_UNZIP) += unzip.o
 
 //usage:#define unzip_trivial_usage
-//usage:       "[-lnojpq] FILE[.zip] [FILE]... [-x FILE...] [-d DIR]"
+//usage:       "[-lnojpq] FILE[.zip] [FILE]... [-x FILE...] [-d DIR]" 
IF_FEATURE_UNZIP_J_NUM(" [-J NUM]")
 //usage:#define unzip_full_usage "\n\n"
 //usage:       "Extract FILEs from ZIP archive\n"
 //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:  IF_FEATURE_UNZIP_J_NUM(
+//usage:     "\n       -J NUM  Strip NUM leading path components on extraction"
+//usage:  )
 //usage:     "\n       -p      Print to stdout"
 //usage:     "\n       -q      Quiet"
 //usage:     "\n       -x FILE Exclude FILEs"
@@ -472,8 +483,12 @@ int unzip_main(int argc, char **argv)
                OPT_l = (1 << 0),
                OPT_x = (1 << 1),
                OPT_j = (1 << 2),
+               OPT_J_num = (1 << 3),
        };
        unsigned opts;
+#if ENABLE_FEATURE_UNZIP_J_NUM
+       unsigned strip_components = 0;
+#endif
        smallint quiet = 0;
        IF_NOT_FEATURE_UNZIP_CDF(const) smallint verbose = 0;
        enum { O_PROMPT, O_NEVER, O_ALWAYS };
@@ -534,7 +549,7 @@ int unzip_main(int argc, char **argv)
 
        opts = 0;
        /* '-' makes getopt return 1 for non-options */
-       while ((i = getopt(argc, argv, "-d:lnopqxjv")) != -1) {
+       while ((i = getopt(argc, argv, "-d:lnopqxj" 
IF_FEATURE_UNZIP_J_NUM("J:") "v")) != -1) {
                switch (i) {
                case 'd':  /* Extract to base directory */
                        base_dir = optarg;
@@ -572,6 +587,13 @@ int unzip_main(int argc, char **argv)
                        opts |= OPT_j;
                        break;
 
+#if ENABLE_FEATURE_UNZIP_J_NUM
+               case 'J':
+                       opts |= OPT_J_num;
+                       strip_components = xatou(optarg);
+                       break;
+#endif
+
                case 1:
                        if (!src_fn) {
                                /* The zip file */
@@ -872,6 +894,36 @@ int unzip_main(int argc, char **argv)
 
                if (opts & OPT_j) /* Strip paths? */
                        overlapping_strcpy(dst_fn, bb_basename(dst_fn));
+#if ENABLE_FEATURE_UNZIP_J_NUM
+               /* we tolerate it when both -j and -J NUM are used at the same 
time */
+               /* by making -j always win, thus 'else if' below */
+               else if ((opts & OPT_J_num) && (strip_components > 0)) {
+                       unsigned n = strip_components;
+                       const char *dst_fn_stripped = dst_fn;
+                       do {
+                               dst_fn_stripped = strchr(dst_fn_stripped, '/');
+                               if (!dst_fn_stripped /* || dst_fn_stripped[1] 
== '\0' */) {
+                               /*                      
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+                                *                      from tar's 
--strip-component
+                                *                      covered by the "DIR/ 
case?" check below
+                                */
+                                       goto skip_cmpsize;
+                               }
+                               dst_fn_stripped++;
+                       } while (--n != 0);
+                       overlapping_strcpy(dst_fn, dst_fn_stripped);
+
+                       /*
+                        * Q: What should we do with link targets?
+                        * A: tar behavior is
+                        *     - link targets are shortened only for hardlinks
+                        *     - softlinks are restored unchanged
+                        *    zip format supports only symlinks
+                        *     => nothing to do in regard to link targets
+                        */
+
+               }
+#endif
 
                /* Did this strip everything ("DIR/" case)? Then skip */
                if (!dst_fn[0])
--
2.15.0
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to