From b701988480151e6693343ecdb246092824604c61 Mon Sep 17 00:00:00 2001
From: wangshouping <wangshouping@huawei.com>
Date: Tue, 11 Feb 2020 19:07:28 -0500
Subject: [PATCH] add param to limit the number of overlap files

Signed-off-by: wangshouping <wangshouping@huawei.com>
---
 extract.c   | 114 ++++++++++++++++++++++++++++++++++++++++++++++--------------
 man/unzip.1 |   8 +++--
 unzip.c     |  84 +++++++++++++++++++++++++++++++++++++++-----
 unzip.h     |   1 +
 unzip.txt   |   6 +++-
 5 files changed, 176 insertions(+), 37 deletions(-)

diff --git a/extract.c b/extract.c
index 3a01d13..031efdb 100644
--- a/extract.c
+++ b/extract.c
@@ -340,23 +340,32 @@ typedef struct {
     span_t *span;       /* allocated, distinct, and sorted list of spans */
     size_t num;         /* number of spans in the list */
     size_t max;         /* allocated number of spans (num <= max) */
+    unsigned long count;
 } cover_t;
 
 /*
  * Return the index of the first span in cover whose beg is greater than val.
  * If there is no such span, then cover->num is returned.
  */
-static size_t cover_find(cover, val)
+static size_t cover_find(cover, val, op)
     cover_t *cover;
     bound_t val;
+    int op;
 {
     size_t lo = 0, hi = cover->num;
+    bound_t tmp_val;
     while (lo < hi) {
         size_t mid = (lo + hi) >> 1;
-        if (val < cover->span[mid].beg)
-            hi = mid;
-        else
-            lo = mid + 1;
+        if (!op) {
+            tmp_val = cover->span[mid].beg;
+        } else {
+            tmp_val = cover->span[mid].end;
+        }
+        if (val < tmp_val) {
+            hi = mid;
+        } else {
+            lo = mid + 1;
+        }
     }
     return hi;
 }
@@ -366,10 +375,16 @@ static int cover_within(cover, val)
     cover_t *cover;
     bound_t val;
 {
-    size_t pos = cover_find(cover, val);
+    size_t pos = cover_find(cover, val, 0);
     return pos > 0 && val < cover->span[pos - 1].end;
 }
 
+static int is_exceed_max_overlaps(cover, val)
+    cover_t *cover;
+{
+    return cover->count >= G.UzO.max_overlaps;
+}
+
 /*
  * Add a new span to the list, but only if the new span does not overlap any
  * spans already in the list. The new span covers the values beg..end-1. beg
@@ -387,7 +402,8 @@ static int cover_add(cover, beg, end)
     bound_t beg;
     bound_t end;
 {
-    size_t pos;
+    size_t pos_beg;
+    size_t pos_end;
     int prec, foll;
 
     if (beg >= end)
@@ -396,31 +412,76 @@ static int cover_add(cover, beg, end)
 
     /* Find where the new span should go, and make sure that it does not
        overlap with any existing spans. */
-    pos = cover_find(cover, beg);
-    if ((pos > 0 && beg < cover->span[pos - 1].end) ||
-        (pos < cover->num && end > cover->span[pos].beg))
-        return 1;
+    pos_beg = cover_find(cover, beg, 0);
+    pos_end = cover_find(cover, end, 1);
 
     /* Check for adjacencies. */
-    prec = pos > 0 && beg == cover->span[pos - 1].end;
-    foll = pos < cover->num && end == cover->span[pos].beg;
+    prec = pos_beg > 0 && beg <= cover->span[pos_beg - 1].end;
+    foll = pos_beg < cover->num && end >= cover->span[pos_beg].beg;
     if (prec && foll) {
+        if (beg < cover->span[pos_beg - 1].end || end > cover->span[pos_beg].beg) {
+            cover->count++;
+        }
+
         /* The new span connects the preceding and following spans. Merge the
            following span into the preceding span, and delete the following
            span. */
-        cover->span[pos - 1].end = cover->span[pos].end;
-        cover->num--;
-        memmove(cover->span + pos, cover->span + pos + 1,
-                (cover->num - pos) * sizeof(span_t));
+        if (end <= cover->span[pos_beg].end) {
+            cover->span[pos_beg - 1].end = cover->span[pos_beg].end;
+            cover->num--;
+            memmove(cover->span + pos_beg, cover->span + pos_beg + 1,
+                    (cover->num - pos_beg) * sizeof(span_t));
+        } else {
+            if (pos_end == cover->num) {
+                cover->span[pos_beg - 1].end = end;
+                cover->num = cover->num - (pos_end - pos_beg);
+            } else if (end >= cover->span[pos_end].beg) {
+                cover->span[pos_beg - 1].end = cover->span[pos_end].end;
+                memmove(cover->span + pos_beg, cover->span + pos_end + 1,
+                        (cover->num - 1 - pos_end) * sizeof(span_t));
+                cover->num = cover->num - (pos_end - pos_beg) - 1;
+            } else {
+                cover->span[pos_beg - 1].end = end;
+                memmove(cover->span + pos_beg, cover->span + pos_end,
+                        (cover->num - 1 - pos_end + 1) * sizeof(span_t));
+                cover->num = cover->num - (pos_end - pos_beg);
+            }
+        }
     }
