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 @@ #define MY_VER_MAJOR 25 -#define MY_VER_MINOR 0 +#define MY_VER_MINOR 1 #define MY_VER_BUILD 0 -#define MY_VERSION_NUMBERS "25.00" +#define MY_VERSION_NUMBERS "25.01" #define MY_VERSION MY_VERSION_NUMBERS #ifdef MY_CPU_NAME @@ -10,7 +10,7 @@ #define MY_VERSION_CPU MY_VERSION #endif -#define MY_DATE "2025-07-05" +#define MY_DATE "2025-08-03" #undef MY_COPYRIGHT #undef MY_VERSION_COPYRIGHT_DATE #define MY_AUTHOR_NAME "Igor Pavlov" diff --git a/C/LzFind.c b/C/LzFind.c index 6aba919..330bc17 100644 --- a/C/LzFind.c +++ b/C/LzFind.c @@ -598,7 +598,7 @@ void MatchFinder_Init(void *_p) #ifdef MY_CPU_X86_OR_AMD64 #if defined(__clang__) && (__clang_major__ >= 4) \ - || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40701) + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) // || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1900) #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 SOURCE=..\..\Compress\PpmdZip.h # End Source File # End Group -# Begin Group "RangeCoder" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\RangeCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\RangeCoderBit.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\RangeCoderBitTree.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\RangeCoderOpt.h -# End Source File -# End Group # Begin Group "Shrink" # 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() if (wres == 0) { wres = CanWriteEvent.Create(); if (wres == 0) { + wres = #ifdef _WIN32 - if (Encoder->_props.NumThreadGroups != 0) - { - const UInt32 group = ThreadNextGroup_GetNext(&Encoder->ThreadNextGroup); - wres = Thread.Create_With_Group(MFThread, this, group, 0); // affinity - } - else + Encoder->_props.NumThreadGroups > 1 ? + Thread.Create_With_Group(MFThread, this, ThreadNextGroup_GetNext(&Encoder->ThreadNextGroup), 0) : // affinity #endif - if (Encoder->_props.Affinity != 0) - wres = Thread.Create_With_Affinity(MFThread, this, (CAffinityMask)Encoder->_props.Affinity); - else - wres = Thread.Create(MFThread, this); + Encoder->_props.Affinity != 0 ? + Thread.Create_With_Affinity(MFThread, this, (CAffinityMask)Encoder->_props.Affinity) : + Thread.Create(MFThread, this); }}} return HRESULT_FROM_WIN32(wres); } @@ -935,14 +931,13 @@ void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, unsigned lastByte HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) { - ThreadNextGroup_Init(&ThreadNextGroup, _props.NumThreadGroups, 0); // startGroup - NumBlocks = 0; - #ifndef Z7_ST +#ifndef Z7_ST Progress = progress; + ThreadNextGroup_Init(&ThreadNextGroup, _props.NumThreadGroups, 0); // startGroup RINOK(Create()) for (UInt32 t = 0; t < NumThreads; t++) - #endif +#endif { #ifndef Z7_ST 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) file.Name = (const wchar_t *)p; file.NameLen = 0; if (size >= sizeof(wchar_t)) - file.NameLen = size / sizeof(wchar_t) - 1; + file.NameLen = size / (unsigned)sizeof(wchar_t) - 1; } else #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 SYS_OBJS = \ $O/MyWindows.o \ - $O/TimeUtils.o \ endif @@ -53,6 +52,7 @@ WIN_OBJS = \ $O/FileName.o \ $O/PropVariant.o \ $O/PropVariantConv.o \ + $O/TimeUtils.o \ 7ZIP_COMMON_OBJS = \ $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[] = { "spf", SWFRM_STRING_SINGL(0) }, { "snh", SWFRM_MINUS }, - { "snld", SWFRM_MINUS }, + { "snld", SWFRM_STRING }, { "snl", SWFRM_MINUS }, { "sni", SWFRM_SIMPLE }, @@ -1479,14 +1479,8 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) SetBoolPair(parser, NKey::kStoreOwnerId, options.StoreOwnerId); SetBoolPair(parser, NKey::kStoreOwnerName, options.StoreOwnerName); - - CBoolPair symLinks_AllowDangerous; - SetBoolPair(parser, NKey::kSymLinks_AllowDangerous, symLinks_AllowDangerous); - - /* bool supportSymLink = options.SymLinks.Val; - if (!options.SymLinks.Def) { if (isExtractOrList) @@ -1494,7 +1488,6 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) else supportSymLink = false; } - #ifdef ENV_HAVE_LSTAT if (supportSymLink) global_use_lstat = 1; @@ -1503,7 +1496,6 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) #endif */ - if (isExtractOrList) { CExtractOptionsBase &eo = options.ExtractOptions; @@ -1527,7 +1519,15 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) if (!options.SymLinks.Def) nt.SymLinks.Val = true; - nt.SymLinks_AllowDangerous = symLinks_AllowDangerous; + if (parser[NKey::kSymLinks_AllowDangerous].ThereIs) + { + const UString &s = parser[NKey::kSymLinks_AllowDangerous].PostStrings[0]; + UInt32 v = 9; // default value for "-snld" instead of default = 5 without "-snld". + if (!s.IsEmpty()) + if (!StringToUInt32(s, v)) + throw CArcCmdLineException("Unsupported switch postfix -snld", s); + nt.SymLinks_DangerousLevel = (unsigned)v; + } nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs; 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"; #ifdef SUPPORT_LINKS static const char * const kCantCreateHardLink = "Cannot create hard link"; static const char * const kCantCreateSymLink = "Cannot create symbolic link"; +static const char * const k_HardLink_to_SymLink_Ignored = "Hard link to symbolic link was ignored"; +static const char * const k_CantDelete_File_for_SymLink = "Cannot delete file for symbolic link creation"; +static const char * const k_CantDelete_Dir_for_SymLink = "Cannot delete directory for symbolic link creation"; #endif static const unsigned k_LinkDataSize_LIMIT = 1 << 12; +#ifdef SUPPORT_LINKS #if WCHAR_PATH_SEPARATOR != L'/' // we convert linux slashes to windows slashes for further processing. // also we convert linux backslashes to BackslashReplacement character. @@ -67,7 +71,7 @@ static const unsigned k_LinkDataSize_LIMIT = 1 << 12; #else #define REPLACE_SLASHES_from_Linux_to_Sys(s) #endif - +#endif #ifndef Z7_SFX @@ -326,13 +330,14 @@ void CArchiveExtractCallback::Init( _outFileStream.Release(); _bufPtrSeqOutStream.Release(); - #ifdef SUPPORT_LINKS +#ifdef SUPPORT_LINKS _hardLinks.Clear(); - #endif + _postLinks.Clear(); +#endif - #ifdef SUPPORT_ALT_STREAMS +#ifdef SUPPORT_ALT_STREAMS _renamedFiles.Clear(); - #endif +#endif _ntOptions = ntOptions; _wildcardCensor = wildcardCensor; @@ -455,7 +460,8 @@ Z7_COM7F_IMF(CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const U } -void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath) +void CArchiveExtractCallback::CreateComplexDirectory( + const UStringVector &dirPathParts, bool isFinal, FString &fullPath) { // we use (_item.IsDir) in this function @@ -487,7 +493,7 @@ void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPat const UString &s = dirPathParts[i]; fullPath += us2fs(s); - const bool isFinalDir = (i == dirPathParts.Size() - 1 && _item.IsDir); + const bool isFinalDir = (i == dirPathParts.Size() - 1 && isFinal && _item.IsDir); if (fullPath.IsEmpty()) { @@ -548,7 +554,7 @@ static void AddPathToMessage(UString &s, const FString &path) s += fs2us(path); } -HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FString &path) +HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FString &path) const { UString s (message); AddPathToMessage(s, path); @@ -556,7 +562,7 @@ HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FSt } -HRESULT CArchiveExtractCallback::SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path) +HRESULT CArchiveExtractCallback::SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path) const { UString s (message); if (errorCode != S_OK) @@ -568,13 +574,13 @@ HRESULT CArchiveExtractCallback::SendMessageError_with_Error(HRESULT errorCode, return _extractCallback2->MessageError(s); } -HRESULT CArchiveExtractCallback::SendMessageError_with_LastError(const char *message, const FString &path) +HRESULT CArchiveExtractCallback::SendMessageError_with_LastError(const char *message, const FString &path) const { const HRESULT errorCode = GetLastError_noZero_HRESULT(); return SendMessageError_with_Error(errorCode, message, path); } -HRESULT CArchiveExtractCallback::SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2) +HRESULT CArchiveExtractCallback::SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2) const { UString s (message); if (errorCode != 0) @@ -588,7 +594,7 @@ HRESULT CArchiveExtractCallback::SendMessageError2(HRESULT errorCode, const char } HRESULT CArchiveExtractCallback::SendMessageError2_with_LastError( - const char *message, const FString &path1, const FString &path2) + const char *message, const FString &path1, const FString &path2) const { const HRESULT errorCode = GetLastError_noZero_HRESULT(); return SendMessageError2(errorCode, message, path1, path2); @@ -627,6 +633,7 @@ Z7_COM7F_IMF(CGetProp::GetProp(PROPID propID, PROPVARIANT *value)) struct CLinkLevelsInfo { bool IsAbsolute; + bool ParentDirDots_after_NonParent; int LowLevel; int FinalLevel; @@ -640,6 +647,8 @@ void CLinkLevelsInfo::Parse(const UString &path, bool isWSL) NName::IsAbsolutePath(path); LowLevel = 0; FinalLevel = 0; + ParentDirDots_after_NonParent = false; + bool nonParentDir = false; UStringVector parts; SplitPathToParts(path, parts); @@ -658,12 +667,17 @@ void CLinkLevelsInfo::Parse(const UString &path, bool isWSL) continue; if (s.IsEqualTo("..")) { + if (IsAbsolute || nonParentDir) + ParentDirDots_after_NonParent = true; level--; if (LowLevel > level) - LowLevel = level; + LowLevel = level; } else + { + nonParentDir = true; level++; + } } FinalLevel = level; @@ -915,7 +929,7 @@ HRESULT CArchiveExtractCallback::ReadLink() #ifndef _WIN32 static HRESULT GetOwner(IInArchive *archive, - UInt32 index, UInt32 pidName, UInt32 pidId, COwnerInfo &res) + UInt32 index, UInt32 pidName, UInt32 pidId, CProcessedFileInfo::COwnerInfo &res) { { NWindows::NCOM::CPropVariant prop; @@ -1047,7 +1061,7 @@ void CArchiveExtractCallback::CorrectPathParts() } -void CArchiveExtractCallback::GetFiTimesCAM(CFiTimesCAM &pt) +static void GetFiTimesCAM(const CProcessedFileInfo &fi, CFiTimesCAM &pt, const CArc &arc) { pt.CTime_Defined = false; pt.ATime_Defined = false; @@ -1055,27 +1069,27 @@ void CArchiveExtractCallback::GetFiTimesCAM(CFiTimesCAM &pt) // if (Write_MTime) { - if (_fi.MTime.Def) + if (fi.MTime.Def) { - _fi.MTime.Write_To_FiTime(pt.MTime); + fi.MTime.Write_To_FiTime(pt.MTime); pt.MTime_Defined = true; } - else if (_arc->MTime.Def) + else if (arc.MTime.Def) { - _arc->MTime.Write_To_FiTime(pt.MTime); + arc.MTime.Write_To_FiTime(pt.MTime); pt.MTime_Defined = true; } } - if (/* Write_CTime && */ _fi.CTime.Def) + if (/* Write_CTime && */ fi.CTime.Def) { - _fi.CTime.Write_To_FiTime(pt.CTime); + fi.CTime.Write_To_FiTime(pt.CTime); pt.CTime_Defined = true; } - if (/* Write_ATime && */ _fi.ATime.Def) + if (/* Write_ATime && */ fi.ATime.Def) { - _fi.ATime.Write_To_FiTime(pt.ATime); + fi.ATime.Write_To_FiTime(pt.ATime); pt.ATime_Defined = true; } } @@ -1086,6 +1100,7 @@ void CArchiveExtractCallback::CreateFolders() // 21.04 : we don't change original (_item.PathParts) here UStringVector pathParts = _item.PathParts; + bool isFinal = true; // bool is_DirOp = false; if (!pathParts.IsEmpty()) { @@ -1095,12 +1110,15 @@ void CArchiveExtractCallback::CreateFolders() but if we create dir item here, it's not problem. */ if (!_item.IsDir #ifdef SUPPORT_LINKS - #ifndef WIN32 + // #ifndef WIN32 || !_link.LinkPath.IsEmpty() - #endif + // #endif #endif ) + { pathParts.DeleteBack(); + isFinal = false; // last path part was excluded + } // else is_DirOp = true; } @@ -1124,7 +1142,7 @@ void CArchiveExtractCallback::CreateFolders() */ FString fullPathNew; - CreateComplexDirectory(pathParts, fullPathNew); + CreateComplexDirectory(pathParts, isFinal, fullPathNew); /* if (is_DirOp) @@ -1145,12 +1163,12 @@ void CArchiveExtractCallback::CreateFolders() return; CDirPathTime pt; - GetFiTimesCAM(pt); + GetFiTimesCAM(_fi, pt, *_arc); if (pt.IsSomeTimeDefined()) { pt.Path = fullPathNew; - pt.SetDirTime(); + pt.SetDirTime_to_FS_2(); _extractedFolders.Add(pt); } } @@ -1292,9 +1310,11 @@ HRESULT CArchiveExtractCallback::CheckExistFile(FString &fullProcessedPath, bool - - - +/* +return: + needExit = false: caller will use (outStreamLoc) and _hashStreamSpec + needExit = true : caller will not use (outStreamLoc) and _hashStreamSpec. +*/ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr &outStreamLoc, bool &needExit) { needExit = true; @@ -1383,12 +1403,15 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtrGetRawProps) + { + const void *data; + UInt32 dataSize; + UInt32 propType; + _arc->GetRawProps->GetRawProp(indexInArc, kpidNtSecure, &data, &dataSize, &propType); + if (dataSize != 0) + { + if (propType != NPropDataType::kRaw) + return E_FAIL; + if (CheckNtSecure((const Byte *)data, dataSize)) + { + SECURITY_INFORMATION securInfo = DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION; + if (_saclEnabled) + securInfo |= SACL_SECURITY_INFORMATION; + // if (! + ::SetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(void *)(const Byte *)(data)); + { + // RINOK(SendMessageError_with_LastError("SetFileSecurity FAILS", path)) + } + } + } + } + return S_OK; +} +#endif // Z7_USE_SECURITY_CODE + + Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 opRes)) { COM_TRY_BEGIN @@ -2490,27 +2705,9 @@ Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 opRes)) RINOK(CloseReparseAndFile()) - #ifdef Z7_USE_SECURITY_CODE - if (!_stdOutMode && _extractMode && _ntOptions.NtSecurity.Val && _arc->GetRawProps) - { - const void *data; - UInt32 dataSize; - UInt32 propType; - _arc->GetRawProps->GetRawProp(_index, kpidNtSecure, &data, &dataSize, &propType); - if (dataSize != 0) - { - if (propType != NPropDataType::kRaw) - return E_FAIL; - if (CheckNtSecure((const Byte *)data, dataSize)) - { - SECURITY_INFORMATION securInfo = DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION; - if (_saclEnabled) - securInfo |= SACL_SECURITY_INFORMATION; - ::SetFileSecurityW(fs2us(_diskFilePath), securInfo, (PSECURITY_DESCRIPTOR)(void *)(const Byte *)(data)); - } - } - } - #endif // Z7_USE_SECURITY_CODE +#ifdef Z7_USE_SECURITY_CODE + RINOK(SetSecurityInfo(_index, _diskFilePath)) +#endif if (!_curSize_Defined) GetUnpackSize(); @@ -2754,15 +2951,58 @@ void CDirPathSortPair::SetNumSlashes(const FChar *s) } -bool CDirPathTime::SetDirTime() const +bool CFiTimesCAM::SetDirTime_to_FS(CFSTR path) const { - return NDir::SetDirTime(Path, + // it's same function for dir and for file + return NDir::SetDirTime(path, CTime_Defined ? &CTime : NULL, ATime_Defined ? &ATime : NULL, MTime_Defined ? &MTime : NULL); } +#ifdef SUPPORT_LINKS + +bool CFiTimesCAM::SetLinkFileTime_to_FS(CFSTR path) const +{ + // it's same function for dir and for file + return NDir::SetLinkFileTime(path, + CTime_Defined ? &CTime : NULL, + ATime_Defined ? &ATime : NULL, + MTime_Defined ? &MTime : NULL); +} + +HRESULT CArchiveExtractCallback::SetPostLinks() const +{ + FOR_VECTOR (i, _postLinks) + { + const CPostLink &link = _postLinks[i]; + bool linkWasSet = false; + RINOK(SetLink2(*this, link, linkWasSet)) + if (linkWasSet) + { +#ifdef _WIN32 + // Linux now doesn't support permissions for symlinks + SetAttrib_Base(link.fullProcessedPath_from, link.item_FileInfo, *this); +#endif + + CFiTimesCAM pt; + GetFiTimesCAM(link.item_FileInfo, pt, *_arc); + if (pt.IsSomeTimeDefined()) + pt.SetLinkFileTime_to_FS(link.fullProcessedPath_from); + +#ifdef Z7_USE_SECURITY_CODE + // we set security information after timestamps setting + RINOK(SetSecurityInfo(link.Index_in_Arc, link.fullProcessedPath_from)) +#endif + } + } + return S_OK; +} + +#endif + + HRESULT CArchiveExtractCallback::SetDirsTimes() { if (!_arc) @@ -2786,7 +3026,7 @@ HRESULT CArchiveExtractCallback::SetDirsTimes() for (i = 0; i < pairs.Size(); i++) { const CDirPathTime &dpt = _extractedFolders[pairs[i].Index]; - if (!dpt.SetDirTime()) + if (!dpt.SetDirTime_to_FS_2()) { // result = E_FAIL; // do we need error message here in Windows and in posix? @@ -2818,10 +3058,20 @@ HRESULT CArchiveExtractCallback::SetDirsTimes() HRESULT CArchiveExtractCallback::CloseArc() { + // we call CloseReparseAndFile() here because we can have non-closed file in some cases? HRESULT res = CloseReparseAndFile(); - const HRESULT res2 = SetDirsTimes(); - if (res == S_OK) - res = res2; +#ifdef SUPPORT_LINKS + { + const HRESULT res2 = SetPostLinks(); + if (res == S_OK) + res = res2; + } +#endif + { + const HRESULT res2 = SetDirsTimes(); + if (res == S_OK) + res = res2; + } _arc = NULL; return res; } 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 { CBoolPair NtSecurity; CBoolPair SymLinks; - CBoolPair SymLinks_AllowDangerous; CBoolPair HardLinks; CBoolPair AltStreams; bool ReplaceColonForAltStream; @@ -66,6 +65,8 @@ struct CExtractNtOptions bool PreserveATime; bool OpenShareForWrite; + unsigned SymLinks_DangerousLevel; + UInt64 MemLimit; CExtractNtOptions(): @@ -74,10 +75,10 @@ struct CExtractNtOptions ExtractOwner(false), PreserveATime(false), OpenShareForWrite(false), + SymLinks_DangerousLevel(5), MemLimit((UInt64)(Int64)-1) { SymLinks.Val = true; - SymLinks_AllowDangerous.Val = false; HardLinks.Val = true; AltStreams.Val = true; @@ -166,19 +167,22 @@ struct CFiTimesCAM ATime_Defined | MTime_Defined; } + bool SetDirTime_to_FS(CFSTR path) const; +#ifdef SUPPORT_LINKS + bool SetLinkFileTime_to_FS(CFSTR path) const; +#endif }; struct CDirPathTime: public CFiTimesCAM { FString Path; - bool SetDirTime() const; + bool SetDirTime_to_FS_2() const { return SetDirTime_to_FS(Path); } }; #ifdef SUPPORT_LINKS - enum ELinkType { k_LinkType_HardLink, @@ -227,6 +231,15 @@ private: #endif // SUPPORT_LINKS + +struct CProcessedFileInfo +{ + CArcTime CTime; + CArcTime ATime; + CArcTime MTime; + UInt32 Attrib; + bool Attrib_Defined; + #ifndef _WIN32 struct COwnerInfo @@ -243,8 +256,76 @@ struct COwnerInfo } }; + COwnerInfo Owner; + COwnerInfo Group; #endif + void Clear() + { +#ifndef _WIN32 + Attrib_Defined = false; + Owner.Clear(); +#endif + } + + bool IsReparse() const + { + return (Attrib_Defined && (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0); + } + + bool IsLinuxSymLink() const + { + return (Attrib_Defined && MY_LIN_S_ISLNK(Attrib >> 16)); + } + + void SetFromPosixAttrib(UInt32 a) + { + // here we set only part of combined attribute required by SetFileAttrib() call + #ifdef _WIN32 + // Windows sets FILE_ATTRIBUTE_NORMAL, if we try to set 0 as attribute. + Attrib = MY_LIN_S_ISDIR(a) ? + FILE_ATTRIBUTE_DIRECTORY : + FILE_ATTRIBUTE_ARCHIVE; + if ((a & 0222) == 0) // (& S_IWUSR) in p7zip + Attrib |= FILE_ATTRIBUTE_READONLY; + // 22.00 : we need type bits for (MY_LIN_S_IFLNK) for IsLinuxSymLink() + a &= MY_LIN_S_IFMT; + if (a == MY_LIN_S_IFLNK) + Attrib |= (a << 16); + #else + Attrib = (a << 16) | FILE_ATTRIBUTE_UNIX_EXTENSION; + #endif + Attrib_Defined = true; + } +}; + + +#ifdef SUPPORT_LINKS + +struct CPostLink +{ + UInt32 Index_in_Arc; + bool item_IsDir; // _item.IsDir + UString item_Path; // _item.Path; + UStringVector item_PathParts; // _item.PathParts; + CProcessedFileInfo item_FileInfo; // _fi + FString fullProcessedPath_from; // full file path in FS + CLinkInfo LinkInfo; +}; + +/* +struct CPostLinks +{ + void Clear() + { + Links.Clear(); + } +}; +*/ + +#endif // SUPPORT_LINKS + + class CArchiveExtractCallback Z7_final: public IArchiveExtractCallback, @@ -292,8 +373,9 @@ public: private: const CArc *_arc; +public: CExtractNtOptions _ntOptions; - +private: bool _encrypted; bool _isSplit; bool _curSize_Defined; @@ -325,7 +407,9 @@ private: CMyComPtr _cryptoGetTextPassword; FString _dirPathPrefix; +public: FString _dirPathPrefix_Full; +private: #ifndef Z7_SFX @@ -337,49 +421,7 @@ private: CReadArcItem _item; FString _diskFilePath; - struct CProcessedFileInfo - { - CArcTime CTime; - CArcTime ATime; - CArcTime MTime; - UInt32 Attrib; - bool Attrib_Defined; - - #ifndef _WIN32 - COwnerInfo Owner; - COwnerInfo Group; - #endif - - bool IsReparse() const - { - return (Attrib_Defined && (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0); - } - - bool IsLinuxSymLink() const - { - return (Attrib_Defined && MY_LIN_S_ISLNK(Attrib >> 16)); - } - - void SetFromPosixAttrib(UInt32 a) - { - // here we set only part of combined attribute required by SetFileAttrib() call - #ifdef _WIN32 - // Windows sets FILE_ATTRIBUTE_NORMAL, if we try to set 0 as attribute. - Attrib = MY_LIN_S_ISDIR(a) ? - FILE_ATTRIBUTE_DIRECTORY : - FILE_ATTRIBUTE_ARCHIVE; - if ((a & 0222) == 0) // (& S_IWUSR) in p7zip - Attrib |= FILE_ATTRIBUTE_READONLY; - // 22.00 : we need type bits for (MY_LIN_S_IFLNK) for IsLinuxSymLink() - a &= MY_LIN_S_IFMT; - if (a == MY_LIN_S_IFLNK) - Attrib |= (a << 16); - #else - Attrib = (a << 16) | FILE_ATTRIBUTE_UNIX_EXTENSION; - #endif - Attrib_Defined = true; - } - } _fi; + CProcessedFileInfo _fi; UInt64 _position; UInt64 _curSize; @@ -421,20 +463,21 @@ private: // CObjectVector _delayedSymLinks; #endif - void CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath); + void CreateComplexDirectory( + const UStringVector &dirPathParts, bool isFinal, FString &fullPath); HRESULT GetTime(UInt32 index, PROPID propID, CArcTime &ft); HRESULT GetUnpackSize(); FString Hash_GetFullFilePath(); - void SetAttrib(); + void SetAttrib() const; public: - HRESULT SendMessageError(const char *message, const FString &path); - HRESULT SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path); - HRESULT SendMessageError_with_LastError(const char *message, const FString &path); - HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2); - HRESULT SendMessageError2_with_LastError(const char *message, const FString &path1, const FString &path2); + HRESULT SendMessageError(const char *message, const FString &path) const; + HRESULT SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path) const; + HRESULT SendMessageError_with_LastError(const char *message, const FString &path) const; + HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2) const; + HRESULT SendMessageError2_with_LastError(const char *message, const FString &path1, const FString &path2) const; #if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) NExtract::NZoneIdMode::EEnum ZoneMode; @@ -497,10 +540,11 @@ public: UInt64 packSize); - #ifdef SUPPORT_LINKS +#ifdef SUPPORT_LINKS private: CHardLinks _hardLinks; + CObjectVector _postLinks; CLinkInfo _link; // const void *NtReparse_Data; // UInt32 NtReparse_Size; @@ -512,13 +556,16 @@ private: const FString &fullProcessedPath_from, const CLinkInfo &linkInfo, bool &linkWasSet); + HRESULT SetPostLinks() const; public: - // call PrepareHardLinks() after Init() + HRESULT CreateHardLink2(const FString &newFilePath, + const FString &existFilePath, bool &link_was_Created) const; + HRESULT DeleteLinkFileAlways_or_RemoveEmptyDir(const FString &path, bool checkThatFileIsEmpty) const; HRESULT PrepareHardLinks(const CRecordVector *realIndices); // NULL means all items +#endif - #endif - +private: #ifdef SUPPORT_ALT_STREAMS CObjectVector _renamedFiles; @@ -526,6 +573,7 @@ public: // call it after Init() +public: #ifndef Z7_SFX void SetBaseParentFolderIndex(UInt32 indexInArc) { @@ -547,7 +595,6 @@ private: HRESULT Read_fi_Props(); void CorrectPathParts(); - void GetFiTimesCAM(CFiTimesCAM &pt); void CreateFolders(); HRESULT CheckExistFile(FString &fullProcessedPath, bool &needExit); @@ -556,8 +603,8 @@ private: HRESULT CloseFile(); HRESULT CloseReparseAndFile(); - HRESULT CloseReparseAndFile2(); HRESULT SetDirsTimes(); + HRESULT SetSecurityInfo(UInt32 indexInArc, const FString &path) const; }; 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) #endif // UNDER_CE -bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) +static bool SetFileTime_Base(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime, DWORD dwFlagsAndAttributes) { #ifndef _UNICODE if (!g_IsNT) @@ -137,14 +137,14 @@ bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CF HANDLE hDir = INVALID_HANDLE_VALUE; IF_USE_MAIN_PATH hDir = ::CreateFileW(fs2us(path), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + NULL, OPEN_EXISTING, dwFlagsAndAttributes, NULL); #ifdef Z7_LONG_PATH if (hDir == INVALID_HANDLE_VALUE && USE_SUPER_PATH) { UString superPath; if (GetSuperPath(path, superPath, USE_MAIN_PATH)) hDir = ::CreateFileW(superPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + NULL, OPEN_EXISTING, dwFlagsAndAttributes, NULL); } #endif @@ -157,6 +157,15 @@ bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CF return res; } +bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) +{ + return SetFileTime_Base(path, cTime, aTime, mTime, FILE_FLAG_BACKUP_SEMANTICS); +} + +bool SetLinkFileTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) +{ + return SetFileTime_Base(path, cTime, aTime, mTime, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT); +} bool SetFileAttrib(CFSTR path, DWORD attrib) @@ -1173,17 +1182,15 @@ bool GetCurrentDir(FString &path) -bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) +static bool SetFileTime_Base(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime, const int flags) { // need testing /* struct utimbuf buf; struct stat st; UNUSED_VAR(cTime) - printf("\nstat = %s\n", path); int ret = stat(path, &st); - if (ret == 0) { buf.actime = st.st_atime; @@ -1195,47 +1202,42 @@ bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CF buf.actime = cur_time; buf.modtime = cur_time; } - if (aTime) { UInt32 ut; if (NTime::FileTimeToUnixTime(*aTime, ut)) buf.actime = ut; } - if (mTime) { UInt32 ut; if (NTime::FileTimeToUnixTime(*mTime, ut)) buf.modtime = ut; } - return utime(path, &buf) == 0; */ // if (!aTime && !mTime) return true; - struct timespec times[2]; UNUSED_VAR(cTime) - bool needChange; needChange = FiTime_To_timespec(aTime, times[0]); needChange |= FiTime_To_timespec(mTime, times[1]); - - /* - if (mTime) - { - printf("\n time = %ld.%9ld\n", mTime->tv_sec, mTime->tv_nsec); - } - */ - + // if (mTime) { printf("\n time = %ld.%9ld\n", mTime->tv_sec, mTime->tv_nsec); } if (!needChange) return true; - const int flags = 0; // follow link - // = AT_SYMLINK_NOFOLLOW; // don't follow link return utimensat(AT_FDCWD, path, times, flags) == 0; } +bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) +{ + return SetFileTime_Base(path, cTime, aTime, mTime, 0); // (flags = 0) means follow_link +} + +bool SetLinkFileTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) +{ + return SetFileTime_Base(path, cTime, aTime, mTime, AT_SYMLINK_NOFOLLOW); +} 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); WIN32 API : SetFileTime() doesn't allow to set zero timestamps in file but linux : allows unix time = 0 in filesystem */ - +/* +SetDirTime() can be used to set time for file or for dir. +If path is symbolic link, SetDirTime() will follow symbolic link, +and it will set timestamps of symbolic link's target file or dir. +*/ bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime); +/* +SetLinkFileTime() doesn't follow symbolic link, +and it sets timestamps for symbolic link file itself. +If (path) is not symbolic link, it still can work (at least in some new OS versions). +*/ +bool SetLinkFileTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime); + #ifdef _WIN32 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 @@ - + 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 @@ -7-Zip 25.00 Sources +7-Zip 25.01 Sources ------------------- 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 @@ HISTORY of the 7-Zip source code -------------------------------- +25.01 2025-08-03 +------------------------- +- The code for handling symbolic links has been changed + to provide greater security when extracting files from archives. + Command line switch -snld20 can be used to bypass default security + checks when creating symbolic links. + + 25.00 2025-07-05 ------------------------- - 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 - deflate (zip/gz) compression speed was increased by 1-3%. - improved support for zip, cpio and fat archives. - fixed some bugs and vulnerabilities. +- the bug was fixed : CVE-2025-53816 : 7-Zip could work incorrectly for some incorrect RAR archives. +- the bug was fixed : CVE-2025-53817 : 7-Zip could crash for some incorrect COM (Compound File) archives. 24.09 2024-11-29