Subversion Repositories autosfx

Rev

Blame | Last modification | View Log | RSS feed

  1. #include "stdafx.h"
  2. #pragma hdrstop
  3.  
  4. #include "ZipOp.h"
  5. #include "dz_errs.h"
  6.  
  7. #undef _DZ_FILE_
  8. #define _DZ_FILE_ DZ_ZIPPRC_CPP
  9.  
  10. /* DLLzip.c * Copyright (C) 1990-1996 Mark Adler, Richard B. Wales, Jean-loup Gailly,
  11.  * Kai Uwe Rommel, Onno van der Linden and Igor Mandrichenko.
  12.  * This version modified by Chris Vleghert and Eric Engler for BCB/Delphi Zip.
  13.  ** distributed under LGPL license
  14.  
  15.   Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
  16.  
  17.   See the accompanying file LICENSE, version 2007-Mar-4 or later
  18.   (the contents of which are also included in zip.h) for terms of use.
  19.   If, for some reason, all these files are missing, the Info-ZIP license
  20.   also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
  21.  
  22.   parts Copyright (C) 1997 Mike White, Eric W. Engler
  23. ************************************************************************
  24.  Copyright (C) 2009, 2010  by Russell J. Peters, Roger Aelbrecht
  25.  
  26.    This file is part of TZipMaster Version 1.9.
  27.  
  28.     TZipMaster is free software: you can redistribute it and/or modify
  29.     it under the terms of the GNU Lesser General Public License as published by
  30.     the Free Software Foundation, either version 3 of the License, or
  31.     (at your option) any later version.
  32.  
  33.     TZipMaster is distributed in the hope that it will be useful,
  34.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  35.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  36.     GNU Lesser General Public License for more details.
  37.  
  38.     You should have received a copy of the GNU Lesser General Public License
  39.     along with TZipMaster.  If not, see <http://www.gnu.org/licenses/>.
  40.  
  41.     contact: problems@delphizip.org (include ZipMaster in the subject).
  42.     updates: http://www.delphizip.org
  43.     DelphiZip maillist subscribe at http://www.freelists.org/list/delphizip
  44. ************************************************************************
  45. */
  46.  
  47. #include <process.h>
  48. #include <signal.h>
  49. #include <errno.h>
  50. #include <stdlib.h>
  51. #include <io.h>
  52.  
  53. // Local option flags
  54. #define PURGE   0 // RCV Changed: was DELETE. (delete is also a function)
  55. #define ADD     1
  56. #define UPDATE  2
  57. #define FRESHEN 3
  58.  
  59. #define MARK_PURGE      -1
  60. #define MARK_KEEP       0
  61. #define MARK_UPDATE     1
  62. #define MARK_RENAMED    2
  63. #define MARK_VERSION    3
  64. #define MARK_NEW        4
  65.  
  66. #ifndef UNICODE
  67. #define __access _access
  68. #endif
  69.  
  70. // Process -o and -m options (if specified), free up malloc'ed stuff, and
  71. //   exit with the code e. e :: Exit code.
  72. void ZipFunc::finish(void)
  73. {
  74.     int r; // return value from trash()
  75.     ulg t; // latest time in zip file
  76.  
  77.         ZipItem *z; // pointer into zfile list
  78.  
  79.     if (flatest && fzipfile.Compare(_T("-")))
  80.     {
  81.         diag(_T("changing time of zip file to time of latest file in it"));
  82.  
  83.         // find latest time in zip file
  84.         if (fzfiles == NULL)
  85.         {
  86.             Notify(IWARNING,
  87.                    _T("zip file is empty, can't make it as old as latest entry"));
  88.         }
  89.         else
  90.         {
  91.             t = 0;
  92.  
  93.                         for (z = fzfiles; z != NULL; z = z->nxt) // Ignore directories in time comparisons
  94.             if (!z->IsFolder && t < z->tim)
  95.                                 t = z->tim;
  96.             // set modified time of zip file to that time
  97.             if (t != 0)
  98.                 stamp(fzipfile, t);
  99.             else
  100.                 Notify(IWARNING,
  101.                        _T("zip file has only directories, can't make it as old as latest entry"));
  102.         }
  103.     }
  104.  
  105.     // If dispose, delete all files in the zfiles list that are marked
  106.     if (fdispose && !Abort_Flag)
  107.     {
  108.         // v1.6017
  109.         diag(_T("deleting files that were added to zip file"));
  110.  
  111.         if ((r = trash()) != DZ_ERR_GOOD)
  112.             DZError(r);
  113.     }
  114. }
  115.  
  116. void ZipFunc::ZipCleanup(void)
  117. {
  118.     delete [] fhwbuf;
  119.     fhwbuf = NULL;
  120.  
  121.     if (ftempzip && (ftempzip != fzipfile))
  122.     {
  123.         // using temp file
  124.         if (fZipOutfile)
  125.         {
  126.             delete fZipOutfile;
  127.             fZipOutfile = NULL;
  128.         }
  129.  
  130.         // remove bad file - if it exists
  131.         EraseFile(ftempzip, false);
  132.     }
  133.  
  134.     Close_Handle(&fhInz);
  135.  
  136.     if (fZipOutfile)
  137.     {
  138.         bool wasopen =  fZipOutfile->IsOpen() && fZipOutfile->IsFile;
  139.         delete fZipOutfile;
  140.         fZipOutfile = NULL;
  141.         // remove damaged file
  142.  
  143.         if (wasopen)
  144.         {
  145.             if (Verbose)
  146.                 Notify(IVERBOSE, _T("deleting damaged %s"), fzipfile.c_str());
  147.  
  148.             EraseFile(fzipfile, false);
  149.         }
  150.     }
  151.  
  152.     ftempzip = "";
  153. }
  154.  
  155. int DriveType(const DZStrW& pth)
  156. {
  157.     TCHAR root[3];
  158.     root[0] = pth.IsEmpty() ? (char)0 : pth[0];
  159.     root[1] = ':';
  160.     root[2] = 0;
  161.  
  162.     if (root[0] == BSLASH)
  163.         root[1] = 0;
  164.  
  165.     return GetDriveType(root);
  166. }
  167.  
  168. const char hx[16] = "0123456789ABCDEF";
  169. char hxbuf[16];
  170. char* toHex(unsigned val)
  171. {
  172.     char* p = &hxbuf[15];
  173.     *p = 0;
  174.     while (val)
  175.     {
  176.         *--p = hx[val & 0x0f];
  177.         val >>= 4;
  178.     }
  179.     return p;
  180. }
  181.  
  182.  
  183. int __fastcall ZipFunc::NameVer(ZipItem* z)
  184. {
  185.         int r;
  186.         DZStrW name = z->IName;
  187.         int i = name.ReverseFind(_T('.'));
  188.  
  189.     if (!VerDate)
  190.     {
  191.         FILETIME now;
  192.         WORD d, t;
  193.         GetSystemTimeAsFileTime(&now);
  194.  
  195.         if (FileTimeToDosDateTime(&now, &d, &t))
  196.             VerDate = (d << 16) | t;
  197.         else
  198.             VerDate = z->tim;
  199.     }
  200.  
  201.     DZStrW nx, nn(name);
  202.     nx = _T("}");
  203.  
  204.     if (i >= 0)
  205.     {
  206.         nn = name.Left(i);
  207.         nx += name.Mid(i);
  208.     }
  209.  
  210.     i = -1;
  211.  
  212.     nn.AppendFormat(_T(".{%X"), VerDate);
  213.     name = nn;
  214.         name += nx;
  215.         DZStrA hn = StrIntSep(name);
  216.  
  217.         const XItem* n;
  218.         while ((n = IntList->FindName(name)) != NULL)
  219.         {
  220.                 // exists
  221.                 if (++i == MAXINT)
  222.                         return -2;  // give up
  223.  
  224.                 name.Format(_T("%s-%X%s"), nn.c_str(), i, nx.c_str());
  225.         }
  226.         hn = StrIntSep(name);
  227.         if (Verbose < 0)
  228.                 Notify(IVERBOSE, _T("%s versioned as %s"), z->iname, name.c_str());
  229.         z->IName = name;
  230.         z->HName = hn;
  231.         // prepare header name
  232.         if ((r = PrepareHeaderName(z, true)) != 0)
  233.                 return r;
  234.  
  235.     if (!n)
  236.         n = IntList->AddNode(z);
  237.  
  238.     return n ? -1 : 0;
  239. }
  240.  
  241. void ZipFunc::DupName(bool fatal, const XItem* o, const XItem* n, const DZStrW name)
  242. {
  243.     // duplicate found
  244.         Notify(IWARNING, _T("internal name in zip file repeated: %s"), name.c_str());
  245.     Notify(IWARNING, _T("  first full name: %s"), o->xname);
  246.     Notify(IWARNING, _T(" second full name: %s"), n->xname);
  247.  
  248.     if (fatal)
  249.                 throw DZException(DZ_ERM_DUPNAME);
  250.         Notify(IWARNING, _T(" rejecting: %s"), n->xname);
  251. }
  252.  
  253. int __fastcall ZipFunc::PrepareHeaderName(ZipItem* z, bool NoComment)
  254. {
  255.         if (!NoComment)
  256.     {
  257. //        // free any old data - probably obsolete
  258. //        z->cextra.Empty();
  259. //        z->extra.Empty();
  260.         if (z->ntfs)
  261.         {
  262.             delete z->ntfs;
  263.             z->ntfs = NULL;
  264.         }
  265.  
  266.         // get or change the comment
  267.         CB->Msg2 = z->Comment;
  268.         if (CB->UserCB(zacComment, z->IName) == CALLBACK_TRUE)
  269.         {
  270.             // User changed the comment
  271.             z->Comment.Empty();
  272.             z->com = CB->Arg1;
  273.  
  274.             if (z->com)
  275.             {
  276.                 DZStrW tc(CB->Msg, z->com);
  277.                 z->Comment = tc;
  278.             }
  279.         }
  280.     }
  281.         // ****** set header name and encoding
  282.         z->options.needutf8 = 0;
  283.         z->options.nameextd = z->IName.BadDOS();
  284.         z->options.cmntextd = z->com && z->Comment.BadDOS();
  285.         z->options.namenew = 0;
  286.  
  287.         DZStrW iiname = StrIntSep(z->IName);
  288.         bool wantOEM = true;
  289.         int bad = 0;
  290.         if (!z->options.nameextd && !z->options.cmntextd)
  291.         {
  292.                 // mimic WinZip
  293.                 z->Enc = zeoOEM;
  294.         }
  295.         else
  296.         {
  297.         unsigned doenc = fEncodeAs;
  298.         if (doenc == zeoAuto)
  299.         {
  300.                         doenc = zeoUPATH;
  301.                         if (z->options.nameextd && z->options.cmntextd)
  302.                                 doenc = zeoUTF8; // recommended
  303.         }
  304.  
  305.                 z->Enc = doenc;
  306.                 if (doenc == zeoUPATH)
  307.                 {
  308.                         z->HName = iiname.SafeNarrow(CP_OEM); // default oem name
  309.                         z->options.dosflag = 2;                 // FAT
  310.                         wantOEM = false;
  311.                 }
  312.                 else
  313.                 if (doenc == zeoUTF8)
  314.                 {
  315.                         z->HName = StrToUTF8(iiname);
  316.                         z->options.nameutf8 = 1;   // so we set the flag
  317.                         z->options.dosflag = 2;  // assume header strings usable on MSDOS
  318.                         wantOEM = false;
  319.                 }
  320.                 else
  321.                 if (doenc == zeoNone)
  322.                 {
  323.                         z->HName = iiname.SafeNarrow(CP_ACP, bad);
  324.                         z->options.nameutf8 = 0;   // so we set the flag
  325.                         bool ntfs = z->HName.BadDOS();
  326.                         if (!ntfs && z->options.cmntextd)
  327.                         {
  328.                                 DZStrA tmp = z->Comment.SafeNarrow(CP_ACP);
  329.                                 ntfs = tmp.BadDOS();
  330.                         }
  331.                         z->options.dosflag = ntfs ? 0 : 1;  // assume header strings usable on NTFS
  332.                         wantOEM = false;
  333.                 }
  334.         }
  335.         if (wantOEM)
  336.         {
  337.                 z->HName = iiname.SafeNarrow(CP_OEM, bad); // default oem name
  338.                 z->options.dosflag = 2;                 // FAT
  339.         }
  340.         if (bad)
  341.         {
  342.                 z->options.namenew = 1; // name was made safe
  343.                 unsigned cp = wantOEM ? CP_OEM : CP_ACP;
  344.                 DZStrW xname(cp, z->hname, z->HName.length());
  345.                 if (Verbose < 0)
  346.                         Notify(IVERBOSE, _T("%s made safe as %hs"),     iiname.c_str(), xname.c_str());
  347.         }
  348. #ifdef ZDEBUG
  349.         if (Verbose < 0)
  350.         {
  351.                 Notify(ITRACE, _T("Prepare %s need %x dos %X"), z->iname, z->ver,
  352.                            z->options.dosflag);
  353.         }
  354. #endif
  355.  
  356.     return 0;
  357. }
  358.  
  359. // Add, update, freshen, or delete zip entries in a zip file. argc; /*
  360. //   Number of tokens in command line. argv; /* Command line tokens.
  361. int ZipFunc::ZipProcess(void)
  362. {
  363.     int a;                // attributes of zip file
  364.     ZInt64 censtt;        // start of central directory
  365.  
  366.     FndItem *f;           // steps through "found" linked list
  367.     FndItem *tempf;
  368.     int k;                // next argument type, marked counter, comment size, entry count
  369.     int marks;            // replaces k as marked counter
  370.         int r;                // temporary variable
  371.         int err;                          // temporary error variable
  372.     ulg t;                // file time, length of central directory
  373.  
  374.         ZipItem *v;           // temporary variable
  375.     ZipItem *z;           // steps through "zfiles" linked list
  376.     const TCHAR *Actions[4] = {_T("PURGE"), _T("ADD"), _T("UPDATE"), _T("FRESHEN")};
  377.  
  378.     int DestType;         //  destination drive type
  379.     unsigned long TotFiles = 0;
  380.     __int64 TotSize = 0;
  381.         unsigned long KeptCnt = 0;  // number of 'kept' files
  382.         __int64 KeptSize = 0;       // size of 'kept' files
  383.     __int64 VerSize = 0;        // size of 'kept' files
  384.         __int64 fsz;                // file size;
  385.     int No_File;                // 1.75 try if file does not exist
  386.     // Process arguments
  387.     diag(_T("processing lists"));
  388.  
  389.         if (Verbose)
  390.         {
  391.                 Notify(IVERBOSE, _T("action = %s"), Actions[faction]);
  392.  
  393.         // zcount is no. of entries in linked-list
  394.         // zfiles is name of the linked-list of filenames for the archive
  395.         Notify(IVERBOSE, _T("zcount=%d (no. of files in ZIP already)"), fzcount);
  396.     }
  397.  
  398.     if (!fzipbeg)
  399.         fjunk_sfx = 0;   // nothing to junk
  400.  
  401.     if (!fzfiles)
  402.         fadjust = 0;     // nothing to adjust
  403.  
  404.  
  405.     if ((r = check_dupExt()) != DZ_ERR_GOOD)   // remove duplicates in ffound
  406.         return DZError(r);
  407.  
  408.     // Check option combinations
  409.     // ?????
  410.     if (faction == PURGE && (fdispose || frecurse || fkey))
  411.                 return DZError(DZ_ERM_BAD_OPTIONS);
  412.  
  413.     // AllowGrow is the "allow append" indicator
  414.     if (!fzcount && ((faction == ADD) || (faction == UPDATE)))
  415.         fAllowGrow = 55; // create new file normally
  416.  
  417.     // if zcount is 0, then zipfile doesn't exist, or is empty
  418.     if (fzcount == 0 && ((faction != ADD && faction != UPDATE)
  419.                          || !fAllowGrow))
  420.     {
  421.         // RCV150199 added UPDATE
  422.         Notify(IWARNING, _T("%s: not found or empty"), fzipfile.c_str());
  423.         return 0;
  424.     }
  425.  
  426.     if (fndlist)
  427.     {
  428.         delete fndlist;
  429.         fndlist = NULL;
  430.     }
  431.  
  432.     DestType = DriveType(fzipfile);
  433.  
  434.     if (Verbose < 0)
  435.         Notify(IVERBOSE, _T("Destination type = %d"), DestType);
  436.  
  437.     // RP - check destination type - if CD set tempath to Windows Temp
  438.     if (ftempath.IsEmpty() && (DestType != DRIVE_FIXED &&
  439.                                DestType != DRIVE_RAMDISK))
  440.     {
  441.         GetTempPath(2047, ftempath.GetBuffer(2047));
  442.         ftempath.ReleaseBuffer();
  443.     }
  444.  
  445.     // If -b not specified, set temporary path to zipfile path
  446.     int pp;
  447.  
  448.     if (ftempath.IsEmpty() && ((pp = fzipfile.ReverseFind(BSLASH)) >= 0
  449.                                || (pp = fzipfile.ReverseFind(_T(':'))) >= 0))
  450.     {
  451.         if (fzipfile[pp] == _T(':'))
  452.             pp++;
  453.  
  454.         ftempath = fzipfile.Left(pp);
  455.     }
  456.  
  457.     // if first_listarg is 0, then we didn't got any fspecs on cmd line
  458.     if (fdoall && (faction == UPDATE || faction == FRESHEN))
  459.     {
  460.         // if -update or -freshen with no args, do all, but, when present, apply
  461.         //   filters
  462.         for (z = fzfiles; z != NULL; z = z->nxt)
  463.             z->mark = fpcount ? !ZMatch(fExcludes, z->IName) : 1;
  464.     }
  465.  
  466.     // NOTE: "k" is being redefined below this point. Now, it going to
  467.     // track the no. of marked files in the "zfiles" linked list.
  468.     // For each marked entry in "zfiles" linked list, if not deleting, check
  469.     //   if a corresponding "external" file exists. If updating or freshening,
  470.     //   compare date of "external" file with entry in orig zipfile. Unmark if it
  471.     //   external file doesn't exist or is too old, else mark it. Entries that
  472.     //   are marked will cause that file to be rezipped.
  473.     diag(_T("checking marked entries"));
  474.     marks = 0; // Initialize marked count
  475.     ZipItem **zlast;          // pointer to last link in "zfiles" list
  476.     ZipItem **verlast = &VerFiles;   // pointer to last link
  477.         ZipItem **fndlast = &fzfound;
  478.         int vercount = 0;
  479.                 for (z = fzfiles; z != NULL; z = z->nxt)
  480.                 {
  481.                         if (z->mark)
  482.                         {
  483.                                 ulg FileAttr;
  484.                                 if (faction != PURGE)
  485.                                 {
  486.                     t = zfiletime(z->FullPath(), &FileAttr, &fsz, NULL);
  487.  
  488.                     if ((t == 0 || t < fbefore
  489.                             || ((faction == UPDATE || faction == FRESHEN) &&
  490.                                 t <= z->tim)
  491.                             || (fArchiveFiles && faction == FRESHEN &&
  492.                                 !(FileAttr &A_ARCHIVE)))
  493.                        )
  494.                     {
  495.                         z->mark = MARK_KEEP;      // keep
  496.                         z->trash = (t && t >= fbefore);
  497.                         // delete if -um or -fm
  498.  
  499.                         if (Verbose)
  500.                         {
  501.                             const TCHAR *expl;
  502.  
  503.                             if (t)
  504.                                 expl = z->trash ?  _T("up to date") : _T("early");
  505.                             else
  506.                                 expl = _T("missing");
  507.  
  508.                                                         Notify(0, _T("%s is %s"), z->xname, expl);
  509.                         }
  510.                     }
  511.                     else
  512.                     {
  513.                                                 // replace
  514.                         TotSize += fsz;
  515.                         TotFiles++;
  516.                         marks++;
  517.                         z->mark = MARK_UPDATE;    // marker for replace
  518.  
  519.                         if (z->options.keepver)
  520.                         {
  521.                                                         ZipItem* vz = new ZipItem(*z);
  522.                                                         *(verlast) = vz;
  523.                                                         verlast = &vz->nxt;
  524.                                                         vz->nxt = NULL;
  525.                                                         vz->Passw = fkey;
  526.                                                         vz->Base = CurBase->Base;
  527.                             vercount++;
  528.                         }
  529.                     }
  530.                 }
  531.                 else
  532.                 {
  533.                     // PURGE
  534.                     marks++;    // incr. number of marked entries
  535.                                         z->mark = MARK_PURGE;  // marker for Purge
  536.                                 }
  537.             }
  538.                 }
  539.     // RP - verify file specified to 'Purge'
  540.     if (faction == PURGE && !marks)
  541.         return DZError(DZ_ERM_NOTHING_TO_DO);
  542.  
  543.     // Remove entries from "found" linked list if: Action is PURGE or FRESHEN
  544.     //   or No "external" matching file is found, or if found, but is too old or
  545.     //   The external file is equal to the ziparchive name while ziparchive name
  546.     //   != "-" If filetime() returns any valid time, then at least we know the
  547.     //   file was found.
  548.     diag(_T("checking new entries"));
  549.         FndItem *prev = NULL;
  550.         // fileio.c built the found list
  551.         for (f = ffound; f != NULL;)
  552.         {
  553.                 if (faction == PURGE || faction == FRESHEN
  554.                                 || (t = zfiletime(f->xname, NULL, NULL, NULL)) == 0
  555.                                 || t < fbefore
  556.                                 || (ZMatch(f->FullPath(), fzipfile)))
  557.                 {
  558.                         if (Verbose && t < fbefore)
  559.                                 Notify(IVERBOSE, _T("rejecting %s as too early"), f->xname);
  560.  
  561.                         if (Verbose < 0)
  562.                                 Notify(ITRACE, _T("expel being called for %s"), f->xname);
  563.                         tempf = f;
  564.                         f = f->nxt;
  565.                         if (prev)
  566.                                 prev->nxt = f;
  567.                         else
  568.                                 ffound = f;     // new first
  569.                         delete tempf;
  570.                         ffcount--;
  571.                 }
  572.                 else                 // file found, and not too old.
  573.                 {
  574.                         prev = f;
  575.                         f = f->nxt;         // save this one, link it up.
  576.                 }
  577.         }
  578.     if (Verbose)
  579.     {
  580.         if (ffound == NULL)
  581.             Notify(IVERBOSE, _T("found list empty - a"));
  582.         else
  583.             Notify(IVERBOSE, _T("found list has at least one entry - a"));
  584.     }
  585.     // 'fix' safe and header names
  586.         IntList = new HashListInt(ffcount + fzcount + vercount);
  587.         // add 'keep' files - no duplicate allowed but should not happen
  588.         ZipItem  *prv = NULL;
  589.         for (z = fzfiles; z != NULL; /* z = z->nxt */)
  590.         {
  591.                 FndItem  *e;
  592.                 if (z->mark >= MARK_KEEP)
  593.                 {
  594.                         // add internal name to list - check for duplicate
  595.                         if ((e = (FndItem*) IntList->AddNode(z)) != 0)
  596.                         {
  597.                                 DupName(Skipping(z->XName, DZ_ERM_DUPNAME, SKIPPED_DUP_NAME),
  598.                                                 e, z, z->IName);
  599.                                 // delete later duplicate
  600.                                 ZipItem  *x = z->nxt;
  601.                                 if (prv)
  602.                                         prv->nxt = x;
  603.                                 else
  604.                                         fzfiles = x;
  605.                                 delete z;
  606.                                 z = x;
  607.                                 fzcount--;
  608.                                 continue;
  609.                         }
  610.                 }
  611.                 prv = z;
  612.                 z = z->nxt;
  613.     }
  614.  
  615.         // now new files - no duplicates
  616.     while ((f = ffound) != NULL)
  617.         {
  618.                 ZipItem **prvlast = fndlast;            // save
  619.                 ZipItem *prvlastnxt = *(fndlast);   // save
  620.         ZipItem *zi = new ZipItem(f);       // copy as ZipItem
  621.                 *(fndlast) = zi;
  622.         fndlast = &zi->nxt;
  623.                 zi->mark = MARK_NEW;
  624.         ffound = f->nxt;
  625.         delete f;
  626.  
  627.                 // set comment and header name
  628.                 if ((r = PrepareHeaderName(zi, false)) != 0)
  629.                         return r;
  630.                 FndItem  *e;
  631.                 if ((e = (FndItem*) IntList->AddNode(zi)) != 0)
  632.                 {
  633.                         DupName(Skipping(zi->XName, 0, SKIPPED_DUP_NAME),
  634.                                         e, f, f->IName);
  635.                         // delete later duplicate
  636.                         fndlast = prvlast;              // restore
  637.                         *(fndlast) = prvlastnxt;        // restore
  638.                         delete zi;
  639.                         ffcount--;
  640.         }
  641.         }
  642.         // now rename versions to unique internal names
  643.         if (vercount)
  644.         {
  645.                 fAllowGrow = 0; // append not allowed
  646.         }
  647.         //
  648.         if (fadjust <= 0)
  649.         fadjust = 0;
  650.  
  651.     // Make sure there's something left to do
  652.     if (marks == 0 && fzfound == NULL && !(fzfiles != NULL && (flatest ||
  653.                                           fadjust || fjunk_sfx)))
  654.     {
  655.         // FOUND WAS NULL HERE, so just figure out which error message to show
  656.         if (faction == UPDATE || faction == FRESHEN)
  657.         {
  658.             finish();
  659.             Notify(IWARNING, _T("no files %s"), (faction == UPDATE) ? _T("updated")
  660.                    : _T("freshened"));
  661.             return 0;
  662.         }
  663.         else
  664.         {
  665.             if (fzfiles == NULL && (flatest || fadjust || fjunk_sfx))
  666.                 return DZError(DZ_ERM_EMPTY_ZIP);
  667.             return DZError(DZ_ERM_NOTHING_TO_DO);
  668.         }
  669.     }
  670.  
  671.     // AllowGrow is false if writing temporary file
  672.     fAllowGrow = (fAllowGrow && (marks == 0)
  673.                   // is allowed and no changes to existing
  674.                   && (fzipbeg || fzfiles != NULL) // something to append to
  675.                  );
  676.  
  677.     // continue on to add new files
  678.     a = 0;
  679.  
  680.     // ignore self-extracting code in front of the zip file (for -J)
  681.     if (fjunk_sfx)
  682.         fzipbeg = 0;
  683.  
  684.     // Calc size of version files
  685.     for (z = VerFiles; z; z = z->nxt)
  686.     {
  687.         if (Abort_Flag)
  688.                         Fatal(DZ_ERM_ABORT, 0);
  689.  
  690.         VerSize += (z->siz + (ulg)(4 + LOCHEAD) + (ulg)z->nam + (ulg)z->ext);
  691.  
  692.         if (z->lflg &8)
  693.             VerSize += 16;
  694.     }
  695.  
  696.     // Count files and sizes which we have to Keep; RP Added
  697.     zlast = &fzfiles;
  698.     while ((z =  *zlast) != NULL)
  699.     {
  700.         if (Abort_Flag)
  701.                         Fatal(DZ_ERM_ABORT, 0);
  702.  
  703.         if (!z->mark)
  704.         {
  705.             KeptSize += (z->siz + (ulg)(4 + LOCHEAD) + (ulg)z->nam + (ulg)z->ext);
  706.  
  707.             if (z->lflg &8)
  708.                 KeptSize += 16;
  709.  
  710.             KeptCnt++;
  711.         }
  712.  
  713.         zlast = &z->nxt;
  714.     }
  715.  
  716.     //Inform(pG, 0, IDIAG, "Kept = %u %Lu Total = %Lu %Lu", KeptCnt, KeptSize, TotFiles, TotSize);
  717.     // Count files and sizes which we have to process; RCV Added
  718.     // First the files in the old zip file...
  719.     // RP - already calculated with new sizes
  720.     // And the found list...
  721.     z = fzfound;
  722.     while (z)
  723.     {
  724.                 if (Abort_Flag)
  725.             Fatal(DZ_ERM_ABORT, 0);
  726.  
  727.         TotSize += z->len;
  728.         TotFiles++;
  729.         z = z->nxt;
  730.         }
  731.  
  732.     fhInz = INVALID_HANDLE_VALUE;
  733.     fOutPosn = 0;
  734.  
  735.     if (!fAllowGrow)
  736.     {
  737.         // check file exists
  738.         No_File = _taccess(fzipfile, 0) && errno == ENOENT;
  739.  
  740.         if (No_File && DestType == DRIVE_FIXED || DestType == DRIVE_RAMDISK)
  741.         {
  742.             // create file using given name
  743.                         diag(_T("Processing - ready to create new file"));
  744.             fZipOutfile = new ZFile(this, fzipfile, GENERIC_WRITE, 0, NULL,
  745.                                     CREATE_NEW, FILE_ATTRIBUTE_NORMAL);
  746.  
  747.             if (fZipOutfile->IsOpen())
  748.             {
  749.                 ftempzip = fzipfile;
  750.                 fAllowGrow =  -1; // new files do grow
  751.             }
  752.             else
  753.                 if (Verbose < 0)
  754.                     Notify(DZ_ERM_ERROR_CREATE, _T("CreateFile failed %s [%s]"),
  755.                            fzipfile.c_str(), SysMsg().c_str());
  756.         }
  757.     }
  758.  
  759.     if (fAllowGrow > 0)
  760.     {
  761.         // zipfile is not stdout, and we are allowed to append
  762.         // AllowGrow is true if we're just appending (-g)
  763.                 diag(_T("Processing - ready to open for appending"));
  764.         fZipOutfile = new ZFile(this, fzipfile, GENERIC_READ | GENERIC_WRITE, 0,
  765.                                 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL);
  766.  
  767.         if (!fZipOutfile->IsOpen())
  768.         {
  769.             if (Verbose < 0)
  770.                 Notify(DZ_ERM_ERROR_CREATE, _T("CreateFile failed 2 %s [%s]"),
  771.                        fzipfile.c_str(), SysMsg().c_str());
  772.  
  773.             return DZError(DZ_ERM_ERROR_CREATE);
  774.         }
  775.  
  776.         ftempzip = fzipfile;
  777.  
  778.         if (fZipOutfile->SetPosition(fcenbeg, FILE_BEGIN) == -1)
  779.             return DZError(GetLastError() ? DZ_ERM_ERROR_SEEK : DZ_ERM_ZIP_EOF);
  780.  
  781.         fOutPosn = fcenbeg;
  782.     }
  783.  
  784.     if (!fAllowGrow)
  785.     {
  786.         diag(_T("Processing - ready to open for Exclusive Read"));
  787.  
  788.         if ((fzfiles != NULL || fzipbeg) &&
  789.             (fhInz = CreateFile(fzipfile, GENERIC_READ, 0, NULL, OPEN_EXISTING,
  790.                 FILE_ATTRIBUTE_NORMAL |  FILE_FLAG_SEQUENTIAL_SCAN, NULL)) ==
  791.                     INVALID_HANDLE_VALUE)
  792.         {
  793.             if (Verbose < 0)
  794.                 Notify(DZ_ERM_ERROR_CREATE, _T("CreateFile failed 3 %s [%s]"),
  795.                        fzipfile.c_str(), SysMsg().c_str());
  796.  
  797.             return DZError(DZ_ERM_ERROR_CREATE);
  798.         }
  799.  
  800.         ftempzip = tempname();
  801.  
  802.         if (Verbose)
  803.             Notify(IVERBOSE, _T("Temp Filename = %s"), ftempzip.c_str());
  804.  
  805.         fZipOutfile = new ZFile(this, ftempzip, GENERIC_WRITE, 0,
  806.                                 NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL);
  807.  
  808.         if (!fZipOutfile->IsOpen())
  809.         {
  810.             if (Verbose < 0)
  811.                 Notify(DZ_ERR_ERROR_CREATE | ITRACE, _T("CreateFile failed 3 %s [%s]"),
  812.                        ftempzip.c_str(), SysMsg().c_str());
  813.  
  814.             return DZError(DZ_ERM_TEMP_FAILED);
  815.         }
  816.     }
  817.  
  818.     if (!fAllowGrow)
  819.     {
  820.         TotFiles += KeptCnt + vercount;
  821.         TotSize += KeptSize + VerSize;
  822.     }
  823.  
  824.     // Pass total number of files and Total Filesize.
  825.     CB->Arg1 = TotFiles;
  826.     CB->UserCB(zacCount);
  827.  
  828.     CB->FileSize = TotSize;
  829.     CB->UserCB(zacSize);
  830.  
  831.     fBatchStarted = 1;
  832.  
  833.     if (!fAllowGrow && fzipbeg)
  834.     {
  835.         if (Verbose)
  836.             Notify(IVERBOSE, _T("Copying SFX stub [%X]"), fzipbeg);
  837.  
  838.         // copy a compressed file from old archive to new archive
  839.         CB->FileSize = fzipbeg;
  840.         CB->Msg = _T("SFX");
  841.         CB->UserCB(zacItem);
  842.  
  843.         if ((r = fcopy(fzipbeg)) != DZ_ERR_GOOD)
  844.             return DZError(r);
  845.  
  846.         fOutPosn = fzipbeg;
  847.     }
  848.  
  849.     // Process zip file, copying from old archive to new archive. Rezip any
  850.     //   marked files
  851.     if (fzfiles != NULL)
  852.         diag(_T("going through old zip file"));
  853.  
  854.     zlast = &fzfiles;
  855.     while ((z =  *zlast) != NULL)
  856.     {
  857.         if (Abort_Flag)
  858.                         Fatal(DZ_ERM_ABORT, 0);
  859.  
  860.         if (z->mark == MARK_UPDATE)
  861.         {
  862.             // This file is marked
  863.                         // if not deleting, rezip it
  864.                         Notify(0, _T("updating: %s"), z->iname);
  865.                         ZipItem zr = *z;        // make copy
  866.                         // update comment and name (if required)
  867.                         if ((r = PrepareHeaderName(z, false)) != 0)
  868.                                 return r;
  869.                         r = zipup(z);
  870.                         int dze = DZ_ERR(r);
  871.                         if (dze == DZ_ERR_NO_FILE_OPEN || dze == DZ_ERR_MISS || //)
  872.                                 dze == DZ_ERR_ERROR_READ || dze ==DZ_ERR_SKIPPED)
  873.                         {
  874.                                 _TCHAR *msg;
  875.  
  876.                                 *z = zr; // restore and try to keep
  877.                                 if (dze == DZ_ERR_NO_FILE_OPEN)
  878.                                         msg = _T("could not open for reading: %s");
  879.                                 else if (dze == DZ_ERR_MISS)
  880.                                         msg = _T("file and directory with the same name: %s");
  881.                                 else
  882.                                         msg = _T("skipped: %s");
  883.                                 Notify(IWARNING, msg, z->xname);
  884.                                 CB->UserMsg(r, z->xname);
  885.                                 dze = 0;        // handled that error
  886.                                 Notify(IWARNING, _T("will just use old version: %s"), z->iname);
  887.                 if ((r = zipcopy(z)) != DZ_ERR_GOOD)
  888.                 {
  889.                                         Notify(IERROR, _T("was copying %s"), z->iname);
  890.                                         dze = -1;       // has error in r
  891.                                 }
  892.                                 else
  893.                                         z->mark = 0;
  894.                         }
  895.                         if (dze != DZ_ERR_GOOD)
  896.                                 return DZError(r);
  897.  
  898.             zlast = &z->nxt;
  899.                         ffiles_acted_on++;
  900.                 }
  901.         else
  902.         if (z->mark == MARK_PURGE)
  903.         {
  904.             // desired action is DELETE, this file marked
  905.             Notify(0, _T("deleting: %s"), z->iname);
  906.  
  907.             v = z->nxt; // delete entry from list
  908.             delete z;
  909.             *zlast = v;           // link prev to next
  910.             fzcount--;
  911.             ffiles_acted_on++;
  912.         }
  913.         else   // mark != 1
  914.         {
  915.             // this file wasn't marked
  916.             // copy the original entry verbatim
  917.             if (!fAllowGrow)
  918.             {
  919.                 Notify(0, _T("keeping: %s"), z->iname);
  920.  
  921.                 if ((r = zipcopy(z)) != DZ_ERR_GOOD)
  922.                 {
  923.                     Notify(IERROR, _T("was copying %s"), z->iname);
  924.                     return DZError(r);
  925.                 }
  926.             }
  927.  
  928.             zlast = &z->nxt;
  929.         }
  930.     } // end while
  931.  
  932.     // Process the 'Version' files
  933.     if (vercount)
  934.     {
  935.         if (Verbose < 0)
  936.             Notify(ITRACE, _T("Copying %d version entries"), vercount);
  937.  
  938.         while ((z = VerFiles) != NULL)
  939.         {
  940.             if (Abort_Flag)
  941.                                 Fatal(DZ_ERM_ABORT, 0);
  942.  
  943.             if (Verbose)
  944.                 Notify(0, _T("Versioning: %s"), z->iname);
  945.  
  946.             VerFiles = VerFiles->nxt;
  947.             z->nxt = NULL;
  948.  
  949.             *zlast = z;     // link to prev->nxt (allow cleanup)
  950.                         // make new internal and header names
  951.                         if ((r = NameVer(z)) != 0)
  952.                                 return r;
  953.  
  954.             if ((r = zipVersion(z)) != DZ_ERR_GOOD)
  955.             {
  956.                 Notify(IERROR, _T("was copying %s"), z->iname);
  957.                 return DZError(r);
  958.             }
  959.  
  960.             // "zipup" of this file was good
  961.             *zlast = z;
  962.             zlast = &z->nxt;
  963.             fzcount++;
  964.             ffiles_acted_on++;
  965.         }
  966.     }
  967.  
  968.     // Process the "found" list, adding them to the zip file.
  969.     // This is used to add files that weren't already in the archive.
  970.     if (Verbose)
  971.         Notify(IVERBOSE, _T("Zipping up %d NEW entries from found list"), ffcount);
  972.  
  973.     // For each new file to add (src names in found list), make a new entry
  974.     //   for it in the "zfiles" linked list, zip up the new file, then remove the
  975.     //   entry from the found list.
  976.     // The last item in the for loop control deallocates spc for fname that
  977.         //   was just zipped up
  978.  
  979.     while ((z = fzfound) != NULL)
  980.     {
  981.         // add a new entry to "zfiles" list, before we zip up the file. That way
  982.         //   we'll be ready to update the ZIP file's directory later.
  983.         if (Abort_Flag)
  984.                         Fatal(DZ_ERM_ABORT, 0);
  985.  
  986.         fzfound = z->nxt;
  987.         ffcount--;
  988.         *zlast = z;     // link to prev->nxt (allow cleanup)
  989.         z->nxt = NULL;
  990.         z->mark = MARK_NEW;
  991.  
  992.                 // zip it up
  993.                 if (z->options.namenew)
  994.                         Notify(0, _T("  adding: %s as %hs"), z->iname, z->hname);
  995.                 else
  996.                         Notify(0, _T("  adding: %s"), z->iname);
  997.  
  998.                 // This is it - try to zip up new file
  999.                 r = zipup(z);
  1000.                 if (r == DZ_ERR_GOOD)
  1001.                 {
  1002.                         // "zipup" of this file was good
  1003.                         *zlast = z;
  1004.                         zlast = &z->nxt;
  1005.                         fzcount++;
  1006.                         ffiles_acted_on++;
  1007.                         continue;
  1008.                 }
  1009.                 err = DZ_ERR(r);
  1010.                 if (err != DZ_ERR_NO_FILE_OPEN && err != DZ_ERR_MISS &&//)
  1011.                                 err != DZ_ERR_ERROR_READ && err != DZ_ERR_SKIPPED)
  1012.                         return DZError(r);
  1013. //              if ((r = zipup(z)) != DZ_ERR_GOOD
  1014. //                              && DZ_ERR(r) != DZ_ERR_NO_FILE_OPEN && DZ_ERR(r) != DZ_ERR_MISS)
  1015. //                      return DZError(r);
  1016.  
  1017. //              if (DZ_ERR(r) == DZ_ERR_NO_FILE_OPEN || DZ_ERR(r) == DZ_ERR_MISS)
  1018. //              if (err == DZ_ERR_NO_FILE_OPEN || err == DZ_ERR_MISS ||
  1019. //                              err == DZ_ERR_ERROR_READ || err ==DZ_ERR_SKIPPED)
  1020. //              if (r != DZ_ERR_GOOD)
  1021. //              {
  1022. //            if (DZ_ERR(r) == DZ_ERR_NO_FILE_OPEN)
  1023.                         if (err == DZ_ERR_NO_FILE_OPEN)
  1024.                                 Notify(r | IWARNING, _T("could not open for reading: %s"), z->xname);
  1025.                         else
  1026. //                              Notify(IWARNING, _T("file and directory with the same name: %s"), z->xname);
  1027.                         {
  1028.                                 _TCHAR *msg;
  1029.                                 if (err == DZ_ERR_MISS)
  1030.                                         msg = _T("file and directory with the same name: %s");
  1031.                                 else
  1032.                                         msg = _T("skipped: %s");
  1033.                                 Notify(IWARNING, msg, z->xname);
  1034.                         }
  1035.             *zlast = NULL;  // remove from list
  1036.             delete z;
  1037. //        }
  1038. //              else
  1039. //              {
  1040. //                      // "zipup" of this file was good
  1041. //                      *zlast = z;
  1042. //                      zlast = &z->nxt;
  1043. //                      fzcount++;
  1044. //                      ffiles_acted_on++;
  1045. //        }
  1046.     }
  1047.  
  1048.     // Write central directory and end header to temporary zip
  1049.     diag(_T("writing central directory"));
  1050.  
  1051.     // get start of central directory
  1052. //    Assert(fOutPosn == SetFilePointer64(fhOutz, 0, 2), _T("invalid out posn dlz 983"));
  1053.  
  1054.     censtt = fOutPosn;
  1055.     k = 0; // keep count of new fnames for ZIPfile's end header
  1056.     __int64 usiz = 0;
  1057.     __int64 csiz = 0;
  1058.     CB->Arg1 = 7;    // type
  1059.     CB->FileSize = fzcount;
  1060.  
  1061.     CB->Msg = _T("*writing central directory");
  1062.     CB->UserCB(zacXItem);
  1063.  
  1064.     for (z = fzfiles; z != NULL; z = z->nxt)
  1065.     {
  1066.         if ((r = putcentral(z)) != DZ_ERR_GOOD)
  1067.             return DZError(r);
  1068.  
  1069.         usiz += z->len;
  1070.         csiz += z->siz;
  1071.         k++;
  1072.  
  1073.         CB->UserXProgress(1, 7);
  1074.     }
  1075.  
  1076.     if (k == 0)
  1077.         Notify(IWARNING, _T("zip file empty"));
  1078.  
  1079.     if ((Verbose) && (faction == ADD) && (!fglobal_error_code)
  1080.             && (ffiles_acted_on > 0))
  1081.     {
  1082.         Notify(IVERBOSE, _T("Total Bytes=%Lu, compr bytes=%Lu -> %d%% savings"), usiz, csiz,
  1083.                percent(usiz, csiz));
  1084.     }
  1085.  
  1086.     diag(_T("writing end of central directory"));
  1087. //    Assert(fOutPosn == SetFilePointer64(fhOutz, 0, 1), _T("invalid out posn dlz 1055"));
  1088.  
  1089.     if (k && ((r = PutEnd(k, censtt)) != DZ_ERR_GOOD))
  1090.         return DZError(r);
  1091.  
  1092.     Close_Handle(&fhInz);
  1093.  
  1094.     delete fZipOutfile;
  1095.     fZipOutfile = NULL;
  1096.  
  1097.     // Replace old zip file with new zip file, leaving only the new one
  1098.     if (!fAllowGrow && (k || faction != PURGE))
  1099.     {
  1100.         diag(_T("replacing old zip file with new zip file"));
  1101.  
  1102.         if ((r = replace(fzipfile, ftempzip)) != DZ_ERR_GOOD)
  1103.         {
  1104.             Notify(IWARNING, _T("new zip file left as: %s"), ftempzip.c_str());
  1105.             return DZError(r);
  1106.         }
  1107.     }
  1108.  
  1109.     // 1.78.1.2
  1110.     if (!k && faction == PURGE)
  1111.         // empty file - remove
  1112.     {
  1113.         a = flatest = 0;
  1114.         DeleteFile(fzipfile);
  1115.  
  1116.         if (!fAllowGrow)
  1117.             DeleteFile(ftempzip);
  1118.     }
  1119.     if (a)
  1120.         setfileattr(fzipfile, a);
  1121.  
  1122.     // Reset the archive bit when needed for all successfull zipped files
  1123.     if (fResetArchiveBit && faction != PURGE)
  1124.     {
  1125.         unsigned cnt = 0; // 1.71.0.0 added extra callbacks
  1126.         diag(_T("resetting archive bits"));
  1127.  
  1128.         for (z = fzfiles; z != NULL; z = z->nxt)
  1129.             if (z->mark)
  1130.                 cnt++;
  1131.  
  1132.         if (cnt)
  1133.         {
  1134.             // new file op.
  1135.             // Pass total number of files. filesize.
  1136.             CB->Arg1 = 1;    // type
  1137.             CB->FileSize = cnt;
  1138.             CB->Msg = _T("*resetting archive bits");
  1139.             CB->UserCB(zacXItem);
  1140.         }
  1141.  
  1142.         cnt = 0;
  1143.  
  1144.         for (z = fzfiles; z != NULL; z = z->nxt)
  1145.         {
  1146.             if (z->mark)
  1147.             {
  1148.                 if (++cnt == 30)
  1149.                 {
  1150.                     CB->UserXProgress(cnt, 1);
  1151.                     cnt = 0;
  1152.                     if (Abort_Flag)
  1153.                         break;
  1154.                 }
  1155.  
  1156.                 DZStrW fullname = z->FullPath();
  1157.  
  1158.                 if (!SetFileAttributes(fullname, GetFileAttributes(fullname)
  1159.                                        &~FILE_ATTRIBUTE_ARCHIVE))
  1160.                     Notify(IWARNING, _T("Archive bit could not be set for: %s [%s]"),
  1161.                          fullname.c_str(), SysMsg().c_str());
  1162.             }
  1163.         }
  1164.  
  1165.         if (cnt)
  1166.             CB->UserXProgress(cnt, 1);
  1167.     }
  1168.     finish();
  1169.  
  1170.     return 0;
  1171. }
  1172.  
  1173.  
  1174.  
  1175.  
  1176.  
  1177.