Blob Blame History Raw
diff --git a/cmsmvs/vmmvs.c b/cmsmvs/vmmvs.c
index 8416ce8..f5bf356 100644
--- a/cmsmvs/vmmvs.c
+++ b/cmsmvs/vmmvs.c
@@ -35,17 +35,23 @@
 /* Function vmmvs_open_infile() */
 /********************************/
 
-FILE *vmmvs_open_infile(__G)
+FILE *vmmvs_open_infile(__G__ fn)
    __GDEF
+   char *fn;
 {
    FILE *fzip;
 
-   G.tempfn = NULL;
 
-   fzip = fopen(G.zipfn, FOPR);
+   fzip = fopen(.fn, FOPR);
+#ifdef CMS_MVS_INFILE_TMP
 
-#if 0
    /* Let's try it without the convert for a while -- RG Hartwig */
+   /* 2015-03-17 SMS.
+    * If ever re-enabled, this code will need changes to accommodate the
+    * additional archive segment file(s) (variable file name).
+    */
+
+   G.tempfn = NULL;
 
    if ((fzip = fopen(G.zipfn,"rb,recfm=fb")) == NULL) {
       size_t cnt;
@@ -82,7 +88,7 @@ FILE *vmmvs_open_infile(__G)
       G.ziplen = ftell(fzip);
    }
 
-#endif
+#endif /* def CMS_MVS_INFILE_TMP */
 
    return fzip;
 }
@@ -177,15 +183,21 @@ void close_outfile(__G)
 /* Function close_infile() */
 /***************************/
 
-void close_infile(__G)
+void close_infile(__G__ pfd)
    __GDEF
+   zipfd_t *pfd;
 {
-   fclose(G.zipfd);
+   int sts;
+   sts = fclose( *pfd);
+   *pfd = NULL;
 
-   /* If we're working from a temp file, erase it now */
-   if (G.tempfn)
-      remove(G.tempfn);
+#ifdef CMS_MVS_INFILE_TMP
+  /* If we're working from a temp file, erase it now */
+  if (G.tempfn)
+    remove(G.tempfn);
+#endif /* def CMS_MVS_INFILE_TMP */
 
+  return sts;
 } /* end function close_infile() */
 
 
diff --git a/consts.h b/consts.h
index 5dfc0a0..dee57b1 100644
--- a/consts.h
+++ b/consts.h
@@ -33,7 +33,7 @@ ZCONST char Far VersionDate[] = UZ_VERSION_DATE; /* now defined in unzvers.h */
 ZCONST char Far CentSigMsg[] =
   "error:  expected central file header signature not found (file #%lu).\n";
 ZCONST char Far SeekMsg[] =
-  "error [%s]:  attempt to seek before beginning of zipfile\n%s";
+  "error [%s]:  attempt to seek before beginning of zipfile (%d)\n%s";
 ZCONST char Far FilenameNotMatched[] = "caution: filename not matched:  %s\n";
 ZCONST char Far ExclFilenameNotMatched[] =
   "caution: excluded filename not matched:  %s\n";
diff --git a/extract.c b/extract.c
index 7134bfe..37850a7 100644
--- a/extract.c
+++ b/extract.c
@@ -19,6 +19,7 @@
              find_compr_idx()
              extract_or_test_entrylist()
              extract_or_test_member()
+             close_segment()
              TestExtraField()
              test_compr_eb()
              memextract()
@@ -323,8 +324,20 @@ static ZCONST char Far BadExtraFieldCRC[] =
   "error [%s]:  bad extra-field CRC %08lx (should be %08lx)\n";
 
 
+/*******************************/
+/*  Function close_segment().  */
+/*******************************/
+static void close_segment(__G)
+  __GDEF
+{
+  if (G.zipfn_sgmnt != NULL)
+  {
+    izu_free(G.zipfn_sgmnt);
+    G.zipfn_sgmnt = NULL;
+  }
+  CLOSE_INFILE( &G.zipfd_sgmnt);
 
-
+} /* close_segment(). */
 
 /**************************************/
 /*  Function extract_or_test_files()  */
@@ -351,6 +364,8 @@ int extract_or_test_files(__G)    /* return PK-type error code */
     unsigned num_dirs=0;
     direntry *dirlist=(direntry *)NULL, **sorted_dirlist=(direntry **)NULL;
 #endif
+    zuvl_t sgmnt_nr;
+    zipfd_t zipfd;
 
     /*
      * First, two general initializations are applied. These have been moved
@@ -578,6 +593,12 @@ int extract_or_test_files(__G)    /* return PK-type error code */
         cd_inptr = G.inptr;
         cd_incnt = G.incnt;
 
+        /* Save the file descr/pointer and segment number, which are subject
+         * to change when the archive is segmented.
+         */
+        zipfd = G.zipfd;
+        sgmnt_nr = G.sgmnt_nr;
+
     /*-----------------------------------------------------------------------
         Second loop:  process files in current block, extracting or testing
         each one.
@@ -606,7 +627,8 @@ int extract_or_test_files(__G)    /* return PK-type error code */
          * Jump back to where we were in the central directory, then go and do
          * the next batch of files.
          */
-
+        G.zipfd = zipfd;
+        G.sgmnt_nr = sgmnt_nr;
 #ifdef USE_STRM_INPUT
         zfseeko(G.zipfd, cd_bufstart, SEEK_SET);
         G.cur_zipfile_bufstart = zftello(G.zipfd);
@@ -1060,8 +1082,51 @@ static int extract_or_test_entrylist(__G__ numchunk,
          * (either haven't yet read far enough, or (maybe) skipping back-
          * ward), skip to the target position and reset readbuf(). */
 
+        if(G.ecrec.number_this_disk > 0)
+        {
+          /* Open file (when it is segmented) even if it is a duplicate
+           * of the same fd, due to possible unwanted changes of G.zipfd
+           * and G.sgmnt_nr which were saved in extract_or_test_files().
+           */
+          if (!fd_is_valid(G.zipfd_sgmnt) || G.sgmnt_nr != G.pInfo->diskstart)
+          {
+            if (fd_is_valid(G.zipfd_sgmnt))
+              close_segment( __G);            /* We need a different file. */
+
+            set_zipfn_sgmnt_name( __G__ G.pInfo->diskstart);
+            if (open_infile( __G__ OIF_SEGMENT))
+            {
+              /* TODO: ask for place/path of zipfile, see wild*!, ... */
+              /* Create new function for this all? */
+              izu_free(G.zipfn_sgmnt);
+              G.zipfn_sgmnt = NULL;
+              error = PK_NOZIP;
+              return error;
+            }
+            else
+            {
+              /* TODO: that's not best solution but for
+               * testing/alpha version is good enough now. */
+              G.zipfd = G.zipfd_sgmnt;
+              G.sgmnt_nr = G.pInfo->diskstart;
+            }
+            /* When we change file, we must refill buffer always!
+             * (Same method as in seek_zipf().)
+             */
+            G.cur_zipfile_bufstart = -1;
+          }
+          /* TODO: check better too -- Is G.extra_bytes important in
+           * segmented?  Otherwise bigger harakiri is here
+           * needed (here = whole request block below)
+           */
+          request = G.pInfo->offset;
+        }
+        else
+        {
+          request = G.pInfo->offset + G.extra_bytes;
+        }
+
         /* seek_zipf(__G__ pInfo->offset);  */
-        request = G.pInfo->offset + G.extra_bytes;
         inbuf_offset = request % INBUFSIZ;
         bufstart = request - inbuf_offset;
 
@@ -1072,7 +1137,7 @@ static int extract_or_test_entrylist(__G__ numchunk,
           (long)bufstart, (long)G.cur_zipfile_bufstart));
         if (request < 0) {
             Info(slide, 0x401, ((char *)slide, LoadFarStringSmall(SeekMsg),
-              G.zipfn, LoadFarString(ReportMsg)));
+              G.zipfn, 1, LoadFarString(ReportMsg)));
             error_in_archive = PK_ERR;
             if (*pfilnum == 1 && G.extra_bytes != 0L) {
                 Info(slide, 0x401, ((char *)slide,
@@ -1093,7 +1158,7 @@ static int extract_or_test_entrylist(__G__ numchunk,
                       "debug: recompensated request still < 0\n"));
                     Info(slide, 0x401, ((char *)slide,
                       LoadFarStringSmall(SeekMsg),
-                      G.zipfn, LoadFarString(ReportMsg)));
+                      G.zipfn, 2,LoadFarString(ReportMsg)));
                     error_in_archive = PK_BADERR;
                     continue;
                 }
