1
0
mirror of https://github.com/hashcat/hashcat.git synced 2024-11-25 01:18:15 +00:00

Merge pull request #3734 from matrix/fix_rar_segfault_AppleSilicon

Dependencies: Updated unrar source to 6.2.7 | Fixed bug in 23800/unrar with Apple Silicon
This commit is contained in:
Jens Steube 2023-06-21 16:27:16 +02:00 committed by GitHub
commit 11502c77e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
102 changed files with 2930 additions and 1760 deletions

View File

@ -138,7 +138,7 @@
<ExceptionHandling>Sync</ExceptionHandling>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<StructMemberAlignment>Default</StructMemberAlignment>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
@ -168,7 +168,7 @@
<ExceptionHandling>Sync</ExceptionHandling>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<StructMemberAlignment>Default</StructMemberAlignment>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
@ -198,7 +198,7 @@
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<StructMemberAlignment>Default</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
@ -239,7 +239,7 @@
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<StructMemberAlignment>Default</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
@ -274,7 +274,7 @@
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<StructMemberAlignment>Default</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
@ -315,7 +315,7 @@
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<StructMemberAlignment>Default</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<RuntimeTypeInfo>false</RuntimeTypeInfo>

47
deps/unrar/acknow.txt vendored
View File

@ -7,49 +7,16 @@
for samples and ideas allowed to make Reed-Solomon coding
more efficient.
* RAR text compression algorithm is based on Dmitry Shkarin PPMII
* RAR4 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.
You can 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.
* RAR encryption includes parts of public domain code
from Szymon Stefanek AES and Steve Reid SHA-1 implementations.
---------------------------------------------------------------------------
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:
* 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/

View File

@ -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;

View File

@ -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<byte> *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);

View File

@ -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<pwd> 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<pwd> 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,7 +974,9 @@ 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)
{
case MHEXTRA_LOCATOR:
{
hd->Locator=true;
uint Flags=(uint)Raw->GetV();
@ -987,6 +993,39 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
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<char> 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<wchar> 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;
}
}
if (bb->HeaderType==HEAD_FILE || bb->HeaderType==HEAD_SERVICE)
@ -1441,7 +1480,9 @@ bool Archive::ReadSubData(Array<byte> *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;
}

30
deps/unrar/array.hpp vendored
View File

@ -10,7 +10,6 @@ template <class T> 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 T> class Array
void Alloc(size_t Items);
void Reset();
void SoftReset();
void operator = (Array<T> &Src);
Array<T>& operator = (const Array<T> &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 <class T> void Array<T>::CleanData()
BufSize=0;
AllocSize=0;
MaxSize=0;
Secure=false;
}
@ -71,11 +68,7 @@ template <class T> Array<T>::Array(const Array &Src)
template <class T> Array<T>::~Array()
{
if (Buffer!=NULL)
{
if (Secure)
cleandata(Buffer,AllocSize*sizeof(T));
free(Buffer);
}
}
@ -111,25 +104,9 @@ template <class T> void Array<T>::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));
T *NewBuffer=(T *)realloc(Buffer,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();
}
Buffer=NewBuffer;
AllocSize=NewSize;
}
@ -165,12 +142,13 @@ template <class T> void Array<T>::SoftReset()
}
template <class T> void Array<T>::operator =(Array<T> &Src)
template <class T> Array<T>& Array<T>::operator =(const Array<T> &Src)
{
Reset();
Alloc(Src.BufSize);
if (Src.BufSize!=0)
memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T));
return *this;
}

View File

@ -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];

View File

@ -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)
{

View File

@ -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<int64> NextVolSizes;
};
#endif

View File

@ -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;

23
deps/unrar/cmdmix.cpp vendored
View File

@ -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;

View File

@ -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} */

61
deps/unrar/consio.cpp vendored
View File

