diff --git a/deps/unrar/UnRAR.vcxproj b/deps/unrar/UnRAR.vcxproj index 512bcf15d..b55873e37 100644 --- a/deps/unrar/UnRAR.vcxproj +++ b/deps/unrar/UnRAR.vcxproj @@ -1,279 +1,279 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {95CC809B-03FC-4EDB-BB20-FD07A698C05F} - UnRAR - Win32Proj - 8.1 - - - - Application - v140_xp - MultiByte - true - - - Application - v140_xp - MultiByte - - - Application - v140_xp - MultiByte - false - - - Application - v140_xp - MultiByte - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>14.0.24720.0 - - - build\unrar32\$(Configuration)\ - build\unrar32\$(Configuration)\obj\ - true - false - - - build\unrar64\$(Configuration)\ - build\unrar64\$(Configuration)\obj\ - true - false - - - build\unrar32\$(Configuration)\ - build\unrar32\$(Configuration)\obj\ - false - false - - - build\unrar64\$(Configuration)\ - build\unrar64\$(Configuration)\obj\ - false - false - - - - /MP %(AdditionalOptions) - Disabled - UNRAR;%(PreprocessorDefinitions) - false - EnableFastChecks - MultiThreadedDebug - false - Use - rar.hpp - Level3 - ProgramDatabase - StdCall - 4007;4996;%(DisableSpecificWarnings) - NoExtensions - - - true - Console - MachineX86 - - - - - X64 - - - /MP %(AdditionalOptions) - Disabled - UNRAR;%(PreprocessorDefinitions) - false - EnableFastChecks - MultiThreadedDebug - false - Use - rar.hpp - Level3 - ProgramDatabase - StdCall - 4007;4996;%(DisableSpecificWarnings) - NotSet - - - true - Console - MachineX64 - - - - - /MP %(AdditionalOptions) - MaxSpeed - true - Neither - true - false - UNRAR;%(PreprocessorDefinitions) - false - MultiThreaded - Default - true - true - NoExtensions - Precise - false - Use - rar.hpp - Level3 - ProgramDatabase - StdCall - 4007;4996;%(DisableSpecificWarnings) - - - true - Console - true - true - - MachineX86 - - - - - X64 - - - /MP %(AdditionalOptions) - MinSpace - true - Neither - true - false - UNRAR;%(PreprocessorDefinitions) - false - false - MultiThreaded - true - true - false - Use - rar.hpp - Level3 - ProgramDatabase - StdCall - 4007;4996;%(DisableSpecificWarnings) - NotSet - - - true - Console - true - true - - MachineX64 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {95CC809B-03FC-4EDB-BB20-FD07A698C05F} + UnRAR + Win32Proj + 8.1 + + + + Application + v140_xp + MultiByte + true + + + Application + v140_xp + MultiByte + + + Application + v140_xp + MultiByte + false + + + Application + v140_xp + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>14.0.24720.0 + + + build\unrar32\$(Configuration)\ + build\unrar32\$(Configuration)\obj\ + true + false + + + build\unrar64\$(Configuration)\ + build\unrar64\$(Configuration)\obj\ + true + false + + + build\unrar32\$(Configuration)\ + build\unrar32\$(Configuration)\obj\ + false + false + + + build\unrar64\$(Configuration)\ + build\unrar64\$(Configuration)\obj\ + false + false + + + + /MP %(AdditionalOptions) + Disabled + UNRAR;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + false + Use + rar.hpp + Level3 + ProgramDatabase + StdCall + 4007;4996;%(DisableSpecificWarnings) + NoExtensions + + + true + Console + MachineX86 + + + + + X64 + + + /MP %(AdditionalOptions) + Disabled + UNRAR;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + false + Use + rar.hpp + Level3 + ProgramDatabase + StdCall + 4007;4996;%(DisableSpecificWarnings) + NotSet + + + true + Console + MachineX64 + + + + + /MP %(AdditionalOptions) + MaxSpeed + true + Neither + true + false + UNRAR;%(PreprocessorDefinitions) + false + MultiThreaded + Default + true + true + NoExtensions + Precise + false + Use + rar.hpp + Level3 + ProgramDatabase + StdCall + 4007;4996;%(DisableSpecificWarnings) + + + true + Console + true + true + + MachineX86 + + + + + X64 + + + /MP %(AdditionalOptions) + MinSpace + true + Neither + true + false + UNRAR;%(PreprocessorDefinitions) + false + false + MultiThreaded + true + true + false + Use + rar.hpp + Level3 + ProgramDatabase + StdCall + 4007;4996;%(DisableSpecificWarnings) + NotSet + + + true + Console + true + true + + MachineX64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/deps/unrar/UnRARDll.vcxproj b/deps/unrar/UnRARDll.vcxproj index ec5c17b00..d96e4d1c1 100644 --- a/deps/unrar/UnRARDll.vcxproj +++ b/deps/unrar/UnRARDll.vcxproj @@ -1,420 +1,420 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - release_nocrypt - Win32 - - - release_nocrypt - x64 - - - Release - Win32 - - - Release - x64 - - - - UnRAR - {E815C46C-36C4-499F-BBC2-E772C6B17971} - UnRAR - Win32Proj - 8.1 - - - - DynamicLibrary - v140_xp - MultiByte - true - - - DynamicLibrary - v140_xp - MultiByte - true - - - DynamicLibrary - v140_xp - MultiByte - - - DynamicLibrary - v140_xp - MultiByte - false - - - DynamicLibrary - v140_xp - MultiByte - false - - - DynamicLibrary - v140_xp - MultiByte - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>14.0.24720.0 - - - build\unrardll32\$(Configuration)\ - build\unrardll32\$(Configuration)\obj\ - true - true - - - build\unrardll64\$(Configuration)\ - build\unrardll64\$(Configuration)\obj\ - true - true - - - build\unrardll32\$(Configuration)\ - build\unrardll32\$(Configuration)\obj\ - false - true - - - build\unrardll64\$(Configuration)\ - build\unrardll64\$(Configuration)\obj\ - false - true - - - build\unrardll32\$(Configuration)\ - build\unrardll32\$(Configuration)\obj\ - false - true - - - build\unrardll64\$(Configuration)\ - build\unrardll64\$(Configuration)\obj\ - false - true - - - - /MP %(AdditionalOptions) - Disabled - RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions) - false - Sync - EnableFastChecks - MultiThreadedDebug - 4Bytes - false - Use - rar.hpp - Level3 - ProgramDatabase - Cdecl - 4007;4996;%(DisableSpecificWarnings) - NoExtensions - - - $(OutDir)unrar.dll - dll.def - true - Console - MachineX86 - - - - - X64 - - - /MP %(AdditionalOptions) - Disabled - RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions) - false - Sync - EnableFastChecks - MultiThreadedDebug - 4Bytes - false - Use - rar.hpp - Level3 - ProgramDatabase - Cdecl - 4007;4996;%(DisableSpecificWarnings) - NotSet - - - $(OutDir)unrar.dll - dll.def - true - Console - MachineX64 - - - - - /MP %(AdditionalOptions) - MaxSpeed - true - Neither - true - false - RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions) - false - Sync - MultiThreaded - 4Bytes - true - true - NoExtensions - Precise - false - Use - rar.hpp - Level3 - ProgramDatabase - Cdecl - 4007;4996;%(DisableSpecificWarnings) - - - /SAFESEH %(AdditionalOptions) - $(OutDir)unrar.dll - dll.def - true - Console - true - true - - MachineX86 - - - - - X64 - - - /MP %(AdditionalOptions) - MaxSpeed - true - Neither - true - false - RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions) - false - false - Sync - MultiThreaded - 4Bytes - true - true - false - Use - rar.hpp - Level3 - ProgramDatabase - Cdecl - 4007;4996;%(DisableSpecificWarnings) - NotSet - - - $(OutDir)unrar.dll - dll.def - true - Console - true - true - - MachineX64 - - - - - /MP %(AdditionalOptions) - MaxSpeed - true - Neither - true - false - RARDLL;UNRAR;SILENT;RAR_NOCRYPT;%(PreprocessorDefinitions) - false - Sync - MultiThreaded - 4Bytes - true - true - NoExtensions - Precise - false - Use - rar.hpp - Level3 - ProgramDatabase - Cdecl - 4007;4996;%(DisableSpecificWarnings) - - - /SAFESEH %(AdditionalOptions) - $(OutDir)unrar.dll - dll_nocrypt.def - true - Console - true - true - - MachineX86 - - - - - X64 - - - /MP %(AdditionalOptions) - MaxSpeed - true - Neither - true - false - RARDLL;UNRAR;SILENT;RAR_NOCRYPT;%(PreprocessorDefinitions) - false - false - Sync - MultiThreaded - 4Bytes - true - true - false - Use - rar.hpp - Level3 - ProgramDatabase - StdCall - 4007;4996;%(DisableSpecificWarnings) - NotSet - - - $(OutDir)unrar.dll - dll_nocrypt.def - true - Console - true - true - - MachineX64 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + release_nocrypt + Win32 + + + release_nocrypt + x64 + + + Release + Win32 + + + Release + x64 + + + + UnRAR + {E815C46C-36C4-499F-BBC2-E772C6B17971} + UnRAR + Win32Proj + 8.1 + + + + DynamicLibrary + v140_xp + MultiByte + true + + + DynamicLibrary + v140_xp + MultiByte + true + + + DynamicLibrary + v140_xp + MultiByte + + + DynamicLibrary + v140_xp + MultiByte + false + + + DynamicLibrary + v140_xp + MultiByte + false + + + DynamicLibrary + v140_xp + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>14.0.24720.0 + + + build\unrardll32\$(Configuration)\ + build\unrardll32\$(Configuration)\obj\ + true + true + + + build\unrardll64\$(Configuration)\ + build\unrardll64\$(Configuration)\obj\ + true + true + + + build\unrardll32\$(Configuration)\ + build\unrardll32\$(Configuration)\obj\ + false + true + + + build\unrardll64\$(Configuration)\ + build\unrardll64\$(Configuration)\obj\ + false + true + + + build\unrardll32\$(Configuration)\ + build\unrardll32\$(Configuration)\obj\ + false + true + + + build\unrardll64\$(Configuration)\ + build\unrardll64\$(Configuration)\obj\ + false + true + + + + /MP %(AdditionalOptions) + Disabled + RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions) + false + Sync + EnableFastChecks + MultiThreadedDebug + Default + false + Use + rar.hpp + Level3 + ProgramDatabase + Cdecl + 4007;4996;%(DisableSpecificWarnings) + NoExtensions + + + $(OutDir)unrar.dll + dll.def + true + Console + MachineX86 + + + + + X64 + + + /MP %(AdditionalOptions) + Disabled + RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions) + false + Sync + EnableFastChecks + MultiThreadedDebug + Default + false + Use + rar.hpp + Level3 + ProgramDatabase + Cdecl + 4007;4996;%(DisableSpecificWarnings) + NotSet + + + $(OutDir)unrar.dll + dll.def + true + Console + MachineX64 + + + + + /MP %(AdditionalOptions) + MaxSpeed + true + Neither + true + false + RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions) + false + Sync + MultiThreaded + Default + true + true + NoExtensions + Precise + false + Use + rar.hpp + Level3 + ProgramDatabase + Cdecl + 4007;4996;%(DisableSpecificWarnings) + + + /SAFESEH %(AdditionalOptions) + $(OutDir)unrar.dll + dll.def + true + Console + true + true + + MachineX86 + + + + + X64 + + + /MP %(AdditionalOptions) + MaxSpeed + true + Neither + true + false + RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions) + false + false + Sync + MultiThreaded + Default + true + true + false + Use + rar.hpp + Level3 + ProgramDatabase + Cdecl + 4007;4996;%(DisableSpecificWarnings) + NotSet + + + $(OutDir)unrar.dll + dll.def + true + Console + true + true + + MachineX64 + + + + + /MP %(AdditionalOptions) + MaxSpeed + true + Neither + true + false + RARDLL;UNRAR;SILENT;RAR_NOCRYPT;%(PreprocessorDefinitions) + false + Sync + MultiThreaded + Default + true + true + NoExtensions + Precise + false + Use + rar.hpp + Level3 + ProgramDatabase + Cdecl + 4007;4996;%(DisableSpecificWarnings) + + + /SAFESEH %(AdditionalOptions) + $(OutDir)unrar.dll + dll_nocrypt.def + true + Console + true + true + + MachineX86 + + + + + X64 + + + /MP %(AdditionalOptions) + MaxSpeed + true + Neither + true + false + RARDLL;UNRAR;SILENT;RAR_NOCRYPT;%(PreprocessorDefinitions) + false + false + Sync + MultiThreaded + Default + true + true + false + Use + rar.hpp + Level3 + ProgramDatabase + StdCall + 4007;4996;%(DisableSpecificWarnings) + NotSet + + + $(OutDir)unrar.dll + dll_nocrypt.def + true + Console + true + true + + MachineX64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/deps/unrar/acknow.txt b/deps/unrar/acknow.txt index 60a772fa1..b8d35a6aa 100644 --- a/deps/unrar/acknow.txt +++ b/deps/unrar/acknow.txt @@ -1,92 +1,59 @@ - ACKNOWLEDGMENTS - -* We used "Screaming Fast Galois Field Arithmetic Using Intel - SIMD Instructions" paper by James S. Plank, Kevin M. Greenan - and Ethan L. Miller to improve Reed-Solomon coding performance. - Also we are grateful to Artem Drobanov and Bulat Ziganshin - for samples and ideas allowed to make Reed-Solomon coding - more efficient. - -* RAR text compression algorithm is based on Dmitry Shkarin PPMII - and Dmitry Subbotin carryless rangecoder public domain source code. - You may find it in ftp.elf.stuba.sk/pub/pc/pack. - -* RAR encryption includes parts of code from Szymon Stefanek - and Brian Gladman AES implementations also as Steve Reid SHA-1 source. - - --------------------------------------------------------------------------- - Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. - All rights reserved. - - LICENSE TERMS - - The free distribution and use of this software in both source and binary - form is allowed (with or without changes) provided that: - - 1. distributions of this source code include the above copyright - notice, this list of conditions and the following disclaimer; - - 2. distributions in binary form include the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other associated materials; - - 3. the copyright holder's name is not used to endorse products - built using this software without specific written permission. - - ALTERNATIVELY, provided that this notice is retained in full, this product - may be distributed under the terms of the GNU General Public License (GPL), - in which case the provisions of the GPL apply INSTEAD OF those given above. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and/or fitness for purpose. - --------------------------------------------------------------------------- - - Source code of this package also as other cryptographic technology - and computing project related links are available on Brian Gladman's - web site: http://www.gladman.me.uk - -* RAR uses CRC32 function based on Intel Slicing-by-8 algorithm. - Original Intel Slicing-by-8 code is available here: - - https://sourceforge.net/projects/slicing-by-8/ - - Original Intel Slicing-by-8 code is licensed under BSD License - available at http://www.opensource.org/licenses/bsd-license.html - - Copyright (c) 2004-2006 Intel Corporation. - All Rights Reserved - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with - the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - -* RAR archives may optionally include BLAKE2sp hash ( https://blake2.net ), - designed by Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn - and Christian Winnerlein. - -* Useful hints provided by Alexander Khoroshev and Bulat Ziganshin allowed - to significantly improve RAR compression and speed. + ACKNOWLEDGMENTS + +* We used "Screaming Fast Galois Field Arithmetic Using Intel + SIMD Instructions" paper by James S. Plank, Kevin M. Greenan + and Ethan L. Miller to improve Reed-Solomon coding performance. + Also we are grateful to Artem Drobanov and Bulat Ziganshin + for samples and ideas allowed to make Reed-Solomon coding + more efficient. + +* RAR4 text compression algorithm is based on Dmitry Shkarin PPMII + and Dmitry Subbotin carryless rangecoder public domain source code. + You can find it in ftp.elf.stuba.sk/pub/pc/pack. + +* RAR encryption includes parts of public domain code + from Szymon Stefanek AES and Steve Reid SHA-1 implementations. + +* With exception of SFX modules, RAR uses CRC32 function based + on Intel Slicing-by-8 algorithm. Original Intel Slicing-by-8 code + is available here: + + https://sourceforge.net/projects/slicing-by-8/ + + Original Intel Slicing-by-8 code is licensed under BSD License + available at http://www.opensource.org/licenses/bsd-license.html + + Copyright (c) 2004-2006 Intel Corporation. + All Rights Reserved + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with + the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +* RAR archives may optionally include BLAKE2sp hash ( https://blake2.net ), + designed by Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn + and Christian Winnerlein. + +* Useful hints provided by Alexander Khoroshev and Bulat Ziganshin allowed + to significantly improve RAR compression and speed. diff --git a/deps/unrar/archive.cpp b/deps/unrar/archive.cpp index 8c5a1da81..25f0c3b79 100644 --- a/deps/unrar/archive.cpp +++ b/deps/unrar/archive.cpp @@ -3,15 +3,15 @@ #include "arccmt.cpp" -Archive::Archive(RAROptions *InitCmd) +Archive::Archive(CommandData *InitCmd) { Cmd=NULL; // Just in case we'll have an exception in 'new' below. DummyCmd=(InitCmd==NULL); - Cmd=DummyCmd ? (new RAROptions):InitCmd; + Cmd=DummyCmd ? (new CommandData):InitCmd; OpenShared=Cmd->OpenShared; - Format=RARFMT15; + Format=RARFMT_NONE; Solid=false; Volume=false; MainComment=false; @@ -31,9 +31,9 @@ Archive::Archive(RAROptions *InitCmd) NextBlockPos=0; - memset(&MainHead,0,sizeof(MainHead)); - memset(&CryptHead,0,sizeof(CryptHead)); - memset(&EndArcHead,0,sizeof(EndArcHead)); + MainHead.Reset(); + CryptHead={}; + EndArcHead.Reset(); VolNumber=0; VolWrite=0; @@ -231,7 +231,7 @@ bool Archive::IsArchive(bool EnableBroken) // first file header to set "comment" flag when reading service header. // Unless we are in silent mode, we need to know about presence of comment // immediately after IsArchive call. - if (HeadersLeft && (!SilentOpen || !Encrypted)) + if (HeadersLeft && (!SilentOpen || !Encrypted) && IsSeekable()) { int64 SavePos=Tell(); int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos; diff --git a/deps/unrar/archive.hpp b/deps/unrar/archive.hpp index d9518f1dc..35a399bca 100644 --- a/deps/unrar/archive.hpp +++ b/deps/unrar/archive.hpp @@ -32,8 +32,8 @@ class Archive:public File size_t ReadHeader14(); size_t ReadHeader15(); size_t ReadHeader50(); - void ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb); - void RequestArcPassword(); + void ProcessExtra50(RawRead *Raw,size_t ExtraSize,const BaseBlock *bb); + void RequestArcPassword(RarCheckPassword *SelPwd); void UnexpEndArcMsg(); void BrokenHeaderMsg(); void UnkEncVerMsg(const wchar *Name,const wchar *Info); @@ -45,7 +45,7 @@ class Archive:public File #endif ComprDataIO SubDataIO; bool DummyCmd; - RAROptions *Cmd; + CommandData *Cmd; RarTime LatestTime; @@ -58,7 +58,7 @@ class Archive:public File bool ProhibitQOpen; #endif public: - Archive(RAROptions *InitCmd=NULL); + Archive(CommandData *InitCmd=NULL); ~Archive(); static RARFORMAT IsSignature(const byte *D,size_t Size); bool IsArchive(bool EnableBroken); @@ -83,7 +83,7 @@ class Archive:public File const wchar *Name,uint Flags); bool ReadSubData(Array *UnpData,File *DestFile,bool TestMode); HEADER_TYPE GetHeaderType() {return CurHeaderType;} - RAROptions* GetRAROptions() {return Cmd;} + CommandData* GetCommandData() {return Cmd;} void SetSilentOpen(bool Mode) {SilentOpen=Mode;} #if 0 void GetRecoveryInfo(bool Required,int64 *Size,int *Percent); diff --git a/deps/unrar/arcread.cpp b/deps/unrar/arcread.cpp index d1df6c041..86488cd49 100644 --- a/deps/unrar/arcread.cpp +++ b/deps/unrar/arcread.cpp @@ -100,6 +100,9 @@ void Archive::UnexpEndArcMsg() // If block positions are equal to file size, this is not an error. // It can happen when we reached the end of older RAR 1.5 archive, // which did not have the end of archive block. + // We can't replace this check by checking that read size is exactly 0 + // in the beginning of file header, because in this case the read position + // still can be beyond the end of archive. if (CurBlockPos!=ArcSize || NextBlockPos!=ArcSize) { uiMsg(UIERROR_UNEXPEOF,FileName); @@ -145,7 +148,7 @@ size_t Archive::ReadHeader15() #ifdef RAR_NOCRYPT // For rarext.dll and unrar_nocrypt.dll. return 0; #else - RequestArcPassword(); + RequestArcPassword(NULL); byte Salt[SIZE_SALT30]; if (Read(Salt,SIZE_SALT30)!=SIZE_SALT30) @@ -251,7 +254,11 @@ size_t Archive::ReadHeader15() hd->SplitAfter=(hd->Flags & LHD_SPLIT_AFTER)!=0; hd->Encrypted=(hd->Flags & LHD_PASSWORD)!=0; hd->SaltSet=(hd->Flags & LHD_SALT)!=0; + + // RAR versions earlier than 2.0 do not set the solid flag + // in file header. They use only a global solid archive flag. hd->Solid=FileBlock && (hd->Flags & LHD_SOLID)!=0; + hd->SubBlock=!FileBlock && (hd->Flags & LHD_SOLID)!=0; hd->Dir=(hd->Flags & LHD_WINDOWMASK)==LHD_DIRECTORY; hd->WinSize=hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5); @@ -558,6 +565,13 @@ size_t Archive::ReadHeader50() return 0; #else + if (Cmd->SkipEncrypted) + { + uiMsg(UIMSG_SKIPENCARC,FileName); + FailedHeaderDecryption=true; // Suppress error messages and quit quietly. + return 0; + } + byte HeadersInitV[SIZE_INITV]; if (Read(HeadersInitV,SIZE_INITV)!=SIZE_INITV) { @@ -570,14 +584,20 @@ size_t Archive::ReadHeader50() // in -p to not stop batch processing for encrypted archives. bool GlobalPassword=Cmd->Password.IsSet() || uiIsGlobalPasswordSet(); + RarCheckPassword CheckPwd; + if (CryptHead.UsePswCheck && !BrokenHeader) + CheckPwd.Set(CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,CryptHead.PswCheck); + while (true) // Repeat the password prompt for wrong passwords. { - RequestArcPassword(); + RequestArcPassword(CheckPwd.IsSet() ? &CheckPwd:NULL); byte PswCheck[SIZE_PSWCHECK]; HeadersCrypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,NULL,PswCheck); - // Verify password validity. - if (CryptHead.UsePswCheck && memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0) + // Verify password validity. If header is damaged, we cannot rely on + // password check value, because it can be damaged too. + if (CryptHead.UsePswCheck && !BrokenHeader && + memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0) { if (GlobalPassword) // For -p or Ctrl+P. { @@ -843,8 +863,6 @@ size_t Archive::ReadHeader50() hd->Dir=(hd->FileFlags & FHFL_DIRECTORY)!=0; hd->WinSize=hd->Dir ? 0:size_t(0x20000)<<((CompInfo>>10)&0xf); - hd->CryptMethod=hd->Encrypted ? CRYPT_RAR50:CRYPT_NONE; - char FileName[NM*4]; size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1); Raw.GetB((byte *)FileName,ReadNameSize); @@ -868,20 +886,6 @@ size_t Archive::ReadHeader50() if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_CMT)) MainComment=true; -#if 0 - // For RAR5 format we read the user specified recovery percent here. - // It would be useful to do it for shell extension too, so we display - // the correct recovery record size in archive properties. But then - // we would need to include the entire recovery record processing - // code to shell extension, which is not done now. - if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_RR) && hd->SubData.Size()>0) - { - RecoveryPercent=hd->SubData[0]; - RSBlockHeader Header; - GetRRInfo(this,&Header); - RecoverySize=Header.RecSectionSize*Header.RecCount; - } -#endif if (BadCRC) // Add the file name to broken header message displayed above. uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName); @@ -904,7 +908,7 @@ size_t Archive::ReadHeader50() #if !defined(RAR_NOCRYPT) -void Archive::RequestArcPassword() +void Archive::RequestArcPassword(RarCheckPassword *CheckPwd) { if (!Cmd->Password.IsSet()) { @@ -934,7 +938,7 @@ void Archive::RequestArcPassword() ErrHandler.Exit(RARX_USERBREAK); } #else - if (!uiGetPassword(UIPASSWORD_ARCHIVE,FileName,&Cmd->Password)) + if (!uiGetPassword(UIPASSWORD_ARCHIVE,FileName,&Cmd->Password,CheckPwd)) { Close(); uiMsg(UIERROR_INCERRCOUNT); // Prevent archive deleting if delete after extraction is on. @@ -947,7 +951,7 @@ void Archive::RequestArcPassword() #endif -void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb) +void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,const BaseBlock *bb) { // Read extra data from the end of block skipping any fields before it. size_t ExtraStart=Raw->Size()-ExtraSize; @@ -970,22 +974,57 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb) if (bb->HeaderType==HEAD_MAIN) { MainHeader *hd=(MainHeader *)bb; - if (FieldType==MHEXTRA_LOCATOR) + switch(FieldType) { - hd->Locator=true; - uint Flags=(uint)Raw->GetV(); - if ((Flags & MHEXTRA_LOCATOR_QLIST)!=0) - { - uint64 Offset=Raw->GetV(); - if (Offset!=0) // 0 means that reserved space was not enough to write the offset. - hd->QOpenOffset=Offset+CurBlockPos; - } - if ((Flags & MHEXTRA_LOCATOR_RR)!=0) - { - uint64 Offset=Raw->GetV(); - if (Offset!=0) // 0 means that reserved space was not enough to write the offset. - hd->RROffset=Offset+CurBlockPos; - } + case MHEXTRA_LOCATOR: + { + hd->Locator=true; + uint Flags=(uint)Raw->GetV(); + if ((Flags & MHEXTRA_LOCATOR_QLIST)!=0) + { + uint64 Offset=Raw->GetV(); + if (Offset!=0) // 0 means that reserved space was not enough to write the offset. + hd->QOpenOffset=Offset+CurBlockPos; + } + if ((Flags & MHEXTRA_LOCATOR_RR)!=0) + { + uint64 Offset=Raw->GetV(); + if (Offset!=0) // 0 means that reserved space was not enough to write the offset. + hd->RROffset=Offset+CurBlockPos; + } + } + break; + case MHEXTRA_METADATA: + { + uint Flags=(uint)Raw->GetV(); + if ((Flags & MHEXTRA_METADATA_NAME)!=0) + { + uint64 NameSize=Raw->GetV(); + if (NameSize<0x10000) // Prevent excessive allocation. + { + std::vector NameU((size_t)NameSize); // UTF-8 name. + Raw->GetB(&NameU[0],(size_t)NameSize); + // If starts from 0, the name was longer than reserved space + // when saving this extra field. + if (NameU[0]!=0) + { + NameU.push_back(0); + std::vector NameW(NameU.size()*4); + UtfToWide(&NameU[0],&NameW[0],NameW.size()); + hd->OrigName.assign(&NameW[0]); + } + } + } + if ((Flags & MHEXTRA_METADATA_CTIME)!=0) + if ((Flags & MHEXTRA_METADATA_UNIXTIME)!=0) + if ((Flags & MHEXTRA_METADATA_UNIX_NS)!=0) + hd->OrigTime.SetUnixNS(Raw->Get8()); + else + hd->OrigTime.SetUnix((time_t)Raw->Get4()); + else + hd->OrigTime.SetWin(Raw->Get8()); + } + break; } } @@ -1441,7 +1480,9 @@ bool Archive::ReadSubData(Array *UnpData,File *DestFile,bool TestMode) { if (SubHead.UnpSize>0x1000000) { - // So huge allocation must never happen in valid archives. + // Prevent the excessive allocation. When reading to memory, normally + // this function operates with reasonably small blocks, such as + // the archive comment, NTFS ACL or "Zone.Identifier" NTFS stream. uiMsg(UIERROR_SUBHEADERUNKNOWN,FileName); return false; } diff --git a/deps/unrar/array.hpp b/deps/unrar/array.hpp index 20d258d5b..ac786f710 100644 --- a/deps/unrar/array.hpp +++ b/deps/unrar/array.hpp @@ -10,7 +10,6 @@ template class Array size_t BufSize; size_t AllocSize; size_t MaxSize; - bool Secure; // Clean memory if true. public: Array(); Array(size_t Size); @@ -24,14 +23,13 @@ template class Array void Alloc(size_t Items); void Reset(); void SoftReset(); - void operator = (Array &Src); + Array& operator = (const Array &Src); void Push(T Item); void Append(T *Item,size_t Count); T* Addr(size_t Item) {return Buffer+Item;} void SetMaxSize(size_t Size) {MaxSize=Size;} T* Begin() {return Buffer;} T* End() {return Buffer==NULL ? NULL:Buffer+BufSize;} - void SetSecure() {Secure=true;} }; @@ -41,7 +39,6 @@ template void Array::CleanData() BufSize=0; AllocSize=0; MaxSize=0; - Secure=false; } @@ -71,11 +68,7 @@ template Array::Array(const Array &Src) template Array::~Array() { if (Buffer!=NULL) - { - if (Secure) - cleandata(Buffer,AllocSize*sizeof(T)); free(Buffer); - } } @@ -111,25 +104,9 @@ template void Array::Add(size_t Items) size_t Suggested=AllocSize+AllocSize/4+32; size_t NewSize=Max(BufSize,Suggested); - T *NewBuffer; - if (Secure) - { - NewBuffer=(T *)malloc(NewSize*sizeof(T)); - if (NewBuffer==NULL) - ErrHandler.MemoryError(); - if (Buffer!=NULL) - { - memcpy(NewBuffer,Buffer,AllocSize*sizeof(T)); - cleandata(Buffer,AllocSize*sizeof(T)); - free(Buffer); - } - } - else - { - NewBuffer=(T *)realloc(Buffer,NewSize*sizeof(T)); - if (NewBuffer==NULL) - ErrHandler.MemoryError(); - } + T *NewBuffer=(T *)realloc(Buffer,NewSize*sizeof(T)); + if (NewBuffer==NULL) + ErrHandler.MemoryError(); Buffer=NewBuffer; AllocSize=NewSize; } @@ -165,12 +142,13 @@ template void Array::SoftReset() } -template void Array::operator =(Array &Src) +template Array& Array::operator =(const Array &Src) { Reset(); Alloc(Src.BufSize); if (Src.BufSize!=0) memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T)); + return *this; } diff --git a/deps/unrar/blake2s.hpp b/deps/unrar/blake2s.hpp index f88ef3780..06e396a77 100644 --- a/deps/unrar/blake2s.hpp +++ b/deps/unrar/blake2s.hpp @@ -20,10 +20,15 @@ enum blake2s_constant // 'new' operator. struct blake2s_state { - enum { BLAKE_ALIGNMENT = 64 }; + // Use constexpr instead of enums, because otherwise clang -std=c++20 + // issues a warning about "arithmetic between different enumeration types" + // in ubuf[BLAKE_DATA_SIZE + BLAKE_ALIGNMENT] declaration. + static constexpr size_t BLAKE_ALIGNMENT = 64; // buffer and uint32 h[8], t[2], f[2]; - enum { BLAKE_DATA_SIZE = 48 + 2 * BLAKE2S_BLOCKBYTES }; + // 2 * BLAKE2S_BLOCKBYTES is the buf size in blake2_code_20140114.zip. + // It might differ in later versions. + static constexpr size_t BLAKE_DATA_SIZE = 48 + 2 * BLAKE2S_BLOCKBYTES; byte ubuf[BLAKE_DATA_SIZE + BLAKE_ALIGNMENT]; diff --git a/deps/unrar/cmddata.cpp b/deps/unrar/cmddata.cpp index 455a07b2c..3a4ab99eb 100644 --- a/deps/unrar/cmddata.cpp +++ b/deps/unrar/cmddata.cpp @@ -26,9 +26,10 @@ void CommandData::Init() FileArgs.Reset(); ExclArgs.Reset(); InclArgs.Reset(); - StoreArgs.Reset(); ArcNames.Reset(); - NextVolSizes.Reset(); + StoreArgs.Reset(); + Password.Clean(); + NextVolSizes.clear(); } @@ -108,6 +109,11 @@ void CommandData::ParseArg(wchar *Arg) // 'S' can contain SFX name, which case is important in Unix. if (*Command!='I' && *Command!='S') wcsupper(Command); + if (*Command=='P') // Enforce -idq for print command. + { + MsgStream=MSG_ERRONLY; + SetConsoleMsgStream(MSG_ERRONLY); + } } else if (*ArcName==0) @@ -309,6 +315,21 @@ void CommandData::ProcessSwitch(const wchar *Switch) case 'I': IgnoreGeneralAttr=true; break; + case 'M': + switch(toupperw(Switch[2])) + { + case 0: + case 'S': + ArcMetadata=ARCMETA_SAVE; + break; + case 'R': + ArcMetadata=ARCMETA_RESTORE; + break; + default: + BadSwitch(Switch); + break; + } + break; case 'N': // Reserved for archive name. break; case 'O': @@ -373,6 +394,9 @@ void CommandData::ProcessSwitch(const wchar *Switch) case '3': ExclPath=EXCL_ABSPATH; break; + case '4': + wcsncpyz(ExclArcPath,Switch+3,ASIZE(ExclArcPath)); + break; } break; default: @@ -399,13 +423,15 @@ void CommandData::ProcessSwitch(const wchar *Switch) EncryptHeaders=true; if (Switch[2]!=0) { + if (wcslen(Switch+2)>=MAXPASSWORD) + uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1); Password.Set(Switch+2); cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0])); } else if (!Password.IsSet()) { - uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password); + uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password,NULL); eprintf(L"\n"); } break; @@ -561,6 +587,10 @@ void CommandData::ProcessSwitch(const wchar *Switch) break; case 'D': break; + case 'E': + if (toupperw(Switch[2])=='S' && Switch[3]==0) + SkipEncrypted=true; + break; case 'S': { wchar StoreNames[1024]; @@ -648,6 +678,10 @@ void CommandData::ProcessSwitch(const wchar *Switch) AllowIncompatNames=true; break; #endif + case 'P': + wcsncpyz(ExtrPath,Switch+2,ASIZE(ExtrPath)); + AddEndSlash(ExtrPath,ASIZE(ExtrPath)); + break; case 'R': Overwrite=OVERWRITE_AUTORENAME; break; @@ -667,11 +701,13 @@ void CommandData::ProcessSwitch(const wchar *Switch) case 'P': if (Switch[1]==0) { - uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password); + uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password,NULL); eprintf(L"\n"); } else { + if (wcslen(Switch+1)>=MAXPASSWORD) + uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1); Password.Set(Switch+1); cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0])); } @@ -752,6 +788,10 @@ void CommandData::ProcessSwitch(const wchar *Switch) case 'D': Solid|=SOLID_VOLUME_DEPENDENT; break; + case 'I': + ProhibitConsoleInput(); + wcsncpyz(UseStdin,Switch[2] ? Switch+2:L"stdin",ASIZE(UseStdin)); + break; case 'L': if (IsDigit(Switch[2])) FileSizeLess=atoilw(Switch+2); @@ -935,7 +975,7 @@ void CommandData::ProcessCommand() wcsncpyz(ArcName,Name,ASIZE(ArcName)); } - if (wcschr(L"AFUMD",*Command)==NULL) + if (wcschr(L"AFUMD",*Command)==NULL && *UseStdin==0) { if (GenerateArcName) { diff --git a/deps/unrar/cmddata.hpp b/deps/unrar/cmddata.hpp index 719b4007e..0feb404b3 100644 --- a/deps/unrar/cmddata.hpp +++ b/deps/unrar/cmddata.hpp @@ -2,7 +2,7 @@ #define _RAR_CMDDATA_ -#define DefaultStoreList L"7z;ace;arj;bz2;cab;gz;jpeg;jpg;lha;lz;lzh;mp3;rar;taz;tgz;xz;z;zip;zipx" +#define DefaultStoreList L"7z;ace;arj;bz2;cab;gz;jpeg;jpg;lha;lz;lzh;mp3;rar;taz;tbz;tbz2;tgz;txz;xz;z;zip;zipx;zst;tzst" enum RAR_CMD_LIST_MODE {RCLM_AUTO,RCLM_REJECT_LISTS,RCLM_ACCEPT_LISTS}; @@ -50,7 +50,7 @@ class CommandData:public RAROptions bool GetArcName(wchar *Name,int MaxSize); bool CheckWinSize(); - int GetRecoverySize(const wchar *Str,int DefSize); + int GetRecoverySize(const wchar *CmdStr,const wchar *Value,int DefSize); #ifndef SFX_MODULE void ReportWrongSwitches(RARFORMAT Format); @@ -65,6 +65,10 @@ class CommandData:public RAROptions StringList InclArgs; StringList ArcNames; StringList StoreArgs; + + SecPassword Password; + + std::vector NextVolSizes; }; #endif diff --git a/deps/unrar/cmdfilter.cpp b/deps/unrar/cmdfilter.cpp index d6517ceb7..e0add14bf 100644 --- a/deps/unrar/cmdfilter.cpp +++ b/deps/unrar/cmdfilter.cpp @@ -262,6 +262,8 @@ bool CommandData::TimeCheck(RarTime &ftm,RarTime &ftc,RarTime &fta) // Return 'true' if we need to exclude the file from processing. bool CommandData::SizeCheck(int64 Size) { + if (Size==INT64NDF) // If called from archive formats like bzip2, not storing the file size. + return false; if (FileSizeLess!=INT64NDF && Size>=FileSizeLess) return true; if (FileSizeMore!=INT64NDF && Size<=FileSizeMore) @@ -287,8 +289,8 @@ int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchTy return 0; if ((FileHead.FileAttr & ExclFileAttr)!=0 || FileHead.Dir && ExclDir) return 0; - if (InclAttrSet && (!FileHead.Dir && (FileHead.FileAttr & InclFileAttr)==0 || - FileHead.Dir && !InclDir)) + if (InclAttrSet && (FileHead.FileAttr & InclFileAttr)==0 && + (!FileHead.Dir || !InclDir)) return 0; if (!Dir && SizeCheck(FileHead.UnpSize)) return 0; diff --git a/deps/unrar/cmdmix.cpp b/deps/unrar/cmdmix.cpp index 3990cc189..6bd1e1ac0 100644 --- a/deps/unrar/cmdmix.cpp +++ b/deps/unrar/cmdmix.cpp @@ -61,14 +61,14 @@ void CommandData::OutHelp(RAR_EXIT ExitCode) MUNRARTitle1,MRARTitle2,MCHelpCmd,MCHelpCmdE,MCHelpCmdL, MCHelpCmdP,MCHelpCmdT,MCHelpCmdV,MCHelpCmdX,MCHelpSw,MCHelpSwm, MCHelpSwAT,MCHelpSwAC,MCHelpSwAD,MCHelpSwAG,MCHelpSwAI,MCHelpSwAP, - MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU, - MCHelpSwDH,MCHelpSwEP,MCHelpSwEP3,MCHelpSwF,MCHelpSwIDP,MCHelpSwIERR, - MCHelpSwINUL,MCHelpSwIOFF,MCHelpSwKB,MCHelpSwN,MCHelpSwNa,MCHelpSwNal, - MCHelpSwO,MCHelpSwOC,MCHelpSwOL,MCHelpSwOR,MCHelpSwOW,MCHelpSwP, - MCHelpSwPm,MCHelpSwR,MCHelpSwRI,MCHelpSwSC,MCHelpSwSL,MCHelpSwSM, - MCHelpSwTA,MCHelpSwTB,MCHelpSwTN,MCHelpSwTO,MCHelpSwTS,MCHelpSwU, - MCHelpSwVUnr,MCHelpSwVER,MCHelpSwVP,MCHelpSwX,MCHelpSwXa,MCHelpSwXal, - MCHelpSwY + MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU,MCHelpSwDH,MCHelpSwEP, + MCHelpSwEP3,MCHelpSwEP4,MCHelpSwF,MCHelpSwIDP,MCHelpSwIERR, + MCHelpSwINUL,MCHelpSwIOFF,MCHelpSwKB,MCHelpSwME,MCHelpSwN,MCHelpSwNa, + MCHelpSwNal,MCHelpSwO,MCHelpSwOC,MCHelpSwOL,MCHelpSwOP,MCHelpSwOR, + MCHelpSwOW,MCHelpSwP,MCHelpSwR,MCHelpSwRI,MCHelpSwSC,MCHelpSwSI, + MCHelpSwSL,MCHelpSwSM,MCHelpSwTA,MCHelpSwTB,MCHelpSwTN,MCHelpSwTO, + MCHelpSwTS,MCHelpSwU,MCHelpSwVUnr,MCHelpSwVER,MCHelpSwVP,MCHelpSwX, + MCHelpSwXa,MCHelpSwXal,MCHelpSwY #endif }; @@ -92,6 +92,13 @@ void CommandData::OutHelp(RAR_EXIT ExitCode) if (Found) continue; #endif +#ifdef _UNIX + if (CmpMSGID(Help[I],MRARTitle2)) + { + mprintf(St(MFwrSlTitle2)); + continue; + } +#endif #if !defined(_UNIX) && !defined(_WIN_ALL) if (CmpMSGID(Help[I],MCHelpSwOW)) continue; diff --git a/deps/unrar/compress.hpp b/deps/unrar/compress.hpp index 73f7ee41a..4ef8570f4 100644 --- a/deps/unrar/compress.hpp +++ b/deps/unrar/compress.hpp @@ -17,6 +17,7 @@ class PackDef static const uint MAX_INC_LZ_MATCH = MAX_LZ_MATCH + 3; static const uint MAX3_LZ_MATCH = 0x101; // Maximum match length for RAR v3. + static const uint MAX3_INC_LZ_MATCH = MAX3_LZ_MATCH + 3; static const uint LOW_DIST_REP_COUNT = 16; static const uint NC = 306; /* alphabet = {0, 1, 2, ..., NC - 1} */ diff --git a/deps/unrar/consio.cpp b/deps/unrar/consio.cpp index fedd5c05c..fa35d6146 100644 --- a/deps/unrar/consio.cpp +++ b/deps/unrar/consio.cpp @@ -3,6 +3,7 @@ static MESSAGE_TYPE MsgStream=MSG_STDOUT; static RAR_CHARSET RedirectCharset=RCH_DEFAULT; +static bool ProhibitInput=false; const int MaxMsgSize=2*NM+2048; @@ -61,6 +62,12 @@ void SetConsoleRedirectCharset(RAR_CHARSET RedirectCharset) } +void ProhibitConsoleInput() +{ + ProhibitInput=true; +} + + #ifndef SILENT static void cvt_wprintf(FILE *dest,const wchar *fmt,va_list arglist) { @@ -141,28 +148,56 @@ void eprintf(const wchar *fmt,...) #ifndef SILENT +static void QuitIfInputProhibited() +{ + // We cannot handle user prompts if -si is used to read file or archive data + // from stdin. + if (ProhibitInput) + { + mprintf(St(MStdinNoInput)); + ErrHandler.Exit(RARX_FATAL); + } +} + + static void GetPasswordText(wchar *Str,uint MaxLength) { if (MaxLength==0) return; + QuitIfInputProhibited(); if (StdinRedirected) getwstr(Str,MaxLength); // Read from pipe or redirected file. else { #ifdef _WIN_ALL HANDLE hConIn=GetStdHandle(STD_INPUT_HANDLE); - HANDLE hConOut=GetStdHandle(STD_OUTPUT_HANDLE); - DWORD ConInMode,ConOutMode; - DWORD Read=0; + DWORD ConInMode; GetConsoleMode(hConIn,&ConInMode); - GetConsoleMode(hConOut,&ConOutMode); - SetConsoleMode(hConIn,ENABLE_LINE_INPUT); - SetConsoleMode(hConOut,ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT); + SetConsoleMode(hConIn,ENABLE_LINE_INPUT); // Remove ENABLE_ECHO_INPUT. + // We prefer ReadConsole to ReadFile, so we can read Unicode input. + DWORD Read=0; ReadConsole(hConIn,Str,MaxLength-1,&Read,NULL); Str[Read]=0; SetConsoleMode(hConIn,ConInMode); - SetConsoleMode(hConOut,ConOutMode); + + // If entered password is longer than MAXPASSWORD and truncated, + // read its unread part anyway, so it isn't read later as the second + // password for -p switch. Low level FlushConsoleInputBuffer doesn't help + // for high level ReadConsole, which in line input mode seems to store + // the rest of string in its own internal buffer. + if (wcschr(Str,'\r')==NULL) // If '\r' is missing, the password was truncated. + while (true) + { + wchar Trail[64]; + DWORD TrailRead=0; + // Use ASIZE(Trail)-1 to reserve the space for trailing 0. + ReadConsole(hConIn,Trail,ASIZE(Trail)-1,&TrailRead,NULL); + Trail[TrailRead]=0; + if (TrailRead==0 || wcschr(Trail,'\r')!=NULL) + break; + } + #else char StrA[MAXPASSWORD*4]; // "*4" for multibyte UTF-8 characters. #if defined(_EMX) || defined (__VMS) @@ -190,16 +225,21 @@ bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword * while (true) { - if (!StdinRedirected) +// if (!StdinRedirected) if (Type==UIPASSWORD_GLOBAL) eprintf(L"\n%s: ",St(MAskPsw)); else eprintf(St(MAskPswFor),FileName); - wchar PlainPsw[MAXPASSWORD]; + wchar PlainPsw[MAXPASSWORD+1]; GetPasswordText(PlainPsw,ASIZE(PlainPsw)); if (*PlainPsw==0 && Type==UIPASSWORD_GLOBAL) return false; + if (wcslen(PlainPsw)>=MAXPASSWORD) + { + PlainPsw[MAXPASSWORD-1]=0; + uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1); + } if (!StdinRedirected && Type==UIPASSWORD_GLOBAL) { eprintf(St(MReAskPsw)); @@ -229,6 +269,8 @@ bool getwstr(wchar *str,size_t n) // Print buffered prompt title function before waiting for input. fflush(stderr); + QuitIfInputProhibited(); + *str=0; #if defined(_WIN_ALL) // fgetws does not work well with non-English text in Windows, @@ -240,6 +282,7 @@ bool getwstr(wchar *str,size_t n) Array StrA(n*4); // Up to 4 UTF-8 characters per wchar_t. File SrcFile; SrcFile.SetHandleType(FILE_HANDLESTD); + SrcFile.SetLineInputMode(true); int ReadSize=SrcFile.Read(&StrA[0],StrA.Size()-1); if (ReadSize<=0) { diff --git a/deps/unrar/consio.hpp b/deps/unrar/consio.hpp index 903dc21a4..bf97289e7 100644 --- a/deps/unrar/consio.hpp +++ b/deps/unrar/consio.hpp @@ -4,6 +4,7 @@ void InitConsole(); void SetConsoleMsgStream(MESSAGE_TYPE MsgStream); void SetConsoleRedirectCharset(RAR_CHARSET RedirectCharset); +void ProhibitConsoleInput(); void OutComment(const wchar *Comment,size_t Size); #ifndef SILENT diff --git a/deps/unrar/crc.cpp b/deps/unrar/crc.cpp index cf23bbf4f..0c6aef160 100644 --- a/deps/unrar/crc.cpp +++ b/deps/unrar/crc.cpp @@ -14,6 +14,12 @@ #include "rar.hpp" +#ifndef SFX_MODULE +// User suggested to avoid BSD license in SFX module, so they do not need +// to include the license to SFX archive. +#define USE_SLICING +#endif + static uint crc_tables[8][256]; // Tables for Slicing-by-8. @@ -37,6 +43,7 @@ static void InitTables() { InitCRC32(crc_tables[0]); +#ifdef USE_SLICING for (uint I=0;I<256;I++) // Build additional lookup tables. { uint C=crc_tables[0][I]; @@ -46,6 +53,7 @@ static void InitTables() crc_tables[J][I]=C; } } +#endif } @@ -55,6 +63,7 @@ uint CRC32(uint StartCRC,const void *Addr,size_t Size) { byte *Data=(byte *)Addr; +#ifdef USE_SLICING // Align Data to 8 for better performance. for (;Size>0 && ((size_t)Data & 7);Size--,Data++) StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8); @@ -77,6 +86,7 @@ uint CRC32(uint StartCRC,const void *Addr,size_t Size) crc_tables[1][(byte)(NextData >> 16)] ^ crc_tables[0][(byte)(NextData >> 24)]; } +#endif for (;Size>0;Size--,Data++) // Process left data. StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8); @@ -100,3 +110,164 @@ ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size) #endif +#if 0 +static uint64 crc64_tables[8][256]; // Tables for Slicing-by-8 for CRC64. + +void InitCRC64(uint64 *CRCTab) +{ + const uint64 poly=INT32TO64(0xC96C5795, 0xD7870F42); // 0xC96C5795D7870F42; + for (uint I=0;I<256;I++) + { + uint64 C=I; + for (uint J=0;J<8;J++) + C=(C & 1) ? (C>>1)^poly: (C>>1); + CRCTab[I]=C; + } +} + + +static void InitTables64() +{ + InitCRC64(crc64_tables[0]); + + for (uint I=0;I<256;I++) // Build additional lookup tables. + { + uint64 C=crc64_tables[0][I]; + for (uint J=1;J<8;J++) + { + C=crc64_tables[0][(byte)C]^(C>>8); + crc64_tables[J][I]=C; + } + } +} + + +// We cannot place the intialization to CRC64(), because we use this function +// in multithreaded mode and it conflicts with multithreading. +struct CallInitCRC64 {CallInitCRC64() {InitTables64();}} static CallInit64; + +uint64 CRC64(uint64 StartCRC,const void *Addr,size_t Size) +{ + byte *Data=(byte *)Addr; + + // Align Data to 8 for better performance. + for (;Size>0 && ((size_t)Data & 7)!=0;Size--,Data++) + StartCRC=crc64_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8); + + for (byte *DataEnd=Data+Size/8*8; Data> 8 ) ] ^ + crc64_tables[ 5 ] [ ( byte ) (Index >> 16 ) ] ^ + crc64_tables[ 4 ] [ ( byte ) (Index >> 24 ) ] ^ + crc64_tables[ 3 ] [ ( byte ) (Index >> 32 ) ] ^ + crc64_tables[ 2 ] [ ( byte ) (Index >> 40 ) ] ^ + crc64_tables[ 1 ] [ ( byte ) (Index >> 48 ) ] ^ + crc64_tables[ 0 ] [ ( byte ) (Index >> 56 ) ] ; + } + + for (Size%=8;Size>0;Size--,Data++) // Process left data. + StartCRC=crc64_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8); + + return StartCRC; +} + + +#if 0 +static void TestCRC(); +struct TestCRCStruct {TestCRCStruct() {TestCRC();exit(0);}} GlobalTesCRC; + +void TestCRC() +{ + const uint FirstSize=300; + byte b[FirstSize]; + + if ((CRC32(0xffffffff,(byte*)"testtesttest",12)^0xffffffff)==0x44608e84) + mprintf(L"\nCRC32 test1 OK"); + else + mprintf(L"\nCRC32 test1 FAILED"); + + if (CRC32(0,(byte*)"te\x80st",5)==0xB2E5C5AE) + mprintf(L"\nCRC32 test2 OK"); + else + mprintf(L"\nCRC32 test2 FAILED"); + + for (uint I=0;I<14;I++) // Check for possible int sign extension. + b[I]=(byte)0x7f+I; + if ((CRC32(0xffffffff,b,14)^0xffffffff)==0x1DFA75DA) + mprintf(L"\nCRC32 test3 OK"); + else + mprintf(L"\nCRC32 test3 FAILED"); + + for (uint I=0;IIsSet() || Method==CRYPT_NONE) + if (Method==CRYPT_NONE || !Password->IsSet()) return false; CryptData::Method=Method; wchar PwdW[MAXPASSWORD]; Password->Get(PwdW,ASIZE(PwdW)); + PwdW[Min(MAXPASSWORD_RAR,MAXPASSWORD)-1]=0; // For compatibility with existing archives. + char PwdA[MAXPASSWORD]; WideToChar(PwdW,PwdA,ASIZE(PwdA)); + PwdA[Min(MAXPASSWORD_RAR,MAXPASSWORD)-1]=0; // For compatibility with existing archives. switch(Method) { diff --git a/deps/unrar/crypt.hpp b/deps/unrar/crypt.hpp index ebbad96ed..8f22bea21 100644 --- a/deps/unrar/crypt.hpp +++ b/deps/unrar/crypt.hpp @@ -30,6 +30,18 @@ class CryptData uint Lg2Count; // Log2 of PBKDF2 repetition count. byte PswCheckValue[SHA256_DIGEST_SIZE]; byte HashKeyValue[SHA256_DIGEST_SIZE]; + + KDF5CacheItem() {Clean();} + ~KDF5CacheItem() {Clean();} + + void Clean() + { + cleandata(Salt,sizeof(Salt)); + cleandata(Key,sizeof(Key)); + cleandata(&Lg2Count,sizeof(Lg2Count)); + cleandata(PswCheckValue,sizeof(PswCheckValue)); + cleandata(HashKeyValue,sizeof(HashKeyValue)); + } }; struct KDF3CacheItem @@ -39,6 +51,17 @@ class CryptData byte Key[16]; byte Init[16]; bool SaltPresent; + + KDF3CacheItem() {Clean();} + ~KDF3CacheItem() {Clean();} + + void Clean() + { + cleandata(Salt,sizeof(Salt)); + cleandata(Key,sizeof(Key)); + cleandata(Init,sizeof(Init)); + cleandata(&SaltPresent,sizeof(SaltPresent)); + } }; @@ -77,7 +100,6 @@ class CryptData ushort Key15[4]; public: CryptData(); - ~CryptData(); bool SetCryptKeys(bool Encrypt,CRYPT_METHOD Method,SecPassword *Password, const byte *Salt,const byte *InitV,uint Lg2Cnt, byte *HashKey,byte *PswCheck); @@ -89,6 +111,54 @@ class CryptData static void SetSalt(byte *Salt,size_t SaltSize); }; + +class CheckPassword +{ + public: + enum CONFIDENCE {CONFIDENCE_HIGH,CONFIDENCE_MEDIUM,CONFIDENCE_LOW}; + virtual CONFIDENCE GetConfidence()=0; + virtual bool Check(SecPassword *Password)=0; +}; + +class RarCheckPassword:public CheckPassword +{ + private: + CryptData *Crypt; + uint Lg2Count; + byte Salt[SIZE_SALT50]; + byte InitV[SIZE_INITV]; + byte PswCheck[SIZE_PSWCHECK]; + public: + RarCheckPassword() + { + Crypt=NULL; + } + ~RarCheckPassword() + { + delete Crypt; + } + void Set(byte *Salt,byte *InitV,uint Lg2Count,byte *PswCheck) + { + if (Crypt==NULL) + Crypt=new CryptData; + memcpy(this->Salt,Salt,sizeof(this->Salt)); + memcpy(this->InitV,InitV,sizeof(this->InitV)); + this->Lg2Count=Lg2Count; + memcpy(this->PswCheck,PswCheck,sizeof(this->PswCheck)); + } + bool IsSet() {return Crypt!=NULL;} + + // RAR5 provides the higly reliable 64 bit password verification value. + CONFIDENCE GetConfidence() {return CONFIDENCE_HIGH;} + + bool Check(SecPassword *Password) + { + byte PswCheck[SIZE_PSWCHECK]; + Crypt->SetCryptKeys(false,CRYPT_RAR50,Password,Salt,InitV,Lg2Count,NULL,PswCheck); + return memcmp(PswCheck,this->PswCheck,sizeof(this->PswCheck))==0; + } +}; + void GetRnd(byte *RndBuf,size_t BufSize); void hmac_sha256(const byte *Key,size_t KeyLength,const byte *Data, diff --git a/deps/unrar/crypt3.cpp b/deps/unrar/crypt3.cpp index fe3bf97b8..e6e3a82cb 100644 --- a/deps/unrar/crypt3.cpp +++ b/deps/unrar/crypt3.cpp @@ -18,8 +18,9 @@ void CryptData::SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,co if (!Cached) { byte RawPsw[2*MAXPASSWORD+SIZE_SALT30]; - WideToRaw(PwdW,RawPsw,ASIZE(RawPsw)); - size_t RawLength=2*wcslen(PwdW); + size_t PswLength=wcslen(PwdW); + size_t RawLength=2*PswLength; + WideToRaw(PwdW,PswLength,RawPsw,RawLength); if (Salt!=NULL) { memcpy(RawPsw+RawLength,Salt,SIZE_SALT30); diff --git a/deps/unrar/crypt5.cpp b/deps/unrar/crypt5.cpp index 7562469f3..5ed65af81 100644 --- a/deps/unrar/crypt5.cpp +++ b/deps/unrar/crypt5.cpp @@ -21,7 +21,7 @@ static void hmac_sha256(const byte *Key,size_t KeyLength,const byte *Data, sha256_context ICtx; if (ICtxOpt!=NULL && *SetIOpt) - ICtx=*ICtxOpt; // Use already calculated first block context. + ICtx=*ICtxOpt; // Use already calculated the first block context. else { // This calculation is the same for all iterations with same password. @@ -90,10 +90,10 @@ void pbkdf2(const byte *Pwd, size_t PwdLength, byte SaltData[MaxSalt+4]; memcpy(SaltData, Salt, Min(SaltLength,MaxSalt)); - SaltData[SaltLength + 0] = 0; // Salt concatenated to 1. - SaltData[SaltLength + 1] = 0; - SaltData[SaltLength + 2] = 0; - SaltData[SaltLength + 3] = 1; + SaltData[SaltLength + 0] = 0; // Block index appened to salt. + SaltData[SaltLength + 1] = 0; // + SaltData[SaltLength + 2] = 0; // Since we do not request the key width + SaltData[SaltLength + 3] = 1; // exceeding HMAC width, it is always 1. // First iteration: HMAC of password, salt and block index (1). byte U1[SHA256_DIGEST_SIZE]; @@ -140,7 +140,7 @@ void CryptData::SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW, for (uint I=0;ILg2Count==Lg2Cnt && Item->Pwd==*Password && + if (Item->Pwd==*Password && Item->Lg2Count==Lg2Cnt && memcmp(Item->Salt,Salt,SIZE_SALT50)==0) { memcpy(Key,Item->Key,sizeof(Key)); diff --git a/deps/unrar/dll.def b/deps/unrar/dll.def index 3c9a2c83a..a7241141a 100644 --- a/deps/unrar/dll.def +++ b/deps/unrar/dll.def @@ -1,13 +1,13 @@ -EXPORTS - RAROpenArchive - RAROpenArchiveEx - RARCloseArchive - RARReadHeader - RARReadHeaderEx - RARProcessFile - RARProcessFileW - RARSetCallback - RARSetChangeVolProc - RARSetProcessDataProc - RARSetPassword - RARGetDllVersion +EXPORTS + RAROpenArchive + RAROpenArchiveEx + RARCloseArchive + RARReadHeader + RARReadHeaderEx + RARProcessFile + RARProcessFileW + RARSetCallback + RARSetChangeVolProc + RARSetProcessDataProc + RARSetPassword + RARGetDllVersion diff --git a/deps/unrar/dll.rc b/deps/unrar/dll.rc index 8dd505da0..ff610c835 100644 --- a/deps/unrar/dll.rc +++ b/deps/unrar/dll.rc @@ -1,28 +1,28 @@ -#include -#include - -VS_VERSION_INFO VERSIONINFO -FILEVERSION 6, 1, 100, 3756 -PRODUCTVERSION 6, 1, 100, 3756 -FILEOS VOS__WINDOWS32 -FILETYPE VFT_APP -{ - BLOCK "StringFileInfo" - { - BLOCK "040904E4" - { - VALUE "CompanyName", "Alexander Roshal\0" - VALUE "ProductName", "RAR decompression library\0" - VALUE "FileDescription", "RAR decompression library\0" - VALUE "FileVersion", "6.1.0\0" - VALUE "ProductVersion", "6.1.0\0" - VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2021\0" - VALUE "OriginalFilename", "Unrar.dll\0" - } - } - BLOCK "VarFileInfo" - { - VALUE "Translation", 0x0409, 0x04E4 - } -} - +#include +#include + +VS_VERSION_INFO VERSIONINFO +FILEVERSION 6, 22, 1, 865 +PRODUCTVERSION 6, 22, 1, 865 +FILEOS VOS__WINDOWS32 +FILETYPE VFT_APP +{ + BLOCK "StringFileInfo" + { + BLOCK "040904E4" + { + VALUE "CompanyName", "Alexander Roshal\0" + VALUE "ProductName", "RAR decompression library\0" + VALUE "FileDescription", "RAR decompression library\0" + VALUE "FileVersion", "6.22.1\0" + VALUE "ProductVersion", "6.22.1\0" + VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2023\0" + VALUE "OriginalFilename", "Unrar.dll\0" + } + } + BLOCK "VarFileInfo" + { + VALUE "Translation", 0x0409, 0x04E4 + } +} + diff --git a/deps/unrar/dll_nocrypt.def b/deps/unrar/dll_nocrypt.def index d473e978e..f7037ea4c 100644 --- a/deps/unrar/dll_nocrypt.def +++ b/deps/unrar/dll_nocrypt.def @@ -1,13 +1,13 @@ -EXPORTS - RAROpenArchive - RAROpenArchiveEx - RARCloseArchive - RARReadHeader - RARReadHeaderEx - RARProcessFile - RARProcessFileW - RARSetCallback - RARSetChangeVolProc - RARSetProcessDataProc -; RARSetPassword - RARGetDllVersion +EXPORTS + RAROpenArchive + RAROpenArchiveEx + RARCloseArchive + RARReadHeader + RARReadHeaderEx + RARProcessFile + RARProcessFileW + RARSetCallback + RARSetChangeVolProc + RARSetProcessDataProc +; RARSetPassword + RARGetDllVersion diff --git a/deps/unrar/encname.cpp b/deps/unrar/encname.cpp index 84731a71e..e1ba1ed70 100644 --- a/deps/unrar/encname.cpp +++ b/deps/unrar/encname.cpp @@ -20,8 +20,6 @@ void EncodeFileName::Decode(char *Name,size_t NameSize,byte *EncName,size_t EncS { if (FlagBits==0) { - if (EncPos>=EncSize) - break; Flags=EncName[EncPos++]; FlagBits=8; } diff --git a/deps/unrar/encname.hpp b/deps/unrar/encname.hpp index 538bcb699..c6b4ed44d 100644 --- a/deps/unrar/encname.hpp +++ b/deps/unrar/encname.hpp @@ -4,9 +4,8 @@ class EncodeFileName { private: - void AddFlags(int Value); + void AddFlags(byte Value,byte *EncName); - byte *EncName; byte Flags; uint FlagBits; size_t FlagsPos; diff --git a/deps/unrar/errhnd.cpp b/deps/unrar/errhnd.cpp index 18e91973e..97193e5ac 100644 --- a/deps/unrar/errhnd.cpp +++ b/deps/unrar/errhnd.cpp @@ -169,10 +169,13 @@ void ErrorHandler::OpenErrorMsg(const wchar *FileName) void ErrorHandler::OpenErrorMsg(const wchar *ArcName,const wchar *FileName) { - Wait(); // Keep GUI responsive if many files cannot be opened when archiving. uiMsg(UIERROR_FILEOPEN,ArcName,FileName); SysErrMsg(); SetErrorCode(RARX_OPEN); + + // Keep GUI responsive if many files cannot be opened when archiving. + // Call after SysErrMsg to avoid modifying the error code and SysErrMsg text. + Wait(); } @@ -367,7 +370,7 @@ bool ErrorHandler::GetSysErrMsg(wchar *Msg,size_t Size) void ErrorHandler::SysErrMsg() { -#if !defined(SFX_MODULE) && !defined(SILENT) +#ifndef SILENT wchar Msg[1024]; if (!GetSysErrMsg(Msg,ASIZE(Msg))) return; diff --git a/deps/unrar/extinfo.cpp b/deps/unrar/extinfo.cpp index 5cb90a408..0f25f3124 100644 --- a/deps/unrar/extinfo.cpp +++ b/deps/unrar/extinfo.cpp @@ -112,6 +112,68 @@ static bool LinkInPath(const wchar *Name) } +// Delete symbolic links in file path, if any, and replace them by directories. +// Prevents extracting files outside of destination folder with symlink chains. +bool LinksToDirs(const wchar *SrcName,const wchar *SkipPart,std::wstring &LastChecked) +{ + // Unlike Unix, Windows doesn't expand lnk1 in symlink targets like + // "lnk1/../dir", but converts the path to "dir". In Unix we need to call + // this function to prevent placing unpacked files outside of destination + // folder if previously we unpacked "dir/lnk1" -> "..", + // "dir/lnk2" -> "lnk1/.." and "dir/lnk2/anypath/poc.txt". + // We may still need this function to prevent abusing symlink chains + // in link source path if we remove detection of such chains + // in IsRelativeSymlinkSafe. This function seems to make other symlink + // related safety checks redundant, but for now we prefer to keep them too. + // + // 2022.12.01: the performance impact is minimized after adding the check + // against the previous path and enabling this verification only after + // extracting a symlink with ".." in target. So we enabled it for Windows + // as well for extra safety. +//#ifdef _UNIX + wchar Path[NM]; + if (wcslen(SrcName)>=ASIZE(Path)) + return false; // It should not be that long, skip. + wcsncpyz(Path,SrcName,ASIZE(Path)); + + size_t SkipLength=wcslen(SkipPart); + + if (SkipLength>0 && wcsncmp(Path,SkipPart,SkipLength)!=0) + SkipLength=0; // Parameter validation, not really needed now. + + // Do not check parts already checked in previous path to improve performance. + for (uint I=0;Path[I]!=0 && ISkipLength) + SkipLength=I; + + wchar *Name=Path; + if (SkipLength>0) + { + // Avoid converting symlinks in destination path part specified by user. + Name+=SkipLength; + while (IsPathDiv(*Name)) + Name++; + } + + for (wchar *s=Path+wcslen(Path)-1;s>Name;s--) + if (IsPathDiv(*s)) + { + *s=0; + FindData FD; + if (FindFile::FastFind(Path,&FD,true) && FD.IsLink) +#ifdef _WIN_ALL + if (!DelDir(Path)) +#else + if (!DelFile(Path)) +#endif + return false; // Couldn't delete the symlink to replace it with directory. + } + LastChecked=SrcName; +//#endif + return true; +} + + bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName) { // Catch root dir based /path/file paths also as stuff like \\?\. @@ -131,10 +193,14 @@ bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *Pr UpLevels++; TargetName++; } - // If link target includes "..", it must not have another links - // in the path, because they can bypass our safety check. For example, + // If link target includes "..", it must not have another links in its + // source path, because they can bypass our safety check. For example, // suppose we extracted "lnk1" -> "." first and "lnk1/lnk2" -> ".." next - // or "dir/lnk1" -> ".." first and "dir/lnk1/lnk2" -> ".." next. + // or "dir/lnk1" -> ".." first, "dir/lnk1/lnk2" -> ".." next and + // file "dir/lnk1/lnk2/poc.txt" last. + // Do not confuse with link chains in target, this is in link source path. + // It is important for Windows too, though this check can be omitted + // if LinksToDirs is invoked in Windows as well. if (UpLevels>0 && LinkInPath(PrepSrcName)) return false; @@ -160,15 +226,26 @@ bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *Pr } -bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName) +bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName,bool &UpLink) { + // Returning true in Uplink indicates that link target might include ".." + // and enables additional checks. It is ok to falsely return true here, + // as it implies only the minor performance penalty. But we shall always + // return true for links with ".." in target for security reason. + + UpLink=true; // Assume the target might include potentially unsafe "..". +#if defined(SAVE_LINKS) && defined(_UNIX) || defined(_WIN_ALL) + if (Arc.Format==RARFMT50) // For RAR5 archives we can check RedirName for both Unix and Windows. + UpLink=wcsstr(Arc.FileHead.RedirName,L"..")!=NULL; +#endif + #if defined(SAVE_LINKS) && defined(_UNIX) // For RAR 3.x archives we process links even in test mode to skip link data. if (Arc.Format==RARFMT15) - return ExtractUnixLink30(Cmd,DataIO,Arc,LinkName); + return ExtractUnixLink30(Cmd,DataIO,Arc,LinkName,UpLink); if (Arc.Format==RARFMT50) return ExtractUnixLink50(Cmd,LinkName,&Arc.FileHead); -#elif defined _WIN_ALL +#elif defined(_WIN_ALL) // RAR 5.0 archives store link information in file header, so there is // no need to additionally test it if we do not create a file. if (Arc.Format==RARFMT50) diff --git a/deps/unrar/extinfo.hpp b/deps/unrar/extinfo.hpp index f3c7511b4..d8551d463 100644 --- a/deps/unrar/extinfo.hpp +++ b/deps/unrar/extinfo.hpp @@ -1,8 +1,9 @@ #ifndef _RAR_EXTINFO_ #define _RAR_EXTINFO_ +bool LinksToDirs(const wchar *SrcName,const wchar *SkipPart,std::wstring &LastChecked); bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName); -bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName); +bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName,bool &UpLink); #ifdef _UNIX void SetUnixOwner(Archive &Arc,const wchar *FileName); #endif diff --git a/deps/unrar/extract.cpp b/deps/unrar/extract.cpp index dc824aa97..4d9e51202 100644 --- a/deps/unrar/extract.cpp +++ b/deps/unrar/extract.cpp @@ -5,10 +5,30 @@ CmdExtract::CmdExtract(CommandData *Cmd) CmdExtract::Cmd=Cmd; *ArcName=0; - *DestFileName=0; + ArcAnalyzed=false; + Analyze=new AnalyzeData; + memset(Analyze,0,sizeof(*Analyze)); + TotalFileCount=0; + + // Common for all archives involved. Set here instead of DoExtract() + // to use in unrar.dll too. Allows to avoid LinksToDirs() calls + // and save CPU time in no symlinks including ".." in target were extracted. +#if defined(_WIN_ALL) + // We can't expand symlink path components in another symlink target + // in Windows. We can't create symlinks in Android now. Even though we do not + // really need LinksToDirs() calls in these systems, we still call it + // for extra safety, but only if symlink with ".." in target was extracted. + ConvertSymlinkPaths=false; +#else + // We enable it by default in Unix to care about the case when several + // archives are unpacked to same directory with several independent RAR runs. + // Worst case performance penalty for a lot of small files seems to be ~3%. + ConvertSymlinkPaths=true; +#endif + Unp=new Unpack(&DataIO); #ifdef RAR_SMP Unp->SetThreads(Cmd->Threads); @@ -18,7 +38,26 @@ CmdExtract::CmdExtract(CommandData *Cmd) CmdExtract::~CmdExtract() { + FreeAnalyzeData(); delete Unp; + delete Analyze; +} + + +void CmdExtract::FreeAnalyzeData() +{ + for (size_t I=0;ICommand[0]); - FindData FD; - while (Cmd->GetArcName(ArcName,ASIZE(ArcName))) - if (FindFile::FastFind(ArcName,&FD)) - DataIO.TotalArcSize+=FD.Size; + if (*Cmd->UseStdin==0) + { + FindData FD; + while (Cmd->GetArcName(ArcName,ASIZE(ArcName))) + if (FindFile::FastFind(ArcName,&FD)) + DataIO.TotalArcSize+=FD.Size; + } Cmd->ArcNames.Rewind(); while (Cmd->GetArcName(ArcName,ASIZE(ArcName))) @@ -49,8 +91,7 @@ void CmdExtract::DoExtract() if (Code!=EXTRACT_ARC_REPEAT) break; } - if (FindFile::FastFind(ArcName,&FD)) - DataIO.ProcessedArcSize+=FD.Size; + DataIO.ProcessedArcSize+=DataIO.LastArcSize; } // Clean user entered password. Not really required, just for extra safety. @@ -82,7 +123,7 @@ void CmdExtract::DoExtract() void CmdExtract::ExtractArchiveInit(Archive &Arc) { - DataIO.UnpArcSize=Arc.FileLength(); + DataIO.AdjustTotalArcSize(&Arc); FileCount=0; MatchedArgs=0; @@ -98,15 +139,33 @@ void CmdExtract::ExtractArchiveInit(Archive &Arc) AllMatchesExact=true; AnySolidDataUnpackedWell=false; + ArcAnalyzed=false; + StartTime.SetCurrentTime(); + + LastCheckedSymlink.clear(); } EXTRACT_ARC_CODE CmdExtract::ExtractArchive() { Archive Arc(Cmd); - if (!Arc.WOpen(ArcName)) - return EXTRACT_ARC_NEXT; + if (*Cmd->UseStdin!=0) + { + Arc.SetHandleType(FILE_HANDLESTD); +#ifdef USE_QOPEN + Arc.SetProhibitQOpen(true); +#endif + } + else + { +#if defined(_WIN_ALL) && !defined(SFX_MODULE) // WinRAR GUI code also resets the cache. + if (*Cmd->Command=='T' || Cmd->Test) + ResetFileCache(ArcName); // Reset the file cache when testing an archive. +#endif + if (!Arc.WOpen(ArcName)) + return EXTRACT_ARC_NEXT; + } if (!Arc.IsArchive(true)) { @@ -155,20 +214,33 @@ EXTRACT_ARC_CODE CmdExtract::ExtractArchive() } #endif + Arc.ViewComment(); // Must be before possible EXTRACT_ARC_REPEAT. + int64 VolumeSetSize=0; // Total size of volumes after the current volume. +#ifndef SFX_MODULE + if (!ArcAnalyzed && *Cmd->UseStdin==0) + { + AnalyzeArchive(Arc.FileName,Arc.Volume,Arc.NewNumbering); + ArcAnalyzed=true; // Avoid repeated analysis on EXTRACT_ARC_REPEAT. + } +#endif + if (Arc.Volume) { #ifndef SFX_MODULE // Try to speed up extraction for independent solid volumes by starting // extraction from non-first volume if we can. - if (!UseExactVolName && Arc.Solid && DetectStartVolume(Arc.FileName,Arc.NewNumbering)) + if (*Analyze->StartName!=0) { + wcsncpyz(ArcName,Analyze->StartName,ASIZE(ArcName)); + *Analyze->StartName=0; + UseExactVolName=true; return EXTRACT_ARC_REPEAT; } #endif - + // Calculate the total size of all accessible volumes. // This size is necessary to display the correct total progress indicator. @@ -203,7 +275,13 @@ EXTRACT_ARC_CODE CmdExtract::ExtractArchive() else uiStartArchiveExtract(!Cmd->Test,ArcName); - Arc.ViewComment(); +#ifndef SFX_MODULE + if (Analyze->StartPos!=0) + { + Arc.Seek(Analyze->StartPos,SEEK_SET); + Analyze->StartPos=0; + } +#endif while (1) @@ -216,14 +294,11 @@ EXTRACT_ARC_CODE CmdExtract::ExtractArchive() if (Repeat) { // If we started extraction from not first volume and need to - // restart it from first, we must correct DataIO.TotalArcSize - // for correct total progress display. We subtract the size - // of current volume and all volumes after it and add the size - // of new (first) volume. - FindData OldArc,NewArc; - if (FindFile::FastFind(Arc.FileName,&OldArc) && - FindFile::FastFind(ArcName,&NewArc)) - DataIO.TotalArcSize-=VolumeSetSize+OldArc.Size-NewArc.Size; + // restart it from first, we must set DataIO.TotalArcSize to size + // of new first volume to display the total progress correctly. + FindData NewArc; + if (FindFile::FastFind(ArcName,&NewArc)) + DataIO.TotalArcSize=NewArc.Size; return EXTRACT_ARC_REPEAT; } else @@ -262,7 +337,14 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) return false; HEADER_TYPE HeaderType=Arc.GetHeaderType(); - if (HeaderType!=HEAD_FILE) + if (HeaderType==HEAD_FILE) + { + // Unlike Arc.FileName, ArcName might store an old volume name here. + if (Analyze->EndPos!=0 && Analyze->EndPos==Arc.CurBlockPos && + (*Analyze->EndName==0 || wcscmp(Analyze->EndName,Arc.FileName)==0)) + return false; + } + else { #ifndef SFX_MODULE if (Arc.Format==RARFMT15 && HeaderType==HEAD3_OLDSERVICE && PrevProcessed) @@ -305,6 +387,9 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) if (Arc.FileHead.UnpSize<0) Arc.FileHead.UnpSize=0; + // 2022.03.20: We might remove this check in the future. + // It duplicates Analyze->EndPos and Analyze->EndName in all cases except + // volumes on removable media. if (!Cmd->Recurse && MatchedArgs>=Cmd->FileArgs.ItemsCount() && AllMatchesExact) return false; @@ -403,7 +488,39 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) FirstFile=false; #endif - if (MatchFound || (SkipSolid=Arc.Solid)!=0) + bool RefTarget=false; + if (!MatchFound) + for (size_t I=0;ITest) // While harmless, it is useless for 't'. + { + // If reference source isn't selected, but target is selected, + // we unpack the source under the temporary name and then rename + // or copy it to target name. We do not unpack it under the target + // name immediately, because the same source can be used by multiple + // targets and it is possible that first target isn't unpacked + // for some reason. Also targets might have associated service blocks + // like ACLs. All this would complicate processing a lot. + wcsncpyz(DestFileName,*Cmd->TempPath!=0 ? Cmd->TempPath:Cmd->ExtrPath,ASIZE(DestFileName)); + AddEndSlash(DestFileName,ASIZE(DestFileName)); + wcsncatz(DestFileName,L"__tmp_reference_source_",ASIZE(DestFileName)); + MkTemp(DestFileName,ASIZE(DestFileName)); + MatchedRef->TmpName=wcsdup(DestFileName); + } + RefTarget=true; // Need it even for 't' to test the reference source. + break; + } + + if (Arc.FileHead.Encrypted && Cmd->SkipEncrypted) + if (Arc.Solid) + return false; // Abort the entire extraction for solid archive. + else + MatchFound=false; // Skip only the current file for non-solid archive. + + if (MatchFound || RefTarget || (SkipSolid=Arc.Solid)!=0) { // First common call of uiStartFileExtract. It is done before overwrite // prompts, so if SkipSolid state is changed below, we'll need to make @@ -411,7 +528,8 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) if (!uiStartFileExtract(ArcFileName,!Cmd->Test,Cmd->Test && Command!='I',SkipSolid)) return false; - ExtrPrepareName(Arc,ArcFileName,DestFileName,ASIZE(DestFileName)); + if (!RefTarget) + ExtrPrepareName(Arc,ArcFileName,DestFileName,ASIZE(DestFileName)); // DestFileName can be set empty in case of excessive -ap switch. ExtrFile=!SkipSolid && *DestFileName!=0 && !Arc.FileHead.SplitBefore; @@ -448,9 +566,13 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) return !Arc.Solid; // Can try extracting next file only in non-solid archive. } - while (true) // Repeat the password prompt for wrong and empty passwords. + if (Arc.FileHead.Encrypted) { - if (Arc.FileHead.Encrypted) + RarCheckPassword CheckPwd; + if (Arc.Format==RARFMT50 && Arc.FileHead.UsePswCheck && !Arc.BrokenHeader) + CheckPwd.Set(Arc.FileHead.Salt,Arc.FileHead.InitV,Arc.FileHead.Lg2Count,Arc.FileHead.PswCheck); + + while (true) // Repeat the password prompt for wrong and empty passwords. { // Stop archive extracting if user cancelled a password prompt. #ifdef RARDLL @@ -460,77 +582,83 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) return false; } #else - if (!ExtrGetPassword(Arc,ArcFileName)) + if (!ExtrGetPassword(Arc,ArcFileName,CheckPwd.IsSet() ? &CheckPwd:NULL)) { PasswordCancelled=true; return false; } #endif - } - - // Set a password before creating the file, so we can skip creating - // in case of wrong password. - SecPassword FilePassword=Cmd->Password; -#if defined(_WIN_ALL) && !defined(SFX_MODULE) - ConvertDosPassword(Arc,FilePassword); -#endif - byte PswCheck[SIZE_PSWCHECK]; - DataIO.SetEncryption(false,Arc.FileHead.CryptMethod,&FilePassword, - Arc.FileHead.SaltSet ? Arc.FileHead.Salt:NULL, - Arc.FileHead.InitV,Arc.FileHead.Lg2Count, - Arc.FileHead.HashKey,PswCheck); - - // If header is damaged, we cannot rely on password check value, - // because it can be damaged too. - if (Arc.FileHead.Encrypted && Arc.FileHead.UsePswCheck && - memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0 && - !Arc.BrokenHeader) - { - if (GlobalPassword) // For -p or Ctrl+P to avoid the infinite loop. - { - // This message is used by Android GUI to reset cached passwords. - // Update appropriate code if changed. - uiMsg(UIERROR_BADPSW,Arc.FileName,ArcFileName); - } - else // For passwords entered manually. + // Set a password before creating the file, so we can skip creating + // in case of wrong password. + SecPassword FilePassword=Cmd->Password; + #if defined(_WIN_ALL) && !defined(SFX_MODULE) + ConvertDosPassword(Arc,FilePassword); + #endif + + byte PswCheck[SIZE_PSWCHECK]; + DataIO.SetEncryption(false,Arc.FileHead.CryptMethod,&FilePassword, + Arc.FileHead.SaltSet ? Arc.FileHead.Salt:NULL, + Arc.FileHead.InitV,Arc.FileHead.Lg2Count, + Arc.FileHead.HashKey,PswCheck); + + // If header is damaged, we cannot rely on password check value, + // because it can be damaged too. + if (Arc.FileHead.UsePswCheck && !Arc.BrokenHeader && + memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0) { - // This message is used by Android GUI and Windows GUI and SFX to - // reset cached passwords. Update appropriate code if changed. - uiMsg(UIWAIT_BADPSW,Arc.FileName,ArcFileName); - Cmd->Password.Clean(); - - // Avoid new requests for unrar.dll to prevent the infinite loop - // if app always returns the same password. -#ifndef RARDLL - continue; // Request a password again. -#endif + if (GlobalPassword) // For -p or Ctrl+P to avoid the infinite loop. + { + // This message is used by Android GUI to reset cached passwords. + // Update appropriate code if changed. + uiMsg(UIERROR_BADPSW,Arc.FileName,ArcFileName); + } + else // For passwords entered manually. + { + // This message is used by Android GUI and Windows GUI and SFX to + // reset cached passwords. Update appropriate code if changed. + uiMsg(UIWAIT_BADPSW,Arc.FileName,ArcFileName); + Cmd->Password.Clean(); + + // Avoid new requests for unrar.dll to prevent the infinite loop + // if app always returns the same password. + #ifndef RARDLL + continue; // Request a password again. + #endif + } + #ifdef RARDLL + // If we already have ERAR_EOPEN as result of missing volume, + // we should not replace it with less precise ERAR_BAD_PASSWORD. + if (Cmd->DllError!=ERAR_EOPEN) + Cmd->DllError=ERAR_BAD_PASSWORD; + #endif + ErrHandler.SetErrorCode(RARX_BADPWD); + ExtrFile=false; } -#ifdef RARDLL - // If we already have ERAR_EOPEN as result of missing volume, - // we should not replace it with less precise ERAR_BAD_PASSWORD. - if (Cmd->DllError!=ERAR_EOPEN) - Cmd->DllError=ERAR_BAD_PASSWORD; -#endif - ErrHandler.SetErrorCode(RARX_BADPWD); - ExtrFile=false; + break; } - break; } + else + DataIO.SetEncryption(false,CRYPT_NONE,NULL,NULL,NULL,0,NULL,NULL); #ifdef RARDLL if (*Cmd->DllDestName!=0) wcsncpyz(DestFileName,Cmd->DllDestName,ASIZE(DestFileName)); #endif + if (ExtrFile && Command!='P' && !Cmd->Test && !Cmd->AbsoluteLinks && + ConvertSymlinkPaths) + ExtrFile=LinksToDirs(DestFileName,Cmd->ExtrPath,LastCheckedSymlink); + File CurFile; bool LinkEntry=Arc.FileHead.RedirType!=FSREDIR_NONE; - if (LinkEntry && Arc.FileHead.RedirType!=FSREDIR_FILECOPY) + if (LinkEntry && (Arc.FileHead.RedirType!=FSREDIR_FILECOPY)) { if (ExtrFile && Command!='P' && !Cmd->Test) { - // Overwrite prompt for symbolic and hard links. + // Overwrite prompt for symbolic and hard links and when we move + // a temporary file to the file reference instead of copying it. bool UserReject=false; if (FileExist(DestFileName) && !UserReject) FileCreate(Cmd,NULL,DestFileName,ASIZE(DestFileName),&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime); @@ -632,7 +760,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) uint64 Preallocated=0; if (!TestMode && !Arc.BrokenHeader && Arc.FileHead.UnpSize>1000000 && - Arc.FileHead.PackSize*1024>Arc.FileHead.UnpSize && + Arc.FileHead.PackSize*1024>Arc.FileHead.UnpSize && Arc.IsSeekable() && (Arc.FileHead.UnpSize<100000000 || Arc.FileLength()>Arc.FileHead.PackSize)) { CurFile.Prealloc(Arc.FileHead.UnpSize); @@ -650,23 +778,51 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) if (Type==FSREDIR_HARDLINK || Type==FSREDIR_FILECOPY) { + wchar RedirName[NM]; + + // 2022.11.15: Might be needed when unpacking WinRAR 5.0 links with + // Unix RAR. WinRAR 5.0 used \ path separators here, when beginning + // from 5.10 even Windows version uses / internally and converts + // them to \ when reading FHEXTRA_REDIR. + // We must perform this conversion before ConvertPath call, + // so paths mixing different slashes like \dir1/dir2\file are + // processed correctly. + SlashToNative(Arc.FileHead.RedirName,RedirName,ASIZE(RedirName)); + + ConvertPath(RedirName,RedirName,ASIZE(RedirName)); + wchar NameExisting[NM]; - ExtrPrepareName(Arc,Arc.FileHead.RedirName,NameExisting,ASIZE(NameExisting)); + ExtrPrepareName(Arc,RedirName,NameExisting,ASIZE(NameExisting)); if (FileCreateMode && *NameExisting!=0) // *NameExisting can be 0 in case of excessive -ap switch. if (Type==FSREDIR_HARDLINK) LinkSuccess=ExtractHardlink(Cmd,DestFileName,NameExisting,ASIZE(NameExisting)); else - LinkSuccess=ExtractFileCopy(CurFile,Arc.FileName,DestFileName,NameExisting,ASIZE(NameExisting)); + LinkSuccess=ExtractFileCopy(CurFile,Arc.FileName,RedirName,DestFileName,NameExisting,ASIZE(NameExisting),Arc.FileHead.UnpSize); } else if (Type==FSREDIR_UNIXSYMLINK || Type==FSREDIR_WINSYMLINK || Type==FSREDIR_JUNCTION) { if (FileCreateMode) - LinkSuccess=ExtractSymlink(Cmd,DataIO,Arc,DestFileName); + { + bool UpLink; + LinkSuccess=ExtractSymlink(Cmd,DataIO,Arc,DestFileName,UpLink); + ConvertSymlinkPaths|=LinkSuccess && UpLink; + + // We do not actually need to reset the cache here if we cache + // only the single last checked path, because at this point + // it will always contain the link own path and link can't + // overwrite its parent folder. But if we ever decide to cache + // several already checked paths, we'll need to reset them here. + // Otherwise if no files were created in one of such paths, + // let's say because of file create error, it might be possible + // to overwrite the path with link and avoid checks. We keep this + // code here as a reminder in case of possible modifications. + LastCheckedSymlink.clear(); // Reset cache for safety reason. + } } else { - uiMsg(UIERROR_UNKNOWNEXTRA,Arc.FileName,DestFileName); + uiMsg(UIERROR_UNKNOWNEXTRA,Arc.FileName,ArcFileName); LinkSuccess=false; } @@ -690,6 +846,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) Unp->Init(Arc.FileHead.WinSize,Arc.FileHead.Solid); Unp->SetDestSize(Arc.FileHead.UnpSize); #ifndef SFX_MODULE + // RAR 1.3 - 1.5 archives do not set per file solid flag. if (Arc.Format!=RARFMT50 && Arc.FileHead.UnpVer<=15) Unp->DoUnpack(15,FileCount>1 && Arc.Solid); else @@ -847,22 +1004,64 @@ void CmdExtract::UnstoreFile(ComprDataIO &DataIO,int64 DestUnpSize) } -bool CmdExtract::ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize) +bool CmdExtract::ExtractFileCopy(File &New,wchar *ArcName,const wchar *RedirName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize,int64 UnpSize) { - SlashToNative(NameExisting,NameExisting,NameExistingSize); // Not needed for RAR 5.1+ archives. - File Existing; - if (!Existing.WOpen(NameExisting)) + if (!Existing.Open(NameExisting)) { - uiMsg(UIERROR_FILECOPY,ArcName,NameExisting,NameNew); - uiMsg(UIERROR_FILECOPYHINT,ArcName); + bool OpenFailed=true; + // If we couldn't find the existing file, check if match is present + // in temporary reference sources list. + for (size_t I=0;IDllError=ERAR_EREFERENCE; + Cmd->DllError=ERAR_EREFERENCE; #endif - return false; + return false; + } } - Array Buffer(0x100000); + Array Buffer(0x100000); int64 CopySize=0; while (true) @@ -871,6 +1070,10 @@ bool CmdExtract::ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar * int ReadSize=Existing.Read(&Buffer[0],Buffer.Size()); if (ReadSize==0) break; + // Update only the current file progress in WinRAR, set the total to 0 + // to keep it as is. It looks better for WinRAR. + uiExtractProgress(CopySize,UnpSize,0,0); + New.Write(&Buffer[0],ReadSize); CopySize+=ReadSize; } @@ -881,6 +1084,16 @@ bool CmdExtract::ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar * void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize) { + if (Cmd->Test) + { + // Destination name conversion isn't needed for simple archive test. + // This check also allows to avoid issuing "Attempting to correct... + // Renaming..." messages in MakeNameCompatible() below for problematic + // names like aux.txt when testing an archive. + wcsncpyz(DestName,ArcFileName,DestSize); + return; + } + wcsncpyz(DestName,Cmd->ExtrPath,DestSize); if (*Cmd->ExtrPath!=0) @@ -888,6 +1101,8 @@ void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *De wchar LastChar=*PointToLastChar(Cmd->ExtrPath); // We need IsPathDiv check here to correctly handle Unix forward slash // in the end of destination path in Windows: rar x arc dest/ + // so we call IsPathDiv first instead of just calling AddEndSlash, + // which checks for only one type of path separator. // IsDriveDiv is needed for current drive dir: rar x arc d: if (!IsPathDiv(LastChar) && !IsDriveDiv(LastChar)) { @@ -919,19 +1134,13 @@ void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *De #endif #ifndef SFX_MODULE - size_t ArcPathLength=wcslen(Cmd->ArcPath); + wchar *ArcPath=*Cmd->ExclArcPath!=0 ? Cmd->ExclArcPath:Cmd->ArcPath; + size_t ArcPathLength=wcslen(ArcPath); if (ArcPathLength>0) { size_t NameLength=wcslen(ArcFileName); - - // Earlier we compared lengths only here, but then noticed a cosmetic bug - // in WinRAR. When extracting a file reference from subfolder with - // "Extract relative paths", so WinRAR sets ArcPath, if reference target - // is missing, error message removed ArcPath both from reference and target - // names. If target was stored in another folder, its name looked wrong. - if (NameLength>=ArcPathLength && - wcsnicompc(Cmd->ArcPath,ArcFileName,ArcPathLength)==0 && - (IsPathDiv(Cmd->ArcPath[ArcPathLength-1]) || + if (NameLength>=ArcPathLength && wcsnicompc(ArcPath,ArcFileName,ArcPathLength)==0 && + (IsPathDiv(ArcPath[ArcPathLength-1]) || IsPathDiv(ArcFileName[ArcPathLength]) || ArcFileName[ArcPathLength]==0)) { ArcFileName+=Min(ArcPathLength,NameLength); @@ -964,7 +1173,7 @@ void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *De // Must do after Cmd->ArcPath processing above, so file name and arc path // trailing spaces are in sync. if (!Cmd->AllowIncompatNames) - MakeNameCompatible(DestName); + MakeNameCompatible(DestName,DestSize); #endif wchar DiskLetter=toupperw(DestName[0]); @@ -1018,18 +1227,14 @@ bool CmdExtract::ExtrDllGetPassword() #ifndef RARDLL -bool CmdExtract::ExtrGetPassword(Archive &Arc,const wchar *ArcFileName) +bool CmdExtract::ExtrGetPassword(Archive &Arc,const wchar *ArcFileName,RarCheckPassword *CheckPwd) { if (!Cmd->Password.IsSet()) { - if (!uiGetPassword(UIPASSWORD_FILE,ArcFileName,&Cmd->Password)/* || !Cmd->Password.IsSet()*/) + if (!uiGetPassword(UIPASSWORD_FILE,ArcFileName,&Cmd->Password,CheckPwd)/* || !Cmd->Password.IsSet()*/) { // Suppress "test is ok" message if user cancelled the password prompt. -// 2019.03.23: If some archives are tested ok and prompt is cancelled for others, -// do we really need to suppress "test is ok"? Also if we set an empty password -// and "Use for all archives" in WinRAR Ctrl+P and skip some encrypted archives. -// We commented out this UIERROR_INCERRCOUNT for now. -// uiMsg(UIERROR_INCERRCOUNT); + uiMsg(UIERROR_INCERRCOUNT); return false; } Cmd->ManualPassword=true; @@ -1044,7 +1249,7 @@ bool CmdExtract::ExtrGetPassword(Archive &Arc,const wchar *ArcFileName) case -1: ErrHandler.Exit(RARX_USERBREAK); case 2: - if (!uiGetPassword(UIPASSWORD_FILE,ArcFileName,&Cmd->Password)) + if (!uiGetPassword(UIPASSWORD_FILE,ArcFileName,&Cmd->Password,CheckPwd)) return false; break; case 3: @@ -1120,6 +1325,8 @@ void CmdExtract::ExtrCreateDir(Archive &Arc,const wchar *ArcFileName) DirExist=FileExist(DestFileName) && IsDir(GetFileAttr(DestFileName)); if (!DirExist) { + if (!Cmd->AbsoluteLinks && ConvertSymlinkPaths) + LinksToDirs(DestFileName,Cmd->ExtrPath,LastCheckedSymlink); CreatePath(DestFileName,true,Cmd->DisableNames); MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,Arc.FileHead.FileAttr); } @@ -1201,6 +1408,8 @@ bool CmdExtract::ExtrCreateFile(Archive &Arc,File &CurFile) MakeNameUsable(DestFileName,true); + if (!Cmd->AbsoluteLinks && ConvertSymlinkPaths) + LinksToDirs(DestFileName,Cmd->ExtrPath,LastCheckedSymlink); CreatePath(DestFileName,true,Cmd->DisableNames); if (FileCreate(Cmd,&CurFile,DestFileName,ASIZE(DestFileName),&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime,true)) { @@ -1247,31 +1456,59 @@ bool CmdExtract::CheckUnpVer(Archive &Arc,const wchar *ArcFileName) #ifndef SFX_MODULE -// To speed up solid volumes extraction, try to find a non-first start volume, -// which still allows to unpack all files. It is possible for independent -// solid volumes with solid statistics reset in the beginning. -bool CmdExtract::DetectStartVolume(const wchar *VolName,bool NewNumbering) +// Find non-matched reference sources in solid and non-solid archives. +// Detect the optimal start position for semi-solid archives +// and optimal start volume for independent solid volumes. +// +// Alternatively we could collect references while extracting an archive +// and perform the second extraction pass for references only. +// But it would be slower for solid archives than scaning headers +// in first pass and extracting everything in second, as implemented now. +// +void CmdExtract::AnalyzeArchive(const wchar *ArcName,bool Volume,bool NewNumbering) { + FreeAnalyzeData(); // If processing non-first archive in multiple archives set. + wchar *ArgName=Cmd->FileArgs.GetString(); Cmd->FileArgs.Rewind(); if (ArgName!=NULL && (wcscmp(ArgName,L"*")==0 || wcscmp(ArgName,L"*.*")==0)) - return false; // No need to check further for * and *.* masks. + return; // No need to check further for * and *.* masks. - wchar StartName[NM]; - *StartName=0; - // Start search from first volume if all volumes preceding current are available. wchar NextName[NM]; - GetFirstVolIfFullSet(VolName,NewNumbering,NextName,ASIZE(NextName)); + if (Volume) + GetFirstVolIfFullSet(ArcName,NewNumbering,NextName,ASIZE(NextName)); + else + wcsncpyz(NextName,ArcName,ASIZE(NextName)); + + bool MatchFound=false; + bool PrevMatched=false; + bool OpenNext=false; + + bool FirstVolume=true; + + // We shall set FirstFile once for all volumes and not for each volume. + // So we do not reuse the outdated Analyze->StartPos from previous volume + // if extracted file resides completely in the beginning of current one. + bool FirstFile=true; - bool Matched=false; - while (!Matched) + while (true) { Archive Arc(Cmd); - if (!Arc.Open(NextName) || !Arc.IsArchive(false) || !Arc.Volume) + if (!Arc.Open(NextName) || !Arc.IsArchive(false)) + { + if (OpenNext) + { + // If we couldn't open trailing volumes, we can't set early exit + // parameters. It is possible that some volume are on removable media + // and will be provided by user when extracting. + *Analyze->EndName=0; + Analyze->EndPos=0; + } break; + } - bool OpenNext=false; + OpenNext=false; while (Arc.ReadHeader()>0) { Wait(); @@ -1284,17 +1521,88 @@ bool CmdExtract::DetectStartVolume(const wchar *VolName,bool NewNumbering) } if (HeaderType==HEAD_FILE) { + if ((Arc.Format==RARFMT14 || Arc.Format==RARFMT15) && Arc.FileHead.UnpVer<=15) + { + // RAR versions earlier than 2.0 do not set per file solid flag. + // They have only the global archive solid flag, so we can't + // reliably analyze them here. + OpenNext=false; + break; + } + if (!Arc.FileHead.SplitBefore) { - if (!Arc.FileHead.Solid) // Can start extraction from here. - wcsncpyz(StartName,NextName,ASIZE(StartName)); + if (!MatchFound && !Arc.FileHead.Solid) // Can start extraction from here. + { + // We would gain nothing and unnecessarily complicate extraction + // if we set StartName for first volume or StartPos for first + // archived file. + if (!FirstVolume) + wcsncpyz(Analyze->StartName,NextName,ASIZE(Analyze->StartName)); + + // We shall set FirstFile once for all volumes for this code + // to work properly. Alternatively we could append + // "|| Analyze->StartPos!=0" to the condition, so we do not reuse + // the outdated Analyze->StartPos value from previous volume. + if (!FirstFile) + Analyze->StartPos=Arc.CurBlockPos; + } if (Cmd->IsProcessFile(Arc.FileHead,NULL,MATCH_WILDSUBPATH,0,NULL,0)!=0) { - Matched=true; // First matched file found, must stop further scan. - break; + MatchFound = true; + PrevMatched = true; + + // Reset the previously set early exit position, if any, because + // we found a new matched file. + Analyze->EndPos=0; + + // Matched file reference pointing at maybe non-matched source file. + // Even though we know RedirName, we can't check if source file + // is certainly non-matched, because it can be filtered out by + // date or attributes, which we do not know here. + if (Arc.FileHead.RedirType==FSREDIR_FILECOPY) + { + bool AlreadyAdded=false; + for (size_t I=0;IEndName,NextName,ASIZE(Analyze->EndName)); + Analyze->EndPos=Arc.CurBlockPos; + } + PrevMatched=false; } } + + FirstFile=false; if (Arc.FileHead.SplitAfter) { OpenNext=true; // Allow open next volume. @@ -1305,16 +1613,25 @@ bool CmdExtract::DetectStartVolume(const wchar *VolName,bool NewNumbering) } Arc.Close(); - if (!OpenNext) - break; + if (Volume && OpenNext) + { + NextVolumeName(NextName,ASIZE(NextName),!Arc.NewNumbering); + FirstVolume=false; - NextVolumeName(NextName,ASIZE(NextName),!Arc.NewNumbering); + // Needed for multivolume archives. Added in case some 'break' + // will quit early from loop above, so we do not set it in the loop. + // Now it can happen for hypothetical archive without file records + // and with HEAD_ENDARC record. + FirstFile=false; + } + else + break; } - bool NewStartFound=wcscmp(VolName,StartName)!=0; - if (NewStartFound) // Found a new volume to start extraction. - wcsncpyz(ArcName,StartName,ASIZE(ArcName)); - - return NewStartFound; + + // If file references are present, we can't reliably skip in semi-solid + // archives, because reference source can be present in skipped data. + if (RefList.Size()!=0) + memset(Analyze,0,sizeof(*Analyze)); } #endif diff --git a/deps/unrar/extract.hpp b/deps/unrar/extract.hpp index 159759b56..18396c5b9 100644 --- a/deps/unrar/extract.hpp +++ b/deps/unrar/extract.hpp @@ -6,13 +6,32 @@ enum EXTRACT_ARC_CODE {EXTRACT_ARC_NEXT,EXTRACT_ARC_REPEAT}; class CmdExtract { private: + struct ExtractRef + { + wchar *RefName; + wchar *TmpName; + uint64 RefCount; + }; + Array RefList; + + struct AnalyzeData + { + wchar StartName[NM]; + uint64 StartPos; + wchar EndName[NM]; + uint64 EndPos; + } *Analyze; + + bool ArcAnalyzed; + + void FreeAnalyzeData(); EXTRACT_ARC_CODE ExtractArchive(); - bool ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize); + bool ExtractFileCopy(File &New,wchar *ArcName,const wchar *RedirName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize,int64 UnpSize); void ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize); #ifdef RARDLL bool ExtrDllGetPassword(); #else - bool ExtrGetPassword(Archive &Arc,const wchar *ArcFileName); + bool ExtrGetPassword(Archive &Arc,const wchar *ArcFileName,RarCheckPassword *CheckPwd); #endif #if defined(_WIN_ALL) && !defined(SFX_MODULE) void ConvertDosPassword(Archive &Arc,SecPassword &DestPwd); @@ -21,7 +40,7 @@ class CmdExtract bool ExtrCreateFile(Archive &Arc,File &CurFile); bool CheckUnpVer(Archive &Arc,const wchar *ArcFileName); #ifndef SFX_MODULE - bool DetectStartVolume(const wchar *VolName,bool NewNumbering); + void AnalyzeArchive(const wchar *ArcName,bool Volume,bool NewNumbering); void GetFirstVolIfFullSet(const wchar *SrcName,bool NewNumbering,wchar *DestName,size_t DestSize); #endif @@ -52,6 +71,15 @@ class CmdExtract bool PrevProcessed; // If previous file was successfully extracted or tested. wchar DestFileName[NM]; bool PasswordCancelled; + + // In Windows it is set to true if at least one symlink with ".." + // in target was extracted. + bool ConvertSymlinkPaths; + + // Last path checked for symlinks. We use it to improve the performance, + // so we do not check recently checked folders again. + std::wstring LastCheckedSymlink; + #if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT) bool Fat32,NotFat32; #endif diff --git a/deps/unrar/filcreat.cpp b/deps/unrar/filcreat.cpp index 620bee813..d58e4f6fe 100644 --- a/deps/unrar/filcreat.cpp +++ b/deps/unrar/filcreat.cpp @@ -1,9 +1,9 @@ #include "rar.hpp" // If NewFile==NULL, we delete created file after user confirmation. -// It is useful we we need to overwrite an existing folder or file, +// It is useful if we need to overwrite an existing folder or file, // but need user confirmation for that. -bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize, +bool FileCreate(CommandData *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize, bool *UserReject,int64 FileSize,RarTime *FileTime,bool WriteOnly) { if (UserReject!=NULL) @@ -44,7 +44,9 @@ bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize, } // Try to truncate the existing file first instead of delete, - // so we preserve existing file permissions such as NTFS permissions. + // so we preserve existing file permissions, such as NTFS permissions, + // also as "Compressed" attribute and hard links. In GUI version we avoid + // deleting an existing file for non-.rar archive formats as well. uint FileMode=WriteOnly ? FMF_WRITE|FMF_SHAREREAD:FMF_UPDATE|FMF_SHAREREAD; if (NewFile!=NULL && NewFile->Create(Name,FileMode)) return true; diff --git a/deps/unrar/filcreat.hpp b/deps/unrar/filcreat.hpp index 44f801d4e..456a4a4a1 100644 --- a/deps/unrar/filcreat.hpp +++ b/deps/unrar/filcreat.hpp @@ -1,7 +1,7 @@ #ifndef _RAR_FILECREATE_ #define _RAR_FILECREATE_ -bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize, +bool FileCreate(CommandData *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize, bool *UserReject,int64 FileSize=INT64NDF, RarTime *FileTime=NULL,bool WriteOnly=false); diff --git a/deps/unrar/file.cpp b/deps/unrar/file.cpp index 5a8099ec5..7bf60fd4e 100644 --- a/deps/unrar/file.cpp +++ b/deps/unrar/file.cpp @@ -7,6 +7,7 @@ File::File() NewFile=false; LastWrite=false; HandleType=FILE_HANDLENORMAL; + LineInput=false; SkipClose=false; ErrorType=FILE_SUCCESS; OpenShared=false; @@ -14,11 +15,11 @@ File::File() AllowExceptions=true; PreserveAtime=false; #ifdef _WIN_ALL - NoSequentialRead=false; CreateMode=FMF_UNDEFINED; #endif ReadErrorMode=FREM_ASK; TruncatedAfterReadError=false; + CurFilePos=0; } @@ -58,7 +59,7 @@ bool File::Open(const wchar *Name,uint Mode) uint ShareMode=(Mode & FMF_OPENEXCLUSIVE) ? 0 : FILE_SHARE_READ; if (OpenShared) ShareMode|=FILE_SHARE_WRITE; - uint Flags=NoSequentialRead ? 0:FILE_FLAG_SEQUENTIAL_SCAN; + uint Flags=FILE_FLAG_SEQUENTIAL_SCAN; FindData FD; if (PreserveAtime) Access|=FILE_WRITE_ATTRIBUTES; // Needed to preserve atime. @@ -379,10 +380,11 @@ int File::Read(void *Data,size_t Size) if (ReadErrorMode==FREM_IGNORE) FilePos=Tell(); - int ReadSize; + int TotalRead=0; while (true) { - ReadSize=DirectRead(Data,Size); + int ReadSize=DirectRead(Data,Size); + if (ReadSize==-1) { ErrorType=FILE_READERROR; @@ -396,6 +398,8 @@ int File::Read(void *Data,size_t Size) size_t SizeToRead=Min(Size-I,512); int ReadCode=DirectRead(Data,SizeToRead); ReadSize+=(ReadCode==-1) ? 512:ReadCode; + if (ReadSize!=-1) + TotalRead+=ReadSize; } } else @@ -415,9 +419,28 @@ int File::Read(void *Data,size_t Size) ErrHandler.ReadError(FileName); } } + TotalRead+=ReadSize; // If ReadSize is -1, TotalRead is also set to -1 here. + + if (HandleType==FILE_HANDLESTD && !LineInput && ReadSize>0 && (uint)ReadSize0) // Can be -1 for error and AllowExceptions disabled. + CurFilePos+=TotalRead; + return TotalRead; // It can return -1 only if AllowExceptions is disabled. } @@ -499,6 +522,36 @@ bool File::RawSeek(int64 Offset,int Method) { if (hFile==FILE_BAD_HANDLE) return true; + if (!IsSeekable()) // To extract archives from stdin with -si. + { + // We tried to dynamically allocate 32 KB buffer here, but it improved + // speed in Windows 10 by mere ~1.5%. + byte Buf[4096]; + if (Method==SEEK_CUR || Method==SEEK_SET && Offset>=CurFilePos) + { + uint64 SkipSize=Method==SEEK_CUR ? Offset:Offset-CurFilePos; + while (SkipSize>0) // Reading to emulate seek forward. + { + int ReadSize=Read(Buf,(size_t)Min(SkipSize,ASIZE(Buf))); + if (ReadSize<=0) + return false; + SkipSize-=ReadSize; + CurFilePos+=ReadSize; + } + return true; + } + // May need it in FileLength() in Archive::UnexpEndArcMsg() when unpacking + // RAR 4.x archives without the end of archive block created with -en. + if (Method==SEEK_END) + { + int ReadSize; + while ((ReadSize=Read(Buf,ASIZE(Buf)))>0) + CurFilePos+=ReadSize; + return true; + } + + return false; // Backward seek on unseekable file. + } if (Offset<0 && Method!=SEEK_SET) { Offset=(Method==SEEK_CUR ? Tell():FileLength())+Offset; @@ -533,6 +586,8 @@ int64 File::Tell() ErrHandler.SeekError(FileName); else return -1; + if (!IsSeekable()) + return CurFilePos; #ifdef _WIN_ALL LONG HighDist=0; uint LowDist=SetFilePointer(hFile,0,&HighDist,FILE_CURRENT); @@ -683,17 +738,40 @@ void File::SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta) } -void File::GetOpenFileTime(RarTime *ft) +#ifdef _UNIX +void File::StatToRarTime(struct stat &st,RarTime *ftm,RarTime *ftc,RarTime *fta) { -#ifdef _WIN_ALL - FILETIME FileTime; - GetFileTime(hFile,NULL,NULL,&FileTime); - ft->SetWinFT(&FileTime); +#ifdef UNIX_TIME_NS +#if defined(_APPLE) + if (ftm!=NULL) ftm->SetUnixNS(st.st_mtimespec.tv_sec*(uint64)1000000000+st.st_mtimespec.tv_nsec); + if (ftc!=NULL) ftc->SetUnixNS(st.st_ctimespec.tv_sec*(uint64)1000000000+st.st_ctimespec.tv_nsec); + if (fta!=NULL) fta->SetUnixNS(st.st_atimespec.tv_sec*(uint64)1000000000+st.st_atimespec.tv_nsec); +#else + if (ftm!=NULL) ftm->SetUnixNS(st.st_mtim.tv_sec*(uint64)1000000000+st.st_mtim.tv_nsec); + if (ftc!=NULL) ftc->SetUnixNS(st.st_ctim.tv_sec*(uint64)1000000000+st.st_ctim.tv_nsec); + if (fta!=NULL) fta->SetUnixNS(st.st_atim.tv_sec*(uint64)1000000000+st.st_atim.tv_nsec); +#endif +#else + if (ftm!=NULL) ftm->SetUnix(st.st_mtime); + if (ftc!=NULL) ftc->SetUnix(st.st_ctime); + if (fta!=NULL) fta->SetUnix(st.st_atime); #endif -#if defined(_UNIX) || defined(_EMX) +} +#endif + + +void File::GetOpenFileTime(RarTime *ftm,RarTime *ftc,RarTime *fta) +{ +#ifdef _WIN_ALL + FILETIME ctime,atime,mtime; + GetFileTime(hFile,&ctime,&atime,&mtime); + if (ftm!=NULL) ftm->SetWinFT(&mtime); + if (ftc!=NULL) ftc->SetWinFT(&ctime); + if (fta!=NULL) fta->SetWinFT(&atime); +#elif defined(_UNIX) struct stat st; fstat(GetFD(),&st); - ft->SetUnix(st.st_mtime); + StatToRarTime(st,ftm,ftc,fta); #endif } diff --git a/deps/unrar/file.hpp b/deps/unrar/file.hpp index 1c436d4ef..5f55de960 100644 --- a/deps/unrar/file.hpp +++ b/deps/unrar/file.hpp @@ -14,8 +14,6 @@ #define FILE_BAD_HANDLE NULL #endif -class RAROptions; - enum FILE_HANDLETYPE {FILE_HANDLENORMAL,FILE_HANDLESTD}; enum FILE_ERRORTYPE {FILE_SUCCESS,FILE_NOTFOUND,FILE_READERROR}; @@ -59,6 +57,16 @@ class File FileHandle hFile; bool LastWrite; FILE_HANDLETYPE HandleType; + + // If we read the user input in console prompts from stdin, we shall + // process the available line immediately, not waiting for rest of data. + // Otherwise apps piping user responses to multiple Ask() prompts can + // hang if no more data is available yet and pipe isn't closed. + // If we read RAR archive or other file data from stdin, we shall collect + // the entire requested block as long as pipe isn't closed, so we get + // complete archive headers, not split between different reads. + bool LineInput; + bool SkipClose; FILE_READ_ERROR_MODE ReadErrorMode; bool NewFile; @@ -70,12 +78,17 @@ class File #endif bool PreserveAtime; bool TruncatedAfterReadError; + + int64 CurFilePos; // Used for forward seeks in stdin files. protected: bool OpenShared; // Set by 'Archive' class. public: wchar FileName[NM]; FILE_ERRORTYPE ErrorType; + + byte *SeekBuf; // To read instead of seek for stdin files. + static const size_t SeekBufSize=0x10000; public: File(); virtual ~File(); @@ -106,11 +119,16 @@ class File void SetOpenFileTime(RarTime *ftm,RarTime *ftc=NULL,RarTime *fta=NULL); void SetCloseFileTime(RarTime *ftm,RarTime *fta=NULL); static void SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta); - void GetOpenFileTime(RarTime *ft); +#ifdef _UNIX + static void StatToRarTime(struct stat &st,RarTime *ftm,RarTime *ftc,RarTime *fta); +#endif + void GetOpenFileTime(RarTime *ftm,RarTime *ftc=NULL,RarTime *fta=NULL); virtual bool IsOpened() {return hFile!=FILE_BAD_HANDLE;} // 'virtual' for MultiFile class. int64 FileLength(); void SetHandleType(FILE_HANDLETYPE Type) {HandleType=Type;} + void SetLineInputMode(bool Mode) {LineInput=Mode;} FILE_HANDLETYPE GetHandleType() {return HandleType;} + bool IsSeekable() {return HandleType!=FILE_HANDLESTD;} bool IsDevice(); static bool RemoveCreated(); FileHandle GetHandle() {return hFile;} @@ -119,9 +137,6 @@ class File int64 Copy(File &Dest,int64 Length=INT64NDF); void SetAllowDelete(bool Allow) {AllowDelete=Allow;} void SetExceptions(bool Allow) {AllowExceptions=Allow;} -#ifdef _WIN_ALL - void RemoveSequentialFlag() {NoSequentialRead=true;} -#endif void SetPreserveAtime(bool Preserve) {PreserveAtime=Preserve;} bool IsTruncatedAfterReadError() {return TruncatedAfterReadError;} #ifdef _UNIX diff --git a/deps/unrar/filefn.cpp b/deps/unrar/filefn.cpp index bab7c7384..aaef305b8 100644 --- a/deps/unrar/filefn.cpp +++ b/deps/unrar/filefn.cpp @@ -320,7 +320,6 @@ bool SetFileAttr(const wchar *Name,uint Attr) } -#if 0 wchar *MkTemp(wchar *Name,size_t MaxSize) { size_t Length=wcslen(Name); @@ -354,7 +353,6 @@ wchar *MkTemp(wchar *Name,size_t MaxSize) } return Name; } -#endif #if !defined(SFX_MODULE) @@ -397,7 +395,11 @@ void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size, { #ifndef SILENT if ((Flags & CALCFSUM_SHOWPROGRESS)!=0) - uiExtractProgress(TotalRead,FileLength,TotalRead,FileLength); + { + // Update only the current file progress in WinRAR, set the total to 0 + // to keep it as is. It looks better for WinRAR. + uiExtractProgress(TotalRead,FileLength,0,0); + } else { if ((Flags & CALCFSUM_SHOWPERCENT)!=0) @@ -517,6 +519,18 @@ bool SetFileCompression(const wchar *Name,bool State) CloseHandle(hFile); return RetCode!=0; } + + +void ResetFileCache(const wchar *Name) +{ + // To reset file cache in Windows it is enough to open it with + // FILE_FLAG_NO_BUFFERING and then close it. + HANDLE hSrc=CreateFile(Name,GENERIC_READ, + FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL,OPEN_EXISTING,FILE_FLAG_NO_BUFFERING,NULL); + if (hSrc!=INVALID_HANDLE_VALUE) + CloseHandle(hSrc); +} #endif diff --git a/deps/unrar/filefn.hpp b/deps/unrar/filefn.hpp index 78735fee9..53d86653f 100644 --- a/deps/unrar/filefn.hpp +++ b/deps/unrar/filefn.hpp @@ -27,9 +27,7 @@ bool IsDeleteAllowed(uint FileAttr); void PrepareToDelete(const wchar *Name); uint GetFileAttr(const wchar *Name); bool SetFileAttr(const wchar *Name,uint Attr); -#if 0 wchar* MkTemp(wchar *Name,size_t MaxSize); -#endif enum CALCFSUM_FLAGS {CALCFSUM_SHOWTEXT=1,CALCFSUM_SHOWPERCENT=2,CALCFSUM_SHOWPROGRESS=4,CALCFSUM_CURPOS=8}; @@ -41,6 +39,7 @@ bool DelDir(const wchar *Name); #if defined(_WIN_ALL) && !defined(SFX_MODULE) bool SetFileCompression(const wchar *Name,bool State); +void ResetFileCache(const wchar *Name); #endif diff --git a/deps/unrar/find.cpp b/deps/unrar/find.cpp index b22f82d8f..c9f2c5768 100644 --- a/deps/unrar/find.cpp +++ b/deps/unrar/find.cpp @@ -117,7 +117,7 @@ bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink) if (hFind==INVALID_HANDLE_VALUE) return false; FindClose(hFind); -#else +#elif defined(_UNIX) char FindMaskA[NM]; WideToChar(FindMask,FindMaskA,ASIZE(FindMaskA)); @@ -143,15 +143,7 @@ bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink) fd->FileAttr=st.st_mode; fd->Size=st.st_size; -#ifdef UNIX_TIME_NS - fd->mtime.SetUnixNS(st.st_mtim.tv_sec*(uint64)1000000000+st.st_mtim.tv_nsec); - fd->atime.SetUnixNS(st.st_atim.tv_sec*(uint64)1000000000+st.st_atim.tv_nsec); - fd->ctime.SetUnixNS(st.st_ctim.tv_sec*(uint64)1000000000+st.st_ctim.tv_nsec); -#else - fd->mtime.SetUnix(st.st_mtime); - fd->atime.SetUnix(st.st_atime); - fd->ctime.SetUnix(st.st_ctime); -#endif + File::StatToRarTime(st,&fd->mtime,&fd->ctime,&fd->atime); wcsncpyz(fd->Name,FindMask,ASIZE(fd->Name)); #endif diff --git a/deps/unrar/getbits.cpp b/deps/unrar/getbits.cpp index e4db2695f..8805f2787 100644 --- a/deps/unrar/getbits.cpp +++ b/deps/unrar/getbits.cpp @@ -5,7 +5,7 @@ BitInput::BitInput(bool AllocBuffer) ExternalBuffer=false; if (AllocBuffer) { - // getbits32 attempts to read data from InAddr, ... InAddr+3 positions. + // getbits*() attempt to read data from InAddr, ... InAddr+3 positions. // So let's allocate 3 additional bytes for situation, when we need to // read only 1 byte from the last position of buffer and avoid a crash // from access to next 3 bytes, which contents we do not need. diff --git a/deps/unrar/getbits.hpp b/deps/unrar/getbits.hpp index 7fbdfdf30..00acbea94 100644 --- a/deps/unrar/getbits.hpp +++ b/deps/unrar/getbits.hpp @@ -4,7 +4,7 @@ class BitInput { public: - enum BufferSize {MAX_SIZE=0x50000}; // Size of input buffer. + enum BufferSize {MAX_SIZE=0x8000}; // Size of input buffer. int InAddr; // Curent byte position in the buffer. int InBit; // Current bit position in the current byte. @@ -28,26 +28,38 @@ class BitInput InAddr+=Bits>>3; InBit=Bits&7; } - + // Return 16 bits from current position in the buffer. // Bit at (InAddr,InBit) has the highest position in returning data. uint getbits() { +#if defined(LITTLE_ENDIAN) && defined(ALLOW_MISALIGNED) + uint32 BitField=*(uint32*)(InBuf+InAddr); + BitField=ByteSwap32(BitField); + BitField >>= (16-InBit); +#else uint BitField=(uint)InBuf[InAddr] << 16; BitField|=(uint)InBuf[InAddr+1] << 8; BitField|=(uint)InBuf[InAddr+2]; BitField >>= (8-InBit); +#endif return BitField & 0xffff; } + // Return 32 bits from current position in the buffer. // Bit at (InAddr,InBit) has the highest position in returning data. uint getbits32() { +#if defined(LITTLE_ENDIAN) && defined(ALLOW_MISALIGNED) + uint32 BitField=*(uint32*)(InBuf+InAddr); + BitField=ByteSwap32(BitField); +#else uint BitField=(uint)InBuf[InAddr] << 24; BitField|=(uint)InBuf[InAddr+1] << 16; BitField|=(uint)InBuf[InAddr+2] << 8; BitField|=(uint)InBuf[InAddr+3]; +#endif BitField <<= InBit; BitField|=(uint)InBuf[InAddr+4] >> (8-InBit); return BitField & 0xffffffff; diff --git a/deps/unrar/global.cpp b/deps/unrar/global.cpp index 3975813a9..771f00016 100644 --- a/deps/unrar/global.cpp +++ b/deps/unrar/global.cpp @@ -1,6 +1,6 @@ #define INCLUDEGLOBAL -#if defined(__BORLANDC__) || defined(_MSC_VER) +#ifdef _MSC_VER #pragma hdrstop #endif diff --git a/deps/unrar/hardlinks.cpp b/deps/unrar/hardlinks.cpp index 40cc0aa49..171b5fa08 100644 --- a/deps/unrar/hardlinks.cpp +++ b/deps/unrar/hardlinks.cpp @@ -1,7 +1,5 @@ bool ExtractHardlink(CommandData *Cmd,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize) { - SlashToNative(NameExisting,NameExisting,NameExistingSize); // Not needed for RAR 5.1+ archives. - if (!FileExist(NameExisting)) { uiMsg(UIERROR_HLINKCREATE,NameNew); diff --git a/deps/unrar/hash.cpp b/deps/unrar/hash.cpp index a4559e05c..106cc6083 100644 --- a/deps/unrar/hash.cpp +++ b/deps/unrar/hash.cpp @@ -26,7 +26,7 @@ void HashValue::Init(HASH_TYPE Type) } -bool HashValue::operator == (const HashValue &cmp) +bool HashValue::operator == (const HashValue &cmp) const { if (Type==HASH_NONE || cmp.Type==HASH_NONE) return true; diff --git a/deps/unrar/hash.hpp b/deps/unrar/hash.hpp index b7d879f66..6315680e7 100644 --- a/deps/unrar/hash.hpp +++ b/deps/unrar/hash.hpp @@ -6,8 +6,14 @@ enum HASH_TYPE {HASH_NONE,HASH_RAR14,HASH_CRC32,HASH_BLAKE2}; struct HashValue { void Init(HASH_TYPE Type); - bool operator == (const HashValue &cmp); - bool operator != (const HashValue &cmp) {return !(*this==cmp);} + + // Use the const member, so types on both sides of "==" match. + // Otherwise clang -std=c++20 issues "ambiguity is between a regular call + // to this operator and a call with the argument order reversed" warning. + bool operator == (const HashValue &cmp) const; + + // Not actually used now. Const member for same reason as operator == above. + bool operator != (const HashValue &cmp) const {return !(*this==cmp);} HASH_TYPE Type; union diff --git a/deps/unrar/headers.cpp b/deps/unrar/headers.cpp index b042dc393..b441376c5 100644 --- a/deps/unrar/headers.cpp +++ b/deps/unrar/headers.cpp @@ -49,13 +49,5 @@ FileHeader& FileHeader::operator = (FileHeader &hd) void MainHeader::Reset() { - HighPosAV=0; - PosAV=0; - CommentInHeader=false; - PackComment=false; - Locator=false; - QOpenOffset=0; - QOpenMaxSize=0; - RROffset=0; - RRMaxSize=0; + *this={}; } diff --git a/deps/unrar/headers.hpp b/deps/unrar/headers.hpp index 6af453a9d..0941220f5 100644 --- a/deps/unrar/headers.hpp +++ b/deps/unrar/headers.hpp @@ -6,7 +6,7 @@ #define SIZEOF_MAINHEAD3 13 // Size of RAR 4.x main archive header. #define SIZEOF_FILEHEAD14 21 // Size of RAR 1.4 file header. #define SIZEOF_FILEHEAD3 32 // Size of RAR 3.0 file header. -#define SIZEOF_SHORTBLOCKHEAD 7 +#define SIZEOF_SHORTBLOCKHEAD 7 // Smallest RAR 4.x block size. #define SIZEOF_LONGBLOCKHEAD 11 #define SIZEOF_SUBBLOCKHEAD 14 #define SIZEOF_COMMHEAD 13 @@ -162,12 +162,16 @@ struct MainHeader:BaseBlock ushort HighPosAV; uint PosAV; bool CommentInHeader; - bool PackComment; // For RAR 1.4 archive format only. + bool PackComment; // For RAR 1.4 archive format only. bool Locator; - uint64 QOpenOffset; // Offset of quick list record. - uint64 QOpenMaxSize; // Maximum size of QOpen offset in locator extra field. - uint64 RROffset; // Offset of recovery record. - uint64 RRMaxSize; // Maximum size of RR offset in locator extra field. + uint64 QOpenOffset; // Offset of quick list record. + uint64 QOpenMaxSize; // Maximum size of QOpen offset in locator extra field. + uint64 RROffset; // Offset of recovery record. + uint64 RRMaxSize; // Maximum size of RR offset in locator extra field. + size_t MetaNameMaxSize; // Maximum size of archive name in metadata extra field. + std::wstring OrigName; // Original archive name. + RarTime OrigTime; // Original archive time. + void Reset(); }; @@ -230,7 +234,7 @@ struct FileHeader:BlockHeader bool LargeFile; // 'true' for HEAD_SERVICE block, which is a child of preceding file block. - // RAR 4.x uses 'solid' flag to indicate child subheader blocks in archives. + // RAR 4.x uses 'solid' flag to indicate children subheader blocks in archives. bool SubBlock; HOST_SYSTEM_TYPE HSType; diff --git a/deps/unrar/headers5.hpp b/deps/unrar/headers5.hpp index 9ea8d979a..50f5955d1 100644 --- a/deps/unrar/headers5.hpp +++ b/deps/unrar/headers5.hpp @@ -59,11 +59,18 @@ // Main header extra field values. #define MHEXTRA_LOCATOR 0x01 // Position of quick list and other blocks. +#define MHEXTRA_METADATA 0x02 // Archive metadata. // Flags for MHEXTRA_LOCATOR. #define MHEXTRA_LOCATOR_QLIST 0x01 // Quick open offset is present. #define MHEXTRA_LOCATOR_RR 0x02 // Recovery record offset is present. +// Flags for MHEXTRA_METADATA. +#define MHEXTRA_METADATA_NAME 0x01 // Archive name is present. +#define MHEXTRA_METADATA_CTIME 0x02 // Archive creation time is present. +#define MHEXTRA_METADATA_UNIXTIME 0x04 // Use Unix nanosecond time format. +#define MHEXTRA_METADATA_UNIX_NS 0x08 // Unix format with nanosecond precision. + // File and service header extra field values. #define FHEXTRA_CRYPT 0x01 // Encryption parameters. #define FHEXTRA_HASH 0x02 // File hash. diff --git a/deps/unrar/isnt.cpp b/deps/unrar/isnt.cpp index 6fadec049..31da8c158 100644 --- a/deps/unrar/isnt.cpp +++ b/deps/unrar/isnt.cpp @@ -13,6 +13,7 @@ DWORD WinNT() dwPlatformId=WinVer.dwPlatformId; dwMajorVersion=WinVer.dwMajorVersion; dwMinorVersion=WinVer.dwMinorVersion; + } DWORD Result=0; if (dwPlatformId==VER_PLATFORM_WIN32_NT) @@ -21,4 +22,102 @@ DWORD WinNT() return Result; } -#endif + + +// Replace it with documented Windows 11 check when available. +#include +#include +#pragma comment(lib, "wbemuuid.lib") + +static bool WMI_IsWindows10() +{ + IWbemLocator *pLoc = NULL; + + HRESULT hres = CoCreateInstance(CLSID_WbemLocator,0,CLSCTX_INPROC_SERVER, + IID_IWbemLocator,(LPVOID *)&pLoc); + + if (FAILED(hres)) + return false; + + IWbemServices *pSvc = NULL; + + BSTR bstr_root_cimv2 = SysAllocString(L"ROOT\\CIMV2"); + + hres = pLoc->ConnectServer(bstr_root_cimv2,NULL,NULL,NULL,0,0,0,&pSvc); + + if (FAILED(hres)) + { + pLoc->Release(); + return false; + } + + hres = CoSetProxyBlanket(pSvc,RPC_C_AUTHN_WINNT,RPC_C_AUTHZ_NONE,NULL, + RPC_C_AUTHN_LEVEL_CALL,RPC_C_IMP_LEVEL_IMPERSONATE,NULL,EOAC_NONE); + + if (FAILED(hres)) + { + pSvc->Release(); + pLoc->Release(); + return false; + } + + IEnumWbemClassObject *pEnumerator = NULL; + + BSTR bstr_wql = SysAllocString(L"WQL"); + BSTR bstr_sql = SysAllocString(L"SELECT * FROM Win32_OperatingSystem"); + + hres = pSvc->ExecQuery(bstr_wql, bstr_sql, + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator); + + if (FAILED(hres)) + { + pSvc->Release(); + pLoc->Release(); + return false; + } + + IWbemClassObject *pclsObj = NULL; + ULONG uReturn = 0; + + bool Win10=false; + while (pEnumerator!=NULL) + { + HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); + + if (uReturn==0) + break; + + VARIANT vtProp; + + hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0); + Win10|=wcsstr(vtProp.bstrVal,L"Windows 10")!=NULL; + VariantClear(&vtProp); + + pclsObj->Release(); + } + + pSvc->Release(); + pLoc->Release(); + pEnumerator->Release(); + + return Win10; +} + + +// Replace it with actual check when available. +bool IsWindows11OrGreater() +{ + static bool IsSet=false,IsWin11=false; + if (!IsSet) + { + OSVERSIONINFO WinVer; + WinVer.dwOSVersionInfoSize=sizeof(WinVer); + GetVersionEx(&WinVer); + IsWin11=WinVer.dwMajorVersion>10 || + WinVer.dwMajorVersion==10 && WinVer.dwBuildNumber >= 22000 && !WMI_IsWindows10(); + IsSet=true; + } + return IsWin11; +} + +#endif // _WIN_ALL diff --git a/deps/unrar/isnt.hpp b/deps/unrar/isnt.hpp index 85790da46..fed0b5173 100644 --- a/deps/unrar/isnt.hpp +++ b/deps/unrar/isnt.hpp @@ -10,4 +10,7 @@ enum WINNT_VERSION { DWORD WinNT(); +// Replace it with actual check when available. +bool IsWindows11OrGreater(); + #endif diff --git a/deps/unrar/list.cpp b/deps/unrar/list.cpp index 476fd3c65..e4444e13a 100644 --- a/deps/unrar/list.cpp +++ b/deps/unrar/list.cpp @@ -1,6 +1,6 @@ #include "rar.hpp" -static void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare); +static void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare,bool DisableNames); static void ListSymLink(Archive &Arc); static void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize); static void ListOldSubHeader(Archive &Arc); @@ -22,9 +22,6 @@ void ListArchive(CommandData *Cmd) Cmd->Password.Clean(); // Clean user entered password before processing next archive. Archive Arc(Cmd); -#ifdef _WIN_ALL - Arc.RemoveSequentialFlag(); -#endif if (!Arc.WOpen(ArcName)) continue; bool FileMatched=true; @@ -39,6 +36,7 @@ void ListArchive(CommandData *Cmd) { Arc.ViewComment(); mprintf(L"\n%s: %s",St(MListArchive),Arc.FileName); + mprintf(L"\n%s: ",St(MListDetails)); uint SetCount=0; const wchar *Fmt=Arc.Format==RARFMT14 ? L"RAR 1.4":(Arc.Format==RARFMT15 ? L"RAR 4":L"RAR 5"); @@ -64,6 +62,16 @@ void ListArchive(CommandData *Cmd) mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListLock)); if (Arc.Encrypted) mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListEncHead)); + + if (!Arc.MainHead.OrigName.empty()) + mprintf(L"\n%s: %s",St(MOrigName),Arc.MainHead.OrigName.c_str()); + if (Arc.MainHead.OrigTime.IsSet()) + { + wchar DateStr[50]; + Arc.MainHead.OrigTime.GetText(DateStr,ASIZE(DateStr),Technical); + mprintf(L"\n%s: %s",St(MOriginalTime),DateStr); + } + mprintf(L"\n"); } @@ -95,7 +103,7 @@ void ListArchive(CommandData *Cmd) FileMatched=Cmd->IsProcessFile(Arc.FileHead,NULL,MATCH_WILDSUBPATH,0,NULL,0)!=0; if (FileMatched) { - ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare); + ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare,Cmd->DisableNames); if (!Arc.FileHead.SplitBefore) { TotalUnpSize+=Arc.FileHead.UnpSize; @@ -108,7 +116,7 @@ void ListArchive(CommandData *Cmd) if (FileMatched && !Bare) { if (Technical && ShowService) - ListFileHeader(Arc,Arc.SubHead,TitleShown,Verbose,true,false); + ListFileHeader(Arc,Arc.SubHead,TitleShown,Verbose,true,false,Cmd->DisableNames); } break; } @@ -188,31 +196,37 @@ enum LISTCOL_TYPE { }; -void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare) +void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare,bool DisableNames) { - wchar *Name=hd.FileName; - RARFORMAT Format=Arc.Format; - - if (Bare) - { - mprintf(L"%s\n",Name); - return; - } - - if (!TitleShown && !Technical) + if (!TitleShown && !Technical && !Bare) { if (Verbose) { mprintf(L"\n%ls",St(MListTitleV)); - mprintf(L"\n----------- --------- -------- ----- ---------- ----- -------- ----"); + if (!DisableNames) + mprintf(L"\n----------- --------- -------- ----- ---------- ----- -------- ----"); } else { mprintf(L"\n%ls",St(MListTitleL)); - mprintf(L"\n----------- --------- ---------- ----- ----"); + if (!DisableNames) + mprintf(L"\n----------- --------- ---------- ----- ----"); } + // Must be set even in DisableNames mode to suppress "0 files" output + // unless no files are matched. TitleShown=true; } + if (DisableNames) + return; + + wchar *Name=hd.FileName; + RARFORMAT Format=Arc.Format; + + if (Bare) + { + mprintf(L"%s\n",Name); + return; + } wchar UnpSizeText[30],PackSizeText[30]; if (hd.UnpSize==INT64NDF) @@ -304,17 +318,21 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo mprintf(L"\n%12ls: %ls",St(MListPacked),PackSizeText); mprintf(L"\n%12ls: %ls",St(MListRatio),RatioStr); } + bool WinTitles=false; +#ifdef _WIN_ALL + WinTitles=true; +#endif if (hd.mtime.IsSet()) - mprintf(L"\n%12ls: %ls",St(MListMtime),DateStr); + mprintf(L"\n%12ls: %ls",St(WinTitles ? MListModified:MListMtime),DateStr); if (hd.ctime.IsSet()) { hd.ctime.GetText(DateStr,ASIZE(DateStr),true); - mprintf(L"\n%12ls: %ls",St(MListCtime),DateStr); + mprintf(L"\n%12ls: %ls",St(WinTitles ? MListCreated:MListCtime),DateStr); } if (hd.atime.IsSet()) { hd.atime.GetText(DateStr,ASIZE(DateStr),true); - mprintf(L"\n%12ls: %ls",St(MListAtime),DateStr); + mprintf(L"\n%12ls: %ls",St(WinTitles ? MListAccessed:MListAtime),DateStr); } mprintf(L"\n%12ls: %ls",St(MListAttr),AttrStr); if (hd.FileHash.Type==HASH_CRC32) @@ -370,15 +388,16 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo { mprintf(L"\n%12ls: ",L"Unix owner"); if (*hd.UnixOwnerName!=0) - mprintf(L"%ls:",GetWide(hd.UnixOwnerName)); + mprintf(L"%ls",GetWide(hd.UnixOwnerName)); + else + if (hd.UnixOwnerNumeric) + mprintf(L"#%d",hd.UnixOwnerID); + mprintf(L":"); if (*hd.UnixGroupName!=0) mprintf(L"%ls",GetWide(hd.UnixGroupName)); - if ((*hd.UnixOwnerName!=0 || *hd.UnixGroupName!=0) && (hd.UnixOwnerNumeric || hd.UnixGroupNumeric)) - mprintf(L" "); - if (hd.UnixOwnerNumeric) - mprintf(L"#%d:",hd.UnixOwnerID); - if (hd.UnixGroupNumeric) - mprintf(L"#%d:",hd.UnixGroupID); + else + if (hd.UnixGroupNumeric) + mprintf(L"#%d",hd.UnixGroupID); } mprintf(L"\n"); diff --git a/deps/unrar/loclang.hpp b/deps/unrar/loclang.hpp index a1cd544a3..8c7c08814 100644 --- a/deps/unrar/loclang.hpp +++ b/deps/unrar/loclang.hpp @@ -28,6 +28,7 @@ #define MRARTitle1 L"\nUsage: rar - - " #define MUNRARTitle1 L"\nUsage: unrar - - " #define MRARTitle2 L"\n <@listfiles...> " +#define MFwrSlTitle2 L"\n <@listfiles...> " #define MCHelpCmd L"\n\n" #define MCHelpCmdA L"\n a Add files to archive" #define MCHelpCmdC L"\n c Add archive comment" @@ -58,6 +59,7 @@ #define MCHelpSwAD L"\n ad[1,2] Alternate destination path" #define MCHelpSwAG L"\n ag[format] Generate archive name using the current date" #define MCHelpSwAI L"\n ai Ignore file attributes" +#define MCHelpSwAM L"\n am[s,r] Archive name and time [save, restore]" #define MCHelpSwAO L"\n ao Add files with Archive attribute set" #define MCHelpSwAP L"\n ap Set path inside archive" #define MCHelpSwAS L"\n as Synchronize archive contents" @@ -72,11 +74,11 @@ #define MCHelpSwDW L"\n dw Wipe files after archiving" #define MCHelpSwEa L"\n e[+] Set file exclude and include attributes" #define MCHelpSwED L"\n ed Do not add empty directories" -#define MCHelpSwEN L"\n en Do not put 'end of archive' block" #define MCHelpSwEP L"\n ep Exclude paths from names" #define MCHelpSwEP1 L"\n ep1 Exclude base directory from names" #define MCHelpSwEP2 L"\n ep2 Expand paths to full" #define MCHelpSwEP3 L"\n ep3 Expand paths to full including the drive letter" +#define MCHelpSwEP4 L"\n ep4 Exclude the path prefix from names" #define MCHelpSwF L"\n f Freshen files" #define MCHelpSwHP L"\n hp[password] Encrypt both file data and headers" #define MCHelpSwHT L"\n ht[b|c] Select hash type [BLAKE2,CRC32] for file checksum" @@ -95,6 +97,7 @@ #define MCHelpSwMA L"\n ma[4|5] Specify a version of archiving format" #define MCHelpSwMC L"\n mc Set advanced compression parameters" #define MCHelpSwMD L"\n md[k,m,g] Dictionary size in KB, MB or GB" +#define MCHelpSwME L"\n me[par] Set encryption parameters" #define MCHelpSwMS L"\n ms[ext;ext] Specify file types to store" #define MCHelpSwMT L"\n mt Set the number of threads" #define MCHelpSwN L"\n n Additionally filter included files" @@ -106,11 +109,11 @@ #define MCHelpSwOI L"\n oi[0-4][:min] Save identical files as references" #define MCHelpSwOL L"\n ol[a] Process symbolic links as the link [absolute paths]" #define MCHelpSwONI L"\n oni Allow potentially incompatible names" +#define MCHelpSwOP L"\n op Set the output path for extracted files" #define MCHelpSwOR L"\n or Rename files automatically" #define MCHelpSwOS L"\n os Save NTFS streams" #define MCHelpSwOW L"\n ow Save or restore file owner and group" #define MCHelpSwP L"\n p[password] Set password" -#define MCHelpSwPm L"\n p- Do not query password" #define MCHelpSwQO L"\n qo[-|+] Add quick open information [none|force]" #define MCHelpSwR L"\n r Recurse subdirectories" #define MCHelpSwRm L"\n r- Disable recursion" @@ -272,6 +275,9 @@ #define MListMtime L"mtime" #define MListCtime L"ctime" #define MListAtime L"atime" +#define MListModified L"Modified" +#define MListCreated L"Created" +#define MListAccessed L"Accessed" #define MListAttr L"Attributes" #define MListFlags L"Flags" #define MListCompInfo L"Compression" @@ -385,3 +391,11 @@ #define MErrReadTrunc L"\n%s is archived incompletely because of read error.\n" #define MErrReadCount L"\n%u files are archived incompletely because of read errors." #define MDirNameExists L"\nDirectory with such name already exists" +#define MStdinNoInput L"\nKeyboard input is not allowed when reading data from stdin" +#define MTruncPsw L"\nPassword exceeds the maximum allowed length of %u characters and will be truncated." +#define MAdjustValue L"\nAdjusting %s value to %s." +#define MOpFailed L"\nOperation failed" +#define MSkipEncArc L"\nSkipping the encrypted archive %s" +#define MOrigName L"Original name" +#define MOriginalTime L"Original time" +#define MFileRenamed L"\n%s is renamed to %s" diff --git a/deps/unrar/makefile b/deps/unrar/makefile index 214f87ef3..55af49bef 100644 --- a/deps/unrar/makefile +++ b/deps/unrar/makefile @@ -123,10 +123,10 @@ UNRAR_OBJ=filestr.o recvol.o rs.o scantree.o qopen.o LIB_OBJ=filestr.o scantree.o dll.o qopen.o OBJECTS=rar.o strlist.o strfn.o pathfn.o smallfn.o global.o file.o filefn.o filcreat.o \ - archive.o arcread.o unicode.o system.o isnt.o crypt.o crc.o rawread.o encname.o \ + archive.o arcread.o unicode.o system.o crypt.o crc.o rawread.o encname.o \ resource.o match.o timefn.o rdwrfn.o consio.o options.o errhnd.o rarvm.o secpassword.o \ rijndael.o getbits.o sha1.o sha256.o blake2s.o hash.o extinfo.o extract.o volume.o \ - list.o find.o unpack.o headers.o threadpool.o rs16.o cmddata.o ui.o + list.o find.o unpack.o headers.o threadpool.o rs16.o cmddata.o ui.o .cpp.o: $(COMPILE) -D$(WHAT) -c $< @@ -142,20 +142,23 @@ clean: @rm -f $(OBJECTS) $(UNRAR_OBJ) $(LIB_OBJ) @rm -f unrar libunrar.* -unrar: clean $(OBJECTS) $(UNRAR_OBJ) +# We removed 'clean' from dependencies, because it prevented parallel +# 'make -Jn' builds. + +unrar: $(OBJECTS) $(UNRAR_OBJ) @rm -f unrar $(LINK) -o unrar $(LDFLAGS) $(OBJECTS) $(UNRAR_OBJ) $(LIBS) $(STRIP) unrar sfx: WHAT=SFX_MODULE -sfx: clean $(OBJECTS) +sfx: $(OBJECTS) @rm -f default.sfx $(LINK) -o default.sfx $(LDFLAGS) $(OBJECTS) $(STRIP) default.sfx lib: WHAT=RARDLL lib: CXXFLAGS+=$(LIBFLAGS) -lib: clean $(OBJECTS) $(LIB_OBJ) +lib: $(OBJECTS) $(LIB_OBJ) @rm -f libunrar.* $(LINK) -shared -o libunrar.so $(LDFLAGS) $(OBJECTS) $(LIB_OBJ) $(AR) rcs libunrar.a $(OBJECTS) $(LIB_OBJ) diff --git a/deps/unrar/model.cpp b/deps/unrar/model.cpp index 3aa29b245..e4f9e3c53 100644 --- a/deps/unrar/model.cpp +++ b/deps/unrar/model.cpp @@ -532,13 +532,15 @@ inline bool RARPPM_CONTEXT::decodeSymbol2(ModelPPM *Model) Model->Coder.SubRange.LowCount=HiCnt; Model->Coder.SubRange.HighCount=Model->Coder.SubRange.scale; i=NumStats-Model->NumMasked; - pps--; + + // 2022.12.02: we removed pps-- here and changed the code below to avoid + // "array subscript -1 is outside array bounds" warning in some compilers. do { - pps++; if (pps>=ps+ASIZE(ps)) // Extra safety check. return false; Model->CharMask[(*pps)->Symbol]=Model->EscCount; + pps++; } while ( --i ); psee2c->Summ += Model->Coder.SubRange.scale; Model->NumMasked = NumStats; @@ -566,17 +568,14 @@ void ModelPPM::CleanUp() } -bool ModelPPM::DecodeInit(Unpack *UnpackRead,int &EscChar,byte *hcppm) +bool ModelPPM::DecodeInit(Unpack *UnpackRead,int &EscChar) { int MaxOrder=UnpackRead->GetChar(); bool Reset=(MaxOrder & 0x20)!=0; int MaxMB; if (Reset) - { MaxMB=UnpackRead->GetChar(); - if (MaxMB>128) return(false); - } else if (SubAlloc.GetAllocatedMemory()==0) return(false); @@ -593,7 +592,6 @@ bool ModelPPM::DecodeInit(Unpack *UnpackRead,int &EscChar,byte *hcppm) SubAlloc.StopSubAllocator(); return(false); } - SubAlloc.SetHeapStartFixed(hcppm); SubAlloc.StartSubAllocator(MaxMB+1); StartModelRare(MaxOrder); } diff --git a/deps/unrar/model.hpp b/deps/unrar/model.hpp index c7444de33..52abc89b3 100644 --- a/deps/unrar/model.hpp +++ b/deps/unrar/model.hpp @@ -115,7 +115,7 @@ class ModelPPM : RARPPM_DEF public: ModelPPM(); void CleanUp(); // reset PPM variables after data error - bool DecodeInit(Unpack *UnpackRead,int &EscChar,byte *hcppm); + bool DecodeInit(Unpack *UnpackRead,int &EscChar); int DecodeChar(); }; diff --git a/deps/unrar/options.cpp b/deps/unrar/options.cpp index 40323be82..22ae27ce2 100644 --- a/deps/unrar/options.cpp +++ b/deps/unrar/options.cpp @@ -6,14 +6,6 @@ RAROptions::RAROptions() } -RAROptions::~RAROptions() -{ - // It is important for security reasons, so we do not have the unnecessary - // password data left in memory. - memset(this,0,sizeof(RAROptions)); -} - - void RAROptions::Init() { memset(this,0,sizeof(RAROptions)); diff --git a/deps/unrar/options.hpp b/deps/unrar/options.hpp index 993b21963..e249eb599 100644 --- a/deps/unrar/options.hpp +++ b/deps/unrar/options.hpp @@ -45,6 +45,12 @@ enum OVERWRITE_MODE OVERWRITE_FORCE_ASK }; +enum ARC_METADATA +{ + ARCMETA_NONE=0, + ARCMETA_SAVE, // -ams + ARCMETA_RESTORE // -amr +}; enum QOPEN_MODE { QOPEN_NONE, QOPEN_AUTO, QOPEN_ALWAYS }; @@ -84,11 +90,12 @@ struct FilterMode #define MAX_GENERATE_MASK 128 +// Here we store simple data types, which we can clear and move all together +// quickly. Rest of data types goes to CommandData. class RAROptions { public: RAROptions(); - ~RAROptions(); void Init(); uint ExclFileAttr; @@ -116,9 +123,10 @@ class RAROptions RAR_CHARSET ErrlogCharset; RAR_CHARSET RedirectCharset; - wchar ArcPath[NM]; - SecPassword Password; + wchar ArcPath[NM]; // For -ap. + wchar ExclArcPath[NM]; // For -ep4 switch. bool EncryptHeaders; + bool SkipEncrypted; bool ManualPassword; // Password entered manually during operation, might need to clean for next archive. @@ -130,6 +138,7 @@ class RAROptions HASH_TYPE HashType; int Recovery; int RecVolNumber; + ARC_METADATA ArcMetadata; bool DisablePercentage; bool DisableCopyright; bool DisableDone; @@ -145,7 +154,6 @@ class RAROptions PATH_EXCL_MODE ExclPath; RECURSE_MODE Recurse; int64 VolSize; - Array NextVolSizes; uint CurVolNum; bool AllYes; bool VerboseOutput; // -iv, display verbose output, used only in "WinRAR t" now. @@ -195,7 +203,11 @@ class RAROptions EXTTIME_MODE xctime; EXTTIME_MODE xatime; bool PreserveAtime; - wchar CompressStdin[NM]; + + // Read data from stdin and store in archive under a name specified here + // when archiving. Read an archive from stdin if any non-empty string + // is specified here when extracting. + wchar UseStdin[NM]; uint Threads; // We use it to init hash even if RAR_SMP is not defined. diff --git a/deps/unrar/os.hpp b/deps/unrar/os.hpp index dadec759a..8b2cdc42d 100644 --- a/deps/unrar/os.hpp +++ b/deps/unrar/os.hpp @@ -13,6 +13,8 @@ #endif #include +#include +#include #if defined(_WIN_ALL) || defined(_EMX) @@ -36,12 +38,23 @@ // re-definition warnings in third party projects. #ifndef UNICODE #define UNICODE +#define _UNICODE // Set _T() macro to convert from narrow to wide strings. #endif -#undef WINVER + +#ifdef _WIN32_WINNT #undef _WIN32_WINNT -#define WINVER 0x0501 -#define _WIN32_WINNT 0x0501 +#endif + +#if 0 +// 2021.09.05: Allow newer Vista+ APIs like IFileOpenDialog for WinRAR, +// but still keep SFX modules XP compatible. +#define WINVER _WIN32_WINNT_VISTA +#define _WIN32_WINNT _WIN32_WINNT_VISTA +#else +#define WINVER _WIN32_WINNT_WINXP +#define _WIN32_WINNT _WIN32_WINNT_WINXP +#endif #if !defined(ZIPSFX) #define RAR_SMP @@ -73,14 +86,14 @@ #include #endif #ifdef _MSC_VER - #if _MSC_VER<1500 - #define for if (0) ; else for - #endif #include #include - #define USE_SSE - #define SSE_ALIGNMENT 16 + // Use SSE only for x86/x64, not ARM Windows. + #if defined(_M_IX86) || defined(_M_X64) + #define USE_SSE + #define SSE_ALIGNMENT 16 + #endif #else #include #endif // _MSC_VER @@ -96,7 +109,6 @@ #include #include - #define SAVE_LINKS #define ENABLE_ACCESS @@ -212,7 +224,8 @@ #endif #endif -#if _POSIX_C_SOURCE >= 200809L +// Unlike Apple x64, utimensat shall be available in all Apple M1 systems. +#if _POSIX_C_SOURCE >= 200809L || defined(__APPLE__) && defined(__arm64__) #define UNIX_TIME_NS // Nanosecond time precision in Unix. #endif diff --git a/deps/unrar/pathfn.cpp b/deps/unrar/pathfn.cpp index 41594bf95..50b6b29da 100644 --- a/deps/unrar/pathfn.cpp +++ b/deps/unrar/pathfn.cpp @@ -5,7 +5,7 @@ wchar* PointToName(const wchar *Path) for (int I=(int)wcslen(Path)-1;I>=0;I--) if (IsPathDiv(Path[I])) return (wchar*)&Path[I+1]; - return (wchar*)((*Path && IsDriveDiv(Path[1])) ? Path+2:Path); + return (wchar*)((*Path!=0 && IsDriveDiv(Path[1])) ? Path+2:Path); } @@ -31,11 +31,17 @@ wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath,size_t DestSize) const wchar *s=DestPtr; if (s[0]!=0 && IsDriveDiv(s[1])) s+=2; - if (s[0]=='\\' && s[1]=='\\') + + // Skip UNC Windows \\server\share\ or Unix //server/share/ + if (IsPathDiv(s[0]) && IsPathDiv(s[1])) { - const wchar *Slash=wcschr(s+2,'\\'); - if (Slash!=NULL && (Slash=wcschr(Slash+1,'\\'))!=NULL) - s=Slash+1; + uint SlashCount=0; + for (const wchar *t=s+2;*t!=0;t++) + if (IsPathDiv(*t) && ++SlashCount==2) + { + s=t+1; // Found two more path separators after leading two. + break; + } } for (const wchar *t=s;*t!=0;t++) if (IsPathDiv(*t)) @@ -184,7 +190,9 @@ void MakeName(const wchar *Path,const wchar *Name,wchar *Pathname,size_t MaxSize // the temporary buffer instead of constructing the name in 'Pathname'. wchar OutName[NM]; wcsncpyz(OutName,Path,ASIZE(OutName)); - AddEndSlash(OutName,ASIZE(OutName)); + // Do not add slash to d:, we want to allow relative paths like d:filename. + if (!IsDriveLetter(Path) || Path[2]!=0) + AddEndSlash(OutName,ASIZE(OutName)); wcsncatz(OutName,Name,ASIZE(OutName)); wcsncpyz(Pathname,OutName,MaxSize); } @@ -317,6 +325,9 @@ void GetConfigName(const wchar *Name,wchar *FullName,size_t MaxSize,bool CheckEx // of file name if numeric part is missing. wchar* GetVolNumPart(const wchar *ArcName) { + // We do not want to increment any characters in path component. + ArcName=PointToName(ArcName); + if (*ArcName==0) return (wchar *)ArcName; @@ -340,7 +351,7 @@ wchar* GetVolNumPart(const wchar *ArcName) { // Validate the first numeric part only if it has a dot somewhere // before it. - wchar *Dot=wcschr(PointToName(ArcName),'.'); + const wchar *Dot=wcschr(ArcName,'.'); if (Dot!=NULL && Dot|\"")==NULL; } -void MakeNameUsable(char *Name,bool Extended) -{ -#ifdef _WIN_ALL - // In Windows we also need to convert characters not defined in current - // code page. This double conversion changes them to '?', which is - // catched by code below. - size_t NameLength=strlen(Name); - wchar NameW[NM]; - CharToWide(Name,NameW,ASIZE(NameW)); - WideToChar(NameW,Name,NameLength+1); - Name[NameLength]=0; -#endif - for (char *s=Name;*s!=0;s=charnext(s)) - { - if (strchr(Extended ? "?*<>|\"":"?*",*s)!=NULL || Extended && (byte)*s<32) - *s='_'; -#ifdef _EMX - if (*s=='=') - *s='_'; -#endif -#ifndef _UNIX - if (s-Name>1 && *s==':') - *s='_'; - // Remove ' ' and '.' before path separator, but allow .\ and ..\. - if ((*s==' ' || *s=='.' && s>Name && !IsPathDiv(s[-1]) && s[-1]!='.') && IsPathDiv(s[1])) - *s='_'; -#endif - } -} void MakeNameUsable(wchar *Name,bool Extended) @@ -469,7 +469,27 @@ void MakeNameUsable(wchar *Name,bool Extended) { if (wcschr(Extended ? L"?*<>|\"":L"?*",*s)!=NULL || Extended && (uint)*s<32) *s='_'; -#ifndef _UNIX +#ifdef _UNIX + // We were asked to apply Windows-like conversion in Linux in case + // files are unpacked to Windows share. This code is invoked only + // if file failed to be created, so it doesn't affect extraction + // of Unix compatible names to native Unix drives. + if (Extended) + { + // Windows shares in Unix do not allow the drive letter, + // so unlike Windows version, we check all characters here. + if (*s==':') + *s='_'; + + // No spaces or dots before the path separator are allowed on Windows + // shares. But they are allowed and automtically removed at the end of + // file or folder name, so it is useless to replace them here. + // Since such files or folders are created successfully, a supposed + // conversion here would never be invoked. + if ((*s==' ' || *s=='.') && IsPathDiv(s[1])) + *s='_'; + } +#else if (s-Name>1 && *s==':') *s='_'; #if 0 // We already can create such files. @@ -692,7 +712,8 @@ static void GenArcName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,u wchar Mask[MAX_GENERATE_MASK]; wcsncpyz(Mask,*GenerateMask!=0 ? GenerateMask:L"yyyymmddhhmmss",ASIZE(Mask)); - bool QuoteMode=false,Hours=false; + bool QuoteMode=false; + uint MAsMinutes=0; // By default we treat 'M' as months. for (uint I=0;Mask[I]!=0;I++) { if (Mask[I]=='{' || Mask[I]=='}') @@ -704,13 +725,16 @@ static void GenArcName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,u continue; int CurChar=toupperw(Mask[I]); if (CurChar=='H') - Hours=true; + MAsMinutes=2; // Treat next two 'M' after 'H' as minutes. + if (CurChar=='D' || CurChar=='Y') + MAsMinutes=0; // Treat 'M' in HHDDMMYY and HHYYMMDD as month. - if (Hours && CurChar=='M') + if (MAsMinutes>0 && CurChar=='M') { // Replace minutes with 'I'. We use 'M' both for months and minutes, - // so we treat as minutes only those 'M' which are found after hours. + // so we treat as minutes only those 'M', which are found after hours. Mask[I]='I'; + MAsMinutes--; } if (CurChar=='N') { @@ -774,7 +798,9 @@ static void GenArcName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,u const wchar *MaskChars=L"YMDHISWAEN"; + // How many times every modifier character was encountered in the mask. int CField[sizeof(Field)/sizeof(Field[0])]; + memset(CField,0,sizeof(CField)); QuoteMode=false; for (uint I=0;Mask[I]!=0;I++) @@ -816,13 +842,22 @@ static void GenArcName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,u { size_t FieldPos=ChPtr-MaskChars; int CharPos=(int)strlen(Field[FieldPos])-CField[FieldPos]--; - if (FieldPos==1 && toupperw(Mask[I+1])=='M' && toupperw(Mask[I+2])=='M') + + // CField[FieldPos] shall have exactly 3 "MMM" symbols, so we do not + // repeat the month name in case "MMMMMMMM" mask. But since we + // decremented CField[FieldPos] above, we compared it with 2. + if (FieldPos==1 && CField[FieldPos]==2 && + toupperw(Mask[I+1])=='M' && toupperw(Mask[I+2])=='M') { wcsncpyz(DateText+J,GetMonthName(rlt.Month-1),ASIZE(DateText)-J); J=wcslen(DateText); I+=2; continue; } + // If CharPos is negative, we have more modifier characters than + // matching time data. We prefer to issue a modifier character + // instead of repeating time data from beginning, so user can notice + // excessive modifiers added by mistake. if (CharPos<0) DateText[J]=Mask[I]; else @@ -985,9 +1020,9 @@ void ConvertToPrecomposed(wchar *Name,size_t NameSize) } -// Remove trailing spaces and dots in file name and in dir names in path. -void MakeNameCompatible(wchar *Name) +void MakeNameCompatible(wchar *Name,size_t MaxSize) { + // Remove trailing spaces and dots in file name and in dir names in path. int Src=0,Dest=0; while (true) { @@ -1005,5 +1040,47 @@ void MakeNameCompatible(wchar *Name) Src++; Dest++; } + + // Rename reserved device names, such as aux.txt to _aux.txt. + // We check them in path components too, where they are also prohibited. + for (uint I=0;Name[I]!=0;I++) + if (I==0 || I>0 && IsPathDiv(Name[I-1])) + { + static const wchar *Devices[]={L"CON",L"PRN",L"AUX",L"NUL",L"COM#",L"LPT#"}; + wchar *s=Name+I; + bool MatchFound=false; + for (uint J=0;JI+1) // I+1, because we do not move the trailing 0. + memmove(s+1,s,(MaxSize-I-1)*sizeof(*s)); + *s='_'; +#ifndef SFX_MODULE + uiMsg(UIMSG_CORRECTINGNAME,nullptr); + uiMsg(UIERROR_RENAMING,nullptr,OrigName,Name); +#endif + } + } } #endif + + diff --git a/deps/unrar/pathfn.hpp b/deps/unrar/pathfn.hpp index 63813d8a4..62cae0ad2 100644 --- a/deps/unrar/pathfn.hpp +++ b/deps/unrar/pathfn.hpp @@ -29,7 +29,6 @@ void GetConfigName(const wchar *Name,wchar *FullName,size_t MaxSize,bool CheckEx wchar* GetVolNumPart(const wchar *ArcName); void NextVolumeName(wchar *ArcName,uint MaxLength,bool OldNumbering); bool IsNameUsable(const wchar *Name); -void MakeNameUsable(char *Name,bool Extended); void MakeNameUsable(wchar *Name,bool Extended); void UnixSlashToDos(const char *SrcName,char *DestName,size_t MaxLength); @@ -70,7 +69,8 @@ void GenerateArchiveName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask #ifdef _WIN_ALL bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize); void ConvertToPrecomposed(wchar *Name,size_t NameSize); -void MakeNameCompatible(wchar *Name); +void MakeNameCompatible(wchar *Name,size_t MaxSize); #endif + #endif diff --git a/deps/unrar/qopen.cpp b/deps/unrar/qopen.cpp index 43346b061..d906d06bd 100644 --- a/deps/unrar/qopen.cpp +++ b/deps/unrar/qopen.cpp @@ -97,7 +97,7 @@ void QuickOpen::Load(uint64 BlockPos) if (Arc->SubHead.Encrypted) { - RAROptions *Cmd=Arc->GetRAROptions(); + CommandData *Cmd=Arc->GetCommandData(); #ifndef RAR_NOCRYPT if (Cmd->Password.IsSet()) Crypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,Arc->SubHead.Salt, diff --git a/deps/unrar/rar.hpp b/deps/unrar/rar.hpp index 3f7414c87..67edb6735 100644 --- a/deps/unrar/rar.hpp +++ b/deps/unrar/rar.hpp @@ -12,10 +12,12 @@ #include "version.hpp" #include "rardefs.hpp" #include "rarlang.hpp" +#include "rawint.hpp" #include "unicode.hpp" #include "errhnd.hpp" #include "secpassword.hpp" #include "array.hpp" +#include "strlist.hpp" #include "timefn.hpp" #include "sha1.hpp" #include "sha256.hpp" @@ -28,13 +30,11 @@ #include "headers.hpp" #include "pathfn.hpp" #include "strfn.hpp" -#include "strlist.hpp" #ifdef _WIN_ALL #include "isnt.hpp" #endif #include "file.hpp" #include "crc.hpp" -#include "ui.hpp" #include "filefn.hpp" #include "filestr.hpp" #include "find.hpp" @@ -47,11 +47,11 @@ #include "archive.hpp" #include "match.hpp" #include "cmddata.hpp" +#include "ui.hpp" #include "filcreat.hpp" #include "consio.hpp" #include "system.hpp" #include "log.hpp" -#include "rawint.hpp" #include "rawread.hpp" #include "encname.hpp" #include "resource.hpp" diff --git a/deps/unrar/rardefs.hpp b/deps/unrar/rardefs.hpp index 095792a03..6858d39c1 100644 --- a/deps/unrar/rardefs.hpp +++ b/deps/unrar/rardefs.hpp @@ -9,9 +9,13 @@ #define ASIZE(x) (sizeof(x)/sizeof(x[0])) -// MAXPASSWORD is expected to be multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE (16) -// for CryptProtectMemory in SecPassword. -#define MAXPASSWORD 128 +// MAXPASSWORD and MAXPASSWORD_RAR are expected to be multiple of +// CRYPTPROTECTMEMORY_BLOCK_SIZE (16) for CryptProtectMemory in SecPassword. +// We allow a larger MAXPASSWORD to unpack archives with lengthy passwords +// in non-RAR formats in GUI versions. For RAR format we set MAXPASSWORD_RAR +// to 128 for compatibility and because it is enough for AES-256. +#define MAXPASSWORD 512 +#define MAXPASSWORD_RAR 128 #define MAXSFXSIZE 0x200000 diff --git a/deps/unrar/rawint.hpp b/deps/unrar/rawint.hpp index 303798886..c8cd86fc7 100644 --- a/deps/unrar/rawint.hpp +++ b/deps/unrar/rawint.hpp @@ -84,7 +84,7 @@ inline uint32 RawGetBE4(const byte *m) { #if defined(USE_MEM_BYTESWAP) && defined(_MSC_VER) return _byteswap_ulong(*(uint32 *)m); -#elif defined(USE_MEM_BYTESWAP) && (__GNUC__ > 3) && (__GNUC_MINOR__ > 2) +#elif defined(USE_MEM_BYTESWAP) && (defined(__clang__) || defined(__GNUC__)) return __builtin_bswap32(*(uint32 *)m); #else return uint32(m[0]<<24) | uint32(m[1]<<16) | uint32(m[2]<<8) | m[3]; @@ -97,7 +97,7 @@ inline void RawPutBE4(uint32 i,byte *mem) { #if defined(USE_MEM_BYTESWAP) && defined(_MSC_VER) *(uint32*)mem = _byteswap_ulong(i); -#elif defined(USE_MEM_BYTESWAP) && (__GNUC__ > 3) && (__GNUC_MINOR__ > 2) +#elif defined(USE_MEM_BYTESWAP) && (defined(__clang__) || defined(__GNUC__)) *(uint32*)mem = __builtin_bswap32(i); #else mem[0]=byte(i>>24); @@ -112,7 +112,7 @@ inline uint32 ByteSwap32(uint32 i) { #ifdef _MSC_VER return _byteswap_ulong(i); -#elif (__GNUC__ > 3) && (__GNUC_MINOR__ > 2) +#elif defined(__clang__) || defined(__GNUC__) return __builtin_bswap32(i); #else return (rotl32(i,24)&0xFF00FF00)|(rotl32(i,8)&0x00FF00FF); diff --git a/deps/unrar/rdwrfn.cpp b/deps/unrar/rdwrfn.cpp index 5c85753da..1b8219acf 100644 --- a/deps/unrar/rdwrfn.cpp +++ b/deps/unrar/rdwrfn.cpp @@ -16,6 +16,7 @@ void ComprDataIO::Init() UnpackFromMemory=false; UnpackToMemory=false; UnpPackedSize=0; + UnpPackedLeft=0; ShowProgress=true; TestMode=false; SkipUnpCRC=false; @@ -35,7 +36,9 @@ void ComprDataIO::Init() SubHead=NULL; SubHeadPos=NULL; CurrentCommand=0; - ProcessedArcSize=TotalArcSize=0; + ProcessedArcSize=0; + LastArcSize=0; + TotalArcSize=0; } @@ -75,10 +78,10 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count) } else { - size_t SizeToRead=((int64)Count>UnpPackedSize) ? (size_t)UnpPackedSize:Count; + size_t SizeToRead=((int64)Count>UnpPackedLeft) ? (size_t)UnpPackedLeft:Count; if (SizeToRead > 0) { - if (UnpVolume && Decryption && (int64)Count>UnpPackedSize) + if (UnpVolume && Decryption && (int64)Count>UnpPackedLeft) { // We need aligned blocks for decryption and we want "Keep broken // files" to work efficiently with missing encrypted volumes. @@ -109,7 +112,7 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count) ReadAddr+=ReadSize; Count-=ReadSize; #endif - UnpPackedSize-=ReadSize; + UnpPackedLeft-=ReadSize; // Do not ask for next volume if we read something from current volume. // If next volume is missing, we need to process all data from current @@ -118,7 +121,7 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count) // we ask for next volume also if we have non-aligned encryption block. // Since we adjust data size for decryption earlier above, // it does not hurt "Keep broken files" mode efficiency. - if (UnpVolume && UnpPackedSize == 0 && + if (UnpVolume && UnpPackedLeft == 0 && (ReadSize==0 || Decryption && (TotalRead & CRYPT_BLOCK_MASK) != 0) ) { #ifndef NOVOLUME @@ -134,7 +137,7 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count) } Archive *SrcArc=(Archive *)SrcFile; if (SrcArc!=NULL) - ShowUnpRead(SrcArc->CurBlockPos+CurUnpRead,UnpArcSize); + ShowUnpRead(SrcArc->NextBlockPos-UnpPackedSize+CurUnpRead,TotalArcSize); if (ReadSize!=-1) { ReadSize=TotalRead; @@ -148,18 +151,11 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count) } -#if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64) -// Disable the run time stack check for unrar.dll, so we can manipulate -// with ProcessDataProc call type below. Run time check would intercept -// a wrong ESP before we restore it. -#pragma runtime_checks( "s", off ) -#endif - void ComprDataIO::UnpWrite(byte *Addr,size_t Count) { #ifdef RARDLL - RAROptions *Cmd=((Archive *)SrcFile)->GetRAROptions(); + CommandData *Cmd=((Archive *)SrcFile)->GetCommandData(); if (Cmd->DllOpMode!=RAR_SKIP) { if (Cmd->Callback!=NULL && @@ -167,28 +163,7 @@ void ComprDataIO::UnpWrite(byte *Addr,size_t Count) ErrHandler.Exit(RARX_USERBREAK); if (Cmd->ProcessDataProc!=NULL) { - // Here we preserve ESP value. It is necessary for those developers, - // who still define ProcessDataProc callback as "C" type function, - // even though in year 2001 we announced in unrar.dll whatsnew.txt - // that it will be PASCAL type (for compatibility with Visual Basic). -#if defined(_MSC_VER) -#ifndef _WIN_64 - __asm mov ebx,esp -#endif -#elif defined(_WIN_ALL) && defined(__BORLANDC__) - _EBX=_ESP; -#endif int RetCode=Cmd->ProcessDataProc(Addr,(int)Count); - - // Restore ESP after ProcessDataProc with wrongly defined calling - // convention broken it. -#if defined(_MSC_VER) -#ifndef _WIN_64 - __asm mov esp,ebx -#endif -#elif defined(_WIN_ALL) && defined(__BORLANDC__) - _ESP=_EBX; -#endif if (RetCode==0) ErrHandler.Exit(RARX_USERBREAK); } @@ -216,11 +191,6 @@ void ComprDataIO::UnpWrite(byte *Addr,size_t Count) Wait(); } -#if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64) -// Restore the run time stack check for unrar.dll. -#pragma runtime_checks( "s", restore ) -#endif - @@ -230,15 +200,11 @@ void ComprDataIO::ShowUnpRead(int64 ArcPos,int64 ArcSize) { if (ShowProgress && SrcFile!=NULL) { - if (TotalArcSize!=0) - { - // important when processing several archives or multivolume archive - ArcSize=TotalArcSize; - ArcPos+=ProcessedArcSize; - } + // Important when processing several archives or multivolume archive. + ArcPos+=ProcessedArcSize; Archive *SrcArc=(Archive *)SrcFile; - RAROptions *Cmd=SrcArc->GetRAROptions(); + CommandData *Cmd=SrcArc->GetCommandData(); int CurPercent=ToPercent(ArcPos,ArcSize); if (!Cmd->DisablePercentage && CurPercent!=LastPercent) @@ -333,3 +299,37 @@ void ComprDataIO::SetUnpackFromMemory(byte *Addr,uint Size) UnpackFromMemoryAddr=Addr; UnpackFromMemorySize=Size; } + +// Extraction progress is based on the position in archive and we adjust +// the total archives size here, so trailing blocks do not prevent progress +// reaching 100% at the end of extraction. Alternatively we could print "100%" +// after completing the entire archive extraction, but then we would need +// to take into account possible messages like the checksum error after +// last file percent progress. +void ComprDataIO::AdjustTotalArcSize(Archive *Arc) +{ + // If we know a position of QO or RR blocks, use them to adjust the total + // packed size to beginning of these blocks. Earlier we already calculated + // the total size based on entire archive sizes. We also set LastArcSize + // to start of first trailing block, to add it later to ProcessedArcSize. + int64 ArcLength=Arc->IsSeekable() ? Arc->FileLength() : 0; + if (Arc->MainHead.QOpenOffset!=0) // QO is always preceding RR record. + LastArcSize=Arc->MainHead.QOpenOffset; + else + if (Arc->MainHead.RROffset!=0) + LastArcSize=Arc->MainHead.RROffset; + else + { + // If neither QO nor RR are found, exclude the approximate size of + // end of archive block. + // We select EndBlock to be larger than typical 8 bytes HEAD_ENDARC, + // but to not exceed the smallest 22 bytes HEAD_FILE with 1 byte file + // name, so we do not have two files with 100% at the end of archive. + const uint EndBlock=23; + + if (ArcLength>EndBlock) + LastArcSize=ArcLength-EndBlock; + } + + TotalArcSize-=ArcLength-LastArcSize; +} diff --git a/deps/unrar/rdwrfn.hpp b/deps/unrar/rdwrfn.hpp index 24c09eec4..f708bf4a9 100644 --- a/deps/unrar/rdwrfn.hpp +++ b/deps/unrar/rdwrfn.hpp @@ -1,6 +1,7 @@ #ifndef _RAR_DATAIO_ #define _RAR_DATAIO_ +class Archive; class CmdAdd; class Unpack; class ArcFileSearch; @@ -29,6 +30,7 @@ class ComprDataIO byte *UnpWrAddr; int64 UnpPackedSize; + int64 UnpPackedLeft; bool ShowProgress; bool TestMode; @@ -61,7 +63,7 @@ class ComprDataIO void UnpWrite(byte *Addr,size_t Count); void EnableShowProgress(bool Show) {ShowProgress=Show;} void GetUnpackedData(byte **Data,size_t *Size); - void SetPackedSizeToRead(int64 Size) {UnpPackedSize=Size;} + void SetPackedSizeToRead(int64 Size) {UnpPackedSize=UnpPackedLeft=Size;} void SetTestMode(bool Mode) {TestMode=Mode;} void SetSkipUnpCRC(bool Skip) {SkipUnpCRC=Skip;} void SetNoFileHeader(bool Mode) {NoFileHeader=Mode;} @@ -76,12 +78,12 @@ class ComprDataIO void SetUnpackToMemory(byte *Addr,uint Size); void SetUnpackFromMemory(byte *Addr,uint Size); void SetCurrentCommand(wchar Cmd) {CurrentCommand=Cmd;} + void AdjustTotalArcSize(Archive *Arc); bool PackVolume; bool UnpVolume; bool NextVolumeMissing; - int64 UnpArcSize; int64 CurPackRead,CurPackWrite,CurUnpRead,CurUnpWrite; @@ -89,6 +91,9 @@ class ComprDataIO // Used to calculate the total operation progress. int64 ProcessedArcSize; + // Last extracted archive size up to QO or RR block. + int64 LastArcSize; + int64 TotalArcSize; DataHash PackedDataHash; // Packed write and unpack read hash. diff --git a/deps/unrar/recvol.cpp b/deps/unrar/recvol.cpp index adf584044..b17820711 100644 --- a/deps/unrar/recvol.cpp +++ b/deps/unrar/recvol.cpp @@ -5,7 +5,7 @@ -bool RecVolumesRestore(RAROptions *Cmd,const wchar *Name,bool Silent) +bool RecVolumesRestore(CommandData *Cmd,const wchar *Name,bool Silent) { Archive Arc(Cmd); if (!Arc.Open(Name)) @@ -42,7 +42,7 @@ bool RecVolumesRestore(RAROptions *Cmd,const wchar *Name,bool Silent) } -void RecVolumesTest(RAROptions *Cmd,Archive *Arc,const wchar *Name) +void RecVolumesTest(CommandData *Cmd,Archive *Arc,const wchar *Name) { wchar RevName[NM]; *RevName=0; diff --git a/deps/unrar/recvol.hpp b/deps/unrar/recvol.hpp index 06510a211..4a6d663ff 100644 --- a/deps/unrar/recvol.hpp +++ b/deps/unrar/recvol.hpp @@ -14,11 +14,11 @@ class RecVolumes3 ThreadPool *RSThreadPool; #endif public: - RecVolumes3(RAROptions *Cmd,bool TestOnly); + RecVolumes3(CommandData *Cmd,bool TestOnly); ~RecVolumes3(); - void Make(RAROptions *Cmd,wchar *ArcName); - bool Restore(RAROptions *Cmd,const wchar *Name,bool Silent); - void Test(RAROptions *Cmd,const wchar *Name); + void Make(CommandData *Cmd,wchar *ArcName); + bool Restore(CommandData *Cmd,const wchar *Name,bool Silent); + void Test(CommandData *Cmd,const wchar *Name); }; @@ -48,8 +48,8 @@ struct RecRSThreadData class RecVolumes5 { private: - void ProcessRS(RAROptions *Cmd,uint DataNum,const byte *Data,uint MaxRead,bool Encode); - void ProcessRS(RAROptions *Cmd,uint MaxRead,bool Encode); + void ProcessRS(CommandData *Cmd,uint DataNum,const byte *Data,uint MaxRead,bool Encode); + void ProcessRS(CommandData *Cmd,uint MaxRead,bool Encode); uint ReadHeader(File *RecFile,bool FirstRev); Array RecItems; @@ -76,13 +76,13 @@ class RecVolumes5 public: // 'public' only because called from thread functions. void ProcessAreaRS(RecRSThreadData *td); public: - RecVolumes5(RAROptions *Cmd,bool TestOnly); + RecVolumes5(CommandData *Cmd,bool TestOnly); ~RecVolumes5(); - bool Restore(RAROptions *Cmd,const wchar *Name,bool Silent); - void Test(RAROptions *Cmd,const wchar *Name); + bool Restore(CommandData *Cmd,const wchar *Name,bool Silent); + void Test(CommandData *Cmd,const wchar *Name); }; -bool RecVolumesRestore(RAROptions *Cmd,const wchar *Name,bool Silent); -void RecVolumesTest(RAROptions *Cmd,Archive *Arc,const wchar *Name); +bool RecVolumesRestore(CommandData *Cmd,const wchar *Name,bool Silent); +void RecVolumesTest(CommandData *Cmd,Archive *Arc,const wchar *Name); #endif diff --git a/deps/unrar/recvol3.cpp b/deps/unrar/recvol3.cpp index 9fb846a28..ecf6dd35e 100644 --- a/deps/unrar/recvol3.cpp +++ b/deps/unrar/recvol3.cpp @@ -36,7 +36,7 @@ THREAD_PROC(RSDecodeThread) } #endif -RecVolumes3::RecVolumes3(RAROptions *Cmd,bool TestOnly) +RecVolumes3::RecVolumes3(CommandData *Cmd,bool TestOnly) { memset(SrcFile,0,sizeof(SrcFile)); if (TestOnly) @@ -99,7 +99,7 @@ static bool IsNewStyleRev(const wchar *Name) } -bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) +bool RecVolumes3::Restore(CommandData *Cmd,const wchar *Name,bool Silent) { wchar ArcName[NM]; wcsncpyz(ArcName,Name,ASIZE(ArcName)); @@ -497,7 +497,7 @@ void RSEncode::DecodeBuf() } -void RecVolumes3::Test(RAROptions *Cmd,const wchar *Name) +void RecVolumes3::Test(CommandData *Cmd,const wchar *Name) { if (!IsNewStyleRev(Name)) // RAR 3.0 name#_#_#.rev do not include CRC32. { diff --git a/deps/unrar/recvol5.cpp b/deps/unrar/recvol5.cpp index 3c524d8ee..2d9c94711 100644 --- a/deps/unrar/recvol5.cpp +++ b/deps/unrar/recvol5.cpp @@ -1,6 +1,10 @@ static const uint MaxVolumes=65535; -RecVolumes5::RecVolumes5(RAROptions *Cmd,bool TestOnly) +// We select this limit arbitrarily, to prevent user creating too many +// rev files by mistake. +#define MAX_REV_TO_DATA_RATIO 10 // 1000% of rev files. + +RecVolumes5::RecVolumes5(CommandData *Cmd,bool TestOnly) { RealBuf=NULL; RealReadBuffer=NULL; @@ -66,7 +70,7 @@ THREAD_PROC(RecThreadRS) #endif -void RecVolumes5::ProcessRS(RAROptions *Cmd,uint DataNum,const byte *Data,uint MaxRead,bool Encode) +void RecVolumes5::ProcessRS(CommandData *Cmd,uint DataNum,const byte *Data,uint MaxRead,bool Encode) { /* RSCoder16 RS; @@ -137,7 +141,7 @@ void RecVolumes5::ProcessAreaRS(RecRSThreadData *td) -bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) +bool RecVolumes5::Restore(CommandData *Cmd,const wchar *Name,bool Silent) { wchar ArcName[NM]; wcsncpyz(ArcName,Name,ASIZE(ArcName)); @@ -145,13 +149,16 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) wchar *Num=GetVolNumPart(ArcName); while (Num>ArcName && IsDigit(*(Num-1))) Num--; - if (Num==ArcName) + if (Num<=PointToName(ArcName)) return false; // Numeric part is missing or entire volume name is numeric, not possible for RAR or REV volume. wcsncpyz(Num,L"*.*",ASIZE(ArcName)-(Num-ArcName)); wchar FirstVolName[NM]; *FirstVolName=0; + wchar LongestRevName[NM]; + *LongestRevName=0; + int64 RecFileSize=0; FindFile VolFind; @@ -164,7 +171,7 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) Archive *Vol=new Archive(Cmd); int ItemPos=-1; - if (Vol->WOpen(fd.Name)) + if (!fd.IsDir && Vol->WOpen(fd.Name)) { if (CmpExt(fd.Name,L"rev")) { @@ -176,6 +183,9 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) ItemPos=RecNum; FoundRecVolumes++; + + if (wcslen(fd.Name)>wcslen(LongestRevName)) + wcsncpyz(LongestRevName,fd.Name,ASIZE(LongestRevName)); } } else @@ -231,6 +241,15 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) if (FoundRecVolumes==0) return false; + // If we did not find even a single .rar volume, create .rar volume name + // based on the longest .rev file name. Use longest .rev, so we have + // enough space for volume number. + if (*FirstVolName==0) + { + SetExt(LongestRevName,L"rar",ASIZE(LongestRevName)); + VolNameToFirstName(LongestRevName,FirstVolName,ASIZE(FirstVolName),true); + } + uiMsg(UIMSG_RECVOLCALCCHECKSUM); MissingVolumes=0; @@ -301,7 +320,7 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) Item->f=NULL; } - if ((Item->New=(Item->f==NULL))) // Additional parentheses to avoid GCC warning. + if ((Item->New=(Item->f==NULL))==true) { wcsncpyz(Item->Name,FirstVolName,ASIZE(Item->Name)); uiMsg(UIMSG_CREATING,Item->Name); @@ -316,7 +335,6 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) } NewVol->Prealloc(Item->FileSize); Item->f=NewVol; - Item->New=true; } NextVolumeName(FirstVolName,ASIZE(FirstVolName),false); } @@ -346,13 +364,11 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) RecBufferSize&=~(SSE_ALIGNMENT-1); // Align for SSE. #endif - uint *Data=new uint[TotalCount]; - RSCoder16 RS; if (!RS.Init(DataCount,RecCount,ValidFlags)) { + uiMsg(UIERROR_OPFAILED); delete[] ValidFlags; - delete[] Data; return false; // Should not happen, we check parameter validity above. } @@ -415,7 +431,6 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) RecItems[I].f->Close(); delete[] ValidFlags; - delete[] Data; #if !defined(SILENT) if (!Cmd->DisablePercentage) mprintf(L"\b\b\b\b100%%"); @@ -479,7 +494,7 @@ uint RecVolumes5::ReadHeader(File *RecFile,bool FirstRev) } -void RecVolumes5::Test(RAROptions *Cmd,const wchar *Name) +void RecVolumes5::Test(CommandData *Cmd,const wchar *Name) { wchar VolName[NM]; wcsncpyz(VolName,Name,ASIZE(VolName)); diff --git a/deps/unrar/rijndael.cpp b/deps/unrar/rijndael.cpp index cbb1722fd..02c4d147b 100644 --- a/deps/unrar/rijndael.cpp +++ b/deps/unrar/rijndael.cpp @@ -1,22 +1,40 @@ -/*************************************************************************** - * This code is based on public domain Szymon Stefanek AES implementation: * - * http://www.pragmaware.net/software/rijndael/index.php * - * * - * Dynamic tables generation is based on the Brian Gladman work: * - * http://fp.gladman.plus.com/cryptography_technology/rijndael * - ***************************************************************************/ +/************************************************************************** + * This code is based on Szymon Stefanek public domain AES implementation * + **************************************************************************/ #include "rar.hpp" #ifdef USE_SSE #include #endif -// not thread-safe ? -//static byte S[256],S5[256],rcon[30]; -//static byte T1[256][4],T2[256][4],T3[256][4],T4[256][4]; -//static byte T5[256][4],T6[256][4],T7[256][4],T8[256][4]; -//static byte U1[256][4],U2[256][4],U3[256][4],U4[256][4]; - +static byte S[256]= +{ + 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, + 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, + 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, + 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, + 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, + 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, + 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, + 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, + 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, + 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, + 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, + 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, + 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, + 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, + 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, + 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22 +}; + +static byte S5[256]; + +// Round constants. 10 items are used by AES-128, 8 by AES-192, 7 by AES-256. +static byte rcon[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36}; + +static byte T1[256][4],T2[256][4],T3[256][4],T4[256][4]; +static byte T5[256][4],T6[256][4],T7[256][4],T8[256][4]; +static byte U1[256][4],U2[256][4],U3[256][4],U4[256][4]; inline void Xor128(void *dest,const void *arg1,const void *arg2) { @@ -64,7 +82,7 @@ inline void Copy128(byte *dest,const byte *src) Rijndael::Rijndael() { - //if (S[0]==0) + if (S5[0]==0) GenerateTables(); CBCMode = true; // Always true for RAR. } @@ -72,18 +90,20 @@ Rijndael::Rijndael() void Rijndael::Init(bool Encrypt,const byte *key,uint keyLen,const byte * initVector) { -#ifdef USE_SSE - // Check SSE here instead of constructor, so if object is a part of some - // structure memset'ed before use, this variable is not lost. + // Check SIMD here instead of constructor, so if object is a part of some + // structure memset'ed before use, these variables are not lost. +#if defined(USE_SSE) int CPUInfo[4]; - __cpuid(CPUInfo, 0x80000000); // Get the maximum supported cpuid function. - if ((CPUInfo[0] & 0x7fffffff)>=1) + __cpuid(CPUInfo, 0); + if (CPUInfo[0]>=1) // Check the maximum supported cpuid function. { __cpuid(CPUInfo, 1); AES_NI=(CPUInfo[2] & 0x2000000)!=0; } else - AES_NI=0; + AES_NI=false; +#elif defined(USE_NEON) + AES_Neon=(getauxval(AT_HWCAP) & HWCAP_AES)!=0; #endif // Other developers asked us to initialize it to suppress "may be used @@ -123,18 +143,25 @@ void Rijndael::Init(bool Encrypt,const byte *key,uint keyLen,const byte * initVe keyEncToDec(); } + void Rijndael::blockEncrypt(const byte *input,size_t inputLen,byte *outBuffer) { if (inputLen <= 0) return; size_t numBlocks = inputLen/16; -#ifdef USE_SSE +#if defined(USE_SSE) if (AES_NI) { blockEncryptSSE(input,numBlocks,outBuffer); return; } +#elif defined(USE_NEON) + if (AES_Neon) + { + blockEncryptNeon(input,numBlocks,outBuffer); + return; + } #endif byte *prevBlock = m_initVector; @@ -221,6 +248,40 @@ void Rijndael::blockEncryptSSE(const byte *input,size_t numBlocks,byte *outBuffe } #endif + +#ifdef USE_NEON +void Rijndael::blockEncryptNeon(const byte *input,size_t numBlocks,byte *outBuffer) +{ + byte *prevBlock = m_initVector; + while (numBlocks > 0) + { + byte block[16]; + if (CBCMode) + vst1q_u8(block, veorq_u8(vld1q_u8(prevBlock), vld1q_u8(input))); + else + vst1q_u8(block, vld1q_u8(input)); + + uint8x16_t data = vld1q_u8(block); + for (uint i = 0; i < m_uRounds-1; i++) + { + data = vaeseq_u8(data, vld1q_u8((byte *)m_expandedKey[i])); + data = vaesmcq_u8(data); + } + data = vaeseq_u8(data, vld1q_u8((byte *)(m_expandedKey[m_uRounds-1]))); + data = veorq_u8(data, vld1q_u8((byte *)(m_expandedKey[m_uRounds]))); + vst1q_u8(outBuffer, data); + + prevBlock=outBuffer; + + outBuffer += 16; + input += 16; + numBlocks--; + } + vst1q_u8(m_initVector, vld1q_u8(prevBlock)); + return; +} +#endif + void Rijndael::blockDecrypt(const byte *input, size_t inputLen, byte *outBuffer) { @@ -228,12 +289,18 @@ void Rijndael::blockDecrypt(const byte *input, size_t inputLen, byte *outBuffer) return; size_t numBlocks=inputLen/16; -#ifdef USE_SSE +#if defined(USE_SSE) if (AES_NI) { blockDecryptSSE(input,numBlocks,outBuffer); return; } +#elif defined(USE_NEON) + if (AES_Neon) + { + blockDecryptNeon(input,numBlocks,outBuffer); + return; + } #endif byte block[16], iv[4][4]; @@ -325,6 +392,41 @@ void Rijndael::blockDecryptSSE(const byte *input, size_t numBlocks, byte *outBuf #endif +#ifdef USE_NEON +void Rijndael::blockDecryptNeon(const byte *input, size_t numBlocks, byte *outBuffer) +{ + byte iv[16]; + memcpy(iv,m_initVector,16); + + while (numBlocks > 0) + { + uint8x16_t data = vld1q_u8(input); + + for (int i=m_uRounds-1; i>0; i--) + { + data = vaesdq_u8(data, vld1q_u8((byte *)m_expandedKey[i+1])); + data = vaesimcq_u8(data); + } + + data = vaesdq_u8(data, vld1q_u8((byte *)m_expandedKey[1])); + data = veorq_u8(data, vld1q_u8((byte *)m_expandedKey[0])); + + if (CBCMode) + data = veorq_u8(data, vld1q_u8(iv)); + + vst1q_u8(iv, vld1q_u8(input)); + vst1q_u8(outBuffer, data); + + input += 16; + outBuffer += 16; + numBlocks--; + } + + memcpy(m_initVector,iv,16); +} +#endif + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // ALGORITHM ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -417,51 +519,40 @@ void Rijndael::keyEncToDec() } -#define ff_poly 0x011b -#define ff_hi 0x80 - -#define FFinv(x) ((x) ? pow[255 - log[x]]: 0) - -#define FFmul02(x) (x ? pow[log[x] + 0x19] : 0) -#define FFmul03(x) (x ? pow[log[x] + 0x01] : 0) -#define FFmul09(x) (x ? pow[log[x] + 0xc7] : 0) -#define FFmul0b(x) (x ? pow[log[x] + 0x68] : 0) -#define FFmul0d(x) (x ? pow[log[x] + 0xee] : 0) -#define FFmul0e(x) (x ? pow[log[x] + 0xdf] : 0) -#define fwd_affine(x) \ - (w = (uint)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), (byte)(0x63^(w^(w>>8)))) +static byte gmul(byte a, byte b) // Galois field "peasant's algorithm" multiplication. +{ + const byte poly=0x1b; // Lower byte of AES 0x11b irreducible polynomial. + byte result = 0; + while (b>0) + { + if ((b & 1) != 0) + result ^= a; + a = (a & 0x80) ? (a<<1)^poly : a<<1; + b >>= 1; + } + return result; +} -#define inv_affine(x) \ - (w = (uint)x, w = (w<<1)^(w<<3)^(w<<6), (byte)(0x05^(w^(w>>8)))) +// 2021-09-24: changed to slower and simpler code without interim tables. +// It is still fast enough for our purpose. void Rijndael::GenerateTables() { - unsigned char pow[512],log[256]; - int i = 0, w = 1; - do - { - pow[i] = (byte)w; - pow[i + 255] = (byte)w; - log[w] = (byte)i++; - w ^= (w << 1) ^ (w & ff_hi ? ff_poly : 0); - } while (w != 1); - - for (int i = 0,w = 1; i < sizeof(rcon)/sizeof(rcon[0]); i++) - { - rcon[i] = w; - w = (w << 1) ^ (w & ff_hi ? ff_poly : 0); - } - for(int i = 0; i < 256; ++i) + for (int I=0;I<256;I++) + S5[S[I]]=I; + + for (int I=0;I<256;I++) { - unsigned char b=S[i]=fwd_affine(FFinv((byte)i)); - T1[i][1]=T1[i][2]=T2[i][2]=T2[i][3]=T3[i][0]=T3[i][3]=T4[i][0]=T4[i][1]=b; - T1[i][0]=T2[i][1]=T3[i][2]=T4[i][3]=FFmul02(b); - T1[i][3]=T2[i][0]=T3[i][1]=T4[i][2]=FFmul03(b); - S5[i] = b = FFinv(inv_affine((byte)i)); - U1[b][3]=U2[b][0]=U3[b][1]=U4[b][2]=T5[i][3]=T6[i][0]=T7[i][1]=T8[i][2]=FFmul0b(b); - U1[b][1]=U2[b][2]=U3[b][3]=U4[b][0]=T5[i][1]=T6[i][2]=T7[i][3]=T8[i][0]=FFmul09(b); - U1[b][2]=U2[b][3]=U3[b][0]=U4[b][1]=T5[i][2]=T6[i][3]=T7[i][0]=T8[i][1]=FFmul0d(b); - U1[b][0]=U2[b][1]=U3[b][2]=U4[b][3]=T5[i][0]=T6[i][1]=T7[i][2]=T8[i][3]=FFmul0e(b); + byte s=S[I]; + T1[I][1]=T1[I][2]=T2[I][2]=T2[I][3]=T3[I][0]=T3[I][3]=T4[I][0]=T4[I][1]=s; + T1[I][0]=T2[I][1]=T3[I][2]=T4[I][3]=gmul(s,2); + T1[I][3]=T2[I][0]=T3[I][1]=T4[I][2]=gmul(s,3); + + byte b=S5[I]; + U1[b][3]=U2[b][0]=U3[b][1]=U4[b][2]=T5[I][3]=T6[I][0]=T7[I][1]=T8[I][2]=gmul(b,0xb); + U1[b][1]=U2[b][2]=U3[b][3]=U4[b][0]=T5[I][1]=T6[I][2]=T7[I][3]=T8[I][0]=gmul(b,0x9); + U1[b][2]=U2[b][3]=U3[b][0]=U4[b][1]=T5[I][2]=T6[I][3]=T7[I][0]=T8[I][1]=gmul(b,0xd); + U1[b][0]=U2[b][1]=U3[b][2]=U4[b][3]=T5[I][0]=T6[I][1]=T7[I][2]=T8[I][3]=gmul(b,0xe); } } diff --git a/deps/unrar/rijndael.hpp b/deps/unrar/rijndael.hpp index 33537d890..96e1d0d14 100644 --- a/deps/unrar/rijndael.hpp +++ b/deps/unrar/rijndael.hpp @@ -2,11 +2,7 @@ #define _RIJNDAEL_H_ /************************************************************************** - * This code is based on Szymon Stefanek AES implementation: * - * http://www.esat.kuleuven.ac.be/~rijmen/rijndael/rijndael-cpplib.tar.gz * - * * - * Dynamic tables generation is based on the Brian Gladman's work: * - * http://fp.gladman.plus.com/cryptography_technology/rijndael * + * This code is based on Szymon Stefanek public domain AES implementation * **************************************************************************/ #define _MAX_KEY_COLUMNS (256/32) @@ -22,6 +18,16 @@ class Rijndael bool AES_NI; #endif +#ifdef USE_NEON + // Set "crypto" attribute as replacement of -march=armv8-a+crypto switch. + __attribute__((target("crypto"))) + void blockEncryptNeon(const byte *input,size_t numBlocks,byte *outBuffer); + __attribute__((target("crypto"))) + void blockDecryptNeon(const byte *input, size_t numBlocks, byte *outBuffer); + + bool AES_Neon; +#endif + void keySched(byte key[_MAX_KEY_COLUMNS][4]); void keyEncToDec(); void GenerateTables(); @@ -33,11 +39,6 @@ class Rijndael int m_uRounds; byte m_initVector[MAX_IV_SIZE]; byte m_expandedKey[_MAX_ROUNDS+1][4][4]; - - byte S[256],S5[256],rcon[30]; - byte T1[256][4],T2[256][4],T3[256][4],T4[256][4]; - byte T5[256][4],T6[256][4],T7[256][4],T8[256][4]; - byte U1[256][4],U2[256][4],U3[256][4],U4[256][4]; public: Rijndael(); void Init(bool Encrypt,const byte *key,uint keyLen,const byte *initVector); diff --git a/deps/unrar/rs16.cpp b/deps/unrar/rs16.cpp index bc8dd0937..f5c7ccac1 100644 --- a/deps/unrar/rs16.cpp +++ b/deps/unrar/rs16.cpp @@ -95,7 +95,9 @@ bool RSCoder16::Init(uint DataCount, uint RecCount, bool *ValidityFlags) if (NE > ValidECC || NE == 0 || ValidECC == 0) return false; } - if (ND + NR > gfSize || NR > ND || ND == 0 || NR == 0) + + // 2021.09.01 - we allowed RR and REV >100%, so no more NR > ND check. + if (ND + NR > gfSize || /*NR > ND ||*/ ND == 0 || NR == 0) return false; delete[] MX; diff --git a/deps/unrar/savepos.hpp b/deps/unrar/savepos.hpp deleted file mode 100644 index 1f8353f65..000000000 --- a/deps/unrar/savepos.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef _RAR_SAVEPOS_ -#define _RAR_SAVEPOS_ - -class SaveFilePos -{ - private: - File *SaveFile; - int64 SavePos; - public: - SaveFilePos(File &Src) - { - SaveFile=&Src; - SavePos=Src.Tell(); - } - ~SaveFilePos() - { - // Unless the file is already closed either by current exception - // processing or intentionally by external code. - if (SaveFile->IsOpened()) - { - try - { - SaveFile->Seek(SavePos,SEEK_SET); - } - catch(RAR_EXIT) - { - // Seek() can throw an exception and it terminates process - // if we are already processing another exception. Also in C++ 11 - // an exception in destructor always terminates process unless - // we mark destructor with noexcept(false). So we do not want to - // throw here. To prevent data loss we do not want to continue - // execution after seek error, so we close the file. - // Any next access to this file will return an error. - SaveFile->Close(); - } - } - } -}; - -#endif diff --git a/deps/unrar/scantree.cpp b/deps/unrar/scantree.cpp index a13a3ebce..03c830e71 100644 --- a/deps/unrar/scantree.cpp +++ b/deps/unrar/scantree.cpp @@ -215,10 +215,23 @@ bool ScanTree::GetNextMask() UnixSlashToDos(CurMask,CurMask,ASIZE(CurMask)); #endif - // We wish to scan entire disk if mask like c:\ is specified - // regardless of recursion mode. Use c:\*.* mask when need to scan only - // the root directory. - ScanEntireDisk=IsDriveLetter(CurMask) && IsPathDiv(CurMask[2]) && CurMask[3]==0; + /* + We prefer to scan entire disk if mask like \\server\share\ or c:\ + is specified regardless of recursion mode. Use \\server\share\*.* + or c:\*.* mask to scan only the root directory. + */ + if (CurMask[0]=='\\' && CurMask[1]=='\\') + { + const wchar *Slash=wcschr(CurMask+2,'\\'); + if (Slash!=NULL) + { + Slash=wcschr(Slash+1,'\\'); + ScanEntireDisk=Slash!=NULL && *(Slash+1)==0; + } + } + else + ScanEntireDisk=IsDriveLetter(CurMask) && IsPathDiv(CurMask[2]) && CurMask[3]==0; + wchar *Name=PointToName(CurMask); if (*Name==0) diff --git a/deps/unrar/secpassword.cpp b/deps/unrar/secpassword.cpp index b99e53af0..42ed47d5e 100644 --- a/deps/unrar/secpassword.cpp +++ b/deps/unrar/secpassword.cpp @@ -56,7 +56,6 @@ static CryptLoader GlobalCryptLoader; SecPassword::SecPassword() { - CrossProcess=false; Set(L""); } @@ -70,7 +69,8 @@ SecPassword::~SecPassword() void SecPassword::Clean() { PasswordSet=false; - cleandata(Password,sizeof(Password)); + if (Password.size()>0) + cleandata(&Password[0],Password.size()); } @@ -104,7 +104,7 @@ void SecPassword::Process(const wchar *Src,size_t SrcSize,wchar *Dst,size_t DstS // Source string can be shorter than destination as in case when we process // -p parameter, so we need to take into account both sizes. memcpy(Dst,Src,Min(SrcSize,DstSize)*sizeof(*Dst)); - SecHideData(Dst,DstSize*sizeof(*Dst),Encode,CrossProcess); + SecHideData(Dst,DstSize*sizeof(*Dst),Encode,false); } @@ -112,7 +112,7 @@ void SecPassword::Get(wchar *Psw,size_t MaxSize) { if (PasswordSet) { - Process(Password,ASIZE(Password),Psw,MaxSize,false); + Process(&Password[0],Password.size(),Psw,MaxSize,false); Psw[MaxSize-1]=0; } else @@ -124,15 +124,14 @@ void SecPassword::Get(wchar *Psw,size_t MaxSize) void SecPassword::Set(const wchar *Psw) { - if (*Psw==0) - { - PasswordSet=false; - memset(Password,0,sizeof(Password)); - } - else + // Eliminate any traces of previously stored password for security reason + // in case it was longer than new one. + Clean(); + + if (*Psw!=0) { PasswordSet=true; - Process(Psw,wcslen(Psw)+1,Password,ASIZE(Password),true); + Process(Psw,wcslen(Psw)+1,&Password[0],Password.size(),true); } } @@ -163,6 +162,9 @@ bool SecPassword::operator == (SecPassword &psw) } +// Set CrossProcess to true if we need to pass a password to another process. +// We use CrossProcess when transferring parameters to UAC elevated WinRAR +// and Windows GUI SFX modules. void SecHideData(void *Data,size_t DataSize,bool Encode,bool CrossProcess) { // CryptProtectMemory is not available in UWP and CryptProtectData diff --git a/deps/unrar/secpassword.hpp b/deps/unrar/secpassword.hpp index 375d3887a..5284bce12 100644 --- a/deps/unrar/secpassword.hpp +++ b/deps/unrar/secpassword.hpp @@ -8,10 +8,7 @@ class SecPassword private: void Process(const wchar *Src,size_t SrcSize,wchar *Dst,size_t DstSize,bool Encode); - wchar Password[MAXPASSWORD]; - - // It is important to have this 'bool' value, so if our object is cleaned - // with memset as a part of larger structure, it is handled correctly. + std::vector Password = std::vector(MAXPASSWORD); bool PasswordSet; public: SecPassword(); @@ -22,10 +19,6 @@ class SecPassword bool IsSet() {return PasswordSet;} size_t Length(); bool operator == (SecPassword &psw); - - // Set to true if we need to pass a password to another process. - // We use it when transferring parameters to UAC elevated WinRAR. - bool CrossProcess; }; diff --git a/deps/unrar/strfn.cpp b/deps/unrar/strfn.cpp index 8904b9072..7617f7a59 100644 --- a/deps/unrar/strfn.cpp +++ b/deps/unrar/strfn.cpp @@ -121,48 +121,26 @@ wchar* RemoveLF(wchar *Str) } -unsigned char loctolower(unsigned char ch) -{ -#if defined(_WIN_ALL) - // Convert to LPARAM first to avoid a warning in 64 bit mode. - // Convert to uintptr_t to avoid Clang/win error: cast to 'char *' from smaller integer type 'unsigned char' [-Werror,-Wint-to-pointer-cast] - return (int)(LPARAM)CharLowerA((LPSTR)(uintptr_t)ch); -#else - return tolower(ch); -#endif -} - - -unsigned char loctoupper(unsigned char ch) -{ -#if defined(_WIN_ALL) - // Convert to LPARAM first to avoid a warning in 64 bit mode. - // Convert to uintptr_t to avoid Clang/win error: cast to 'char *' from smaller integer type 'unsigned char' [-Werror,-Wint-to-pointer-cast] - return (int)(LPARAM)CharUpperA((LPSTR)(uintptr_t)ch); -#else - return toupper(ch); -#endif -} - - -// toupper with English only results if English input is provided. -// It avoids Turkish (small i) -> (big I with dot) conversion problem. -// We do not define 'ch' as 'int' to avoid necessity to cast all +#if defined(SFX_MODULE) +// char version of etoupperw. Used in console SFX module only. +// Fast toupper for English only input and output. Additionally to speed, +// it also avoids Turkish small i to big I with dot conversion problem. +// We do not define 'c' as 'int' to avoid necessity to cast all // signed chars passed to this function to unsigned char. -unsigned char etoupper(unsigned char ch) +unsigned char etoupper(unsigned char c) { - if (ch=='i') - return 'I'; - return toupper(ch); + return c>='a' && c<='z' ? c-'a'+'A' : c; } +#endif -// Unicode version of etoupper. -wchar etoupperw(wchar ch) +// Fast toupper for English only input and output. Additionally to speed, +// it also avoids Turkish small i to big I with dot conversion problem. +// We do not define 'c' as 'int' to avoid necessity to cast all +// signed wchars passed to this function to unsigned char. +wchar etoupperw(wchar c) { - if (ch=='i') - return 'I'; - return toupperw(ch); + return c>='a' && c<='z' ? c-'a'+'A' : c; } @@ -379,6 +357,32 @@ void itoa(int64 n,wchar *Str,size_t MaxSize) } +// Convert the number to string using thousand separators. +void fmtitoa(int64 n,wchar *Str,size_t MaxSize) +{ + static wchar ThSep=0; // Thousands separator. +#ifdef _WIN_ALL + wchar Info[10]; + if (!ThSep!=0 && GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_STHOUSAND,Info,ASIZE(Info))>0) + ThSep=*Info; +#elif defined(_UNIX) + ThSep=*localeconv()->thousands_sep; +#endif + if (ThSep==0) // If failed to detect the actual separator value. + ThSep=' '; + wchar RawText[30]; // 20 characters are enough for largest unsigned 64 bit int. + itoa(n,RawText,ASIZE(RawText)); + uint S=0,D=0,L=wcslen(RawText)%3; + while (RawText[S]!=0 && D+1=7) { diff --git a/deps/unrar/threadmisc.cpp b/deps/unrar/threadmisc.cpp index 742eda41d..7a6ec7822 100644 --- a/deps/unrar/threadmisc.cpp +++ b/deps/unrar/threadmisc.cpp @@ -149,3 +149,5 @@ uint GetNumberOfThreads() return NumCPU; } + + diff --git a/deps/unrar/timefn.cpp b/deps/unrar/timefn.cpp index e86d41a11..0abf49de9 100644 --- a/deps/unrar/timefn.cpp +++ b/deps/unrar/timefn.cpp @@ -273,12 +273,12 @@ void RarTime::SetAgeText(const wchar *TimeText) uint Seconds=0,Value=0; for (uint I=0;TimeText[I]!=0;I++) { - int Ch=TimeText[I]; + wchar Ch=TimeText[I]; if (IsDigit(Ch)) Value=Value*10+Ch-'0'; else { - switch(etoupper(Ch)) + switch(etoupperw(Ch)) { case 'D': Seconds+=Value*24*3600; diff --git a/deps/unrar/timefn.hpp b/deps/unrar/timefn.hpp index 527136164..49b61e85d 100644 --- a/deps/unrar/timefn.hpp +++ b/deps/unrar/timefn.hpp @@ -22,6 +22,17 @@ class RarTime // Internal time representation in 1/TICKS_PER_SECOND since 01.01.1601. // We use nanoseconds here to handle the high precision Unix time. + // It allows dates up to July 2185. + // + // If we'll ever need to extend the date range, we can define a lower + // precision Windows version of TICKS_PER_SECOND. But then Unix and Windows + // versions can differ in least significant digits of "lt" time output + // for Unix archives. + // Alternatively we can introduce 'bool HighPrecision' set to true + // in SetUnixNS() and TicksPerSecond() instead of constant above. + // It might be more reliable than defining TicksPerSecond variable, + // which wouldn't survive memset of any structure hosting RarTime. + // We would need to eliminate all such memsets in the entire code first. uint64 itime; public: // RarLocalTime::Reminder precision. Must be equal to TICKS_PER_SECOND. diff --git a/deps/unrar/ui.hpp b/deps/unrar/ui.hpp index 2654387c2..5def26df1 100644 --- a/deps/unrar/ui.hpp +++ b/deps/unrar/ui.hpp @@ -39,7 +39,7 @@ enum UIMESSAGE_CODE { UIERROR_UOWNERBROKEN, UIERROR_UOWNERGETOWNERID, UIERROR_UOWNERGETGROUPID, UIERROR_UOWNERSET, UIERROR_ULINKREAD, UIERROR_ULINKEXIST, UIERROR_OPENPRESERVEATIME, UIERROR_READERRTRUNCATED, UIERROR_READERRCOUNT, - UIERROR_DIRNAMEEXISTS, + UIERROR_DIRNAMEEXISTS,UIERROR_TRUNCPSW,UIERROR_ADJUSTVALUE, UIMSG_FIRST, UIMSG_STRING, UIMSG_BUILD, UIMSG_RRSEARCH, UIMSG_ANALYZEFILEDATA, @@ -49,6 +49,7 @@ enum UIMESSAGE_CODE { UIMSG_CORRECTINGNAME, UIMSG_BADARCHIVE, UIMSG_CREATING, UIMSG_RENAMING, UIMSG_RECVOLCALCCHECKSUM, UIMSG_RECVOLFOUND, UIMSG_RECVOLMISSING, UIMSG_MISSINGVOL, UIMSG_RECONSTRUCTING, UIMSG_CHECKSUM, UIMSG_FAT32SIZE, + UIMSG_SKIPENCARC, UIMSG_FILERENAME, UIWAIT_FIRST, UIWAIT_DISKFULLNEXT, UIWAIT_FCREATEERROR, UIWAIT_BADPSW, @@ -76,7 +77,7 @@ enum UIASKREP_RESULT { }; UIASKREP_RESULT uiAskReplace(wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags); -UIASKREP_RESULT uiAskReplaceEx(RAROptions *Cmd,wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags); +UIASKREP_RESULT uiAskReplaceEx(CommandData *Cmd,wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags); void uiInit(SOUND_NOTIFY_MODE Sound); @@ -87,7 +88,7 @@ void uiExtractProgress(int64 CurFileSize,int64 TotalFileSize,int64 CurSize,int64 void uiProcessProgress(const char *Command,int64 CurSize,int64 TotalSize); enum UIPASSWORD_TYPE {UIPASSWORD_GLOBAL,UIPASSWORD_FILE,UIPASSWORD_ARCHIVE}; -bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password); +bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password,CheckPassword *CheckPwd); bool uiIsGlobalPasswordSet(); enum UIALARM_TYPE {UIALARM_ERROR, UIALARM_INFO, UIALARM_QUESTION}; @@ -144,30 +145,31 @@ class uiMsgStore // Templates recognize usual NULL as integer, not wchar*. #define UINULL ((wchar *)NULL) -inline void uiMsg(UIMESSAGE_CODE Code) +inline void uiMsgBase(uiMsgStore &Store) { - uiMsgStore Store(Code); - Store.Msg(); + // Called last, when no parameters are left. } -template void uiMsg(UIMESSAGE_CODE Code,T1 a1) +template void uiMsgBase(uiMsgStore &Store,T1&& a1,TN&&... aN) { - uiMsgStore Store(Code); + // Process first parameter and pass the rest to same uiMsgBase. Store< void uiMsg(UIMESSAGE_CODE Code,T1 a1,T2 a2) -{ - uiMsgStore Store(Code); - Store< void uiMsg(UIMESSAGE_CODE code,T1 a1,T2 a2,T3 a3) +// Use variadic templates. +// +// We must pass variable parameters by reference, so no temporary copies are +// created for custom string objects like CStringBase in 7-Zip decompression +// code. Such temporary copies would be destroyed inside of recursive +// uiMsgBase calls, leaving us with Str[] items pointing at released memory. +// Since we pass integer values as well, we can't use & references +// and must resort to && rvalue references. +template void uiMsg(UIMESSAGE_CODE Code,TN&&... aN) { - uiMsgStore Store(code); - Store<Overwrite==OVERWRITE_NONE) return UIASKREP_R_SKIP; diff --git a/deps/unrar/uiconsole.cpp b/deps/unrar/uiconsole.cpp index ceae1a7c5..b1ac51322 100644 --- a/deps/unrar/uiconsole.cpp +++ b/deps/unrar/uiconsole.cpp @@ -71,7 +71,10 @@ bool uiStartFileExtract(const wchar *FileName,bool Extract,bool Test,bool Skip) void uiExtractProgress(int64 CurFileSize,int64 TotalFileSize,int64 CurSize,int64 TotalSize) { - int CurPercent=ToPercent(CurSize,TotalSize); + // We set the total size to 0 to update only the current progress and keep + // the total progress intact in WinRAR. Unlike WinRAR, console RAR has only + // the total progress and updates it with current values in such case. + int CurPercent=TotalSize!=0 ? ToPercent(CurSize,TotalSize) : ToPercent(CurFileSize,TotalFileSize); mprintf(L"\b\b\b\b%3d%%",CurPercent); } @@ -247,6 +250,9 @@ void uiMsgStore::Msg() mprintf(L"\n"); // Needed when called from CmdExtract::ExtractCurrentFile. break; #ifndef SFX_MODULE + case UIERROR_OPFAILED: + Log(NULL,St(MOpFailed)); + break; case UIERROR_NEWRARFORMAT: Log(Str[0],St(MNewRarFormat)); break; @@ -256,6 +262,7 @@ void uiMsgStore::Msg() break; case UIERROR_MISSINGVOL: Log(Str[0],St(MAbsNextVol),Str[0]); + mprintf(L" "); // For progress percent. break; #ifndef SFX_MODULE case UIERROR_NEEDPREVVOL: @@ -329,6 +336,13 @@ void uiMsgStore::Msg() case UIERROR_DIRNAMEEXISTS: Log(NULL,St(MDirNameExists)); break; + case UIERROR_TRUNCPSW: + eprintf(St(MTruncPsw),Num[0]); + eprintf(L"\n"); + break; + case UIERROR_ADJUSTVALUE: + Log(NULL,St(MAdjustValue),Str[0],Str[1]); + break; #ifndef SFX_MODULE case UIMSG_STRING: @@ -369,6 +383,9 @@ void uiMsgStore::Msg() mprintf(St(MFAT32Size)); mprintf(L" "); // For progress percent. break; + case UIMSG_SKIPENCARC: + Log(NULL,St(MSkipEncArc),Str[0]); + break; @@ -379,7 +396,8 @@ void uiMsgStore::Msg() } -bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password) +bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName, + SecPassword *Password,CheckPassword *CheckPwd) { // Unlike GUI we cannot provide Cancel button here, so we use the empty // password to abort. Otherwise user not knowing a password would need to diff --git a/deps/unrar/uisilent.cpp b/deps/unrar/uisilent.cpp index 1df097566..815588574 100644 --- a/deps/unrar/uisilent.cpp +++ b/deps/unrar/uisilent.cpp @@ -33,7 +33,8 @@ void uiMsgStore::Msg() } -bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password) +bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName, + SecPassword *Password,CheckPassword *CheckPwd) { return false; } diff --git a/deps/unrar/ulinks.cpp b/deps/unrar/ulinks.cpp index d198f2e06..141a97fec 100644 --- a/deps/unrar/ulinks.cpp +++ b/deps/unrar/ulinks.cpp @@ -50,7 +50,28 @@ static bool IsFullPath(const char *PathA) // Unix ASCII version. } -bool ExtractUnixLink30(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName) +// For security purpose we prefer to be sure that CharToWide completed +// successfully and even if it truncated a string for some reason, +// it didn't affect the number of path related characters we analyze +// in IsRelativeSymlinkSafe later. +// This check is likely to be excessive, but let's keep it anyway. +static bool SafeCharToWide(const char *Src,wchar *Dest,size_t DestSize) +{ + if (!CharToWide(Src,Dest,DestSize) || *Dest==0) + return false; + uint SrcChars=0,DestChars=0; + for (uint I=0;Src[I]!=0;I++) + if (Src[I]=='/' || Src[I]=='.') + SrcChars++; + for (uint I=0;Dest[I]!=0;I++) + if (Dest[I]=='/' || Dest[I]=='.') + DestChars++; + return SrcChars==DestChars; +} + + +static bool ExtractUnixLink30(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc, + const wchar *LinkName,bool &UpLink) { char Target[NM]; if (IsLink(Arc.FileHead.FileAttr)) @@ -72,21 +93,22 @@ bool ExtractUnixLink30(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const w return true; wchar TargetW[NM]; - CharToWide(Target,TargetW,ASIZE(TargetW)); - // Check for *TargetW==0 to catch CharToWide failure. + if (!SafeCharToWide(Target,TargetW,ASIZE(TargetW))) + return false; // Use Arc.FileHead.FileName instead of LinkName, since LinkName // can include the destination path as a prefix, which can // confuse IsRelativeSymlinkSafe algorithm. - if (!Cmd->AbsoluteLinks && (*TargetW==0 || IsFullPath(TargetW) || + if (!Cmd->AbsoluteLinks && (IsFullPath(TargetW) || !IsRelativeSymlinkSafe(Cmd,Arc.FileHead.FileName,LinkName,TargetW))) return false; + UpLink=strstr(Target,"..")!=NULL; return UnixSymlink(Cmd,Target,LinkName,&Arc.FileHead.mtime,&Arc.FileHead.atime); } return false; } -bool ExtractUnixLink50(CommandData *Cmd,const wchar *Name,FileHeader *hd) +static bool ExtractUnixLink50(CommandData *Cmd,const wchar *Name,FileHeader *hd) { char Target[NM]; WideToChar(hd->RedirName,Target,ASIZE(Target)); @@ -100,11 +122,15 @@ bool ExtractUnixLink50(CommandData *Cmd,const wchar *Name,FileHeader *hd) return false; DosSlashToUnix(Target,Target,ASIZE(Target)); } + + wchar TargetW[NM]; + if (!SafeCharToWide(Target,TargetW,ASIZE(TargetW))) + return false; // Use hd->FileName instead of LinkName, since LinkName can include // the destination path as a prefix, which can confuse // IsRelativeSymlinkSafe algorithm. - if (!Cmd->AbsoluteLinks && (IsFullPath(Target) || - !IsRelativeSymlinkSafe(Cmd,hd->FileName,Name,hd->RedirName))) + if (!Cmd->AbsoluteLinks && (IsFullPath(TargetW) || + !IsRelativeSymlinkSafe(Cmd,hd->FileName,Name,TargetW))) return false; return UnixSymlink(Cmd,Target,Name,&hd->mtime,&hd->atime); } diff --git a/deps/unrar/unicode.cpp b/deps/unrar/unicode.cpp index 641f6c892..73b09bb22 100644 --- a/deps/unrar/unicode.cpp +++ b/deps/unrar/unicode.cpp @@ -229,10 +229,11 @@ void CharToWideMap(const char *Src,wchar *Dest,size_t DestSize,bool &Success) #endif -// SrcSize is in wide characters, not in bytes. -byte* WideToRaw(const wchar *Src,byte *Dest,size_t SrcSize) +// SrcSize is source data size in wide characters, not in bytes. +// DestSize is the maximum allowed destination size. +byte* WideToRaw(const wchar *Src,size_t SrcSize,byte *Dest,size_t DestSize) { - for (size_t I=0;I>8); @@ -601,59 +602,6 @@ char* SupportDBCS::charnext(const char *s) // to break string processing loops. return (char *)(IsLeadByte[(byte)*s] && s[1]!=0 ? s+2:s+1); } - - -size_t SupportDBCS::strlend(const char *s) -{ - size_t Length=0; - while (*s!=0) - { - if (IsLeadByte[(byte)*s]) - s+=2; - else - s++; - Length++; - } - return(Length); -} - - -char* SupportDBCS::strchrd(const char *s, int c) -{ - while (*s!=0) - if (IsLeadByte[(byte)*s]) - s+=2; - else - if (*s==c) - return((char *)s); - else - s++; - return(NULL); -} - - -void SupportDBCS::copychrd(char *dest,const char *src) -{ - dest[0]=src[0]; - if (IsLeadByte[(byte)src[0]]) - dest[1]=src[1]; -} - - -char* SupportDBCS::strrchrd(const char *s, int c) -{ - const char *found=NULL; - while (*s!=0) - if (IsLeadByte[(byte)*s]) - s+=2; - else - { - if (*s==c) - found=s; - s++; - } - return((char *)found); -} #endif diff --git a/deps/unrar/unicode.hpp b/deps/unrar/unicode.hpp index 031ac09ab..9bfd9c5dc 100644 --- a/deps/unrar/unicode.hpp +++ b/deps/unrar/unicode.hpp @@ -7,7 +7,7 @@ bool WideToChar(const wchar *Src,char *Dest,size_t DestSize); bool CharToWide(const char *Src,wchar *Dest,size_t DestSize); -byte* WideToRaw(const wchar *Src,byte *Dest,size_t SrcSize); +byte* WideToRaw(const wchar *Src,size_t SrcSize,byte *Dest,size_t DestSize); wchar* RawToWide(const byte *Src,wchar *Dest,size_t DestSize); void WideToUtf(const wchar *Src,char *Dest,size_t DestSize); size_t WideToUtfSize(const wchar *Src); @@ -33,34 +33,19 @@ class SupportDBCS public: SupportDBCS(); void Init(); - char* charnext(const char *s); - size_t strlend(const char *s); - char *strchrd(const char *s, int c); - char *strrchrd(const char *s, int c); - void copychrd(char *dest,const char *src); bool IsLeadByte[256]; bool DBCSMode; }; - extern SupportDBCS gdbcs; inline char* charnext(const char *s) {return (char *)(gdbcs.DBCSMode ? gdbcs.charnext(s):s+1);} -inline size_t strlend(const char *s) {return (uint)(gdbcs.DBCSMode ? gdbcs.strlend(s):strlen(s));} -inline char* strchrd(const char *s, int c) {return (char *)(gdbcs.DBCSMode ? gdbcs.strchrd(s,c):strchr(s,c));} -inline char* strrchrd(const char *s, int c) {return (char *)(gdbcs.DBCSMode ? gdbcs.strrchrd(s,c):strrchr(s,c));} -inline void copychrd(char *dest,const char *src) {if (gdbcs.DBCSMode) gdbcs.copychrd(dest,src); else *dest=*src;} -inline bool IsDBCSMode() {return(gdbcs.DBCSMode);} -inline void InitDBCS() {gdbcs.Init();} +inline bool IsDBCSMode() {return gdbcs.DBCSMode;} #else #define charnext(s) ((s)+1) -#define strlend strlen -#define strchrd strchr -#define strrchrd strrchr -#define IsDBCSMode() (true) -inline void copychrd(char *dest,const char *src) {*dest=*src;} +#define IsDBCSMode() (false) #endif diff --git a/deps/unrar/unpack.cpp b/deps/unrar/unpack.cpp index 5f577d85d..1597505ea 100644 --- a/deps/unrar/unpack.cpp +++ b/deps/unrar/unpack.cpp @@ -16,7 +16,7 @@ #include "unpack50frag.cpp" Unpack::Unpack(ComprDataIO *DataIO) -:Inp(false),VMCodeInp(false) +:Inp(true),VMCodeInp(true) { UnpIO=DataIO; Window=NULL; @@ -49,8 +49,8 @@ Unpack::~Unpack() { InitFilters30(false); - //if (Window!=NULL) - // free(Window); + if (Window!=NULL) + free(Window); #ifdef RAR_SMP delete UnpThreadPool; delete[] ReadBufMT; @@ -117,7 +117,7 @@ void Unpack::Init(size_t WinSize,bool Solid) if (Grow && Fragmented) throw std::bad_alloc(); - byte *NewWindow=Fragmented ? NULL : (byte *)hcwin; + byte *NewWindow=Fragmented ? NULL : (byte *)malloc(WinSize); if (NewWindow==NULL) if (Grow || WinSize<0x1000000) @@ -130,7 +130,7 @@ void Unpack::Init(size_t WinSize,bool Solid) { if (Window!=NULL) // If allocated by preceding files. { - //free(Window); + free(Window); Window=NULL; } FragWindow.Init(WinSize); @@ -141,7 +141,7 @@ void Unpack::Init(size_t WinSize,bool Solid) { // Clean the window to generate the same output when unpacking corrupt // RAR files, which may access unused areas of sliding dictionary. - //memset(NewWindow,0,WinSize); + memset(NewWindow,0,WinSize); // If Window is not NULL, it means that window size has grown. // In solid streams we need to copy data to a new window in such case. @@ -151,8 +151,8 @@ void Unpack::Init(size_t WinSize,bool Solid) for (size_t I=1;I<=MaxWinSize;I++) NewWindow[(UnpPtr-I)&(WinSize-1)]=Window[(UnpPtr-I)&(MaxWinSize-1)]; - //if (Window!=NULL) - // free(Window); + if (Window!=NULL) + free(Window); Window=NewWindow; } @@ -324,7 +324,7 @@ void Unpack::MakeDecodeTables(byte *LengthTable,DecodeTable *Dec,uint Size) Dec->QuickBits=MAX_QUICK_DECODE_BITS; break; default: - Dec->QuickBits=MAX_QUICK_DECODE_BITS-3; + Dec->QuickBits=MAX_QUICK_DECODE_BITS>3 ? MAX_QUICK_DECODE_BITS-3 : 0; break; } diff --git a/deps/unrar/unpack.hpp b/deps/unrar/unpack.hpp index f76ddcc86..3e23cd320 100644 --- a/deps/unrar/unpack.hpp +++ b/deps/unrar/unpack.hpp @@ -23,8 +23,8 @@ // allocation. Must be equal or larger than MAX_ANALYZE_SIZE. #define MAX_FILTER_BLOCK_SIZE 0x400000 -// Write data in 4 MB or smaller blocks. Must not exceed PACK_MAX_WRITE, -// so we keep a number of buffered filters in unpacker reasonable. +// Write data in 4 MB or smaller blocks. Must not exceed PACK_MAX_READ, +// so we keep the number of buffered filters in unpacker reasonable. #define UNPACK_MAX_WRITE 0x400000 // Decode compressed bit fields to alphabet numbers. @@ -93,17 +93,17 @@ struct UnpackBlockTables #ifdef RAR_SMP enum UNP_DEC_TYPE { - UNPDT_LITERAL,UNPDT_MATCH,UNPDT_FULLREP,UNPDT_REP,UNPDT_FILTER + UNPDT_LITERAL=0,UNPDT_MATCH,UNPDT_FULLREP,UNPDT_REP,UNPDT_FILTER }; struct UnpackDecodedItem { - UNP_DEC_TYPE Type; + byte Type; // 'byte' instead of enum type to reduce memory use. ushort Length; union { uint Distance; - byte Literal[4]; + byte Literal[8]; // Store up to 8 chars here to speed up extraction. }; }; diff --git a/deps/unrar/unpack30.cpp b/deps/unrar/unpack30.cpp index 346bcf970..7c2adfab2 100644 --- a/deps/unrar/unpack30.cpp +++ b/deps/unrar/unpack30.cpp @@ -55,7 +55,7 @@ void Unpack::Unpack29(bool Solid) if (!UnpReadBuf30()) break; } - if (((WrPtr-UnpPtr) & MaxWinMask)<260 && WrPtr!=UnpPtr) + if (((WrPtr-UnpPtr) & MaxWinMask)<=MAX3_INC_LZ_MATCH && WrPtr!=UnpPtr) { UnpWriteBuf30(); if (WrittenFileSize>DestUnpSize) @@ -637,7 +637,7 @@ bool Unpack::ReadTables30() if (BitField & 0x8000) { UnpBlockType=BLOCK_PPM; - return(PPM.DecodeInit(this,PPMEscChar,hcppm)); + return(PPM.DecodeInit(this,PPMEscChar)); } UnpBlockType=BLOCK_LZ; diff --git a/deps/unrar/unpack50.cpp b/deps/unrar/unpack50.cpp index 99119507f..e040907c2 100644 --- a/deps/unrar/unpack50.cpp +++ b/deps/unrar/unpack50.cpp @@ -42,7 +42,7 @@ void Unpack::Unpack5(bool Solid) break; } - if (((WriteBorder-UnpPtr) & MaxWinMask)DestUnpSize) @@ -93,7 +93,7 @@ void Unpack::Unpack5(bool Solid) } else { - Distance+=Inp.getbits32()>>(32-DBits); + Distance+=Inp.getbits()>>(16-DBits); Inp.addbits(DBits); } } diff --git a/deps/unrar/unpack50mt.cpp b/deps/unrar/unpack50mt.cpp index 691ac8e99..82c9c4a8c 100644 --- a/deps/unrar/unpack50mt.cpp +++ b/deps/unrar/unpack50mt.cpp @@ -345,7 +345,7 @@ void Unpack::UnpackDecode(UnpackThreadData &D) if (D.DecodedSize>1) { UnpackDecodedItem *PrevItem=CurItem-1; - if (PrevItem->Type==UNPDT_LITERAL && PrevItem->Length<3) + if (PrevItem->Type==UNPDT_LITERAL && PrevItem->LengthLiteral)-1) { PrevItem->Length++; PrevItem->Literal[PrevItem->Length]=(byte)MainSlot; @@ -388,7 +388,7 @@ void Unpack::UnpackDecode(UnpackThreadData &D) } else { - Distance+=D.Inp.getbits32()>>(32-DBits); + Distance+=D.Inp.getbits()>>(16-DBits); D.Inp.addbits(DBits); } } @@ -451,7 +451,7 @@ bool Unpack::ProcessDecoded(UnpackThreadData &D) while (ItemDestUnpSize) @@ -461,10 +461,10 @@ bool Unpack::ProcessDecoded(UnpackThreadData &D) if (Item->Type==UNPDT_LITERAL) { #if defined(LITTLE_ENDIAN) && defined(ALLOW_MISALIGNED) - if (Item->Length==3 && UnpPtrLength==7 && UnpPtrLiteral; - UnpPtr+=4; + *(uint64 *)(Window+UnpPtr)=*(uint64 *)(Item->Literal); + UnpPtr+=8; } else #endif @@ -559,7 +559,7 @@ bool Unpack::UnpackLargeBlock(UnpackThreadData &D) break; } } - if (((WriteBorder-UnpPtr) & MaxWinMask)DestUnpSize) diff --git a/deps/unrar/version.hpp b/deps/unrar/version.hpp index 922c67ed8..9af752ed0 100644 --- a/deps/unrar/version.hpp +++ b/deps/unrar/version.hpp @@ -1,6 +1,6 @@ #define RARVER_MAJOR 6 -#define RARVER_MINOR 1 -#define RARVER_BETA 0 -#define RARVER_DAY 7 -#define RARVER_MONTH 4 -#define RARVER_YEAR 2021 +#define RARVER_MINOR 22 +#define RARVER_BETA 1 +#define RARVER_DAY 14 +#define RARVER_MONTH 5 +#define RARVER_YEAR 2023 diff --git a/deps/unrar/volume.cpp b/deps/unrar/volume.cpp index 001a9673a..4924d8d0e 100644 --- a/deps/unrar/volume.cpp +++ b/deps/unrar/volume.cpp @@ -1,15 +1,15 @@ #include "rar.hpp" #ifdef RARDLL -static bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize); -static bool DllVolNotify(RAROptions *Cmd,wchar *NextName); +static bool DllVolChange(CommandData *Cmd,wchar *NextName,size_t NameSize); +static bool DllVolNotify(CommandData *Cmd,wchar *NextName); #endif bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Command) { - RAROptions *Cmd=Arc.GetRAROptions(); + CommandData *Cmd=Arc.GetCommandData(); HEADER_TYPE HeaderType=Arc.GetHeaderType(); FileHeader *hd=HeaderType==HEAD_SERVICE ? &Arc.SubHead:&Arc.FileHead; @@ -25,10 +25,12 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma uiMsg(UIERROR_CHECKSUMPACKED, Arc.FileName, hd->FileName); } + bool PrevVolEncrypted=Arc.Encrypted; + int64 PosBeforeClose=Arc.Tell(); if (DataIO!=NULL) - DataIO->ProcessedArcSize+=Arc.FileLength(); + DataIO->ProcessedArcSize+=DataIO->LastArcSize; Arc.Close(); @@ -40,12 +42,20 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma #if !defined(SFX_MODULE) && !defined(RARDLL) bool RecoveryDone=false; #endif - bool FailedOpen=false,OldSchemeTested=false; + bool OldSchemeTested=false; + bool FailedOpen=false; // No more next volume open attempts if true. #if !defined(SILENT) // In -vp mode we force the pause before next volume even if it is present // and even if we are on the hard disk. It is important when user does not // want to process partially downloaded volumes preliminary. + // 2022.01.11: In WinRAR 6.10 beta versions we tried to ignore VolumePause + // if we could open the next volume with FMF_OPENEXCLUSIVE. But another + // developer asked us to return the previous behavior and always prompt + // for confirmation. They want to control when unrar continues, because + // the next file might not be fully decoded yet. They write chunks of data + // and then close the file again until the next chunk comes in. + if (Cmd->VolumePause && !uiAskNextVolume(NextName,ASIZE(NextName))) FailedOpen=true; #endif @@ -127,6 +137,16 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma return false; #endif + if (Arc.Encrypted!=PrevVolEncrypted) + { + // There is no legitimate reason for encrypted header state to be + // changed in the middle of volume sequence. So we abort here to prevent + // replacing an encrypted header volume to unencrypted and adding + // unexpected files by third party to encrypted extraction. + uiMsg(UIERROR_BADARCHIVE,Arc.FileName); + ErrHandler.Exit(RARX_FATAL); + } + if (SplitHeader) Arc.SearchBlock(HeaderType); else @@ -151,10 +171,9 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma DataIO->UnpVolume=hd->SplitAfter; DataIO->SetPackedSizeToRead(hd->PackSize); } -#ifdef SFX_MODULE - DataIO->UnpArcSize=Arc.FileLength(); -#endif - + + DataIO->AdjustTotalArcSize(&Arc); + // Reset the size of packed data read from current volume. It is used // to display the total progress and preceding volumes are already // compensated with ProcessedArcSize, so we need to reset this variable. @@ -171,14 +190,7 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma #ifdef RARDLL -#if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64) -// Disable the run time stack check for unrar.dll, so we can manipulate -// with ChangeVolProc call type below. Run time check would intercept -// a wrong ESP before we restore it. -#pragma runtime_checks( "s", off ) -#endif - -bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize) +bool DllVolChange(CommandData *Cmd,wchar *NextName,size_t NameSize) { bool DllVolChanged=false,DllVolAborted=false; @@ -212,28 +224,7 @@ bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize) { char NextNameA[NM]; WideToChar(NextName,NextNameA,ASIZE(NextNameA)); - // Here we preserve ESP value. It is necessary for those developers, - // who still define ChangeVolProc callback as "C" type function, - // even though in year 2001 we announced in unrar.dll whatsnew.txt - // that it will be PASCAL type (for compatibility with Visual Basic). -#if defined(_MSC_VER) -#ifndef _WIN_64 - __asm mov ebx,esp -#endif -#elif defined(_WIN_ALL) && defined(__BORLANDC__) - _EBX=_ESP; -#endif int RetCode=Cmd->ChangeVolProc(NextNameA,RAR_VOL_ASK); - - // Restore ESP after ChangeVolProc with wrongly defined calling - // convention broken it. -#if defined(_MSC_VER) -#ifndef _WIN_64 - __asm mov esp,ebx -#endif -#elif defined(_WIN_ALL) && defined(__BORLANDC__) - _ESP=_EBX; -#endif if (RetCode==0) DllVolAborted=true; else @@ -255,7 +246,7 @@ bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize) #ifdef RARDLL -bool DllVolNotify(RAROptions *Cmd,wchar *NextName) +bool DllVolNotify(CommandData *Cmd,wchar *NextName) { char NextNameA[NM]; WideToChar(NextName,NextNameA,ASIZE(NextNameA)); @@ -268,21 +259,10 @@ bool DllVolNotify(RAROptions *Cmd,wchar *NextName) } if (Cmd->ChangeVolProc!=NULL) { -#if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__) - _EBX=_ESP; -#endif int RetCode=Cmd->ChangeVolProc(NextNameA,RAR_VOL_NOTIFY); -#if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__) - _ESP=_EBX; -#endif if (RetCode==0) return false; } return true; } - -#if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64) -// Restore the run time stack check for unrar.dll. -#pragma runtime_checks( "s", restore ) -#endif #endif diff --git a/deps/unrar/volume.hpp b/deps/unrar/volume.hpp index 2d6a6d5c1..4ada10910 100644 --- a/deps/unrar/volume.hpp +++ b/deps/unrar/volume.hpp @@ -1,10 +1,7 @@ #ifndef _RAR_VOLUME_ #define _RAR_VOLUME_ -void SplitArchive(Archive &Arc,FileHeader *fh,int64 *HeaderPos, - ComprDataIO *DataIO); bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName, wchar Command); -void SetVolWrite(Archive &Dest,int64 VolSize); #endif diff --git a/deps/unrar/win32stm.cpp b/deps/unrar/win32stm.cpp index eaa43be2d..048fd86b6 100644 --- a/deps/unrar/win32stm.cpp +++ b/deps/unrar/win32stm.cpp @@ -111,16 +111,23 @@ void ExtractStreams(Archive &Arc,const wchar *FileName,bool TestMode) wcsncatz(FullName,StreamName,ASIZE(FullName)); + FindData fd; - bool Found=FindFile::FastFind(FileName,&fd); + bool HostFound=FindFile::FastFind(FileName,&fd); if ((fd.FileAttr & FILE_ATTRIBUTE_READONLY)!=0) SetFileAttr(FileName,fd.FileAttr & ~FILE_ATTRIBUTE_READONLY); File CurFile; - if (CurFile.WCreate(FullName) && Arc.ReadSubData(NULL,&CurFile,false)) - CurFile.Close(); + + if (CurFile.WCreate(FullName)) + { + if (Arc.ReadSubData(NULL,&CurFile,false)) + CurFile.Close(); + } + + // Restoring original file timestamps. File HostFile; - if (Found && HostFile.Open(FileName,FMF_OPENSHARED|FMF_UPDATE)) + if (HostFound && HostFile.Open(FileName,FMF_OPENSHARED|FMF_UPDATE)) SetFileTime(HostFile.GetHandle(),&fd.ftCreationTime,&fd.ftLastAccessTime, &fd.ftLastWriteTime); diff --git a/docs/changes.txt b/docs/changes.txt index d67ff6ce6..c44adb63b 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -90,6 +90,7 @@ - Fixed minimum password length in module of hash-mode 29800 - Fixed maximum password length in module/test_module of hash-mode 2400 - Fixed buffer overflow on module_26600.c / module_hash_encode() +- Fixed bug in 23800/unrar with Apple Silicon - Fixed vector datatypes usage for HIP ## @@ -101,6 +102,7 @@ - Apple Driver: Updated requirements to use Apple OpenCL API to macOS 13.0 - use - Backend Checks: Describe workaround in error message when detecting more than 64 backend devices - Brain: Added sanity check and corresponding error message for invalid --brain-port values +- Dependencies: Updated unrar source to 6.2.7 - Building: Support building windows binaries on macOS using MinGW - Dependencies: Updated OpenCL-Headers to v2023.04.17 - Documents: Updated BUILD.md and added BUILD_macOS.md (containing instructions for building windows binaries on macOS) diff --git a/src/Makefile b/src/Makefile index 9fc12a311..1cd440645 100644 --- a/src/Makefile +++ b/src/Makefile @@ -217,6 +217,8 @@ ifneq ($(CC),clang) CFLAGS_UNRAR += -Wno-class-memaccess CFLAGS_UNRAR += -Wno-misleading-indentation CFLAGS_UNRAR += -Wno-format-overflow +else +CFLAGS_UNRAR += -std=c++11 endif CFLAGS_UNRAR += -Wno-missing-braces CFLAGS_UNRAR += -Wno-unused-variable @@ -761,6 +763,7 @@ LFLAGS_CROSS_WIN += -lpsapi LFLAGS_CROSS_WIN += -lws2_32 LFLAGS_CROSS_WIN += -lpowrprof LFLAGS_CROSS_WIN += -static -static-libgcc -static-libstdc++ +LFLAGS_CROSS_WIN += -lole32 -loleaut32 -lwbemuuid CFLAGS_LZMA_WIN := $(CFLAGS_LZMA) CFLAGS_UNRAR_WIN := $(CFLAGS_UNRAR)