diff --git a/fileio.c b/fileio.c
index 2a61a30..5a47b0a 100644
--- a/fileio.c
+++ b/fileio.c
@@ -147,6 +147,10 @@ static int disk_error OF((__GPRO));
 static ZCONST char Far CannotOpenZipfile[] =
   "error:  cannot open zipfile [ %s ]\n        %s\n";
 
+static ZCONST char Far NoSuchSegment[] =
+  "Bad archive segment value (%d > %d)";
+
+
 #if (!defined(VMS) && !defined(AOS_VS) && !defined(CMS_MVS) && !defined(MACOS))
 #if (!defined(TANDEM))
 #if (defined(ATH_BEO_THS_UNX) || defined(DOS_FLX_NLM_OS2_W32))
@@ -215,51 +219,234 @@ static ZCONST char Far ExtraFieldCorrupt[] =
 
 
 /******************************/
-/* Function open_input_file() */
+/* Function open_infile() */
 /******************************/
 
-int open_input_file(__G)    /* return 1 if open failed */
+int open_infile(__G__ which)    /* return 1 if open failed */
     __GDEF
+    int which;            /* 0: Primary archive; 1: Segment archive. */
+
 {
-    /*
-     *  open the zipfile for reading and in BINARY mode to prevent cr/lf
-     *  translation, which would corrupt the bitstreams
-     */
+
+  /* Open an archive (zipfile) for reading and in BINARY mode to
+   * prevent CR/LF translation, which would corrupt the data.
+   * Return 0: success; 1: failure.
+   */
+
+  char *fn;
+  zipfd_t *pfd;
+
+  if (which == OIF_PRIMARY)
+  {
+    fn = G.zipfn;               /* Primary archive file name (".zip"). */
+    pfd = &G.zipfd;             /* Primary archive file descr/pointer. */
+  }
+  else
+  {
+    fn = G.zipfn_sgmnt;         /* Segment archive file name (".zXX"). */
+    pfd = &G.zipfd_sgmnt;       /* Segment archive file descr/pointer. */
+  }
 
 #ifdef VMS
-    G.zipfd = open(G.zipfn, O_RDONLY, 0, OPNZIP_RMS_ARGS);
+    *pfd = open( fn, O_RDONLY, 0, OPNZIP_RMS_ARGS);
 #else /* !VMS */
 #ifdef MACOS
-    G.zipfd = open(G.zipfn, 0);
+    *pfd = open(fn, 0);
 #else /* !MACOS */
 #ifdef CMS_MVS
-    G.zipfd = vmmvs_open_infile(__G);
+    *pfd = vmmvs_open_infile(__G__ fn, pfd);
 #else /* !CMS_MVS */
 #ifdef USE_STRM_INPUT
-    G.zipfd = fopen(G.zipfn, FOPR);
+    *pfd = fopen(fn, FOPR);
 #else /* !USE_STRM_INPUT */
-    G.zipfd = open(G.zipfn, O_RDONLY | O_BINARY);
+    *pfd = open(fn, O_RDONLY | O_BINARY);
 #endif /* ?USE_STRM_INPUT */
 #endif /* ?CMS_MVS */
 #endif /* ?MACOS */
 #endif /* ?VMS */
 
-#ifdef USE_STRM_INPUT
-    if (G.zipfd == NULL)
-#else
-    /* if (G.zipfd < 0) */  /* no good for Windows CE port */
-    if (G.zipfd == -1)
-#endif
+    if (!fd_is_valid( *pfd))
     {
         Info(slide, 0x401, ((char *)slide, LoadFarString(CannotOpenZipfile),
-          G.zipfn, strerror(errno)));
+          fn, strerror(errno)));
         return 1;
     }
     return 0;
 
 } /* end function open_input_file() */
 
