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