@ -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<char> 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)
{

View File

@ -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

171
deps/unrar/crc.cpp vendored
View File

@ -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<DataEnd; Data+=8 )
{
uint64 Index=StartCRC;
#ifdef BIG_ENDIAN
Index ^= (uint64(Data[0])|(uint64(Data[1])<<8)|(uint64(Data[2])<<16)|(uint64(Data[3])<<24))|
(uint64(Data[4])<<32)|(uint64(Data[5])<<40)|(uint64(Data[6])<<48)|(uint64(Data[7])<<56);
#else
Index ^= *(uint64 *)Data;
#endif
StartCRC = crc64_tables[ 7 ] [ ( byte ) (Index ) ] ^
crc64_tables[ 6 ] [ ( byte ) (Index >> 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;I<FirstSize;I++)
b[I]=(byte)I;
uint r32=CRC32(0xffffffff,b,FirstSize);
for (uint I=FirstSize;I<1024;I++)
{
b[0]=(byte)I;
r32=CRC32(r32,b,1);
}
if ((r32^0xffffffff)==0xB70B4C26)
mprintf(L"\nCRC32 test4 OK");
else
mprintf(L"\nCRC32 test4 FAILED");
if ((CRC64(0xffffffffffffffff,(byte*)"testtesttest",12)^0xffffffffffffffff)==0x7B1C2D230EDEB436)
mprintf(L"\nCRC64 test1 OK");
else
mprintf(L"\nCRC64 test1 FAILED");
if (CRC64(0,(byte*)"te\x80st",5)==0xB5DBF9583A6EED4A)
mprintf(L"\nCRC64 test2 OK");
else
mprintf(L"\nCRC64 test2 FAILED");
for (uint I=0;I<14;I++) // Check for possible int sign extension.
b[I]=(byte)0x7f+I;
if ((CRC64(0xffffffffffffffff,b,14)^0xffffffffffffffff)==0xE019941C05B2820C)
mprintf(L"\nCRC64 test3 OK");
else
mprintf(L"\nCRC64 test3 FAILED");
for (uint I=0;I<FirstSize;I++)
b[I]=(byte)I;
uint64 r64=CRC64(0xffffffffffffffff,b,FirstSize);
for (uint I=FirstSize;I<1024;I++)
{
b[0]=(byte)I;
r64=CRC64(r64,b,1);
}
if ((r64^0xffffffffffffffff)==0xD51FB58DC789C400)
mprintf(L"\nCRC64 test4 OK");
else
mprintf(L"\nCRC64 test4 FAILED");
const size_t BufSize=0x100000;
byte *Buf=new byte[BufSize];
memset(Buf,0,BufSize);
clock_t StartTime=clock();
r32=0xffffffff;
const uint BufCount=5000;
for (uint I=0;I<BufCount;I++)
r32=CRC32(r32,Buf,BufSize);
if (r32!=0) // Otherwise compiler optimizer removes CRC calculation.
mprintf(L"\nCRC32 speed: %d MB/s",BufCount*1000/(clock()-StartTime));
StartTime=clock();
r64=0xffffffffffffffff;
for (uint I=0;I<BufCount;I++)
r64=CRC64(r64,Buf,BufSize);
if (r64!=0) // Otherwise compiler optimizer removes CRC calculation.
mprintf(L"\nCRC64 speed: %d MB/s",BufCount*1000/(clock()-StartTime));
}
#endif
#endif

4
deps/unrar/crc.hpp vendored
View File

@ -11,5 +11,9 @@ uint CRC32(uint StartCRC,const void *Addr,size_t Size);
ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size);
#endif
#if 0
void InitCRC64(uint64 *CRCTab);
uint64 CRC64(uint64 StartCRC,const void *Addr,size_t Size);
#endif
#endif

14
deps/unrar/crypt.cpp vendored
View File