+/***************************/
+/* Function close_infile() */
+/***************************/
+int close_infile( __G__ pfd)
+  __GDEF
+  zipfd_t *pfd;
+{
+  int sts = 0;
+
+  if (fd_is_valid( *pfd))
+  {
+#ifdef USE_STRM_INPUT
+    sts = fclose( *pfd);
+#else /* def USE_STRM_INPUT */
+    sts = close( *pfd);
+#endif /* def USE_STRM_INPUT [else] */
+    *pfd = ZIPFD_INVALID;
+  }
 
+  return sts;
+} /* close_infile() */
+
+/***********************************/
+/* Function set_zipfn_sgmnt_name() */
+/***********************************/
+int set_zipfn_sgmnt_name( __G__ sgmnt_nr)
+  __GDEF
+  zuvl_t sgmnt_nr;
+{
+  char *suffix;
+  int sufx_len;
+
+/* sizeof( ".z65535") == 8 should be safe. */
+#define SGMNT_NAME_BOOST 8
+
+  if (sgmnt_nr > G.ecrec.number_this_disk)
+  {
+    /* Segment number greater than (max?) central-dir disk number. */
+    Info(slide, 1, ((char *)slide, LoadFarString(NoSuchSegment),
+     sgmnt_nr, G.ecrec.number_this_disk));
+    return 1;
+  }
+
+  if (G.zipfn_sgmnt == NULL)
+  {
+    G.zipfn_sgmnt_size = strlen(G.zipfn)+ SGMNT_NAME_BOOST;
+    if ((G.zipfn_sgmnt = izu_malloc(G.zipfn_sgmnt_size)) == NULL)
+    {
+      G.zipfn_sgmnt_size = -1;
+      return 1;
+    }
+  }
+  else
+  {
+    if (G.zipfn_sgmnt_size < (int)strlen(G.zipfn)+ SGMNT_NAME_BOOST)
+    {
+      G.zipfn_sgmnt_size = strlen(G.zipfn)+ SGMNT_NAME_BOOST;
+      izu_free(G.zipfn_sgmnt);
+      if ((G.zipfn_sgmnt = izu_malloc(G.zipfn_sgmnt_size)) == NULL)
+      {
+        G.zipfn_sgmnt_size = -1;
+        return 1;
+      }
+    }
+  }
+
+
+  if (sgmnt_nr == G.ecrec.number_this_disk)
+  {
+    zfstrcpy(G.zipfn_sgmnt, G.zipfn);
+    return 0;           /* Last segment.  Name already ".zip." */
+  }
+
+#ifdef VMS
+
+  /* A VMS archive file spec may include a version number (";nnn"),
+   * confusing any simple scheme (like the one below).  $PARSE can
+   * easily replace one file type with another (and null out the version
+   * number), so use it, instead.
+   */
+  vms_sgmnt_name( G.zipfn_sgmnt, G.zipfn, (sgmnt_nr+ 1));
+
+#else /* def VMS */
+
+  zfstrcpy(G.zipfn_sgmnt, G.zipfn);
+  /* Expect to find ".zXX" at the end of the segment file name. */
+  sufx_len = IZ_MAX( 0, ((int)strlen(G.zipfn_sgmnt)- 4));
+  suffix = G.zipfn_sgmnt+ sufx_len;
+
+  /* try find filename extension and set right position for add number */
+  if (zfstrcmp(suffix, ZSUFX) == 0)
+  {
+    suffix += 2;        /* Point to digits after ".z". */
+# ifdef ZSUFX2
+  }
+  else if (zfstrcmp(suffix, ZSUFX2) == 0)       /* Check alternate suffix. */
+  {
+    suffix[1] = 'z';    /* Should be always lowercase??? */
+    suffix += 2;        /* Point to digits after ".z". */
+# endif
+  }
+  else
+  {
+    zfstrcpy( (suffix+ sufx_len), ZSUFX);
+    suffix += sufx_len+ 2;
+  }
+  /* Insert the next segment number into the file name (G.zipfn_sgmnt). */
+  sprintf(suffix, "%02d", (sgmnt_nr+ 1));
+
+#endif /* def VMS [else] */
+
+  return 0;
+} /* set_zipfn_sgmnt_name(). */
+
+/********************************/
+/* Function open_infile_sgmnt() */
+/********************************/
+int open_infile_sgmnt(__G__ movement)
+  __GDEF
+  int movement;
+{
+  zipfd_t zipfd;
+  zipfd_t zipfd_sgmnt;
+
+  if (movement == 0)            /* Nothing to do. */
+    return 0;
+
+   zipfd = G.zipfd;
+   zipfd_sgmnt = G.zipfd_sgmnt;
+
+  /* Set the new segment file name. */
+  if (set_zipfn_sgmnt_name( __G__ G.sgmnt_nr+ movement))
+    return 1;
+
+  if (open_infile( __G__ OIF_SEGMENT))
+  {
+    /* TODO: ask for input and try it again */
+    /* error, load back old zipfn (it shouldn't be frequently) */
+    if (fd_is_valid(zipfd_sgmnt))
+    {
+      set_zipfn_sgmnt_name( __G__ G.sgmnt_nr);
+    }
+    else
+    {
+      /* Loading of central directory record probably??? */
+      izu_free(G.zipfn_sgmnt);
+      G.zipfn_sgmnt = NULL;
+    }
+
+    G.zipfd_sgmnt = zipfd_sgmnt;
+    return 1;
+  }
+
+  G.sgmnt_nr += movement;
+
+  /* close old file - yes, that's nasty solution */
+  /* Switch I/O to the new segment. */
+  G.zipfd = G.zipfd_sgmnt;
+  G.zipfd_sgmnt = zipfd;                /* Old G.zipfd. */
+  CLOSE_INFILE( &G.zipfd_sgmnt);
+  if (fd_is_valid(zipfd_sgmnt))         /* Old G.zipfd_sgmnt. */
+  {
+    G.zipfd_sgmnt = G.zipfd;
+  }
+  else
+  {
+    izu_free(G.zipfn_sgmnt);            /* We must clean it now. */
+    G.zipfn_sgmnt = NULL;
+  }
+
+  return 0;
+} /* open_infile_sgmnt() */
 
 
 #if (!defined(VMS) && !defined(AOS_VS) && !defined(CMS_MVS) && !defined(MACOS))
@@ -581,11 +768,26 @@ unsigned readbuf(__G__ buf, size)   /* return number of bytes read into buf */
     unsigned n;
 
     n = size;
