1// ArchiveCommandLine.cpp 2 3#include "StdAfx.h" 4#undef printf 5#undef sprintf 6 7#ifdef _WIN32 8#ifndef UNDER_CE 9#include <io.h> 10#endif 11#else 12// for isatty() 13#include <unistd.h> 14#endif 15 16#include <stdio.h> 17 18#ifdef Z7_LARGE_PAGES 19#include "../../../../C/Alloc.h" 20#endif 21 22#include "../../../Common/IntToString.h" 23#include "../../../Common/ListFileUtils.h" 24#include "../../../Common/StringConvert.h" 25#include "../../../Common/StringToInt.h" 26 27#include "../../../Windows/ErrorMsg.h" 28#include "../../../Windows/FileDir.h" 29#include "../../../Windows/FileName.h" 30#include "../../../Windows/System.h" 31#ifdef _WIN32 32#include "../../../Windows/FileMapping.h" 33#include "../../../Windows/MemoryLock.h" 34#include "../../../Windows/Synchronization.h" 35#endif 36 37#include "ArchiveCommandLine.h" 38#include "EnumDirItems.h" 39#include "Update.h" 40#include "UpdateAction.h" 41 42extern bool g_CaseSensitive; 43extern bool g_PathTrailReplaceMode; 44 45#ifdef Z7_LARGE_PAGES 46extern 47bool g_LargePagesMode; 48bool g_LargePagesMode = false; 49#endif 50 51/* 52#ifdef ENV_HAVE_LSTAT 53EXTERN_C_BEGIN 54extern int global_use_lstat; 55EXTERN_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); 67static 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 80using namespace NCommandLineParser; 81using namespace NWindows; 82using namespace NFile; 83 84static 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 94namespace NKey { 95enum Enum 96{ 97 kHelp1 = 0, 98 kHelp2, 99 kHelp3, 100 101 kDisableHeaders, 102 kDisablePercents, 103 kShowTime, 104 kLogLevel, 105 106 kOutStream, 107 kErrStream, 108 kPercentStream, 109 110 kYes, 111 112 kShowDialog, 113 kOverwrite, 114 115 kArchiveType, 116 kExcludedArcType, 117 118 kProperty, 119 kOutputDir, 120 kWorkingDir, 121 122 kInclude, 123 kExclude, 124 kArInclude, 125 kArExclude, 126 kNoArName, 127 128 kUpdate, 129 kVolume, 130 kRecursed, 131 132 kAffinity, 133 kSfx, 134 kEmail, 135 kHash, 136 // kHashGenFile, 137 kHashDir, 138 139 kStdIn, 140 kStdOut, 141 142 kLargePages, 143 kListfileCharSet, 144 kConsoleCharSet, 145 kTechMode, 146 kListFields, 147 148 kPreserveATime, 149 kShareForWrite, 150 kStopAfterOpenError, 151 kCaseSensitive, 152 kArcNameMode, 153 154 kUseSlashMark, 155 kDisableWildcardParsing, 156 kElimDup, 157 kFullPathMode, 158 159 kHardLinks, 160 kSymLinks_AllowDangerous, 161 kSymLinks, 162 kNtSecurity, 163 164 kStoreOwnerId, 165 kStoreOwnerName, 166 167 kZoneFile, 168 kAltStreams, 169 kReplaceColonForAltStream, 170 kWriteToAltStreamIfColon, 171 172 kNameTrailReplace, 173 174 kDeleteAfterCompressing, 175 kSetArcMTime 176 177 #ifndef Z7_NO_CRYPTO 178 , kPassword 179 #endif 180}; 181 182} 183 184 185static const wchar_t kRecursedIDChar = 'r'; 186static const char * const kRecursedPostCharSet = "0-"; 187 188static const char * const k_ArcNameMode_PostCharSet = "sea"; 189 190static const char * const k_Stream_PostCharSet = "012"; 191 192static 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 202namespace 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 217static const Byte kSomeCludePostStringMinSize = 2; // at least <@|!><N>ame must be 218static const Byte kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>ame must be 219 220static const char * const kOverwritePostCharSet = "asut"; 221 222static 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 243static const CSwitchForm kSwitchForms[] = 244{ 245 { "?", SWFRM_SIMPLE }, 246 { "h", SWFRM_SIMPLE }, 247 { "-help", SWFRM_SIMPLE }, 248 249 { "ba", SWFRM_SIMPLE }, 250 { "bd", SWFRM_SIMPLE }, 251 { "bt", SWFRM_SIMPLE }, 252 { "bb", SWFRM_STRING_SINGL(0) }, 253 254 { "bso", NSwitchType::kChar, false, 1, k_Stream_PostCharSet }, 255 { "bse", NSwitchType::kChar, false, 1, k_Stream_PostCharSet }, 256 { "bsp", NSwitchType::kChar, false, 1, k_Stream_PostCharSet }, 257 258 { "y", SWFRM_SIMPLE }, 259 260 { "ad", SWFRM_SIMPLE }, 261 { "ao", NSwitchType::kChar, false, 1, kOverwritePostCharSet}, 262 263 { "t", SWFRM_STRING_SINGL(1) }, 264 { "stx", SWFRM_STRING_MULT(1) }, 265 266 { "m", SWFRM_STRING_MULT(1) }, 267 { "o", SWFRM_STRING_SINGL(1) }, 268 { "w", SWFRM_STRING }, 269 270 { "i", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) }, 271 { "x", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) }, 272 { "ai", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) }, 273 { "ax", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) }, 274 { "an", SWFRM_SIMPLE }, 275 276 { "u", SWFRM_STRING_MULT(1) }, 277 { "v", SWFRM_STRING_MULT(1) }, 278 { "r", NSwitchType::kChar, false, 0, kRecursedPostCharSet }, 279 280 { "stm", SWFRM_STRING }, 281 { "sfx", SWFRM_STRING }, 282 { "seml", SWFRM_STRING_SINGL(0) }, 283 { "scrc", SWFRM_STRING_MULT(0) }, 284 // { "scrf", SWFRM_STRING_SINGL(1) }, 285 { "shd", SWFRM_STRING_SINGL(1) }, 286 287 { "si", SWFRM_STRING }, 288 { "so", SWFRM_SIMPLE }, 289 290 { "slp", SWFRM_STRING }, 291 { "scs", SWFRM_STRING }, 292 { "scc", SWFRM_STRING }, 293 { "slt", SWFRM_SIMPLE }, 294 { "slf", SWFRM_STRING_SINGL(1) }, 295 296 { "ssp", SWFRM_SIMPLE }, 297 { "ssw", SWFRM_SIMPLE }, 298 { "sse", SWFRM_SIMPLE }, 299 { "ssc", SWFRM_MINUS }, 300 { "sa", NSwitchType::kChar, false, 1, k_ArcNameMode_PostCharSet }, 301 302 { "spm", SWFRM_STRING_SINGL(0) }, 303 { "spd", SWFRM_SIMPLE }, 304 { "spe", SWFRM_MINUS }, 305 { "spf", SWFRM_STRING_SINGL(0) }, 306 307 { "snh", SWFRM_MINUS }, 308 { "snld", SWFRM_MINUS }, 309 { "snl", SWFRM_MINUS }, 310 { "sni", SWFRM_SIMPLE }, 311 312 { "snoi", SWFRM_MINUS }, 313 { "snon", SWFRM_MINUS }, 314 315 { "snz", SWFRM_STRING_SINGL(0) }, 316 { "sns", SWFRM_MINUS }, 317 { "snr", SWFRM_SIMPLE }, 318 { "snc", SWFRM_SIMPLE }, 319 320 { "snt", SWFRM_MINUS }, 321 322 { "sdel", SWFRM_SIMPLE }, 323 { "stl", SWFRM_SIMPLE } 324 325 #ifndef Z7_NO_CRYPTO 326 , { "p", SWFRM_STRING } 327 #endif 328}; 329 330static const char * const kUniversalWildcard = "*"; 331static const unsigned kMinNonSwitchWords = 1; 332static const unsigned kCommandIndex = 0; 333 334// static const char * const kUserErrorMessage = "Incorrect command line"; 335// static const char * const kCannotFindListFile = "Cannot find listfile"; 336static const char * const kIncorrectListFile = "Incorrect item in listfile.\nCheck charset encoding and -scs switch."; 337static const char * const kTerminalOutError = "I won't write compressed data to a terminal"; 338static const char * const kSameTerminalError = "I won't write data and program's messages to same stream"; 339static const char * const kEmptyFilePath = "Empty file path"; 340 341bool CArcCommand::IsFromExtractGroup() const 342{ 343 switch ((int)CommandType) 344 { 345 case NCommandType::kTest: 346 case NCommandType::kExtract: 347 case NCommandType::kExtractFull: 348 return true; 349 default: 350 return false; 351 } 352} 353 354NExtract::NPathMode::EEnum CArcCommand::GetPathMode() const 355{ 356 switch ((int)CommandType) 357 { 358 case NCommandType::kTest: 359 case NCommandType::kExtractFull: 360 return NExtract::NPathMode::kFullPaths; 361 default: 362 return NExtract::NPathMode::kNoPaths; 363 } 364} 365 366bool CArcCommand::IsFromUpdateGroup() const 367{ 368 switch ((int)CommandType) 369 { 370 case NCommandType::kAdd: 371 case NCommandType::kUpdate: 372 case NCommandType::kDelete: 373 case NCommandType::kRename: 374 return true; 375 default: 376 return false; 377 } 378} 379 380static 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 393static const char *g_Commands = "audtexlbih"; 394 395static 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 420struct CNameOption 421{ 422 bool Include; 423 bool WildcardMatching; 424 Byte MarkMode; 425 NRecursedType::EEnum RecursedType; 426 427 CNameOption(): 428 Include(true), 429 WildcardMatching(true), 430 MarkMode(NWildcard::kMark_FileOrDir), 431 RecursedType(NRecursedType::kNonRecursed) 432 {} 433}; 434 435 436static void AddNameToCensor(NWildcard::CCensor &censor, 437 const CNameOption &nop, const UString &name) 438{ 439 bool recursed = false; 440 441 switch ((int)nop.RecursedType) 442 { 443 case NRecursedType::kWildcardOnlyRecursed: 444 recursed = DoesNameContainWildcard(name); 445 break; 446 case NRecursedType::kRecursed: 447 recursed = true; 448 break; 449 default: 450 break; 451 } 452 453 NWildcard::CCensorPathProps props; 454 props.Recursive = recursed; 455 props.WildcardMatching = nop.WildcardMatching; 456 props.MarkMode = nop.MarkMode; 457 censor.AddPreItem(nop.Include, name, props); 458} 459 460static 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 485static 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 523static 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 587struct CEventSetEnd 588{ 589 UString Name; 590 591 CEventSetEnd(const wchar_t *name): Name(name) {} 592 ~CEventSetEnd() 593 { 594 NSynchronization::CManualResetEvent event; 595 if (event.Open(EVENT_MODIFY_STATE, false, GetSystemString(Name)) == 0) 596 event.Set(); 597 } 598}; 599 600static const char * const k_IncorrectMapCommand = "Incorrect Map command"; 601 602static 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 658static 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/* 804static 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 817static const char * const kUpdatePairStateIDSet = "pqrxyzw"; 818static const int kUpdatePairStateNotSupportedActions[] = {2, 2, 1, -1, -1, -1, -1}; 819 820static const unsigned kNumUpdatePairActions = 4; 821static const char * const kUpdateIgnoreItselfPostStringID = "-"; 822static const wchar_t kUpdateNewArchivePostCharID = '!'; 823 824 825static 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 853static 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 900bool ParseComplexSize(const wchar_t *s, UInt64 &result); 901 902static void SetAddCommandOptions( 903 NCommandType::EEnum commandType, 904 const CParser &parser, 905 CUpdateOptions &options) 906{ 907 NUpdateArchive::CActionSet defaultActionSet; 908 switch ((int)commandType) 909 { 910 case NCommandType::kAdd: 911 defaultActionSet = NUpdateArchive::k_ActionSet_Add; 912 break; 913 case NCommandType::kDelete: 914 defaultActionSet = NUpdateArchive::k_ActionSet_Delete; 915 break; 916 default: 917 defaultActionSet = NUpdateArchive::k_ActionSet_Update; 918 } 919 920 options.UpdateArchiveItself = true; 921 922 options.Commands.Clear(); 923 CUpdateArchiveCommand updateMainCommand; 924 updateMainCommand.ActionSet = defaultActionSet; 925 options.Commands.Add(updateMainCommand); 926 if (parser[NKey::kUpdate].ThereIs) 927 ParseUpdateCommandString(options, parser[NKey::kUpdate].PostStrings, 928 defaultActionSet); 929 if (parser[NKey::kWorkingDir].ThereIs) 930 { 931 const UString &postString = parser[NKey::kWorkingDir].PostStrings[0]; 932 if (postString.IsEmpty()) 933 NDir::MyGetTempPath(options.WorkingDir); 934 else 935 options.WorkingDir = us2fs(postString); 936 } 937 options.SfxMode = parser[NKey::kSfx].ThereIs; 938 if (options.SfxMode) 939 options.SfxModule = us2fs(parser[NKey::kSfx].PostStrings[0]); 940 941 if (parser[NKey::kVolume].ThereIs) 942 { 943 const UStringVector &sv = parser[NKey::kVolume].PostStrings; 944 FOR_VECTOR (i, sv) 945 { 946 UInt64 size; 947 if (!ParseComplexSize(sv[i], size)) 948 throw CArcCmdLineException("Incorrect volume size:", sv[i]); 949 if (i == sv.Size() - 1 && size == 0) 950 throw CArcCmdLineException("zero size last volume is not allowed"); 951 options.VolumesSizes.Add(size); 952 } 953 } 954} 955 956static void SetMethodOptions(const CParser &parser, CObjectVector<CProperty> &properties) 957{ 958 if (parser[NKey::kProperty].ThereIs) 959 { 960 FOR_VECTOR (i, parser[NKey::kProperty].PostStrings) 961 { 962 CProperty prop; 963 prop.Name = parser[NKey::kProperty].PostStrings[i]; 964 int index = prop.Name.Find(L'='); 965 if (index >= 0) 966 { 967 prop.Value = prop.Name.Ptr((unsigned)(index + 1)); 968 prop.Name.DeleteFrom((unsigned)index); 969 } 970 properties.Add(prop); 971 } 972 } 973} 974 975 976static inline void SetStreamMode(const CSwitchResult &sw, unsigned &res) 977{ 978 if (sw.ThereIs) 979 res = (unsigned)sw.PostCharIndex; 980} 981 982 983#if defined(_WIN32) && !defined(UNDER_CE) 984static void PrintHex(UString &s, UInt64 v) 985{ 986 char temp[32]; 987 ConvertUInt64ToHex(v, temp); 988 s += temp; 989} 990#endif 991 992 993void CArcCmdLineParser::Parse1(const UStringVector &commandStrings, 994 CArcCmdLineOptions &options) 995{ 996 Parse1Log.Empty(); 997 if (!parser.ParseStrings(kSwitchForms, Z7_ARRAY_SIZE(kSwitchForms), commandStrings)) 998 throw CArcCmdLineException(parser.ErrorMessage, parser.ErrorLine); 999 1000 options.IsInTerminal = MY_IS_TERMINAL(stdin); 1001 options.IsStdOutTerminal = MY_IS_TERMINAL(stdout); 1002 options.IsStdErrTerminal = MY_IS_TERMINAL(stderr); 1003 1004 options.HelpMode = parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs || parser[NKey::kHelp3].ThereIs; 1005 1006 options.StdInMode = parser[NKey::kStdIn].ThereIs; 1007 options.StdOutMode = parser[NKey::kStdOut].ThereIs; 1008 options.EnableHeaders = !parser[NKey::kDisableHeaders].ThereIs; 1009 if (parser[NKey::kListFields].ThereIs) 1010 { 1011 const UString &s = parser[NKey::kListFields].PostStrings[0]; 1012 options.ListFields = GetAnsiString(s); 1013 } 1014 options.TechMode = parser[NKey::kTechMode].ThereIs; 1015 options.ShowTime = parser[NKey::kShowTime].ThereIs; 1016 1017 if (parser[NKey::kDisablePercents].ThereIs 1018 || options.StdOutMode 1019 || !options.IsStdOutTerminal) 1020 options.Number_for_Percents = k_OutStream_disabled; 1021 1022 if (options.StdOutMode) 1023 options.Number_for_Out = k_OutStream_disabled; 1024 1025 SetStreamMode(parser[NKey::kOutStream], options.Number_for_Out); 1026 SetStreamMode(parser[NKey::kErrStream], options.Number_for_Errors); 1027 SetStreamMode(parser[NKey::kPercentStream], options.Number_for_Percents); 1028 1029 if (parser[NKey::kLogLevel].ThereIs) 1030 { 1031 const UString &s = parser[NKey::kLogLevel].PostStrings[0]; 1032 if (s.IsEmpty()) 1033 options.LogLevel = 1; 1034 else 1035 { 1036 UInt32 v; 1037 if (!StringToUInt32(s, v)) 1038 throw CArcCmdLineException("Unsupported switch postfix -bb", s); 1039 options.LogLevel = (unsigned)v; 1040 } 1041 } 1042 1043 if (parser[NKey::kCaseSensitive].ThereIs) 1044 { 1045 options.CaseSensitive = 1046 g_CaseSensitive = !parser[NKey::kCaseSensitive].WithMinus; 1047 options.CaseSensitive_Change = true; 1048 } 1049 1050 1051 #if defined(_WIN32) && !defined(UNDER_CE) 1052 NSecurity::EnablePrivilege_SymLink(); 1053 #endif 1054 1055 // options.LargePages = false; 1056 1057 if (parser[NKey::kLargePages].ThereIs) 1058 { 1059 UInt32 slp = 0; 1060 const UString &s = parser[NKey::kLargePages].PostStrings[0]; 1061 if (s.IsEmpty()) 1062 slp = 1; 1063 else if (s != L"-") 1064 { 1065 if (!StringToUInt32(s, slp)) 1066 throw CArcCmdLineException("Unsupported switch postfix for -slp", s); 1067 } 1068 1069 #ifdef Z7_LARGE_PAGES 1070 if (slp > 1071 #if defined(_WIN32) && !defined(UNDER_CE) 1072 (unsigned)NSecurity::Get_LargePages_RiskLevel() 1073 #else 1074 0 1075 #endif 1076 ) 1077 { 1078 #ifdef _WIN32 // change it ! 1079 SetLargePageSize(); 1080 #endif 1081 // note: this process also can inherit that Privilege from parent process 1082 g_LargePagesMode = 1083 #if defined(_WIN32) && !defined(UNDER_CE) 1084 NSecurity::EnablePrivilege_LockMemory(); 1085 #else 1086 true; 1087 #endif 1088 } 1089 #endif 1090 } 1091 1092 1093 #ifndef UNDER_CE 1094 1095 if (parser[NKey::kAffinity].ThereIs) 1096 { 1097 const UString &s = parser[NKey::kAffinity].PostStrings[0]; 1098 if (!s.IsEmpty()) 1099 { 1100 AString a; 1101 a.SetFromWStr_if_Ascii(s); 1102 Parse1Log += "Set process affinity mask: "; 1103 1104 #ifdef _WIN32 1105 1106 UInt64 v = 0; 1107 { 1108 const char *end; 1109 v = ConvertHexStringToUInt64(a, &end); 1110 if (*end != 0) 1111 a.Empty(); 1112 } 1113 if (a.IsEmpty()) 1114 throw CArcCmdLineException("Unsupported switch postfix -stm", s); 1115 1116 { 1117 #ifndef _WIN64 1118 if (v >= ((UInt64)1 << 32)) 1119 throw CArcCmdLineException("unsupported value -stm", s); 1120 #endif 1121 { 1122 PrintHex(Parse1Log, v); 1123 if (!SetProcessAffinityMask(GetCurrentProcess(), (DWORD_PTR)v)) 1124 { 1125 DWORD lastError = GetLastError(); 1126 Parse1Log += " : ERROR : "; 1127 Parse1Log += NError::MyFormatMessage(lastError); 1128 } 1129 } 1130 } 1131 1132 #else // _WIN32 1133 1134 { 1135 Parse1Log += a; 1136 NSystem::CProcessAffinity aff; 1137 aff.CpuZero(); 1138 for (unsigned i = 0; i < a.Len(); i++) 1139 { 1140 char c = a[i]; 1141 unsigned v; 1142 if (c >= '0' && c <= '9') v = (unsigned)(c - '0'); 1143 else if (c >= 'A' && c <= 'F') v = 10 + (unsigned)(c - 'A'); 1144 else if (c >= 'a' && c <= 'f') v = 10 + (unsigned)(c - 'a'); 1145 else 1146 throw CArcCmdLineException("Unsupported switch postfix -stm", s); 1147 for (unsigned k = 0; k < 4; k++) 1148 { 1149 const unsigned cpu = (a.Len() - 1 - i) * 4 + k; 1150 if (v & ((unsigned)1 << k)) 1151 aff.CpuSet(cpu); 1152 } 1153 } 1154 1155 if (!aff.SetProcAffinity()) 1156 { 1157 DWORD lastError = GetLastError(); 1158 Parse1Log += " : ERROR : "; 1159 Parse1Log += NError::MyFormatMessage(lastError); 1160 } 1161 } 1162 #endif // _WIN32 1163 1164 Parse1Log.Add_LF(); 1165 } 1166 } 1167 1168 #endif 1169} 1170 1171 1172 1173struct CCodePagePair 1174{ 1175 const char *Name; 1176 UInt32 CodePage; 1177}; 1178 1179static const unsigned kNumByteOnlyCodePages = 3; 1180 1181static const CCodePagePair g_CodePagePairs[] = 1182{ 1183 { "utf-8", CP_UTF8 }, 1184 { "win", CP_ACP }, 1185 { "dos", CP_OEMCP }, 1186 { "utf-16le", Z7_WIN_CP_UTF16 }, 1187 { "utf-16be", Z7_WIN_CP_UTF16BE } 1188}; 1189 1190static Int32 FindCharset(const NCommandLineParser::CParser &parser, unsigned keyIndex, 1191 bool byteOnlyCodePages, Int32 defaultVal) 1192{ 1193 if (!parser[keyIndex].ThereIs) 1194 return defaultVal; 1195 1196 UString name (parser[keyIndex].PostStrings.Back()); 1197 UInt32 v; 1198 if (StringToUInt32(name, v)) 1199 if (v < ((UInt32)1 << 16)) 1200 return (Int32)v; 1201 name.MakeLower_Ascii(); 1202 const unsigned num = byteOnlyCodePages ? kNumByteOnlyCodePages : Z7_ARRAY_SIZE(g_CodePagePairs); 1203 for (unsigned i = 0;; i++) 1204 { 1205 if (i == num) // to disable warnings from different compilers 1206 throw CArcCmdLineException("Unsupported charset:", name); 1207 const CCodePagePair &pair = g_CodePagePairs[i]; 1208 if (name.IsEqualTo(pair.Name)) 1209 return (Int32)pair.CodePage; 1210 } 1211} 1212 1213 1214static void SetBoolPair(NCommandLineParser::CParser &parser, unsigned switchID, CBoolPair &bp) 1215{ 1216 bp.Def = parser[switchID].ThereIs; 1217 if (bp.Def) 1218 bp.Val = !parser[switchID].WithMinus; 1219} 1220 1221void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) 1222{ 1223 const UStringVector &nonSwitchStrings = parser.NonSwitchStrings; 1224 const unsigned numNonSwitchStrings = nonSwitchStrings.Size(); 1225 if (numNonSwitchStrings < kMinNonSwitchWords) 1226 throw CArcCmdLineException("The command must be specified"); 1227 1228 if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], options.Command)) 1229 throw CArcCmdLineException("Unsupported command:", nonSwitchStrings[kCommandIndex]); 1230 1231 if (parser[NKey::kHash].ThereIs) 1232 options.HashMethods = parser[NKey::kHash].PostStrings; 1233 1234 /* 1235 if (parser[NKey::kHashGenFile].ThereIs) 1236 { 1237 const UString &s = parser[NKey::kHashGenFile].PostStrings[0]; 1238 for (unsigned i = 0 ; i < s.Len();) 1239 { 1240 const wchar_t c = s[i++]; 1241 if (!options.HashOptions.ParseFlagCharOption(c, true)) 1242 { 1243 if (c != '=') 1244 throw CArcCmdLineException("Unsupported hash mode switch:", s); 1245 options.HashOptions.HashFilePath = s.Ptr(i); 1246 break; 1247 } 1248 } 1249 } 1250 */ 1251 1252 if (parser[NKey::kHashDir].ThereIs) 1253 options.ExtractOptions.HashDir = parser[NKey::kHashDir].PostStrings[0]; 1254 1255 if (parser[NKey::kElimDup].ThereIs) 1256 { 1257 options.ExtractOptions.ElimDup.Def = true; 1258 options.ExtractOptions.ElimDup.Val = !parser[NKey::kElimDup].WithMinus; 1259 } 1260 1261 NWildcard::ECensorPathMode censorPathMode = NWildcard::k_RelatPath; 1262 bool fullPathMode = parser[NKey::kFullPathMode].ThereIs; 1263 if (fullPathMode) 1264 { 1265 censorPathMode = NWildcard::k_AbsPath; 1266 const UString &s = parser[NKey::kFullPathMode].PostStrings[0]; 1267 if (!s.IsEmpty()) 1268 { 1269 if (s == L"2") 1270 censorPathMode = NWildcard::k_FullPath; 1271 else 1272 throw CArcCmdLineException("Unsupported -spf:", s); 1273 } 1274 } 1275 1276 if (parser[NKey::kNameTrailReplace].ThereIs) 1277 g_PathTrailReplaceMode = !parser[NKey::kNameTrailReplace].WithMinus; 1278 1279 CNameOption nop; 1280 1281 if (parser[NKey::kRecursed].ThereIs) 1282 nop.RecursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex); 1283 1284 if (parser[NKey::kDisableWildcardParsing].ThereIs) 1285 nop.WildcardMatching = false; 1286 1287 if (parser[NKey::kUseSlashMark].ThereIs) 1288 { 1289 const UString &s = parser[NKey::kUseSlashMark].PostStrings[0]; 1290 if (s.IsEmpty()) 1291 nop.MarkMode = NWildcard::kMark_StrictFile; 1292 else if (s.IsEqualTo_Ascii_NoCase("-")) 1293 nop.MarkMode = NWildcard::kMark_FileOrDir; 1294 else if (s.IsEqualTo_Ascii_NoCase("2")) 1295 nop.MarkMode = NWildcard::kMark_StrictFile_IfWildcard; 1296 else 1297 throw CArcCmdLineException("Unsupported -spm:", s); 1298 } 1299 1300 1301 options.ConsoleCodePage = FindCharset(parser, NKey::kConsoleCharSet, true, -1); 1302 1303 UInt32 codePage = (UInt32)FindCharset(parser, NKey::kListfileCharSet, false, CP_UTF8); 1304 1305 bool thereAreSwitchIncludes = false; 1306 1307 if (parser[NKey::kInclude].ThereIs) 1308 { 1309 thereAreSwitchIncludes = true; 1310 nop.Include = true; 1311 AddSwitchWildcardsToCensor(options.Censor, 1312 parser[NKey::kInclude].PostStrings, nop, codePage); 1313 } 1314 1315 if (parser[NKey::kExclude].ThereIs) 1316 { 1317 nop.Include = false; 1318 AddSwitchWildcardsToCensor(options.Censor, 1319 parser[NKey::kExclude].PostStrings, nop, codePage); 1320 } 1321 1322 unsigned curCommandIndex = kCommandIndex + 1; 1323 bool thereIsArchiveName = !parser[NKey::kNoArName].ThereIs && 1324 options.Command.CommandType != NCommandType::kBenchmark && 1325 options.Command.CommandType != NCommandType::kInfo && 1326 options.Command.CommandType != NCommandType::kHash; 1327 1328 const bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); 1329 const bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList; 1330 const bool isRename = options.Command.CommandType == NCommandType::kRename; 1331 1332 if ((isExtractOrList || isRename) && options.StdInMode) 1333 thereIsArchiveName = false; 1334 1335 if (parser[NKey::kArcNameMode].ThereIs) 1336 options.UpdateOptions.ArcNameMode = ParseArcNameMode(parser[NKey::kArcNameMode].PostCharIndex); 1337 1338 if (thereIsArchiveName) 1339 { 1340 if (curCommandIndex >= numNonSwitchStrings) 1341 throw CArcCmdLineException("Cannot find archive name"); 1342 options.ArchiveName = nonSwitchStrings[curCommandIndex++]; 1343 if (options.ArchiveName.IsEmpty()) 1344 throw CArcCmdLineException("Archive name cannot by empty"); 1345 #ifdef _WIN32 1346 // options.ArchiveName.Replace(L'/', WCHAR_PATH_SEPARATOR); 1347 #endif 1348 } 1349 1350 nop.Include = true; 1351 AddToCensorFromNonSwitchesStrings(isRename ? &options.UpdateOptions.RenamePairs : NULL, 1352 curCommandIndex, options.Censor, 1353 nonSwitchStrings, parser.StopSwitchIndex, 1354 nop, 1355 thereAreSwitchIncludes, codePage); 1356 1357 options.YesToAll = parser[NKey::kYes].ThereIs; 1358 1359 1360 #ifndef Z7_NO_CRYPTO 1361 options.PasswordEnabled = parser[NKey::kPassword].ThereIs; 1362 if (options.PasswordEnabled) 1363 options.Password = parser[NKey::kPassword].PostStrings[0]; 1364 #endif 1365 1366 options.ShowDialog = parser[NKey::kShowDialog].ThereIs; 1367 1368 if (parser[NKey::kArchiveType].ThereIs) 1369 options.ArcType = parser[NKey::kArchiveType].PostStrings[0]; 1370 1371 options.ExcludedArcTypes = parser[NKey::kExcludedArcType].PostStrings; 1372 1373 SetMethodOptions(parser, options.Properties); 1374 1375 if (parser[NKey::kNtSecurity].ThereIs) options.NtSecurity.SetTrueTrue(); 1376 1377 SetBoolPair(parser, NKey::kAltStreams, options.AltStreams); 1378 SetBoolPair(parser, NKey::kHardLinks, options.HardLinks); 1379 SetBoolPair(parser, NKey::kSymLinks, options.SymLinks); 1380 1381 SetBoolPair(parser, NKey::kStoreOwnerId, options.StoreOwnerId); 1382 SetBoolPair(parser, NKey::kStoreOwnerName, options.StoreOwnerName); 1383 1384 CBoolPair symLinks_AllowDangerous; 1385 SetBoolPair(parser, NKey::kSymLinks_AllowDangerous, symLinks_AllowDangerous); 1386 1387 1388 /* 1389 bool supportSymLink = options.SymLinks.Val; 1390 1391 if (!options.SymLinks.Def) 1392 { 1393 if (isExtractOrList) 1394 supportSymLink = true; 1395 else 1396 supportSymLink = false; 1397 } 1398 1399 #ifdef ENV_HAVE_LSTAT 1400 if (supportSymLink) 1401 global_use_lstat = 1; 1402 else 1403 global_use_lstat = 0; 1404 #endif 1405 */ 1406 1407 1408 if (isExtractOrList) 1409 { 1410 CExtractOptionsBase &eo = options.ExtractOptions; 1411 1412 eo.ExcludeDirItems = options.Censor.ExcludeDirItems; 1413 eo.ExcludeFileItems = options.Censor.ExcludeFileItems; 1414 1415 { 1416 CExtractNtOptions &nt = eo.NtOptions; 1417 nt.NtSecurity = options.NtSecurity; 1418 1419 nt.AltStreams = options.AltStreams; 1420 if (!options.AltStreams.Def) 1421 nt.AltStreams.Val = true; 1422 1423 nt.HardLinks = options.HardLinks; 1424 if (!options.HardLinks.Def) 1425 nt.HardLinks.Val = true; 1426 1427 nt.SymLinks = options.SymLinks; 1428 if (!options.SymLinks.Def) 1429 nt.SymLinks.Val = true; 1430 1431 nt.SymLinks_AllowDangerous = symLinks_AllowDangerous; 1432 1433 nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs; 1434 nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs; 1435 1436 nt.ExtractOwner = options.StoreOwnerId.Val; // StoreOwnerName 1437 1438 if (parser[NKey::kPreserveATime].ThereIs) 1439 nt.PreserveATime = true; 1440 if (parser[NKey::kShareForWrite].ThereIs) 1441 nt.OpenShareForWrite = true; 1442 } 1443 1444 if (parser[NKey::kZoneFile].ThereIs) 1445 { 1446 eo.ZoneMode = NExtract::NZoneIdMode::kAll; 1447 const UString &s = parser[NKey::kZoneFile].PostStrings[0]; 1448 if (!s.IsEmpty()) 1449 { 1450 if (s == L"0") eo.ZoneMode = NExtract::NZoneIdMode::kNone; 1451 else if (s == L"1") eo.ZoneMode = NExtract::NZoneIdMode::kAll; 1452 else if (s == L"2") eo.ZoneMode = NExtract::NZoneIdMode::kOffice; 1453 else 1454 throw CArcCmdLineException("Unsupported -snz:", s); 1455 } 1456 } 1457 1458 options.Censor.AddPathsToCensor(NWildcard::k_AbsPath); 1459 options.Censor.ExtendExclude(); 1460 1461 // are there paths that look as non-relative (!Prefix.IsEmpty()) 1462 if (!options.Censor.AllAreRelative()) 1463 throw CArcCmdLineException("Cannot use absolute pathnames for this command"); 1464 1465 NWildcard::CCensor &arcCensor = options.arcCensor; 1466 1467 CNameOption nopArc; 1468 // nopArc.RecursedType = NRecursedType::kNonRecursed; // default: we don't want recursing for archives, if -r specified 1469 // is it OK, external switches can disable WildcardMatching and MarcMode for arc. 1470 nopArc.WildcardMatching = nop.WildcardMatching; 1471 nopArc.MarkMode = nop.MarkMode; 1472 1473 if (parser[NKey::kArInclude].ThereIs) 1474 { 1475 nopArc.Include = true; 1476 AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArInclude].PostStrings, nopArc, codePage); 1477 } 1478 if (parser[NKey::kArExclude].ThereIs) 1479 { 1480 nopArc.Include = false; 1481 AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArExclude].PostStrings, nopArc, codePage); 1482 } 1483 1484 if (thereIsArchiveName) 1485 { 1486 nopArc.Include = true; 1487 AddNameToCensor(arcCensor, nopArc, options.ArchiveName); 1488 } 1489 1490 arcCensor.AddPathsToCensor(NWildcard::k_RelatPath); 1491 1492 #ifdef _WIN32 1493 ConvertToLongNames(arcCensor); 1494 #endif 1495 1496 arcCensor.ExtendExclude(); 1497 1498 if (options.StdInMode) 1499 options.ArcName_for_StdInMode = parser[NKey::kStdIn].PostStrings.Front(); 1500 1501 if (isExtractGroupCommand) 1502 { 1503 if (options.StdOutMode) 1504 { 1505 if ( 1506 options.Number_for_Percents == k_OutStream_stdout 1507 // || options.Number_for_Out == k_OutStream_stdout 1508 // || options.Number_for_Errors == k_OutStream_stdout 1509 || 1510 ( 1511 (options.IsStdOutTerminal && options.IsStdErrTerminal) 1512 && 1513 ( 1514 options.Number_for_Percents != k_OutStream_disabled 1515 // || options.Number_for_Out != k_OutStream_disabled 1516 // || options.Number_for_Errors != k_OutStream_disabled 1517 ) 1518 ) 1519 ) 1520 throw CArcCmdLineException(kSameTerminalError); 1521 } 1522 1523 if (parser[NKey::kOutputDir].ThereIs) 1524 { 1525 eo.OutputDir = us2fs(parser[NKey::kOutputDir].PostStrings[0]); 1526 #ifdef _WIN32 1527 NFile::NName::NormalizeDirSeparators(eo.OutputDir); 1528 #endif 1529 NFile::NName::NormalizeDirPathPrefix(eo.OutputDir); 1530 } 1531 1532 eo.OverwriteMode = NExtract::NOverwriteMode::kAsk; 1533 if (parser[NKey::kOverwrite].ThereIs) 1534 { 1535 eo.OverwriteMode = k_OverwriteModes[(unsigned)parser[NKey::kOverwrite].PostCharIndex]; 1536 eo.OverwriteMode_Force = true; 1537 } 1538 else if (options.YesToAll) 1539 { 1540 eo.OverwriteMode = NExtract::NOverwriteMode::kOverwrite; 1541 eo.OverwriteMode_Force = true; 1542 } 1543 } 1544 1545 eo.PathMode = options.Command.GetPathMode(); 1546 if (censorPathMode == NWildcard::k_AbsPath) 1547 { 1548 eo.PathMode = NExtract::NPathMode::kAbsPaths; 1549 eo.PathMode_Force = true; 1550 } 1551 else if (censorPathMode == NWildcard::k_FullPath) 1552 { 1553 eo.PathMode = NExtract::NPathMode::kFullPaths; 1554 eo.PathMode_Force = true; 1555 } 1556 } 1557 else if (options.Command.IsFromUpdateGroup()) 1558 { 1559 if (parser[NKey::kArInclude].ThereIs) 1560 throw CArcCmdLineException("-ai switch is not supported for this command"); 1561 1562 CUpdateOptions &updateOptions = options.UpdateOptions; 1563 1564 SetAddCommandOptions(options.Command.CommandType, parser, updateOptions); 1565 1566 updateOptions.MethodMode.Properties = options.Properties; 1567 1568 if (parser[NKey::kPreserveATime].ThereIs) 1569 updateOptions.PreserveATime = true; 1570 if (parser[NKey::kShareForWrite].ThereIs) 1571 updateOptions.OpenShareForWrite = true; 1572 if (parser[NKey::kStopAfterOpenError].ThereIs) 1573 updateOptions.StopAfterOpenError = true; 1574 1575 updateOptions.PathMode = censorPathMode; 1576 1577 updateOptions.AltStreams = options.AltStreams; 1578 updateOptions.NtSecurity = options.NtSecurity; 1579 updateOptions.HardLinks = options.HardLinks; 1580 updateOptions.SymLinks = options.SymLinks; 1581 1582 updateOptions.StoreOwnerId = options.StoreOwnerId; 1583 updateOptions.StoreOwnerName = options.StoreOwnerName; 1584 1585 updateOptions.EMailMode = parser[NKey::kEmail].ThereIs; 1586 if (updateOptions.EMailMode) 1587 { 1588 updateOptions.EMailAddress = parser[NKey::kEmail].PostStrings.Front(); 1589 if (updateOptions.EMailAddress.Len() > 0) 1590 if (updateOptions.EMailAddress[0] == L'.') 1591 { 1592 updateOptions.EMailRemoveAfter = true; 1593 updateOptions.EMailAddress.Delete(0); 1594 } 1595 } 1596 1597 updateOptions.StdOutMode = options.StdOutMode; 1598 updateOptions.StdInMode = options.StdInMode; 1599 1600 updateOptions.DeleteAfterCompressing = parser[NKey::kDeleteAfterCompressing].ThereIs; 1601 updateOptions.SetArcMTime = parser[NKey::kSetArcMTime].ThereIs; 1602 1603 if (updateOptions.StdOutMode && updateOptions.EMailMode) 1604 throw CArcCmdLineException("stdout mode and email mode cannot be combined"); 1605 1606 if (updateOptions.StdOutMode) 1607 { 1608 if (options.IsStdOutTerminal) 1609 throw CArcCmdLineException(kTerminalOutError); 1610 1611 if (options.Number_for_Percents == k_OutStream_stdout 1612 || options.Number_for_Out == k_OutStream_stdout 1613 || options.Number_for_Errors == k_OutStream_stdout) 1614 throw CArcCmdLineException(kSameTerminalError); 1615 } 1616 1617 if (updateOptions.StdInMode) 1618 updateOptions.StdInFileName = parser[NKey::kStdIn].PostStrings.Front(); 1619 1620 if (options.Command.CommandType == NCommandType::kRename) 1621 if (updateOptions.Commands.Size() != 1) 1622 throw CArcCmdLineException("Only one archive can be created with rename command"); 1623 } 1624 else if (options.Command.CommandType == NCommandType::kBenchmark) 1625 { 1626 options.NumIterations = 1; 1627 options.NumIterations_Defined = false; 1628 if (curCommandIndex < numNonSwitchStrings) 1629 { 1630 if (!StringToUInt32(nonSwitchStrings[curCommandIndex], options.NumIterations)) 1631 throw CArcCmdLineException("Incorrect number of benchmark iterations", nonSwitchStrings[curCommandIndex]); 1632 curCommandIndex++; 1633 options.NumIterations_Defined = true; 1634 } 1635 } 1636 else if (options.Command.CommandType == NCommandType::kHash) 1637 { 1638 options.Censor.AddPathsToCensor(censorPathMode); 1639 options.Censor.ExtendExclude(); 1640 1641 CHashOptions &hashOptions = options.HashOptions; 1642 hashOptions.PathMode = censorPathMode; 1643 hashOptions.Methods = options.HashMethods; 1644 // hashOptions.HashFilePath = options.HashFilePath; 1645 if (parser[NKey::kPreserveATime].ThereIs) 1646 hashOptions.PreserveATime = true; 1647 if (parser[NKey::kShareForWrite].ThereIs) 1648 hashOptions.OpenShareForWrite = true; 1649 hashOptions.StdInMode = options.StdInMode; 1650 hashOptions.AltStreamsMode = options.AltStreams.Val; 1651 hashOptions.SymLinks = options.SymLinks; 1652 } 1653 else if (options.Command.CommandType == NCommandType::kInfo) 1654 { 1655 } 1656 else 1657 throw 20150919; 1658} 1659 1660 1661 1662#ifndef _WIN32 1663 1664static AString g_ModuleDirPrefix; 1665 1666void Set_ModuleDirPrefix_From_ProgArg0(const char *s); 1667void Set_ModuleDirPrefix_From_ProgArg0(const char *s) 1668{ 1669 AString a (s); 1670 int sep = a.ReverseFind_PathSepar(); 1671 a.DeleteFrom((unsigned)(sep + 1)); 1672 g_ModuleDirPrefix = a; 1673} 1674 1675namespace NWindows { 1676namespace NDLL { 1677 1678FString GetModuleDirPrefix(); 1679FString GetModuleDirPrefix() 1680{ 1681 FString s; 1682 1683 s = fas2fs(g_ModuleDirPrefix); 1684 if (s.IsEmpty()) 1685 s = FTEXT(".") FSTRING_PATH_SEPARATOR; 1686 return s; 1687 /* 1688 setenv("_7ZIP_HOME_DIR", "/test/", 0); 1689 const char *home = getenv("_7ZIP_HOME_DIR"); 1690 if (home) 1691 s = home; 1692 else 1693 s = FTEXT(".") FSTRING_PATH_SEPARATOR; 1694 return s; 1695 */ 1696} 1697 1698}} 1699 1700#endif // ! _WIN32 1701