@ -11,21 +11,12 @@
CryptData::CryptData()
{
Method=CRYPT_NONE;
memset(KDF3Cache,0,sizeof(KDF3Cache));
memset(KDF5Cache,0,sizeof(KDF5Cache));
KDF3CachePos=0;
KDF5CachePos=0;
memset(CRCTab,0,sizeof(CRCTab));
}
CryptData::~CryptData()
{
cleandata(KDF3Cache,sizeof(KDF3Cache));
cleandata(KDF5Cache,sizeof(KDF5Cache));
}
void CryptData::DecryptBlock(byte *Buf,size_t Size)
@ -56,15 +47,18 @@ bool CryptData::SetCryptKeys(bool Encrypt,CRYPT_METHOD Method,
SecPassword *Password,const byte *Salt,
const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck)
{
if (!Password->IsSet() || 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)
{

72
deps/unrar/crypt.hpp vendored
View File

@ -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,

View File

@ -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);

12
deps/unrar/crypt5.cpp vendored
View File

@ -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;I<ASIZE(KDF5Cache);I++)
{
KDF5CacheItem *Item=KDF5Cache+I;
if (Item->Lg2Count==Lg2Cnt && Item->Pwd==*Password &&
if (Item->Pwd==*Password && Item->Lg2Count==Lg2Cnt &&
memcmp(Item->Salt,Salt,SIZE_SALT50)==0)
{
memcpy(Key,Item->Key,sizeof(Key));

10
deps/unrar/dll.rc vendored
View File

@ -2,8 +2,8 @@
#include <commctrl.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION 6, 1, 100, 3756
PRODUCTVERSION 6, 1, 100, 3756
FILEVERSION 6, 22, 1, 865
PRODUCTVERSION 6, 22, 1, 865
FILEOS VOS__WINDOWS32
FILETYPE VFT_APP
{
@ -14,9 +14,9 @@ FILETYPE VFT_APP
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 "FileVersion", "6.22.1\0"
VALUE "ProductVersion", "6.22.1\0"
VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2023\0"
VALUE "OriginalFilename", "Unrar.dll\0"
}
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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 && I<LastChecked.size() && Path[I]==LastChecked[I];I++)
if (IsPathDiv(Path[I]) && I>SkipLength)
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)

View File

@ -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

485
deps/unrar/extract.cpp vendored
View File

@ -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;I<RefList.Size();I++)
{
// We can have undeleted temporary reference source here if extraction
// was interrupted early or if user refused to overwrite prompt.
if (RefList[I].TmpName!=NULL)
DelFile(RefList[I].TmpName);
free(RefList[I].RefName);
free(RefList[I].TmpName);
}
RefList.Reset();
memset(Analyze,0,sizeof(*Analyze));
}
@ -30,10 +69,13 @@ void CmdExtract::DoExtract()
PasswordCancelled=false;
DataIO.SetCurrentCommand(Cmd->Command[0]);
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 (*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,15 +214,28 @@ 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;
}
@ -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;I<RefList.Size();I++)
if (wcscmp(ArcFileName,RefList[I].RefName)==0)
{
ExtractRef *MatchedRef=&RefList[I];
if (!Cmd->Test) // 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,6 +528,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
if (!uiStartFileExtract(ArcFileName,!Cmd->Test,Cmd->Test && Command!='I',SkipSolid))
return false;
if (!RefTarget)
ExtrPrepareName(Arc,ArcFileName,DestFileName,ASIZE(DestFileName));
// DestFileName can be set empty in case of excessive -ap switch.
@ -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)
{
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,20 +582,19 @@ 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)
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
ConvertDosPassword(Arc,FilePassword);
#endif
#endif
byte PswCheck[SIZE_PSWCHECK];
DataIO.SetEncryption(false,Arc.FileHead.CryptMethod,&FilePassword,
@ -483,9 +604,8 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
// 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 (Arc.FileHead.UsePswCheck && !Arc.BrokenHeader &&
memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0)
{
if (GlobalPassword) // For -p<pwd> or Ctrl+P to avoid the infinite loop.
{
@ -502,35 +622,43 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
// Avoid new requests for unrar.dll to prevent the infinite loop
// if app always returns the same password.
#ifndef RARDLL
#ifndef RARDLL
continue; // Request a password again.
#endif
#endif
}
#ifdef RARDLL
#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
#endif
ErrHandler.SetErrorCode(RARX_BADPWD);
ExtrFile=false;
}
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,13 +1004,54 @@ 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))
{
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;I<RefList.Size();I++)
if (wcscmp(RedirName,RefList[I].RefName)==0 && RefList[I].TmpName!=NULL)
{
// If only one reference left targeting to this temporary file,
// it is faster to move the file instead of copying and deleting it.
bool RefMove=RefList[I].RefCount-- == 1;
NameExisting=RefList[I].TmpName;
if (RefMove) // Only one reference left for this temporary file.
{
New.Delete(); // Delete the previously opened destination file.
// Try moving the file first.
bool MoveFailed=!RenameFile(NameExisting,NameNew);
if (MoveFailed)
{
// If move failed, re-create the destination and try coping.
if (!New.WCreate(NameNew,FMF_WRITE|FMF_SHAREREAD))
return false;
RefMove=false; // Try copying below.
}
else
{
// If moved successfully, reopen the destination file and seek to
// end for SetOpenFileTime() and possible Truncate() calls later.
if (New.Open(NameNew))
New.Seek(0,SEEK_END);
// We already moved the file, so clean the name to not try
// deleting non-existent temporary file later.
free(RefList[I].TmpName);
RefList[I].TmpName=NULL;
return true;
}
}
if (!RefMove)
OpenFailed=!Existing.Open(NameExisting);
break;
}
if (OpenFailed)
{
ErrHandler.OpenErrorMsg(NameExisting);
uiMsg(UIERROR_FILECOPY,ArcName,NameExisting,NameNew);
uiMsg(UIERROR_FILECOPYHINT,ArcName);
#ifdef RARDLL
@ -861,8 +1059,9 @@ bool CmdExtract::ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *
#endif
return false;
}
}
Array<char> Buffer(0x100000);
Array<byte> 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.
wchar StartName[NM];
*StartName=0;
return; // No need to check further for * and *.* masks.
// 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 Matched=false;
while (!Matched)
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;
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.
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;I<RefList.Size();I++)
if (wcscmp(Arc.FileHead.RedirName,RefList[I].RefName)==0)
{
// Increment the reference count if we added such reference
// source earlier.
RefList[I].RefCount++;
AlreadyAdded=true;
break;
}
// Limit the maximum size of reference sources list to some
// sensible value to prevent the excessive memory allocation.
size_t MaxListSize=1000000;
if (!AlreadyAdded && RefList.Size()<MaxListSize)
{
ExtractRef Ref={0};
Ref.RefName=wcsdup(Arc.FileHead.RedirName);
Ref.RefCount=1;
RefList.Push(Ref);
}
}
}
else
{
if (PrevMatched) // First non-matched item after matched.
{
// We would perform the unnecessarily string comparison
// when extracting if we set this value for first volume
// or non-volume archive.
if (!FirstVolume)
wcsncpyz(Analyze->EndName,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);
}
bool NewStartFound=wcscmp(VolName,StartName)!=0;
if (NewStartFound) // Found a new volume to start extraction.
wcsncpyz(ArcName,StartName,ASIZE(ArcName));
FirstVolume=false;
return NewStartFound;
// 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;
}
// 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