-    while (size) {
-        if (G.incnt <= 0) {
+    while (size)
+    {
+        if (G.incnt <= 0)
+        {
             if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) == 0)
-                return (n-size);
-            else if (G.incnt < 0) {
+            {
+              /* read() got no data.  If the srchive is segmented, then
+               * try again with the next segment file.
+               */
+              if (G.ecrec.number_this_disk > 0)
+              {
+                if ((open_infile_sgmnt( __G__ 1) != 0) ||
+                 (G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) == 0)
+                    return (n-size);    /* Return short retry size. */
+              } else
+                 return (n-size);       /* Return short size. */
+            }
+
+            if (G.incnt < 0)
+            {
                 /* another hack, but no real harm copying same thing twice */
                 (*G.message)((zvoid *)&G,
                   (uch *)LoadFarString(ReadError),  /* CANNOT use slide */
@@ -620,16 +822,33 @@ int readbyte(__G)   /* refill inbuf and return a byte if available, else EOF */
 {
     if (G.mem_mode)
         return EOF;
-    if (G.csize <= 0) {
+    if (G.csize <= 0)
+    {
         G.csize--;             /* for tests done after exploding */
         G.incnt = 0;
         return EOF;
     }
-    if (G.incnt <= 0) {
-        if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) == 0) {
-            return EOF;
-        } else if (G.incnt < 0) {  /* "fail" (abort, retry, ...) returns this */
-            /* another hack, but no real harm copying same thing twice */
+    if (G.incnt <= 0)
+    {
+        if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) == 0)
+        {
+            /* read() got no data.  If the srchive is segmented, then
+             * try again with the next segment file.
+             */
+            /* if(fd_is_valid(G.zipfd_sgmnt)) { */
+            if (G.ecrec.number_this_disk > 0)
+            {
+              if ((open_infile_sgmnt( __G__ 1) != 0) ||
+               (G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) == 0)
+                return EOF;
+            } else
+              return EOF;
+        }
+
+        if (G.incnt < 0)
+        {   /* "fail" (abort, retry, ...) returns this.
+             * another hack, but no real harm copying same thing twice.
+             */
             (*G.message)((zvoid *)&G,
               (uch *)LoadFarString(ReadError),
               (ulg)strlen(LoadFarString(ReadError)), 0x401);
@@ -724,55 +943,142 @@ int seek_zipf(__G__ abs_offset)
  *  "proper offset" (i.e., if there were no extra bytes prepended);
  *  cur_zipfile_bufstart contains the corrected offset.
  *
- *  Since seek_zipf() is never used during decompression, it is safe to
- *  use the slide[] buffer for the error message.
+ *  Because seek_zipf() is never used during decompression, it is safe
+ *  to use the slide[] buffer for the error message.
  *
  * returns PK error codes:
  *  PK_BADERR if effective offset in zipfile is negative
  *  PK_EOF if seeking past end of zipfile
  *  PK_OK when seek was successful
  */
-    zoff_t request = abs_offset + G.extra_bytes;
-    zoff_t inbuf_offset = request % INBUFSIZ;
-    zoff_t bufstart = request - inbuf_offset;
 
-    if (request < 0) {
+  zoff_t request;
+  zoff_t inbuf_offset;
+  zoff_t bufstart;
+
+  request = abs_offset + G.extra_bytes;
+
+#if 0 /* Pre-segment-support. */
+  if (request < 0)
+  {
+    Info(slide, 1, ((char *)slide, LoadFarStringSmall(SeekMsg),
+     G.zipfn, 11, LoadFarString(ReportMsg)));
+    return PK_BADERR;
+  }
+#endif /* 0 */ /* Pre-segment-support. */
+
+  while (request < 0)
+  {
+    if (G.sgmnt_size == 0)
+    {
+      if ((G.sgmnt_nr == 0) || open_infile_sgmnt( __G__ -1))
+      {
         Info(slide, 1, ((char *)slide, LoadFarStringSmall(SeekMsg),
-             G.zipfn, LoadFarString(ReportMsg)));
-        return(PK_BADERR);
-    } else if (bufstart != G.cur_zipfile_bufstart) {
-        Trace((stderr,
-          "fpos_zip: abs_offset = %s, G.extra_bytes = %s\n",
-          FmZofft(abs_offset, NULL, NULL),
-          FmZofft(G.extra_bytes, NULL, NULL)));
+         G.zipfn, 12, LoadFarString(ReportMsg)));
+        return PK_BADERR;
+      }
+      /* Get the new segment size, and calculate the new offset.
+       * This is where G.sgmnt_size gets a real (non-zero) value.
+       */
 #ifdef USE_STRM_INPUT
-        zfseeko(G.zipfd, bufstart, SEEK_SET);
-        G.cur_zipfile_bufstart = zftello(G.zipfd);
+      zfseeko(G.zipfd, 0, SEEK_END);
+      G.sgmnt_size = zftello(G.zipfd);
 #else /* !USE_STRM_INPUT */
-        G.cur_zipfile_bufstart = zlseek(G.zipfd, bufstart, SEEK_SET);
-#endif /* ?USE_STRM_INPUT */
-        Trace((stderr,
-          "       request = %s, (abs+extra) = %s, inbuf_offset = %s\n",
-          FmZofft(request, NULL, NULL),
-          FmZofft((abs_offset+G.extra_bytes), NULL, NULL),
-          FmZofft(inbuf_offset, NULL, NULL)));
-        Trace((stderr, "       bufstart = %s, cur_zipfile_bufstart = %s\n",
-          FmZofft(bufstart, NULL, NULL),
-          FmZofft(G.cur_zipfile_bufstart, NULL, NULL)));
-        if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) <= 0)
-            return(PK_EOF);
-        G.incnt -= (int)inbuf_offset;
-        G.inptr = G.inbuf + (int)inbuf_offset;
-    } else {
-        G.incnt += (G.inptr-G.inbuf) - (int)inbuf_offset;
-        G.inptr = G.inbuf + (int)inbuf_offset;
+      G.sgmnt_size = zlseek(G.zipfd, 0, SEEK_END);
+#endif /* USE_STRM_INPUT */
+      request += G.sgmnt_size;
     }
-    return(PK_OK);
-} /* end function seek_zipf() */
-
+    else
+    {
+      /* SMSd.  Can we trust that all segments have the same size? */
+      /* We know segment size(s?), so we can calculate against
+       * abs_offset and sgmnt_nr, and open the segment file which we
+       * actually need.
+       */
+      unsigned int tmp_disk = G.ecrec.number_this_disk;
+
+      while (request < 0)
+      {
+        tmp_disk--;
+        request += G.sgmnt_size;
+      }
+      /* for same as actual disk (movement == 0) return 0  */
+      if (open_infile_sgmnt( __G__ (tmp_disk- G.sgmnt_nr)))
+      {
+          Info(slide, 1, ((char *)slide, LoadFarStringSmall(SeekMsg),
+           G.zipfn, 13, LoadFarString(ReportMsg)));
+          return PK_BADERR;
+      }
+    }
+    /* In both cases we need to refill buffer, so set
+     * G.cur_zipfile_bufstart negative (so that bufstart !=
+     * G.cur_zipfile_bufstart, below).
+     */
+    G.cur_zipfile_bufstart = -1;
+  }
 
+  inbuf_offset = request % INBUFSIZ;
+  bufstart = request - inbuf_offset;
 
+  if (bufstart != G.cur_zipfile_bufstart)
+  {
+    Trace((stderr,
+     "fpos_zip: abs_offset = %s, G.extra_bytes = %s\n",
+     FmZofft(abs_offset, NULL, NULL),
+     FmZofft(G.extra_bytes, NULL, NULL)));
 
+#ifdef USE_STRM_INPUT
+    zfseeko(G.zipfd, bufstart, SEEK_SET);
+    G.cur_zipfile_bufstart = zftello(G.zipfd);
+#else /* def USE_STRM_INPUT */
+    G.cur_zipfile_bufstart = zlseek(G.zipfd, bufstart, SEEK_SET);
+#endif /* def USE_STRM_INPUT [else] */
+
+    Trace((stderr,
+     "       request = %s, (abs+extra) = %s, inbuf_offset = %s\n",
+     FmZofft(request, NULL, NULL),
+     FmZofft((abs_offset+G.extra_bytes), NULL, NULL),
+     FmZofft(inbuf_offset, NULL, NULL)));
+    Trace((stderr, "       bufstart = %s, cur_zipfile_bufstart = %s\n",
+     FmZofft(bufstart, NULL, NULL),
+     FmZofft(G.cur_zipfile_bufstart, NULL, NULL)));
+
+    if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) < INBUFSIZ)
+    {
+      /* If we're not at the end of file, then we need move to the
+       * next segment file.
+       * TODO: Check if EOF, instead?
+       */
+      if (G.ecrec.number_this_disk != G.sgmnt_nr)
+      {
+        int tmp;
+
+        if (open_infile_sgmnt( __G__ 1))
+          return PK_EOF; /*TODO: Add some new return code? */
+
+        /* append rest of data to buffer - it's important when we are only
+         * few bytes before EOF and want read CDR! Now it's more safe.
+         * Only some disk error could be wrong for us in that case.
+         */
+        tmp = read(G.zipfd, (char *)(G.inbuf+ G.incnt), (INBUFSIZ- G.incnt));
+        if (tmp <= 0)
+          return PK_EOF;
+
+        G.incnt += tmp;
+      }
+      else if (G.incnt <= 0)
+        return PK_EOF;
+    }
+    G.incnt -= (int)inbuf_offset;
+    G.inptr = G.inbuf + (int)inbuf_offset;
+  }
+  else
+  {
+    G.incnt += (int)(G.inptr- G.inbuf) - (int)inbuf_offset;
+    G.inptr = G.inbuf + (int)inbuf_offset;
+  }
+    return(PK_OK);
+} /* end function seek_zipf() */
 
 #ifndef VMS  /* for VMS use code in vms.c */
 
diff --git a/globals.c b/globals.c
index fa8cca5..9cac035 100644
--- a/globals.c
+++ b/globals.c
@@ -198,6 +198,9 @@ Uz_Globs *globalsCtor()
     G.mpause = UzpMorePause;
 #endif
     G.decr_passwd = UzpPassword;
+    G.zipfn_sgmnt = NULL;               /* Archive segment name */
+    G.zipfn_sgmnt_size = 0;             /* Archive segment size */
+    G.zipfd_sgmnt = ZIPFD_INVALID;      /* Archive segment file descr/pntr */
 #endif /* !FUNZIP */
 
 #if (!defined(DOS_FLX_H68_NLM_OS2_W32) && !defined(AMIGA) && !defined(RISCOS))