-    else if (prec)
+    else if (prec) {
         /* The new span is adjacent only to the preceding span. Extend the end
            of the preceding span. */
-        cover->span[pos - 1].end = end;
-    else if (foll)
+        if (beg < cover->span[pos_beg - 1].end) {
+            cover->count++;
+        }
+        if (end > cover->span[pos_beg - 1].end) {
+            cover->span[pos_beg - 1].end = end;
+        }
+    }
+    else if (foll) {
+        if (end > cover->span[pos_beg].beg) {
+                cover->count++;
+        }
         /* The new span is adjacent only to the following span. Extend the
            beginning of the following span. */
-        cover->span[pos].beg = beg;
+        cover->span[pos_beg].beg = beg;
+        if (end > cover->span[pos_beg].end) {
+            if (pos_end == cover->num) {
+                cover->span[pos_beg].end = end;
+                cover->num = cover->num - (pos_end - pos_beg) + 1;
+            } else if (end >= cover->span[pos_end].beg) {
+                cover->span[pos_beg].end = cover->span[pos_end].end;
+                memmove(cover->span + pos_beg + 1, cover->span + pos_end + 1,
+                        (cover->num - 1 - pos_end) * sizeof(span_t));
+                cover->num = cover->num - (pos_end - pos_beg);
+            } else {
+               cover->span[pos_beg].end = end;
+                memmove(cover->span + pos_beg + 1, cover->span + pos_end,
+                        (cover->num - 1 - pos_end + 1) * sizeof(span_t));
+                cover->num = cover->num - (pos_end - pos_beg) + 1;
+            }
+        }
+    }
     else {
         /* The new span has gaps between both the preceding and the following
            spans. Assure that there is room and insert the span.  */
@@ -432,11 +493,11 @@ static int cover_add(cover, beg, end)
             cover->span = span;
             cover->max = max;
         }
-        memmove(cover->span + pos + 1, cover->span + pos,
-                (cover->num - pos) * sizeof(span_t));
+        memmove(cover->span + pos_beg + 1, cover->span + pos_beg,
+                (cover->num - pos_beg) * sizeof(span_t));
         cover->num++;
-        cover->span[pos].beg = beg;
-        cover->span[pos].end = end;
+        cover->span[pos_beg].beg = beg;
+        cover->span[pos_beg].end = end;
     }
     return 0;
 }
@@ -511,6 +572,7 @@ int extract_or_test_files(__G)    /* return PK-type error code */
         ((cover_t *)G.cover)->max = 0;
     }
     ((cover_t *)G.cover)->num = 0;
