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