diff --git a/globals.h b/globals.h
index 11b7215..0a84432 100644
--- a/globals.h
+++ b/globals.h
@@ -243,12 +243,13 @@ typedef struct Globals {
     int       zipeof;
     char      *argv0;               /* used for NT and EXE_EXTENSION */
     char      *wildzipfn;
-    char      *zipfn;    /* GRR:  WINDLL:  must nuke any malloc'd zipfn... */
-#ifdef USE_STRM_INPUT
-    FILE      *zipfd;               /* zipfile file descriptor */
-#else
-    int       zipfd;                /* zipfile file handle */
-#endif
+    char      *zipfn;               /* zipfile path/name */
+    char      *zipfn_sgmnt;         /* zipfile segment path/name */
+    int       zipfn_sgmnt_size;     /* zipfile segment path/name size */
+    zuvl_t    sgmnt_nr;             /* zipfile segment number */
+    zoff_t    sgmnt_size;           /* zipfile segment size */
+    zipfd_t   zipfd;                /* zipfile primary file descr/pointer */
+    zipfd_t   zipfd_sgmnt;          /* zipfile segment file descr/pointer */
     zoff_t    ziplen;
     zoff_t    cur_zipfile_bufstart; /* extract_or_test, readbuf, ReadByte */
     zoff_t    extra_bytes;          /* used in unzip.c, misc.c */
@@ -306,7 +307,8 @@ typedef struct Globals {
     char     *unipath_filename;    /* UTF-8 path */
 #endif /* UNICODE_SUPPORT */
 
-#ifdef CMS_MVS
+#  ifdef CMS_MVS_INFILE_TMP
+    /* 2015-03-17 SMS.  See note in zos/vmmvs.c. */
     char     *tempfn;              /* temp file used; erase on close */
 #endif
 
diff --git a/process.c b/process.c
index 0d57ab4..76652a9 100644
--- a/process.c
+++ b/process.c
@@ -726,8 +726,10 @@ static int do_seekable(__G__ lastchance)        /* return PK-type error code */
         return PK_ERR;
 #endif
 
-    if (open_input_file(__G))   /* this should never happen, given */
-        return PK_NOZIP;        /*  the stat() test above, but... */
+    if (open_infile(__G__ OIF_PRIMARY))
+    { /* This should never fail, given the stat() test above, but... */
+        return PK_NOZIP;
+    }
 
 #ifdef DO_SAFECHECK_2GB
     /* Need more care: Do not trust the size returned by stat() but
@@ -740,7 +742,7 @@ static int do_seekable(__G__ lastchance)        /* return PK-type error code */
         printf(
 " We need a better error message for: 64-bit file, 32-bit program.\n");
         */
-        CLOSE_INFILE();
+        CLOSE_INFILE( &G.zipfd);
         return IZ_ERRBF;
     }
 #endif /* DO_SAFECHECK_2GB */
@@ -755,6 +757,7 @@ static int do_seekable(__G__ lastchance)        /* return PK-type error code */
 
     G.cur_zipfile_bufstart = 0;
     G.inptr = G.inbuf;
+    G.sgmnt_size = 0;   /* Init before ECREC for each archive in the list. */
 
 #if ((!defined(WINDLL) && !defined(SFX)) || !defined(NO_ZIPINFO))
 # if (!defined(WINDLL) && !defined(SFX))
@@ -785,7 +788,7 @@ static int do_seekable(__G__ lastchance)        /* return PK-type error code */
                                         MIN(G.ziplen, 66000L)))
          > PK_WARN )
     {
-        CLOSE_INFILE();
+       CLOSE_INFILE( &G.zipfd); 
 
 #ifdef SFX
         ++lastchance;   /* avoid picky compiler warnings */
@@ -804,7 +807,7 @@ static int do_seekable(__G__ lastchance)        /* return PK-type error code */
     }
 
     if ((uO.zflag > 0) && !uO.zipinfo_mode) { /* unzip: zflag = comment ONLY */
-        CLOSE_INFILE();
+        CLOSE_INFILE( &G.zipfd);
         return error_in_archive;
     }
 
@@ -892,10 +895,13 @@ static int do_seekable(__G__ lastchance)        /* return PK-type error code */
             else
                 Info(slide, 0x401, ((char *)slide, LoadFarString(ZipfileEmpty),
                                     G.zipfn));
-            CLOSE_INFILE();
+            CLOSE_INFILE( &G.zipfd);
             return (error_in_archive > PK_WARN)? error_in_archive : PK_WARN;
         }
 
+        /* Set the segment number (needed for segmented archives). */
+        G.sgmnt_nr = G.ecrec.number_this_disk;
+
     /*-----------------------------------------------------------------------
         Compensate for missing or extra bytes, and seek to where the start
         of central directory should be.  If header not found, uncompensate
@@ -905,12 +911,12 @@ static int do_seekable(__G__ lastchance)        /* return PK-type error code */
 
         error = seek_zipf(__G__ G.ecrec.offset_start_central_directory);
         if (error == PK_BADERR) {
-            CLOSE_INFILE();
+            CLOSE_INFILE( &G.zipfd);
             return PK_BADERR;
         }
 #ifdef OLD_SEEK_TEST
         if (error != PK_OK || readbuf(__G__ G.sig, 4) == 0) {
-            CLOSE_INFILE();
+            CLOSE_INFILE( &G.zipfd);
             return PK_ERR;  /* file may be locked, or possibly disk error(?) */
         }
         if (memcmp(G.sig, central_hdr_sig, 4))
@@ -932,7 +938,7 @@ static int do_seekable(__G__ lastchance)        /* return PK-type error code */
                   Info(slide, 0x401, ((char *)slide,
                     LoadFarString(CentDirStartNotFound), G.zipfn,
                     LoadFarStringSmall(ReportMsg)));
-                CLOSE_INFILE();
+                CLOSE_INFILE( &G.zipfd);
                 return (error != PK_OK ? error : PK_BADERR);
             }
 #ifndef SFX
@@ -950,7 +956,7 @@ static int do_seekable(__G__ lastchance)        /* return PK-type error code */
 
         error = seek_zipf(__G__ G.ecrec.offset_start_central_directory);
         if (error != PK_OK) {
-            CLOSE_INFILE();
+            CLOSE_INFILE( &G.zipfd);
             return error;
         }
 
@@ -996,7 +1002,7 @@ static int do_seekable(__G__ lastchance)        /* return PK-type error code */
     } /* end if (!too_weird_to_continue) */
 #endif
 
