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.DisablePercents = true;
1044
1045 if (parser[NKey::kDisablePercents].ThereIs
1046 || options.StdOutMode
1047 || !options.IsStdOutTerminal)
1048 options.Number_for_Percents = k_OutStream_disabled;
1049
1050 if (options.StdOutMode)
1051 options.Number_for_Out = k_OutStream_disabled;
1052
1053 SetStreamMode(parser[NKey::kOutStream], options.Number_for_Out);
1054 SetStreamMode(parser[NKey::kErrStream], options.Number_for_Errors);
1055 SetStreamMode(parser[NKey::kPercentStream], options.Number_for_Percents);
1056
1057 if (parser[NKey::kLogLevel].ThereIs)
1058 {
1059 const UString &s = parser[NKey::kLogLevel].PostStrings[0];
1060 if (s.IsEmpty())
1061 options.LogLevel = 1;
1062 else
1063 {
1064 UInt32 v;
1065 if (!StringToUInt32(s, v))
1066 throw CArcCmdLineException("Unsupported switch postfix -bb", s);
1067 options.LogLevel = (unsigned)v;
1068 }
1069 }
1070
1071 if (parser[NKey::kCaseSensitive].ThereIs)
1072 {
1073 options.CaseSensitive =
1074 g_CaseSensitive = !parser[NKey::kCaseSensitive].WithMinus;
1075 options.CaseSensitive_Change = true;
1076 }
1077
1078
1079 #if defined(_WIN32) && !defined(UNDER_CE)
1080 NSecurity::EnablePrivilege_SymLink();
1081 #endif
1082
1083 // options.LargePages = false;
1084
1085 if (parser[NKey::kLargePages].ThereIs)
1086 {
1087 UInt32 slp = 0;
1088 const UString &s = parser[NKey::kLargePages].PostStrings[0];
1089 if (s.IsEmpty())
1090 slp = 1;
1091 else if (s != L"-")
1092 {
1093 if (!StringToUInt32(s, slp))
1094 throw CArcCmdLineException("Unsupported switch postfix for -slp", s);
1095 }
1096
1097 #ifdef Z7_LARGE_PAGES
1098 if (slp >
1099 #if defined(_WIN32) && !defined(UNDER_CE)
1100 (unsigned)NSecurity::Get_LargePages_RiskLevel()
1101 #else
1102 0
1103 #endif
1104 )
1105 {
1106 #ifdef _WIN32 // change it !
1107 SetLargePageSize();
1108 #endif
1109 // note: this process also can inherit that Privilege from parent process
1110 g_LargePagesMode =
1111 #if defined(_WIN32) && !defined(UNDER_CE)
1112 NSecurity::EnablePrivilege_LockMemory();
1113 #else
1114 true;
1115 #endif
1116 }
1117 #endif
1118 }
1119
1120
1121 #ifndef UNDER_CE
1122
1123 if (parser[NKey::kAffinity].ThereIs)
1124 {
1125 const UString &s = parser[NKey::kAffinity].PostStrings[0];
1126 if (!s.IsEmpty())
1127 {
1128 AString a;
1129 a.SetFromWStr_if_Ascii(s);
1130 Parse1Log += "Set process affinity mask: ";
1131
1132 bool isError = false;
1133
1134 #ifdef _WIN32
1135
1136 UInt64 v = 0;
1137 {
1138 const char *end;
1139 v = ConvertHexStringToUInt64(a, &end);
1140 if (*end != 0)
1141 a.Empty();
1142 }
1143 if (a.IsEmpty())
1144 isError = true;
1145 else
1146 {
1147 #ifndef _WIN64
1148 if (v >= ((UInt64)1 << 32))
1149 throw CArcCmdLineException("unsupported value -stm", s);
1150 else
1151 #endif
1152 {
1153 PrintHex(Parse1Log, v);
1154 if (!SetProcessAffinityMask(GetCurrentProcess(), (DWORD_PTR)v))
1155 {
1156 const DWORD lastError = GetLastError();
1157 Parse1Log += " : ERROR : ";
1158 Parse1Log += NError::MyFormatMessage(lastError);
1159 }
1160 }
1161 }
1162
1163 #else // _WIN32
1164
1165 if (a.Len() != s.Len())
1166 isError = true;
1167 else
1168 {
1169 Parse1Log += a;
1170 NSystem::CProcessAffinity aff;
1171 aff.CpuZero();
1172 unsigned cpu = 0;
1173 unsigned i = a.Len();
1174 while (i)
1175 {
1176 unsigned v = (Byte)a[--i];
1177 Z7_PARSE_HEX_DIGIT(v, { isError = true; break; })
1178 for (unsigned mask = 1; mask != 1u << 4; mask <<= 1, cpu++)
1179 if (v & mask)
1180 aff.CpuSet(cpu);
1181 }
1182 if (!isError)
1183 if (!aff.SetProcAffinity())
1184 {
1185 const DWORD lastError = GetLastError();
1186 Parse1Log += " : ERROR : ";
1187 Parse1Log += NError::MyFormatMessage(lastError);
1188 }
1189 }
1190 #endif // _WIN32
1191
1192 if (isError)
1193 throw CArcCmdLineException("Unsupported switch postfix -stm", s);
1194
1195 Parse1Log.Add_LF();
1196 }
1197 }
1198
1199 #endif
1200 }
1201
1202
1203
1204 struct CCodePagePair
1205 {
1206 const char *Name;
1207 UInt32 CodePage;
1208 };
1209
1210 static const unsigned kNumByteOnlyCodePages = 3;
1211
1212 static const CCodePagePair g_CodePagePairs[] =
1213 {
1214 { "utf-8", CP_UTF8 },
1215 { "win", CP_ACP },
1216 { "dos", CP_OEMCP },
1217 { "utf-16le", Z7_WIN_CP_UTF16 },
1218 { "utf-16be", Z7_WIN_CP_UTF16BE }
1219 };
1220
FindCharset(const NCommandLineParser::CParser & parser,unsigned keyIndex,bool byteOnlyCodePages,Int32 defaultVal)1221 static Int32 FindCharset(const NCommandLineParser::CParser &parser, unsigned keyIndex,
1222 bool byteOnlyCodePages, Int32 defaultVal)
1223 {
1224 if (!parser[keyIndex].ThereIs)
1225 return defaultVal;
1226
1227 UString name (parser[keyIndex].PostStrings.Back());
1228 UInt32 v;
1229 if (StringToUInt32(name, v))
1230 if (v < ((UInt32)1 << 16))
1231 return (Int32)v;
1232 name.MakeLower_Ascii();
1233 const unsigned num = byteOnlyCodePages ? kNumByteOnlyCodePages : Z7_ARRAY_SIZE(g_CodePagePairs);
1234 for (unsigned i = 0;; i++)
1235 {
1236 if (i == num) // to disable warnings from different compilers
1237 throw CArcCmdLineException("Unsupported charset:", name);
1238 const CCodePagePair &pair = g_CodePagePairs[i];
1239 if (name.IsEqualTo(pair.Name))
1240 return (Int32)pair.CodePage;
1241 }
1242 }
1243
1244
SetBoolPair(NCommandLineParser::CParser & parser,unsigned switchID,CBoolPair & bp)1245 static void SetBoolPair(NCommandLineParser::CParser &parser, unsigned switchID, CBoolPair &bp)
1246 {
1247 bp.Def = parser[switchID].ThereIs;
1248 if (bp.Def)
1249 bp.Val = !parser[switchID].WithMinus;
1250 }
1251
1252
ParseSizeString(const wchar_t * s,UInt64 & res)1253 static bool ParseSizeString(const wchar_t *s, UInt64 &res)
1254 {
1255 const wchar_t *end;
1256 const UInt64 v = ConvertStringToUInt64(s, &end);
1257 if (s == end)
1258 return false;
1259 const wchar_t c = *end;
1260
1261 if (c == 0)
1262 {
1263 res = v;
1264 return true;
1265 }
1266 if (end[1] != 0)
1267 return false;
1268
1269 unsigned numBits;
1270 switch (MyCharLower_Ascii(c))
1271 {
1272 case 'b': numBits = 0; break;
1273 case 'k': numBits = 10; break;
1274 case 'm': numBits = 20; break;
1275 case 'g': numBits = 30; break;
1276 case 't': numBits = 40; break;
1277 default: return false;
1278 }
1279 const UInt64 val2 = v << numBits;
1280 if ((val2 >> numBits) != v)
1281 return false;
1282 res = val2;
1283 return true;
1284 }
1285
Parse2(CArcCmdLineOptions & options)1286 void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
1287 {
1288 const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
1289 const unsigned numNonSwitchStrings = nonSwitchStrings.Size();
1290 if (numNonSwitchStrings < kMinNonSwitchWords)
1291 throw CArcCmdLineException("The command must be specified");
1292
1293 if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], options.Command))
1294 throw CArcCmdLineException("Unsupported command:", nonSwitchStrings[kCommandIndex]);
1295
1296 if (parser[NKey::kHash].ThereIs)
1297 options.HashMethods = parser[NKey::kHash].PostStrings;
1298
1299 /*
1300 if (parser[NKey::kHashGenFile].ThereIs)
1301 {
1302 const UString &s = parser[NKey::kHashGenFile].PostStrings[0];
1303 for (unsigned i = 0 ; i < s.Len();)
1304 {
1305 const wchar_t c = s[i++];
1306 if (!options.HashOptions.ParseFlagCharOption(c, true))
1307 {
1308 if (c != '=')
1309 throw CArcCmdLineException("Unsupported hash mode switch:", s);
1310 options.HashOptions.HashFilePath = s.Ptr(i);
1311 break;
1312 }
1313 }
1314 }
1315 */
1316
1317 if (parser[NKey::kHashDir].ThereIs)
1318 options.ExtractOptions.HashDir = parser[NKey::kHashDir].PostStrings[0];
1319
1320 if (parser[NKey::kExtractMemLimit].ThereIs)
1321 {
1322 const UString &s = parser[NKey::kExtractMemLimit].PostStrings[0];
1323 if (!ParseSizeString(s, options.ExtractOptions.NtOptions.MemLimit))
1324 throw CArcCmdLineException("Unsupported -smemx:", s);
1325 }
1326
1327 if (parser[NKey::kElimDup].ThereIs)
1328 {
1329 options.ExtractOptions.ElimDup.Def = true;
1330 options.ExtractOptions.ElimDup.Val = !parser[NKey::kElimDup].WithMinus;
1331 }
1332
1333 NWildcard::ECensorPathMode censorPathMode = NWildcard::k_RelatPath;
1334 bool fullPathMode = parser[NKey::kFullPathMode].ThereIs;
1335 if (fullPathMode)
1336 {
1337 censorPathMode = NWildcard::k_AbsPath;
1338 const UString &s = parser[NKey::kFullPathMode].PostStrings[0];
1339 if (!s.IsEmpty())
1340 {
1341 if (s == L"2")
1342 censorPathMode = NWildcard::k_FullPath;
1343 else
1344 throw CArcCmdLineException("Unsupported -spf:", s);
1345 }
1346 }
1347
1348 if (parser[NKey::kNameTrailReplace].ThereIs)
1349 g_PathTrailReplaceMode = !parser[NKey::kNameTrailReplace].WithMinus;
1350
1351 CNameOption nop;
1352
1353 if (parser[NKey::kRecursed].ThereIs)
1354 nop.RecursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex);
1355
1356 if (parser[NKey::kDisableWildcardParsing].ThereIs)
1357 nop.WildcardMatching = false;
1358
1359 if (parser[NKey::kUseSlashMark].ThereIs)
1360 {
1361 const UString &s = parser[NKey::kUseSlashMark].PostStrings[0];
1362 if (s.IsEmpty())
1363 nop.MarkMode = NWildcard::kMark_StrictFile;
1364 else if (s.IsEqualTo_Ascii_NoCase("-"))
1365 nop.MarkMode = NWildcard::kMark_FileOrDir;
1366 else if (s.IsEqualTo_Ascii_NoCase("2"))
1367 nop.MarkMode = NWildcard::kMark_StrictFile_IfWildcard;
1368 else
1369 throw CArcCmdLineException("Unsupported -spm:", s);
1370 }
1371
1372
1373 options.ConsoleCodePage = FindCharset(parser, NKey::kConsoleCharSet, true, -1);
1374
1375 const UInt32 codePage = (UInt32)FindCharset(parser, NKey::kListfileCharSet, false, CP_UTF8);
1376
1377 bool thereAreSwitchIncludes = false;
1378
1379 if (parser[NKey::kInclude].ThereIs)
1380 {
1381 thereAreSwitchIncludes = true;
1382 nop.Include = true;
1383 AddSwitchWildcardsToCensor(options.Censor,
1384 parser[NKey::kInclude].PostStrings, nop, codePage);
1385 }
1386
1387 if (parser[NKey::kExclude].ThereIs)
1388 {
1389 nop.Include = false;
1390 AddSwitchWildcardsToCensor(options.Censor,
1391 parser[NKey::kExclude].PostStrings, nop, codePage);
1392 }
1393
1394 unsigned curCommandIndex = kCommandIndex + 1;
1395 bool thereIsArchiveName = !parser[NKey::kNoArName].ThereIs &&
1396 options.Command.CommandType != NCommandType::kBenchmark &&
1397 options.Command.CommandType != NCommandType::kInfo &&
1398 options.Command.CommandType != NCommandType::kHash;
1399
1400 const bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
1401 const bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList;
1402 const bool isRename = options.Command.CommandType == NCommandType::kRename;
1403
1404 if ((isExtractOrList || isRename) && options.StdInMode)
1405 thereIsArchiveName = false;
1406
1407 if (parser[NKey::kArcNameMode].ThereIs)
1408 options.UpdateOptions.ArcNameMode = ParseArcNameMode(parser[NKey::kArcNameMode].PostCharIndex);
1409
1410 if (thereIsArchiveName)
1411 {
1412 if (curCommandIndex >= numNonSwitchStrings)
1413 throw CArcCmdLineException("Cannot find archive name");
1414 options.ArchiveName = nonSwitchStrings[curCommandIndex++];
1415 if (options.ArchiveName.IsEmpty())
1416 throw CArcCmdLineException("Archive name cannot by empty");
1417 #ifdef _WIN32
1418 // options.ArchiveName.Replace(L'/', WCHAR_PATH_SEPARATOR);
1419 #endif
1420 }
1421
1422 nop.Include = true;
1423 AddToCensorFromNonSwitchesStrings(isRename ? &options.UpdateOptions.RenamePairs : NULL,
1424 curCommandIndex, options.Censor,
1425 nonSwitchStrings, parser.StopSwitchIndex,
1426 nop,
1427 thereAreSwitchIncludes, codePage);
1428
1429 #ifndef Z7_NO_CRYPTO
1430 options.PasswordEnabled = parser[NKey::kPassword].ThereIs;
1431 if (options.PasswordEnabled)
1432 options.Password = parser[NKey::kPassword].PostStrings[0];
1433 #endif
1434
1435 options.ShowDialog = parser[NKey::kShowDialog].ThereIs;
1436
1437 if (parser[NKey::kArchiveType].ThereIs)
1438 options.ArcType = parser[NKey::kArchiveType].PostStrings[0];
1439
1440 options.ExcludedArcTypes = parser[NKey::kExcludedArcType].PostStrings;
1441
1442 SetMethodOptions(parser, options.Properties);
1443
1444 if (parser[NKey::kNtSecurity].ThereIs) options.NtSecurity.SetTrueTrue();
1445
1446 SetBoolPair(parser, NKey::kAltStreams, options.AltStreams);
1447 SetBoolPair(parser, NKey::kHardLinks, options.HardLinks);
1448 SetBoolPair(parser, NKey::kSymLinks, options.SymLinks);
1449
1450 SetBoolPair(parser, NKey::kStoreOwnerId, options.StoreOwnerId);
1451 SetBoolPair(parser, NKey::kStoreOwnerName, options.StoreOwnerName);
1452
1453 CBoolPair symLinks_AllowDangerous;
1454 SetBoolPair(parser, NKey::kSymLinks_AllowDangerous, symLinks_AllowDangerous);
1455
1456
1457 /*
1458 bool supportSymLink = options.SymLinks.Val;
1459
1460 if (!options.SymLinks.Def)
1461 {
1462 if (isExtractOrList)
1463 supportSymLink = true;
1464 else
1465 supportSymLink = false;
1466 }
1467
1468 #ifdef ENV_HAVE_LSTAT
1469 if (supportSymLink)
1470 global_use_lstat = 1;
1471 else
1472 global_use_lstat = 0;
1473 #endif
1474 */
1475
1476
1477 if (isExtractOrList)
1478 {
1479 CExtractOptionsBase &eo = options.ExtractOptions;
1480
1481 eo.ExcludeDirItems = options.Censor.ExcludeDirItems;
1482 eo.ExcludeFileItems = options.Censor.ExcludeFileItems;
1483
1484 {
1485 CExtractNtOptions &nt = eo.NtOptions;
1486 nt.NtSecurity = options.NtSecurity;
1487
1488 nt.AltStreams = options.AltStreams;
1489 if (!options.AltStreams.Def)
1490 nt.AltStreams.Val = true;
1491
1492 nt.HardLinks = options.HardLinks;
1493 if (!options.HardLinks.Def)
1494 nt.HardLinks.Val = true;
1495
1496 nt.SymLinks = options.SymLinks;
1497 if (!options.SymLinks.Def)
1498 nt.SymLinks.Val = true;
1499
1500 nt.SymLinks_AllowDangerous = symLinks_AllowDangerous;
1501
1502 nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs;
1503 nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs;
1504
1505 nt.ExtractOwner = options.StoreOwnerId.Val; // StoreOwnerName
1506
1507 if (parser[NKey::kPreserveATime].ThereIs)
1508 nt.PreserveATime = true;
1509 if (parser[NKey::kShareForWrite].ThereIs)
1510 nt.OpenShareForWrite = true;
1511 }
1512
1513 if (parser[NKey::kZoneFile].ThereIs)
1514 {
1515 eo.ZoneMode = NExtract::NZoneIdMode::kAll;
1516 const UString &s = parser[NKey::kZoneFile].PostStrings[0];
1517 if (!s.IsEmpty())
1518 {
1519 if (s == L"0") eo.ZoneMode = NExtract::NZoneIdMode::kNone;
1520 else if (s == L"1") eo.ZoneMode = NExtract::NZoneIdMode::kAll;
1521 else if (s == L"2") eo.ZoneMode = NExtract::NZoneIdMode::kOffice;
1522 else
1523 throw CArcCmdLineException("Unsupported -snz:", s);
1524 }
1525 }
1526
1527 options.Censor.AddPathsToCensor(NWildcard::k_AbsPath);
1528 options.Censor.ExtendExclude();
1529
1530 // are there paths that look as non-relative (!Prefix.IsEmpty())
1531 if (!options.Censor.AllAreRelative())
1532 throw CArcCmdLineException("Cannot use absolute pathnames for this command");
1533
1534 NWildcard::CCensor &arcCensor = options.arcCensor;
1535
1536 CNameOption nopArc;
1537 // nopArc.RecursedType = NRecursedType::kNonRecursed; // default: we don't want recursing for archives, if -r specified
1538 // is it OK, external switches can disable WildcardMatching and MarcMode for arc.
1539 nopArc.WildcardMatching = nop.WildcardMatching;
1540 nopArc.MarkMode = nop.MarkMode;
1541
1542 if (parser[NKey::kArInclude].ThereIs)
1543 {
1544 nopArc.Include = true;
1545 AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArInclude].PostStrings, nopArc, codePage);
1546 }
1547 if (parser[NKey::kArExclude].ThereIs)
1548 {
1549 nopArc.Include = false;
1550 AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArExclude].PostStrings, nopArc, codePage);
1551 }
1552
1553 if (thereIsArchiveName)
1554 {
1555 nopArc.Include = true;
1556 AddNameToCensor(arcCensor, nopArc, options.ArchiveName);
1557 }
1558
1559 arcCensor.AddPathsToCensor(NWildcard::k_RelatPath);
1560
1561 #ifdef _WIN32
1562 ConvertToLongNames(arcCensor);
1563 #endif
1564
1565 arcCensor.ExtendExclude();
1566
1567 if (options.StdInMode)
1568 options.ArcName_for_StdInMode = parser[NKey::kStdIn].PostStrings.Front();
1569
1570 if (isExtractGroupCommand)
1571 {
1572 if (options.StdOutMode)
1573 {
1574 if (
1575 options.Number_for_Percents == k_OutStream_stdout
1576 // || options.Number_for_Out == k_OutStream_stdout
1577 // || options.Number_for_Errors == k_OutStream_stdout
1578 ||
1579 (
1580 (options.IsStdOutTerminal && options.IsStdErrTerminal)
1581 &&
1582 (
1583 options.Number_for_Percents != k_OutStream_disabled
1584 // || options.Number_for_Out != k_OutStream_disabled
1585 // || options.Number_for_Errors != k_OutStream_disabled
1586 )
1587 )
1588 )
1589 throw CArcCmdLineException(kSameTerminalError);
1590 }
1591
1592 if (parser[NKey::kOutputDir].ThereIs)
1593 {
1594 eo.OutputDir = us2fs(parser[NKey::kOutputDir].PostStrings[0]);
1595 #ifdef _WIN32
1596 NFile::NName::NormalizeDirSeparators(eo.OutputDir);
1597 #endif
1598 NFile::NName::NormalizeDirPathPrefix(eo.OutputDir);
1599 }
1600
1601 eo.OverwriteMode = NExtract::NOverwriteMode::kAsk;
1602 if (parser[NKey::kOverwrite].ThereIs)
1603 {
1604 eo.OverwriteMode = k_OverwriteModes[(unsigned)parser[NKey::kOverwrite].PostCharIndex];
1605 eo.OverwriteMode_Force = true;
1606 }
1607 else if (options.YesToAll)
1608 {
1609 eo.OverwriteMode = NExtract::NOverwriteMode::kOverwrite;
1610 eo.OverwriteMode_Force = true;
1611 }
1612 }
1613
1614 eo.PathMode = options.Command.GetPathMode();
1615 if (censorPathMode == NWildcard::k_AbsPath)
1616 {
1617 eo.PathMode = NExtract::NPathMode::kAbsPaths;
1618 eo.PathMode_Force = true;
1619 }
1620 else if (censorPathMode == NWildcard::k_FullPath)
1621 {
1622 eo.PathMode = NExtract::NPathMode::kFullPaths;
1623 eo.PathMode_Force = true;
1624 }
1625 }
1626 else if (options.Command.IsFromUpdateGroup())
1627 {
1628 if (parser[NKey::kArInclude].ThereIs)
1629 throw CArcCmdLineException("-ai switch is not supported for this command");
1630
1631 CUpdateOptions &updateOptions = options.UpdateOptions;
1632
1633 SetAddCommandOptions(options.Command.CommandType, parser, updateOptions);
1634
1635 updateOptions.MethodMode.Properties = options.Properties;
1636
1637 if (parser[NKey::kPreserveATime].ThereIs)
1638 updateOptions.PreserveATime = true;
1639 if (parser[NKey::kShareForWrite].ThereIs)
1640 updateOptions.OpenShareForWrite = true;
1641 if (parser[NKey::kStopAfterOpenError].ThereIs)
1642 updateOptions.StopAfterOpenError = true;
1643
1644 updateOptions.PathMode = censorPathMode;
1645
1646 updateOptions.AltStreams = options.AltStreams;
1647 updateOptions.NtSecurity = options.NtSecurity;
1648 updateOptions.HardLinks = options.HardLinks;
1649 updateOptions.SymLinks = options.SymLinks;
1650
1651 updateOptions.StoreOwnerId = options.StoreOwnerId;
1652 updateOptions.StoreOwnerName = options.StoreOwnerName;
1653
1654 updateOptions.EMailMode = parser[NKey::kEmail].ThereIs;
1655 if (updateOptions.EMailMode)
1656 {
1657 updateOptions.EMailAddress = parser[NKey::kEmail].PostStrings.Front();
1658 if (updateOptions.EMailAddress.Len() > 0)
1659 if (updateOptions.EMailAddress[0] == L'.')
1660 {
1661 updateOptions.EMailRemoveAfter = true;
1662 updateOptions.EMailAddress.Delete(0);
1663 }
1664 }
1665
1666 updateOptions.StdOutMode = options.StdOutMode;
1667 updateOptions.StdInMode = options.StdInMode;
1668
1669 updateOptions.DeleteAfterCompressing = parser[NKey::kDeleteAfterCompressing].ThereIs;
1670 updateOptions.SetArcMTime = parser[NKey::kSetArcMTime].ThereIs;
1671
1672 if (updateOptions.StdOutMode && updateOptions.EMailMode)
1673 throw CArcCmdLineException("stdout mode and email mode cannot be combined");
1674
1675 if (updateOptions.StdOutMode)
1676 {
1677 if (options.IsStdOutTerminal)
1678 throw CArcCmdLineException(kTerminalOutError);
1679
1680 if (options.Number_for_Percents == k_OutStream_stdout
1681 || options.Number_for_Out == k_OutStream_stdout
1682 || options.Number_for_Errors == k_OutStream_stdout)
1683 throw CArcCmdLineException(kSameTerminalError);
1684 }
1685
1686 if (updateOptions.StdInMode)
1687 updateOptions.StdInFileName = parser[NKey::kStdIn].PostStrings.Front();
1688
1689 if (options.Command.CommandType == NCommandType::kRename)
1690 if (updateOptions.Commands.Size() != 1)
1691 throw CArcCmdLineException("Only one archive can be created with rename command");
1692 }
1693 else if (options.Command.CommandType == NCommandType::kBenchmark)
1694 {
1695 options.NumIterations = 1;
1696 options.NumIterations_Defined = false;
1697 if (curCommandIndex < numNonSwitchStrings)
1698 {
1699 if (!StringToUInt32(nonSwitchStrings[curCommandIndex], options.NumIterations))
1700 throw CArcCmdLineException("Incorrect number of benchmark iterations", nonSwitchStrings[curCommandIndex]);
1701 curCommandIndex++;
1702 options.NumIterations_Defined = true;
1703 }
1704 }
1705 else if (options.Command.CommandType == NCommandType::kHash)
1706 {
1707 options.Censor.AddPathsToCensor(censorPathMode);
1708 options.Censor.ExtendExclude();
1709
1710 CHashOptions &hashOptions = options.HashOptions;
1711 hashOptions.PathMode = censorPathMode;
1712 hashOptions.Methods = options.HashMethods;
1713 // hashOptions.HashFilePath = options.HashFilePath;
1714 if (parser[NKey::kPreserveATime].ThereIs)
1715 hashOptions.PreserveATime = true;
1716 if (parser[NKey::kShareForWrite].ThereIs)
1717 hashOptions.OpenShareForWrite = true;
1718 hashOptions.StdInMode = options.StdInMode;
1719 hashOptions.AltStreamsMode = options.AltStreams.Val;
1720 hashOptions.SymLinks = options.SymLinks;
1721 }
1722 else if (options.Command.CommandType == NCommandType::kInfo)
1723 {
1724 }
1725 else
1726 throw 20150919;
1727 }
1728
1729
1730
1731 #ifndef _WIN32
1732
1733 static AString g_ModuleDirPrefix;
1734
1735 void Set_ModuleDirPrefix_From_ProgArg0(const char *s);
Set_ModuleDirPrefix_From_ProgArg0(const char * s)1736 void Set_ModuleDirPrefix_From_ProgArg0(const char *s)
1737 {
1738 AString a (s);
1739 int sep = a.ReverseFind_PathSepar();
1740 a.DeleteFrom((unsigned)(sep + 1));
1741 g_ModuleDirPrefix = a;
1742 }
1743
1744 namespace NWindows {
1745 namespace NDLL {
1746
1747 FString GetModuleDirPrefix();
GetModuleDirPrefix()1748 FString GetModuleDirPrefix()
1749 {
1750 FString s;
1751
1752 s = fas2fs(g_ModuleDirPrefix);
1753 if (s.IsEmpty())
1754 s = FTEXT(".") FSTRING_PATH_SEPARATOR;
1755 return s;
1756 /*
1757 setenv("_7ZIP_HOME_DIR", "/test/", 0);
1758 const char *home = getenv("_7ZIP_HOME_DIR");
1759 if (home)
1760 s = home;
1761 else
1762 s = FTEXT(".") FSTRING_PATH_SEPARATOR;
1763 return s;
1764 */
1765 }
1766
1767 }}
1768
1769 #endif // ! _WIN32
1770