View File

@ -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<ExtractRef> 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

View File

@ -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;

View File

@ -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);

102
deps/unrar/file.cpp vendored
View File

@ -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)ReadSize<Size)
{
// Unlike regular files, for pipe we can read only as much as was
// written at the other end of pipe. We had seen data coming in small
// ~80 byte chunks when piping from 'type arc.rar'. Extraction code
// would fail if we read an incomplete archive header from stdin.
// So here we ensure that requested size is completely read.
// But we return the available data immediately in "line input" mode,
// when processing user's input in console prompts. Otherwise apps
// piping user responses to multiple Ask() prompts can hang if no more
// data is available yet and pipe isn't closed.
Data=(byte*)Data+ReadSize;
Size-=ReadSize;
continue;
}
break;
}
return ReadSize; // It can return -1 only if AllowExceptions is disabled.
if (TotalRead>0) // 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 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
}
#endif
void File::GetOpenFileTime(RarTime *ftm,RarTime *ftc,RarTime *fta)
{
#ifdef _WIN_ALL
FILETIME FileTime;
GetFileTime(hFile,NULL,NULL,&FileTime);
ft->SetWinFT(&FileTime);
#endif
#if defined(_UNIX) || defined(_EMX)
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
}

27
deps/unrar/file.hpp vendored
View File

