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/IntToString.h"
23 #include "../../../Common/ListFileUtils.h"
24 #include "../../../Common/StringConvert.h"
25 #include "../../../Common/StringToInt.h"
26 
27 #include "../../../Windows/ErrorMsg.h"
28 #include "../../../Windows/FileDir.h"
29 #include "../../../Windows/FileName.h"
30 #include "../../../Windows/System.h"
31 #ifdef _WIN32
32 #include "../../../Windows/FileMapping.h"
33 #include "../../../Windows/MemoryLock.h"
34 #include "../../../Windows/Synchronization.h"
35 #endif
36 
37 #include "ArchiveCommandLine.h"
38 #include "EnumDirItems.h"
39 #include "Update.h"
40 #include "UpdateAction.h"
41 
42 extern bool g_CaseSensitive;
43 extern bool g_PathTrailReplaceMode;
44 
45 #ifdef _7ZIP_LARGE_PAGES
46 extern
47 bool g_LargePagesMode;
48 bool g_LargePagesMode = false;
49 #endif
50 
51 /*
52 #ifdef ENV_HAVE_LSTAT
53 EXTERN_C_BEGIN
54 extern int global_use_lstat;
55 EXTERN_C_END
56 #endif
57 */
58 
59 #ifdef UNDER_CE
60 
61 #define MY_IS_TERMINAL(x) false;
62 
63 #else
64 
65 // #define MY_isatty_fileno(x) (isatty(fileno(x)))
66 // #define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 0);
MY_IS_TERMINAL(FILE * x)67 static inline bool MY_IS_TERMINAL(FILE *x)
68 {
69   return (
70     #if defined(_MSC_VER) && (_MSC_VER >= 1400)
71       _isatty(_fileno(x))
72     #else
73       isatty(fileno(x))
74     #endif
75       != 0);
76 }
77 
78 #endif
79 
80 using namespace NCommandLineParser;
81 using namespace NWindows;
82 using namespace NFile;
83 
StringToUInt32(const wchar_t * s,UInt32 & v)84 static bool StringToUInt32(const wchar_t *s, UInt32 &v)
85 {
86   if (*s == 0)
87     return false;
88   const wchar_t *end;
89   v = ConvertStringToUInt32(s, &end);
90   return *end == 0;
91 }
92 
93 
94 namespace NKey {
95 enum Enum
96 {
97   kHelp1 = 0,
98   kHelp2,
99   kHelp3,
100 
101   kDisableHeaders,
102   kDisablePercents,
103   kShowTime,
104   kLogLevel,
105 
106   kOutStream,
107   kErrStream,
108   kPercentStream,
109 
110   kYes,
111 
112   kShowDialog,
113   kOverwrite,
114 
115   kArchiveType,
116   kExcludedArcType,
117 
118   kProperty,
119   kOutputDir,
120   kWorkingDir,
121 
122   kInclude,
123   kExclude,
124   kArInclude,
125   kArExclude,
126   kNoArName,
127 
128   kUpdate,
129   kVolume,
130   kRecursed,
131 
132   kAffinity,
133   kSfx,
134   kEmail,
135   kHash,
136   // kHashGenFile,
137   kHashDir,
138 
139   kStdIn,
140   kStdOut,
141 
142   kLargePages,
143   kListfileCharSet,
144   kConsoleCharSet,
145   kTechMode,
146   kListFields,
147 
148   kPreserveATime,
149   kShareForWrite,
150   kStopAfterOpenError,
151   kCaseSensitive,
152   kArcNameMode,
153 
154   kUseSlashMark,
155   kDisableWildcardParsing,
156   kElimDup,
157   kFullPathMode,
158 
159   kHardLinks,
160   kSymLinks_AllowDangerous,
161   kSymLinks,
162   kNtSecurity,
163 
164   kAltStreams,
165   kReplaceColonForAltStream,
166   kWriteToAltStreamIfColon,
167 
168   kNameTrailReplace,
169 
170   kDeleteAfterCompressing,
171   kSetArcMTime
172 
173   #ifndef _NO_CRYPTO
174   , kPassword
175   #endif
176 };
177 
178 }
179 
180 
181 static const wchar_t kRecursedIDChar = 'r';
182 static const char * const kRecursedPostCharSet = "0-";
183 
184 static const char * const k_ArcNameMode_PostCharSet = "sea";
185 
186 static const char * const k_Stream_PostCharSet = "012";
187 
ParseArcNameMode(int postCharIndex)188 static inline EArcNameMode ParseArcNameMode(int postCharIndex)
189 {
190   switch (postCharIndex)
191   {
192     case 1: return k_ArcNameMode_Exact;
193     case 2: return k_ArcNameMode_Add;
194     default: return k_ArcNameMode_Smart;
195   }
196 }
197 
198 namespace NRecursedPostCharIndex {
199   enum EEnum
200   {
201     kWildcardRecursionOnly = 0,
202     kNoRecursion = 1
203   };
204 }
205 
206 // static const char
207 #define kImmediateNameID '!'
208 #ifdef _WIN32
209 #define kMapNameID '#'
210 #endif
211 #define kFileListID '@'
212 
213 static const Byte kSomeCludePostStringMinSize = 2; // at least <@|!><N>ame must be
214 static const Byte kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>ame must be
215 
216 static const char * const kOverwritePostCharSet = "asut";
217 
218 static const NExtract::NOverwriteMode::EEnum k_OverwriteModes[] =
219 {
220   NExtract::NOverwriteMode::kOverwrite,
221   NExtract::NOverwriteMode::kSkip,
222   NExtract::NOverwriteMode::kRename,
223   NExtract::NOverwriteMode::kRenameExisting
224 };
225 
226 
227 
228 #define SWFRM_3(t, mu, mi) t, mu, mi, NULL
229 
230 #define SWFRM_1(t) SWFRM_3(t, false, 0)
231 #define SWFRM_SIMPLE SWFRM_1(NSwitchType::kSimple)
232 #define SWFRM_MINUS  SWFRM_1(NSwitchType::kMinus)
233 #define SWFRM_STRING SWFRM_1(NSwitchType::kString)
234 
235 #define SWFRM_STRING_SINGL(mi) SWFRM_3(NSwitchType::kString, false, mi)
236 #define SWFRM_STRING_MULT(mi)  SWFRM_3(NSwitchType::kString, true, mi)
237 
238 
239 static const CSwitchForm kSwitchForms[] =
240 {
241   { "?", SWFRM_SIMPLE },
242   { "h", SWFRM_SIMPLE },
243   { "-help", SWFRM_SIMPLE },
244 
245   { "ba", SWFRM_SIMPLE },
246   { "bd", SWFRM_SIMPLE },
247   { "bt", SWFRM_SIMPLE },
248   { "bb", SWFRM_STRING_SINGL(0) },
249 
250   { "bso", NSwitchType::kChar, false, 1, k_Stream_PostCharSet },
251   { "bse", NSwitchType::kChar, false, 1, k_Stream_PostCharSet },
252   { "bsp", NSwitchType::kChar, false, 1, k_Stream_PostCharSet },
253 
254   { "y", SWFRM_SIMPLE },
255 
256   { "ad", SWFRM_SIMPLE },
257   { "ao", NSwitchType::kChar, false, 1, kOverwritePostCharSet},
258 
259   { "t",  SWFRM_STRING_SINGL(1) },
260   { "stx", SWFRM_STRING_MULT(1) },
261 
262   { "m",  SWFRM_STRING_MULT(1) },
263   { "o",  SWFRM_STRING_SINGL(1) },
264   { "w",  SWFRM_STRING },
265 
266   { "i",  SWFRM_STRING_MULT(kSomeCludePostStringMinSize) },
267   { "x",  SWFRM_STRING_MULT(kSomeCludePostStringMinSize) },
268   { "ai", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) },
269   { "ax", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) },
270   { "an", SWFRM_SIMPLE },
271 
272   { "u",  SWFRM_STRING_MULT(1) },
273   { "v",  SWFRM_STRING_MULT(1) },
274   { "r",  NSwitchType::kChar, false, 0, kRecursedPostCharSet },
275 
276   { "stm", SWFRM_STRING },
277   { "sfx", SWFRM_STRING },
278   { "seml", SWFRM_STRING_SINGL(0) },
279   { "scrc", SWFRM_STRING_MULT(0) },
280   // { "scrf", SWFRM_STRING_SINGL(1) },
281   { "shd", SWFRM_STRING_SINGL(1) },
282 
283   { "si", SWFRM_STRING },
284   { "so", SWFRM_SIMPLE },
285 
286   { "slp", SWFRM_STRING },
287   { "scs", SWFRM_STRING },
288   { "scc", SWFRM_STRING },
289   { "slt", SWFRM_SIMPLE },
290   { "slf", SWFRM_STRING_SINGL(1) },
291 
292   { "ssp", SWFRM_SIMPLE },
293   { "ssw", SWFRM_SIMPLE },
294   { "sse", SWFRM_SIMPLE },
295   { "ssc", SWFRM_MINUS },
296   { "sa",  NSwitchType::kChar, false, 1, k_ArcNameMode_PostCharSet },
297 
298   { "spm", SWFRM_STRING_SINGL(0) },
299   { "spd", SWFRM_SIMPLE },
300   { "spe", SWFRM_MINUS },
301   { "spf", SWFRM_STRING_SINGL(0) },
302 
303   { "snh", SWFRM_MINUS },
304   { "snld", SWFRM_MINUS },
305   { "snl", SWFRM_MINUS },
306   { "sni", SWFRM_SIMPLE },
307 
308   { "sns", SWFRM_MINUS },
309   { "snr", SWFRM_SIMPLE },
310   { "snc", SWFRM_SIMPLE },
311 
312   { "snt", SWFRM_MINUS },
313 
314   { "sdel", SWFRM_SIMPLE },
315   { "stl", SWFRM_SIMPLE }
316 
317   #ifndef _NO_CRYPTO
318   , { "p", SWFRM_STRING }
319   #endif
320 };
321 
322 static const char * const kUniversalWildcard = "*";
323 static const unsigned kMinNonSwitchWords = 1;
324 static const unsigned kCommandIndex = 0;
325 
326 // static const char * const kUserErrorMessage  = "Incorrect command line";
327 // static const char * const kCannotFindListFile = "Cannot find listfile";
328 static const char * const kIncorrectListFile = "Incorrect item in listfile.\nCheck charset encoding and -scs switch.";
329 static const char * const kTerminalOutError = "I won't write compressed data to a terminal";
330 static const char * const kSameTerminalError = "I won't write data and program's messages to same stream";
331 static const char * const kEmptyFilePath = "Empty file path";
332 
IsFromExtractGroup() const333 bool CArcCommand::IsFromExtractGroup() const
334 {
335   switch (CommandType)
336   {
337     case NCommandType::kTest:
338     case NCommandType::kExtract:
339     case NCommandType::kExtractFull:
340       return true;
341     default:
342       return false;
343   }
344 }
345 
GetPathMode() const346 NExtract::NPathMode::EEnum CArcCommand::GetPathMode() const
347 {
348   switch (CommandType)
349   {
350     case NCommandType::kTest:
351     case NCommandType::kExtractFull:
352       return NExtract::NPathMode::kFullPaths;
353     default:
354       return NExtract::NPathMode::kNoPaths;
355   }
356 }
357 
IsFromUpdateGroup() const358 bool CArcCommand::IsFromUpdateGroup() const
359 {
360   switch (CommandType)
361   {
362     case NCommandType::kAdd:
363     case NCommandType::kUpdate:
364     case NCommandType::kDelete:
365     case NCommandType::kRename:
366       return true;
367     default:
368       return false;
369   }
370 }
371 
GetRecursedTypeFromIndex(int index)372 static NRecursedType::EEnum GetRecursedTypeFromIndex(int index)
373 {
374   switch (index)
375   {
376     case NRecursedPostCharIndex::kWildcardRecursionOnly:
377       return NRecursedType::kWildcardOnlyRecursed;
378     case NRecursedPostCharIndex::kNoRecursion:
379       return NRecursedType::kNonRecursed;
380     default:
381       return NRecursedType::kRecursed;
382   }
383 }
384 
385 static const char *g_Commands = "audtexlbih";
386 
ParseArchiveCommand(const UString & commandString,CArcCommand & command)387 static bool ParseArchiveCommand(const UString &commandString, CArcCommand &command)
388 {
389   UString s (commandString);
390   s.MakeLower_Ascii();
391   if (s.Len() == 1)
392   {
393     if (s[0] > 0x7F)
394       return false;
395     int index = FindCharPosInString(g_Commands, (char)s[0]);
396     if (index < 0)
397       return false;
398     command.CommandType = (NCommandType::EEnum)index;
399     return true;
400   }
401   if (s.Len() == 2 && s[0] == 'r' && s[1] == 'n')
402   {
403     command.CommandType = (NCommandType::kRename);
404     return true;
405   }
406   return false;
407 }
408 
409 // ------------------------------------------------------------------
410 // filenames functions
411 
412 struct CNameOption
413 {
414   bool Include;
415   bool WildcardMatching;
416   Byte MarkMode;
417   NRecursedType::EEnum RecursedType;
418 
CNameOptionCNameOption419   CNameOption():
420       Include(true),
421       WildcardMatching(true),
422       MarkMode(NWildcard::kMark_FileOrDir),
423       RecursedType(NRecursedType::kNonRecursed)
424       {}
425 };
426 
427 
AddNameToCensor(NWildcard::CCensor & censor,const CNameOption & nop,const UString & name)428 static void AddNameToCensor(NWildcard::CCensor &censor,
429     const CNameOption &nop, const UString &name)
430 {
431   bool recursed = false;
432 
433   switch (nop.RecursedType)
434   {
435     case NRecursedType::kWildcardOnlyRecursed:
436       recursed = DoesNameContainWildcard(name);
437       break;
438     case NRecursedType::kRecursed:
439       recursed = true;
440       break;
441     default:
442       break;
443   }
444 
445   NWildcard::CCensorPathProps props;
446   props.Recursive = recursed;
447   props.WildcardMatching = nop.WildcardMatching;
448   props.MarkMode = nop.MarkMode;
449   censor.AddPreItem(nop.Include, name, props);
450 }
451 
AddRenamePair(CObjectVector<CRenamePair> * renamePairs,const UString & oldName,const UString & newName,NRecursedType::EEnum type,bool wildcardMatching)452 static void AddRenamePair(CObjectVector<CRenamePair> *renamePairs,
453     const UString &oldName, const UString &newName, NRecursedType::EEnum type,
454     bool wildcardMatching)
455 {
456   CRenamePair &pair = renamePairs->AddNew();
457   pair.OldName = oldName;
458   pair.NewName = newName;
459   pair.RecursedType = type;
460   pair.WildcardParsing = wildcardMatching;
461 
462   if (!pair.Prepare())
463   {
464     UString val;
465     val += pair.OldName;
466     val.Add_LF();
467     val += pair.NewName;
468     val.Add_LF();
469     if (type == NRecursedType::kRecursed)
470       val += "-r";
471     else if (type == NRecursedType::kWildcardOnlyRecursed)
472       val += "-r0";
473     throw CArcCmdLineException("Unsupported rename command:", val);
474   }
475 }
476 
AddToCensorFromListFile(CObjectVector<CRenamePair> * renamePairs,NWildcard::CCensor & censor,const CNameOption & nop,LPCWSTR fileName,UInt32 codePage)477 static void AddToCensorFromListFile(
478     CObjectVector<CRenamePair> *renamePairs,
479     NWildcard::CCensor &censor,
480     const CNameOption &nop, LPCWSTR fileName, UInt32 codePage)
481 {
482   UStringVector names;
483   /*
484   if (!NFind::DoesFileExist_FollowLink(us2fs(fileName)))
485     throw CArcCmdLineException(kCannotFindListFile, fileName);
486   */
487   DWORD lastError = 0;
488   if (!ReadNamesFromListFile2(us2fs(fileName), names, codePage, lastError))
489   {
490     if (lastError != 0)
491     {
492       UString m;
493       m = "The file operation error for listfile";
494       m.Add_LF();
495       m += NError::MyFormatMessage(lastError);
496       throw CArcCmdLineException(m, fileName);
497     }
498     throw CArcCmdLineException(kIncorrectListFile, fileName);
499   }
500   if (renamePairs)
501   {
502     if ((names.Size() & 1) != 0)
503       throw CArcCmdLineException(kIncorrectListFile, fileName);
504     for (unsigned i = 0; i < names.Size(); i += 2)
505     {
506       // change type !!!!
507       AddRenamePair(renamePairs, names[i], names[i + 1], nop.RecursedType, nop.WildcardMatching);
508     }
509   }
510   else
511     FOR_VECTOR (i, names)
512       AddNameToCensor(censor, nop, names[i]);
513 }
514 
AddToCensorFromNonSwitchesStrings(CObjectVector<CRenamePair> * renamePairs,unsigned startIndex,NWildcard::CCensor & censor,const UStringVector & nonSwitchStrings,int stopSwitchIndex,const CNameOption & nop,bool thereAreSwitchIncludes,UInt32 codePage)515 static void AddToCensorFromNonSwitchesStrings(
516     CObjectVector<CRenamePair> *renamePairs,
517     unsigned startIndex,
518     NWildcard::CCensor &censor,
519     const UStringVector &nonSwitchStrings,
520     int stopSwitchIndex,
521     const CNameOption &nop,
522     bool thereAreSwitchIncludes, UInt32 codePage)
523 {
524   // another default
525   if ((renamePairs || nonSwitchStrings.Size() == startIndex) && !thereAreSwitchIncludes)
526   {
527     /* for rename command: -i switch sets the mask for archive item reading.
528        if (thereAreSwitchIncludes), { we don't use UniversalWildcard. }
529        also for non-rename command: we set UniversalWildcard, only if there are no nonSwitches. */
530     // we use default fileds in (CNameOption) for UniversalWildcard.
531     CNameOption nop2;
532     // recursive mode is not important for UniversalWildcard (*)
533     // nop2.RecursedType = nop.RecursedType; // we don't need it
534     /*
535     nop2.RecursedType = NRecursedType::kNonRecursed;
536     nop2.Include = true;
537     nop2.WildcardMatching = true;
538     nop2.MarkMode = NWildcard::kMark_FileOrDir;
539     */
540     AddNameToCensor(censor, nop2, UString(kUniversalWildcard));
541   }
542 
543   int oldIndex = -1;
544 
545   if (stopSwitchIndex < 0)
546     stopSwitchIndex = (int)nonSwitchStrings.Size();
547 
548   for (unsigned i = startIndex; i < nonSwitchStrings.Size(); i++)
549   {
550     const UString &s = nonSwitchStrings[i];
551     if (s.IsEmpty())
552       throw CArcCmdLineException(kEmptyFilePath);
553     if (i < (unsigned)stopSwitchIndex && s[0] == kFileListID)
554       AddToCensorFromListFile(renamePairs, censor, nop, s.Ptr(1), codePage);
555     else if (renamePairs)
556     {
557       if (oldIndex == -1)
558         oldIndex = (int)i;
559       else
560       {
561         // NRecursedType::EEnum type is used for global wildcard (-i! switches)
562         AddRenamePair(renamePairs, nonSwitchStrings[(unsigned)oldIndex], s, NRecursedType::kNonRecursed, nop.WildcardMatching);
563         // AddRenamePair(renamePairs, nonSwitchStrings[oldIndex], s, type);
564         oldIndex = -1;
565       }
566     }
567     else
568       AddNameToCensor(censor, nop, s);
569   }
570 
571   if (oldIndex != -1)
572   {
573     throw CArcCmdLineException("There is no second file name for rename pair:", nonSwitchStrings[(unsigned)oldIndex]);
574   }
575 }
576 
577 #ifdef _WIN32
578 
579 struct CEventSetEnd
580 {
581   UString Name;
582 
CEventSetEndCEventSetEnd583   CEventSetEnd(const wchar_t *name): Name(name) {}
~CEventSetEndCEventSetEnd584   ~CEventSetEnd()
585   {
586     NSynchronization::CManualResetEvent event;
587     if (event.Open(EVENT_MODIFY_STATE, false, GetSystemString(Name)) == 0)
588       event.Set();
589   }
590 };
591 
592 static const char * const k_IncorrectMapCommand = "Incorrect Map command";
593 
ParseMapWithPaths(NWildcard::CCensor & censor,const UString & s2,const CNameOption & nop)594 static const char *ParseMapWithPaths(
595     NWildcard::CCensor &censor,
596     const UString &s2,
597     const CNameOption &nop)
598 {
599   UString s (s2);
600   int pos = s.Find(L':');
601   if (pos < 0)
602     return k_IncorrectMapCommand;
603   int pos2 = s.Find(L':', (unsigned)(pos + 1));
604   if (pos2 < 0)
605     return k_IncorrectMapCommand;
606 
607   CEventSetEnd eventSetEnd((const wchar_t *)s + (unsigned)(pos2 + 1));
608   s.DeleteFrom((unsigned)pos2);
609   UInt32 size;
610   if (!StringToUInt32(s.Ptr((unsigned)(pos + 1)), size)
611       || size < sizeof(wchar_t)
612       || size > ((UInt32)1 << 31)
613       || size % sizeof(wchar_t) != 0)
614     return "Unsupported Map data size";
615 
616   s.DeleteFrom((unsigned)pos);
617   CFileMapping map;
618   if (map.Open(FILE_MAP_READ, GetSystemString(s)) != 0)
619     return "Cannot open mapping";
620   LPVOID data = map.Map(FILE_MAP_READ, 0, size);
621   if (!data)
622     return "MapViewOfFile error";
623   CFileUnmapper unmapper(data);
624 
625   UString name;
626   const wchar_t *p = (const wchar_t *)data;
627   if (*p != 0) // data format marker
628     return "Unsupported Map data";
629   UInt32 numChars = size / sizeof(wchar_t);
630   for (UInt32 i = 1; i < numChars; i++)
631   {
632     wchar_t c = p[i];
633     if (c == 0)
634     {
635       // MessageBoxW(0, name, L"7-Zip", 0);
636       AddNameToCensor(censor, nop, name);
637       name.Empty();
638     }
639     else
640       name += c;
641   }
642   if (!name.IsEmpty())
643     return "Map data error";
644 
645   return NULL;
646 }
647 
648 #endif
649 
AddSwitchWildcardsToCensor(NWildcard::CCensor & censor,const UStringVector & strings,const CNameOption & nop,UInt32 codePage)650 static void AddSwitchWildcardsToCensor(
651     NWildcard::CCensor &censor,
652     const UStringVector &strings,
653     const CNameOption &nop,
654     UInt32 codePage)
655 {
656   const char *errorMessage = NULL;
657   unsigned i;
658   for (i = 0; i < strings.Size(); i++)
659   {
660     const UString &name = strings[i];
661     unsigned pos = 0;
662 
663     if (name.Len() < kSomeCludePostStringMinSize)
664     {
665       errorMessage = "Too short switch";
666       break;
667     }
668 
669     if (!nop.Include)
670     {
671       if (name.IsEqualTo_Ascii_NoCase("td"))
672       {
673         censor.ExcludeDirItems = true;
674         continue;
675       }
676       if (name.IsEqualTo_Ascii_NoCase("tf"))
677       {
678         censor.ExcludeFileItems = true;
679         continue;
680       }
681     }
682 
683     CNameOption nop2 = nop;
684 
685     bool type_WasUsed = false;
686     bool recursed_WasUsed = false;
687     bool matching_WasUsed = false;
688     bool error = false;
689 
690     for (;;)
691     {
692       wchar_t c = ::MyCharLower_Ascii(name[pos]);
693       if (c == kRecursedIDChar)
694       {
695         if (recursed_WasUsed)
696         {
697           error = true;
698           break;
699         }
700         recursed_WasUsed = true;
701         pos++;
702         c = name[pos];
703         int index = -1;
704         if (c <= 0x7F)
705           index = FindCharPosInString(kRecursedPostCharSet, (char)c);
706         nop2.RecursedType = GetRecursedTypeFromIndex(index);
707         if (index >= 0)
708         {
709           pos++;
710           continue;
711         }
712       }
713 
714       if (c == 'w')
715       {
716         if (matching_WasUsed)
717         {
718           error = true;
719           break;
720         }
721         matching_WasUsed = true;
722         nop2.WildcardMatching = true;
723         pos++;
724         if (name[pos] == '-')
725         {
726           nop2.WildcardMatching = false;
727           pos++;
728         }
729       }
730       else if (c == 'm')
731       {
732         if (type_WasUsed)
733         {
734           error = true;
735           break;
736         }
737         type_WasUsed = true;
738         pos++;
739         nop2.MarkMode = NWildcard::kMark_StrictFile;
740         c = name[pos];
741         if (c == '-')
742         {
743           nop2.MarkMode = NWildcard::kMark_FileOrDir;
744           pos++;
745         }
746         else if (c == '2')
747         {
748           nop2.MarkMode = NWildcard::kMark_StrictFile_IfWildcard;
749           pos++;
750         }
751       }
752       else
753         break;
754     }
755 
756     if (error)
757     {
758       errorMessage = "inorrect switch";
759       break;
760     }
761 
762     if (name.Len() < pos + kSomeCludeAfterRecursedPostStringMinSize)
763     {
764       errorMessage = "Too short switch";
765       break;
766     }
767 
768     const UString tail = name.Ptr(pos + 1);
769 
770     const wchar_t c = name[pos];
771 
772     if (c == kImmediateNameID)
773       AddNameToCensor(censor, nop2, tail);
774     else if (c == kFileListID)
775       AddToCensorFromListFile(NULL, censor, nop2, tail, codePage);
776     #ifdef _WIN32
777     else if (c == kMapNameID)
778     {
779       errorMessage = ParseMapWithPaths(censor, tail, nop2);
780       if (errorMessage)
781         break;
782     }
783     #endif
784     else
785     {
786       errorMessage = "Incorrect wildcard type marker";
787       break;
788     }
789   }
790 
791   if (i != strings.Size())
792     throw CArcCmdLineException(errorMessage, strings[i]);
793 }
794 
795 /*
796 static NUpdateArchive::NPairAction::EEnum GetUpdatePairActionType(int i)
797 {
798   switch (i)
799   {
800     case NUpdateArchive::NPairAction::kIgnore: return NUpdateArchive::NPairAction::kIgnore;
801     case NUpdateArchive::NPairAction::kCopy: return NUpdateArchive::NPairAction::kCopy;
802     case NUpdateArchive::NPairAction::kCompress: return NUpdateArchive::NPairAction::kCompress;
803     case NUpdateArchive::NPairAction::kCompressAsAnti: return NUpdateArchive::NPairAction::kCompressAsAnti;
804   }
805   throw 98111603;
806 }
807 */
808 
809 static const char * const kUpdatePairStateIDSet = "pqrxyzw";
810 static const int kUpdatePairStateNotSupportedActions[] = {2, 2, 1, -1, -1, -1, -1};
811 
812 static const unsigned kNumUpdatePairActions = 4;
813 static const char * const kUpdateIgnoreItselfPostStringID = "-";
814 static const wchar_t kUpdateNewArchivePostCharID = '!';
815 
816 
ParseUpdateCommandString2(const UString & command,NUpdateArchive::CActionSet & actionSet,UString & postString)817 static bool ParseUpdateCommandString2(const UString &command,
818     NUpdateArchive::CActionSet &actionSet, UString &postString)
819 {
820   for (unsigned i = 0; i < command.Len();)
821   {
822     wchar_t c = MyCharLower_Ascii(command[i]);
823     int statePos = FindCharPosInString(kUpdatePairStateIDSet, (char)c);
824     if (c > 0x7F || statePos < 0)
825     {
826       postString = command.Ptr(i);
827       return true;
828     }
829     i++;
830     if (i >= command.Len())
831       return false;
832     c = command[i];
833     if (c < '0' || c >= (wchar_t)('0' + kNumUpdatePairActions))
834       return false;
835     unsigned actionPos = (unsigned)(c - '0');
836     actionSet.StateActions[(unsigned)statePos] = (NUpdateArchive::NPairAction::EEnum)(actionPos);
837     if (kUpdatePairStateNotSupportedActions[(unsigned)statePos] == (int)actionPos)
838       return false;
839     i++;
840   }
841   postString.Empty();
842   return true;
843 }
844 
ParseUpdateCommandString(CUpdateOptions & options,const UStringVector & updatePostStrings,const NUpdateArchive::CActionSet & defaultActionSet)845 static void ParseUpdateCommandString(CUpdateOptions &options,
846     const UStringVector &updatePostStrings,
847     const NUpdateArchive::CActionSet &defaultActionSet)
848 {
849   const char *errorMessage = "incorrect update switch command";
850   unsigned i;
851   for (i = 0; i < updatePostStrings.Size(); i++)
852   {
853     const UString &updateString = updatePostStrings[i];
854     if (updateString.IsEqualTo(kUpdateIgnoreItselfPostStringID))
855     {
856       if (options.UpdateArchiveItself)
857       {
858         options.UpdateArchiveItself = false;
859         options.Commands.Delete(0);
860       }
861     }
862     else
863     {
864       NUpdateArchive::CActionSet actionSet = defaultActionSet;
865 
866       UString postString;
867       if (!ParseUpdateCommandString2(updateString, actionSet, postString))
868         break;
869       if (postString.IsEmpty())
870       {
871         if (options.UpdateArchiveItself)
872           options.Commands[0].ActionSet = actionSet;
873       }
874       else
875       {
876         if (postString[0] != kUpdateNewArchivePostCharID)
877           break;
878         CUpdateArchiveCommand uc;
879         UString archivePath = postString.Ptr(1);
880         if (archivePath.IsEmpty())
881           break;
882         uc.UserArchivePath = archivePath;
883         uc.ActionSet = actionSet;
884         options.Commands.Add(uc);
885       }
886     }
887   }
888   if (i != updatePostStrings.Size())
889     throw CArcCmdLineException(errorMessage, updatePostStrings[i]);
890 }
891 
892 bool ParseComplexSize(const wchar_t *s, UInt64 &result);
893 
SetAddCommandOptions(NCommandType::EEnum commandType,const CParser & parser,CUpdateOptions & options)894 static void SetAddCommandOptions(
895     NCommandType::EEnum commandType,
896     const CParser &parser,
897     CUpdateOptions &options)
898 {
899   NUpdateArchive::CActionSet defaultActionSet;
900   switch (commandType)
901   {
902     case NCommandType::kAdd:
903       defaultActionSet = NUpdateArchive::k_ActionSet_Add;
904       break;
905     case NCommandType::kDelete:
906       defaultActionSet = NUpdateArchive::k_ActionSet_Delete;
907       break;
908     default:
909       defaultActionSet = NUpdateArchive::k_ActionSet_Update;
910   }
911 
912   options.UpdateArchiveItself = true;
913 
914   options.Commands.Clear();
915   CUpdateArchiveCommand updateMainCommand;
916   updateMainCommand.ActionSet = defaultActionSet;
917   options.Commands.Add(updateMainCommand);
918   if (parser[NKey::kUpdate].ThereIs)
919     ParseUpdateCommandString(options, parser[NKey::kUpdate].PostStrings,
920         defaultActionSet);
921   if (parser[NKey::kWorkingDir].ThereIs)
922   {
923     const UString &postString = parser[NKey::kWorkingDir].PostStrings[0];
924     if (postString.IsEmpty())
925       NDir::MyGetTempPath(options.WorkingDir);
926     else
927       options.WorkingDir = us2fs(postString);
928   }
929   options.SfxMode = parser[NKey::kSfx].ThereIs;
930   if (options.SfxMode)
931     options.SfxModule = us2fs(parser[NKey::kSfx].PostStrings[0]);
932 
933   if (parser[NKey::kVolume].ThereIs)
934   {
935     const UStringVector &sv = parser[NKey::kVolume].PostStrings;
936     FOR_VECTOR (i, sv)
937     {
938       UInt64 size;
939       if (!ParseComplexSize(sv[i], size) || size == 0)
940         throw CArcCmdLineException("Incorrect volume size:", sv[i]);
941       options.VolumesSizes.Add(size);
942     }
943   }
944 }
945 
SetMethodOptions(const CParser & parser,CObjectVector<CProperty> & properties)946 static void SetMethodOptions(const CParser &parser, CObjectVector<CProperty> &properties)
947 {
948   if (parser[NKey::kProperty].ThereIs)
949   {
950     FOR_VECTOR (i, parser[NKey::kProperty].PostStrings)
951     {
952       CProperty prop;
953       prop.Name = parser[NKey::kProperty].PostStrings[i];
954       int index = prop.Name.Find(L'=');
955       if (index >= 0)
956       {
957         prop.Value = prop.Name.Ptr((unsigned)(index + 1));
958         prop.Name.DeleteFrom((unsigned)index);
959       }
960       properties.Add(prop);
961     }
962   }
963 }
964 
965 
SetStreamMode(const CSwitchResult & sw,unsigned & res)966 static inline void SetStreamMode(const CSwitchResult &sw, unsigned &res)
967 {
968   if (sw.ThereIs)
969     res = (unsigned)sw.PostCharIndex;
970 }
971 
972 
973 #if defined(_WIN32) && !defined(UNDER_CE)
PrintHex(UString & s,UInt64 v)974 static void PrintHex(UString &s, UInt64 v)
975 {
976   char temp[32];
977   ConvertUInt64ToHex(v, temp);
978   s += temp;
979 }
980 #endif
981 
982 
Parse1(const UStringVector & commandStrings,CArcCmdLineOptions & options)983 void CArcCmdLineParser::Parse1(const UStringVector &commandStrings,
984     CArcCmdLineOptions &options)
985 {
986   Parse1Log.Empty();
987   if (!parser.ParseStrings(kSwitchForms, ARRAY_SIZE(kSwitchForms), commandStrings))
988     throw CArcCmdLineException(parser.ErrorMessage, parser.ErrorLine);
989 
990   options.IsInTerminal = MY_IS_TERMINAL(stdin);
991   options.IsStdOutTerminal = MY_IS_TERMINAL(stdout);
992   options.IsStdErrTerminal = MY_IS_TERMINAL(stderr);
993 
994   options.HelpMode = parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs  || parser[NKey::kHelp3].ThereIs;
995 
996   options.StdInMode = parser[NKey::kStdIn].ThereIs;
997   options.StdOutMode = parser[NKey::kStdOut].ThereIs;
998   options.EnableHeaders = !parser[NKey::kDisableHeaders].ThereIs;
999   if (parser[NKey::kListFields].ThereIs)
1000   {
1001     const UString &s = parser[NKey::kListFields].PostStrings[0];
1002     options.ListFields = GetAnsiString(s);
1003   }
1004   options.TechMode = parser[NKey::kTechMode].ThereIs;
1005   options.ShowTime = parser[NKey::kShowTime].ThereIs;
1006 
1007   if (parser[NKey::kDisablePercents].ThereIs
1008       || options.StdOutMode
1009       || !options.IsStdOutTerminal)
1010     options.Number_for_Percents = k_OutStream_disabled;
1011 
1012   if (options.StdOutMode)
1013     options.Number_for_Out = k_OutStream_disabled;
1014 
1015   SetStreamMode(parser[NKey::kOutStream], options.Number_for_Out);
1016   SetStreamMode(parser[NKey::kErrStream], options.Number_for_Errors);
1017   SetStreamMode(parser[NKey::kPercentStream], options.Number_for_Percents);
1018 
1019   if (parser[NKey::kLogLevel].ThereIs)
1020   {
1021     const UString &s = parser[NKey::kLogLevel].PostStrings[0];
1022     if (s.IsEmpty())
1023       options.LogLevel = 1;
1024     else
1025     {
1026       UInt32 v;
1027       if (!StringToUInt32(s, v))
1028         throw CArcCmdLineException("Unsupported switch postfix -bb", s);
1029       options.LogLevel = (unsigned)v;
1030     }
1031   }
1032 
1033   if (parser[NKey::kCaseSensitive].ThereIs)
1034   {
1035     g_CaseSensitive = !parser[NKey::kCaseSensitive].WithMinus;
1036     options.CaseSensitiveChange = true;
1037     options.CaseSensitive = g_CaseSensitive;
1038   }
1039 
1040 
1041   #if defined(_WIN32) && !defined(UNDER_CE)
1042   NSecurity::EnablePrivilege_SymLink();
1043   #endif
1044 
1045   // options.LargePages = false;
1046 
1047   if (parser[NKey::kLargePages].ThereIs)
1048   {
1049     unsigned slp = 0;
1050     const UString &s = parser[NKey::kLargePages].PostStrings[0];
1051     if (s.IsEmpty())
1052       slp = 1;
1053     else if (s != L"-")
1054     {
1055       if (!StringToUInt32(s, slp))
1056         throw CArcCmdLineException("Unsupported switch postfix for -slp", s);
1057     }
1058 
1059     #ifdef _7ZIP_LARGE_PAGES
1060     if (slp >
1061           #if defined(_WIN32) && !defined(UNDER_CE)
1062             (unsigned)NSecurity::Get_LargePages_RiskLevel()
1063           #else
1064             0
1065           #endif
1066         )
1067     {
1068       #ifdef _WIN32 // change it !
1069       SetLargePageSize();
1070       #endif
1071       // note: this process also can inherit that Privilege from parent process
1072       g_LargePagesMode =
1073       #if defined(_WIN32) && !defined(UNDER_CE)
1074         NSecurity::EnablePrivilege_LockMemory();
1075       #else
1076         true;
1077       #endif
1078     }
1079     #endif
1080   }
1081 
1082 
1083   #ifndef UNDER_CE
1084 
1085   if (parser[NKey::kAffinity].ThereIs)
1086   {
1087     const UString &s = parser[NKey::kAffinity].PostStrings[0];
1088     if (!s.IsEmpty())
1089     {
1090       AString a;
1091       a.SetFromWStr_if_Ascii(s);
1092       Parse1Log += "Set process affinity mask: ";
1093 
1094       #ifdef _WIN32
1095 
1096       UInt64 v = 0;
1097       {
1098         const char *end;
1099         v = ConvertHexStringToUInt64(a, &end);
1100         if (*end != 0)
1101           a.Empty();
1102       }
1103       if (a.IsEmpty())
1104         throw CArcCmdLineException("Unsupported switch postfix -stm", s);
1105 
1106       {
1107         #ifndef _WIN64
1108         if (v >= ((UInt64)1 << 32))
1109           throw CArcCmdLineException("unsupported value -stm", s);
1110         #endif
1111         {
1112           PrintHex(Parse1Log, v);
1113           if (!SetProcessAffinityMask(GetCurrentProcess(), (DWORD_PTR)v))
1114           {
1115             DWORD lastError = GetLastError();
1116             Parse1Log += " : ERROR : ";
1117             Parse1Log += NError::MyFormatMessage(lastError);
1118           }
1119         }
1120       }
1121 
1122       #else // _WIN32
1123 
1124       {
1125         Parse1Log += a;
1126         NSystem::CProcessAffinity aff;
1127         aff.CpuZero();
1128         for (unsigned i = 0; i < a.Len(); i++)
1129         {
1130           char c = a[i];
1131           unsigned v;
1132                if (c >= '0' && c <= '9') v =      (unsigned)(c - '0');
1133           else if (c >= 'A' && c <= 'F') v = 10 + (unsigned)(c - 'A');
1134           else if (c >= 'a' && c <= 'f') v = 10 + (unsigned)(c - 'a');
1135           else
1136             throw CArcCmdLineException("Unsupported switch postfix -stm", s);
1137           for (unsigned k = 0; k < 4; k++)
1138           {
1139             const unsigned cpu = (a.Len() - 1 - i) * 4 + k;
1140             if (v & ((unsigned)1 << k))
1141               aff.CpuSet(cpu);
1142           }
1143         }
1144 
1145         if (!aff.SetProcAffinity())
1146         {
1147           DWORD lastError = GetLastError();
1148           Parse1Log += " : ERROR : ";
1149           Parse1Log += NError::MyFormatMessage(lastError);
1150         }
1151       }
1152       #endif // _WIN32
1153 
1154       Parse1Log.Add_LF();
1155     }
1156   }
1157 
1158   #endif
1159 }
1160 
1161 
1162 
1163 struct CCodePagePair
1164 {
1165   const char *Name;
1166   UInt32 CodePage;
1167 };
1168 
1169 static const unsigned kNumByteOnlyCodePages = 3;
1170 
1171 static const CCodePagePair g_CodePagePairs[] =
1172 {
1173   { "utf-8", CP_UTF8 },
1174   { "win", CP_ACP },
1175   { "dos", CP_OEMCP },
1176   { "utf-16le", MY__CP_UTF16 },
1177   { "utf-16be", MY__CP_UTF16BE }
1178 };
1179 
FindCharset(const NCommandLineParser::CParser & parser,unsigned keyIndex,bool byteOnlyCodePages,Int32 defaultVal)1180 static Int32 FindCharset(const NCommandLineParser::CParser &parser, unsigned keyIndex,
1181     bool byteOnlyCodePages, Int32 defaultVal)
1182 {
1183   if (!parser[keyIndex].ThereIs)
1184     return defaultVal;
1185 
1186   UString name (parser[keyIndex].PostStrings.Back());
1187   UInt32 v;
1188   if (StringToUInt32(name, v))
1189     if (v < ((UInt32)1 << 16))
1190       return (Int32)v;
1191   name.MakeLower_Ascii();
1192   unsigned num = byteOnlyCodePages ? kNumByteOnlyCodePages : ARRAY_SIZE(g_CodePagePairs);
1193   for (unsigned i = 0;; i++)
1194   {
1195     if (i == num) // to disable warnings from different compilers
1196       throw CArcCmdLineException("Unsupported charset:", name);
1197     const CCodePagePair &pair = g_CodePagePairs[i];
1198     if (name.IsEqualTo(pair.Name))
1199       return (Int32)pair.CodePage;
1200   }
1201 }
1202 
1203 
SetBoolPair(NCommandLineParser::CParser & parser,unsigned switchID,CBoolPair & bp)1204 static void SetBoolPair(NCommandLineParser::CParser &parser, unsigned switchID, CBoolPair &bp)
1205 {
1206   bp.Def = parser[switchID].ThereIs;
1207   if (bp.Def)
1208     bp.Val = !parser[switchID].WithMinus;
1209 }
1210 
Parse2(CArcCmdLineOptions & options)1211 void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
1212 {
1213   const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
1214   const unsigned numNonSwitchStrings = nonSwitchStrings.Size();
1215   if (numNonSwitchStrings < kMinNonSwitchWords)
1216     throw CArcCmdLineException("The command must be specified");
1217 
1218   if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], options.Command))
1219     throw CArcCmdLineException("Unsupported command:", nonSwitchStrings[kCommandIndex]);
1220 
1221   if (parser[NKey::kHash].ThereIs)
1222     options.HashMethods = parser[NKey::kHash].PostStrings;
1223 
1224   /*
1225   if (parser[NKey::kHashGenFile].ThereIs)
1226   {
1227     const UString &s = parser[NKey::kHashGenFile].PostStrings[0];
1228     for (unsigned i = 0 ; i < s.Len();)
1229     {
1230       const wchar_t c = s[i++];
1231       if (!options.HashOptions.ParseFlagCharOption(c, true))
1232       {
1233         if (c != '=')
1234           throw CArcCmdLineException("Unsupported hash mode switch:", s);
1235         options.HashOptions.HashFilePath = s.Ptr(i);
1236         break;
1237       }
1238     }
1239   }
1240   */
1241 
1242   if (parser[NKey::kHashDir].ThereIs)
1243     options.ExtractOptions.HashDir = parser[NKey::kHashDir].PostStrings[0];
1244 
1245   if (parser[NKey::kElimDup].ThereIs)
1246   {
1247     options.ExtractOptions.ElimDup.Def = true;
1248     options.ExtractOptions.ElimDup.Val = !parser[NKey::kElimDup].WithMinus;
1249   }
1250 
1251   NWildcard::ECensorPathMode censorPathMode = NWildcard::k_RelatPath;
1252   bool fullPathMode = parser[NKey::kFullPathMode].ThereIs;
1253   if (fullPathMode)
1254   {
1255     censorPathMode = NWildcard::k_AbsPath;
1256     const UString &s = parser[NKey::kFullPathMode].PostStrings[0];
1257     if (!s.IsEmpty())
1258     {
1259       if (s == L"2")
1260         censorPathMode = NWildcard::k_FullPath;
1261       else
1262         throw CArcCmdLineException("Unsupported -spf:", s);
1263     }
1264   }
1265 
1266   if (parser[NKey::kNameTrailReplace].ThereIs)
1267     g_PathTrailReplaceMode = !parser[NKey::kNameTrailReplace].WithMinus;
1268 
1269   CNameOption nop;
1270 
1271   if (parser[NKey::kRecursed].ThereIs)
1272     nop.RecursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex);
1273 
1274   if (parser[NKey::kDisableWildcardParsing].ThereIs)
1275     nop.WildcardMatching = false;
1276 
1277   if (parser[NKey::kUseSlashMark].ThereIs)
1278   {
1279     const UString &s = parser[NKey::kUseSlashMark].PostStrings[0];
1280     if (s.IsEmpty())
1281       nop.MarkMode = NWildcard::kMark_StrictFile;
1282     else if (s.IsEqualTo_Ascii_NoCase("-"))
1283       nop.MarkMode = NWildcard::kMark_FileOrDir;
1284     else if (s.IsEqualTo_Ascii_NoCase("2"))
1285       nop.MarkMode = NWildcard::kMark_StrictFile_IfWildcard;
1286     else
1287       throw CArcCmdLineException("Unsupported -spm:", s);
1288   }
1289 
1290 
1291   options.ConsoleCodePage = FindCharset(parser, NKey::kConsoleCharSet, true, -1);
1292 
1293   UInt32 codePage = (UInt32)FindCharset(parser, NKey::kListfileCharSet, false, CP_UTF8);
1294 
1295   bool thereAreSwitchIncludes = false;
1296 
1297   if (parser[NKey::kInclude].ThereIs)
1298   {
1299     thereAreSwitchIncludes = true;
1300     nop.Include = true;
1301     AddSwitchWildcardsToCensor(options.Censor,
1302         parser[NKey::kInclude].PostStrings, nop, codePage);
1303   }
1304 
1305   if (parser[NKey::kExclude].ThereIs)
1306   {
1307     nop.Include = false;
1308     AddSwitchWildcardsToCensor(options.Censor,
1309         parser[NKey::kExclude].PostStrings, nop, codePage);
1310   }
1311 
1312   unsigned curCommandIndex = kCommandIndex + 1;
1313   bool thereIsArchiveName = !parser[NKey::kNoArName].ThereIs &&
1314       options.Command.CommandType != NCommandType::kBenchmark &&
1315       options.Command.CommandType != NCommandType::kInfo &&
1316       options.Command.CommandType != NCommandType::kHash;
1317 
1318   const bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
1319   const bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList;
1320   const bool isRename = options.Command.CommandType == NCommandType::kRename;
1321 
1322   if ((isExtractOrList || isRename) && options.StdInMode)
1323     thereIsArchiveName = false;
1324 
1325   if (parser[NKey::kArcNameMode].ThereIs)
1326     options.UpdateOptions.ArcNameMode = ParseArcNameMode(parser[NKey::kArcNameMode].PostCharIndex);
1327 
1328   if (thereIsArchiveName)
1329   {
1330     if (curCommandIndex >= numNonSwitchStrings)
1331       throw CArcCmdLineException("Cannot find archive name");
1332     options.ArchiveName = nonSwitchStrings[curCommandIndex++];
1333     if (options.ArchiveName.IsEmpty())
1334       throw CArcCmdLineException("Archive name cannot by empty");
1335     #ifdef _WIN32
1336     // options.ArchiveName.Replace(L'/', WCHAR_PATH_SEPARATOR);
1337     #endif
1338   }
1339 
1340   nop.Include = true;
1341   AddToCensorFromNonSwitchesStrings(isRename ? &options.UpdateOptions.RenamePairs : NULL,
1342       curCommandIndex, options.Censor,
1343       nonSwitchStrings, parser.StopSwitchIndex,
1344       nop,
1345       thereAreSwitchIncludes, codePage);
1346 
1347   options.YesToAll = parser[NKey::kYes].ThereIs;
1348 
1349 
1350   #ifndef _NO_CRYPTO
1351   options.PasswordEnabled = parser[NKey::kPassword].ThereIs;
1352   if (options.PasswordEnabled)
1353     options.Password = parser[NKey::kPassword].PostStrings[0];
1354   #endif
1355 
1356   options.ShowDialog = parser[NKey::kShowDialog].ThereIs;
1357 
1358   if (parser[NKey::kArchiveType].ThereIs)
1359     options.ArcType = parser[NKey::kArchiveType].PostStrings[0];
1360 
1361   options.ExcludedArcTypes = parser[NKey::kExcludedArcType].PostStrings;
1362 
1363   SetMethodOptions(parser, options.Properties);
1364 
1365   if (parser[NKey::kNtSecurity].ThereIs) options.NtSecurity.SetTrueTrue();
1366 
1367   SetBoolPair(parser, NKey::kAltStreams, options.AltStreams);
1368   SetBoolPair(parser, NKey::kHardLinks, options.HardLinks);
1369   SetBoolPair(parser, NKey::kSymLinks, options.SymLinks);
1370 
1371   CBoolPair symLinks_AllowDangerous;
1372   SetBoolPair(parser, NKey::kSymLinks_AllowDangerous, symLinks_AllowDangerous);
1373 
1374 
1375   /*
1376   bool supportSymLink = options.SymLinks.Val;
1377 
1378   if (!options.SymLinks.Def)
1379   {
1380     if (isExtractOrList)
1381       supportSymLink = true;
1382     else
1383       supportSymLink = false;
1384   }
1385 
1386   #ifdef ENV_HAVE_LSTAT
1387   if (supportSymLink)
1388     global_use_lstat = 1;
1389   else
1390     global_use_lstat = 0;
1391   #endif
1392   */
1393 
1394 
1395   if (isExtractOrList)
1396   {
1397     CExtractOptionsBase &eo = options.ExtractOptions;
1398 
1399     eo.ExcludeDirItems = options.Censor.ExcludeDirItems;
1400     eo.ExcludeFileItems = options.Censor.ExcludeFileItems;
1401 
1402     {
1403       CExtractNtOptions &nt = eo.NtOptions;
1404       nt.NtSecurity = options.NtSecurity;
1405 
1406       nt.AltStreams = options.AltStreams;
1407       if (!options.AltStreams.Def)
1408         nt.AltStreams.Val = true;
1409 
1410       nt.HardLinks = options.HardLinks;
1411       if (!options.HardLinks.Def)
1412         nt.HardLinks.Val = true;
1413 
1414       nt.SymLinks = options.SymLinks;
1415       if (!options.SymLinks.Def)
1416         nt.SymLinks.Val = true;
1417 
1418       nt.SymLinks_AllowDangerous = symLinks_AllowDangerous;
1419 
1420       nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs;
1421       nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs;
1422 
1423       if (parser[NKey::kPreserveATime].ThereIs)
1424         nt.PreserveATime = true;
1425       if (parser[NKey::kShareForWrite].ThereIs)
1426         nt.OpenShareForWrite = true;
1427     }
1428 
1429     options.Censor.AddPathsToCensor(NWildcard::k_AbsPath);
1430     options.Censor.ExtendExclude();
1431 
1432     // are there paths that look as non-relative (!Prefix.IsEmpty())
1433     if (!options.Censor.AllAreRelative())
1434       throw CArcCmdLineException("Cannot use absolute pathnames for this command");
1435 
1436     NWildcard::CCensor &arcCensor = options.arcCensor;
1437 
1438     CNameOption nopArc;
1439     // nopArc.RecursedType = NRecursedType::kNonRecursed; // default:  we don't want recursing for archives, if -r specified
1440     // is it OK, external switches can disable WildcardMatching and MarcMode for arc.
1441     nopArc.WildcardMatching = nop.WildcardMatching;
1442     nopArc.MarkMode = nop.MarkMode;
1443 
1444     if (parser[NKey::kArInclude].ThereIs)
1445     {
1446       nopArc.Include = true;
1447       AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArInclude].PostStrings, nopArc, codePage);
1448     }
1449     if (parser[NKey::kArExclude].ThereIs)
1450     {
1451       nopArc.Include = false;
1452       AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArExclude].PostStrings, nopArc, codePage);
1453     }
1454 
1455     if (thereIsArchiveName)
1456     {
1457       nopArc.Include = true;
1458       AddNameToCensor(arcCensor, nopArc, options.ArchiveName);
1459     }
1460 
1461     arcCensor.AddPathsToCensor(NWildcard::k_RelatPath);
1462 
1463     #ifdef _WIN32
1464     ConvertToLongNames(arcCensor);
1465     #endif
1466 
1467     arcCensor.ExtendExclude();
1468 
1469     if (options.StdInMode)
1470       options.ArcName_for_StdInMode = parser[NKey::kStdIn].PostStrings.Front();
1471 
1472     if (isExtractGroupCommand)
1473     {
1474       if (options.StdOutMode)
1475       {
1476         if (
1477                   options.Number_for_Percents == k_OutStream_stdout
1478             // || options.Number_for_Out      == k_OutStream_stdout
1479             // || options.Number_for_Errors   == k_OutStream_stdout
1480             ||
1481             (
1482               (options.IsStdOutTerminal && options.IsStdErrTerminal)
1483               &&
1484               (
1485                       options.Number_for_Percents != k_OutStream_disabled
1486                 // || options.Number_for_Out      != k_OutStream_disabled
1487                 // || options.Number_for_Errors   != k_OutStream_disabled
1488               )
1489             )
1490            )
1491           throw CArcCmdLineException(kSameTerminalError);
1492       }
1493 
1494       if (parser[NKey::kOutputDir].ThereIs)
1495       {
1496         eo.OutputDir = us2fs(parser[NKey::kOutputDir].PostStrings[0]);
1497         #ifdef _WIN32
1498           NFile::NName::NormalizeDirSeparators(eo.OutputDir);
1499         #endif
1500         NFile::NName::NormalizeDirPathPrefix(eo.OutputDir);
1501       }
1502 
1503       eo.OverwriteMode = NExtract::NOverwriteMode::kAsk;
1504       if (parser[NKey::kOverwrite].ThereIs)
1505       {
1506         eo.OverwriteMode = k_OverwriteModes[(unsigned)parser[NKey::kOverwrite].PostCharIndex];
1507         eo.OverwriteMode_Force = true;
1508       }
1509       else if (options.YesToAll)
1510       {
1511         eo.OverwriteMode = NExtract::NOverwriteMode::kOverwrite;
1512         eo.OverwriteMode_Force = true;
1513       }
1514     }
1515 
1516     eo.PathMode = options.Command.GetPathMode();
1517     if (censorPathMode == NWildcard::k_AbsPath)
1518     {
1519       eo.PathMode = NExtract::NPathMode::kAbsPaths;
1520       eo.PathMode_Force = true;
1521     }
1522     else if (censorPathMode == NWildcard::k_FullPath)
1523     {
1524       eo.PathMode = NExtract::NPathMode::kFullPaths;
1525       eo.PathMode_Force = true;
1526     }
1527   }
1528   else if (options.Command.IsFromUpdateGroup())
1529   {
1530     if (parser[NKey::kArInclude].ThereIs)
1531       throw CArcCmdLineException("-ai switch is not supported for this command");
1532 
1533     CUpdateOptions &updateOptions = options.UpdateOptions;
1534 
1535     SetAddCommandOptions(options.Command.CommandType, parser, updateOptions);
1536 
1537     updateOptions.MethodMode.Properties = options.Properties;
1538 
1539     if (parser[NKey::kPreserveATime].ThereIs)
1540       updateOptions.PreserveATime = true;
1541     if (parser[NKey::kShareForWrite].ThereIs)
1542       updateOptions.OpenShareForWrite = true;
1543     if (parser[NKey::kStopAfterOpenError].ThereIs)
1544       updateOptions.StopAfterOpenError = true;
1545 
1546     updateOptions.PathMode = censorPathMode;
1547 
1548     updateOptions.AltStreams = options.AltStreams;
1549     updateOptions.NtSecurity = options.NtSecurity;
1550     updateOptions.HardLinks = options.HardLinks;
1551     updateOptions.SymLinks = options.SymLinks;
1552 
1553     updateOptions.EMailMode = parser[NKey::kEmail].ThereIs;
1554     if (updateOptions.EMailMode)
1555     {
1556       updateOptions.EMailAddress = parser[NKey::kEmail].PostStrings.Front();
1557       if (updateOptions.EMailAddress.Len() > 0)
1558         if (updateOptions.EMailAddress[0] == L'.')
1559         {
1560           updateOptions.EMailRemoveAfter = true;
1561           updateOptions.EMailAddress.Delete(0);
1562         }
1563     }
1564 
1565     updateOptions.StdOutMode = options.StdOutMode;
1566     updateOptions.StdInMode = options.StdInMode;
1567 
1568     updateOptions.DeleteAfterCompressing = parser[NKey::kDeleteAfterCompressing].ThereIs;
1569     updateOptions.SetArcMTime = parser[NKey::kSetArcMTime].ThereIs;
1570 
1571     if (updateOptions.StdOutMode && updateOptions.EMailMode)
1572       throw CArcCmdLineException("stdout mode and email mode cannot be combined");
1573 
1574     if (updateOptions.StdOutMode)
1575     {
1576       if (options.IsStdOutTerminal)
1577         throw CArcCmdLineException(kTerminalOutError);
1578 
1579       if (options.Number_for_Percents == k_OutStream_stdout
1580           || options.Number_for_Out == k_OutStream_stdout
1581           || options.Number_for_Errors == k_OutStream_stdout)
1582         throw CArcCmdLineException(kSameTerminalError);
1583     }
1584 
1585     if (updateOptions.StdInMode)
1586       updateOptions.StdInFileName = parser[NKey::kStdIn].PostStrings.Front();
1587 
1588     if (options.Command.CommandType == NCommandType::kRename)
1589       if (updateOptions.Commands.Size() != 1)
1590         throw CArcCmdLineException("Only one archive can be created with rename command");
1591   }
1592   else if (options.Command.CommandType == NCommandType::kBenchmark)
1593   {
1594     options.NumIterations = 1;
1595     options.NumIterations_Defined = false;
1596     if (curCommandIndex < numNonSwitchStrings)
1597     {
1598       if (!StringToUInt32(nonSwitchStrings[curCommandIndex], options.NumIterations))
1599         throw CArcCmdLineException("Incorrect number of benchmark iterations", nonSwitchStrings[curCommandIndex]);
1600       curCommandIndex++;
1601       options.NumIterations_Defined = true;
1602     }
1603   }
1604   else if (options.Command.CommandType == NCommandType::kHash)
1605   {
1606     options.Censor.AddPathsToCensor(censorPathMode);
1607     options.Censor.ExtendExclude();
1608 
1609     CHashOptions &hashOptions = options.HashOptions;
1610     hashOptions.PathMode = censorPathMode;
1611     hashOptions.Methods = options.HashMethods;
1612     // hashOptions.HashFilePath = options.HashFilePath;
1613     if (parser[NKey::kPreserveATime].ThereIs)
1614       hashOptions.PreserveATime = true;
1615     if (parser[NKey::kShareForWrite].ThereIs)
1616       hashOptions.OpenShareForWrite = true;
1617     hashOptions.StdInMode = options.StdInMode;
1618     hashOptions.AltStreamsMode = options.AltStreams.Val;
1619     hashOptions.SymLinks = options.SymLinks;
1620   }
1621   else if (options.Command.CommandType == NCommandType::kInfo)
1622   {
1623   }
1624   else
1625     throw 20150919;
1626 }
1627 
1628 
1629 
1630 #ifndef _WIN32
1631 
1632 static AString g_ModuleDirPrefix;
1633 
1634 void Set_ModuleDirPrefix_From_ProgArg0(const char *s);
Set_ModuleDirPrefix_From_ProgArg0(const char * s)1635 void Set_ModuleDirPrefix_From_ProgArg0(const char *s)
1636 {
1637   AString a (s);
1638   int sep = a.ReverseFind_PathSepar();
1639   a.DeleteFrom((unsigned)(sep + 1));
1640   g_ModuleDirPrefix = a;
1641 }
1642 
1643 namespace NWindows {
1644 namespace NDLL {
1645 
1646 FString GetModuleDirPrefix();
GetModuleDirPrefix()1647 FString GetModuleDirPrefix()
1648 {
1649   FString s;
1650 
1651   s = fas2fs(g_ModuleDirPrefix);
1652   if (s.IsEmpty())
1653     s = FTEXT(".") FSTRING_PATH_SEPARATOR;
1654   return s;
1655   /*
1656   setenv("_7ZIP_HOME_DIR", "/test/", 0);
1657   const char *home = getenv("_7ZIP_HOME_DIR");
1658   if (home)
1659     s = home;
1660   else
1661     s = FTEXT(".") FSTRING_PATH_SEPARATOR;
1662   return s;
1663   */
1664 }
1665 
1666 }}
1667 
1668 #endif // ! _WIN32
1669