tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ArchiveCommandLine.cpp (37286B)


      1 // ArchiveCommandLine.cpp
      2 
      3 #include "StdAfx.h"
      4 #undef printf
      5 #undef sprintf
      6 
      7 #ifdef _WIN32
      8 #ifndef UNDER_CE
      9 #include <io.h>
     10 #endif
     11 #else
     12 // for isatty()
     13 #include <unistd.h>
     14 #endif
     15 
     16 #include <stdio.h>
     17 
     18 #ifdef _7ZIP_LARGE_PAGES
     19 #include "../../../../C/Alloc.h"
     20 #endif
     21 
     22 #include "../../../Common/ListFileUtils.h"
     23 #include "../../../Common/StringConvert.h"
     24 #include "../../../Common/StringToInt.h"
     25 
     26 #include "../../../Windows/FileDir.h"
     27 #include "../../../Windows/FileName.h"
     28 #ifdef _WIN32
     29 #include "../../../Windows/FileMapping.h"
     30 #include "../../../Windows/MemoryLock.h"
     31 #include "../../../Windows/Synchronization.h"
     32 #endif
     33 
     34 #include "ArchiveCommandLine.h"
     35 #include "EnumDirItems.h"
     36 #include "Update.h"
     37 #include "UpdateAction.h"
     38 
     39 extern bool g_CaseSensitive;
     40 extern bool g_PathTrailReplaceMode;
     41 
     42 bool g_LargePagesMode = false;
     43 
     44 #ifdef UNDER_CE
     45 
     46 #define MY_IS_TERMINAL(x) false;
     47 
     48 #else
     49 
     50 #if _MSC_VER >= 1400
     51 #define MY_isatty_fileno(x) _isatty(_fileno(x))
     52 #else
     53 #define MY_isatty_fileno(x) isatty(fileno(x))
     54 #endif
     55 
     56 #define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 0);
     57 
     58 #endif
     59 
     60 using namespace NCommandLineParser;
     61 using namespace NWindows;
     62 using namespace NFile;
     63 
     64 static bool StringToUInt32(const wchar_t *s, UInt32 &v)
     65 {
     66  if (*s == 0)
     67    return false;
     68  const wchar_t *end;
     69  v = ConvertStringToUInt32(s, &end);
     70  return *end == 0;
     71 }
     72 
     73 
     74 int g_CodePage = -1;
     75 
     76 namespace NKey {
     77 enum Enum
     78 {
     79  kHelp1 = 0,
     80  kHelp2,
     81  kHelp3,
     82  
     83  kDisableHeaders,
     84  kDisablePercents,
     85  kShowTime,
     86  kLogLevel,
     87 
     88  kOutStream,
     89  kErrStream,
     90  kPercentStream,
     91 
     92  kYes,
     93 
     94  kShowDialog,
     95  kOverwrite,
     96 
     97  kArchiveType,
     98  kExcludedArcType,
     99 
    100  kProperty,
    101  kOutputDir,
    102  kWorkingDir,
    103  
    104  kInclude,
    105  kExclude,
    106  kArInclude,
    107  kArExclude,
    108  kNoArName,
    109 
    110  kUpdate,
    111  kVolume,
    112  kRecursed,
    113 
    114  kAffinity,
    115  kSfx,
    116  kEmail,
    117  kHash,
    118 
    119  kStdIn,
    120  kStdOut,
    121 
    122  kLargePages,
    123  kListfileCharSet,
    124  kConsoleCharSet,
    125  kTechMode,
    126  
    127  kShareForWrite,
    128  kStopAfterOpenError,
    129  kCaseSensitive,
    130  kArcNameMode,
    131 
    132  kDisableWildcardParsing,
    133  kElimDup,
    134  kFullPathMode,
    135  
    136  kHardLinks,
    137  kSymLinks,
    138  kNtSecurity,
    139  
    140  kAltStreams,
    141  kReplaceColonForAltStream,
    142  kWriteToAltStreamIfColon,
    143 
    144  kNameTrailReplace,
    145 
    146  kDeleteAfterCompressing,
    147  kSetArcMTime
    148 
    149  #ifndef _NO_CRYPTO
    150  , kPassword
    151  #endif
    152 };
    153 
    154 }
    155 
    156 
    157 static const wchar_t kRecursedIDChar = 'r';
    158 static const char * const kRecursedPostCharSet = "0-";
    159 
    160 static const char * const k_ArcNameMode_PostCharSet = "sea";
    161 
    162 static const char * const k_Stream_PostCharSet = "012";
    163 
    164 static inline const EArcNameMode ParseArcNameMode(int postCharIndex)
    165 {
    166  switch (postCharIndex)
    167  {
    168    case 1: return k_ArcNameMode_Exact;
    169    case 2: return k_ArcNameMode_Add;
    170    default: return k_ArcNameMode_Smart;
    171  }
    172 }
    173 
    174 namespace NRecursedPostCharIndex {
    175  enum EEnum
    176  {
    177    kWildcardRecursionOnly = 0,
    178    kNoRecursion = 1
    179  };
    180 }
    181 
    182 static const char kImmediateNameID = '!';
    183 static const char kMapNameID = '#';
    184 static const char kFileListID = '@';
    185 
    186 static const char kSomeCludePostStringMinSize = 2; // at least <@|!><N>ame must be
    187 static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>ame must be
    188 
    189 static const char * const kOverwritePostCharSet = "asut";
    190 
    191 static const NExtract::NOverwriteMode::EEnum k_OverwriteModes[] =
    192 {
    193  NExtract::NOverwriteMode::kOverwrite,
    194  NExtract::NOverwriteMode::kSkip,
    195  NExtract::NOverwriteMode::kRename,
    196  NExtract::NOverwriteMode::kRenameExisting
    197 };
    198 
    199 static const CSwitchForm kSwitchForms[] =
    200 {
    201  { "?" },
    202  { "h" },
    203  { "-help" },
    204  
    205  { "ba" },
    206  { "bd" },
    207  { "bt" },
    208  { "bb", NSwitchType::kString, false, 0 },
    209 
    210  { "bso", NSwitchType::kChar, false, 1, k_Stream_PostCharSet },
    211  { "bse", NSwitchType::kChar, false, 1, k_Stream_PostCharSet },
    212  { "bsp", NSwitchType::kChar, false, 1, k_Stream_PostCharSet },
    213  
    214  { "y" },
    215  
    216  { "ad" },
    217  { "ao", NSwitchType::kChar, false, 1, kOverwritePostCharSet},
    218 
    219  { "t",  NSwitchType::kString, false, 1 },
    220  { "stx", NSwitchType::kString, true, 1 },
    221  
    222  { "m",  NSwitchType::kString, true, 1 },
    223  { "o",  NSwitchType::kString, false, 1 },
    224  { "w",  NSwitchType::kString },
    225 
    226  { "i",  NSwitchType::kString, true, kSomeCludePostStringMinSize},
    227  { "x",  NSwitchType::kString, true, kSomeCludePostStringMinSize},
    228  { "ai", NSwitchType::kString, true, kSomeCludePostStringMinSize},
    229  { "ax", NSwitchType::kString, true, kSomeCludePostStringMinSize},
    230  { "an" },
    231  
    232  { "u",  NSwitchType::kString, true, 1},
    233  { "v",  NSwitchType::kString, true, 1},
    234  { "r",  NSwitchType::kChar, false, 0, kRecursedPostCharSet },
    235  
    236  { "stm", NSwitchType::kString },
    237  { "sfx", NSwitchType::kString },
    238  { "seml", NSwitchType::kString, false, 0},
    239  { "scrc", NSwitchType::kString, true, 0 },
    240  
    241  { "si", NSwitchType::kString },
    242  { "so" },
    243 
    244  { "slp", NSwitchType::kString },
    245  { "scs", NSwitchType::kString },
    246  { "scc", NSwitchType::kString },
    247  { "slt" },
    248 
    249  { "ssw" },
    250  { "sse" },
    251  { "ssc", NSwitchType::kMinus },
    252  { "sa",  NSwitchType::kChar, false, 1, k_ArcNameMode_PostCharSet },
    253  
    254  { "spd" },
    255  { "spe", NSwitchType::kMinus },
    256  { "spf", NSwitchType::kString, false, 0 },
    257  
    258  { "snh", NSwitchType::kMinus },
    259  { "snl", NSwitchType::kMinus },
    260  { "sni" },
    261  
    262  { "sns", NSwitchType::kMinus },
    263  { "snr" },
    264  { "snc" },
    265  
    266  { "snt", NSwitchType::kMinus },
    267  
    268  { "sdel" },
    269  { "stl" }
    270 
    271  #ifndef _NO_CRYPTO
    272  , { "p",  NSwitchType::kString }
    273  #endif
    274 };
    275 
    276 static const char * const kUniversalWildcard = "*";
    277 static const unsigned kMinNonSwitchWords = 1;
    278 static const unsigned kCommandIndex = 0;
    279 
    280 // static const char * const kUserErrorMessage  = "Incorrect command line";
    281 static const char * const kCannotFindListFile = "Cannot find listfile";
    282 static const char * const kIncorrectListFile = "Incorrect item in listfile.\nCheck charset encoding and -scs switch.";
    283 static const char * const kTerminalOutError = "I won't write compressed data to a terminal";
    284 static const char * const kSameTerminalError = "I won't write data and program's messages to same stream";
    285 static const char * const kEmptyFilePath = "Empty file path";
    286 
    287 bool CArcCommand::IsFromExtractGroup() const
    288 {
    289  switch (CommandType)
    290  {
    291    case NCommandType::kTest:
    292    case NCommandType::kExtract:
    293    case NCommandType::kExtractFull:
    294      return true;
    295  }
    296  return false;
    297 }
    298 
    299 NExtract::NPathMode::EEnum CArcCommand::GetPathMode() const
    300 {
    301  switch (CommandType)
    302  {
    303    case NCommandType::kTest:
    304    case NCommandType::kExtractFull:
    305      return NExtract::NPathMode::kFullPaths;
    306  }
    307  return NExtract::NPathMode::kNoPaths;
    308 }
    309 
    310 bool CArcCommand::IsFromUpdateGroup() const
    311 {
    312  switch (CommandType)
    313  {
    314    case NCommandType::kAdd:
    315    case NCommandType::kUpdate:
    316    case NCommandType::kDelete:
    317    case NCommandType::kRename:
    318      return true;
    319  }
    320  return false;
    321 }
    322 
    323 static NRecursedType::EEnum GetRecursedTypeFromIndex(int index)
    324 {
    325  switch (index)
    326  {
    327    case NRecursedPostCharIndex::kWildcardRecursionOnly:
    328      return NRecursedType::kWildcardOnlyRecursed;
    329    case NRecursedPostCharIndex::kNoRecursion:
    330      return NRecursedType::kNonRecursed;
    331    default:
    332      return NRecursedType::kRecursed;
    333  }
    334 }
    335 
    336 static const char *g_Commands = "audtexlbih";
    337 
    338 static bool ParseArchiveCommand(const UString &commandString, CArcCommand &command)
    339 {
    340  UString s (commandString);
    341  s.MakeLower_Ascii();
    342  if (s.Len() == 1)
    343  {
    344    if (s[0] > 0x7F)
    345      return false;
    346    int index = FindCharPosInString(g_Commands, (char)s[0]);
    347    if (index < 0)
    348      return false;
    349    command.CommandType = (NCommandType::EEnum)index;
    350    return true;
    351  }
    352  if (s.Len() == 2 && s[0] == 'r' && s[1] == 'n')
    353  {
    354    command.CommandType = (NCommandType::kRename);
    355    return true;
    356  }
    357  return false;
    358 }
    359 
    360 // ------------------------------------------------------------------
    361 // filenames functions
    362 
    363 static void AddNameToCensor(NWildcard::CCensor &censor,
    364    const UString &name, bool include, NRecursedType::EEnum type, bool wildcardMatching)
    365 {
    366  bool recursed = false;
    367 
    368  switch (type)
    369  {
    370    case NRecursedType::kWildcardOnlyRecursed:
    371      recursed = DoesNameContainWildcard(name);
    372      break;
    373    case NRecursedType::kRecursed:
    374      recursed = true;
    375      break;
    376  }
    377  censor.AddPreItem(include, name, recursed, wildcardMatching);
    378 }
    379 
    380 static void AddRenamePair(CObjectVector<CRenamePair> *renamePairs,
    381    const UString &oldName, const UString &newName, NRecursedType::EEnum type,
    382    bool wildcardMatching)
    383 {
    384  CRenamePair &pair = renamePairs->AddNew();
    385  pair.OldName = oldName;
    386  pair.NewName = newName;
    387  pair.RecursedType = type;
    388  pair.WildcardParsing = wildcardMatching;
    389 
    390  if (!pair.Prepare())
    391  {
    392    UString val;
    393    val += pair.OldName;
    394    val.Add_LF();
    395    val += pair.NewName;
    396    val.Add_LF();
    397    if (type == NRecursedType::kRecursed)
    398      val += "-r";
    399    else if (type == NRecursedType::kWildcardOnlyRecursed)
    400      val += "-r0";
    401    throw CArcCmdLineException("Unsupported rename command:", val);
    402  }
    403 }
    404 
    405 static void AddToCensorFromListFile(
    406    CObjectVector<CRenamePair> *renamePairs,
    407    NWildcard::CCensor &censor,
    408    LPCWSTR fileName, bool include, NRecursedType::EEnum type, bool wildcardMatching, Int32 codePage)
    409 {
    410  UStringVector names;
    411  if (!NFind::DoesFileExist(us2fs(fileName)))
    412    throw CArcCmdLineException(kCannotFindListFile, fileName);
    413  if (!ReadNamesFromListFile(us2fs(fileName), names, codePage))
    414    throw CArcCmdLineException(kIncorrectListFile, fileName);
    415  if (renamePairs)
    416  {
    417    if ((names.Size() & 1) != 0)
    418      throw CArcCmdLineException(kIncorrectListFile, fileName);
    419    for (unsigned i = 0; i < names.Size(); i += 2)
    420    {
    421      // change type !!!!
    422      AddRenamePair(renamePairs, names[i], names[i + 1], type, wildcardMatching);
    423    }
    424  }
    425  else
    426    FOR_VECTOR (i, names)
    427      AddNameToCensor(censor, names[i], include, type, wildcardMatching);
    428 }
    429 
    430 static void AddToCensorFromNonSwitchesStrings(
    431    CObjectVector<CRenamePair> *renamePairs,
    432    unsigned startIndex,
    433    NWildcard::CCensor &censor,
    434    const UStringVector &nonSwitchStrings,
    435    int stopSwitchIndex,
    436    NRecursedType::EEnum type,
    437    bool wildcardMatching,
    438    bool thereAreSwitchIncludes, Int32 codePage)
    439 {
    440  if ((renamePairs || nonSwitchStrings.Size() == startIndex) && !thereAreSwitchIncludes)
    441    AddNameToCensor(censor, UString(kUniversalWildcard), true, type,
    442        true // wildcardMatching
    443        );
    444 
    445  int oldIndex = -1;
    446  
    447  if (stopSwitchIndex < 0)
    448    stopSwitchIndex = nonSwitchStrings.Size();
    449 
    450  for (unsigned i = startIndex; i < nonSwitchStrings.Size(); i++)
    451  {
    452    const UString &s = nonSwitchStrings[i];
    453    if (s.IsEmpty())
    454      throw CArcCmdLineException(kEmptyFilePath);
    455    if (i < (unsigned)stopSwitchIndex && s[0] == kFileListID)
    456      AddToCensorFromListFile(renamePairs, censor, s.Ptr(1), true, type, wildcardMatching, codePage);
    457    else if (renamePairs)
    458    {
    459      if (oldIndex == -1)
    460        oldIndex = i;
    461      else
    462      {
    463        // NRecursedType::EEnum type is used for global wildcard (-i! switches)
    464        AddRenamePair(renamePairs, nonSwitchStrings[oldIndex], s, NRecursedType::kNonRecursed, wildcardMatching);
    465        // AddRenamePair(renamePairs, nonSwitchStrings[oldIndex], s, type);
    466        oldIndex = -1;
    467      }
    468    }
    469    else
    470      AddNameToCensor(censor, s, true, type, wildcardMatching);
    471  }
    472  
    473  if (oldIndex != -1)
    474  {
    475    throw CArcCmdLineException("There is no second file name for rename pair:", nonSwitchStrings[oldIndex]);
    476  }
    477 }
    478 
    479 #ifdef _WIN32
    480 
    481 struct CEventSetEnd
    482 {
    483  UString Name;
    484  
    485  CEventSetEnd(const wchar_t *name): Name(name) {}
    486  ~CEventSetEnd()
    487  {
    488    NSynchronization::CManualResetEvent event;
    489    if (event.Open(EVENT_MODIFY_STATE, false, GetSystemString(Name)) == 0)
    490      event.Set();
    491  }
    492 };
    493 
    494 static const char * const k_IncorrectMapCommand = "Incorrect Map command";
    495 
    496 static const char *ParseMapWithPaths(
    497    NWildcard::CCensor &censor,
    498    const UString &s2, bool include,
    499    NRecursedType::EEnum commonRecursedType,
    500    bool wildcardMatching)
    501 {
    502  UString s (s2);
    503  int pos = s.Find(L':');
    504  if (pos < 0)
    505    return k_IncorrectMapCommand;
    506  int pos2 = s.Find(L':', pos + 1);
    507  if (pos2 < 0)
    508    return k_IncorrectMapCommand;
    509 
    510  CEventSetEnd eventSetEnd((const wchar_t *)s + ((unsigned)pos2 + 1));
    511  s.DeleteFrom(pos2);
    512  UInt32 size;
    513  if (!StringToUInt32(s.Ptr(pos + 1), size)
    514      || size < sizeof(wchar_t)
    515      || size > ((UInt32)1 << 31)
    516      || size % sizeof(wchar_t) != 0)
    517    return "Unsupported Map data size";
    518 
    519  s.DeleteFrom(pos);
    520  CFileMapping map;
    521  if (map.Open(FILE_MAP_READ, GetSystemString(s)) != 0)
    522    return "Can not open mapping";
    523  LPVOID data = map.Map(FILE_MAP_READ, 0, size);
    524  if (!data)
    525    return "MapViewOfFile error";
    526  CFileUnmapper unmapper(data);
    527 
    528  UString name;
    529  const wchar_t *p = (const wchar_t *)data;
    530  if (*p != 0) // data format marker
    531    return "Unsupported Map data";
    532  UInt32 numChars = size / sizeof(wchar_t);
    533  for (UInt32 i = 1; i < numChars; i++)
    534  {
    535    wchar_t c = p[i];
    536    if (c == 0)
    537    {
    538      // MessageBoxW(0, name, L"7-Zip", 0);
    539      AddNameToCensor(censor, name, include, commonRecursedType, wildcardMatching);
    540      name.Empty();
    541    }
    542    else
    543      name += c;
    544  }
    545  if (!name.IsEmpty())
    546    return "Map data error";
    547 
    548  return NULL;
    549 }
    550 
    551 #endif
    552 
    553 static void AddSwitchWildcardsToCensor(
    554    NWildcard::CCensor &censor,
    555    const UStringVector &strings, bool include,
    556    NRecursedType::EEnum commonRecursedType,
    557    bool wildcardMatching,
    558    Int32 codePage)
    559 {
    560  const char *errorMessage = NULL;
    561  unsigned i;
    562  for (i = 0; i < strings.Size(); i++)
    563  {
    564    const UString &name = strings[i];
    565    NRecursedType::EEnum recursedType;
    566    unsigned pos = 0;
    567    
    568    if (name.Len() < kSomeCludePostStringMinSize)
    569    {
    570      errorMessage = "Too short switch";
    571      break;
    572    }
    573    
    574    if (::MyCharLower_Ascii(name[pos]) == kRecursedIDChar)
    575    {
    576      pos++;
    577      wchar_t c = name[pos];
    578      int index = -1;
    579      if (c <= 0x7F)
    580        index = FindCharPosInString(kRecursedPostCharSet, (char)c);
    581      recursedType = GetRecursedTypeFromIndex(index);
    582      if (index >= 0)
    583        pos++;
    584    }
    585    else
    586      recursedType = commonRecursedType;
    587    
    588    if (name.Len() < pos + kSomeCludeAfterRecursedPostStringMinSize)
    589    {
    590      errorMessage = "Too short switch";
    591      break;
    592    }
    593    
    594    const UString tail = name.Ptr(pos + 1);
    595    
    596    if (name[pos] == kImmediateNameID)
    597      AddNameToCensor(censor, tail, include, recursedType, wildcardMatching);
    598    else if (name[pos] == kFileListID)
    599      AddToCensorFromListFile(NULL, censor, tail, include, recursedType, wildcardMatching, codePage);
    600    #ifdef _WIN32
    601    else if (name[pos] == kMapNameID)
    602    {
    603      errorMessage = ParseMapWithPaths(censor, tail, include, recursedType, wildcardMatching);
    604      if (errorMessage)
    605        break;
    606    }
    607    #endif
    608    else
    609    {
    610      errorMessage = "Incorrect wildcard type marker";
    611      break;
    612    }
    613  }
    614  if (i != strings.Size())
    615    throw CArcCmdLineException(errorMessage, strings[i]);
    616 }
    617 
    618 /*
    619 static NUpdateArchive::NPairAction::EEnum GetUpdatePairActionType(int i)
    620 {
    621  switch (i)
    622  {
    623    case NUpdateArchive::NPairAction::kIgnore: return NUpdateArchive::NPairAction::kIgnore;
    624    case NUpdateArchive::NPairAction::kCopy: return NUpdateArchive::NPairAction::kCopy;
    625    case NUpdateArchive::NPairAction::kCompress: return NUpdateArchive::NPairAction::kCompress;
    626    case NUpdateArchive::NPairAction::kCompressAsAnti: return NUpdateArchive::NPairAction::kCompressAsAnti;
    627  }
    628  throw 98111603;
    629 }
    630 */
    631 
    632 static const char * const kUpdatePairStateIDSet = "pqrxyzw";
    633 static const int kUpdatePairStateNotSupportedActions[] = {2, 2, 1, -1, -1, -1, -1};
    634 
    635 static const unsigned kNumUpdatePairActions = 4;
    636 static const char * const kUpdateIgnoreItselfPostStringID = "-";
    637 static const wchar_t kUpdateNewArchivePostCharID = '!';
    638 
    639 
    640 static bool ParseUpdateCommandString2(const UString &command,
    641    NUpdateArchive::CActionSet &actionSet, UString &postString)
    642 {
    643  for (unsigned i = 0; i < command.Len();)
    644  {
    645    wchar_t c = MyCharLower_Ascii(command[i]);
    646    int statePos = FindCharPosInString(kUpdatePairStateIDSet, (char)c);
    647    if (c > 0x7F || statePos < 0)
    648    {
    649      postString = command.Ptr(i);
    650      return true;
    651    }
    652    i++;
    653    if (i >= command.Len())
    654      return false;
    655    c = command[i];
    656    if (c < '0' || c >= '0' + kNumUpdatePairActions)
    657      return false;
    658    unsigned actionPos = c - '0';
    659    actionSet.StateActions[(unsigned)statePos] = (NUpdateArchive::NPairAction::EEnum)(actionPos);
    660    if (kUpdatePairStateNotSupportedActions[(unsigned)statePos] == (int)actionPos)
    661      return false;
    662    i++;
    663  }
    664  postString.Empty();
    665  return true;
    666 }
    667 
    668 static void ParseUpdateCommandString(CUpdateOptions &options,
    669    const UStringVector &updatePostStrings,
    670    const NUpdateArchive::CActionSet &defaultActionSet)
    671 {
    672  const char *errorMessage = "incorrect update switch command";
    673  unsigned i;
    674  for (i = 0; i < updatePostStrings.Size(); i++)
    675  {
    676    const UString &updateString = updatePostStrings[i];
    677    if (updateString.IsEqualTo(kUpdateIgnoreItselfPostStringID))
    678    {
    679      if (options.UpdateArchiveItself)
    680      {
    681        options.UpdateArchiveItself = false;
    682        options.Commands.Delete(0);
    683      }
    684    }
    685    else
    686    {
    687      NUpdateArchive::CActionSet actionSet = defaultActionSet;
    688 
    689      UString postString;
    690      if (!ParseUpdateCommandString2(updateString, actionSet, postString))
    691        break;
    692      if (postString.IsEmpty())
    693      {
    694        if (options.UpdateArchiveItself)
    695          options.Commands[0].ActionSet = actionSet;
    696      }
    697      else
    698      {
    699        if (postString[0] != kUpdateNewArchivePostCharID)
    700          break;
    701        CUpdateArchiveCommand uc;
    702        UString archivePath = postString.Ptr(1);
    703        if (archivePath.IsEmpty())
    704          break;
    705        uc.UserArchivePath = archivePath;
    706        uc.ActionSet = actionSet;
    707        options.Commands.Add(uc);
    708      }
    709    }
    710  }
    711  if (i != updatePostStrings.Size())
    712    throw CArcCmdLineException(errorMessage, updatePostStrings[i]);
    713 }
    714 
    715 bool ParseComplexSize(const wchar_t *s, UInt64 &result);
    716 
    717 static void SetAddCommandOptions(
    718    NCommandType::EEnum commandType,
    719    const CParser &parser,
    720    CUpdateOptions &options)
    721 {
    722  NUpdateArchive::CActionSet defaultActionSet;
    723  switch (commandType)
    724  {
    725    case NCommandType::kAdd:
    726      defaultActionSet = NUpdateArchive::k_ActionSet_Add;
    727      break;
    728    case NCommandType::kDelete:
    729      defaultActionSet = NUpdateArchive::k_ActionSet_Delete;
    730      break;
    731    default:
    732      defaultActionSet = NUpdateArchive::k_ActionSet_Update;
    733  }
    734  
    735  options.UpdateArchiveItself = true;
    736  
    737  options.Commands.Clear();
    738  CUpdateArchiveCommand updateMainCommand;
    739  updateMainCommand.ActionSet = defaultActionSet;
    740  options.Commands.Add(updateMainCommand);
    741  if (parser[NKey::kUpdate].ThereIs)
    742    ParseUpdateCommandString(options, parser[NKey::kUpdate].PostStrings,
    743        defaultActionSet);
    744  if (parser[NKey::kWorkingDir].ThereIs)
    745  {
    746    const UString &postString = parser[NKey::kWorkingDir].PostStrings[0];
    747    if (postString.IsEmpty())
    748      NDir::MyGetTempPath(options.WorkingDir);
    749    else
    750      options.WorkingDir = us2fs(postString);
    751  }
    752  options.SfxMode = parser[NKey::kSfx].ThereIs;
    753  if (options.SfxMode)
    754    options.SfxModule = us2fs(parser[NKey::kSfx].PostStrings[0]);
    755 
    756  if (parser[NKey::kVolume].ThereIs)
    757  {
    758    const UStringVector &sv = parser[NKey::kVolume].PostStrings;
    759    FOR_VECTOR (i, sv)
    760    {
    761      UInt64 size;
    762      if (!ParseComplexSize(sv[i], size) || size == 0)
    763        throw CArcCmdLineException("Incorrect volume size:", sv[i]);
    764      options.VolumesSizes.Add(size);
    765    }
    766  }
    767 }
    768 
    769 static void SetMethodOptions(const CParser &parser, CObjectVector<CProperty> &properties)
    770 {
    771  if (parser[NKey::kProperty].ThereIs)
    772  {
    773    FOR_VECTOR (i, parser[NKey::kProperty].PostStrings)
    774    {
    775      CProperty prop;
    776      prop.Name = parser[NKey::kProperty].PostStrings[i];
    777      int index = prop.Name.Find(L'=');
    778      if (index >= 0)
    779      {
    780        prop.Value = prop.Name.Ptr(index + 1);
    781        prop.Name.DeleteFrom(index);
    782      }
    783      properties.Add(prop);
    784    }
    785  }
    786 }
    787 
    788 
    789 static inline void SetStreamMode(const CSwitchResult &sw, unsigned &res)
    790 {
    791  if (sw.ThereIs)
    792    res = sw.PostCharIndex;
    793 }
    794 
    795 
    796 void CArcCmdLineParser::Parse1(const UStringVector &commandStrings,
    797    CArcCmdLineOptions &options)
    798 {
    799  if (!parser.ParseStrings(kSwitchForms, ARRAY_SIZE(kSwitchForms), commandStrings))
    800    throw CArcCmdLineException(parser.ErrorMessage, parser.ErrorLine);
    801 
    802  options.IsInTerminal = MY_IS_TERMINAL(stdin);
    803  options.IsStdOutTerminal = MY_IS_TERMINAL(stdout);
    804  options.IsStdErrTerminal = MY_IS_TERMINAL(stderr);
    805 
    806  options.HelpMode = parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs  || parser[NKey::kHelp3].ThereIs;
    807 
    808  options.StdInMode = parser[NKey::kStdIn].ThereIs;
    809  options.StdOutMode = parser[NKey::kStdOut].ThereIs;
    810  options.EnableHeaders = !parser[NKey::kDisableHeaders].ThereIs;
    811  options.TechMode = parser[NKey::kTechMode].ThereIs;
    812  options.ShowTime = parser[NKey::kShowTime].ThereIs;
    813 
    814  if (parser[NKey::kDisablePercents].ThereIs
    815      || options.StdOutMode
    816      || !options.IsStdOutTerminal)
    817    options.Number_for_Percents = k_OutStream_disabled;
    818 
    819  if (options.StdOutMode)
    820    options.Number_for_Out = k_OutStream_disabled;
    821 
    822  SetStreamMode(parser[NKey::kOutStream], options.Number_for_Out);
    823  SetStreamMode(parser[NKey::kErrStream], options.Number_for_Errors);
    824  SetStreamMode(parser[NKey::kPercentStream], options.Number_for_Percents);
    825 
    826  if (parser[NKey::kLogLevel].ThereIs)
    827  {
    828    const UString &s = parser[NKey::kLogLevel].PostStrings[0];
    829    if (s.IsEmpty())
    830      options.LogLevel = 1;
    831    else
    832    {
    833      UInt32 v;
    834      if (!StringToUInt32(s, v))
    835        throw CArcCmdLineException("Unsupported switch postfix -bb", s);
    836      options.LogLevel = (unsigned)v;
    837    }
    838  }
    839 
    840  if (parser[NKey::kCaseSensitive].ThereIs)
    841  {
    842    g_CaseSensitive = !parser[NKey::kCaseSensitive].WithMinus;
    843    options.CaseSensitiveChange = true;
    844    options.CaseSensitive = g_CaseSensitive;
    845  }
    846 
    847 
    848  #if defined(_WIN32) && !defined(UNDER_CE)
    849  NSecurity::EnablePrivilege_SymLink();
    850  #endif
    851  
    852  // options.LargePages = false;
    853 
    854  if (parser[NKey::kLargePages].ThereIs)
    855  {
    856    unsigned slp = 0;
    857    const UString &s = parser[NKey::kLargePages].PostStrings[0];
    858    if (s.IsEmpty())
    859      slp = 1;
    860    else if (s != L"-")
    861    {
    862      if (!StringToUInt32(s, slp))
    863        throw CArcCmdLineException("Unsupported switch postfix for -slp", s);
    864    }
    865    
    866    #ifdef _7ZIP_LARGE_PAGES
    867    if (slp >
    868          #ifndef UNDER_CE
    869            (unsigned)NSecurity::Get_LargePages_RiskLevel()
    870          #else
    871            0
    872          #endif
    873        )
    874    {
    875      SetLargePageSize();
    876      // note: this process also can inherit that Privilege from parent process
    877      g_LargePagesMode =
    878      #if defined(_WIN32) && !defined(UNDER_CE)
    879        NSecurity::EnablePrivilege_LockMemory();
    880      #else
    881        true;
    882      #endif
    883    }
    884    #endif
    885  }
    886 
    887 
    888  #ifndef UNDER_CE
    889 
    890  if (parser[NKey::kAffinity].ThereIs)
    891  {
    892    const UString &s = parser[NKey::kAffinity].PostStrings[0];
    893    if (!s.IsEmpty())
    894    {
    895      UInt32 v = 0;
    896      AString a;
    897      a.SetFromWStr_if_Ascii(s);
    898      if (!a.IsEmpty())
    899      {
    900        const char *end;
    901        v = ConvertHexStringToUInt32(a, &end);
    902        if (*end != 0)
    903          a.Empty();
    904      }
    905      if (a.IsEmpty())
    906        throw CArcCmdLineException("Unsupported switch postfix -stm", s);
    907      
    908      #ifdef _WIN32
    909      SetProcessAffinityMask(GetCurrentProcess(), v);
    910      #endif
    911    }
    912  }
    913 
    914  #endif
    915 }
    916 
    917 struct CCodePagePair
    918 {
    919  const char *Name;
    920  Int32 CodePage;
    921 };
    922 
    923 static const unsigned kNumByteOnlyCodePages = 3;
    924 
    925 static const CCodePagePair g_CodePagePairs[] =
    926 {
    927  { "utf-8", CP_UTF8 },
    928  { "win", CP_ACP },
    929  { "dos", CP_OEMCP },
    930  { "utf-16le", MY__CP_UTF16 },
    931  { "utf-16be", MY__CP_UTF16BE }
    932 };
    933 
    934 static Int32 FindCharset(const NCommandLineParser::CParser &parser, unsigned keyIndex,
    935    bool byteOnlyCodePages, Int32 defaultVal)
    936 {
    937  if (!parser[keyIndex].ThereIs)
    938    return defaultVal;
    939 
    940  UString name (parser[keyIndex].PostStrings.Back());
    941  UInt32 v;
    942  if (StringToUInt32(name, v))
    943    if (v < ((UInt32)1 << 16))
    944      return (Int32)v;
    945  name.MakeLower_Ascii();
    946  unsigned num = byteOnlyCodePages ? kNumByteOnlyCodePages : ARRAY_SIZE(g_CodePagePairs);
    947  for (unsigned i = 0;; i++)
    948  {
    949    if (i == num) // to disable warnings from different compilers
    950      throw CArcCmdLineException("Unsupported charset:", name);
    951    const CCodePagePair &pair = g_CodePagePairs[i];
    952    if (name.IsEqualTo(pair.Name))
    953      return pair.CodePage;
    954  }
    955 }
    956 
    957 
    958 static void SetBoolPair(NCommandLineParser::CParser &parser, unsigned switchID, CBoolPair &bp)
    959 {
    960  bp.Def = parser[switchID].ThereIs;
    961  if (bp.Def)
    962    bp.Val = !parser[switchID].WithMinus;
    963 }
    964 
    965 void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
    966 {
    967  const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
    968  const unsigned numNonSwitchStrings = nonSwitchStrings.Size();
    969  if (numNonSwitchStrings < kMinNonSwitchWords)
    970    throw CArcCmdLineException("The command must be specified");
    971 
    972  if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], options.Command))
    973    throw CArcCmdLineException("Unsupported command:", nonSwitchStrings[kCommandIndex]);
    974 
    975  if (parser[NKey::kHash].ThereIs)
    976    options.HashMethods = parser[NKey::kHash].PostStrings;
    977  
    978  if (parser[NKey::kElimDup].ThereIs)
    979  {
    980    options.ExtractOptions.ElimDup.Def = true;
    981    options.ExtractOptions.ElimDup.Val = !parser[NKey::kElimDup].WithMinus;
    982  }
    983  
    984  NWildcard::ECensorPathMode censorPathMode = NWildcard::k_RelatPath;
    985  bool fullPathMode = parser[NKey::kFullPathMode].ThereIs;
    986  if (fullPathMode)
    987  {
    988    censorPathMode = NWildcard::k_AbsPath;
    989    const UString &s = parser[NKey::kFullPathMode].PostStrings[0];
    990    if (!s.IsEmpty())
    991    {
    992      if (s == L"2")
    993        censorPathMode = NWildcard::k_FullPath;
    994      else
    995        throw CArcCmdLineException("Unsupported -spf:", s);
    996    }
    997  }
    998 
    999  if (parser[NKey::kNameTrailReplace].ThereIs)
   1000    g_PathTrailReplaceMode = !parser[NKey::kNameTrailReplace].WithMinus;
   1001 
   1002  NRecursedType::EEnum recursedType;
   1003  if (parser[NKey::kRecursed].ThereIs)
   1004    recursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex);
   1005  else
   1006    recursedType = NRecursedType::kNonRecursed;
   1007 
   1008  bool wildcardMatching = true;
   1009  if (parser[NKey::kDisableWildcardParsing].ThereIs)
   1010    wildcardMatching = false;
   1011 
   1012  g_CodePage = FindCharset(parser, NKey::kConsoleCharSet, true, -1);
   1013  Int32 codePage = FindCharset(parser, NKey::kListfileCharSet, false, CP_UTF8);
   1014 
   1015  bool thereAreSwitchIncludes = false;
   1016  
   1017  if (parser[NKey::kInclude].ThereIs)
   1018  {
   1019    thereAreSwitchIncludes = true;
   1020    AddSwitchWildcardsToCensor(options.Censor,
   1021        parser[NKey::kInclude].PostStrings, true, recursedType, wildcardMatching, codePage);
   1022  }
   1023 
   1024  if (parser[NKey::kExclude].ThereIs)
   1025    AddSwitchWildcardsToCensor(options.Censor,
   1026        parser[NKey::kExclude].PostStrings, false, recursedType, wildcardMatching, codePage);
   1027 
   1028  unsigned curCommandIndex = kCommandIndex + 1;
   1029  bool thereIsArchiveName = !parser[NKey::kNoArName].ThereIs &&
   1030      options.Command.CommandType != NCommandType::kBenchmark &&
   1031      options.Command.CommandType != NCommandType::kInfo &&
   1032      options.Command.CommandType != NCommandType::kHash;
   1033 
   1034  bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
   1035  bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList;
   1036  bool isRename = options.Command.CommandType == NCommandType::kRename;
   1037 
   1038  if ((isExtractOrList || isRename) && options.StdInMode)
   1039    thereIsArchiveName = false;
   1040 
   1041  if (parser[NKey::kArcNameMode].ThereIs)
   1042    options.UpdateOptions.ArcNameMode = ParseArcNameMode(parser[NKey::kArcNameMode].PostCharIndex);
   1043 
   1044  if (thereIsArchiveName)
   1045  {
   1046    if (curCommandIndex >= numNonSwitchStrings)
   1047      throw CArcCmdLineException("Cannot find archive name");
   1048    options.ArchiveName = nonSwitchStrings[curCommandIndex++];
   1049    if (options.ArchiveName.IsEmpty())
   1050      throw CArcCmdLineException("Archive name cannot by empty");
   1051    #ifdef _WIN32
   1052    // options.ArchiveName.Replace(L'/', WCHAR_PATH_SEPARATOR);
   1053    #endif
   1054  }
   1055 
   1056  AddToCensorFromNonSwitchesStrings(isRename ? &options.UpdateOptions.RenamePairs : NULL,
   1057      curCommandIndex, options.Censor,
   1058      nonSwitchStrings, parser.StopSwitchIndex,
   1059      recursedType, wildcardMatching,
   1060      thereAreSwitchIncludes, codePage);
   1061 
   1062  options.YesToAll = parser[NKey::kYes].ThereIs;
   1063 
   1064 
   1065  #ifndef _NO_CRYPTO
   1066  options.PasswordEnabled = parser[NKey::kPassword].ThereIs;
   1067  if (options.PasswordEnabled)
   1068    options.Password = parser[NKey::kPassword].PostStrings[0];
   1069  #endif
   1070 
   1071  options.ShowDialog = parser[NKey::kShowDialog].ThereIs;
   1072 
   1073  if (parser[NKey::kArchiveType].ThereIs)
   1074    options.ArcType = parser[NKey::kArchiveType].PostStrings[0];
   1075 
   1076  options.ExcludedArcTypes = parser[NKey::kExcludedArcType].PostStrings;
   1077 
   1078  SetMethodOptions(parser, options.Properties);
   1079 
   1080  if (parser[NKey::kNtSecurity].ThereIs) options.NtSecurity.SetTrueTrue();
   1081 
   1082  SetBoolPair(parser, NKey::kAltStreams, options.AltStreams);
   1083  SetBoolPair(parser, NKey::kHardLinks, options.HardLinks);
   1084  SetBoolPair(parser, NKey::kSymLinks, options.SymLinks);
   1085 
   1086  if (isExtractOrList)
   1087  {
   1088    CExtractOptionsBase &eo = options.ExtractOptions;
   1089 
   1090    {
   1091      CExtractNtOptions &nt = eo.NtOptions;
   1092      nt.NtSecurity = options.NtSecurity;
   1093 
   1094      nt.AltStreams = options.AltStreams;
   1095      if (!options.AltStreams.Def)
   1096        nt.AltStreams.Val = true;
   1097 
   1098      nt.HardLinks = options.HardLinks;
   1099      if (!options.HardLinks.Def)
   1100        nt.HardLinks.Val = true;
   1101 
   1102      nt.SymLinks = options.SymLinks;
   1103      if (!options.SymLinks.Def)
   1104        nt.SymLinks.Val = true;
   1105 
   1106      nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs;
   1107      nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs;
   1108    }
   1109      
   1110    options.Censor.AddPathsToCensor(NWildcard::k_AbsPath);
   1111    options.Censor.ExtendExclude();
   1112 
   1113    // are there paths that look as non-relative (!Prefix.IsEmpty())
   1114    if (!options.Censor.AllAreRelative())
   1115      throw CArcCmdLineException("Cannot use absolute pathnames for this command");
   1116 
   1117    NWildcard::CCensor &arcCensor = options.arcCensor;
   1118 
   1119    if (parser[NKey::kArInclude].ThereIs)
   1120      AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArInclude].PostStrings, true, NRecursedType::kNonRecursed, wildcardMatching, codePage);
   1121    if (parser[NKey::kArExclude].ThereIs)
   1122      AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArExclude].PostStrings, false, NRecursedType::kNonRecursed, wildcardMatching, codePage);
   1123 
   1124    if (thereIsArchiveName)
   1125      AddNameToCensor(arcCensor, options.ArchiveName, true, NRecursedType::kNonRecursed, wildcardMatching);
   1126 
   1127    arcCensor.AddPathsToCensor(NWildcard::k_RelatPath);
   1128 
   1129    #ifdef _WIN32
   1130    ConvertToLongNames(arcCensor);
   1131    #endif
   1132 
   1133    arcCensor.ExtendExclude();
   1134 
   1135    if (options.StdInMode)
   1136      options.ArcName_for_StdInMode = parser[NKey::kStdIn].PostStrings.Front();
   1137    
   1138    if (isExtractGroupCommand)
   1139    {
   1140      if (options.StdOutMode)
   1141      {
   1142        if (
   1143                  options.Number_for_Percents == k_OutStream_stdout
   1144            // || options.Number_for_Out      == k_OutStream_stdout
   1145            // || options.Number_for_Errors   == k_OutStream_stdout
   1146            ||
   1147            (
   1148              (options.IsStdOutTerminal && options.IsStdErrTerminal)
   1149              &&
   1150              (
   1151                      options.Number_for_Percents != k_OutStream_disabled
   1152                // || options.Number_for_Out      != k_OutStream_disabled
   1153                // || options.Number_for_Errors   != k_OutStream_disabled
   1154              )
   1155            )
   1156           )
   1157          throw CArcCmdLineException(kSameTerminalError);
   1158      }
   1159      
   1160      if (parser[NKey::kOutputDir].ThereIs)
   1161      {
   1162        eo.OutputDir = us2fs(parser[NKey::kOutputDir].PostStrings[0]);
   1163        NFile::NName::NormalizeDirPathPrefix(eo.OutputDir);
   1164      }
   1165 
   1166      eo.OverwriteMode = NExtract::NOverwriteMode::kAsk;
   1167      if (parser[NKey::kOverwrite].ThereIs)
   1168      {
   1169        eo.OverwriteMode = k_OverwriteModes[(unsigned)parser[NKey::kOverwrite].PostCharIndex];
   1170        eo.OverwriteMode_Force = true;
   1171      }
   1172      else if (options.YesToAll)
   1173      {
   1174        eo.OverwriteMode = NExtract::NOverwriteMode::kOverwrite;
   1175        eo.OverwriteMode_Force = true;
   1176      }
   1177    }
   1178 
   1179    eo.PathMode = options.Command.GetPathMode();
   1180    if (censorPathMode == NWildcard::k_AbsPath)
   1181    {
   1182      eo.PathMode = NExtract::NPathMode::kAbsPaths;
   1183      eo.PathMode_Force = true;
   1184    }
   1185    else if (censorPathMode == NWildcard::k_FullPath)
   1186    {
   1187      eo.PathMode = NExtract::NPathMode::kFullPaths;
   1188      eo.PathMode_Force = true;
   1189    }
   1190  }
   1191  else if (options.Command.IsFromUpdateGroup())
   1192  {
   1193    if (parser[NKey::kArInclude].ThereIs)
   1194      throw CArcCmdLineException("-ai switch is not supported for this command");
   1195 
   1196    CUpdateOptions &updateOptions = options.UpdateOptions;
   1197 
   1198    SetAddCommandOptions(options.Command.CommandType, parser, updateOptions);
   1199    
   1200    updateOptions.MethodMode.Properties = options.Properties;
   1201 
   1202    if (parser[NKey::kShareForWrite].ThereIs)
   1203      updateOptions.OpenShareForWrite = true;
   1204    if (parser[NKey::kStopAfterOpenError].ThereIs)
   1205      updateOptions.StopAfterOpenError = true;
   1206 
   1207    updateOptions.PathMode = censorPathMode;
   1208 
   1209    updateOptions.AltStreams = options.AltStreams;
   1210    updateOptions.NtSecurity = options.NtSecurity;
   1211    updateOptions.HardLinks = options.HardLinks;
   1212    updateOptions.SymLinks = options.SymLinks;
   1213 
   1214    updateOptions.EMailMode = parser[NKey::kEmail].ThereIs;
   1215    if (updateOptions.EMailMode)
   1216    {
   1217      updateOptions.EMailAddress = parser[NKey::kEmail].PostStrings.Front();
   1218      if (updateOptions.EMailAddress.Len() > 0)
   1219        if (updateOptions.EMailAddress[0] == L'.')
   1220        {
   1221          updateOptions.EMailRemoveAfter = true;
   1222          updateOptions.EMailAddress.Delete(0);
   1223        }
   1224    }
   1225 
   1226    updateOptions.StdOutMode = options.StdOutMode;
   1227    updateOptions.StdInMode = options.StdInMode;
   1228 
   1229    updateOptions.DeleteAfterCompressing = parser[NKey::kDeleteAfterCompressing].ThereIs;
   1230    updateOptions.SetArcMTime = parser[NKey::kSetArcMTime].ThereIs;
   1231 
   1232    if (updateOptions.StdOutMode && updateOptions.EMailMode)
   1233      throw CArcCmdLineException("stdout mode and email mode cannot be combined");
   1234    
   1235    if (updateOptions.StdOutMode)
   1236    {
   1237      if (options.IsStdOutTerminal)
   1238        throw CArcCmdLineException(kTerminalOutError);
   1239      
   1240      if (options.Number_for_Percents == k_OutStream_stdout
   1241          || options.Number_for_Out == k_OutStream_stdout
   1242          || options.Number_for_Errors == k_OutStream_stdout)
   1243        throw CArcCmdLineException(kSameTerminalError);
   1244    }
   1245    
   1246    if (updateOptions.StdInMode)
   1247      updateOptions.StdInFileName = parser[NKey::kStdIn].PostStrings.Front();
   1248 
   1249    if (options.Command.CommandType == NCommandType::kRename)
   1250      if (updateOptions.Commands.Size() != 1)
   1251        throw CArcCmdLineException("Only one archive can be created with rename command");
   1252  }
   1253  else if (options.Command.CommandType == NCommandType::kBenchmark)
   1254  {
   1255    options.NumIterations = 1;
   1256    if (curCommandIndex < numNonSwitchStrings)
   1257    {
   1258      if (!StringToUInt32(nonSwitchStrings[curCommandIndex], options.NumIterations))
   1259        throw CArcCmdLineException("Incorrect Number of benmchmark iterations", nonSwitchStrings[curCommandIndex]);
   1260      curCommandIndex++;
   1261    }
   1262  }
   1263  else if (options.Command.CommandType == NCommandType::kHash)
   1264  {
   1265    options.Censor.AddPathsToCensor(censorPathMode);
   1266    options.Censor.ExtendExclude();
   1267 
   1268    CHashOptions &hashOptions = options.HashOptions;
   1269    hashOptions.PathMode = censorPathMode;
   1270    hashOptions.Methods = options.HashMethods;
   1271    if (parser[NKey::kShareForWrite].ThereIs)
   1272      hashOptions.OpenShareForWrite = true;
   1273    hashOptions.StdInMode = options.StdInMode;
   1274    hashOptions.AltStreamsMode = options.AltStreams.Val;
   1275  }
   1276  else if (options.Command.CommandType == NCommandType::kInfo)
   1277  {
   1278  }
   1279  else
   1280    throw 20150919;
   1281 }