@ -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

20
deps/unrar/filefn.cpp vendored
View File

@ -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

View File

@ -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

12
deps/unrar/find.cpp vendored
View File

@ -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

View File

@ -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.

View File

@ -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.
@ -33,21 +33,33 @@ class BitInput
// 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;

View File

@ -1,6 +1,6 @@
#define INCLUDEGLOBAL
#if defined(__BORLANDC__) || defined(_MSC_VER)
#ifdef _MSC_VER
#pragma hdrstop
#endif

View File

@ -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);

2
deps/unrar/hash.cpp vendored
View File

@ -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;

10
deps/unrar/hash.hpp vendored
View File

@ -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

View File

@ -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={};
}

View File

@ -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
@ -168,6 +168,10 @@ struct MainHeader:BaseBlock
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;

View File

@ -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.

101
deps/unrar/isnt.cpp vendored
View File

@ -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 <comdef.h>
#include <wbemidl.h>
#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

3
deps/unrar/isnt.hpp vendored
View File

@ -10,4 +10,7 @@ enum WINNT_VERSION {
DWORD WinNT();
// Replace it with actual check when available.
bool IsWindows11OrGreater();
#endif

81
deps/unrar/list.cpp vendored
View File

@ -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,8 +196,29 @@ 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)
{
if (!TitleShown && !Technical && !Bare)
{
if (Verbose)
{
mprintf(L"\n%ls",St(MListTitleV));
if (!DisableNames)
mprintf(L"\n----------- --------- -------- ----- ---------- ----- -------- ----");
}
else
{
mprintf(L"\n%ls",St(MListTitleL));
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;
@ -199,21 +228,6 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
return;
}
if (!TitleShown && !Technical)
{
if (Verbose)
{
mprintf(L"\n%ls",St(MListTitleV));
mprintf(L"\n----------- --------- -------- ----- ---------- ----- -------- ----");
}
else
{
mprintf(L"\n%ls",St(MListTitleL));
mprintf(L"\n----------- --------- ---------- ----- ----");
}
TitleShown=true;
}
wchar UnpSizeText[30],PackSizeText[30];
if (hd.UnpSize==INT64NDF)
wcsncpyz(UnpSizeText,L"?",ASIZE(UnpSizeText));
@ -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);
else
if (hd.UnixGroupNumeric)
mprintf(L"#%d:",hd.UnixGroupID);
mprintf(L"#%d",hd.UnixGroupID);
}
mprintf(L"\n");

View File

@ -28,6 +28,7 @@
#define MRARTitle1 L"\nUsage: rar <command> -<switch 1> -<switch N> <archive> <files...>"
#define MUNRARTitle1 L"\nUsage: unrar <command> -<switch 1> -<switch N> <archive> <files...>"
#define MRARTitle2 L"\n <@listfiles...> <path_to_extract\\>"
#define MFwrSlTitle2 L"\n <@listfiles...> <path_to_extract/>"
#define MCHelpCmd L"\n\n<Commands>"
#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<path> 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[+]<attr> 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<path> 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<par> Set advanced compression parameters"
#define MCHelpSwMD L"\n md<n>[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<threads> Set the number of threads"
#define MCHelpSwN L"\n n<file> 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<path> 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"

