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