diff options
-rw-r--r-- | C/7zVersion.h | 6 | ||||
-rw-r--r-- | C/LzFind.c | 2 | ||||
-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 | ||||
-rw-r--r-- | DOC/7zip.wxs | 2 | ||||
-rw-r--r-- | DOC/readme.txt | 2 | ||||
-rw-r--r-- | DOC/src-history.txt | 10 |
14 files changed, 577 insertions, 282 deletions
diff --git a/C/7zVersion.h b/C/7zVersion.h index 72733f7..b6142e9 100644 --- a/C/7zVersion.h +++ b/C/7zVersion.h | |||
@@ -1,7 +1,7 @@ | |||
1 | #define MY_VER_MAJOR 25 | 1 | #define MY_VER_MAJOR 25 |
2 | #define MY_VER_MINOR 0 | 2 | #define MY_VER_MINOR 1 |
3 | #define MY_VER_BUILD 0 | 3 | #define MY_VER_BUILD 0 |
4 | #define MY_VERSION_NUMBERS "25.00" | 4 | #define MY_VERSION_NUMBERS "25.01" |
5 | #define MY_VERSION MY_VERSION_NUMBERS | 5 | #define MY_VERSION MY_VERSION_NUMBERS |
6 | 6 | ||
7 | #ifdef MY_CPU_NAME | 7 | #ifdef MY_CPU_NAME |
@@ -10,7 +10,7 @@ | |||
10 | #define MY_VERSION_CPU MY_VERSION | 10 | #define MY_VERSION_CPU MY_VERSION |
11 | #endif | 11 | #endif |
12 | 12 | ||
13 | #define MY_DATE "2025-07-05" | 13 | #define MY_DATE "2025-08-03" |
14 | #undef MY_COPYRIGHT | 14 | #undef MY_COPYRIGHT |
15 | #undef MY_VERSION_COPYRIGHT_DATE | 15 | #undef MY_VERSION_COPYRIGHT_DATE |
16 | #define MY_AUTHOR_NAME "Igor Pavlov" | 16 | #define MY_AUTHOR_NAME "Igor Pavlov" |
@@ -598,7 +598,7 @@ void MatchFinder_Init(void *_p) | |||
598 | 598 | ||
599 | #ifdef MY_CPU_X86_OR_AMD64 | 599 | #ifdef MY_CPU_X86_OR_AMD64 |
600 | #if defined(__clang__) && (__clang_major__ >= 4) \ | 600 | #if defined(__clang__) && (__clang_major__ >= 4) \ |
601 | || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40701) | 601 | || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) |
602 | // || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1900) | 602 | // || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1900) |
603 | 603 | ||
604 | #define USE_LZFIND_SATUR_SUB_128 | 604 | #define USE_LZFIND_SATUR_SUB_128 |
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 | ||
diff --git a/DOC/7zip.wxs b/DOC/7zip.wxs index d369074..703e22e 100644 --- a/DOC/7zip.wxs +++ b/DOC/7zip.wxs | |||
@@ -1,7 +1,7 @@ | |||
1 | <?xml version="1.0"?> | 1 | <?xml version="1.0"?> |
2 | 2 | ||
3 | <?define VerMajor = "25" ?> | 3 | <?define VerMajor = "25" ?> |
4 | <?define VerMinor = "00" ?> | 4 | <?define VerMinor = "01" ?> |
5 | <?define VerBuild = "00" ?> | 5 | <?define VerBuild = "00" ?> |
6 | <?define MmVer = "$(var.VerMajor).$(var.VerMinor)" ?> | 6 | <?define MmVer = "$(var.VerMajor).$(var.VerMinor)" ?> |
7 | <?define MmHex = "$(var.VerMajor)$(var.VerMinor)" ?> | 7 | <?define MmHex = "$(var.VerMajor)$(var.VerMinor)" ?> |
diff --git a/DOC/readme.txt b/DOC/readme.txt index 7fbbdc8..cc89a39 100644 --- a/DOC/readme.txt +++ b/DOC/readme.txt | |||
@@ -1,4 +1,4 @@ | |||
1 | 7-Zip 25.00 Sources | 1 | 7-Zip 25.01 Sources |
2 | ------------------- | 2 | ------------------- |
3 | 3 | ||
4 | 7-Zip is a file archiver for Windows. | 4 | 7-Zip is a file archiver for Windows. |
diff --git a/DOC/src-history.txt b/DOC/src-history.txt index 70b11b5..48c9647 100644 --- a/DOC/src-history.txt +++ b/DOC/src-history.txt | |||
@@ -1,6 +1,14 @@ | |||
1 | HISTORY of the 7-Zip source code | 1 | HISTORY of the 7-Zip source code |
2 | -------------------------------- | 2 | -------------------------------- |
3 | 3 | ||
4 | 25.01 2025-08-03 | ||
5 | ------------------------- | ||
6 | - The code for handling symbolic links has been changed | ||
7 | to provide greater security when extracting files from archives. | ||
8 | Command line switch -snld20 can be used to bypass default security | ||
9 | checks when creating symbolic links. | ||
10 | |||
11 | |||
4 | 25.00 2025-07-05 | 12 | 25.00 2025-07-05 |
5 | ------------------------- | 13 | ------------------------- |
6 | - 7-Zip for Windows can now use more than 64 CPU threads for compression | 14 | - 7-Zip for Windows can now use more than 64 CPU threads for compression |
@@ -11,6 +19,8 @@ HISTORY of the 7-Zip source code | |||
11 | - deflate (zip/gz) compression speed was increased by 1-3%. | 19 | - deflate (zip/gz) compression speed was increased by 1-3%. |
12 | - improved support for zip, cpio and fat archives. | 20 | - improved support for zip, cpio and fat archives. |
13 | - fixed some bugs and vulnerabilities. | 21 | - fixed some bugs and vulnerabilities. |
22 | - the bug was fixed : CVE-2025-53816 : 7-Zip could work incorrectly for some incorrect RAR archives. | ||
23 | - the bug was fixed : CVE-2025-53817 : 7-Zip could crash for some incorrect COM (Compound File) archives. | ||
14 | 24 | ||
15 | 25 | ||
16 | 24.09 2024-11-29 | 26 | 24.09 2024-11-29 |