11
deps/unrar/makefile vendored
View File

@ -123,7 +123,7 @@ 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
@ -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)

12
deps/unrar/model.cpp vendored
View File

@ -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);
}

View File

@ -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();
};

View File

@ -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));

View File

@ -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<path>.
wchar ExclArcPath[NM]; // For -ep4<path> 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<int64> 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.

29
deps/unrar/os.hpp vendored
View File

@ -13,6 +13,8 @@
#endif
#include <new>
#include <string>
#include <vector>
#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 <dir.h>
#endif
#ifdef _MSC_VER
#if _MSC_VER<1500
#define for if (0) ; else for
#endif
#include <direct.h>
#include <intrin.h>
// 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 <dirent.h>
#endif // _MSC_VER
@ -96,7 +109,6 @@
#include <time.h>
#include <signal.h>
#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

169
deps/unrar/pathfn.cpp vendored
View File

@ -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,6 +190,8 @@ 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));
// 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<NumPtr)
ChPtr=NumPtr;
break;
@ -417,50 +428,39 @@ void NextVolumeName(wchar *ArcName,uint MaxLength,bool OldNumbering)
bool IsNameUsable(const wchar *Name)
{
#ifndef _UNIX
if (Name[0] && Name[1] && wcschr(Name+2,':')!=NULL)
// 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.
#ifdef _UNIX
// Windows shares in Unix do not allow the drive letter,
// so unlike Windows version, we check all characters here.
if (wcschr(Name,':')!=NULL)
return false;
#else
if (Name[0]!=0 && Name[1]!=0 && wcschr(Name+2,':')!=NULL)
return false;
#endif
for (const wchar *s=Name;*s!=0;s++)
{
if ((uint)*s<32)
return false;
// It is for Windows shares in Unix. We can create such names in Windows.
#ifdef _UNIX
// No spaces or dots before the path separator are allowed in 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]))
return false;
}
#endif
}
return *Name!=0 && wcspbrk(Name,L"?*<>|\"")==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;J<ASIZE(Devices);J++)
for (uint K=0;;K++)
if (Devices[J][K]=='#')
{
if (!IsDigit(s[K]))
break;
}
else
if (Devices[J][K]==0)
{
// Names like aux.txt are accessible without \\?\ prefix
// since Windows 11. Pure aux is still prohibited.
MatchFound=s[K]==0 || s[K]=='.' && !IsWindows11OrGreater() || IsPathDiv(s[K]);
break;
}
else
if (Devices[J][K]!=toupperw(s[K]))
break;
if (MatchFound)
{
wchar OrigName[NM];
wcsncpyz(OrigName,Name,ASIZE(OrigName));
if (MaxSize>I+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

View File

@ -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

View File

@ -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,

6
deps/unrar/rar.hpp vendored
View File

@ -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"

View File

@ -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

View File

@ -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);

92
deps/unrar/rdwrfn.cpp vendored
View File

@ -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;
// 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;
}

View File

@ -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.

View File

@ -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;

22
deps/unrar/recvol.hpp vendored
View File

@ -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<RecVolItem> 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

View File

@ -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.
{

View File

@ -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));

View File

@ -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 <wmmintrin.h>
#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;
@ -222,18 +249,58 @@ 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)
{
if (inputLen <= 0)
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
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 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))))
#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;I<256;I++)
S5[S[I]]=I;
for (int i = 0,w = 1; i < sizeof(rcon)/sizeof(rcon[0]); i++)
for (int I=0;I<256;I++)
{
rcon[i] = w;
w = (w << 1) ^ (w & ff_hi ? ff_poly : 0);
}
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);
}
}