-    CLOSE_INFILE();
+    CLOSE_INFILE( &G.zipfd);
 
 #ifdef TIMESTAMP
     if (uO.T_flag && !uO.zipinfo_mode && (nmember > 0L)) {
diff --git a/unix/Makefile b/unix/Makefile
index ab32270..783f261 100644
--- a/unix/Makefile
+++ b/unix/Makefile
@@ -47,7 +47,7 @@ LD = $(CC)#	must match, else "unresolved symbol:  ___main" is possible)
 AS = as
 LOC = $(D_USE_BZ2) $(LOCAL_UNZIP)
 AF = $(LOC)
-CFLAGS = -O
+CFLAGS = -O0
 CF_NOOPT = -I. -I$(IZ_BZIP2) -DUNIX $(LOC)
 CF = $(CFLAGS) $(CF_NOOPT)
 LFLAGS1 =
@@ -594,12 +594,12 @@ generic_shlib:	unix_make
 	@echo\
  'which is UnZip linked with the DLL).  This target is an example only.'
 	@echo ""
-	$(MAKE) objsdll CC=gcc CFLAGS="-O3 -Wall -fPIC -DDLL"
+	$(MAKE) objsdll CC=gcc CFLAGS="-O0 -Wall -fPIC -DDLL"
 	gcc -shared -Wl,-soname,libunzip.so.0 -o libunzip.so.0.4 $(OBJSDLL)
 	$(RM) libunzip.so.0 libunzip.so
 	$(LN) -s libunzip.so.0.4 libunzip.so.0
 	$(LN) -s libunzip.so.0 libunzip.so
-	gcc -c -O unzipstb.c
+	gcc -c -O0 unzipstb.c
 	gcc -o unzip_shlib unzipstb.o -L. -lunzip
 
 #----------------------------------------------------------------------------
@@ -694,7 +694,7 @@ _v7:
 	$(MAKE) unzips CF="$(CF) -DNO_DIR -DNO_MKDIR -DNO_STRNICMP -DNO_UID_GID -DNO_FCHMOD -DNO_LCHOWN -DNO_LCHMOD -DCBREAK=2"
 
 7300_gcc:	unix_make
-	$(MAKE) unzips CC=gcc LD=gcc LF2="" CFLAGS="-O2" \
+	$(MAKE) unzips CC=gcc LD=gcc LF2="" CFLAGS="-O0" \
 	 LOC="-DNO_DIR -DNO_MKDIR -DNO_STDLIB_H -DNO_STRNICMP -DNO_UID_GID -DNO_FCHMOD -DNO_LCHOWN -DNO_LCHMOD -DCBREAK=2 $(LOC)"
 	$(STRIP) $(UNZIPS)
 
@@ -717,13 +717,13 @@ apollo:		unix_make
 bsdi:		unix_make
 	@echo 'NOTE:  use bsdi_noasm target for non-Intel BSD/OS compiles.'
 	$(MAKE) unzips CC=gcc2 LD=shlicc2 AS=gcc2\
-	 CFLAGS="-O3 -Wall -DASM_CRC -DBSD" CRCA_O=crc_gcc$O
+	 CFLAGS="-O0 -Wall -DASM_CRC -DBSD" CRCA_O=crc_gcc$O
 
 # BSDI BSD/OS
 bsdi_noasm:	unix_make
 #	@echo 'NOTE:  use bsd target for non-Intel BSD/OS compiles.'
 	$(MAKE) unzips CC=gcc2 LD=shlicc2 AS=gcc2\
-	 CFLAGS="-O3 -Wall -DBSD"
+	 CFLAGS="-O0 -Wall -DBSD"
 
 # Coherent 3.x/4.x, Mark Williams C.  ``For Coherent's CC, it needs either
 # -T0 or -T150000 (or bigger) added to the CFLAGS, otherwise the compiler
@@ -747,7 +747,7 @@ cyber_sgi:	unix_make
 # Info-ZIP recommends using "win32/Makefile.gcc" instead.
 cygwin:		unix_make
 	$(MAKE) unzips CC=gcc LD=gcc AS=gcc\
-	 CFLAGS="-O3 -DASM_CRC -DNO_LCHOWN -DNO_LCHMOD"\
+	 CFLAGS="-O0 -DASM_CRC -DNO_LCHOWN -DNO_LCHMOD"\
 	 AF="-Di386 $(AF)" CRCA_O=crc_gcc$O\
 	 E=".exe" CP="cp" LN="ln -s"
 
@@ -764,7 +764,7 @@ dnix:		unix_make
 freebsd:		unix_make
 	@echo 'NOTE:  use bsd target for non-Intel FreeBSD compiles (if any).'
 	$(MAKE) unzips CC=gcc LD=gcc AS=gcc\
-	 CFLAGS="-O3 -Wall -DASM_CRC -DBSD"\
+	 CFLAGS="-O0 -Wall -DASM_CRC -DBSD"\
 	 AF="-Di386 $(AF)" CRCA_O=crc_gcc$O
 
 # Generic BSDish Unix gcc.  ``The -O3 only works with later versions of gcc;
@@ -775,7 +775,7 @@ freebsd:		unix_make
 # with "echo" instead).
 #
 gcc:		unix_make
-	$(MAKE) unzips CC=gcc LD=gcc CFLAGS="-O3" LF2=""
+	$(MAKE) unzips CC=gcc LD=gcc CFLAGS="-O0" LF2=""
 	$(STRIP) $(UNZIPS)
 
 # Heurikon HK68 (68010), UniPlus+ System V 5.0, Green Hills C-68000
@@ -787,13 +787,13 @@ hk68:		unix_make
 # ISC Unix on 386 platform
 isc:		unix_make
 	$(MAKE) unzips LF2="-lc_s $(LF2)" CRCA_O=crc_sysv$O \
-	 CFLAGS="-O" LOC="-DASM_CRC -DSYSV -DNO_UID_GID -DNEED_PTEM -DNO_LCHOWN -DNO_LCHMOD $(LOC)" \
+	 CFLAGS="-O0" LOC="-DASM_CRC -DSYSV -DNO_UID_GID -DNEED_PTEM -DNO_LCHOWN -DNO_LCHMOD $(LOC)" \
 	 AF="-DNO_UNDERLINE -Djecxz=jcxz -DALIGNMENT='.align 16' $(AF)"
 
 isc_gcc:	unix_make
 	$(MAKE) unzips AS=gcc CC=gcc LD=gcc CRCA_O=crc_gcc$O \
 	 LF="-shlib $(LF)" SL="-shlib $(SL)" FL="-shlib $(FL)" LF2="" \
-	 CFLAGS="-O3" LOC="-DSYSV -DASM_CRC -DNO_UID_GID -DNEED_PTEM -DNO_LCHOWN -DNO_LCHMOD $(LOC)" \
+	 CFLAGS="-O0" LOC="-DSYSV -DASM_CRC -DNO_UID_GID -DNEED_PTEM -DNO_LCHOWN -DNO_LCHMOD $(LOC)" \
 	 AF="-DNO_UNDERLINE -Djecxz=jcxz -DALIGNMENT='.align 16' $(AF)"
 	$(STRIP) $(UNZIPS)
 
@@ -809,7 +809,7 @@ isi:		unix_make
 linux:		unix_make
 	@echo 'NOTE:  use linux_noasm target for non-Intel Linux compiles.'
 	$(MAKE) unzips CC=gcc LD=gcc AS=gcc\
-	 CFLAGS="-O3 -Wall -DASM_CRC"\
+	 CFLAGS="-O0 -Wall -DASM_CRC"\
 	 AF="-Di386 $(AF)" CRCA_O=crc_gcc$O
 # GRR:  this echo is pointless; if user gets this far, no difference to install
 #	@echo 'Be sure to use the install_asm target rather than the install target'
@@ -819,19 +819,19 @@ linux_asm:	linux
 # Linux (Posix, approximately SysV):  virtually any version since before 0.96,
 # for any platform.  Change "-O" to "-O3" or whatever, as desired...
 linux_noasm:	unix_make
-	$(MAKE) unzips CC=gcc LD=gcc CFLAGS="-O -Wall"
+	$(MAKE) unzips CC=gcc LD=gcc CFLAGS="-O0 -Wall"
 
 # Linux with lcc compiler:  __inline__ (stat.h) not recognized, and must edit
 # /usr/include/gnu/types.h to get rid of "long long" if __LCC__ defined.  -O3
 # (or -O2 or -O) is ignored.  [GRR 960828: test target only]
 #
 linux_lcc:	unix_make
-	$(MAKE) unzips CC=lcc LD=lcc CFLAGS="-O3 -Wall -D__inline__= "
+	$(MAKE) unzips CC=lcc LD=lcc CFLAGS="-O0 -Wall -D__inline__= "
 
 # Linux host with go32 (djgpp) cross-compiler (go32crs.tgz) for 32-bit DOS.
 linux_dos:	unix_make
 	$(MAKE) unzips CC=go32gcc LD=go32gcc M=msdos OSDEP_H="msdos/doscfg.h" \
-	 CFLAGS="-O2 -Wall"
+	 CFLAGS="-O0 -Wall"
 #	go32-strip unzip
 #	Due to limitations of the cross-compiling package, this has to be
 #	done manually:
@@ -845,25 +845,25 @@ linux_dos:	unix_make
 # library).
 #
 linux_shlib:	unix_make
-	$(MAKE) objsdll CC=gcc CFLAGS="-O3 -Wall -fPIC"\
+	$(MAKE) objsdll CC=gcc CFLAGS="-O0 -Wall -fPIC"\
 	 LOC="-DDLL -DASM_CRC $(LOC)"\
 	 AS=gcc AF="-fPIC -Di386 $(AF)" CRCA_O=crc_gcc$O
 	gcc -shared -Wl,-soname,libunzip.so.0 -o libunzip.so.0.4 $(OBJSDLL)\
 	 crc_gcc.pic.o
 	ln -sf libunzip.so.0.4 libunzip.so.0
 	ln -sf libunzip.so.0 libunzip.so
-	gcc -c -O unzipstb.c
+	gcc -c -O0 unzipstb.c
 	gcc -o unzip_shlib unzipstb.o -L. -lunzip
 
 # Linux ELF shared library, as above, but using inflate() from zlib (libz.so)
 # instead of the original UnZip version.  (libz was libgz prior to 0.94)
 linux_shlibz:	unix_make
 	$(MAKE) objsdll CC=gcc AS=gcc AF="-fPIC -Di386 $(AF)" CRCA_O=crc_gcc$O\
-	 CFLAGS="-O3 -Wall -fPIC" LOC="-DDLL -DUSE_ZLIB -DASM_CRC $(LOC)"
+	 CFLAGS="-O0 -Wall -fPIC" LOC="-DDLL -DUSE_ZLIB -DASM_CRC $(LOC)"
 	gcc -shared -Wl,-soname,libunzip.so.0 -o libunzip.so.0.4 $(OBJSDLL)\
 	 crc_gcc.pic.o
 	ln -sf libunzip.so.0.4 libunzip.so.0
-	gcc -c -O unzipstb.c
+	gcc -c -O0 unzipstb.c
 	gcc -o unzip unzipstb.o -L. -lunzip -lz
 
 # LynxOS-x86 2.3.0 and newer, a real-time BSD-like OS; uses gcc.
@@ -872,12 +872,12 @@ lynx:		unix_make
 
 # Macintosh MacOS X (Unix-compatible enviroment), using standard compiler
 macosx:	unix_make
-	$(MAKE) unzips CFLAGS="-O3 -Wall -DBSD" LF2=""
+	$(MAKE) unzips CFLAGS="-O0 -Wall -DBSD" LF2=""
 	$(STRIP) $(UNZIPS)
 
 # Macintosh MacOS X (Unix-compatible enviroment), using gcc
 macosx_gcc:	unix_make
-	$(MAKE) unzips CC=gcc CFLAGS="-O3 -Wall -DBSD" LF2=""
+	$(MAKE) unzips CC=gcc CFLAGS="-O0 -Wall -DBSD" LF2=""
 	$(STRIP) $(UNZIPS)
 
 # Minix 1.5 PC for the 386.  Invoke as is to use default cc, or as "make
@@ -914,12 +914,12 @@ next2x:		unix_make
 
 # NeXT 3.x: as above, plus better optimization.
 next3x:		unix_make
-	$(MAKE) unzips CFLAGS="-O2" LF2="-object -s"
+	$(MAKE) unzips CFLAGS="-O0" LF2="-object -s"
 
 # NeXT 3.1+: make the executable fat (multi-architecture binary [MAB],
 # for "black" [NeXT] and "white" [x86] hardware, so far).
 nextfat:	unix_make
-	$(MAKE) unzips CFLAGS="-O2 -arch i386 -arch m68k" \
+	$(MAKE) unzips CFLAGS="-O0 -arch i386 -arch m68k" \
 	 LF2="-arch i386 -arch m68k -object -s"
 
 # IBM OS/390 (formerly MVS) compiled under "OpenEdition" shell
@@ -972,7 +972,7 @@ rs6000:		unix_make
 # recognize the -M0 flag that forces 8086 code.)  (GRR:  may need to reduce
 # stack to 0c00h if using 286/small-model code...?)
 sco_dos:	unix_make
-	$(MAKE) unzips CFLAGS="-O -dos -M0" M=msdos OSDEP_H="msdos/doscfg.h" \
+	$(MAKE) unzips CFLAGS="-O0 -dos -M0" M=msdos OSDEP_H="msdos/doscfg.h" \
 	 LF="-dos -F 2000" LF2="-o unzip.exe" \
 	 FL="-dos" FL2="-o funzip.exe" SL="-dos" SL2="-o unzipsfx.exe"
 
@@ -1000,7 +1000,7 @@ sunos3:		unix_make
 
 # Generic System V + GNU C
 sysv_gcc:	unix_make
-	$(MAKE) unzips CC=gcc LD=gcc CFLAGS="-O2 -DSYSV" LF2=""
+	$(MAKE) unzips CC=gcc LD=gcc CFLAGS="-O0 -DSYSV" LF2=""
 	$(STRIP) $(UNZIPS)
 
 # AT&T 6300+, System V.2 Unix:  run-time out-of-memory error if don't use -Ml;
diff --git a/unzpriv.h b/unzpriv.h
index 5c83a6e..22ef1eb 100644
--- a/unzpriv.h
+++ b/unzpriv.h
@@ -567,7 +567,6 @@
 
 #ifdef CMS_MVS
 #  include "vmmvs.h"
-#  define CLOSE_INFILE()  close_infile(__G)
 #endif
 
 /*---------------------------------------------------------------------------
@@ -669,8 +668,10 @@
    typedef unsigned int extent;
 #endif /* ?MODERN */
 
-
-
+/* compatible macros with upstream */
+# define izu_free free
+# define izu_malloc malloc
+# define izu_realloc realloc
 
 /*************/
 /*  Defines  */
@@ -768,7 +769,7 @@
 #  define DATE_SEPCHAR  '-'
 #endif
 #ifndef CLOSE_INFILE
-#  define CLOSE_INFILE()  close(G.zipfd)
+#  define CLOSE_INFILE( pfd)  close_infile(__G__ pfd)
 #endif
 #ifndef RETURN
 #  define RETURN        return  /* only used in main() */
@@ -1661,6 +1662,10 @@
 #define GETPATH           4    /* retrieve the complete path and free it */
 #define END               5    /* free root path prior to exiting program */
 
+/* Input archive file options for fileio.c:open_infile(). */
+#define OIF_PRIMARY     0       /* Primary archive (".zip") file. */
+#define OIF_SEGMENT     1       /* Segment archive (".zXX") file. */
+
 /* version_made_by codes (central dir):  make sure these */
 /*  are not defined on their respective systems!! */
 #define FS_FAT_           0    /* filesystem used by MS-DOS, OS/2, Win32 */
@@ -1977,6 +1982,14 @@
 #  endif
 #endif
 
+    /* Archive file descriptor/pointer. */
+#ifdef USE_STRM_INPUT
+    typedef FILE *zipfd_t;              /* Stdio file pointer. */
+#else /* def USE_STRM_INPUT */
+    typedef int   zipfd_t;              /* UNIX I/O file descriptor. */
+#endif /* def USE_STRM_INPUT */
+
+
 #if (defined(GOT_UTIMBUF) || defined(sgi) || defined(ATARI))
    typedef struct utimbuf ztimbuf;
 #else
@@ -2305,8 +2318,10 @@ void     fnprint                 OF((__GPRO));
     Functions in fileio.c:
   ---------------------------------------------------------------------------*/
 
-int      open_input_file      OF((__GPRO));
+int      close_infile         OF((__GPRO__ zipfd_t *pfd));
+int      open_infile          OF((__GPRO__ int which));
 int      open_outfile         OF((__GPRO));                    /* also vms.c */
+int      set_zipfn_sgmnt_name OF((__GPRO__ zuvl_t sgmnt_nr));
 void     undefer_input        OF((__GPRO));
 void     defer_leftover_input OF((__GPRO));
 unsigned readbuf              OF((__GPRO__ char *buf, register unsigned len));
@@ -2525,8 +2540,10 @@ int    huft_build                OF((__GPRO__ ZCONST unsigned *b, unsigned n,
 
 #ifdef CMS_MVS
    extent getVMMVSexfield     OF((char *type, uch *ef_block, unsigned datalen));
-   FILE  *vmmvs_open_infile   OF((__GPRO));                       /* vmmvs.c */
+   FILE  *vmmvs_open_infile   OF((__GPRO__ char *fn));            /* vmmvs.c */
+#if 0
    void   close_infile        OF((__GPRO));                       /* vmmvs.c */
+#endif /* 0 */
 #endif
 
 /*---------------------------------------------------------------------------
@@ -2548,6 +2565,9 @@ int    huft_build                OF((__GPRO__ ZCONST unsigned *b, unsigned n,
    ulg    vms_unzip_cmdline   OF((int *, char ***));            /* cmdline.c */
    int    VMSCLI_usage        OF((__GPRO__ int error));         /* cmdline.c */
 #endif
+   int vms_sgmnt_name         OF((char *fn_sgmnt,                   /* vms.c */
+                                  char *fn_primary,
+                                  zuvl_t nr_sgmnt));
 #endif
 
 /*---------------------------------------------------------------------------
@@ -2645,12 +2665,8 @@ char    *GetLoadPath     OF((__GPRO));                              /* local */
 /*  Macros  */
 /************/
 
-#ifndef MAX
-#  define MAX(a,b)   ((a) > (b) ? (a) : (b))
-#endif
-#ifndef MIN
-#  define MIN(a,b)   ((a) < (b) ? (a) : (b))
-#endif
+#define IZ_MAX( a, b) ((a) > (b) ? (a) : (b))
+#define IZ_MIN( a, b) ((a) < (b) ? (a) : (b))
 
 #ifdef DEBUG
 #  if (defined(THEOS) && defined(NO_BOGUS_SPC))
@@ -2685,13 +2701,22 @@ char    *GetLoadPath     OF((__GPRO));                              /* local */
    /* ``Replace'' the unbuffered UNIX style I/O function with similar
     * standard C functions from <stdio.h>.
     */
-#  define read(fd,buf,n) fread((buf),1,(n),(FILE *)(fd))
-#  ifdef zlseek
-#    undef zlseek
-#  endif
-#  define zlseek(fd,o,w) zfseeko((FILE *)(fd),(o),(w))
-#  define close(fd) fclose((FILE *)(fd))
-#endif /* USE_STRM_INPUT */
+# define read(fd,buf,n) fread((buf),1,(n),(FILE *)(fd))
+# ifdef zlseek
+#  undef zlseek
+# endif
+# define zlseek(fd,o,w) zfseeko((FILE *)(fd),(o),(w))
+# define close(fd) fclose((FILE *)(fd))
+# define fd_is_valid(fd) (fd != NULL)
+# define ZIPFD_INVALID NULL
+#else /* def USE_STRM_INPUT */
+# ifdef _WIN32_WCE                      /* Really necessary? */
+#  define fd_is_valid(fd) (fd != -1)
+# else /* def _WIN32_WCE [else] */
+#  define fd_is_valid(fd) (fd >= 0)
+# endif /* def _WIN32_WCE [else] */
+# define ZIPFD_INVALID (-1)
+#endif /* def USE_STRM_INPUT [else] */
 
 /* The return value of the Info() "macro function" is never checked in
  * UnZip. Otherwise, to get the same behaviour as for (*G.message)(), the
diff --git a/vms/vms.c b/vms/vms.c
index d826174..a57f1d7 100644
--- a/vms/vms.c
+++ b/vms/vms.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 1990-2009 Info-ZIP.  All rights reserved.
+  Copyright (c) 1990-2015 Info-ZIP.  All rights reserved.
 
   See the accompanying file LICENSE, version 2009-Jan-02 or later
   (the contents of which are also included in unzip.h) for terms of use.
@@ -34,6 +34,7 @@
              screensize()
              screenlinewrap()
              version()
+             vms_sgmnt_name()
 
   ---------------------------------------------------------------------------*/
 
@@ -581,6 +582,59 @@ int open_outfile(__G)
     }
 }
 
+/* vms_sgmnt_name()
+ *
+ *    Derive an archive segment file spec from an archive primary file
+ *    spec and the desired segment number.  File specs are  VMS-style.
+ *    Returns sys$parse() status, with expanded file spec in user's
+ *    storage.
+ */
+int vms_sgmnt_name( char *fn_sgmnt, char *fn_primary, zuvl_t nr_sgmnt)
+{
+    int sts;
+    char sgmnt_type[ 16];
+
+    struct FAB fab;
+    struct NAMX_STRUCT nam;
+    char e_name[ NAMX_MAXRSS + 1];
+
+    fab = cc$rms_fab;                   /* Initialize FAB. */
+    nam = CC_RMS_NAMX;                  /* Initialize NAM[L]. */
+    fab.FAB_NAMX = &nam;                /* Point FAB to NAM[L]. */
+
+    /* Form a ".zXX;" type string and version from the segment number. */
+    sprintf( sgmnt_type, ".z%02u;", nr_sgmnt);
+
+    NAMX_DNA_FNA_SET( fab)
+
+    /* Use the primary archive name as the default file spec. */
+    FAB_OR_NAML( fab, nam).FAB_OR_NAML_DNA = fn_primary;
+    FAB_OR_NAML( fab, nam).FAB_OR_NAML_DNS = strlen( fn_primary);
+
+    /* Use the segment type and version as the normal file spec. */
+    FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNA = sgmnt_type;
+    FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNS = strlen( sgmnt_type);
+
+    nam.NAMX_ESA = e_name;
+    nam.NAMX_ESS = sizeof( e_name)- 1;
+
+    nam.NAMX_NOP = NAMX_M_SYNCHK;         /* Syntax-only analysis. */
+    sts = sys$parse( &fab);
+    if ((sts & STS$M_SUCCESS) == STS$K_SUCCESS)
+    {
+        /* Save (NUL-terminated) result in user's storage. */
+        e_name[ nam.NAMX_ESL] = '\0';
+        strncpy( fn_sgmnt, nam.NAMX_ESA, (nam.NAMX_ESL+ 1));
+    }
+    else
+    {
+        fn_sgmnt[0] = '\0';
+    }
+
+    return sts;
+} /* vms_sgmnt_name(). */
+
+
 static void init_buf_ring()
 {
     locptr = &locbuf[0];