diff options
Diffstat (limited to 'CPP')
| -rw-r--r-- | CPP/7zip/Bundles/Alone/Alone.dsp | 20 | ||||
| -rw-r--r-- | CPP/7zip/Compress/BZip2Encoder.cpp | 23 | ||||
| -rw-r--r-- | CPP/7zip/UI/Agent/AgentProxy.cpp | 2 | ||||
| -rw-r--r-- | CPP/7zip/UI/Client7z/makefile.gcc | 2 | ||||
| -rw-r--r-- | CPP/7zip/UI/Common/ArchiveCommandLine.cpp | 20 | ||||
| -rw-r--r-- | CPP/7zip/UI/Common/ArchiveExtractCallback.cpp | 544 | ||||
| -rw-r--r-- | CPP/7zip/UI/Common/ArchiveExtractCallback.h | 169 | ||||
| -rw-r--r-- | CPP/Windows/FileDir.cpp | 44 | ||||
| -rw-r--r-- | CPP/Windows/FileDir.h | 13 |
9 files changed, 561 insertions, 276 deletions
diff --git a/CPP/7zip/Bundles/Alone/Alone.dsp b/CPP/7zip/Bundles/Alone/Alone.dsp index beed5a7..558c41e 100644 --- a/CPP/7zip/Bundles/Alone/Alone.dsp +++ b/CPP/7zip/Bundles/Alone/Alone.dsp | |||
| @@ -1148,26 +1148,6 @@ SOURCE=..\..\Compress\PpmdZip.cpp | |||
| 1148 | SOURCE=..\..\Compress\PpmdZip.h | 1148 | SOURCE=..\..\Compress\PpmdZip.h |
| 1149 | # End Source File | 1149 | # End Source File |
| 1150 | # End Group | 1150 | # End Group |
| 1151 | # Begin Group "RangeCoder" | ||
| 1152 | |||
| 1153 | # PROP Default_Filter "" | ||
| 1154 | # Begin Source File | ||
| 1155 | |||
| 1156 | SOURCE=..\..\Compress\RangeCoder.h | ||
| 1157 | # End Source File | ||
| 1158 | # Begin Source File | ||
| 1159 | |||
| 1160 | SOURCE=..\..\Compress\RangeCoderBit.h | ||
| 1161 | # End Source File | ||
| 1162 | # Begin Source File | ||
| 1163 | |||
| 1164 | SOURCE=..\..\Compress\RangeCoderBitTree.h | ||
| 1165 | # End Source File | ||
| 1166 | # Begin Source File | ||
| 1167 | |||
| 1168 | SOURCE=..\..\Compress\RangeCoderOpt.h | ||
| 1169 | # End Source File | ||
| 1170 | # End Group | ||
| 1171 | # Begin Group "Shrink" | 1151 | # Begin Group "Shrink" |
| 1172 | 1152 | ||
| 1173 | # PROP Default_Filter "" | 1153 | # PROP Default_Filter "" |
diff --git a/CPP/7zip/Compress/BZip2Encoder.cpp b/CPP/7zip/Compress/BZip2Encoder.cpp index f8ee0c9..af0b312 100644 --- a/CPP/7zip/Compress/BZip2Encoder.cpp +++ b/CPP/7zip/Compress/BZip2Encoder.cpp | |||
| @@ -66,18 +66,14 @@ HRESULT CThreadInfo::Create() | |||
| 66 | if (wres == 0) { wres = CanWriteEvent.Create(); | 66 | if (wres == 0) { wres = CanWriteEvent.Create(); |
| 67 | if (wres == 0) | 67 | if (wres == 0) |
| 68 | { | 68 | { |
| 69 | wres = | ||
| 69 | #ifdef _WIN32 | 70 | #ifdef _WIN32 |
| 70 | if (Encoder->_props.NumThreadGroups != 0) | 71 | Encoder->_props.NumThreadGroups > 1 ? |
| 71 | { | 72 | Thread.Create_With_Group(MFThread, this, ThreadNextGroup_GetNext(&Encoder->ThreadNextGroup), 0) : // affinity |
| 72 | const UInt32 group = ThreadNextGroup_GetNext(&Encoder->ThreadNextGroup); | ||
| 73 | wres = Thread.Create_With_Group(MFThread, this, group, 0); // affinity | ||
| 74 | } | ||
| 75 | else | ||
| 76 | #endif | 73 | #endif |
| 77 | if (Encoder->_props.Affinity != 0) | 74 | Encoder->_props.Affinity != 0 ? |
| 78 | wres = Thread.Create_With_Affinity(MFThread, this, (CAffinityMask)Encoder->_props.Affinity); | 75 | Thread.Create_With_Affinity(MFThread, this, (CAffinityMask)Encoder->_props.Affinity) : |
| 79 | else | 76 | Thread.Create(MFThread, this); |
| 80 | wres = Thread.Create(MFThread, this); | ||
| 81 | }}} | 77 | }}} |
| 82 | return HRESULT_FROM_WIN32(wres); | 78 | return HRESULT_FROM_WIN32(wres); |
| 83 | } | 79 | } |
| @@ -935,14 +931,13 @@ void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, unsigned lastByte | |||
| 935 | HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, | 931 | HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, |
| 936 | const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) | 932 | const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) |
| 937 | { | 933 | { |
| 938 | ThreadNextGroup_Init(&ThreadNextGroup, _props.NumThreadGroups, 0); // startGroup | ||
| 939 | |||
| 940 | NumBlocks = 0; | 934 | NumBlocks = 0; |
| 941 | #ifndef Z7_ST | 935 | #ifndef Z7_ST |
| 942 | Progress = progress; | 936 | Progress = progress; |
| 937 | ThreadNextGroup_Init(&ThreadNextGroup, _props.NumThreadGroups, 0); // startGroup | ||
| 943 | RINOK(Create()) | 938 | RINOK(Create()) |
| 944 | for (UInt32 t = 0; t < NumThreads; t++) | 939 | for (UInt32 t = 0; t < NumThreads; t++) |
| 945 | #endif | 940 | #endif |
| 946 | { | 941 | { |
| 947 | #ifndef Z7_ST | 942 | #ifndef Z7_ST |
| 948 | CThreadInfo &ti = ThreadsInfo[t]; | 943 | CThreadInfo &ti = ThreadsInfo[t]; |
diff --git a/CPP/7zip/UI/Agent/AgentProxy.cpp b/CPP/7zip/UI/Agent/AgentProxy.cpp index 176f39b..d04ddab 100644 --- a/CPP/7zip/UI/Agent/AgentProxy.cpp +++ b/CPP/7zip/UI/Agent/AgentProxy.cpp | |||
| @@ -636,7 +636,7 @@ HRESULT CProxyArc2::Load(const CArc &arc, IProgress *progress) | |||
| 636 | file.Name = (const wchar_t *)p; | 636 | file.Name = (const wchar_t *)p; |
| 637 | file.NameLen = 0; | 637 | file.NameLen = 0; |
| 638 | if (size >= sizeof(wchar_t)) | 638 | if (size >= sizeof(wchar_t)) |
| 639 | file.NameLen = size / sizeof(wchar_t) - 1; | 639 | file.NameLen = size / (unsigned)sizeof(wchar_t) - 1; |
| 640 | } | 640 | } |
| 641 | else | 641 | else |
| 642 | #endif | 642 | #endif |
diff --git a/CPP/7zip/UI/Client7z/makefile.gcc b/CPP/7zip/UI/Client7z/makefile.gcc index fe27011..0f89cb0 100644 --- a/CPP/7zip/UI/Client7z/makefile.gcc +++ b/CPP/7zip/UI/Client7z/makefile.gcc | |||
| @@ -24,7 +24,6 @@ else | |||
| 24 | 24 | ||
| 25 | SYS_OBJS = \ | 25 | SYS_OBJS = \ |
| 26 | $O/MyWindows.o \ | 26 | $O/MyWindows.o \ |
| 27 | $O/TimeUtils.o \ | ||
| 28 | 27 | ||
| 29 | endif | 28 | endif |
| 30 | 29 | ||
| @@ -53,6 +52,7 @@ WIN_OBJS = \ | |||
| 53 | $O/FileName.o \ | 52 | $O/FileName.o \ |
| 54 | $O/PropVariant.o \ | 53 | $O/PropVariant.o \ |
| 55 | $O/PropVariantConv.o \ | 54 | $O/PropVariantConv.o \ |
| 55 | $O/TimeUtils.o \ | ||
| 56 | 56 | ||
| 57 | 7ZIP_COMMON_OBJS = \ | 57 | 7ZIP_COMMON_OBJS = \ |
| 58 | $O/FileStreams.o \ | 58 | $O/FileStreams.o \ |
diff --git a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp index de9f43e..7fe18fb 100644 --- a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp +++ b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp | |||
| @@ -341,7 +341,7 @@ static const CSwitchForm kSwitchForms[] = | |||
| 341 | { "spf", SWFRM_STRING_SINGL(0) }, | 341 | { "spf", SWFRM_STRING_SINGL(0) }, |
| 342 | 342 | ||
| 343 | { "snh", SWFRM_MINUS }, | 343 | { "snh", SWFRM_MINUS }, |
| 344 | { "snld", SWFRM_MINUS }, | 344 | { "snld", SWFRM_STRING }, |
| 345 | { "snl", SWFRM_MINUS }, | 345 | { "snl", SWFRM_MINUS }, |
| 346 | { "sni", SWFRM_SIMPLE }, | 346 | { "sni", SWFRM_SIMPLE }, |
| 347 | 347 | ||
| @@ -1479,14 +1479,8 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) | |||
| 1479 | 1479 | ||
| 1480 | SetBoolPair(parser, NKey::kStoreOwnerId, options.StoreOwnerId); | 1480 | SetBoolPair(parser, NKey::kStoreOwnerId, options.StoreOwnerId); |
| 1481 | SetBoolPair(parser, NKey::kStoreOwnerName, options.StoreOwnerName); | 1481 | SetBoolPair(parser, NKey::kStoreOwnerName, options.StoreOwnerName); |
| 1482 | |||
| 1483 | CBoolPair symLinks_AllowDangerous; | ||
| 1484 | SetBoolPair(parser, NKey::kSymLinks_AllowDangerous, symLinks_AllowDangerous); | ||
| 1485 | |||
| 1486 | |||
| 1487 | /* | 1482 | /* |
| 1488 | bool supportSymLink = options.SymLinks.Val; | 1483 | bool supportSymLink = options.SymLinks.Val; |
| 1489 | |||
| 1490 | if (!options.SymLinks.Def) | 1484 | if (!options.SymLinks.Def) |
| 1491 | { | 1485 | { |
| 1492 | if (isExtractOrList) | 1486 | if (isExtractOrList) |
| @@ -1494,7 +1488,6 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) | |||
| 1494 | else | 1488 | else |
| 1495 | supportSymLink = false; | 1489 | supportSymLink = false; |
| 1496 | } | 1490 | } |
| 1497 | |||
| 1498 | #ifdef ENV_HAVE_LSTAT | 1491 | #ifdef ENV_HAVE_LSTAT |
| 1499 | if (supportSymLink) | 1492 | if (supportSymLink) |
| 1500 | global_use_lstat = 1; | 1493 | global_use_lstat = 1; |
| @@ -1503,7 +1496,6 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) | |||
| 1503 | #endif | 1496 | #endif |
| 1504 | */ | 1497 | */ |
| 1505 | 1498 | ||
| 1506 | |||
| 1507 | if (isExtractOrList) | 1499 | if (isExtractOrList) |
| 1508 | { | 1500 | { |
| 1509 | CExtractOptionsBase &eo = options.ExtractOptions; | 1501 | CExtractOptionsBase &eo = options.ExtractOptions; |
| @@ -1527,7 +1519,15 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) | |||
| 1527 | if (!options.SymLinks.Def) | 1519 | if (!options.SymLinks.Def) |
| 1528 | nt.SymLinks.Val = true; | 1520 | nt.SymLinks.Val = true; |
| 1529 | 1521 | ||
| 1530 | nt.SymLinks_AllowDangerous = symLinks_AllowDangerous; | 1522 | if (parser[NKey::kSymLinks_AllowDangerous].ThereIs) |
| 1523 | { | ||
| 1524 | const UString &s = parser[NKey::kSymLinks_AllowDangerous].PostStrings[0]; | ||
| 1525 | UInt32 v = 9; // default value for "-snld" instead of default = 5 without "-snld". | ||
| 1526 | if (!s.IsEmpty()) | ||
| 1527 | if (!StringToUInt32(s, v)) | ||
| 1528 | throw CArcCmdLineException("Unsupported switch postfix -snld", s); | ||
| 1529 | nt.SymLinks_DangerousLevel = (unsigned)v; | ||
| 1530 | } | ||
| 1531 | 1531 | ||
| 1532 | nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs; | 1532 | nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs; |
| 1533 | nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs; | 1533 | nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs; |
diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp index 3abcd2d..6631629 100644 --- a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp +++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp | |||
| @@ -54,10 +54,14 @@ static const char * const kCantSetFileLen = "Cannot set length for output file"; | |||
| 54 | #ifdef SUPPORT_LINKS | 54 | #ifdef SUPPORT_LINKS |
| 55 | static const char * const kCantCreateHardLink = "Cannot create hard link"; | 55 | static const char * const kCantCreateHardLink = "Cannot create hard link"; |
| 56 | static const char * const kCantCreateSymLink = "Cannot create symbolic link"; | 56 | static const char * const kCantCreateSymLink = "Cannot create symbolic link"; |
| 57 | static const char * const k_HardLink_to_SymLink_Ignored = "Hard link to symbolic link was ignored"; | ||
| 58 | static const char * const k_CantDelete_File_for_SymLink = "Cannot delete file for symbolic link creation"; | ||
| 59 | static const char * const k_CantDelete_Dir_for_SymLink = "Cannot delete directory for symbolic link creation"; | ||
| 57 | #endif | 60 | #endif |
| 58 | 61 | ||
| 59 | static const unsigned k_LinkDataSize_LIMIT = 1 << 12; | 62 | static const unsigned k_LinkDataSize_LIMIT = 1 << 12; |
| 60 | 63 | ||
| 64 | #ifdef SUPPORT_LINKS | ||
| 61 | #if WCHAR_PATH_SEPARATOR != L'/' | 65 | #if WCHAR_PATH_SEPARATOR != L'/' |
| 62 | // we convert linux slashes to windows slashes for further processing. | 66 | // we convert linux slashes to windows slashes for further processing. |
| 63 | // also we convert linux backslashes to BackslashReplacement character. | 67 | // also we convert linux backslashes to BackslashReplacement character. |
| @@ -67,7 +71,7 @@ static const unsigned k_LinkDataSize_LIMIT = 1 << 12; | |||
| 67 | #else | 71 | #else |
| 68 | #define REPLACE_SLASHES_from_Linux_to_Sys(s) | 72 | #define REPLACE_SLASHES_from_Linux_to_Sys(s) |
| 69 | #endif | 73 | #endif |
| 70 | 74 | #endif | |
| 71 | 75 | ||
| 72 | #ifndef Z7_SFX | 76 | #ifndef Z7_SFX |
| 73 | 77 | ||
| @@ -326,13 +330,14 @@ void CArchiveExtractCallback::Init( | |||
| 326 | _outFileStream.Release(); | 330 | _outFileStream.Release(); |
| 327 | _bufPtrSeqOutStream.Release(); | 331 | _bufPtrSeqOutStream.Release(); |
| 328 | 332 | ||
| 329 | #ifdef SUPPORT_LINKS | 333 | #ifdef SUPPORT_LINKS |
| 330 | _hardLinks.Clear(); | 334 | _hardLinks.Clear(); |
| 331 | #endif | 335 | _postLinks.Clear(); |
| 336 | #endif | ||
| 332 | 337 | ||
| 333 | #ifdef SUPPORT_ALT_STREAMS | 338 | #ifdef SUPPORT_ALT_STREAMS |
| 334 | _renamedFiles.Clear(); | 339 | _renamedFiles.Clear(); |
| 335 | #endif | 340 | #endif |
| 336 | 341 | ||
| 337 | _ntOptions = ntOptions; | 342 | _ntOptions = ntOptions; |
| 338 | _wildcardCensor = wildcardCensor; | 343 | _wildcardCensor = wildcardCensor; |
| @@ -455,7 +460,8 @@ Z7_COM7F_IMF(CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const U | |||
| 455 | } | 460 | } |
| 456 | 461 | ||
| 457 | 462 | ||
| 458 | void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath) | 463 | void CArchiveExtractCallback::CreateComplexDirectory( |
| 464 | const UStringVector &dirPathParts, bool isFinal, FString &fullPath) | ||
| 459 | { | 465 | { |
| 460 | // we use (_item.IsDir) in this function | 466 | // we use (_item.IsDir) in this function |
| 461 | 467 | ||
| @@ -487,7 +493,7 @@ void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPat | |||
| 487 | const UString &s = dirPathParts[i]; | 493 | const UString &s = dirPathParts[i]; |
| 488 | fullPath += us2fs(s); | 494 | fullPath += us2fs(s); |
| 489 | 495 | ||
| 490 | const bool isFinalDir = (i == dirPathParts.Size() - 1 && _item.IsDir); | 496 | const bool isFinalDir = (i == dirPathParts.Size() - 1 && isFinal && _item.IsDir); |
| 491 | 497 | ||
| 492 | if (fullPath.IsEmpty()) | 498 | if (fullPath.IsEmpty()) |
| 493 | { | 499 | { |
| @@ -548,7 +554,7 @@ static void AddPathToMessage(UString &s, const FString &path) | |||
| 548 | s += fs2us(path); | 554 | s += fs2us(path); |
| 549 | } | 555 | } |
| 550 | 556 | ||
| 551 | HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FString &path) | 557 | HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FString &path) const |
| 552 | { | 558 | { |
| 553 | UString s (message); | 559 | UString s (message); |
| 554 | AddPathToMessage(s, path); | 560 | AddPathToMessage(s, path); |
| @@ -556,7 +562,7 @@ HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FSt | |||
| 556 | } | 562 | } |
| 557 | 563 | ||
| 558 | 564 | ||
| 559 | HRESULT CArchiveExtractCallback::SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path) | 565 | HRESULT CArchiveExtractCallback::SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path) const |
| 560 | { | 566 | { |
| 561 | UString s (message); | 567 | UString s (message); |
| 562 | if (errorCode != S_OK) | 568 | if (errorCode != S_OK) |
| @@ -568,13 +574,13 @@ HRESULT CArchiveExtractCallback::SendMessageError_with_Error(HRESULT errorCode, | |||
| 568 | return _extractCallback2->MessageError(s); | 574 | return _extractCallback2->MessageError(s); |
| 569 | } | 575 | } |
| 570 | 576 | ||
| 571 | HRESULT CArchiveExtractCallback::SendMessageError_with_LastError(const char *message, const FString &path) | 577 | HRESULT CArchiveExtractCallback::SendMessageError_with_LastError(const char *message, const FString &path) const |
| 572 | { | 578 | { |
| 573 | const HRESULT errorCode = GetLastError_noZero_HRESULT(); | 579 | const HRESULT errorCode = GetLastError_noZero_HRESULT(); |
| 574 | return SendMessageError_with_Error(errorCode, message, path); | 580 | return SendMessageError_with_Error(errorCode, message, path); |
| 575 | } | 581 | } |
| 576 | 582 | ||
| 577 | HRESULT CArchiveExtractCallback::SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2) | 583 | HRESULT CArchiveExtractCallback::SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2) const |
| 578 | { | 584 | { |
| 579 | UString s (message); | 585 | UString s (message); |
| 580 | if (errorCode != 0) | 586 | if (errorCode != 0) |
| @@ -588,7 +594,7 @@ HRESULT CArchiveExtractCallback::SendMessageError2(HRESULT errorCode, const char | |||
| 588 | } | 594 | } |
| 589 | 595 | ||
| 590 | HRESULT CArchiveExtractCallback::SendMessageError2_with_LastError( | 596 | HRESULT CArchiveExtractCallback::SendMessageError2_with_LastError( |
| 591 | const char *message, const FString &path1, const FString &path2) | 597 | const char *message, const FString &path1, const FString &path2) const |
| 592 | { | 598 | { |
| 593 | const HRESULT errorCode = GetLastError_noZero_HRESULT(); | 599 | const HRESULT errorCode = GetLastError_noZero_HRESULT(); |
| 594 | return SendMessageError2(errorCode, message, path1, path2); | 600 | return SendMessageError2(errorCode, message, path1, path2); |
| @@ -627,6 +633,7 @@ Z7_COM7F_IMF(CGetProp::GetProp(PROPID propID, PROPVARIANT *value)) | |||
| 627 | struct CLinkLevelsInfo | 633 | struct CLinkLevelsInfo |
| 628 | { | 634 | { |
| 629 | bool IsAbsolute; | 635 | bool IsAbsolute; |
| 636 | bool ParentDirDots_after_NonParent; | ||
| 630 | int LowLevel; | 637 | int LowLevel; |
| 631 | int FinalLevel; | 638 | int FinalLevel; |
| 632 | 639 | ||
| @@ -640,6 +647,8 @@ void CLinkLevelsInfo::Parse(const UString &path, bool isWSL) | |||
| 640 | NName::IsAbsolutePath(path); | 647 | NName::IsAbsolutePath(path); |
| 641 | LowLevel = 0; | 648 | LowLevel = 0; |
| 642 | FinalLevel = 0; | 649 | FinalLevel = 0; |
| 650 | ParentDirDots_after_NonParent = false; | ||
| 651 | bool nonParentDir = false; | ||
| 643 | 652 | ||
| 644 | UStringVector parts; | 653 | UStringVector parts; |
| 645 | SplitPathToParts(path, parts); | 654 | SplitPathToParts(path, parts); |
| @@ -658,12 +667,17 @@ void CLinkLevelsInfo::Parse(const UString &path, bool isWSL) | |||
| 658 | continue; | 667 | continue; |
| 659 | if (s.IsEqualTo("..")) | 668 | if (s.IsEqualTo("..")) |
| 660 | { | 669 | { |
| 670 | if (IsAbsolute || nonParentDir) | ||
| 671 | ParentDirDots_after_NonParent = true; | ||
| 661 | level--; | 672 | level--; |
| 662 | if (LowLevel > level) | 673 | if (LowLevel > level) |
| 663 | LowLevel = level; | 674 | LowLevel = level; |
| 664 | } | 675 | } |
| 665 | else | 676 | else |
| 677 | { | ||
| 678 | nonParentDir = true; | ||
| 666 | level++; | 679 | level++; |
| 680 | } | ||
| 667 | } | 681 | } |
| 668 | 682 | ||
| 669 | FinalLevel = level; | 683 | FinalLevel = level; |
| @@ -915,7 +929,7 @@ HRESULT CArchiveExtractCallback::ReadLink() | |||
| 915 | #ifndef _WIN32 | 929 | #ifndef _WIN32 |
| 916 | 930 | ||
| 917 | static HRESULT GetOwner(IInArchive *archive, | 931 | static HRESULT GetOwner(IInArchive *archive, |
| 918 | UInt32 index, UInt32 pidName, UInt32 pidId, COwnerInfo &res) | 932 | UInt32 index, UInt32 pidName, UInt32 pidId, CProcessedFileInfo::COwnerInfo &res) |
| 919 | { | 933 | { |
| 920 | { | 934 | { |
| 921 | NWindows::NCOM::CPropVariant prop; | 935 | NWindows::NCOM::CPropVariant prop; |
| @@ -1047,7 +1061,7 @@ void CArchiveExtractCallback::CorrectPathParts() | |||
| 1047 | } | 1061 | } |
| 1048 | 1062 | ||
| 1049 | 1063 | ||
| 1050 | void CArchiveExtractCallback::GetFiTimesCAM(CFiTimesCAM &pt) | 1064 | static void GetFiTimesCAM(const CProcessedFileInfo &fi, CFiTimesCAM &pt, const CArc &arc) |
| 1051 | { | 1065 | { |
| 1052 | pt.CTime_Defined = false; | 1066 | pt.CTime_Defined = false; |
| 1053 | pt.ATime_Defined = false; | 1067 | pt.ATime_Defined = false; |
| @@ -1055,27 +1069,27 @@ void CArchiveExtractCallback::GetFiTimesCAM(CFiTimesCAM &pt) | |||
| 1055 | 1069 | ||
| 1056 | // if (Write_MTime) | 1070 | // if (Write_MTime) |
| 1057 | { | 1071 | { |
| 1058 | if (_fi.MTime.Def) | 1072 | if (fi.MTime.Def) |
| 1059 | { | 1073 | { |
| 1060 | _fi.MTime.Write_To_FiTime(pt.MTime); | 1074 | fi.MTime.Write_To_FiTime(pt.MTime); |
| 1061 | pt.MTime_Defined = true; | 1075 | pt.MTime_Defined = true; |
| 1062 | } | 1076 | } |
| 1063 | else if (_arc->MTime.Def) | 1077 | else if (arc.MTime.Def) |
| 1064 | { | 1078 | { |
| 1065 | _arc->MTime.Write_To_FiTime(pt.MTime); | 1079 | arc.MTime.Write_To_FiTime(pt.MTime); |
| 1066 | pt.MTime_Defined = true; | 1080 | pt.MTime_Defined = true; |
| 1067 | } | 1081 | } |
| 1068 | } | 1082 | } |
| 1069 | 1083 | ||
| 1070 | if (/* Write_CTime && */ _fi.CTime.Def) | 1084 | if (/* Write_CTime && */ fi.CTime.Def) |
| 1071 | { | 1085 | { |
| 1072 | _fi.CTime.Write_To_FiTime(pt.CTime); | 1086 | fi.CTime.Write_To_FiTime(pt.CTime); |
| 1073 | pt.CTime_Defined = true; | 1087 | pt.CTime_Defined = true; |
| 1074 | } | 1088 | } |
| 1075 | 1089 | ||
| 1076 | if (/* Write_ATime && */ _fi.ATime.Def) | 1090 | if (/* Write_ATime && */ fi.ATime.Def) |
| 1077 | { | 1091 | { |
| 1078 | _fi.ATime.Write_To_FiTime(pt.ATime); | 1092 | fi.ATime.Write_To_FiTime(pt.ATime); |
| 1079 | pt.ATime_Defined = true; | 1093 | pt.ATime_Defined = true; |
| 1080 | } | 1094 | } |
| 1081 | } | 1095 | } |
| @@ -1086,6 +1100,7 @@ void CArchiveExtractCallback::CreateFolders() | |||
| 1086 | // 21.04 : we don't change original (_item.PathParts) here | 1100 | // 21.04 : we don't change original (_item.PathParts) here |
| 1087 | UStringVector pathParts = _item.PathParts; | 1101 | UStringVector pathParts = _item.PathParts; |
| 1088 | 1102 | ||
| 1103 | bool isFinal = true; | ||
| 1089 | // bool is_DirOp = false; | 1104 | // bool is_DirOp = false; |
| 1090 | if (!pathParts.IsEmpty()) | 1105 | if (!pathParts.IsEmpty()) |
| 1091 | { | 1106 | { |
| @@ -1095,12 +1110,15 @@ void CArchiveExtractCallback::CreateFolders() | |||
| 1095 | but if we create dir item here, it's not problem. */ | 1110 | but if we create dir item here, it's not problem. */ |
| 1096 | if (!_item.IsDir | 1111 | if (!_item.IsDir |
| 1097 | #ifdef SUPPORT_LINKS | 1112 | #ifdef SUPPORT_LINKS |
| 1098 | #ifndef WIN32 | 1113 | // #ifndef WIN32 |
| 1099 | || !_link.LinkPath.IsEmpty() | 1114 | || !_link.LinkPath.IsEmpty() |
| 1100 | #endif | 1115 | // #endif |
| 1101 | #endif | 1116 | #endif |
| 1102 | ) | 1117 | ) |
| 1118 | { | ||
| 1103 | pathParts.DeleteBack(); | 1119 | pathParts.DeleteBack(); |
| 1120 | isFinal = false; // last path part was excluded | ||
| 1121 | } | ||
| 1104 | // else is_DirOp = true; | 1122 | // else is_DirOp = true; |
| 1105 | } | 1123 | } |
| 1106 | 1124 | ||
| @@ -1124,7 +1142,7 @@ void CArchiveExtractCallback::CreateFolders() | |||
| 1124 | */ | 1142 | */ |
| 1125 | 1143 | ||
| 1126 | FString fullPathNew; | 1144 | FString fullPathNew; |
| 1127 | CreateComplexDirectory(pathParts, fullPathNew); | 1145 | CreateComplexDirectory(pathParts, isFinal, fullPathNew); |
| 1128 | 1146 | ||
| 1129 | /* | 1147 | /* |
| 1130 | if (is_DirOp) | 1148 | if (is_DirOp) |
| @@ -1145,12 +1163,12 @@ void CArchiveExtractCallback::CreateFolders() | |||
| 1145 | return; | 1163 | return; |
| 1146 | 1164 | ||
| 1147 | CDirPathTime pt; | 1165 | CDirPathTime pt; |
| 1148 | GetFiTimesCAM(pt); | 1166 | GetFiTimesCAM(_fi, pt, *_arc); |
| 1149 | 1167 | ||
| 1150 | if (pt.IsSomeTimeDefined()) | 1168 | if (pt.IsSomeTimeDefined()) |
| 1151 | { | 1169 | { |
| 1152 | pt.Path = fullPathNew; | 1170 | pt.Path = fullPathNew; |
| 1153 | pt.SetDirTime(); | 1171 | pt.SetDirTime_to_FS_2(); |
| 1154 | _extractedFolders.Add(pt); | 1172 | _extractedFolders.Add(pt); |
| 1155 | } | 1173 | } |
| 1156 | } | 1174 | } |
| @@ -1292,9 +1310,11 @@ HRESULT CArchiveExtractCallback::CheckExistFile(FString &fullProcessedPath, bool | |||
| 1292 | 1310 | ||
| 1293 | 1311 | ||
| 1294 | 1312 | ||
| 1295 | 1313 | /* | |
| 1296 | 1314 | return: | |
| 1297 | 1315 | needExit = false: caller will use (outStreamLoc) and _hashStreamSpec | |
| 1316 | needExit = true : caller will not use (outStreamLoc) and _hashStreamSpec. | ||
| 1317 | */ | ||
| 1298 | HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream> &outStreamLoc, bool &needExit) | 1318 | HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream> &outStreamLoc, bool &needExit) |
| 1299 | { | 1319 | { |
| 1300 | needExit = true; | 1320 | needExit = true; |
| @@ -1383,12 +1403,15 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream | |||
| 1383 | { | 1403 | { |
| 1384 | bool linkWasSet = false; | 1404 | bool linkWasSet = false; |
| 1385 | RINOK(SetLink(fullProcessedPath, _link, linkWasSet)) | 1405 | RINOK(SetLink(fullProcessedPath, _link, linkWasSet)) |
| 1406 | /* | ||
| 1407 | // we don't set attributes for placeholder. | ||
| 1386 | if (linkWasSet) | 1408 | if (linkWasSet) |
| 1387 | { | 1409 | { |
| 1388 | _isSymLinkCreated = _link.Is_AnySymLink(); | 1410 | _isSymLinkCreated = _link.Is_AnySymLink(); |
| 1389 | SetAttrib(); | 1411 | SetAttrib(); |
| 1390 | // printf("\nlinkWasSet %s\n", GetAnsiString(_diskFilePath)); | 1412 | // printf("\nlinkWasSet %s\n", GetAnsiString(_diskFilePath)); |
| 1391 | } | 1413 | } |
| 1414 | */ | ||
| 1392 | } | 1415 | } |
| 1393 | #endif // UNDER_CE | 1416 | #endif // UNDER_CE |
| 1394 | 1417 | ||
| @@ -1414,11 +1437,17 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream | |||
| 1414 | hl = fullProcessedPath; | 1437 | hl = fullProcessedPath; |
| 1415 | else | 1438 | else |
| 1416 | { | 1439 | { |
| 1417 | if (!MyCreateHardLink(fullProcessedPath, hl)) | 1440 | bool link_was_Created = false; |
| 1418 | return SendMessageError2_with_LastError(kCantCreateHardLink, fullProcessedPath, hl); | 1441 | RINOK(CreateHardLink2(fullProcessedPath, hl, link_was_Created)) |
| 1442 | if (!link_was_Created) | ||
| 1443 | return S_OK; | ||
| 1419 | // printf("\nHard linkWasSet Archive_Get_HardLinkNode %s\n", GetAnsiString(_diskFilePath)); | 1444 | // printf("\nHard linkWasSet Archive_Get_HardLinkNode %s\n", GetAnsiString(_diskFilePath)); |
| 1420 | // _needSetAttrib = true; // do we need to set attribute ? | 1445 | // _needSetAttrib = true; // do we need to set attribute ? |
| 1421 | SetAttrib(); | 1446 | SetAttrib(); |
| 1447 | /* if we set (needExit = false) here, _hashStreamSpec will be used, | ||
| 1448 | and hash will be calulated for all hard links files (it's slower). | ||
| 1449 | But "Test" operation also calculates hashes. | ||
| 1450 | */ | ||
| 1422 | needExit = false; | 1451 | needExit = false; |
| 1423 | return S_OK; | 1452 | return S_OK; |
| 1424 | } | 1453 | } |
| @@ -1943,7 +1972,7 @@ HRESULT CArchiveExtractCallback::CloseFile() | |||
| 1943 | #endif | 1972 | #endif |
| 1944 | 1973 | ||
| 1945 | CFiTimesCAM t; | 1974 | CFiTimesCAM t; |
| 1946 | GetFiTimesCAM(t); | 1975 | GetFiTimesCAM(_fi, t, *_arc); |
| 1947 | 1976 | ||
| 1948 | // #ifdef _WIN32 | 1977 | // #ifdef _WIN32 |
| 1949 | if (t.IsSomeTimeDefined()) | 1978 | if (t.IsSomeTimeDefined()) |
| @@ -1970,52 +1999,219 @@ HRESULT CArchiveExtractCallback::CloseFile() | |||
| 1970 | 1999 | ||
| 1971 | #ifdef SUPPORT_LINKS | 2000 | #ifdef SUPPORT_LINKS |
| 1972 | 2001 | ||
| 2002 | static bool CheckLinkPath_in_FS_for_pathParts(const FString &path, const UStringVector &v) | ||
| 2003 | { | ||
| 2004 | FString path2 = path; | ||
| 2005 | FOR_VECTOR (i, v) | ||
| 2006 | { | ||
| 2007 | // if (i == v.Size() - 1) path = path2; // we don't need last part in returned path | ||
| 2008 | path2 += us2fs(v[i]); | ||
| 2009 | NFind::CFileInfo fi; | ||
| 2010 | // printf("\nCheckLinkPath_in_FS_for_pathParts(): %s\n", GetOemString(path2).Ptr()); | ||
| 2011 | if (fi.Find(path2) && fi.IsOsSymLink()) | ||
| 2012 | return false; | ||
| 2013 | path2.Add_PathSepar(); | ||
| 2014 | } | ||
| 2015 | return true; | ||
| 2016 | } | ||
| 2017 | |||
| 1973 | /* | 2018 | /* |
| 1974 | in: | 2019 | link.isRelative / relative_item_PathPrefix |
| 1975 | link.LinkPath : must be relative (non-absolute) path in any case !!! | 2020 | false / empty |
| 1976 | link.isRelative / target path that must stored as created link: | 2021 | true / item path without last part |
| 1977 | == false / _dirPathPrefix_Full + link.LinkPath | ||
| 1978 | == true / link.LinkPath | ||
| 1979 | */ | 2022 | */ |
| 2023 | static bool CheckLinkPath_in_FS( | ||
| 2024 | const FString &pathPrefix_in_FS, | ||
| 2025 | const CPostLink &postLink, | ||
| 2026 | const UString &relative_item_PathPrefix) | ||
| 2027 | { | ||
| 2028 | const CLinkInfo &link = postLink.LinkInfo; | ||
| 2029 | if (postLink.item_PathParts.IsEmpty() || link.LinkPath.IsEmpty()) | ||
| 2030 | return false; | ||
| 2031 | FString path; | ||
| 2032 | { | ||
| 2033 | const UString &s = postLink.item_PathParts[0]; | ||
| 2034 | if (!s.IsEmpty() && !NName::IsAbsolutePath(s)) | ||
| 2035 | path = pathPrefix_in_FS; // item_PathParts is relative. So we use absolutre prefix | ||
| 2036 | } | ||
| 2037 | if (!CheckLinkPath_in_FS_for_pathParts(path, postLink.item_PathParts)) | ||
| 2038 | return false; | ||
| 2039 | path += us2fs(relative_item_PathPrefix); | ||
| 2040 | UStringVector v; | ||
| 2041 | SplitPathToParts(link.LinkPath, v); | ||
| 2042 | // we check target paths: | ||
| 2043 | return CheckLinkPath_in_FS_for_pathParts(path, v); | ||
| 2044 | } | ||
| 2045 | |||
| 2046 | static const unsigned k_DangLevel_MAX_for_Link_over_Link = 9; | ||
| 2047 | |||
| 2048 | HRESULT CArchiveExtractCallback::CreateHardLink2( | ||
| 2049 | const FString &newFilePath, const FString &existFilePath, bool &link_was_Created) const | ||
| 2050 | { | ||
| 2051 | link_was_Created = false; | ||
| 2052 | if (_ntOptions.SymLinks_DangerousLevel <= k_DangLevel_MAX_for_Link_over_Link) | ||
| 2053 | { | ||
| 2054 | NFind::CFileInfo fi; | ||
| 2055 | if (fi.Find(existFilePath) && fi.IsOsSymLink()) | ||
| 2056 | return SendMessageError2(0, k_HardLink_to_SymLink_Ignored, newFilePath, existFilePath); | ||
| 2057 | } | ||
| 2058 | if (!MyCreateHardLink(newFilePath, existFilePath)) | ||
| 2059 | return SendMessageError2_with_LastError(kCantCreateHardLink, newFilePath, existFilePath); | ||
| 2060 | link_was_Created = true; | ||
| 2061 | return S_OK; | ||
| 2062 | } | ||
| 2063 | |||
| 2064 | |||
| 1980 | 2065 | ||
| 1981 | HRESULT CArchiveExtractCallback::SetLink( | 2066 | HRESULT CArchiveExtractCallback::SetLink( |
| 1982 | const FString &fullProcessedPath_from, | 2067 | const FString &fullProcessedPath_from, |
| 1983 | const CLinkInfo &link, | 2068 | const CLinkInfo &link, |
| 1984 | bool &linkWasSet) | 2069 | bool &linkWasSet) // placeholder was created |
| 1985 | { | 2070 | { |
| 1986 | linkWasSet = false; | 2071 | linkWasSet = false; |
| 1987 | if (link.LinkPath.IsEmpty()) | 2072 | if (link.LinkPath.IsEmpty()) |
| 1988 | return S_OK; | 2073 | return S_OK; |
| 1989 | if (!_ntOptions.SymLinks.Val && link.Is_AnySymLink()) | 2074 | if (!_ntOptions.SymLinks.Val && link.Is_AnySymLink()) |
| 1990 | return S_OK; | 2075 | return S_OK; |
| 2076 | CPostLink postLink; | ||
| 2077 | postLink.Index_in_Arc = _index; | ||
| 2078 | postLink.item_IsDir = _item.IsDir; | ||
| 2079 | postLink.item_Path = _item.Path; | ||
| 2080 | postLink.item_PathParts = _item.PathParts; | ||
| 2081 | postLink.item_FileInfo = _fi; | ||
| 2082 | postLink.fullProcessedPath_from = fullProcessedPath_from; | ||
| 2083 | postLink.LinkInfo = link; | ||
| 2084 | _postLinks.Add(postLink); | ||
| 2085 | |||
| 2086 | // file doesn't exist in most cases. So we don't check for error. | ||
| 2087 | DeleteLinkFileAlways_or_RemoveEmptyDir(fullProcessedPath_from, false); // checkThatFileIsEmpty = false | ||
| 2088 | |||
| 2089 | NIO::COutFile outFile; | ||
| 2090 | if (!outFile.Create_NEW(fullProcessedPath_from)) | ||
| 2091 | return SendMessageError("Cannot create temporary link file", fullProcessedPath_from); | ||
| 2092 | #if 0 // 1 for debug | ||
| 2093 | // here we can write link path to temporary link file placeholder, | ||
| 2094 | // but empty placeholder is better, because we don't want to get any non-eampty data instead of link file. | ||
| 2095 | AString s; | ||
| 2096 | ConvertUnicodeToUTF8(link.LinkPath, s); | ||
| 2097 | outFile.WriteFull(s, s.Len()); | ||
| 2098 | #endif | ||
| 2099 | linkWasSet = true; | ||
| 2100 | return S_OK; | ||
| 2101 | } | ||
| 2102 | |||
| 2103 | |||
| 2104 | // if file/dir is symbolic link it will remove only link itself | ||
| 2105 | HRESULT CArchiveExtractCallback::DeleteLinkFileAlways_or_RemoveEmptyDir( | ||
| 2106 | const FString &path, bool checkThatFileIsEmpty) const | ||
| 2107 | { | ||
| 2108 | NFile::NFind::CFileInfo fi; | ||
| 2109 | if (fi.Find(path)) // followLink = false | ||
| 1991 | { | 2110 | { |
| 1992 | UString path; | 2111 | if (fi.IsDir()) |
| 1993 | if (link.isRelative) | ||
| 1994 | { | 2112 | { |
| 1995 | // _item.PathParts : parts that will be created in output folder. | 2113 | if (RemoveDirAlways_if_Empty(path)) |
| 1996 | // we want to get directory prefix of link item. | 2114 | return S_OK; |
| 1997 | // so we remove file name (last non-empty part) from PathParts: | ||
| 1998 | UStringVector v = _item.PathParts; | ||
| 1999 | while (!v.IsEmpty()) | ||
| 2000 | { | ||
| 2001 | const unsigned len = v.Back().Len(); | ||
| 2002 | v.DeleteBack(); | ||
| 2003 | if (len) | ||
| 2004 | break; | ||
| 2005 | } | ||
| 2006 | path = MakePathFromParts(v); | ||
| 2007 | NName::NormalizeDirPathPrefix(path); | ||
| 2008 | } | 2115 | } |
| 2009 | path += link.LinkPath; | 2116 | else |
| 2117 | { | ||
| 2118 | // link file placeholder must be empty | ||
| 2119 | if (checkThatFileIsEmpty && !fi.IsOsSymLink() && fi.Size != 0) | ||
| 2120 | return SendMessageError("Temporary link file is not empty", path); | ||
| 2121 | if (DeleteFileAlways(path)) | ||
| 2122 | return S_OK; | ||
| 2123 | } | ||
| 2124 | if (GetLastError() != ERROR_FILE_NOT_FOUND) | ||
| 2125 | return SendMessageError_with_LastError( | ||
| 2126 | fi.IsDir() ? | ||
| 2127 | k_CantDelete_Dir_for_SymLink: | ||
| 2128 | k_CantDelete_File_for_SymLink, | ||
| 2129 | path); | ||
| 2130 | } | ||
| 2131 | return S_OK; | ||
| 2132 | } | ||
| 2133 | |||
| 2134 | |||
| 2135 | /* | ||
| 2136 | in: | ||
| 2137 | link.LinkPath : must be relative (non-absolute) path in any case !!! | ||
| 2138 | link.isRelative / target path that must stored as created link: | ||
| 2139 | == false / _dirPathPrefix_Full + link.LinkPath | ||
| 2140 | == true / link.LinkPath | ||
| 2141 | */ | ||
| 2142 | static HRESULT SetLink2(const CArchiveExtractCallback &callback, | ||
| 2143 | const CPostLink &postLink, bool &linkWasSet) | ||
| 2144 | { | ||
| 2145 | const CLinkInfo &link = postLink.LinkInfo; | ||
| 2146 | const FString &fullProcessedPath_from = postLink.fullProcessedPath_from; // full file path in FS (fullProcessedPath_from) | ||
| 2147 | |||
| 2148 | const unsigned level = callback._ntOptions.SymLinks_DangerousLevel; | ||
| 2149 | if (level < 20) | ||
| 2150 | { | ||
| 2010 | /* | 2151 | /* |
| 2011 | path is calculated virtual target path of link | 2152 | We want to use additional check for links that can link to directory. |
| 2012 | path is relative to root folder of extracted items | 2153 | - linux: all symbolic links are files. |
| 2013 | if (!link.isRelative), then (path == link.LinkPath) | 2154 | - windows: we can have file/directory symbolic link, |
| 2155 | but file symbolic link works like directory link in windows. | ||
| 2156 | So we use additional check for all relative links. | ||
| 2157 | |||
| 2158 | We don't allow decreasing of final level of link. | ||
| 2159 | So if some another extracted file will use this link, | ||
| 2160 | then number of real path parts (after link redirection) cannot be | ||
| 2161 | smaller than number of requested path parts from archive records. | ||
| 2162 | |||
| 2163 | here we check only (link.LinkPath) without (_item.PathParts). | ||
| 2014 | */ | 2164 | */ |
| 2015 | if (!IsSafePath(path, link.Is_WSL())) | 2165 | CLinkLevelsInfo li; |
| 2016 | return SendMessageError2(0, // errorCode | 2166 | li.Parse(link.LinkPath, link.Is_WSL()); |
| 2017 | "Dangerous link path was ignored", | 2167 | bool isDang; |
| 2018 | us2fs(_item.Path), us2fs(link.LinkPath)); | 2168 | UString relativePathPrefix; |
| 2169 | if (li.IsAbsolute // unexpected | ||
| 2170 | || li.ParentDirDots_after_NonParent | ||
| 2171 | || (level <= 5 && link.isRelative && li.FinalLevel < 1) // final level lower | ||
| 2172 | || (level <= 5 && link.isRelative && li.LowLevel < 0) // negative temporary levels | ||
| 2173 | ) | ||
| 2174 | isDang = true; | ||
| 2175 | else // if (!isDang) | ||
| 2176 | { | ||
| 2177 | UString path; | ||
| 2178 | if (link.isRelative) | ||
| 2179 | { | ||
| 2180 | // item_PathParts : parts that will be created in output folder. | ||
| 2181 | // we want to get directory prefix of link item. | ||
| 2182 | // so we remove file name (last non-empty part) from PathParts: | ||
| 2183 | UStringVector v = postLink.item_PathParts; | ||
| 2184 | while (!v.IsEmpty()) | ||
| 2185 | { | ||
| 2186 | const unsigned len = v.Back().Len(); | ||
| 2187 | v.DeleteBack(); | ||
| 2188 | if (len) | ||
| 2189 | break; | ||
| 2190 | } | ||
| 2191 | path = MakePathFromParts(v); | ||
| 2192 | NName::NormalizeDirPathPrefix(path); | ||
| 2193 | relativePathPrefix = path; | ||
| 2194 | } | ||
| 2195 | path += link.LinkPath; | ||
| 2196 | /* | ||
| 2197 | path is calculated virtual target path of link | ||
| 2198 | path is relative to root folder of extracted items | ||
| 2199 | if (!link.isRelative), then (path == link.LinkPath) | ||
| 2200 | */ | ||
| 2201 | isDang = false; | ||
| 2202 | if (!IsSafePath(path, link.Is_WSL())) | ||
| 2203 | isDang = true; | ||
| 2204 | } | ||
| 2205 | const char *message = NULL; | ||
| 2206 | if (isDang) | ||
| 2207 | message = "Dangerous link path was ignored"; | ||
| 2208 | else if (level <= k_DangLevel_MAX_for_Link_over_Link | ||
| 2209 | && !CheckLinkPath_in_FS(callback._dirPathPrefix_Full, | ||
| 2210 | postLink, relativePathPrefix)) | ||
| 2211 | message = "Dangerous link via another link was ignored"; | ||
| 2212 | if (message) | ||
| 2213 | return callback.SendMessageError2(0, // errorCode | ||
| 2214 | message, us2fs(postLink.item_Path), us2fs(link.LinkPath)); | ||
| 2019 | } | 2215 | } |
| 2020 | 2216 | ||
| 2021 | FString target; // target path that will be stored to link field | 2217 | FString target; // target path that will be stored to link field |
| @@ -2025,8 +2221,8 @@ HRESULT CArchiveExtractCallback::SetLink( | |||
| 2025 | // all hard links and absolute symbolic links | 2221 | // all hard links and absolute symbolic links |
| 2026 | // relatPath == link.LinkPath | 2222 | // relatPath == link.LinkPath |
| 2027 | // we get absolute link path for target: | 2223 | // we get absolute link path for target: |
| 2028 | if (!NName::GetFullPath(_dirPathPrefix_Full, us2fs(link.LinkPath), target)) | 2224 | if (!NName::GetFullPath(callback._dirPathPrefix_Full, us2fs(link.LinkPath), target)) |
| 2029 | return SendMessageError("Incorrect link path", us2fs(link.LinkPath)); | 2225 | return callback.SendMessageError("Incorrect link path", us2fs(link.LinkPath)); |
| 2030 | // (target) is (_dirPathPrefix_Full + relatPath) | 2226 | // (target) is (_dirPathPrefix_Full + relatPath) |
| 2031 | } | 2227 | } |
| 2032 | else | 2228 | else |
| @@ -2036,21 +2232,24 @@ HRESULT CArchiveExtractCallback::SetLink( | |||
| 2036 | target = us2fs(link.LinkPath); | 2232 | target = us2fs(link.LinkPath); |
| 2037 | } | 2233 | } |
| 2038 | if (target.IsEmpty()) | 2234 | if (target.IsEmpty()) |
| 2039 | return SendMessageError("Empty link", fullProcessedPath_from); | 2235 | return callback.SendMessageError("Empty link", fullProcessedPath_from); |
| 2040 | 2236 | ||
| 2041 | if (link.Is_HardLink() /* || link.IsCopyLink */) | 2237 | if (link.Is_HardLink() /* || link.IsCopyLink */) |
| 2042 | { | 2238 | { |
| 2043 | // if (link.isHardLink) | 2239 | // if (link.isHardLink) |
| 2044 | { | 2240 | { |
| 2045 | if (!MyCreateHardLink(fullProcessedPath_from, target)) | 2241 | RINOK(callback.DeleteLinkFileAlways_or_RemoveEmptyDir(fullProcessedPath_from, true)) // checkThatFileIsEmpty |
| 2046 | return SendMessageError2_with_LastError(kCantCreateHardLink, fullProcessedPath_from, target); | 2242 | { |
| 2243 | // RINOK(SendMessageError_with_LastError(k_Cant_DeleteTempLinkFile, fullProcessedPath_from)) | ||
| 2244 | } | ||
| 2245 | return callback.CreateHardLink2(fullProcessedPath_from, target, linkWasSet); | ||
| 2047 | /* | 2246 | /* |
| 2048 | RINOK(PrepareOperation(NArchive::NExtract::NAskMode::kExtract)) | 2247 | RINOK(PrepareOperation(NArchive::NExtract::NAskMode::kExtract)) |
| 2049 | _op_WasReported = true; | 2248 | _op_WasReported = true; |
| 2050 | RINOK(SetOperationResult(NArchive::NExtract::NOperationResult::kOK)) | 2249 | RINOK(SetOperationResult(NArchive::NExtract::NOperationResult::kOK)) |
| 2051 | */ | ||
| 2052 | linkWasSet = true; | 2250 | linkWasSet = true; |
| 2053 | return S_OK; | 2251 | return S_OK; |
| 2252 | */ | ||
| 2054 | } | 2253 | } |
| 2055 | /* | 2254 | /* |
| 2056 | // IsCopyLink | 2255 | // IsCopyLink |
| @@ -2086,36 +2285,10 @@ HRESULT CArchiveExtractCallback::SetLink( | |||
| 2086 | */ | 2285 | */ |
| 2087 | 2286 | ||
| 2088 | #ifdef _WIN32 | 2287 | #ifdef _WIN32 |
| 2089 | const bool isDir = (_item.IsDir || link.LinkType == k_LinkType_Junction); | 2288 | const bool isDir = (postLink.item_IsDir || link.LinkType == k_LinkType_Junction); |
| 2090 | #endif | 2289 | #endif |
| 2091 | 2290 | ||
| 2092 | if (!_ntOptions.SymLinks_AllowDangerous.Val && link.isRelative) | 2291 | |
| 2093 | { | ||
| 2094 | /* | ||
| 2095 | We want to use additional check for links that can link to directory. | ||
| 2096 | - linux: all symbolic links are files. | ||
| 2097 | - windows: we can have file/directory symbolic link, | ||
| 2098 | but file symbolic link works like directory link in windows. | ||
| 2099 | So we use additional check for all relative links. | ||
| 2100 | |||
| 2101 | We don't allow decreasing of final level of link. | ||
| 2102 | So if some another extracted file will use this link, | ||
| 2103 | then number of real path parts (after link redirection) cannot be | ||
| 2104 | smaller than number of requested path parts from archive records. | ||
| 2105 | |||
| 2106 | Now we check only (link.LinkPath) without (_item.PathParts). | ||
| 2107 | */ | ||
| 2108 | CLinkLevelsInfo levelsInfo; | ||
| 2109 | levelsInfo.Parse(link.LinkPath, link.Is_WSL()); | ||
| 2110 | if (levelsInfo.FinalLevel < 1 | ||
| 2111 | // || levelsInfo.LowLevel < 0 // we allow negative temporary levels | ||
| 2112 | || levelsInfo.IsAbsolute) | ||
| 2113 | return SendMessageError2(0, // errorCode | ||
| 2114 | "Dangerous symbolic link path was ignored", | ||
| 2115 | us2fs(_item.Path), us2fs(link.LinkPath)); | ||
| 2116 | } | ||
| 2117 | |||
| 2118 | |||
| 2119 | #ifdef _WIN32 | 2292 | #ifdef _WIN32 |
| 2120 | CByteBuffer data; | 2293 | CByteBuffer data; |
| 2121 | // printf("\nFillLinkData(): %s\n", GetOemString(target).Ptr()); | 2294 | // printf("\nFillLinkData(): %s\n", GetOemString(target).Ptr()); |
| @@ -2127,7 +2300,7 @@ HRESULT CArchiveExtractCallback::SetLink( | |||
| 2127 | else | 2300 | else |
| 2128 | FillLinkData_WinLink(data, fs2us(target), link.LinkType != k_LinkType_Junction); | 2301 | FillLinkData_WinLink(data, fs2us(target), link.LinkType != k_LinkType_Junction); |
| 2129 | if (data.Size() == 0) | 2302 | if (data.Size() == 0) |
| 2130 | return SendMessageError("Cannot fill link data", us2fs(_item.Path)); | 2303 | return callback.SendMessageError("Cannot fill link data", us2fs(postLink.item_Path)); |
| 2131 | /* | 2304 | /* |
| 2132 | if (NtReparse_Size != data.Size() || memcmp(NtReparse_Data, data, data.Size()) != 0) | 2305 | if (NtReparse_Size != data.Size() || memcmp(NtReparse_Data, data, data.Size()) != 0) |
| 2133 | SendMessageError("reconstructed Reparse is different", fs2us(target)); | 2306 | SendMessageError("reconstructed Reparse is different", fs2us(target)); |
| @@ -2136,14 +2309,18 @@ HRESULT CArchiveExtractCallback::SetLink( | |||
| 2136 | // we check that reparse data is correct, but we ignore attr.MinorError. | 2309 | // we check that reparse data is correct, but we ignore attr.MinorError. |
| 2137 | CReparseAttr attr; | 2310 | CReparseAttr attr; |
| 2138 | if (!attr.Parse(data, data.Size())) | 2311 | if (!attr.Parse(data, data.Size())) |
| 2139 | return SendMessageError("Internal error for symbolic link file", us2fs(_item.Path)); | 2312 | return callback.SendMessageError("Internal error for symbolic link file", us2fs(postLink.item_Path)); |
| 2140 | } | 2313 | } |
| 2314 | #endif | ||
| 2315 | |||
| 2316 | RINOK(callback.DeleteLinkFileAlways_or_RemoveEmptyDir(fullProcessedPath_from, true)) // checkThatFileIsEmpty | ||
| 2317 | #ifdef _WIN32 | ||
| 2141 | if (!NFile::NIO::SetReparseData(fullProcessedPath_from, isDir, data, (DWORD)data.Size())) | 2318 | if (!NFile::NIO::SetReparseData(fullProcessedPath_from, isDir, data, (DWORD)data.Size())) |
| 2142 | #else // ! _WIN32 | 2319 | #else // ! _WIN32 |
| 2143 | if (!NFile::NIO::SetSymLink(fullProcessedPath_from, target)) | 2320 | if (!NFile::NIO::SetSymLink(fullProcessedPath_from, target)) |
| 2144 | #endif // ! _WIN32 | 2321 | #endif // ! _WIN32 |
| 2145 | { | 2322 | { |
| 2146 | return SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath_from); | 2323 | return callback.SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath_from); |
| 2147 | } | 2324 | } |
| 2148 | linkWasSet = true; | 2325 | linkWasSet = true; |
| 2149 | return S_OK; | 2326 | return S_OK; |
| @@ -2392,6 +2569,7 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile() | |||
| 2392 | _curSize_Defined = true; | 2569 | _curSize_Defined = true; |
| 2393 | if (needSetReparse) | 2570 | if (needSetReparse) |
| 2394 | { | 2571 | { |
| 2572 | // empty file was created so we must delete it. | ||
| 2395 | // in Linux : we must delete empty file before symbolic link creation | 2573 | // in Linux : we must delete empty file before symbolic link creation |
| 2396 | // in Windows : we can create symbolic link even without file deleting | 2574 | // in Windows : we can create symbolic link even without file deleting |
| 2397 | if (!DeleteFileAlways(_diskFilePath)) | 2575 | if (!DeleteFileAlways(_diskFilePath)) |
| @@ -2404,9 +2582,12 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile() | |||
| 2404 | // link.isJunction = true; // for debug | 2582 | // link.isJunction = true; // for debug |
| 2405 | link.Normalize_to_RelativeSafe(_removePathParts); | 2583 | link.Normalize_to_RelativeSafe(_removePathParts); |
| 2406 | RINOK(SetLink(_diskFilePath, link, linkWasSet)) | 2584 | RINOK(SetLink(_diskFilePath, link, linkWasSet)) |
| 2585 | /* | ||
| 2586 | // we don't set attributes for placeholder. | ||
| 2407 | if (linkWasSet) | 2587 | if (linkWasSet) |
| 2408 | _isSymLinkCreated = true; // link.IsSymLink(); | 2588 | _isSymLinkCreated = true; // link.IsSymLink(); |
| 2409 | else | 2589 | else |
| 2590 | */ | ||
| 2410 | _needSetAttrib = false; | 2591 | _needSetAttrib = false; |
| 2411 | } | 2592 | } |
| 2412 | } | 2593 | } |
| @@ -2416,13 +2597,37 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile() | |||
| 2416 | } | 2597 | } |
| 2417 | 2598 | ||
| 2418 | 2599 | ||
| 2419 | void CArchiveExtractCallback::SetAttrib() | 2600 | static void SetAttrib_Base(const FString &path, const CProcessedFileInfo &fi, |
| 2601 | const CArchiveExtractCallback &callback) | ||
| 2420 | { | 2602 | { |
| 2421 | #ifndef _WIN32 | 2603 | #ifndef _WIN32 |
| 2604 | if (fi.Owner.Id_Defined && | ||
| 2605 | fi.Group.Id_Defined) | ||
| 2606 | { | ||
| 2607 | if (my_chown(path, fi.Owner.Id, fi.Group.Id) != 0) | ||
| 2608 | callback.SendMessageError_with_LastError("Cannot set owner", path); | ||
| 2609 | } | ||
| 2610 | #endif | ||
| 2611 | |||
| 2612 | if (fi.Attrib_Defined) | ||
| 2613 | { | ||
| 2614 | // const AString s = GetAnsiString(_diskFilePath); | ||
| 2615 | // printf("\nSetFileAttrib_PosixHighDetect: %s: hex:%x\n", s.Ptr(), _fi.Attrib); | ||
| 2616 | if (!SetFileAttrib_PosixHighDetect(path, fi.Attrib)) | ||
| 2617 | { | ||
| 2618 | // do we need error message here in Windows and in posix? | ||
| 2619 | callback.SendMessageError_with_LastError("Cannot set file attribute", path); | ||
| 2620 | } | ||
| 2621 | } | ||
| 2622 | } | ||
| 2623 | |||
| 2624 | void CArchiveExtractCallback::SetAttrib() const | ||
| 2625 | { | ||
| 2626 | #ifndef _WIN32 | ||
| 2422 | // Linux now doesn't support permissions for symlinks | 2627 | // Linux now doesn't support permissions for symlinks |
| 2423 | if (_isSymLinkCreated) | 2628 | if (_isSymLinkCreated) |
| 2424 | return; | 2629 | return; |
| 2425 | #endif | 2630 | #endif |
| 2426 | 2631 | ||
| 2427 | if (_itemFailure | 2632 | if (_itemFailure |
| 2428 | || _diskFilePath.IsEmpty() | 2633 | || _diskFilePath.IsEmpty() |
| @@ -2430,29 +2635,39 @@ void CArchiveExtractCallback::SetAttrib() | |||
| 2430 | || !_extractMode) | 2635 | || !_extractMode) |
| 2431 | return; | 2636 | return; |
| 2432 | 2637 | ||
| 2433 | #ifndef _WIN32 | 2638 | SetAttrib_Base(_diskFilePath, _fi, *this); |
| 2434 | if (_fi.Owner.Id_Defined && | 2639 | } |
| 2435 | _fi.Group.Id_Defined) | 2640 | |
| 2436 | { | ||
| 2437 | if (my_chown(_diskFilePath, _fi.Owner.Id, _fi.Group.Id) != 0) | ||
| 2438 | { | ||
| 2439 | SendMessageError_with_LastError("Cannot set owner", _diskFilePath); | ||
| 2440 | } | ||
| 2441 | } | ||
| 2442 | #endif | ||
| 2443 | 2641 | ||
| 2444 | if (_fi.Attrib_Defined) | 2642 | #ifdef Z7_USE_SECURITY_CODE |
| 2643 | HRESULT CArchiveExtractCallback::SetSecurityInfo(UInt32 indexInArc, const FString &path) const | ||
| 2644 | { | ||
| 2645 | if (!_stdOutMode && _extractMode && _ntOptions.NtSecurity.Val && _arc->GetRawProps) | ||
| 2445 | { | 2646 | { |
| 2446 | // const AString s = GetAnsiString(_diskFilePath); | 2647 | const void *data; |
| 2447 | // printf("\nSetFileAttrib_PosixHighDetect: %s: hex:%x\n", s.Ptr(), _fi.Attrib); | 2648 | UInt32 dataSize; |
| 2448 | bool res = SetFileAttrib_PosixHighDetect(_diskFilePath, _fi.Attrib); | 2649 | UInt32 propType; |
| 2449 | if (!res) | 2650 | _arc->GetRawProps->GetRawProp(indexInArc, kpidNtSecure, &data, &dataSize, &propType); |
| 2651 | if (dataSize != 0) | ||
| 2450 | { | 2652 | { |
| 2451 | // do we need error message here in Windows and in posix? | 2653 | if (propType != NPropDataType::kRaw) |
| 2452 | SendMessageError_with_LastError("Cannot set file attribute", _diskFilePath); | 2654 | return E_FAIL; |
| 2655 | if (CheckNtSecure((const Byte *)data, dataSize)) | ||
| 2656 | { | ||
| 2657 | SECURITY_INFORMATION securInfo = DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION; | ||
| 2658 | if (_saclEnabled) | ||
| 2659 | securInfo |= SACL_SECURITY_INFORMATION; | ||
| 2660 | // if (! | ||
| 2661 | ::SetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(void *)(const Byte *)(data)); | ||
| 2662 | { | ||
| 2663 | // RINOK(SendMessageError_with_LastError("SetFileSecurity FAILS", path)) | ||
| 2664 | } | ||
| 2665 | } | ||
| 2453 | } | 2666 | } |
| 2454 | } | 2667 | } |
| 2668 | return S_OK; | ||
| 2455 | } | 2669 | } |
| 2670 | #endif // Z7_USE_SECURITY_CODE | ||
| 2456 | 2671 | ||
| 2457 | 2672 | ||
| 2458 | Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 opRes)) | 2673 | Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 opRes)) |
| @@ -2490,27 +2705,9 @@ Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 opRes)) | |||
| 2490 | 2705 | ||
| 2491 | RINOK(CloseReparseAndFile()) | 2706 | RINOK(CloseReparseAndFile()) |
| 2492 | 2707 | ||
| 2493 | #ifdef Z7_USE_SECURITY_CODE | 2708 | #ifdef Z7_USE_SECURITY_CODE |
| 2494 | if (!_stdOutMode && _extractMode && _ntOptions.NtSecurity.Val && _arc->GetRawProps) | 2709 | RINOK(SetSecurityInfo(_index, _diskFilePath)) |
| 2495 | { | 2710 | #endif |
| 2496 | const void *data; | ||
| 2497 | UInt32 dataSize; | ||
| 2498 | UInt32 propType; | ||
| 2499 | _arc->GetRawProps->GetRawProp(_index, kpidNtSecure, &data, &dataSize, &propType); | ||
| 2500 | if (dataSize != 0) | ||
| 2501 | { | ||
| 2502 | if (propType != NPropDataType::kRaw) | ||
| 2503 | return E_FAIL; | ||
| 2504 | if (CheckNtSecure((const Byte *)data, dataSize)) | ||
| 2505 | { | ||
| 2506 | SECURITY_INFORMATION securInfo = DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION; | ||
| 2507 | if (_saclEnabled) | ||
| 2508 | securInfo |= SACL_SECURITY_INFORMATION; | ||
| 2509 | ::SetFileSecurityW(fs2us(_diskFilePath), securInfo, (PSECURITY_DESCRIPTOR)(void *)(const Byte *)(data)); | ||
| 2510 | } | ||
| 2511 | } | ||
| 2512 | } | ||
| 2513 | #endif // Z7_USE_SECURITY_CODE | ||
| 2514 | 2711 | ||
| 2515 | if (!_curSize_Defined) | 2712 | if (!_curSize_Defined) |
| 2516 | GetUnpackSize(); | 2713 | GetUnpackSize(); |
| @@ -2754,15 +2951,58 @@ void CDirPathSortPair::SetNumSlashes(const FChar *s) | |||
| 2754 | } | 2951 | } |
| 2755 | 2952 | ||
| 2756 | 2953 | ||
| 2757 | bool CDirPathTime::SetDirTime() const | 2954 | bool CFiTimesCAM::SetDirTime_to_FS(CFSTR path) const |
| 2758 | { | 2955 | { |
| 2759 | return NDir::SetDirTime(Path, | 2956 | // it's same function for dir and for file |
| 2957 | return NDir::SetDirTime(path, | ||
| 2760 | CTime_Defined ? &CTime : NULL, | 2958 | CTime_Defined ? &CTime : NULL, |
| 2761 | ATime_Defined ? &ATime : NULL, | 2959 | ATime_Defined ? &ATime : NULL, |
| 2762 | MTime_Defined ? &MTime : NULL); | 2960 | MTime_Defined ? &MTime : NULL); |
| 2763 | } | 2961 | } |
| 2764 | 2962 | ||
| 2765 | 2963 | ||
| 2964 | #ifdef SUPPORT_LINKS | ||
| 2965 | |||
| 2966 | bool CFiTimesCAM::SetLinkFileTime_to_FS(CFSTR path) const | ||
| 2967 | { | ||
| 2968 | // it's same function for dir and for file | ||
| 2969 | return NDir::SetLinkFileTime(path, | ||
| 2970 | CTime_Defined ? &CTime : NULL, | ||
| 2971 | ATime_Defined ? &ATime : NULL, | ||
| 2972 | MTime_Defined ? &MTime : NULL); | ||
| 2973 | } | ||
| 2974 | |||
| 2975 | HRESULT CArchiveExtractCallback::SetPostLinks() const | ||
| 2976 | { | ||
| 2977 | FOR_VECTOR (i, _postLinks) | ||
| 2978 | { | ||
| 2979 | const CPostLink &link = _postLinks[i]; | ||
| 2980 | bool linkWasSet = false; | ||
| 2981 | RINOK(SetLink2(*this, link, linkWasSet)) | ||
| 2982 | if (linkWasSet) | ||
| 2983 | { | ||
| 2984 | #ifdef _WIN32 | ||
| 2985 | // Linux now doesn't support permissions for symlinks | ||
| 2986 | SetAttrib_Base(link.fullProcessedPath_from, link.item_FileInfo, *this); | ||
| 2987 | #endif | ||
| 2988 | |||
| 2989 | CFiTimesCAM pt; | ||
| 2990 | GetFiTimesCAM(link.item_FileInfo, pt, *_arc); | ||
| 2991 | if (pt.IsSomeTimeDefined()) | ||
| 2992 | pt.SetLinkFileTime_to_FS(link.fullProcessedPath_from); | ||
| 2993 | |||
| 2994 | #ifdef Z7_USE_SECURITY_CODE | ||
| 2995 | // we set security information after timestamps setting | ||
| 2996 | RINOK(SetSecurityInfo(link.Index_in_Arc, link.fullProcessedPath_from)) | ||
| 2997 | #endif | ||
| 2998 | } | ||
| 2999 | } | ||
| 3000 | return S_OK; | ||
| 3001 | } | ||
| 3002 | |||
| 3003 | #endif | ||
| 3004 | |||
| 3005 | |||
| 2766 | HRESULT CArchiveExtractCallback::SetDirsTimes() | 3006 | HRESULT CArchiveExtractCallback::SetDirsTimes() |
| 2767 | { | 3007 | { |
| 2768 | if (!_arc) | 3008 | if (!_arc) |
| @@ -2786,7 +3026,7 @@ HRESULT CArchiveExtractCallback::SetDirsTimes() | |||
| 2786 | for (i = 0; i < pairs.Size(); i++) | 3026 | for (i = 0; i < pairs.Size(); i++) |
| 2787 | { | 3027 | { |
| 2788 | const CDirPathTime &dpt = _extractedFolders[pairs[i].Index]; | 3028 | const CDirPathTime &dpt = _extractedFolders[pairs[i].Index]; |
| 2789 | if (!dpt.SetDirTime()) | 3029 | if (!dpt.SetDirTime_to_FS_2()) |
| 2790 | { | 3030 | { |
| 2791 | // result = E_FAIL; | 3031 | // result = E_FAIL; |
| 2792 | // do we need error message here in Windows and in posix? | 3032 | // do we need error message here in Windows and in posix? |
| @@ -2818,10 +3058,20 @@ HRESULT CArchiveExtractCallback::SetDirsTimes() | |||
| 2818 | 3058 | ||
| 2819 | HRESULT CArchiveExtractCallback::CloseArc() | 3059 | HRESULT CArchiveExtractCallback::CloseArc() |
| 2820 | { | 3060 | { |
| 3061 | // we call CloseReparseAndFile() here because we can have non-closed file in some cases? | ||
| 2821 | HRESULT res = CloseReparseAndFile(); | 3062 | HRESULT res = CloseReparseAndFile(); |
| 2822 | const HRESULT res2 = SetDirsTimes(); | 3063 | #ifdef SUPPORT_LINKS |
| 2823 | if (res == S_OK) | 3064 | { |
| 2824 | res = res2; | 3065 | const HRESULT res2 = SetPostLinks(); |
| 3066 | if (res == S_OK) | ||
| 3067 | res = res2; | ||
| 3068 | } | ||
| 3069 | #endif | ||
| 3070 | { | ||
| 3071 | const HRESULT res2 = SetDirsTimes(); | ||
| 3072 | if (res == S_OK) | ||
| 3073 | res = res2; | ||
| 3074 | } | ||
| 2825 | _arc = NULL; | 3075 | _arc = NULL; |
| 2826 | return res; | 3076 | return res; |
| 2827 | } | 3077 | } |
diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.h b/CPP/7zip/UI/Common/ArchiveExtractCallback.h index 71fa3ef..3c62763 100644 --- a/CPP/7zip/UI/Common/ArchiveExtractCallback.h +++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.h | |||
| @@ -52,7 +52,6 @@ struct CExtractNtOptions | |||
| 52 | { | 52 | { |
| 53 | CBoolPair NtSecurity; | 53 | CBoolPair NtSecurity; |
| 54 | CBoolPair SymLinks; | 54 | CBoolPair SymLinks; |
| 55 | CBoolPair SymLinks_AllowDangerous; | ||
| 56 | CBoolPair HardLinks; | 55 | CBoolPair HardLinks; |
| 57 | CBoolPair AltStreams; | 56 | CBoolPair AltStreams; |
| 58 | bool ReplaceColonForAltStream; | 57 | bool ReplaceColonForAltStream; |
| @@ -66,6 +65,8 @@ struct CExtractNtOptions | |||
| 66 | bool PreserveATime; | 65 | bool PreserveATime; |
| 67 | bool OpenShareForWrite; | 66 | bool OpenShareForWrite; |
| 68 | 67 | ||
| 68 | unsigned SymLinks_DangerousLevel; | ||
| 69 | |||
| 69 | UInt64 MemLimit; | 70 | UInt64 MemLimit; |
| 70 | 71 | ||
| 71 | CExtractNtOptions(): | 72 | CExtractNtOptions(): |
| @@ -74,10 +75,10 @@ struct CExtractNtOptions | |||
| 74 | ExtractOwner(false), | 75 | ExtractOwner(false), |
| 75 | PreserveATime(false), | 76 | PreserveATime(false), |
| 76 | OpenShareForWrite(false), | 77 | OpenShareForWrite(false), |
| 78 | SymLinks_DangerousLevel(5), | ||
| 77 | MemLimit((UInt64)(Int64)-1) | 79 | MemLimit((UInt64)(Int64)-1) |
| 78 | { | 80 | { |
| 79 | SymLinks.Val = true; | 81 | SymLinks.Val = true; |
| 80 | SymLinks_AllowDangerous.Val = false; | ||
| 81 | HardLinks.Val = true; | 82 | HardLinks.Val = true; |
| 82 | AltStreams.Val = true; | 83 | AltStreams.Val = true; |
| 83 | 84 | ||
| @@ -166,19 +167,22 @@ struct CFiTimesCAM | |||
| 166 | ATime_Defined | | 167 | ATime_Defined | |
| 167 | MTime_Defined; | 168 | MTime_Defined; |
| 168 | } | 169 | } |
| 170 | bool SetDirTime_to_FS(CFSTR path) const; | ||
| 171 | #ifdef SUPPORT_LINKS | ||
| 172 | bool SetLinkFileTime_to_FS(CFSTR path) const; | ||
| 173 | #endif | ||
| 169 | }; | 174 | }; |
| 170 | 175 | ||
| 171 | struct CDirPathTime: public CFiTimesCAM | 176 | struct CDirPathTime: public CFiTimesCAM |
| 172 | { | 177 | { |
| 173 | FString Path; | 178 | FString Path; |
| 174 | 179 | ||
| 175 | bool SetDirTime() const; | 180 | bool SetDirTime_to_FS_2() const { return SetDirTime_to_FS(Path); } |
| 176 | }; | 181 | }; |
| 177 | 182 | ||
| 178 | 183 | ||
| 179 | #ifdef SUPPORT_LINKS | 184 | #ifdef SUPPORT_LINKS |
| 180 | 185 | ||
| 181 | |||
| 182 | enum ELinkType | 186 | enum ELinkType |
| 183 | { | 187 | { |
| 184 | k_LinkType_HardLink, | 188 | k_LinkType_HardLink, |
| @@ -227,6 +231,15 @@ private: | |||
| 227 | #endif // SUPPORT_LINKS | 231 | #endif // SUPPORT_LINKS |
| 228 | 232 | ||
| 229 | 233 | ||
| 234 | |||
| 235 | struct CProcessedFileInfo | ||
| 236 | { | ||
| 237 | CArcTime CTime; | ||
| 238 | CArcTime ATime; | ||
| 239 | CArcTime MTime; | ||
| 240 | UInt32 Attrib; | ||
| 241 | bool Attrib_Defined; | ||
| 242 | |||
| 230 | #ifndef _WIN32 | 243 | #ifndef _WIN32 |
| 231 | 244 | ||
| 232 | struct COwnerInfo | 245 | struct COwnerInfo |
| @@ -243,8 +256,76 @@ struct COwnerInfo | |||
| 243 | } | 256 | } |
| 244 | }; | 257 | }; |
| 245 | 258 | ||
| 259 | COwnerInfo Owner; | ||
| 260 | COwnerInfo Group; | ||
| 246 | #endif | 261 | #endif |
| 247 | 262 | ||
| 263 | void Clear() | ||
| 264 | { | ||
| 265 | #ifndef _WIN32 | ||
| 266 | Attrib_Defined = false; | ||
| 267 | Owner.Clear(); | ||
| 268 | #endif | ||
| 269 | } | ||
| 270 | |||
| 271 | bool IsReparse() const | ||
| 272 | { | ||
| 273 | return (Attrib_Defined && (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0); | ||
| 274 | } | ||
| 275 | |||
| 276 | bool IsLinuxSymLink() const | ||
| 277 | { | ||
| 278 | return (Attrib_Defined && MY_LIN_S_ISLNK(Attrib >> 16)); | ||
| 279 | } | ||
| 280 | |||
| 281 | void SetFromPosixAttrib(UInt32 a) | ||
| 282 | { | ||
| 283 | // here we set only part of combined attribute required by SetFileAttrib() call | ||
| 284 | #ifdef _WIN32 | ||
| 285 | // Windows sets FILE_ATTRIBUTE_NORMAL, if we try to set 0 as attribute. | ||
| 286 | Attrib = MY_LIN_S_ISDIR(a) ? | ||
| 287 | FILE_ATTRIBUTE_DIRECTORY : | ||
| 288 | FILE_ATTRIBUTE_ARCHIVE; | ||
| 289 | if ((a & 0222) == 0) // (& S_IWUSR) in p7zip | ||
| 290 | Attrib |= FILE_ATTRIBUTE_READONLY; | ||
| 291 | // 22.00 : we need type bits for (MY_LIN_S_IFLNK) for IsLinuxSymLink() | ||
| 292 | a &= MY_LIN_S_IFMT; | ||
| 293 | if (a == MY_LIN_S_IFLNK) | ||
| 294 | Attrib |= (a << 16); | ||
| 295 | #else | ||
| 296 | Attrib = (a << 16) | FILE_ATTRIBUTE_UNIX_EXTENSION; | ||
| 297 | #endif | ||
| 298 | Attrib_Defined = true; | ||
| 299 | } | ||
| 300 | }; | ||
| 301 | |||
| 302 | |||
| 303 | #ifdef SUPPORT_LINKS | ||
| 304 | |||
| 305 | struct CPostLink | ||
| 306 | { | ||
| 307 | UInt32 Index_in_Arc; | ||
| 308 | bool item_IsDir; // _item.IsDir | ||
| 309 | UString item_Path; // _item.Path; | ||
| 310 | UStringVector item_PathParts; // _item.PathParts; | ||
| 311 | CProcessedFileInfo item_FileInfo; // _fi | ||
| 312 | FString fullProcessedPath_from; // full file path in FS | ||
| 313 | CLinkInfo LinkInfo; | ||
| 314 | }; | ||
| 315 | |||
| 316 | /* | ||
| 317 | struct CPostLinks | ||
| 318 | { | ||
| 319 | void Clear() | ||
| 320 | { | ||
| 321 | Links.Clear(); | ||
| 322 | } | ||
| 323 | }; | ||
| 324 | */ | ||
| 325 | |||
| 326 | #endif // SUPPORT_LINKS | ||
| 327 | |||
| 328 | |||
| 248 | 329 | ||
| 249 | class CArchiveExtractCallback Z7_final: | 330 | class CArchiveExtractCallback Z7_final: |
| 250 | public IArchiveExtractCallback, | 331 | public IArchiveExtractCallback, |
| @@ -292,8 +373,9 @@ public: | |||
| 292 | private: | 373 | private: |
| 293 | 374 | ||
| 294 | const CArc *_arc; | 375 | const CArc *_arc; |
| 376 | public: | ||
| 295 | CExtractNtOptions _ntOptions; | 377 | CExtractNtOptions _ntOptions; |
| 296 | 378 | private: | |
| 297 | bool _encrypted; | 379 | bool _encrypted; |
| 298 | bool _isSplit; | 380 | bool _isSplit; |
| 299 | bool _curSize_Defined; | 381 | bool _curSize_Defined; |
| @@ -325,7 +407,9 @@ private: | |||
| 325 | CMyComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword; | 407 | CMyComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword; |
| 326 | 408 | ||
| 327 | FString _dirPathPrefix; | 409 | FString _dirPathPrefix; |
| 410 | public: | ||
| 328 | FString _dirPathPrefix_Full; | 411 | FString _dirPathPrefix_Full; |
| 412 | private: | ||
| 329 | 413 | ||
| 330 | #ifndef Z7_SFX | 414 | #ifndef Z7_SFX |
| 331 | 415 | ||
| @@ -337,49 +421,7 @@ private: | |||
| 337 | CReadArcItem _item; | 421 | CReadArcItem _item; |
| 338 | FString _diskFilePath; | 422 | FString _diskFilePath; |
| 339 | 423 | ||
| 340 | struct CProcessedFileInfo | 424 | CProcessedFileInfo _fi; |
| 341 | { | ||
| 342 | CArcTime CTime; | ||
| 343 | CArcTime ATime; | ||
| 344 | CArcTime MTime; | ||
| 345 | UInt32 Attrib; | ||
| 346 | bool Attrib_Defined; | ||
| 347 | |||
| 348 | #ifndef _WIN32 | ||
| 349 | COwnerInfo Owner; | ||
| 350 | COwnerInfo Group; | ||
| 351 | #endif | ||
| 352 | |||
| 353 | bool IsReparse() const | ||
| 354 | { | ||
| 355 | return (Attrib_Defined && (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0); | ||
| 356 | } | ||
| 357 | |||
| 358 | bool IsLinuxSymLink() const | ||
| 359 | { | ||
| 360 | return (Attrib_Defined && MY_LIN_S_ISLNK(Attrib >> 16)); | ||
| 361 | } | ||
| 362 | |||
| 363 | void SetFromPosixAttrib(UInt32 a) | ||
| 364 | { | ||
| 365 | // here we set only part of combined attribute required by SetFileAttrib() call | ||
| 366 | #ifdef _WIN32 | ||
| 367 | // Windows sets FILE_ATTRIBUTE_NORMAL, if we try to set 0 as attribute. | ||
| 368 | Attrib = MY_LIN_S_ISDIR(a) ? | ||
| 369 | FILE_ATTRIBUTE_DIRECTORY : | ||
| 370 | FILE_ATTRIBUTE_ARCHIVE; | ||
| 371 | if ((a & 0222) == 0) // (& S_IWUSR) in p7zip | ||
| 372 | Attrib |= FILE_ATTRIBUTE_READONLY; | ||
| 373 | // 22.00 : we need type bits for (MY_LIN_S_IFLNK) for IsLinuxSymLink() | ||
| 374 | a &= MY_LIN_S_IFMT; | ||
| 375 | if (a == MY_LIN_S_IFLNK) | ||
| 376 | Attrib |= (a << 16); | ||
| 377 | #else | ||
| 378 | Attrib = (a << 16) | FILE_ATTRIBUTE_UNIX_EXTENSION; | ||
| 379 | #endif | ||
| 380 | Attrib_Defined = true; | ||
| 381 | } | ||
| 382 | } _fi; | ||
| 383 | 425 | ||
| 384 | UInt64 _position; | 426 | UInt64 _position; |
| 385 | UInt64 _curSize; | 427 | UInt64 _curSize; |
| @@ -421,20 +463,21 @@ private: | |||
| 421 | // CObjectVector<NWindows::NFile::NDir::CDelayedSymLink> _delayedSymLinks; | 463 | // CObjectVector<NWindows::NFile::NDir::CDelayedSymLink> _delayedSymLinks; |
| 422 | #endif | 464 | #endif |
| 423 | 465 | ||
| 424 | void CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath); | 466 | void CreateComplexDirectory( |
| 467 | const UStringVector &dirPathParts, bool isFinal, FString &fullPath); | ||
| 425 | HRESULT GetTime(UInt32 index, PROPID propID, CArcTime &ft); | 468 | HRESULT GetTime(UInt32 index, PROPID propID, CArcTime &ft); |
| 426 | HRESULT GetUnpackSize(); | 469 | HRESULT GetUnpackSize(); |
| 427 | 470 | ||
| 428 | FString Hash_GetFullFilePath(); | 471 | FString Hash_GetFullFilePath(); |
| 429 | 472 | ||
| 430 | void SetAttrib(); | 473 | void SetAttrib() const; |
| 431 | 474 | ||
| 432 | public: | 475 | public: |
| 433 | HRESULT SendMessageError(const char *message, const FString &path); | 476 | HRESULT SendMessageError(const char *message, const FString &path) const; |
| 434 | HRESULT SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path); | 477 | HRESULT SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path) const; |
| 435 | HRESULT SendMessageError_with_LastError(const char *message, const FString &path); | 478 | HRESULT SendMessageError_with_LastError(const char *message, const FString &path) const; |
| 436 | HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2); | 479 | HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2) const; |
| 437 | HRESULT SendMessageError2_with_LastError(const char *message, const FString &path1, const FString &path2); | 480 | HRESULT SendMessageError2_with_LastError(const char *message, const FString &path1, const FString &path2) const; |
| 438 | 481 | ||
| 439 | #if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) | 482 | #if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) |
| 440 | NExtract::NZoneIdMode::EEnum ZoneMode; | 483 | NExtract::NZoneIdMode::EEnum ZoneMode; |
| @@ -497,10 +540,11 @@ public: | |||
| 497 | UInt64 packSize); | 540 | UInt64 packSize); |
| 498 | 541 | ||
| 499 | 542 | ||
| 500 | #ifdef SUPPORT_LINKS | 543 | #ifdef SUPPORT_LINKS |
| 501 | 544 | ||
| 502 | private: | 545 | private: |
| 503 | CHardLinks _hardLinks; | 546 | CHardLinks _hardLinks; |
| 547 | CObjectVector<CPostLink> _postLinks; | ||
| 504 | CLinkInfo _link; | 548 | CLinkInfo _link; |
| 505 | // const void *NtReparse_Data; | 549 | // const void *NtReparse_Data; |
| 506 | // UInt32 NtReparse_Size; | 550 | // UInt32 NtReparse_Size; |
| @@ -512,13 +556,16 @@ private: | |||
| 512 | const FString &fullProcessedPath_from, | 556 | const FString &fullProcessedPath_from, |
| 513 | const CLinkInfo &linkInfo, | 557 | const CLinkInfo &linkInfo, |
| 514 | bool &linkWasSet); | 558 | bool &linkWasSet); |
| 559 | HRESULT SetPostLinks() const; | ||
| 515 | 560 | ||
| 516 | public: | 561 | public: |
| 517 | // call PrepareHardLinks() after Init() | 562 | HRESULT CreateHardLink2(const FString &newFilePath, |
| 563 | const FString &existFilePath, bool &link_was_Created) const; | ||
| 564 | HRESULT DeleteLinkFileAlways_or_RemoveEmptyDir(const FString &path, bool checkThatFileIsEmpty) const; | ||
| 518 | HRESULT PrepareHardLinks(const CRecordVector<UInt32> *realIndices); // NULL means all items | 565 | HRESULT PrepareHardLinks(const CRecordVector<UInt32> *realIndices); // NULL means all items |
| 566 | #endif | ||
| 519 | 567 | ||
| 520 | #endif | 568 | private: |
| 521 | |||
| 522 | 569 | ||
| 523 | #ifdef SUPPORT_ALT_STREAMS | 570 | #ifdef SUPPORT_ALT_STREAMS |
| 524 | CObjectVector<CIndexToPathPair> _renamedFiles; | 571 | CObjectVector<CIndexToPathPair> _renamedFiles; |
| @@ -526,6 +573,7 @@ public: | |||
| 526 | 573 | ||
| 527 | // call it after Init() | 574 | // call it after Init() |
| 528 | 575 | ||
| 576 | public: | ||
| 529 | #ifndef Z7_SFX | 577 | #ifndef Z7_SFX |
| 530 | void SetBaseParentFolderIndex(UInt32 indexInArc) | 578 | void SetBaseParentFolderIndex(UInt32 indexInArc) |
| 531 | { | 579 | { |
| @@ -547,7 +595,6 @@ private: | |||
| 547 | 595 | ||
| 548 | HRESULT Read_fi_Props(); | 596 | HRESULT Read_fi_Props(); |
| 549 | void CorrectPathParts(); | 597 | void CorrectPathParts(); |
| 550 | void GetFiTimesCAM(CFiTimesCAM &pt); | ||
| 551 | void CreateFolders(); | 598 | void CreateFolders(); |
| 552 | 599 | ||
| 553 | HRESULT CheckExistFile(FString &fullProcessedPath, bool &needExit); | 600 | HRESULT CheckExistFile(FString &fullProcessedPath, bool &needExit); |
| @@ -556,8 +603,8 @@ private: | |||
| 556 | 603 | ||
| 557 | HRESULT CloseFile(); | 604 | HRESULT CloseFile(); |
| 558 | HRESULT CloseReparseAndFile(); | 605 | HRESULT CloseReparseAndFile(); |
| 559 | HRESULT CloseReparseAndFile2(); | ||
| 560 | HRESULT SetDirsTimes(); | 606 | HRESULT SetDirsTimes(); |
| 607 | HRESULT SetSecurityInfo(UInt32 indexInArc, const FString &path) const; | ||
| 561 | }; | 608 | }; |
| 562 | 609 | ||
| 563 | 610 | ||
diff --git a/CPP/Windows/FileDir.cpp b/CPP/Windows/FileDir.cpp index 10c4e98..ad0d8c9 100644 --- a/CPP/Windows/FileDir.cpp +++ b/CPP/Windows/FileDir.cpp | |||
| @@ -124,7 +124,7 @@ bool GetSystemDir(FString &path) | |||
| 124 | #endif // UNDER_CE | 124 | #endif // UNDER_CE |
| 125 | 125 | ||
| 126 | 126 | ||
| 127 | bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) | 127 | static bool SetFileTime_Base(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime, DWORD dwFlagsAndAttributes) |
| 128 | { | 128 | { |
| 129 | #ifndef _UNICODE | 129 | #ifndef _UNICODE |
| 130 | if (!g_IsNT) | 130 | if (!g_IsNT) |
| @@ -137,14 +137,14 @@ bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CF | |||
| 137 | HANDLE hDir = INVALID_HANDLE_VALUE; | 137 | HANDLE hDir = INVALID_HANDLE_VALUE; |
| 138 | IF_USE_MAIN_PATH | 138 | IF_USE_MAIN_PATH |
| 139 | hDir = ::CreateFileW(fs2us(path), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, | 139 | hDir = ::CreateFileW(fs2us(path), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, |
| 140 | NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); | 140 | NULL, OPEN_EXISTING, dwFlagsAndAttributes, NULL); |
| 141 | #ifdef Z7_LONG_PATH | 141 | #ifdef Z7_LONG_PATH |
| 142 | if (hDir == INVALID_HANDLE_VALUE && USE_SUPER_PATH) | 142 | if (hDir == INVALID_HANDLE_VALUE && USE_SUPER_PATH) |
| 143 | { | 143 | { |
| 144 | UString superPath; | 144 | UString superPath; |
| 145 | if (GetSuperPath(path, superPath, USE_MAIN_PATH)) | 145 | if (GetSuperPath(path, superPath, USE_MAIN_PATH)) |
| 146 | hDir = ::CreateFileW(superPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, | 146 | hDir = ::CreateFileW(superPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, |
| 147 | NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); | 147 | NULL, OPEN_EXISTING, dwFlagsAndAttributes, NULL); |
| 148 | } | 148 | } |
| 149 | #endif | 149 | #endif |
| 150 | 150 | ||
| @@ -157,6 +157,15 @@ bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CF | |||
| 157 | return res; | 157 | return res; |
| 158 | } | 158 | } |
| 159 | 159 | ||
| 160 | bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) | ||
| 161 | { | ||
| 162 | return SetFileTime_Base(path, cTime, aTime, mTime, FILE_FLAG_BACKUP_SEMANTICS); | ||
| 163 | } | ||
| 164 | |||
| 165 | bool SetLinkFileTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) | ||
| 166 | { | ||
| 167 | return SetFileTime_Base(path, cTime, aTime, mTime, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT); | ||
| 168 | } | ||
| 160 | 169 | ||
| 161 | 170 | ||
| 162 | bool SetFileAttrib(CFSTR path, DWORD attrib) | 171 | bool SetFileAttrib(CFSTR path, DWORD attrib) |
| @@ -1173,17 +1182,15 @@ bool GetCurrentDir(FString &path) | |||
| 1173 | 1182 | ||
| 1174 | 1183 | ||
| 1175 | 1184 | ||
| 1176 | bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) | 1185 | static bool SetFileTime_Base(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime, const int flags) |
| 1177 | { | 1186 | { |
| 1178 | // need testing | 1187 | // need testing |
| 1179 | /* | 1188 | /* |
| 1180 | struct utimbuf buf; | 1189 | struct utimbuf buf; |
| 1181 | struct stat st; | 1190 | struct stat st; |
| 1182 | UNUSED_VAR(cTime) | 1191 | UNUSED_VAR(cTime) |
| 1183 | |||
| 1184 | printf("\nstat = %s\n", path); | 1192 | printf("\nstat = %s\n", path); |
| 1185 | int ret = stat(path, &st); | 1193 | int ret = stat(path, &st); |
| 1186 | |||
| 1187 | if (ret == 0) | 1194 | if (ret == 0) |
| 1188 | { | 1195 | { |
| 1189 | buf.actime = st.st_atime; | 1196 | buf.actime = st.st_atime; |
| @@ -1195,47 +1202,42 @@ bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CF | |||
| 1195 | buf.actime = cur_time; | 1202 | buf.actime = cur_time; |
| 1196 | buf.modtime = cur_time; | 1203 | buf.modtime = cur_time; |
| 1197 | } | 1204 | } |
| 1198 | |||
| 1199 | if (aTime) | 1205 | if (aTime) |
| 1200 | { | 1206 | { |
| 1201 | UInt32 ut; | 1207 | UInt32 ut; |
| 1202 | if (NTime::FileTimeToUnixTime(*aTime, ut)) | 1208 | if (NTime::FileTimeToUnixTime(*aTime, ut)) |
| 1203 | buf.actime = ut; | 1209 | buf.actime = ut; |
| 1204 | } | 1210 | } |
| 1205 | |||
| 1206 | if (mTime) | 1211 | if (mTime) |
| 1207 | { | 1212 | { |
| 1208 | UInt32 ut; | 1213 | UInt32 ut; |
| 1209 | if (NTime::FileTimeToUnixTime(*mTime, ut)) | 1214 | if (NTime::FileTimeToUnixTime(*mTime, ut)) |
| 1210 | buf.modtime = ut; | 1215 | buf.modtime = ut; |
| 1211 | } | 1216 | } |
| 1212 | |||
| 1213 | return utime(path, &buf) == 0; | 1217 | return utime(path, &buf) == 0; |
| 1214 | */ | 1218 | */ |
| 1215 | 1219 | ||
| 1216 | // if (!aTime && !mTime) return true; | 1220 | // if (!aTime && !mTime) return true; |
| 1217 | |||
| 1218 | struct timespec times[2]; | 1221 | struct timespec times[2]; |
| 1219 | UNUSED_VAR(cTime) | 1222 | UNUSED_VAR(cTime) |
| 1220 | |||
| 1221 | bool needChange; | 1223 | bool needChange; |
| 1222 | needChange = FiTime_To_timespec(aTime, times[0]); | 1224 | needChange = FiTime_To_timespec(aTime, times[0]); |
| 1223 | needChange |= FiTime_To_timespec(mTime, times[1]); | 1225 | needChange |= FiTime_To_timespec(mTime, times[1]); |
| 1224 | 1226 | // if (mTime) { printf("\n time = %ld.%9ld\n", mTime->tv_sec, mTime->tv_nsec); } | |
| 1225 | /* | ||
| 1226 | if (mTime) | ||
| 1227 | { | ||
| 1228 | printf("\n time = %ld.%9ld\n", mTime->tv_sec, mTime->tv_nsec); | ||
| 1229 | } | ||
| 1230 | */ | ||
| 1231 | |||
| 1232 | if (!needChange) | 1227 | if (!needChange) |
| 1233 | return true; | 1228 | return true; |
| 1234 | const int flags = 0; // follow link | ||
| 1235 | // = AT_SYMLINK_NOFOLLOW; // don't follow link | ||
| 1236 | return utimensat(AT_FDCWD, path, times, flags) == 0; | 1229 | return utimensat(AT_FDCWD, path, times, flags) == 0; |
| 1237 | } | 1230 | } |
| 1238 | 1231 | ||
| 1232 | bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) | ||
| 1233 | { | ||
| 1234 | return SetFileTime_Base(path, cTime, aTime, mTime, 0); // (flags = 0) means follow_link | ||
| 1235 | } | ||
| 1236 | |||
| 1237 | bool SetLinkFileTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) | ||
| 1238 | { | ||
| 1239 | return SetFileTime_Base(path, cTime, aTime, mTime, AT_SYMLINK_NOFOLLOW); | ||
| 1240 | } | ||
| 1239 | 1241 | ||
| 1240 | 1242 | ||
| 1241 | struct C_umask | 1243 | struct C_umask |
diff --git a/CPP/Windows/FileDir.h b/CPP/Windows/FileDir.h index 65e6368..9ba98fc 100644 --- a/CPP/Windows/FileDir.h +++ b/CPP/Windows/FileDir.h | |||
| @@ -18,9 +18,20 @@ bool GetSystemDir(FString &path); | |||
| 18 | WIN32 API : SetFileTime() doesn't allow to set zero timestamps in file | 18 | WIN32 API : SetFileTime() doesn't allow to set zero timestamps in file |
| 19 | but linux : allows unix time = 0 in filesystem | 19 | but linux : allows unix time = 0 in filesystem |
| 20 | */ | 20 | */ |
| 21 | 21 | /* | |
| 22 | SetDirTime() can be used to set time for file or for dir. | ||
| 23 | If path is symbolic link, SetDirTime() will follow symbolic link, | ||
| 24 | and it will set timestamps of symbolic link's target file or dir. | ||
| 25 | */ | ||
| 22 | bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime); | 26 | bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime); |
| 23 | 27 | ||
| 28 | /* | ||
| 29 | SetLinkFileTime() doesn't follow symbolic link, | ||
| 30 | and it sets timestamps for symbolic link file itself. | ||
| 31 | If (path) is not symbolic link, it still can work (at least in some new OS versions). | ||
| 32 | */ | ||
| 33 | bool SetLinkFileTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime); | ||
| 34 | |||
| 24 | 35 | ||
| 25 | #ifdef _WIN32 | 36 | #ifdef _WIN32 |
| 26 | 37 | ||
