Subversion Repositories autosfx

Rev

Blame | Last modification | View Log | RSS feed

  1. #include "stdafx.h"
  2. #pragma hdrstop
  3. #include "ZipOp.h"
  4. #include "dz_errs.h"
  5.  
  6. #undef _DZ_FILE_
  7. #define _DZ_FILE_ DZ_ZIPWIN32_CPP
  8.  
  9. /* Win32Zip.c
  10.  * 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 ** see license.txt for details
  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. #include <direct.h>                   // for rmdir()
  47. #include <time.h>
  48. #include <io.h>
  49. #include <ctype.h>
  50. #include <sys\stat.h>
  51. #ifndef __BORLANDC__
  52. #define stati64 _stati64
  53. #endif
  54.  
  55. const char *GetLongPathEA(void);
  56.  
  57. #define PATH_END      BSLASH //'\\'            // SLASH
  58. #define HIDD_SYS_BITS (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)
  59.  
  60. class ZDir
  61. {
  62.                 WIN32_FIND_DATA fdata;
  63.         bool    ffirst;
  64.         bool    fdone;
  65.         bool    hidden;
  66.         bool    archiveOnly;
  67.         ZipOp *Owner;
  68.         HANDLE  d_hFindFile;
  69.         ZDir();
  70.         ZDir(const ZDir&);
  71.         ZDir& operator=(const ZDir&);
  72.         DWORD __fastcall GetAttrs() const;
  73.         DZStrW __fastcall GetFilename() const;
  74.         __int64 __fastcall GetSize() const;
  75.  
  76.     protected:
  77.         bool __fastcall next(void);
  78.  
  79.     public:
  80.         ZDir(ZipOp* theOwner, const DZStrW& path);
  81.         ~ZDir(void);
  82.         bool __fastcall Read();
  83.         __property DWORD Attrs = {read = GetAttrs};
  84.         __property DZStrW Filename = {read = GetFilename};
  85.         __property bool Done = {read = fdone};
  86.         __property __int64 size = {read = GetSize};
  87. };
  88.  
  89. ZDir::ZDir(ZipOp* theOwner, const DZStrW& path)
  90. {
  91.     Owner = theOwner;
  92.     fdone = true;
  93.     hidden = Owner->fhidden_files;
  94.     archiveOnly = Owner->fArchiveFiles;
  95.  
  96.     DZStrW tmp;
  97.     if (!Is_DrvEx(path))
  98.         tmp = Owner->CurBase->Base;
  99.  
  100.     tmp += path;
  101.     if (tmp.LastChar() != BSLASH)
  102.         tmp += BSLASH;
  103.  
  104.     tmp += _T("*.*");   // "*.*" MS-DOS match-all spec
  105.     d_hFindFile = FindFirstFile(tmp, &fdata);
  106.     fdone = d_hFindFile == INVALID_HANDLE_VALUE;
  107. }
  108.  
  109. ZDir::~ZDir(void)
  110. {
  111.     if (d_hFindFile != INVALID_HANDLE_VALUE)
  112.         FindClose(d_hFindFile);
  113. }
  114.  
  115. bool __fastcall ZDir::next(void)
  116. {
  117.     if (Done)
  118.         return false;
  119.  
  120.     if (ffirst)
  121.     {
  122.         ffirst = false;
  123.         return true;
  124.     }
  125.  
  126.     if (!FindNextFile(d_hFindFile, &fdata))
  127.         fdone = true;
  128.  
  129.     return !Done;
  130. }
  131.  
  132. DWORD __fastcall ZDir::GetAttrs() const
  133. {
  134.     if (Done)
  135.         return 0;
  136.  
  137.     return fdata.dwFileAttributes & 0xFF; // ignore rest
  138. }
  139.  
  140. DZStrW __fastcall ZDir::GetFilename() const
  141. {
  142.     if (Done)
  143.         return DZStrW(_T(""));
  144.  
  145.     return DZStrW(fdata.cFileName);
  146. }
  147.  
  148. __int64 __fastcall ZDir::GetSize() const
  149. {
  150.     if (Done)
  151.         return 0;
  152.  
  153.     __int64 x = fdata.nFileSizeHigh;
  154.     x <<= 32;
  155.     return x + fdata.nFileSizeLow;
  156. }
  157.  
  158.  
  159. bool __fastcall ZDir::Read(void)
  160. {
  161.     if (Done)
  162.         return false;
  163.  
  164.     unsigned        cnt = 0;
  165.     DWORD attrs;
  166.  
  167.     // Loop to read all dir entries, until next normal entry is found
  168.     do
  169.         {
  170.         if (!next())
  171.             break;
  172.  
  173.         if ((++cnt & 0x1F) == 0)        // added 1.71.00
  174.         {
  175.             // tickle and check cancel
  176.             if (Owner->CB->UserCB(zacTick) < CALLBACK_IGNORED)
  177.                 return false;
  178.                 }
  179.                 attrs = Attrs;
  180.     }
  181.     // Loop to read all dir entries, until next normal entry is found  
  182.     while ((!hidden && (attrs & HIDD_SYS_BITS))
  183.                  || (archiveOnly && !(attrs & FILE_ATTRIBUTE_DIRECTORY)
  184.                                          && !(attrs & FILE_ATTRIBUTE_ARCHIVE)));
  185.     return !Done;
  186. }
  187.  
  188.  
  189. // If not in exclude mode, expand the pattern based on the contents of the
  190. //   file system. This function is used while gathering filenames to be added
  191. //   or updated w :: Path/pattern to match. Possible return values: ZEN_MISS,
  192. //   DZ_ERR_GOOD, ZEN_ABORT, ZEN_MEM or ZEN_PARMS.
  193. int ZipOp::Wild(const DZStrW &w)
  194. {
  195.         int   WError;           // Result of Wild()
  196.         int   r;                // Result / temp var.
  197.     bool  StopRecurs = false; // No recursion if filespec is file.
  198.  
  199.     if (Verbose < 0)
  200.                 Notify(ITRACE, _T("in Wild of win32zip.c, pattern=%s recurse=%d"), w.c_str(),
  201.                frecurse);
  202.  
  203.     // diag(fewemsg, pG);
  204.     // "zip -$ foo a:" can be used to force a drive name once. // v1.6017
  205.     if (fvolume_label == 1)
  206.     {
  207.                 fvolume_label = 2;
  208.         flabel = getVolumeLabel(w, &flabel_time, &flabel_mode, &flabel_utim);
  209.  
  210.                 // 1.78.4.1 RP - reject empty label
  211.         if (!flabel.IsEmpty())
  212.             (void)newname(flabel, 0);
  213.  
  214.         if (Is_Drv(w) == 1)
  215.             return DZ_ERR_GOOD;
  216.     }
  217.  
  218.     // Allocate and copy pattern
  219.     // Separate path and name into p and q
  220.     // We have '\' or '\name' or 'path1\path2\name2' or 'C:\path\name' but NOT
  221.     // 'C:\name'
  222.         DZStrW path(w);
  223.         DZStrW name;
  224.         DZStrW cdir;
  225.         int cpos = w.ReverseFind(BSLASH);
  226.         if (cpos >= 0 && (cpos > 0 && w[cpos - 1] != _T(':')))
  227.     {
  228.         path = w.Left(cpos);   // before sep
  229.         if (path.IsEmpty())
  230.             cdir = _T("\\.");
  231.                 name = w.Mid(cpos + 1);
  232.     }
  233.     else
  234.     {
  235.                 cpos = w.ReverseFind(_T(':'));
  236.         if (cpos > 0)
  237.         {
  238.             // We have 'C:' or 'C:\' or 'C:\name'
  239.             if ((cpos + 1) < (int) w.length() && w[cpos + 1] == BSLASH)
  240.                 cpos++;
  241.  
  242.             path = w.Left(cpos + 1);
  243.             name = w.Mid(cpos + 1);
  244.             path += _T('.');
  245.                         cdir = path + _T(':');
  246.         }
  247.                 else
  248.                         if (frecurse && (!w.Compare(_T(".")) || !w.Compare(_T(".."))))
  249.             {
  250.                 // current or parent directory
  251.                 // Get "zip -r foo ." to work. Allow the dubious "zip -r foo .." but
  252.                                 //   reject "zip -r -m foo ..". "dispose" means wipe out source path.
  253.                 if (fdispose && !w.Compare(_T("..")))
  254.                     DZException(DZ_ERM_BAD_OPTIONS);
  255.  
  256.                 name = _T("*.*");
  257.             }
  258.             else
  259.             {
  260.                                 // no path or device
  261.                 name = w;
  262.                 cdir = _T(".");
  263.                 path = cdir;
  264.             }
  265.  
  266.     }
  267.  
  268.         if (frecurse && name.IsEmpty())
  269.         name = _T("*.*");
  270.  
  271.     // take out a possibly redundant dir name of "."
  272.     DZStrW tmp = path.Right(2);
  273.  
  274.     if (!tmp.Compare(_T(":.")) || !tmp.Compare(_T("\\.")))
  275.         path = path.Left(path.length() - 1);
  276.  
  277.         // Only filename (not the path) can have special matching characters
  278.     if (IsWild(path))
  279.     {
  280.         diag(_T("path has illegal chars"));
  281.         return DZ_ERM_INVAL_NAME;
  282.     }
  283.  
  284.     if (!IsWild(name))
  285.     {
  286.                 // Speed up checking if file exits in case there are no wildcards
  287.         struct stati64 s;  // and no recursion and no archiving v1.6016
  288.  
  289.                 if (!frecurse && !fArchiveFiles)
  290.         {
  291.                         if (!ZStat(GetFullPath(w), &s))  // file exists ?
  292.                 return procname(w, false);
  293.  
  294.                         return DZ_ERM_MISS;  // woops, no wildcards where is the file!
  295.                 }
  296.     }
  297.  
  298.     // Now that we have a dir spec, along with an fspec, we'll step in the dir
  299.     //   specified to see if there's any matches against the fspec.
  300.     WError = DZ_ERM_MISS; //ZEN_MISS02;
  301.  
  302.     ZDir dir(this, path);
  303.  
  304.     if (path[0] != _T('.') && path.LastChar() != BSLASH)
  305.         path += BSLASH;
  306.  
  307.     if (!dir.Done)
  308.         {
  309.         while (dir.Read())
  310.         {
  311.             if (Abort_Flag)
  312.                                 Fatal(DZ_ERM_ABORT, 0);
  313.  
  314.             DZStrW n = dir.Filename;
  315.  
  316.             // if e is NOT '.' or '..', and is a dir or match fspec.
  317.             if (!n.Compare(_T(".")) || !n.Compare(_T("..")))
  318.                 continue;
  319.  
  320.             if (dir.Attrs & FILE_ATTRIBUTE_DIRECTORY)
  321.             {
  322.                 // We do not save dirs or go into dirs if norecursefiles==1 and we
  323.                 // have a file without * or ? specs.
  324.                 if (!StopRecurs && (fdirnames || frecurse))
  325.                 {
  326.                     if (!path.IsEmpty() && path[0] == _T('.'))
  327.                         path.Empty();
  328.  
  329.                     if (!path.IsEmpty())
  330.                     {
  331.                         if (path.LastChar() != BSLASH)
  332.                             path += BSLASH;
  333.  
  334.                         n = path + n;
  335.                     }
  336.  
  337.                     if (fdirnames)
  338.                     {
  339.                         // Save directory names also.
  340.                         r = procname(n, false);
  341.  
  342.                         if (ZEN_Rank(r) > ZEN_Rank(WError))
  343.                             WError = r;
  344.  
  345.                         if (DZ_ERR(r) == DZ_ERR_INVAL_NAME)
  346.                             continue; // ignore invalid name
  347.  
  348.                                                 if (ZEN_Rank(r) > 0)
  349.                                                         break;
  350.                     }
  351.  
  352.                     if (frecurse)
  353.                     {
  354.                                                 // Recursively go into dir and check for other pattern matches.
  355.                         if (n.LastChar() != BSLASH)
  356.                             n += BSLASH;
  357.  
  358.                         n += name;  // Add the original pattern.
  359.  
  360.                         r = Wild(n);
  361.  
  362.                                                 // We keep a DZ_ERR_GOOD even when DZ_ERR_MISS occurs.
  363.                         if (ZEN_Rank(r) > ZEN_Rank(WError))
  364.                             WError = r;
  365.  
  366.                         if (DZ_ERR(r) == DZ_ERR_INVAL_NAME)
  367.                             continue; // ignore invalid name
  368.  
  369.                         if (ZEN_Rank(r) > 0)
  370.                             break;                        // An error, stop processing.
  371.                     }
  372.                 }
  373.             }
  374.             else   // not a directory
  375.                 if (ZMatch(name, n))
  376.                 {
  377.                     if (!path.Compare(_T(".")))
  378.                         r = procname(n, false);
  379.                     else
  380.                     {
  381.                         n = path + n;
  382.                         r = procname(n, false);
  383.                     }
  384.  
  385.                                         if (ZEN_Rank(r) > ZEN_Rank(WError))
  386.                         WError = r;
  387.  
  388.                     if (DZ_ERR(r) == DZ_ERR_INVAL_NAME)
  389.                         continue; // ignore invalid name
  390.  
  391.                                         if (ZEN_Rank(r) > 0)
  392.                         break;
  393.                                 }
  394.                 }                                         // end while
  395.     }
  396.     else
  397.                 diag(_T("can't open dir"));
  398.  
  399.     return WError;
  400. }
  401.  
  402. // Process a name or wildcard expression to operate on (or exclude). We will
  403. //   only arrive here if we do a Freshen or Delete. Return an error code in the
  404. //   ZEN_ class. DZ_ERR_GOOD, ZEN_ABORT, ZEN_MISS03, ZEN_MISS04, ZEN_MISS05,
  405. //   ZEN_MEM22, ZEN_MEM23 ArgName :: Name to process.
  406. int ZipOp::procname(const DZStrW &ArgName, bool RecurseDir)
  407. {
  408.         int           m;                            // matched flag
  409.     int           pnError;                      // ProcName error
  410.  
  411.     struct stati64 StatRes;                    // result of stat()
  412.     ZipItem  *z;                           // steps through zfiles list
  413.  
  414.     if (Verbose < 0)
  415.         Notify(ITRACE, _T("in procname, name=%s recurse=%d"), ArgName.c_str(),
  416.                RecurseDir);
  417.  
  418.     m = 1;                                      // set dflt for success indicator
  419.  
  420.     ///* (0=success)
  421.  
  422.     if (Abort_Flag)
  423.                 Fatal(DZ_ERM_ABORT, 0);
  424.  
  425.     if (ArgName.IsEmpty())
  426.         return DZ_ERM_MISS;
  427.  
  428.     // LSSTAT returns 0 if it's arg is any kind of file (even a dir).
  429.     // IsShExp returns true if a wildcard symbol is found, or NULL if none
  430.         //   were found -- IsShExp is in util.c
  431.     if (IsWild(ArgName) || ZStat(GetFullPath(ArgName), &StatRes))
  432.     {
  433.         // diag("not a file or dir - 'ArgName' must be a wildcard fspec");
  434.         // Upon finding a wildcard fspec, we need to mark entries in
  435.         // the "zfiles" list that are included by the wildcard.
  436.         // convert the "external" (native) filename to an internal
  437.                 //   ZIP-archive-compatible filename.
  438.         DZStrW p = ex2IntForm(ArgName, false);  // shouldn't affect matching chars
  439.  
  440.         if (Verbose < 0)
  441.                         Notify(ITRACE, _T("in procname, searching %s"), p.c_str());
  442.  
  443.         // does any file already in the archive match this spec?
  444.         // Note that we need the pathname and filename together for this
  445.  
  446.         for (z = fzfiles; z; z = z->nxt)
  447.         {
  448.             if (z->mark)
  449.             {
  450. #ifdef ZDEBUG
  451.                 if (Verbose < 0)
  452.                     Notify(ITRACE, _T("%s already marked"), z->IName.c_str());
  453. #endif
  454.                 continue;       // only mark once
  455.             }
  456.  
  457.             // z->name = 'external' version of zname for unmatched names
  458.             if (ZMatch(p, z->IName))
  459.             {
  460.                 // name is in archive - mark it for updating
  461.                 z->mark = fpcount ? !ZMatch(fExcludes, z->IName) : 1;
  462.                 if (Verbose)
  463.                     Notify(0, _T("%scluding %s"), z->mark ? _T("in") : _T("ex"), z->IName.c_str());
  464.  
  465.                 if (z->mark)
  466.                                 {
  467.                     if (Is_Drv(ArgName) > 0  && ArgName[2] == BSLASH)
  468.                     {
  469.                         z->XName = ArgName.Left(3) + z->IName;
  470.                     }
  471.  
  472.                     // RA password added
  473.                     z->Passw = fkey;
  474.                     z->Base = CurBase->Base;
  475.                     z->options.keepver = fversion ? 1 : 0;
  476.  
  477.                     m = 0;  // we had at least one file in the archive that we marked
  478.                 }
  479.  
  480.                 // if not wild it can only match once
  481.                 if (!IsWild(ArgName))
  482.                     break;
  483.             }
  484.         }
  485.  
  486.         // returns 1 if no "zfiles" entries were marked, 0 if at least one entry
  487.         //   was marked
  488.         if (m)
  489.         {
  490.             // diag("returning ZEN_MISS04 from procname");
  491.             return DZ_ERM_MISS;
  492.         }
  493.  
  494.         // diag("returning DZ_ERR_GOOD from procname");
  495.         return DZ_ERR_GOOD;
  496.     }                         // end of "if (LSSTAT..."
  497.  
  498.     // Existing and good filename or directory-- add the name if it's a file,
  499.     //   recurse if directory
  500.     // diag("good entry to add, or a dir to go into");
  501.     // check the status returned by LSSTAT earlier to see if 'ArgName' is a dir
  502.     pnError = DZ_ERR_GOOD;
  503.  
  504.     if (!(StatRes.st_mode & S_IFDIR))
  505.     {
  506.         // it's not a directory - add file to found list
  507.         if (Verbose)
  508.             Notify(IVERBOSE, _T("Adding file %s to found list"), ArgName.c_str());
  509.  
  510.         // newname (fileio.c) adds to found list. If error m!=0 on return
  511.         if ((m = newname(ArgName, StatRes.st_size)) != DZ_ERR_GOOD)
  512.         {
  513.             if (Verbose < 0)
  514.                 Notify(ITRACE, _T("returning %d from procname after newname call"), m);
  515.  
  516.             return m;
  517.         }
  518.     }
  519.     else
  520.     {
  521.         // It is a directory - Add trailing / to the directory name
  522.         if (Verbose < 0)
  523.             Notify(ITRACE, _T("procname dir = %s"), ArgName.c_str());
  524.  
  525.                 // diag("Spot 2, directory found");
  526.         DZStrW p;
  527.  
  528.                 if (ArgName.Compare(_T(".")) && ArgName.Compare(_T("\\.")))
  529.         {
  530.                         if (Verbose)
  531.                                 Notify(IVERBOSE, _T("Adding folder %s to found list"), ArgName.c_str());
  532.                         p = ArgName;
  533.             if (p.LastChar() != BSLASH)
  534.                 p += BSLASH;
  535.  
  536.             // newname (fileio.c) adds to found list. If error m != 0 on return
  537.             if (fdirnames && (m = newname(p, 0)) != DZ_ERR_GOOD)
  538.             {
  539.                 if (Verbose < 0)
  540.                     Notify(ITRACE, _T("returning %d from procname after 2nd newname call"),
  541.                         DZ_ERR(m));
  542.  
  543.                 return m;
  544.             }
  545.         }
  546.  
  547.         // recurse into directory
  548.         // p = empty or dirname
  549.         // diag("spot 4: optional recurse into dir");
  550.         if (RecurseDir)
  551.         {
  552.                         ZDir dir(this, ArgName);
  553.             while (dir.Read())
  554.             {
  555.                 if (Abort_Flag)
  556.                                         Fatal(DZ_ERM_ABORT, 0);
  557.                                 DZStrW a(p);
  558.  
  559.                 a += dir.Filename;
  560.  
  561.                 // form the new dir's pathname followed by the fname just read
  562.                 // (we need to send in the dir and fname, or it won't be detected
  563.                                 //   as a valid file by LSSTAT)
  564.  
  565.                 // diag("DOING RECURSIVE CALL TO PROCNAME FROM PROCNAME");
  566.                 if ((m = procname(a, RecurseDir)) != DZ_ERR_GOOD)
  567.                 {
  568.                                         // recursive call failed; return code not DZ_ERR_GOOD
  569.                                         // unknown error; RCV error handling changed
  570.                                         pnError = m;
  571.                                         break;
  572.                 }
  573.             }                       // end while
  574.  
  575.         }
  576.     }                           // (StatRes.st_mode & S_IFDIR) == 0)
  577.  
  578.     // diag("returning ZEN_ class from procname");
  579.     return pnError;
  580. }
  581.  
  582. #if 0
  583. // ** moved to DzOp
  584. // Convert the external file name to an "internal" file name form,
  585. //   returning the malloc'ed string, or NULL if not enough memory.
  586. //   I.e. Strip the drive if present, strip the path
  587. //if we
  588. //   don't want one and change the name to 8.3 if needed. Not implemented, but
  589. //   also 'put in' change the short path to a long path.
  590. DZStrW ZipOp::ex2IntForm(const DZStrW &exname, bool ignore)
  591. {
  592.     bool  pathput;
  593.  
  594.     if (ignore)
  595.         {
  596.         pathput = true;
  597.     }
  598.     else
  599.         {
  600.         pathput = fpathput;
  601.     }
  602.  
  603.         DZStrW XName(exname);
  604.  
  605.     if (XName.IsEmpty())
  606.         return XName;
  607.  
  608.         DZStrW nname = StrExtSep(XName);
  609.     int p = DriveLen(nname);
  610.  
  611.     int len = nname.length();
  612.     // Strip leading "\" to convert an absolute path into a relative path
  613.  
  614.     while (p < len && nname[p] == BSLASH)
  615.         p++;
  616.  
  617.     // Strip leading "./" as well as drive letter v1.6017
  618.     while ((p + 2) < len && (nname[p] == _T('.') && nname[p + 1] == BSLASH))
  619.         p += 2;
  620.  
  621.     // This is where the dirname gets stripped if user doesn't want it
  622.     if (!pathput)
  623.     {
  624.         int t = nname.ReverseFind(BSLASH);
  625.  
  626.         if (t >= p)
  627.             p = ++t;
  628.     }
  629.  
  630.     if (p)
  631.     {
  632.         nname = nname.Mid(p);
  633.     }
  634.  
  635.     if (nname.length() > MAX_PATH)
  636.     {
  637.         int t = nname.length();
  638.         XName = nname.Left(MAX_PATH);
  639.  
  640.         if (Verbose) // < 0)
  641.             Notify(IWARNING, _T("File name %s is too long [%d]. Truncated to %s"),
  642.                    nname.c_str(), t, XName.c_str());
  643.  
  644.         nname = XName;
  645.     }
  646.  
  647.     return nname;
  648. }
  649. #endif
  650.  
  651. // Set last updated and accessed time of file f to the DOS time d. This is
  652. //   called by dllzip.c to set date/time of the zipfile. RCV Removed __TURBOC__
  653. //   version. f :: name of file to change. d :: dos-style time to change it to.
  654. typedef struct  DosDate
  655. {
  656.     WORD  lo;
  657.     WORD  hi;
  658. }dosdate;
  659.  
  660. void stamp(const DZStrW& f, ulg d)
  661. {
  662.     HANDLE    fHandle;
  663.     FILETIME  LocalFT,
  664.     FT;
  665.  
  666.     fHandle = CreateFile(f, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
  667.                          FILE_ATTRIBUTE_ARCHIVE, NULL);
  668.  
  669.     if (fHandle != INVALID_HANDLE_VALUE)
  670.     {
  671.         if (DosDateTimeToFileTime(((struct DosDate *) &d)->hi,
  672.                                   ((struct DosDate *) &d)->lo, &LocalFT)
  673.                 && LocalFileTimeToFileTime(&LocalFT, &FT))
  674.             SetFileTime(fHandle, NULL, NULL, &FT);
  675.  
  676.         CloseHandle(fHandle);
  677.     }
  678. }
  679.  
  680. /*********************************/
  681. /* Function NtfsFileTime2utime() */
  682. /*********************************/
  683.  
  684. /* scale factor and offset for conversion time_t -> FILETIME */
  685. #define NT_QUANTA_PER_UNIX 10000000L
  686. #define UNIX_TIME_ZERO_HI  0x019DB1DEUL
  687. #define UNIX_TIME_ZERO_LO  0xD53E8000UL
  688.  
  689. // /* nonzero if `y' is a leap year, else zero */
  690. //#define leap(y) (((y)%4 == 0 && (y)%100 != 0) || (y)%400 == 0)
  691. // /* number of leap years from 1970 to `y' (not including `y' itself) */
  692. //#define nleap(y) (((y)-1969)/4 - ((y)-1901)/100 + ((y)-1601)/400)
  693.  
  694. int NtfsFileTime2utime(const FILETIME *pft, time_t *ut)
  695. {
  696.     unsigned __int64 NTtime;
  697.  
  698.     NTtime = ((unsigned __int64)pft->dwLowDateTime +
  699.               ((unsigned __int64)pft->dwHighDateTime << 32));
  700.  
  701.     NTtime -= ((unsigned __int64)UNIX_TIME_ZERO_LO +
  702.                ((unsigned __int64)UNIX_TIME_ZERO_HI << 32));
  703.     *ut = (time_t)(NTtime / (unsigned long)NT_QUANTA_PER_UNIX);
  704.     return TRUE;
  705. } /* end function NtfsFileTime2utime() */
  706.  
  707.  
  708. // If file *f does not exist, return 0. Else, return the file's last
  709. //   modified date and time as an MSDOS date and time. The date and time is
  710. //   returned in a long with the date most significant to allow unsigned
  711. //   integer comparison of absolute times. Also, if a is not a NULL pointer,
  712. //   store the file attributes there, with the high two bytes being the Unix
  713. //   attributes, and the low byte being a mapping of that to DOS attributes.
  714. //   If n is not NULL, store the file size there.
  715. //     If f is "-", use standard input as the file.
  716. //     If f is a device, return a file size of -1
  717. //     If f is a Volume Name, return a file size of -2
  718. //   If t is not NULL, the file's access and modification time are stored there
  719. //    as UNIX time_t values.
  720. //   f :: Name of file to get info on.
  721. //   a :: Return value: file attributes.
  722. //   n :: Return value: file size.
  723. //   t :: Return value: access and modification time.
  724. extern BOOL unixtofile(time_t tim, FILETIME *ftp);
  725.  
  726. ulg ZipFunc::zfiletime(const DZStrW& f, ulg *a, __int64 *n, ztimbuf *t)
  727. {
  728.     WIN32_FIND_DATA ff;
  729.     HANDLE      hfind;              /* file handle */
  730.  
  731.     if (f == flabel)
  732.     {
  733.         if (a != NULL)
  734.             *a = flabel_mode;
  735.  
  736.         if (n != NULL)
  737.             *n = ZFT_LABEL;               // convention for a label name
  738.  
  739.         if (t != NULL)
  740.             t->actime = t->modtime = flabel_utim;
  741.  
  742.         return flabel_time;
  743.     }
  744.  
  745.     int drv = Is_Drv(f);
  746.  
  747.     if (drv < 0)
  748.     {
  749.                 //stream
  750.                 ZSData.BufP = 0;
  751.         ZSData.Number = (-drv) - 2; // stream number
  752.         ZSData.OpCode = zsaIdentify;
  753.         int ok = StreamCB() == CALLBACK_TRUE;
  754.  
  755.         if (ok)
  756.         {
  757.             if (n)
  758.                 *n = ZSData.ArgLL;
  759.  
  760.             if (a != NULL)
  761.             {
  762.                                 DWORD dwAttr = ZSData.ArgA;
  763.                 *a = (dwAttr & FILE_ATTRIBUTE_READONLY ? A_RONLY : 0) |
  764.                      (dwAttr & FILE_ATTRIBUTE_HIDDEN ? A_HIDDEN : 0) |
  765.                      (dwAttr & FILE_ATTRIBUTE_SYSTEM ? A_SYSTEM : 0) |
  766.                      (dwAttr & FILE_ATTRIBUTE_DIRECTORY ? A_DIR : 0) |
  767.                      (dwAttr & FILE_ATTRIBUTE_ARCHIVE ? A_ARCHIVE : 0);
  768.                         }
  769.             return ZSData.ArgD;
  770.         }
  771.  
  772.         return 0;
  773.     }
  774.  
  775.     DZStrW fullname = drv ? f : GetFullPath(f);
  776.  
  777.         // not all systems allow stat'ing a file with / appended, so remove it
  778.     if (fullname.LastChar() == BSLASH)
  779.         fullname = fullname.Left(fullname.length()-1);
  780.  
  781.         // Accept about any kind of file including directories
  782.     if ((hfind = FindFirstFile(fullname, &ff)) == INVALID_HANDLE_VALUE)
  783.     {
  784.         if (Verbose < 0)
  785.             Notify(ITRACE, _T("Could not find %s"), fullname.c_str());
  786.  
  787.         return 0;                 // error in stat!
  788.     }
  789.  
  790.         FindClose(hfind);
  791.         // found
  792.     if (n != NULL)
  793.     {
  794.         *n = ff.nFileSizeLow  | ((__int64)ff.nFileSizeHigh << 32);
  795.     }
  796.  
  797.     if (a != NULL)
  798.     {
  799.         DWORD dwAttr = ff.dwFileAttributes;
  800.         *a = (dwAttr & FILE_ATTRIBUTE_READONLY ? A_RONLY : 0) |
  801.              (dwAttr & FILE_ATTRIBUTE_HIDDEN ? A_HIDDEN : 0) |
  802.              (dwAttr & FILE_ATTRIBUTE_SYSTEM ? A_SYSTEM : 0) |
  803.              (dwAttr & FILE_ATTRIBUTE_DIRECTORY ? A_DIR : 0) |
  804.              (dwAttr & FILE_ATTRIBUTE_ARCHIVE ? A_ARCHIVE : 0);
  805.     }
  806.  
  807.     if (t != NULL)
  808.     {
  809.         NtfsFileTime2utime(&ff.ftLastAccessTime, &t->actime);
  810.                 NtfsFileTime2utime(&ff.ftLastWriteTime, &t->modtime);
  811.     }
  812.  
  813.     return FileTime2DosTime(ff.ftLastWriteTime);
  814. }
  815.  
  816. ulg FileTime2DosTime(_FILETIME ftime)
  817. {
  818.     _FILETIME local;
  819.     WORD dt, tm;
  820.  
  821.     if (FileTimeToLocalFileTime(&ftime, &local) &&
  822.             FileTimeToDosDateTime(&local, &dt, &tm))
  823.         return (dt << 16) | tm;
  824.  
  825. //      Notify(0, "zip diagnostic: GetFileAttributes failed");
  826.     return 0;
  827. }
  828.  
  829. #define EAID  0x0009
  830.  
  831. // NOTE: NTFS is handled by the HPFS code. FAT / HPFS detection.
  832. int ZipOp::IsFileSystemOldFAT(const DZStrW &dir)
  833. {
  834.     DWORD vfnsize;
  835.     DWORD vfsflags;
  836.  
  837.     if (Verbose < 0)
  838.         Notify(ITRACE, _T("IsFileSyatemOldFAT called for %s"), dir.c_str());
  839.  
  840.     // We separate FAT and HPFS+other file systems here. I consider other
  841.     //   systems to be similar to HPFS/NTFS, i.e. support for long file names and
  842.     //   being case sensitive to some extent.
  843.     DZStrW fp = dir;
  844.  
  845.     if (fp.IsEmpty() || Is_DrvEx(fp) <= 0)
  846.     {
  847.         fp = fRootDir;   // use current root
  848.  
  849.         if (fp.IsEmpty() || Is_Drv(fp) <= 0)
  850.             return false; // assume ntfs
  851.     }
  852.  
  853.     int dt = Is_DrvEx(fp);
  854.  
  855.     if (dt < 0)
  856.         return false;
  857.  
  858.     if (dt == 1)
  859.     {
  860.         fp = fp.Left(1);
  861.         fp.ToUpper();
  862.         TCHAR r = fp[0];
  863.  
  864.         if (r == fDrv[0])
  865.             return fDrv[1] != 0;  // use cached result
  866.  
  867.         fp += _T(":\\");
  868.     }
  869.     else
  870.     {
  871.         if (dt != 2)
  872.             return false;
  873.  
  874.         // specify \\MyServer\MyShare as \\MyServer\MyShare\.
  875.         fp = fp.Left(DriveLen(fp));
  876.     }
  877.  
  878.     if (!GetVolumeInformation(fp, NULL, 0, NULL, &vfnsize, &vfsflags, NULL, 0))
  879.     {
  880.         if (Verbose)
  881.         {
  882.             Notify(IVERBOSE, _T(" GetVolumeInformation failed for %s [%s]"),
  883.                    fp.c_str(), SysMsg().c_str());
  884.         }
  885.  
  886.         return (false);    // assume NTFS
  887.     }
  888.  
  889.     if (Verbose)
  890.         Notify(IVERBOSE, _T("Max component size for %s = %d"), fp.c_str(), vfnsize);
  891.  
  892.     if (_istascii(fp[0]))
  893.     {
  894.         fDrv[0] = fp[0];
  895.         fDrv[1] = (char)(vfnsize <= 12 ? 1 : 0);
  896.     }
  897.  
  898.     return vfnsize <= 12;
  899. }
  900.  
  901. // access mode bits and time stamp.
  902. int ZipOp::GetFileMode(const DZStrW& name)
  903. {
  904.     DWORD dwAttr;
  905.  
  906.     dwAttr = GetFileAttributes(GetFullPath(name));   // v1.6017
  907.  
  908.     if (dwAttr == 0xFFFFFFFF)
  909.     {
  910.         // RCV Changed: was ...= -1
  911.         Notify(0, _T("zip diagnostic: GetFileAttributes failed"));
  912.  
  913.         // DLLprintf ("zip diagnostic: GetFileAttributes failed\n");
  914.         return (0x20);       // the most likely, though why the error? security?
  915.     }
  916.  
  917.     return
  918.         (
  919.             (dwAttr & FILE_ATTRIBUTE_READONLY ? A_RONLY : 0) |
  920.             (dwAttr & FILE_ATTRIBUTE_HIDDEN ? A_HIDDEN : 0) |
  921.             (dwAttr & FILE_ATTRIBUTE_SYSTEM ? A_SYSTEM : 0) |
  922.             (dwAttr & FILE_ATTRIBUTE_DIRECTORY ? A_DIR : 0) |
  923.             (dwAttr & FILE_ATTRIBUTE_ARCHIVE ? A_ARCHIVE : 0)
  924.         );
  925. }
  926.  
  927. const char *GetLongPathEA(void)
  928. {
  929.     return (NULL);                // volunteers ?
  930. }
  931.  
  932. // If a volume label exists for the given drive, return its name and pretend
  933. //   to set its time and mode. The returned name is global data. Drive = drive
  934. //   name: 'A' .. 'Z' or '\0' for current drive
  935. DZStrW ZipOp::getVolumeLabel(const DZStrW &drv, ulg *vtime, ulg *vmode, time_t *vutim)
  936. {
  937.     DZStrW Root(drv, 2);
  938.     ulg   fnlen,
  939.     flags;
  940.     long  OldMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
  941.     BOOL  Result;
  942.  
  943.     *vmode = A_ARCHIVE | A_LABEL; // this is what msdos returns
  944.     *vtime = dostime(1980, 1, 1, 0, 0, 0);    // no true date info available
  945.     *vutim = dos2unixtime(*vtime);
  946.  
  947.         DZStrW vol;
  948.  
  949.     if (Is_Drv(drv) != 1)
  950.         Root.Empty();
  951.     else
  952.         Root += BSLASH;
  953.  
  954.     Result = GetVolumeInformation(Root, vol.GetBuffer(MAX_PATH), MAX_PATH - 1,
  955.                                   NULL, &fnlen, &flags, NULL, 0);
  956.     SetErrorMode(OldMode);
  957.     vol.ReleaseBuffer();
  958.  
  959.     if (!Result)
  960.         vol.Empty();
  961.  
  962.     return vol;//Result ? fvol : NULL;
  963. }
  964.  
  965.  
  966.  
  967.  
  968.  
  969.