+    ((cover_t *)G.cover)->count = 0;
     if (cover_add((cover_t *)G.cover,
                   G.extra_bytes + G.ecrec.offset_start_central_directory,
                   G.extra_bytes + G.ecrec.offset_start_central_directory +
@@ -1218,7 +1280,7 @@ static int extract_or_test_entrylist(__G__ numchunk,
 
         /* seek_zipf(__G__ pInfo->offset);  */
         request = G.pInfo->offset + G.extra_bytes;
-        if (cover_within((cover_t *)G.cover, request)) {
+        if (is_exceed_max_overlaps((cover_t *)G.cover)) {
             Info(slide, 0x401, ((char *)slide,
               LoadFarString(OverlappedComponents)));
             return PK_BOMB;
diff --git a/man/unzip.1 b/man/unzip.1
index 21816d1..a637a14 100644
--- a/man/unzip.1
+++ b/man/unzip.1
@@ -25,7 +25,7 @@
 unzip \- list, test and extract compressed files in a ZIP archive
 .PD
 .SH SYNOPSIS
-\fBunzip\fP [\fB\-Z\fP] [\fB\-cflptTuvz\fP[\fBabjnoqsCDKLMUVWX$/:^\fP]]
+\fBunzip\fP [\fB\-Z\fP] [\fB\-cflptTuvz\fP[\fBabjnoqsCDKLMUVWX$/:^\fP][\fB\-g num\fP]]
 \fIfile\fP[\fI.zip\fP] [\fIfile(s)\fP\ .\|.\|.]
 [\fB\-x\fP\ \fIxfile(s)\fP\ .\|.\|.] [\fB\-d\fP\ \fIexdir\fP]
 .PD
@@ -195,6 +195,10 @@ but will be in future releases.
 .TP
 .B \-z
 display only the archive comment.
+.IP \fB\-g\fP\ \fInum\fP
+limit the number of overlap files. When the number of
+overlap files exceeds the num we set, it is a bomb. the num
+is a decimal number.
 .PD
 .\" =========================================================================
 .SH MODIFIERS
diff --git a/unzip.c b/unzip.c
index 5b7d288..8c4c37e 100644
--- a/unzip.c
+++ b/unzip.c
@@ -601,7 +601,7 @@ Latest sources and executables are at ftp://ftp.info-zip.org/pub/infozip/ ;\
 \n  file[.zip] may be a wildcard.  %s\n";
 #else /* !VM_CMS */
 static ZCONST char Far UnzipUsageLine2[] = "\
-Usage: unzip %s[-opts[modifiers]] file[.zip] [list] [-x xlist] [-d exdir]\n \
+Usage: unzip %s[-opts[modifiers][-g num]] file[.zip] [list] [-x xlist] [-d exdir]\n \
  Default action is to extract files in list, except those in xlist, to exdir;\n\
   file[.zip] may be a wildcard.  %s\n";
 #endif /* ?VM_CMS */
@@ -647,7 +648,8 @@ static ZCONST char Far UnzipUsageLine3[] = "\n\
   -f  freshen existing files, create none    -t  test compressed archive data\n\
   -u  update files, create if necessary      -z  display archive comment only\n\
   -v  list verbosely/show version info     %s\n\
-  -x  exclude files that follow (in xlist)   -d  extract files into exdir\n";
+  -x  exclude files that follow (in xlist)   -d  extract files into exdir\n\
+  -g  limit the number of overlap files\n";
 #endif /* ?VM_CMS */
 #endif /* ?MACOS */
 
@@ -1367,7 +1414,7 @@ int uz_opts(__G__ pargc, pargv)
     extern char OEM_CP[MAX_CP_NAME];
     extern char ISO_CP[MAX_CP_NAME];
 #endif
-    
+    uO.max_overlaps = (unsigned long)(-1);  /* if not set, uncheck overlaps */
     while (++argv, (--argc > 0 && *argv != NULL && **argv == '-')) {
         s = *argv + 1;
         while ((c = *s++) != 0) {    /* "!= 0":  prevent Turbo C warning */
@@ -1528,6 +1575,26 @@ int uz_opts(__G__ pargc, pargv)
                         uO.acorn_nfs_ext = TRUE;
                     break;
 #endif /* RISCOS || ACORN_FTYPE_NFS */
+#ifdef UNIX
+                case('g'):  /* set overlap entries */
+                    if (negative) { // invalid param, eg: --g
+                        Info(slide, 0x401, ((char *)slide,
+                          "error: invalid param, eg: unzip --g"));
+                        return(PK_PARAM);
+                    } else {
+                        if (argc > 1) {
+                            char *leftover;
+                            --argc;
+                            ++argv;
+                            uO.max_overlaps = strtoul(*argv, &leftover, 10);
+                        } else {     /* else pwdarg points at decryption password */
+                                Info(slide, 0x401, ((char *)slide,
+                                  "error: invalid param, -g need add decimal number"));
+                                return(PK_PARAM);
+                        }
+                    }
+                    break;
+#endif
                 case ('h'):    /* just print help message and quit */
                     if (showhelp == 0) {
 #ifndef SFX
@@ -2235,6 +2302,7 @@ static void help_extended(__G)
   "         information.  Also can be added to other list commands for more",
   "         verbose output.",
   "  -z   Display only archive comment.",
+  "  -g   Limit the number of overlap files.",
   "",
   "unzip modifiers:",
   "  -a   Convert text files to local OS format.  Convert line ends, EOF",
diff --git a/unzip.h b/unzip.h
index ed24a5b..a7e8a64 100644
--- a/unzip.h
+++ b/unzip.h
@@ -560,6 +560,7 @@ typedef struct _UzpOpts {
     int cflxflag;       /* -^: allow control chars in extracted filenames */
 #endif
 #endif /* !FUNZIP */
+    unsigned long max_overlaps;  /* Maximum number of overlaps allowed */
 } UzpOpts;
 
 /* intended to be a private struct: */
diff --git a/unzip.txt b/unzip.txt
index e8e9719..6594ee6 100644
--- a/unzip.txt
+++ b/unzip.txt
@@ -4,7 +4,7 @@ NAME
        unzip - list, test and extract compressed files in a ZIP archive
 
 SYNOPSIS
-       unzip  [-Z] [-cflptTuvz[abjnoqsCDKLMUVWX$/:^]] file[.zip] [file(s) ...]
+       unzip  [-Z] [-cflptTuvz[abjnoqsCDKLMUVWX$/:^][-g num]] file[.zip] [file(s) ...]
        [-x xfile(s) ...] [-d exdir]
 
 DESCRIPTION
@@ -177,6 +177,10 @@ OPTIONS
               implemented but will be in future releases.
 
        -z     display only the archive comment.
+       -g num
+              limit the number of overlap files. When the number of overlap f-
+              iles exceeds the num we set, it is a bomb. the num is a decimal
+              number.
 
 MODIFIERS
        -a     convert  text files.  Ordinarily all files are extracted exactly
-- 
1.8.3.1

