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