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