View File

@ -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);

4
deps/unrar/rs16.cpp vendored
View File

@ -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;

View File

@ -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

View File

@ -215,11 +215,24 @@ 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.
/*
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)
wcsncatz(CurMask,MASKALL,ASIZE(CurMask));

View File

@ -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<pwd> 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

View File

@ -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<wchar> Password = std::vector<wchar>(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;
};

76
deps/unrar/strfn.cpp vendored
View File

@ -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<MaxSize)
{
if (S!=0 && (S+3-L)%3==0)
Str[D++]=ThSep;
Str[D++]=RawText[S++];
}
Str[D]=0;
}
const wchar* GetWide(const char *Src)
{
const size_t MaxLength=NM;

View File

@ -13,16 +13,16 @@ int stricomp(const char *s1,const char *s2);
int strnicomp(const char *s1,const char *s2,size_t n);
wchar* RemoveEOL(wchar *Str);
wchar* RemoveLF(wchar *Str);
unsigned char loctolower(unsigned char ch);
unsigned char loctoupper(unsigned char ch);
void strncpyz(char *dest, const char *src, size_t maxlen);
void wcsncpyz(wchar *dest, const wchar *src, size_t maxlen);
void strncatz(char* dest, const char* src, size_t maxlen);
void wcsncatz(wchar* dest, const wchar* src, size_t maxlen);
unsigned char etoupper(unsigned char ch);
wchar etoupperw(wchar ch);
#if defined(SFX_MODULE)
unsigned char etoupper(unsigned char c);
#endif
wchar etoupperw(wchar c);
bool IsDigit(int ch);
bool IsSpace(int ch);
@ -42,6 +42,7 @@ int wcsnicompc(const wchar *s1,const wchar *s2,size_t n);
void itoa(int64 n,char *Str,size_t MaxSize);
void itoa(int64 n,wchar *Str,size_t MaxSize);
void fmtitoa(int64 n,wchar *Str,size_t MaxSize);
const wchar* GetWide(const char *Src);
const wchar* GetCmdParam(const wchar *CmdLine,wchar *Param,size_t MaxSize);
#ifndef RARDLL

View File

@ -71,7 +71,7 @@ void SubAllocator::StopSubAllocator()
if ( SubAllocatorSize )
{
SubAllocatorSize=0;
//free(HeapStart);
free(HeapStart);
}
}
@ -88,8 +88,7 @@ bool SubAllocator::StartSubAllocator(int SASize)
// units: one as reserve for HeapEnd overflow checks and another
// to provide the space to correctly align UnitsStart.
uint AllocSize=t/FIXED_UNIT_SIZE*UNIT_SIZE+2*UNIT_SIZE;
//if ((HeapStart=(byte *)malloc(AllocSize)) == NULL)
if ((HeapStart=(byte *)HeapStartFixed) == NULL)
if ((HeapStart=(byte *)malloc(AllocSize)) == NULL)
{
ErrHandler.MemoryError();
return false;

View File

@ -80,9 +80,6 @@ class SubAllocator
long GetAllocatedMemory() {return(SubAllocatorSize);}
byte *pText, *UnitsStart,*HeapEnd,*FakeUnitsStart;
byte *HeapStartFixed;
void SetHeapStartFixed(byte *p) {HeapStartFixed=p;}
};

View File

@ -187,10 +187,10 @@ SSE_VERSION _SSE_Version=GetSSEVersion();
SSE_VERSION GetSSEVersion()
{
int CPUInfo[4];
__cpuid(CPUInfo, 0x80000000);
__cpuid(CPUInfo, 0);
// Maximum supported cpuid function. For example, Pentium M 755 returns 4 here.
uint MaxSupported=CPUInfo[0] & 0x7fffffff;
// Maximum supported cpuid function.
uint MaxSupported=CPUInfo[0];
if (MaxSupported>=7)
{

View File

@ -149,3 +149,5 @@ uint GetNumberOfThreads()
return NumCPU;
}

View File

@ -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;

11
deps/unrar/timefn.hpp vendored
View File

@ -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.

38
deps/unrar/ui.hpp vendored
View File

@ -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<class T1> void uiMsg(UIMESSAGE_CODE Code,T1 a1)
template<class T1,class... TN> void uiMsgBase(uiMsgStore &Store,T1&& a1,TN&&... aN)
{
uiMsgStore Store(Code);
// Process first parameter and pass the rest to same uiMsgBase.
Store<<a1;
Store.Msg();
uiMsgBase(Store,aN...);
}
template<class T1,class T2> void uiMsg(UIMESSAGE_CODE Code,T1 a1,T2 a2)
// 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<class... TN> void uiMsg(UIMESSAGE_CODE Code,TN&&... aN)
{
uiMsgStore Store(Code);
Store<<a1<<a2;
Store.Msg();
}
template<class T1,class T2,class T3> void uiMsg(UIMESSAGE_CODE code,T1 a1,T2 a2,T3 a3)
{
uiMsgStore Store(code);
Store<<a1<<a2<<a3;
uiMsgBase(Store,aN...);
Store.Msg();
}

View File

@ -8,7 +8,7 @@ void uiInit(SOUND_NOTIFY_MODE Sound)
// Additionally to handling user input, it analyzes and sets command options.
// Returns only 'replace', 'skip' and 'cancel' codes.
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)
{
if (Cmd->Overwrite==OVERWRITE_NONE)
return UIASKREP_R_SKIP;

View File

@ -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

View File

@ -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;
}

40
deps/unrar/ulinks.cpp vendored
View File

@ -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);
}

View File

@ -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<SrcSize;I++,Src++)
for (size_t I=0;I<SrcSize && I*2+1<DestSize;I++,Src++)
{
Dest[I*2]=(byte)*Src;
Dest[I*2+1]=(byte)(*Src>>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

View File

@ -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

18
deps/unrar/unpack.cpp vendored
View File

@ -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;
}

10
deps/unrar/unpack.hpp vendored
View File

@ -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.
};
};

View File

@ -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;

View File

@ -42,7 +42,7 @@ void Unpack::Unpack5(bool Solid)
break;
}
if (((WriteBorder-UnpPtr) & MaxWinMask)<MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr)
if (((WriteBorder-UnpPtr) & MaxWinMask)<=MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr)
{
UnpWriteBuf();
if (WrittenFileSize>DestUnpSize)
@ -93,7 +93,7 @@ void Unpack::Unpack5(bool Solid)
}
else
{
Distance+=Inp.getbits32()>>(32-DBits);
Distance+=Inp.getbits()>>(16-DBits);
Inp.addbits(DBits);
}
}

View File

@ -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->Length<ASIZE(PrevItem->Literal)-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 (Item<Border)
{
UnpPtr&=MaxWinMask;
if (((WriteBorder-UnpPtr) & MaxWinMask)<MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr)
if (((WriteBorder-UnpPtr) & MaxWinMask)<=MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr)
{
UnpWriteBuf();
if (WrittenFileSize>DestUnpSize)
@ -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 && UnpPtr<MaxWinSize-4)
if (Item->Length==7 && UnpPtr<MaxWinSize-8)
{
*(uint32 *)(Window+UnpPtr)=*(uint32 *)Item->Literal;
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)<MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr)
if (((WriteBorder-UnpPtr) & MaxWinMask)<=MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr)
{
UnpWriteBuf();
if (WrittenFileSize>DestUnpSize)

View File

@ -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

78
deps/unrar/volume.cpp vendored
View File

@ -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,9 +171,8 @@ 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
@ -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

View File

@ -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

View File

@ -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))
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);

View File

@ -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)

View File

@ -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)