mirror of
https://github.com/php-win-ext/php-rar.git
synced 2026-03-24 04:52:07 +01:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e783678a51 | ||
|
|
b2c9c08fe0 |
@@ -238,8 +238,10 @@
|
||||
<ClCompile Include="hash.cpp" />
|
||||
<ClCompile Include="headers.cpp" />
|
||||
<ClCompile Include="isnt.cpp" />
|
||||
<ClCompile Include="largepage.cpp" />
|
||||
<ClCompile Include="list.cpp" />
|
||||
<ClCompile Include="match.cpp" />
|
||||
<ClCompile Include="motw.cpp" />
|
||||
<ClCompile Include="options.cpp" />
|
||||
<ClCompile Include="pathfn.cpp" />
|
||||
<ClCompile Include="qopen.cpp" />
|
||||
|
||||
@@ -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>
|
||||
@@ -374,7 +374,9 @@
|
||||
<ClCompile Include="hash.cpp" />
|
||||
<ClCompile Include="headers.cpp" />
|
||||
<ClCompile Include="isnt.cpp" />
|
||||
<ClCompile Include="largepage.cpp" />
|
||||
<ClCompile Include="match.cpp" />
|
||||
<ClCompile Include="motw.cpp" />
|
||||
<ClCompile Include="options.cpp" />
|
||||
<ClCompile Include="pathfn.cpp" />
|
||||
<ClCompile Include="qopen.cpp" />
|
||||
|
||||
@@ -7,51 +7,18 @@
|
||||
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.
|
||||
* 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:
|
||||
|
||||
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:
|
||||
|
||||
http://sourceforge.net/projects/slicing-by-8/
|
||||
https://sourceforge.net/projects/slicing-by-8/
|
||||
|
||||
Original Intel Slicing-by-8 code is licensed under BSD License
|
||||
available at http://www.opensource.org/licenses/bsd-license.html
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
static bool IsAnsiEscComment(const wchar *Data,size_t Size);
|
||||
|
||||
bool Archive::GetComment(Array<wchar> *CmtData)
|
||||
bool Archive::GetComment(std::wstring &CmtData)
|
||||
{
|
||||
if (!MainComment)
|
||||
return false;
|
||||
@@ -11,7 +11,7 @@ bool Archive::GetComment(Array<wchar> *CmtData)
|
||||
}
|
||||
|
||||
|
||||
bool Archive::DoGetComment(Array<wchar> *CmtData)
|
||||
bool Archive::DoGetComment(std::wstring &CmtData)
|
||||
{
|
||||
#ifndef SFX_MODULE
|
||||
uint CmtLength;
|
||||
@@ -36,7 +36,12 @@ bool Archive::DoGetComment(Array<wchar> *CmtData)
|
||||
{
|
||||
// Current (RAR 3.0+) version of archive comment.
|
||||
Seek(GetStartPos(),SEEK_SET);
|
||||
return SearchSubBlock(SUBHEAD_TYPE_CMT)!=0 && ReadCommentData(CmtData);
|
||||
if (SearchSubBlock(SUBHEAD_TYPE_CMT)!=0)
|
||||
if (ReadCommentData(CmtData))
|
||||
return true;
|
||||
else
|
||||
uiMsg(UIERROR_CMTBROKEN,FileName);
|
||||
return false;
|
||||
}
|
||||
#ifndef SFX_MODULE
|
||||
// Old style (RAR 2.9) comment header embedded into the main
|
||||
@@ -101,10 +106,8 @@ bool Archive::DoGetComment(Array<wchar> *CmtData)
|
||||
// 4x memory for OEM to UTF-8 output here.
|
||||
OemToCharBuffA((char *)UnpData,(char *)UnpData,(DWORD)UnpDataSize);
|
||||
#endif
|
||||
CmtData->Alloc(UnpDataSize+1);
|
||||
memset(CmtData->Addr(0),0,CmtData->Size()*sizeof(wchar));
|
||||
CharToWide((char *)UnpData,CmtData->Addr(0),CmtData->Size());
|
||||
CmtData->Alloc(wcslen(CmtData->Addr(0)));
|
||||
std::string UnpStr((char*)UnpData,UnpDataSize);
|
||||
CharToWide(UnpStr,CmtData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,12 +115,12 @@ bool Archive::DoGetComment(Array<wchar> *CmtData)
|
||||
{
|
||||
if (CmtLength==0)
|
||||
return false;
|
||||
Array<byte> CmtRaw(CmtLength);
|
||||
int ReadSize=Read(&CmtRaw[0],CmtLength);
|
||||
std::vector<byte> CmtRaw(CmtLength);
|
||||
int ReadSize=Read(CmtRaw.data(),CmtLength);
|
||||
if (ReadSize>=0 && (uint)ReadSize<CmtLength) // Comment is shorter than declared.
|
||||
{
|
||||
CmtLength=ReadSize;
|
||||
CmtRaw.Alloc(CmtLength);
|
||||
CmtRaw.resize(CmtLength);
|
||||
}
|
||||
|
||||
if (Format!=RARFMT14 && CommHead.CommCRC!=(~CRC32(0xffffffff,&CmtRaw[0],CmtLength)&0xffff))
|
||||
@@ -125,43 +128,41 @@ bool Archive::DoGetComment(Array<wchar> *CmtData)
|
||||
uiMsg(UIERROR_CMTBROKEN,FileName);
|
||||
return false;
|
||||
}
|
||||
CmtData->Alloc(CmtLength+1);
|
||||
CmtRaw.Push(0);
|
||||
// CmtData.resize(CmtLength+1);
|
||||
CmtRaw.push_back(0);
|
||||
#ifdef _WIN_ALL
|
||||
// If we ever decide to extend it to Android, we'll need to alloc
|
||||
// 4x memory for OEM to UTF-8 output here.
|
||||
OemToCharA((char *)&CmtRaw[0],(char *)&CmtRaw[0]);
|
||||
OemToCharA((char *)CmtRaw.data(),(char *)CmtRaw.data());
|
||||
#endif
|
||||
CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
|
||||
CmtData->Alloc(wcslen(CmtData->Addr(0)));
|
||||
CharToWide((const char *)CmtRaw.data(),CmtData);
|
||||
// CmtData->resize(wcslen(CmtData->data()));
|
||||
}
|
||||
#endif
|
||||
return CmtData->Size() > 0;
|
||||
return CmtData.size() > 0;
|
||||
}
|
||||
|
||||
|
||||
bool Archive::ReadCommentData(Array<wchar> *CmtData)
|
||||
bool Archive::ReadCommentData(std::wstring &CmtData)
|
||||
{
|
||||
Array<byte> CmtRaw;
|
||||
std::vector<byte> CmtRaw;
|
||||
if (!ReadSubData(&CmtRaw,NULL,false))
|
||||
return false;
|
||||
size_t CmtSize=CmtRaw.Size();
|
||||
CmtRaw.Push(0);
|
||||
CmtData->Alloc(CmtSize+1);
|
||||
size_t CmtSize=CmtRaw.size();
|
||||
CmtRaw.push_back(0);
|
||||
// CmtData->resize(CmtSize+1);
|
||||
if (Format==RARFMT50)
|
||||
UtfToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
|
||||
UtfToWide((char *)CmtRaw.data(),CmtData);
|
||||
else
|
||||
if ((SubHead.SubFlags & SUBHEAD_FLAGS_CMT_UNICODE)!=0)
|
||||
{
|
||||
RawToWide(&CmtRaw[0],CmtData->Addr(0),CmtSize/2);
|
||||
(*CmtData)[CmtSize/2]=0;
|
||||
|
||||
CmtData=RawToWide(CmtRaw);
|
||||
}
|
||||
else
|
||||
{
|
||||
CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
|
||||
CharToWide((const char *)CmtRaw.data(),CmtData);
|
||||
}
|
||||
CmtData->Alloc(wcslen(CmtData->Addr(0))); // Set buffer size to actual comment length.
|
||||
// CmtData->resize(wcslen(CmtData->data())); // Set buffer size to actual comment length.
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -170,15 +171,16 @@ void Archive::ViewComment()
|
||||
{
|
||||
if (Cmd->DisableComment)
|
||||
return;
|
||||
Array<wchar> CmtBuf;
|
||||
if (GetComment(&CmtBuf)) // In GUI too, so "Test" command detects broken comments.
|
||||
std::wstring CmtBuf;
|
||||
if (GetComment(CmtBuf)) // In GUI too, so "Test" command detects broken comments.
|
||||
{
|
||||
size_t CmtSize=CmtBuf.Size();
|
||||
wchar *ChPtr=wcschr(&CmtBuf[0],0x1A);
|
||||
if (ChPtr!=NULL)
|
||||
CmtSize=ChPtr-&CmtBuf[0];
|
||||
mprintf(L"\n");
|
||||
OutComment(&CmtBuf[0],CmtSize);
|
||||
size_t CmtSize=CmtBuf.size();
|
||||
auto EndPos=CmtBuf.find(0x1A);
|
||||
if (EndPos!=std::wstring::npos)
|
||||
CmtSize=EndPos;
|
||||
mprintf(St(MArcComment));
|
||||
mprintf(L":\n");
|
||||
OutComment(CmtBuf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -26,20 +26,21 @@ Archive::Archive(RAROptions *InitCmd)
|
||||
FailedHeaderDecryption=false;
|
||||
BrokenHeader=false;
|
||||
LastReadBlock=0;
|
||||
CurHeaderType=HEAD_UNKNOWN;
|
||||
|
||||
CurBlockPos=0;
|
||||
NextBlockPos=0;
|
||||
|
||||
RecoveryPercent=-1;
|
||||
|
||||
memset(&MainHead,0,sizeof(MainHead));
|
||||
memset(&CryptHead,0,sizeof(CryptHead));
|
||||
memset(&EndArcHead,0,sizeof(EndArcHead));
|
||||
MainHead.Reset();
|
||||
CryptHead={};
|
||||
EndArcHead.Reset();
|
||||
|
||||
VolNumber=0;
|
||||
VolWrite=0;
|
||||
AddingFilesSize=0;
|
||||
AddingHeadersSize=0;
|
||||
*FirstVolumeName=0;
|
||||
|
||||
Splitting=false;
|
||||
NewArchive=false;
|
||||
@@ -68,13 +69,13 @@ void Archive::CheckArc(bool EnableBroken)
|
||||
// password is incorrect.
|
||||
if (!FailedHeaderDecryption)
|
||||
uiMsg(UIERROR_BADARCHIVE,FileName);
|
||||
ErrHandler.Exit(RARX_FATAL);
|
||||
ErrHandler.Exit(RARX_BADARC);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if !defined(SFX_MODULE)
|
||||
void Archive::CheckOpen(const wchar *Name)
|
||||
void Archive::CheckOpen(const std::wstring &Name)
|
||||
{
|
||||
TOpen(Name);
|
||||
CheckArc(false);
|
||||
@@ -82,7 +83,7 @@ void Archive::CheckOpen(const wchar *Name)
|
||||
#endif
|
||||
|
||||
|
||||
bool Archive::WCheckOpen(const wchar *Name)
|
||||
bool Archive::WCheckOpen(const std::wstring &Name)
|
||||
{
|
||||
if (!WOpen(Name))
|
||||
return false;
|
||||
@@ -110,9 +111,11 @@ RARFORMAT Archive::IsSignature(const byte *D,size_t Size)
|
||||
// We check the last signature byte, so we can return a sensible
|
||||
// warning in case we'll want to change the archive format
|
||||
// sometimes in the future.
|
||||
#ifndef SFX_MODULE
|
||||
if (D[6]==0)
|
||||
Type=RARFMT15;
|
||||
else
|
||||
#endif
|
||||
if (D[6]==1)
|
||||
Type=RARFMT50;
|
||||
else
|
||||
@@ -148,9 +151,9 @@ bool Archive::IsArchive(bool EnableBroken)
|
||||
}
|
||||
else
|
||||
{
|
||||
Array<char> Buffer(MAXSFXSIZE);
|
||||
std::vector<char> Buffer(MAXSFXSIZE);
|
||||
long CurPos=(long)Tell();
|
||||
int ReadSize=Read(&Buffer[0],Buffer.Size()-16);
|
||||
int ReadSize=Read(Buffer.data(),Buffer.size()-16);
|
||||
for (int I=0;I<ReadSize;I++)
|
||||
if (Buffer[I]==0x52 && (Type=IsSignature((byte *)&Buffer[I],ReadSize-I))!=RARFMT_NONE)
|
||||
{
|
||||
@@ -231,7 +234,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;
|
||||
@@ -265,7 +268,7 @@ bool Archive::IsArchive(bool EnableBroken)
|
||||
Seek(SavePos,SEEK_SET);
|
||||
}
|
||||
if (!Volume || FirstVolume)
|
||||
wcsncpyz(FirstVolumeName,FileName,ASIZE(FirstVolumeName));
|
||||
FirstVolumeName=FileName;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -301,7 +304,7 @@ uint Archive::FullHeaderSize(size_t Size)
|
||||
|
||||
|
||||
#ifdef USE_QOPEN
|
||||
bool Archive::Open(const wchar *Name,uint Mode)
|
||||
bool Archive::Open(const std::wstring &Name,uint Mode)
|
||||
{
|
||||
// Important if we reuse Archive object and it has virtual QOpen
|
||||
// file position not matching real. For example, for 'l -v volname'.
|
||||
@@ -336,3 +339,23 @@ int64 Archive::Tell()
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Return 0 if dictionary size is invalid. If size is RAR7 only, return
|
||||
// the adjusted nearest bottom value. Return header flags in Flags.
|
||||
uint64 Archive::GetWinSize(uint64 Size,uint &Flags)
|
||||
{
|
||||
Flags=0;
|
||||
// Allow 128 KB - 1 TB range.
|
||||
if (Size<0x20000 || Size>0x10000000000ULL)
|
||||
return 0;
|
||||
uint64 Pow2=0x20000; // Power of 2 dictionary size.
|
||||
for (;2*Pow2<=Size;Pow2*=2)
|
||||
Flags+=FCI_DICT_BIT0;
|
||||
if (Size==Pow2)
|
||||
return Size; // If 'Size' is the power of 2, return it as is.
|
||||
|
||||
// Get the number of Pow2/32 to add to Pow2 for nearest value not exceeding 'Size'.
|
||||
uint64 Fraction=(Size-Pow2)/(Pow2/32);
|
||||
Flags+=(uint)Fraction*FCI_DICT_FRACT0;
|
||||
return Pow2+Fraction*(Pow2/32);
|
||||
}
|
||||
|
||||
@@ -27,26 +27,27 @@ class Archive:public File
|
||||
{
|
||||
private:
|
||||
void UpdateLatestTime(FileHeader *CurBlock);
|
||||
void ConvertNameCase(wchar *Name);
|
||||
void ConvertNameCase(std::wstring &Name);
|
||||
void ConvertFileHeader(FileHeader *hd);
|
||||
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);
|
||||
bool DoGetComment(Array<wchar> *CmtData);
|
||||
bool ReadCommentData(Array<wchar> *CmtData);
|
||||
void UnkEncVerMsg(const std::wstring &Name,const std::wstring &Info);
|
||||
bool DoGetComment(std::wstring &CmtData);
|
||||
bool ReadCommentData(std::wstring &CmtData);
|
||||
|
||||
#if !defined(RAR_NOCRYPT)
|
||||
CryptData HeadersCrypt;
|
||||
#endif
|
||||
ComprDataIO SubDataIO;
|
||||
bool DummyCmd;
|
||||
RAROptions *Cmd;
|
||||
CommandData *Cmd;
|
||||
|
||||
int RecoveryPercent;
|
||||
|
||||
RarTime LatestTime;
|
||||
int LastReadBlock;
|
||||
@@ -58,18 +59,19 @@ class Archive:public File
|
||||
bool ProhibitQOpen;
|
||||
#endif
|
||||
public:
|
||||
Archive(RAROptions *InitCmd=NULL);
|
||||
Archive(CommandData *InitCmd=nullptr);
|
||||
~Archive();
|
||||
static RARFORMAT IsSignature(const byte *D,size_t Size);
|
||||
bool IsArchive(bool EnableBroken);
|
||||
size_t SearchBlock(HEADER_TYPE HeaderType);
|
||||
size_t SearchSubBlock(const wchar *Type);
|
||||
size_t SearchRR();
|
||||
int GetRecoveryPercent() {return RecoveryPercent;}
|
||||
size_t ReadHeader();
|
||||
void CheckArc(bool EnableBroken);
|
||||
void CheckOpen(const wchar *Name);
|
||||
bool WCheckOpen(const wchar *Name);
|
||||
bool GetComment(Array<wchar> *CmtData);
|
||||
void CheckOpen(const std::wstring &Name);
|
||||
bool WCheckOpen(const std::wstring &Name);
|
||||
bool GetComment(std::wstring &CmtData);
|
||||
void ViewComment();
|
||||
void SetLatestTime(RarTime *NewTime);
|
||||
void SeekToNext();
|
||||
@@ -79,23 +81,25 @@ class Archive:public File
|
||||
void VolSubtractHeaderSize(size_t SubSize);
|
||||
uint FullHeaderSize(size_t Size);
|
||||
int64 GetStartPos();
|
||||
void AddSubData(byte *SrcData,uint64 DataSize,File *SrcFile,
|
||||
void AddSubData(const byte *SrcData,uint64 DataSize,File *SrcFile,
|
||||
const wchar *Name,uint Flags);
|
||||
bool ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode);
|
||||
bool ReadSubData(std::vector<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);
|
||||
#endif
|
||||
#ifdef USE_QOPEN
|
||||
bool Open(const wchar *Name,uint Mode=FMF_READ);
|
||||
int Read(void *Data,size_t Size);
|
||||
void Seek(int64 Offset,int Method);
|
||||
int64 Tell();
|
||||
bool Open(const std::wstring &Name,uint Mode=FMF_READ) override;
|
||||
int Read(void *Data,size_t Size) override;
|
||||
void Seek(int64 Offset,int Method) override;
|
||||
int64 Tell() override;
|
||||
void QOpenUnload() {QOpen.Unload();}
|
||||
void SetProhibitQOpen(bool Mode) {ProhibitQOpen=Mode;}
|
||||
#endif
|
||||
static uint64 GetWinSize(uint64 Size,uint &Flags);
|
||||
|
||||
// Needed to see wstring based Open from File. Otherwise compiler finds
|
||||
// Open in Archive and doesn't check the base class overloads.
|
||||
using File::Open;
|
||||
|
||||
BaseBlock ShortBlock;
|
||||
MarkHeader MarkHead;
|
||||
@@ -107,7 +111,6 @@ class Archive:public File
|
||||
FileHeader SubHead;
|
||||
CommentHeader CommHead;
|
||||
ProtectHeader ProtectHead;
|
||||
UnixOwnersHeader UOHead;
|
||||
EAHeader EAHead;
|
||||
StreamHeader StreamHead;
|
||||
|
||||
@@ -136,12 +139,19 @@ class Archive:public File
|
||||
|
||||
uint VolNumber;
|
||||
int64 VolWrite;
|
||||
|
||||
// Total size of files adding to archive. Might also include the size of
|
||||
// files repacked in solid archive.
|
||||
uint64 AddingFilesSize;
|
||||
|
||||
uint64 AddingHeadersSize;
|
||||
|
||||
bool NewArchive;
|
||||
|
||||
wchar FirstVolumeName[NM];
|
||||
std::wstring FirstVolumeName;
|
||||
#ifdef PROPAGATE_MOTW
|
||||
MarkOfTheWeb Motw;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -20,10 +20,10 @@ size_t Archive::ReadHeader()
|
||||
case RARFMT14:
|
||||
ReadSize=ReadHeader14();
|
||||
break;
|
||||
#endif
|
||||
case RARFMT15:
|
||||
ReadSize=ReadHeader15();
|
||||
break;
|
||||
#endif
|
||||
case RARFMT50:
|
||||
ReadSize=ReadHeader50();
|
||||
break;
|
||||
@@ -100,9 +100,15 @@ 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);
|
||||
if (CurHeaderType!=HEAD_FILE && CurHeaderType!=HEAD_UNKNOWN)
|
||||
uiMsg(UIERROR_TRUNCSERVICE,FileName,SubHead.FileName);
|
||||
|
||||
ErrHandler.SetErrorCode(RARX_WARNING);
|
||||
}
|
||||
}
|
||||
@@ -116,10 +122,10 @@ void Archive::BrokenHeaderMsg()
|
||||
}
|
||||
|
||||
|
||||
void Archive::UnkEncVerMsg(const wchar *Name,const wchar *Info)
|
||||
void Archive::UnkEncVerMsg(const std::wstring &Name,const std::wstring &Info)
|
||||
{
|
||||
uiMsg(UIERROR_UNKNOWNENCMETHOD,FileName,Name,Info);
|
||||
ErrHandler.SetErrorCode(RARX_WARNING);
|
||||
ErrHandler.SetErrorCode(RARX_FATAL);
|
||||
}
|
||||
|
||||
|
||||
@@ -134,6 +140,7 @@ inline int64 SafeAdd(int64 v1,int64 v2,int64 f)
|
||||
}
|
||||
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
size_t Archive::ReadHeader15()
|
||||
{
|
||||
RawRead Raw(this);
|
||||
@@ -142,10 +149,10 @@ size_t Archive::ReadHeader15()
|
||||
|
||||
if (Decrypt)
|
||||
{
|
||||
#ifdef RAR_NOCRYPT // For rarext.dll and unrar_nocrypt.dll.
|
||||
#ifdef RAR_NOCRYPT // For rarext.dll, Setup.SFX and unrar_nocrypt.dll.
|
||||
return 0;
|
||||
#else
|
||||
RequestArcPassword();
|
||||
RequestArcPassword(NULL);
|
||||
|
||||
byte Salt[SIZE_SALT30];
|
||||
if (Read(Salt,SIZE_SALT30)!=SIZE_SALT30)
|
||||
@@ -219,7 +226,7 @@ size_t Archive::ReadHeader15()
|
||||
{
|
||||
case HEAD_MAIN:
|
||||
MainHead.Reset();
|
||||
*(BaseBlock *)&MainHead=ShortBlock;
|
||||
MainHead.SetBaseBlock(ShortBlock);
|
||||
MainHead.HighPosAV=Raw.Get2();
|
||||
MainHead.PosAV=Raw.Get4();
|
||||
|
||||
@@ -245,13 +252,17 @@ size_t Archive::ReadHeader15()
|
||||
FileHeader *hd=FileBlock ? &FileHead:&SubHead;
|
||||
hd->Reset();
|
||||
|
||||
*(BaseBlock *)hd=ShortBlock;
|
||||
hd->SetBaseBlock(ShortBlock);
|
||||
|
||||
hd->SplitBefore=(hd->Flags & LHD_SPLIT_BEFORE)!=0;
|
||||
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);
|
||||
@@ -300,7 +311,7 @@ size_t Archive::ReadHeader15()
|
||||
if (hd->HostOS==HOST_UNIX && (hd->FileAttr & 0xF000)==0xA000)
|
||||
{
|
||||
hd->RedirType=FSREDIR_UNIXSYMLINK;
|
||||
*hd->RedirName=0;
|
||||
hd->RedirName.clear();
|
||||
}
|
||||
|
||||
hd->Inherited=!FileBlock && (hd->SubFlags & SUBHEAD_FLAGS_INHERITED)!=0;
|
||||
@@ -327,27 +338,26 @@ size_t Archive::ReadHeader15()
|
||||
if (hd->UnknownUnpSize)
|
||||
hd->UnpSize=INT64NDF;
|
||||
|
||||
char FileName[NM*4];
|
||||
size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
|
||||
Raw.GetB((byte *)FileName,ReadNameSize);
|
||||
FileName[ReadNameSize]=0;
|
||||
size_t ReadNameSize=Min(NameSize,MAXPATHSIZE);
|
||||
std::string FileName(ReadNameSize,0);
|
||||
Raw.GetB((byte *)&FileName[0],ReadNameSize);
|
||||
|
||||
if (FileBlock)
|
||||
{
|
||||
*hd->FileName=0;
|
||||
hd->FileName.clear();
|
||||
if ((hd->Flags & LHD_UNICODE)!=0)
|
||||
{
|
||||
EncodeFileName NameCoder;
|
||||
size_t Length=strlen(FileName);
|
||||
size_t Length=strlen(FileName.data());
|
||||
Length++;
|
||||
if (ReadNameSize>Length)
|
||||
NameCoder.Decode(FileName,ReadNameSize,(byte *)FileName+Length,
|
||||
ReadNameSize-Length,hd->FileName,
|
||||
ASIZE(hd->FileName));
|
||||
NameCoder.Decode(FileName.data(),ReadNameSize,
|
||||
(byte *)&FileName[Length],
|
||||
ReadNameSize-Length,hd->FileName);
|
||||
}
|
||||
|
||||
if (*hd->FileName==0)
|
||||
ArcCharToWide(FileName,hd->FileName,ASIZE(hd->FileName),ACTW_OEM);
|
||||
if (hd->FileName.empty())
|
||||
ArcCharToWide(FileName.data(),hd->FileName,ACTW_OEM);
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
ConvertNameCase(hd->FileName);
|
||||
@@ -356,7 +366,7 @@ size_t Archive::ReadHeader15()
|
||||
}
|
||||
else
|
||||
{
|
||||
CharToWide(FileName,hd->FileName,ASIZE(hd->FileName));
|
||||
CharToWide(FileName.data(),hd->FileName);
|
||||
|
||||
// Calculate the size of optional data.
|
||||
int DataSize=int(hd->HeadSize-NameSize-SIZEOF_FILEHEAD3);
|
||||
@@ -367,14 +377,15 @@ size_t Archive::ReadHeader15()
|
||||
{
|
||||
// Here we read optional additional fields for subheaders.
|
||||
// They are stored after the file name and before salt.
|
||||
hd->SubData.Alloc(DataSize);
|
||||
Raw.GetB(&hd->SubData[0],DataSize);
|
||||
hd->SubData.resize(DataSize);
|
||||
Raw.GetB(hd->SubData.data(),DataSize);
|
||||
|
||||
}
|
||||
|
||||
if (hd->CmpName(SUBHEAD_TYPE_CMT))
|
||||
MainComment=true;
|
||||
}
|
||||
|
||||
if ((hd->Flags & LHD_SALT)!=0)
|
||||
Raw.GetB(hd->Salt,SIZE_SALT30);
|
||||
hd->mtime.SetDos(FileTime);
|
||||
@@ -417,7 +428,7 @@ size_t Archive::ReadHeader15()
|
||||
NextBlockPos=SafeAdd(NextBlockPos,hd->PackSize,0);
|
||||
|
||||
bool CRCProcessedOnly=hd->CommentInHeader;
|
||||
ushort HeaderCRC=Raw.GetCRC15(CRCProcessedOnly);
|
||||
uint HeaderCRC=Raw.GetCRC15(CRCProcessedOnly);
|
||||
if (hd->HeadCRC!=HeaderCRC)
|
||||
{
|
||||
BrokenHeader=true;
|
||||
@@ -434,7 +445,7 @@ size_t Archive::ReadHeader15()
|
||||
}
|
||||
break;
|
||||
case HEAD_ENDARC:
|
||||
*(BaseBlock *)&EndArcHead=ShortBlock;
|
||||
EndArcHead.SetBaseBlock(ShortBlock);
|
||||
EndArcHead.NextVolume=(EndArcHead.Flags & EARC_NEXT_VOLUME)!=0;
|
||||
EndArcHead.DataCRC=(EndArcHead.Flags & EARC_DATACRC)!=0;
|
||||
EndArcHead.RevSpace=(EndArcHead.Flags & EARC_REVSPACE)!=0;
|
||||
@@ -446,14 +457,14 @@ size_t Archive::ReadHeader15()
|
||||
break;
|
||||
#ifndef SFX_MODULE
|
||||
case HEAD3_CMT:
|
||||
*(BaseBlock *)&CommHead=ShortBlock;
|
||||
CommHead.SetBaseBlock(ShortBlock);
|
||||
CommHead.UnpSize=Raw.Get2();
|
||||
CommHead.UnpVer=Raw.Get1();
|
||||
CommHead.Method=Raw.Get1();
|
||||
CommHead.CommCRC=Raw.Get2();
|
||||
break;
|
||||
case HEAD3_PROTECT:
|
||||
*(BaseBlock *)&ProtectHead=ShortBlock;
|
||||
ProtectHead.SetBaseBlock(ShortBlock);
|
||||
ProtectHead.DataSize=Raw.Get4();
|
||||
ProtectHead.Version=Raw.Get1();
|
||||
ProtectHead.RecSectors=Raw.Get2();
|
||||
@@ -462,26 +473,13 @@ size_t Archive::ReadHeader15()
|
||||
NextBlockPos+=ProtectHead.DataSize;
|
||||
break;
|
||||
case HEAD3_OLDSERVICE: // RAR 2.9 and earlier.
|
||||
*(BaseBlock *)&SubBlockHead=ShortBlock;
|
||||
SubBlockHead.SetBaseBlock(ShortBlock);
|
||||
SubBlockHead.DataSize=Raw.Get4();
|
||||
NextBlockPos+=SubBlockHead.DataSize;
|
||||
SubBlockHead.SubType=Raw.Get2();
|
||||
SubBlockHead.Level=Raw.Get1();
|
||||
switch(SubBlockHead.SubType)
|
||||
{
|
||||
case UO_HEAD:
|
||||
*(SubBlockHeader *)&UOHead=SubBlockHead;
|
||||
UOHead.OwnerNameSize=Raw.Get2();
|
||||
UOHead.GroupNameSize=Raw.Get2();
|
||||
if (UOHead.OwnerNameSize>=ASIZE(UOHead.OwnerName))
|
||||
UOHead.OwnerNameSize=ASIZE(UOHead.OwnerName)-1;
|
||||
if (UOHead.GroupNameSize>=ASIZE(UOHead.GroupName))
|
||||
UOHead.GroupNameSize=ASIZE(UOHead.GroupName)-1;
|
||||
Raw.GetB(UOHead.OwnerName,UOHead.OwnerNameSize);
|
||||
Raw.GetB(UOHead.GroupName,UOHead.GroupNameSize);
|
||||
UOHead.OwnerName[UOHead.OwnerNameSize]=0;
|
||||
UOHead.GroupName[UOHead.GroupNameSize]=0;
|
||||
break;
|
||||
case NTACL_HEAD:
|
||||
*(SubBlockHeader *)&EAHead=SubBlockHead;
|
||||
EAHead.UnpSize=Raw.Get4();
|
||||
@@ -496,10 +494,13 @@ size_t Archive::ReadHeader15()
|
||||
StreamHead.Method=Raw.Get1();
|
||||
StreamHead.StreamCRC=Raw.Get4();
|
||||
StreamHead.StreamNameSize=Raw.Get2();
|
||||
if (StreamHead.StreamNameSize>=ASIZE(StreamHead.StreamName))
|
||||
StreamHead.StreamNameSize=ASIZE(StreamHead.StreamName)-1;
|
||||
Raw.GetB(StreamHead.StreamName,StreamHead.StreamNameSize);
|
||||
StreamHead.StreamName[StreamHead.StreamNameSize]=0;
|
||||
|
||||
const size_t MaxStreamName20=260; // Maximum allowed stream name in RAR 2.x format.
|
||||
if (StreamHead.StreamNameSize>MaxStreamName20)
|
||||
StreamHead.StreamNameSize=MaxStreamName20;
|
||||
|
||||
StreamHead.StreamName.resize(StreamHead.StreamNameSize);
|
||||
Raw.GetB(&StreamHead.StreamName[0],StreamHead.StreamNameSize);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -510,11 +511,15 @@ size_t Archive::ReadHeader15()
|
||||
break;
|
||||
}
|
||||
|
||||
ushort HeaderCRC=Raw.GetCRC15(false);
|
||||
uint HeaderCRC=Raw.GetCRC15(false);
|
||||
|
||||
// Old AV header does not have header CRC properly set.
|
||||
// Old Unix owners header didn't include string fields into header size,
|
||||
// but included them into CRC, so it couldn't be verified with generic
|
||||
// approach here.
|
||||
if (ShortBlock.HeadCRC!=HeaderCRC && ShortBlock.HeaderType!=HEAD3_SIGN &&
|
||||
ShortBlock.HeaderType!=HEAD3_AV)
|
||||
ShortBlock.HeaderType!=HEAD3_AV &&
|
||||
(ShortBlock.HeaderType!=HEAD3_OLDSERVICE || SubBlockHead.SubType!=UO_HEAD))
|
||||
{
|
||||
bool Recovered=false;
|
||||
if (ShortBlock.HeaderType==HEAD_ENDARC && EndArcHead.RevSpace)
|
||||
@@ -544,6 +549,7 @@ size_t Archive::ReadHeader15()
|
||||
|
||||
return Raw.Size();
|
||||
}
|
||||
#endif // #ifndef SFX_MODULE
|
||||
|
||||
|
||||
size_t Archive::ReadHeader50()
|
||||
@@ -558,6 +564,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 +583,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)
|
||||
bool EncSet=HeadersCrypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,NULL,PswCheck);
|
||||
// Verify password validity. If header is damaged, we cannot rely on
|
||||
// password check value, because it can be damaged too.
|
||||
if (EncSet && CryptHead.UsePswCheck && !BrokenHeader &&
|
||||
memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0)
|
||||
{
|
||||
if (GlobalPassword) // For -p<pwd> or Ctrl+P.
|
||||
{
|
||||
@@ -635,7 +654,7 @@ size_t Archive::ReadHeader50()
|
||||
}
|
||||
|
||||
int SizeToRead=int(BlockSize);
|
||||
SizeToRead-=FirstReadSize-SizeBytes-4; // Adjust overread size bytes if any.
|
||||
SizeToRead-=int(FirstReadSize-SizeBytes-4); // Adjust overread size bytes if any.
|
||||
uint HeaderSize=4+SizeBytes+(uint)BlockSize;
|
||||
|
||||
if (SizeToRead<0 || HeaderSize<SIZEOF_SHORTBLOCKHEAD5)
|
||||
@@ -700,13 +719,12 @@ size_t Archive::ReadHeader50()
|
||||
{
|
||||
case HEAD_CRYPT:
|
||||
{
|
||||
*(BaseBlock *)&CryptHead=ShortBlock;
|
||||
CryptHead.SetBaseBlock(ShortBlock);
|
||||
uint CryptVersion=(uint)Raw.GetV();
|
||||
if (CryptVersion>CRYPT_VERSION)
|
||||
{
|
||||
wchar Info[20];
|
||||
swprintf(Info,ASIZE(Info),L"h%u",CryptVersion);
|
||||
UnkEncVerMsg(FileName,Info);
|
||||
UnkEncVerMsg(FileName,L"h" + std::to_wstring(CryptVersion));
|
||||
FailedHeaderDecryption=true;
|
||||
return 0;
|
||||
}
|
||||
uint EncFlags=(uint)Raw.GetV();
|
||||
@@ -714,9 +732,8 @@ size_t Archive::ReadHeader50()
|
||||
CryptHead.Lg2Count=Raw.Get1();
|
||||
if (CryptHead.Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
|
||||
{
|
||||
wchar Info[20];
|
||||
swprintf(Info,ASIZE(Info),L"hc%u",CryptHead.Lg2Count);
|
||||
UnkEncVerMsg(FileName,Info);
|
||||
UnkEncVerMsg(FileName,L"hc" + std::to_wstring(CryptHead.Lg2Count));
|
||||
FailedHeaderDecryption=true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -728,14 +745,15 @@ size_t Archive::ReadHeader50()
|
||||
byte csum[SIZE_PSWCHECK_CSUM];
|
||||
Raw.GetB(csum,SIZE_PSWCHECK_CSUM);
|
||||
|
||||
sha256_context ctx;
|
||||
sha256_init(&ctx);
|
||||
sha256_process(&ctx, CryptHead.PswCheck, SIZE_PSWCHECK);
|
||||
|
||||
// Exclude this code for rarext.dll, Setup.SFX and unrar_nocrypt.dll linked
|
||||
// without sha256. But still set Encrypted=true for rarext.dll here,
|
||||
// so it can recognize encrypted header archives in archive properties.
|
||||
#ifndef RAR_NOCRYPT
|
||||
byte Digest[SHA256_DIGEST_SIZE];
|
||||
sha256_done(&ctx, Digest);
|
||||
sha256_get(CryptHead.PswCheck, SIZE_PSWCHECK, Digest);
|
||||
|
||||
CryptHead.UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0;
|
||||
#endif
|
||||
}
|
||||
Encrypted=true;
|
||||
}
|
||||
@@ -743,7 +761,7 @@ size_t Archive::ReadHeader50()
|
||||
case HEAD_MAIN:
|
||||
{
|
||||
MainHead.Reset();
|
||||
*(BaseBlock *)&MainHead=ShortBlock;
|
||||
MainHead.SetBaseBlock(ShortBlock);
|
||||
uint ArcFlags=(uint)Raw.GetV();
|
||||
|
||||
Volume=(ArcFlags & MHFL_VOLUME)!=0;
|
||||
@@ -785,7 +803,7 @@ size_t Archive::ReadHeader50()
|
||||
case HEAD_SERVICE:
|
||||
{
|
||||
FileHeader *hd=ShortBlock.HeaderType==HEAD_FILE ? &FileHead:&SubHead;
|
||||
hd->Reset();
|
||||
hd->Reset(); // Clear hash, time fields and other stuff like flags.
|
||||
*(BaseBlock *)hd=ShortBlock;
|
||||
|
||||
bool FileBlock=ShortBlock.HeaderType==HEAD_FILE;
|
||||
@@ -821,9 +839,14 @@ size_t Archive::ReadHeader50()
|
||||
// we may need to use the compression algorithm 15 in the future,
|
||||
// but it was already used in RAR 1.5 and Unpack needs to distinguish
|
||||
// them.
|
||||
hd->UnpVer=(CompInfo & 0x3f) + 50;
|
||||
if (hd->UnpVer!=50) // Only 5.0 compression is known now.
|
||||
hd->UnpVer=VER_UNKNOWN;
|
||||
uint UnpVer=(CompInfo & 0x3f);
|
||||
if (UnpVer==0)
|
||||
hd->UnpVer=VER_PACK5;
|
||||
else
|
||||
if (UnpVer==1)
|
||||
hd->UnpVer=VER_PACK7;
|
||||
else
|
||||
hd->UnpVer=VER_UNKNOWN;
|
||||
|
||||
hd->HostOS=(byte)Raw.GetV();
|
||||
size_t NameSize=(size_t)Raw.GetV();
|
||||
@@ -841,16 +864,29 @@ size_t Archive::ReadHeader50()
|
||||
hd->SubBlock=(hd->Flags & HFL_CHILD)!=0;
|
||||
hd->Solid=FileBlock && (CompInfo & FCI_SOLID)!=0;
|
||||
hd->Dir=(hd->FileFlags & FHFL_DIRECTORY)!=0;
|
||||
hd->WinSize=hd->Dir ? 0:size_t(0x20000)<<((CompInfo>>10)&0xf);
|
||||
if (hd->Dir || UnpVer>1)
|
||||
hd->WinSize=0;
|
||||
else
|
||||
{
|
||||
hd->WinSize=0x20000ULL<<((CompInfo>>10)&(UnpVer==0 ? 0x0f:0x1f));
|
||||
if (UnpVer==1)
|
||||
{
|
||||
hd->WinSize+=hd->WinSize/32*((CompInfo>>15)&0x1f);
|
||||
|
||||
hd->CryptMethod=hd->Encrypted ? CRYPT_RAR50:CRYPT_NONE;
|
||||
// RAR7 header with RAR5 compression. Needed to append RAR7 files
|
||||
// to RAR5 solid stream if new dictionary is larger than existing.
|
||||
if ((CompInfo & FCI_RAR5_COMPAT)!=0)
|
||||
hd->UnpVer=VER_PACK5;
|
||||
if (hd->WinSize>UNPACK_MAX_DICT)
|
||||
hd->UnpVer=VER_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
char FileName[NM*4];
|
||||
size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
|
||||
Raw.GetB((byte *)FileName,ReadNameSize);
|
||||
FileName[ReadNameSize]=0;
|
||||
size_t ReadNameSize=Min(NameSize,MAXPATHSIZE);
|
||||
std::string FileName(ReadNameSize,0);
|
||||
Raw.GetB((byte *)&FileName[0],ReadNameSize);
|
||||
|
||||
UtfToWide(FileName,hd->FileName,ASIZE(hd->FileName));
|
||||
UtfToWide(FileName.data(),hd->FileName);
|
||||
|
||||
// Should do it before converting names, because extra fields can
|
||||
// affect name processing, like in case of NTFS streams.
|
||||
@@ -868,20 +904,16 @@ 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)
|
||||
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;
|
||||
// It is stored as a single byte up to RAR 6.02 and as vint since
|
||||
// 6.10, where we extended the maximum RR size from 99% to 1000%.
|
||||
RawRead RawPercent;
|
||||
RawPercent.Read(hd->SubData.data(),hd->SubData.size());
|
||||
RecoveryPercent=(int)RawPercent.GetV();
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
if (BadCRC) // Add the file name to broken header message displayed above.
|
||||
uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName);
|
||||
@@ -889,7 +921,7 @@ size_t Archive::ReadHeader50()
|
||||
break;
|
||||
case HEAD_ENDARC:
|
||||
{
|
||||
*(BaseBlock *)&EndArcHead=ShortBlock;
|
||||
EndArcHead.SetBaseBlock(ShortBlock);
|
||||
uint ArcFlags=(uint)Raw.GetV();
|
||||
EndArcHead.NextVolume=(ArcFlags & EHFL_NEXTVOLUME)!=0;
|
||||
EndArcHead.StoreVolNumber=false;
|
||||
@@ -904,7 +936,7 @@ size_t Archive::ReadHeader50()
|
||||
|
||||
|
||||
#if !defined(RAR_NOCRYPT)
|
||||
void Archive::RequestArcPassword()
|
||||
void Archive::RequestArcPassword(RarCheckPassword *CheckPwd)
|
||||
{
|
||||
if (!Cmd->Password.IsSet())
|
||||
{
|
||||
@@ -921,7 +953,7 @@ void Archive::RequestArcPassword()
|
||||
*PasswordA=0;
|
||||
if (Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)PasswordA,ASIZE(PasswordA))==-1)
|
||||
*PasswordA=0;
|
||||
GetWideName(PasswordA,NULL,PasswordW,ASIZE(PasswordW));
|
||||
CharToWide(PasswordA,PasswordW,ASIZE(PasswordW));
|
||||
cleandata(PasswordA,sizeof(PasswordA));
|
||||
}
|
||||
Cmd->Password.Set(PasswordW);
|
||||
@@ -934,7 +966,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 +979,7 @@ void Archive::RequestArcPassword()
|
||||
#endif
|
||||
|
||||
|
||||
void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
|
||||
void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,const BaseBlock *bb)
|
||||
{
|
||||
// Read extra data from the end of block skipping any fields before it.
|
||||
size_t ExtraStart=Raw->Size()-ExtraSize;
|
||||
@@ -970,22 +1002,52 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
|
||||
if (bb->HeaderType==HEAD_MAIN)
|
||||
{
|
||||
MainHeader *hd=(MainHeader *)bb;
|
||||
if (FieldType==MHEXTRA_LOCATOR)
|
||||
switch(FieldType)
|
||||
{
|
||||
hd->Locator=true;
|
||||
uint Flags=(uint)Raw->GetV();
|
||||
if ((Flags & MHEXTRA_LOCATOR_QLIST)!=0)
|
||||
{
|
||||
uint64 Offset=Raw->GetV();
|
||||
if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
|
||||
hd->QOpenOffset=Offset+CurBlockPos;
|
||||
}
|
||||
if ((Flags & MHEXTRA_LOCATOR_RR)!=0)
|
||||
{
|
||||
uint64 Offset=Raw->GetV();
|
||||
if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
|
||||
hd->RROffset=Offset+CurBlockPos;
|
||||
}
|
||||
case MHEXTRA_LOCATOR:
|
||||
{
|
||||
hd->Locator=true;
|
||||
uint Flags=(uint)Raw->GetV();
|
||||
if ((Flags & MHEXTRA_LOCATOR_QLIST)!=0)
|
||||
{
|
||||
uint64 Offset=Raw->GetV();
|
||||
if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
|
||||
hd->QOpenOffset=Offset+CurBlockPos;
|
||||
}
|
||||
if ((Flags & MHEXTRA_LOCATOR_RR)!=0)
|
||||
{
|
||||
uint64 Offset=Raw->GetV();
|
||||
if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
|
||||
hd->RROffset=Offset+CurBlockPos;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MHEXTRA_METADATA:
|
||||
{
|
||||
uint Flags=(uint)Raw->GetV();
|
||||
if ((Flags & MHEXTRA_METADATA_NAME)!=0)
|
||||
{
|
||||
uint64 NameSize=Raw->GetV();
|
||||
if (NameSize>0 && NameSize<MAXPATHSIZE) // Prevent excessive allocation.
|
||||
{
|
||||
std::string NameU((size_t)NameSize,0); // 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)
|
||||
UtfToWide(&NameU[0],hd->OrigName);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -994,64 +1056,64 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
|
||||
FileHeader *hd=(FileHeader *)bb;
|
||||
switch(FieldType)
|
||||
{
|
||||
#ifndef RAR_NOCRYPT // Except rarext.dll, Setup.SFX and unrar_nocrypt.dll.
|
||||
case FHEXTRA_CRYPT:
|
||||
{
|
||||
FileHeader *hd=(FileHeader *)bb;
|
||||
uint EncVersion=(uint)Raw->GetV();
|
||||
if (EncVersion>CRYPT_VERSION)
|
||||
{
|
||||
wchar Info[20];
|
||||
swprintf(Info,ASIZE(Info),L"x%u",EncVersion);
|
||||
UnkEncVerMsg(hd->FileName,Info);
|
||||
UnkEncVerMsg(hd->FileName,L"x" + std::to_wstring(EncVersion));
|
||||
hd->CryptMethod=CRYPT_UNKNOWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint Flags=(uint)Raw->GetV();
|
||||
hd->UsePswCheck=(Flags & FHEXTRA_CRYPT_PSWCHECK)!=0;
|
||||
hd->UseHashKey=(Flags & FHEXTRA_CRYPT_HASHMAC)!=0;
|
||||
hd->Lg2Count=Raw->Get1();
|
||||
if (hd->Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
|
||||
{
|
||||
wchar Info[20];
|
||||
swprintf(Info,ASIZE(Info),L"xc%u",hd->Lg2Count);
|
||||
UnkEncVerMsg(hd->FileName,Info);
|
||||
UnkEncVerMsg(hd->FileName,L"xc" + std::to_wstring(hd->Lg2Count));
|
||||
hd->CryptMethod=CRYPT_UNKNOWN;
|
||||
}
|
||||
Raw->GetB(hd->Salt,SIZE_SALT50);
|
||||
Raw->GetB(hd->InitV,SIZE_INITV);
|
||||
if (hd->UsePswCheck)
|
||||
else
|
||||
{
|
||||
Raw->GetB(hd->PswCheck,SIZE_PSWCHECK);
|
||||
hd->UsePswCheck=(Flags & FHEXTRA_CRYPT_PSWCHECK)!=0;
|
||||
hd->UseHashKey=(Flags & FHEXTRA_CRYPT_HASHMAC)!=0;
|
||||
|
||||
// It is important to know if password check data is valid.
|
||||
// If it is damaged and header CRC32 fails to detect it,
|
||||
// archiver would refuse to decompress a possibly valid file.
|
||||
// Since we want to be sure distinguishing a wrong password
|
||||
// or corrupt file data, we use 64-bit password check data
|
||||
// and to control its validity we use 32 bits of password
|
||||
// check data SHA-256 additionally to 32-bit header CRC32.
|
||||
byte csum[SIZE_PSWCHECK_CSUM];
|
||||
Raw->GetB(csum,SIZE_PSWCHECK_CSUM);
|
||||
Raw->GetB(hd->Salt,SIZE_SALT50);
|
||||
Raw->GetB(hd->InitV,SIZE_INITV);
|
||||
if (hd->UsePswCheck)
|
||||
{
|
||||
Raw->GetB(hd->PswCheck,SIZE_PSWCHECK);
|
||||
|
||||
sha256_context ctx;
|
||||
sha256_init(&ctx);
|
||||
sha256_process(&ctx, hd->PswCheck, SIZE_PSWCHECK);
|
||||
// It is important to know if password check data is valid.
|
||||
// If it is damaged and header CRC32 fails to detect it,
|
||||
// archiver would refuse to decompress a possibly valid file.
|
||||
// Since we want to be sure distinguishing a wrong password
|
||||
// or corrupt file data, we use 64-bit password check data
|
||||
// and to control its validity we use 32 bits of password
|
||||
// check data SHA-256 additionally to 32-bit header CRC32.
|
||||
byte csum[SIZE_PSWCHECK_CSUM];
|
||||
Raw->GetB(csum,SIZE_PSWCHECK_CSUM);
|
||||
|
||||
byte Digest[SHA256_DIGEST_SIZE];
|
||||
sha256_done(&ctx, Digest);
|
||||
byte Digest[SHA256_DIGEST_SIZE];
|
||||
sha256_get(hd->PswCheck, SIZE_PSWCHECK, Digest);
|
||||
|
||||
hd->UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0;
|
||||
hd->UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0;
|
||||
|
||||
// RAR 5.21 and earlier set PswCheck field in service records to 0
|
||||
// even if UsePswCheck was present.
|
||||
if (bb->HeaderType==HEAD_SERVICE && memcmp(hd->PswCheck,"\0\0\0\0\0\0\0\0",SIZE_PSWCHECK)==0)
|
||||
hd->UsePswCheck=0;
|
||||
// RAR 5.21 and earlier set PswCheck field in service records to 0
|
||||
// even if UsePswCheck was present.
|
||||
if (bb->HeaderType==HEAD_SERVICE && memcmp(hd->PswCheck,"\0\0\0\0\0\0\0\0",SIZE_PSWCHECK)==0)
|
||||
hd->UsePswCheck=0;
|
||||
}
|
||||
hd->SaltSet=true;
|
||||
hd->CryptMethod=CRYPT_RAR50;
|
||||
hd->Encrypted=true;
|
||||
}
|
||||
hd->SaltSet=true;
|
||||
hd->CryptMethod=CRYPT_RAR50;
|
||||
hd->Encrypted=true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case FHEXTRA_HASH:
|
||||
{
|
||||
FileHeader *hd=(FileHeader *)bb;
|
||||
@@ -1103,31 +1165,27 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
|
||||
if (Version!=0)
|
||||
{
|
||||
hd->Version=true;
|
||||
|
||||
wchar VerText[20];
|
||||
swprintf(VerText,ASIZE(VerText),L";%u",Version);
|
||||
wcsncatz(hd->FileName,VerText,ASIZE(hd->FileName));
|
||||
hd->FileName += L';' + std::to_wstring(Version);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FHEXTRA_REDIR:
|
||||
{
|
||||
hd->RedirType=(FILE_SYSTEM_REDIRECT)Raw->GetV();
|
||||
FILE_SYSTEM_REDIRECT RedirType=(FILE_SYSTEM_REDIRECT)Raw->GetV();
|
||||
uint Flags=(uint)Raw->GetV();
|
||||
hd->DirTarget=(Flags & FHEXTRA_REDIR_DIR)!=0;
|
||||
size_t NameSize=(size_t)Raw->GetV();
|
||||
|
||||
char UtfName[NM*4];
|
||||
*UtfName=0;
|
||||
if (NameSize<ASIZE(UtfName)-1)
|
||||
if (NameSize>0 && NameSize<MAXPATHSIZE)
|
||||
{
|
||||
Raw->GetB(UtfName,NameSize);
|
||||
UtfName[NameSize]=0;
|
||||
}
|
||||
std::string UtfName(NameSize,0);
|
||||
hd->RedirType=RedirType;
|
||||
hd->DirTarget=(Flags & FHEXTRA_REDIR_DIR)!=0;
|
||||
Raw->GetB(&UtfName[0],NameSize);
|
||||
UtfToWide(&UtfName[0],hd->RedirName);
|
||||
#ifdef _WIN_ALL
|
||||
UnixSlashToDos(UtfName,UtfName,ASIZE(UtfName));
|
||||
UnixSlashToDos(hd->RedirName,hd->RedirName);
|
||||
#endif
|
||||
UtfToWide(UtfName,hd->RedirName,ASIZE(hd->RedirName));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FHEXTRA_UOWNER:
|
||||
@@ -1184,8 +1242,8 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
|
||||
// We cannot allocate too much memory here, because above
|
||||
// we check FieldSize againt Raw size and we control that Raw size
|
||||
// is sensible when reading headers.
|
||||
hd->SubData.Alloc((size_t)FieldSize);
|
||||
Raw->GetB(hd->SubData.Addr(0),(size_t)FieldSize);
|
||||
hd->SubData.resize((size_t)FieldSize);
|
||||
Raw->GetB(hd->SubData.data(),(size_t)FieldSize);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1208,7 +1266,7 @@ size_t Archive::ReadHeader14()
|
||||
Raw.GetB(Mark,4);
|
||||
uint HeadSize=Raw.Get2();
|
||||
if (HeadSize<7)
|
||||
return false;
|
||||
return 0;
|
||||
byte Flags=Raw.Get1();
|
||||
NextBlockPos=CurBlockPos+HeadSize;
|
||||
CurHeaderType=HEAD_MAIN;
|
||||
@@ -1231,7 +1289,7 @@ size_t Archive::ReadHeader14()
|
||||
FileHead.FileHash.CRC32=Raw.Get2();
|
||||
FileHead.HeadSize=Raw.Get2();
|
||||
if (FileHead.HeadSize<21)
|
||||
return false;
|
||||
return 0;
|
||||
uint FileTime=Raw.Get4();
|
||||
FileHead.FileAttr=Raw.Get1();
|
||||
FileHead.Flags=Raw.Get1()|LONG_BLOCK;
|
||||
@@ -1255,12 +1313,13 @@ size_t Archive::ReadHeader14()
|
||||
|
||||
Raw.Read(NameSize);
|
||||
|
||||
char FileName[NM];
|
||||
size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
|
||||
Raw.GetB((byte *)FileName,ReadNameSize);
|
||||
FileName[ReadNameSize]=0;
|
||||
IntToExt(FileName,FileName,ASIZE(FileName));
|
||||
CharToWide(FileName,FileHead.FileName,ASIZE(FileHead.FileName));
|
||||
// RAR 1.4 name size is stored in a single byte field and it can't
|
||||
// exceed 255, so additional checks are not needed.
|
||||
std::string FileName(NameSize,0);
|
||||
Raw.GetB((byte *)&FileName[0],NameSize);
|
||||
std::string NameA;
|
||||
OemToExt(FileName,NameA);
|
||||
CharToWide(NameA,FileHead.FileName);
|
||||
ConvertNameCase(FileHead.FileName);
|
||||
ConvertFileHeader(&FileHead);
|
||||
|
||||
@@ -1274,7 +1333,7 @@ size_t Archive::ReadHeader14()
|
||||
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
void Archive::ConvertNameCase(wchar *Name)
|
||||
void Archive::ConvertNameCase(std::wstring &Name)
|
||||
{
|
||||
if (Cmd->ConvertNames==NAMES_UPPERCASE)
|
||||
wcsupper(Name);
|
||||
@@ -1292,7 +1351,7 @@ bool Archive::IsArcDir()
|
||||
|
||||
void Archive::ConvertAttributes()
|
||||
{
|
||||
#if defined(_WIN_ALL) || defined(_EMX)
|
||||
#ifdef _WIN_ALL
|
||||
if (FileHead.HSType!=HSYS_WINDOWS)
|
||||
FileHead.FileAttr=FileHead.Dir ? 0x10 : 0x20;
|
||||
#endif
|
||||
@@ -1357,19 +1416,23 @@ void Archive::ConvertAttributes()
|
||||
|
||||
void Archive::ConvertFileHeader(FileHeader *hd)
|
||||
{
|
||||
/*
|
||||
if (hd->HSType==HSYS_UNKNOWN)
|
||||
if (hd->Dir)
|
||||
hd->FileAttr=0x10;
|
||||
else
|
||||
hd->FileAttr=0x20;
|
||||
*/
|
||||
|
||||
#ifdef _WIN_ALL
|
||||
if (hd->HSType==HSYS_UNIX) // Convert Unix, OS X and Android decomposed chracters to Windows precomposed.
|
||||
ConvertToPrecomposed(hd->FileName,ASIZE(hd->FileName));
|
||||
ConvertToPrecomposed(hd->FileName);
|
||||
#endif
|
||||
|
||||
for (wchar *s=hd->FileName;*s!=0;s++)
|
||||
for (uint I=0;I<hd->FileName.size();I++)
|
||||
{
|
||||
wchar *s=&hd->FileName[I];
|
||||
|
||||
#ifdef _UNIX
|
||||
// Backslash is the invalid character for Windows file headers,
|
||||
// but it can present in Unix file names extracted in Unix.
|
||||
@@ -1377,7 +1440,7 @@ void Archive::ConvertFileHeader(FileHeader *hd)
|
||||
*s='_';
|
||||
#endif
|
||||
|
||||
#if defined(_WIN_ALL) || defined(_EMX)
|
||||
#ifdef _WIN_ALL
|
||||
// RAR 5.0 archives do not use '\' as path separator, so if we see it,
|
||||
// it means that it is a part of Unix file name, which we cannot
|
||||
// extract in Windows.
|
||||
@@ -1402,6 +1465,9 @@ void Archive::ConvertFileHeader(FileHeader *hd)
|
||||
if (*s=='/' || *s=='\\' && Format!=RARFMT50)
|
||||
*s=CPATHDIVIDER;
|
||||
}
|
||||
|
||||
// Zeroes inside might be possible in broken Unicode names decoded with EncodeFileName::Decode.
|
||||
TruncateAtZero(hd->FileName); // Ensure there are no zeroes inside of string.
|
||||
}
|
||||
|
||||
|
||||
@@ -1416,7 +1482,7 @@ int64 Archive::GetStartPos()
|
||||
}
|
||||
|
||||
|
||||
bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode)
|
||||
bool Archive::ReadSubData(std::vector<byte> *UnpData,File *DestFile,bool TestMode)
|
||||
{
|
||||
if (BrokenHeader)
|
||||
{
|
||||
@@ -1424,7 +1490,7 @@ bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode)
|
||||
ErrHandler.SetErrorCode(RARX_CRC);
|
||||
return false;
|
||||
}
|
||||
if (SubHead.Method>5 || SubHead.UnpVer>(Format==RARFMT50 ? VER_UNPACK5:VER_UNPACK))
|
||||
if (SubHead.Method>5 || SubHead.UnpVer>(Format==RARFMT50 ? VER_UNPACK7:VER_UNPACK))
|
||||
{
|
||||
uiMsg(UIERROR_SUBHEADERUNKNOWN,FileName);
|
||||
return false;
|
||||
@@ -1441,7 +1507,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;
|
||||
}
|
||||
@@ -1449,7 +1517,7 @@ bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode)
|
||||
SubDataIO.SetTestMode(true);
|
||||
else
|
||||
{
|
||||
UnpData->Alloc((size_t)SubHead.UnpSize);
|
||||
UnpData->resize((size_t)SubHead.UnpSize);
|
||||
SubDataIO.SetUnpackToMemory(&(*UnpData)[0],(uint)SubHead.UnpSize);
|
||||
}
|
||||
}
|
||||
@@ -1478,7 +1546,7 @@ bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode)
|
||||
uiMsg(UIERROR_SUBHEADERDATABROKEN,FileName,SubHead.FileName);
|
||||
ErrHandler.SetErrorCode(RARX_CRC);
|
||||
if (UnpData!=NULL)
|
||||
UnpData->Reset();
|
||||
UnpData->clear();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
191
unrar/array.hpp
191
unrar/array.hpp
@@ -1,191 +0,0 @@
|
||||
#ifndef _RAR_ARRAY_
|
||||
#define _RAR_ARRAY_
|
||||
|
||||
extern ErrorHandler ErrHandler;
|
||||
|
||||
template <class T> class Array
|
||||
{
|
||||
private:
|
||||
T *Buffer;
|
||||
size_t BufSize;
|
||||
size_t AllocSize;
|
||||
size_t MaxSize;
|
||||
bool Secure; // Clean memory if true.
|
||||
public:
|
||||
Array();
|
||||
Array(size_t Size);
|
||||
Array(const Array &Src); // Copy constructor.
|
||||
~Array();
|
||||
inline void CleanData();
|
||||
inline T& operator [](size_t Item) const;
|
||||
inline T* operator + (size_t Pos);
|
||||
inline size_t Size(); // Returns the size in items, not in bytes.
|
||||
void Add(size_t Items);
|
||||
void Alloc(size_t Items);
|
||||
void Reset();
|
||||
void SoftReset();
|
||||
void operator = (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;}
|
||||
};
|
||||
|
||||
|
||||
template <class T> void Array<T>::CleanData()
|
||||
{
|
||||
Buffer=NULL;
|
||||
BufSize=0;
|
||||
AllocSize=0;
|
||||
MaxSize=0;
|
||||
Secure=false;
|
||||
}
|
||||
|
||||
|
||||
template <class T> Array<T>::Array()
|
||||
{
|
||||
CleanData();
|
||||
}
|
||||
|
||||
|
||||
template <class T> Array<T>::Array(size_t Size)
|
||||
{
|
||||
CleanData();
|
||||
Add(Size);
|
||||
}
|
||||
|
||||
|
||||
// Copy constructor in case we need to pass an object as value.
|
||||
template <class T> Array<T>::Array(const Array &Src)
|
||||
{
|
||||
CleanData();
|
||||
Alloc(Src.BufSize);
|
||||
if (Src.BufSize!=0)
|
||||
memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T));
|
||||
}
|
||||
|
||||
|
||||
template <class T> Array<T>::~Array()
|
||||
{
|
||||
if (Buffer!=NULL)
|
||||
{
|
||||
if (Secure)
|
||||
cleandata(Buffer,AllocSize*sizeof(T));
|
||||
free(Buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class T> inline T& Array<T>::operator [](size_t Item) const
|
||||
{
|
||||
return Buffer[Item];
|
||||
}
|
||||
|
||||
|
||||
template <class T> inline T* Array<T>::operator +(size_t Pos)
|
||||
{
|
||||
return Buffer+Pos;
|
||||
}
|
||||
|
||||
|
||||
template <class T> inline size_t Array<T>::Size()
|
||||
{
|
||||
return BufSize;
|
||||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::Add(size_t Items)
|
||||
{
|
||||
BufSize+=Items;
|
||||
if (BufSize>AllocSize)
|
||||
{
|
||||
if (MaxSize!=0 && BufSize>MaxSize)
|
||||
{
|
||||
ErrHandler.GeneralErrMsg(L"Maximum allowed array size (%u) is exceeded",MaxSize);
|
||||
ErrHandler.MemoryError();
|
||||
}
|
||||
|
||||
size_t Suggested=AllocSize+AllocSize/4+32;
|
||||
size_t NewSize=Max(BufSize,Suggested);
|
||||
|
||||
T *NewBuffer;
|
||||
if (Secure)
|
||||
{
|
||||
NewBuffer=(T *)malloc(NewSize*sizeof(T));
|
||||
if (NewBuffer==NULL)
|
||||
ErrHandler.MemoryError();
|
||||
if (Buffer!=NULL)
|
||||
{
|
||||
memcpy(NewBuffer,Buffer,AllocSize*sizeof(T));
|
||||
cleandata(Buffer,AllocSize*sizeof(T));
|
||||
free(Buffer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NewBuffer=(T *)realloc(Buffer,NewSize*sizeof(T));
|
||||
if (NewBuffer==NULL)
|
||||
ErrHandler.MemoryError();
|
||||
}
|
||||
Buffer=NewBuffer;
|
||||
AllocSize=NewSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::Alloc(size_t Items)
|
||||
{
|
||||
if (Items>AllocSize)
|
||||
Add(Items-BufSize);
|
||||
else
|
||||
BufSize=Items;
|
||||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::Reset()
|
||||
{
|
||||
if (Buffer!=NULL)
|
||||
{
|
||||
free(Buffer);
|
||||
Buffer=NULL;
|
||||
}
|
||||
BufSize=0;
|
||||
AllocSize=0;
|
||||
}
|
||||
|
||||
|
||||
// Reset buffer size, but preserve already allocated memory if any,
|
||||
// so we can reuse it without wasting time to allocation.
|
||||
template <class T> void Array<T>::SoftReset()
|
||||
{
|
||||
BufSize=0;
|
||||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::operator =(Array<T> &Src)
|
||||
{
|
||||
Reset();
|
||||
Alloc(Src.BufSize);
|
||||
if (Src.BufSize!=0)
|
||||
memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T));
|
||||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::Push(T Item)
|
||||
{
|
||||
Add(1);
|
||||
(*this)[Size()-1]=Item;
|
||||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::Append(T *Items,size_t Count)
|
||||
{
|
||||
size_t CurSize=Size();
|
||||
Add(Count);
|
||||
memcpy(Buffer+CurSize,Items,Count*sizeof(T));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -2,6 +2,20 @@
|
||||
|
||||
#include "rar.hpp"
|
||||
|
||||
static const byte blake2s_sigma[10][16] =
|
||||
{
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
|
||||
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
|
||||
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
|
||||
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
|
||||
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
|
||||
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
|
||||
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
|
||||
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
|
||||
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
|
||||
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
|
||||
};
|
||||
|
||||
#ifdef USE_SSE
|
||||
#include "blake2s_sse.cpp"
|
||||
#endif
|
||||
@@ -18,20 +32,6 @@ static const uint32 blake2s_IV[8] =
|
||||
0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL
|
||||
};
|
||||
|
||||
static const byte blake2s_sigma[10][16] =
|
||||
{
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
|
||||
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
|
||||
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
|
||||
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
|
||||
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
|
||||
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
|
||||
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
|
||||
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
|
||||
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
|
||||
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
|
||||
};
|
||||
|
||||
static inline void blake2s_set_lastnode( blake2s_state *S )
|
||||
{
|
||||
S->f[1] = ~0U;
|
||||
@@ -134,11 +134,7 @@ void blake2s_update( blake2s_state *S, const byte *in, size_t inlen )
|
||||
blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES );
|
||||
|
||||
#ifdef USE_SSE
|
||||
#ifdef _WIN_32 // We use SSSE3 _mm_shuffle_epi8 only in x64 mode.
|
||||
if (_SSE_Version>=SSE_SSE2)
|
||||
#else
|
||||
if (_SSE_Version>=SSE_SSSE3)
|
||||
#endif
|
||||
blake2s_compress_sse( S, S->buf );
|
||||
else
|
||||
blake2s_compress( S, S->buf ); // Compress
|
||||
|
||||
@@ -5,12 +5,9 @@
|
||||
#define BLAKE2_DIGEST_SIZE 32
|
||||
#define BLAKE2_THREADS_NUMBER 8
|
||||
|
||||
enum blake2s_constant
|
||||
{
|
||||
BLAKE2S_BLOCKBYTES = 64,
|
||||
BLAKE2S_OUTBYTES = 32
|
||||
};
|
||||
|
||||
// Use constexpr instead of enums for -std=c++20 compatibility.
|
||||
constexpr size_t BLAKE2S_BLOCKBYTES = 64;
|
||||
constexpr size_t BLAKE2S_OUTBYTES = 32;
|
||||
|
||||
// Alignment to 64 improves performance of both SSE and non-SSE versions.
|
||||
// Alignment to n*16 is required for SSE version, so we selected 64.
|
||||
@@ -20,10 +17,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];
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
// Based on public domain code written in 2012 by Samuel Neves
|
||||
|
||||
extern const byte blake2s_sigma[10][16];
|
||||
|
||||
// Initialization vector.
|
||||
static __m128i blake2s_IV_0_3, blake2s_IV_4_7;
|
||||
|
||||
#ifdef _WIN_64
|
||||
// Constants for cyclic rotation. Used in 64-bit mode in mm_rotr_epi32 macro.
|
||||
// Constants for cyclic rotation.
|
||||
static __m128i crotr8, crotr16;
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
__attribute__((target("sse2")))
|
||||
#endif
|
||||
static void blake2s_init_sse()
|
||||
{
|
||||
// We cannot initialize these 128 bit variables in place when declaring
|
||||
@@ -24,28 +23,18 @@ static void blake2s_init_sse()
|
||||
blake2s_IV_0_3 = _mm_setr_epi32( 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A );
|
||||
blake2s_IV_4_7 = _mm_setr_epi32( 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 );
|
||||
|
||||
#ifdef _WIN_64
|
||||
crotr8 = _mm_set_epi8( 12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1 );
|
||||
crotr16 = _mm_set_epi8( 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2 );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#define LOAD(p) _mm_load_si128( (__m128i *)(p) )
|
||||
#define STORE(p,r) _mm_store_si128((__m128i *)(p), r)
|
||||
|
||||
#ifdef _WIN_32
|
||||
// 32-bit mode has less SSE2 registers and in MSVC2008 it is more efficient
|
||||
// to not use _mm_shuffle_epi8 here.
|
||||
#define mm_rotr_epi32(r, c) ( \
|
||||
_mm_xor_si128(_mm_srli_epi32( (r), c ),_mm_slli_epi32( (r), 32-c )) )
|
||||
#else
|
||||
#define mm_rotr_epi32(r, c) ( \
|
||||
c==8 ? _mm_shuffle_epi8(r,crotr8) \
|
||||
: c==16 ? _mm_shuffle_epi8(r,crotr16) \
|
||||
: _mm_xor_si128(_mm_srli_epi32( (r), c ),_mm_slli_epi32( (r), 32-c )) )
|
||||
#endif
|
||||
|
||||
|
||||
#define G1(row1,row2,row3,row4,buf) \
|
||||
row1 = _mm_add_epi32( _mm_add_epi32( row1, buf), row2 ); \
|
||||
@@ -73,14 +62,6 @@ static void blake2s_init_sse()
|
||||
row3 = _mm_shuffle_epi32( row3, _MM_SHUFFLE(1,0,3,2) ); \
|
||||
row2 = _mm_shuffle_epi32( row2, _MM_SHUFFLE(2,1,0,3) );
|
||||
|
||||
#ifdef _WIN_64
|
||||
// MSVC 2008 in x64 mode expands _mm_set_epi32 to store to stack and load
|
||||
// from stack operations, which are slower than this code.
|
||||
#define _mm_set_epi32(i3,i2,i1,i0) \
|
||||
_mm_unpacklo_epi32(_mm_unpacklo_epi32(_mm_cvtsi32_si128(i0),_mm_cvtsi32_si128(i2)), \
|
||||
_mm_unpacklo_epi32(_mm_cvtsi32_si128(i1),_mm_cvtsi32_si128(i3)))
|
||||
#endif
|
||||
|
||||
// Original BLAKE2 SSE4.1 message loading code was a little slower in x86 mode
|
||||
// and about the same in x64 mode in our test. Perhaps depends on compiler.
|
||||
// We also tried _mm_i32gather_epi32 and _mm256_i32gather_epi32 AVX2 gather
|
||||
@@ -101,6 +82,9 @@ static void blake2s_init_sse()
|
||||
}
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
__attribute__((target("ssse3")))
|
||||
#endif
|
||||
static int blake2s_compress_sse( blake2s_state *S, const byte block[BLAKE2S_BLOCKBYTES] )
|
||||
{
|
||||
__m128i row[4];
|
||||
|
||||
@@ -20,7 +20,7 @@ void blake2sp_init( blake2sp_state *S )
|
||||
|
||||
blake2s_init_param( &S->R, 0, 1 ); // Init root.
|
||||
|
||||
for( uint i = 0; i < PARALLELISM_DEGREE; ++i )
|
||||
for( uint32 i = 0; i < PARALLELISM_DEGREE; ++i )
|
||||
blake2s_init_param( &S->S[i], i, 0 ); // Init leaf.
|
||||
|
||||
S->R.last_node = 1;
|
||||
@@ -49,6 +49,8 @@ void Blake2ThreadData::Update()
|
||||
if (_SSE_Version>=SSE_SSE && inlen__ >= 2 * PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES)
|
||||
_mm_prefetch((char*)(in__ + PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES), _MM_HINT_T0);
|
||||
#endif
|
||||
// We tried to _forceinline blake2s_update and blake2s_compress_sse,
|
||||
// but it didn't improve performance.
|
||||
blake2s_update( S, in__, BLAKE2S_BLOCKBYTES );
|
||||
in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
|
||||
inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
|
||||
|
||||
@@ -13,8 +13,18 @@ void CommandData::Init()
|
||||
{
|
||||
RAROptions::Init();
|
||||
|
||||
*Command=0;
|
||||
*ArcName=0;
|
||||
Command.clear();
|
||||
ArcName.clear();
|
||||
ExtrPath.clear();
|
||||
TempPath.clear();
|
||||
SFXModule.clear();
|
||||
CommentFile.clear();
|
||||
ArcPath.clear();
|
||||
ExclArcPath.clear();
|
||||
LogName.clear();
|
||||
EmailTo.clear();
|
||||
UseStdin.clear();
|
||||
|
||||
FileLists=false;
|
||||
NoMoreSwitches=false;
|
||||
|
||||
@@ -26,61 +36,52 @@ void CommandData::Init()
|
||||
FileArgs.Reset();
|
||||
ExclArgs.Reset();
|
||||
InclArgs.Reset();
|
||||
StoreArgs.Reset();
|
||||
ArcNames.Reset();
|
||||
NextVolSizes.Reset();
|
||||
}
|
||||
|
||||
|
||||
// Return the pointer to next position in the string and store dynamically
|
||||
// allocated command line parameter in Par.
|
||||
static const wchar *AllocCmdParam(const wchar *CmdLine,wchar **Par)
|
||||
{
|
||||
const wchar *NextCmd=GetCmdParam(CmdLine,NULL,0);
|
||||
if (NextCmd==NULL)
|
||||
return NULL;
|
||||
size_t ParSize=NextCmd-CmdLine+2; // Parameter size including the trailing zero.
|
||||
*Par=(wchar *)malloc(ParSize*sizeof(wchar));
|
||||
if (*Par==NULL)
|
||||
return NULL;
|
||||
return GetCmdParam(CmdLine,*Par,ParSize);
|
||||
StoreArgs.Reset();
|
||||
#ifdef PROPAGATE_MOTW
|
||||
MotwList.Reset();
|
||||
#endif
|
||||
Password.Clean();
|
||||
NextVolSizes.clear();
|
||||
#ifdef RARDLL
|
||||
DllDestName.clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if !defined(SFX_MODULE)
|
||||
void CommandData::ParseCommandLine(bool Preprocess,int argc, char *argv[])
|
||||
{
|
||||
*Command=0;
|
||||
Command.clear();
|
||||
NoMoreSwitches=false;
|
||||
#ifdef CUSTOM_CMDLINE_PARSER
|
||||
// In Windows we may prefer to implement our own command line parser
|
||||
// to avoid replacing \" by " in standard parser. Such replacing corrupts
|
||||
// destination paths like "dest path\" in extraction commands.
|
||||
// Also our own parser is Unicode compatible.
|
||||
const wchar *CmdLine=GetCommandLine();
|
||||
std::wstring CmdLine=GetCommandLine();
|
||||
|
||||
std::wstring Param;
|
||||
std::wstring::size_type Pos=0;
|
||||
|
||||
wchar *Par;
|
||||
for (bool FirstParam=true;;FirstParam=false)
|
||||
{
|
||||
if ((CmdLine=AllocCmdParam(CmdLine,&Par))==NULL)
|
||||
if (!GetCmdParam(CmdLine,Pos,Param))
|
||||
break;
|
||||
if (!FirstParam) // First parameter is the executable name.
|
||||
if (Preprocess)
|
||||
PreprocessArg(Par);
|
||||
PreprocessArg(Param.c_str());
|
||||
else
|
||||
ParseArg(Par);
|
||||
free(Par);
|
||||
ParseArg(Param.c_str());
|
||||
}
|
||||
#else
|
||||
Array<wchar> Arg;
|
||||
for (int I=1;I<argc;I++)
|
||||
{
|
||||
Arg.Alloc(strlen(argv[I])+1);
|
||||
CharToWide(argv[I],&Arg[0],Arg.Size());
|
||||
std::wstring Arg;
|
||||
CharToWide(argv[I],Arg);
|
||||
if (Preprocess)
|
||||
PreprocessArg(&Arg[0]);
|
||||
PreprocessArg(Arg.c_str());
|
||||
else
|
||||
ParseArg(&Arg[0]);
|
||||
ParseArg(Arg.c_str());
|
||||
}
|
||||
#endif
|
||||
if (!Preprocess)
|
||||
@@ -90,7 +91,7 @@ void CommandData::ParseCommandLine(bool Preprocess,int argc, char *argv[])
|
||||
|
||||
|
||||
#if !defined(SFX_MODULE)
|
||||
void CommandData::ParseArg(wchar *Arg)
|
||||
void CommandData::ParseArg(const wchar *Arg)
|
||||
{
|
||||
if (IsSwitch(*Arg) && !NoMoreSwitches)
|
||||
if (Arg[1]=='-' && Arg[2]==0)
|
||||
@@ -98,34 +99,52 @@ void CommandData::ParseArg(wchar *Arg)
|
||||
else
|
||||
ProcessSwitch(Arg+1);
|
||||
else
|
||||
if (*Command==0)
|
||||
if (Command.empty())
|
||||
{
|
||||
wcsncpyz(Command,Arg,ASIZE(Command));
|
||||
Command=Arg;
|
||||
|
||||
|
||||
*Command=toupperw(*Command);
|
||||
Command[0]=toupperw(Command[0]);
|
||||
// 'I' and 'S' commands can contain case sensitive strings after
|
||||
// the first character, so we must not modify their case.
|
||||
// 'S' can contain SFX name, which case is important in Unix.
|
||||
if (*Command!='I' && *Command!='S')
|
||||
if (Command[0]!='I' && Command[0]!='S')
|
||||
wcsupper(Command);
|
||||
if (Command[0]=='P') // Enforce -idq for print command.
|
||||
{
|
||||
MsgStream=MSG_ERRONLY;
|
||||
SetConsoleMsgStream(MSG_ERRONLY);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (*ArcName==0)
|
||||
wcsncpyz(ArcName,Arg,ASIZE(ArcName));
|
||||
if (ArcName.empty())
|
||||
ArcName=Arg;
|
||||
else
|
||||
{
|
||||
// Check if last character is the path separator.
|
||||
size_t Length=wcslen(Arg);
|
||||
wchar EndChar=Length==0 ? 0:Arg[Length-1];
|
||||
bool EndSeparator=IsDriveDiv(EndChar) || IsPathDiv(EndChar);
|
||||
// Check if trailing path separator like path\ is present.
|
||||
bool FolderArg=IsDriveDiv(EndChar) || IsPathDiv(EndChar);
|
||||
|
||||
wchar CmdChar=toupperw(*Command);
|
||||
// 2024.01.05: We were asked to support exotic d:. and d:.. paths.
|
||||
if (IsDriveLetter(Arg) && Arg[2]=='.' && (Arg[3]==0 || Arg[3]=='.' && Arg[4]==0))
|
||||
FolderArg=true;
|
||||
|
||||
// 2024.01.06: FindFile::FastFind check below fails in Windows 10 if
|
||||
// "." or ".." points at disk root. So we enforce it for "." and ".."
|
||||
// optionally preceded with some path like "..\..".
|
||||
size_t L=Length;
|
||||
if (L>0 && Arg[L-1]=='.' && (L==1 || L>=2 && (IsPathDiv(Arg[L-2]) ||
|
||||
Arg[L-2]=='.' && (L==2 || L>=3 && IsPathDiv(Arg[L-3])))))
|
||||
FolderArg=true;
|
||||
|
||||
wchar CmdChar=toupperw(Command[0]);
|
||||
bool Add=wcschr(L"AFUM",CmdChar)!=NULL;
|
||||
bool Extract=CmdChar=='X' || CmdChar=='E';
|
||||
bool Repair=CmdChar=='R' && Command[1]==0;
|
||||
if (EndSeparator && !Add)
|
||||
wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath));
|
||||
if (FolderArg && !Add)
|
||||
ExtrPath=Arg;
|
||||
else
|
||||
if ((Add || CmdChar=='T') && (*Arg!='@' || ListMode==RCLM_REJECT_LISTS))
|
||||
FileArgs.AddString(Arg);
|
||||
@@ -142,10 +161,10 @@ void CommandData::ParseArg(wchar *Arg)
|
||||
|
||||
}
|
||||
else // We use 'destpath\' when extracting and reparing.
|
||||
if (Found && FileData.IsDir && (Extract || Repair) && *ExtrPath==0)
|
||||
if (Found && FileData.IsDir && (Extract || Repair) && ExtrPath.empty())
|
||||
{
|
||||
wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath));
|
||||
AddEndSlash(ExtrPath,ASIZE(ExtrPath));
|
||||
ExtrPath=Arg;
|
||||
AddEndSlash(ExtrPath);
|
||||
}
|
||||
else
|
||||
FileArgs.AddString(Arg);
|
||||
@@ -173,12 +192,12 @@ void CommandData::ParseDone()
|
||||
#if !defined(SFX_MODULE)
|
||||
void CommandData::ParseEnvVar()
|
||||
{
|
||||
char *EnvStr=getenv("RAR");
|
||||
if (EnvStr!=NULL)
|
||||
char *EnvVar=getenv("RARINISWITCHES");
|
||||
if (EnvVar!=NULL)
|
||||
{
|
||||
Array<wchar> EnvStrW(strlen(EnvStr)+1);
|
||||
CharToWide(EnvStr,&EnvStrW[0],EnvStrW.Size());
|
||||
ProcessSwitchesString(&EnvStrW[0]);
|
||||
std::wstring EnvStr;
|
||||
CharToWide(EnvVar,EnvStr);
|
||||
ProcessSwitchesString(EnvStr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -187,7 +206,7 @@ void CommandData::ParseEnvVar()
|
||||
|
||||
#if !defined(SFX_MODULE)
|
||||
// Preprocess those parameters, which must be processed before the rest of
|
||||
// command line. Return 'false' to stop further processing.
|
||||
// command line.
|
||||
void CommandData::PreprocessArg(const wchar *Arg)
|
||||
{
|
||||
if (IsSwitch(Arg[0]) && !NoMoreSwitches)
|
||||
@@ -196,7 +215,7 @@ void CommandData::PreprocessArg(const wchar *Arg)
|
||||
if (Arg[0]=='-' && Arg[1]==0) // Switch "--".
|
||||
NoMoreSwitches=true;
|
||||
if (wcsicomp(Arg,L"cfg-")==0)
|
||||
ConfigDisabled=true;
|
||||
ProcessSwitch(Arg);
|
||||
if (wcsnicomp(Arg,L"ilog",4)==0)
|
||||
{
|
||||
// Ensure that correct log file name is already set
|
||||
@@ -208,13 +227,13 @@ void CommandData::PreprocessArg(const wchar *Arg)
|
||||
{
|
||||
// Process -sc before reading any file lists.
|
||||
ProcessSwitch(Arg);
|
||||
if (*LogName!=0)
|
||||
if (!LogName.empty())
|
||||
InitLogOptions(LogName,ErrlogCharset);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (*Command==0)
|
||||
wcsncpy(Command,Arg,ASIZE(Command)); // Need for rar.ini.
|
||||
if (Command.empty())
|
||||
Command=Arg; // Need for rar.ini.
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -232,10 +251,10 @@ void CommandData::ReadConfig()
|
||||
Str++;
|
||||
if (wcsnicomp(Str,L"switches=",9)==0)
|
||||
ProcessSwitchesString(Str+9);
|
||||
if (*Command!=0)
|
||||
if (!Command.empty())
|
||||
{
|
||||
wchar Cmd[16];
|
||||
wcsncpyz(Cmd,Command,ASIZE(Cmd));
|
||||
wcsncpyz(Cmd,Command.c_str(),ASIZE(Cmd));
|
||||
wchar C0=toupperw(Cmd[0]);
|
||||
wchar C1=toupperw(Cmd[1]);
|
||||
if (C0=='I' || C0=='L' || C0=='M' || C0=='S' || C0=='V')
|
||||
@@ -255,14 +274,19 @@ void CommandData::ReadConfig()
|
||||
|
||||
|
||||
#if !defined(SFX_MODULE)
|
||||
void CommandData::ProcessSwitchesString(const wchar *Str)
|
||||
void CommandData::ProcessSwitchesString(const std::wstring &Str)
|
||||
{
|
||||
wchar *Par;
|
||||
while ((Str=AllocCmdParam(Str,&Par))!=NULL)
|
||||
std::wstring Par;
|
||||
std::wstring::size_type Pos=0;
|
||||
while (GetCmdParam(Str,Pos,Par))
|
||||
{
|
||||
if (IsSwitch(*Par))
|
||||
ProcessSwitch(Par+1);
|
||||
free(Par);
|
||||
if (IsSwitch(Par[0]))
|
||||
ProcessSwitch(&Par[1]);
|
||||
else
|
||||
{
|
||||
mprintf(St(MSwSyntaxError),Par.c_str());
|
||||
ErrHandler.Exit(RARX_USERERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -272,6 +296,9 @@ void CommandData::ProcessSwitchesString(const wchar *Str)
|
||||
void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
{
|
||||
|
||||
if (LargePageAlloc::ProcessSwitch(this,Switch))
|
||||
return;
|
||||
|
||||
switch(toupperw(Switch[0]))
|
||||
{
|
||||
case '@':
|
||||
@@ -288,7 +315,10 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
AppendArcNameToPath=APPENDARCNAME_DESTPATH;
|
||||
else
|
||||
if (Switch[2]=='1')
|
||||
AppendArcNameToPath=APPENDARCNAME_OWNDIR;
|
||||
AppendArcNameToPath=APPENDARCNAME_OWNSUBDIR;
|
||||
else
|
||||
if (Switch[2]=='2')
|
||||
AppendArcNameToPath=APPENDARCNAME_OWNDIR;
|
||||
break;
|
||||
#ifndef SFX_MODULE
|
||||
case 'G':
|
||||
@@ -307,13 +337,27 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
case 'I':
|
||||
IgnoreGeneralAttr=true;
|
||||
break;
|
||||
case 'N': // Reserved for archive name.
|
||||
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 'O':
|
||||
AddArcOnly=true;
|
||||
break;
|
||||
case 'P':
|
||||
wcsncpyz(ArcPath,Switch+2,ASIZE(ArcPath));
|
||||
// Convert slashes here than before every comparison.
|
||||
SlashToNative(Switch+2,ArcPath);
|
||||
break;
|
||||
case 'S':
|
||||
SyncFiles=true;
|
||||
@@ -324,7 +368,14 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
}
|
||||
break;
|
||||
case 'C':
|
||||
if (Switch[2]==0)
|
||||
if (Switch[2]!=0)
|
||||
{
|
||||
if (wcsicomp(Switch+1,L"FG-")==0)
|
||||
ConfigDisabled=true;
|
||||
else
|
||||
BadSwitch(Switch);
|
||||
}
|
||||
else
|
||||
switch(toupperw(Switch[1]))
|
||||
{
|
||||
case '-':
|
||||
@@ -336,10 +387,15 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
case 'L':
|
||||
ConvertNames=NAMES_LOWERCASE;
|
||||
break;
|
||||
default:
|
||||
BadSwitch(Switch);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'D':
|
||||
if (Switch[2]==0)
|
||||
if (Switch[2]!=0)
|
||||
BadSwitch(Switch);
|
||||
else
|
||||
switch(toupperw(Switch[1]))
|
||||
{
|
||||
case 'S':
|
||||
@@ -351,6 +407,9 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
case 'F':
|
||||
DeleteFiles=true;
|
||||
break;
|
||||
default:
|
||||
BadSwitch(Switch);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'E':
|
||||
@@ -371,6 +430,13 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
case '3':
|
||||
ExclPath=EXCL_ABSPATH;
|
||||
break;
|
||||
case '4':
|
||||
// Convert slashes here than before every comparison.
|
||||
SlashToNative(Switch+3,ExclArcPath);
|
||||
break;
|
||||
default:
|
||||
BadSwitch(Switch);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -397,13 +463,17 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
EncryptHeaders=true;
|
||||
if (Switch[2]!=0)
|
||||
{
|
||||
// We use this code for other archive formats too, so MAXPASSWORD
|
||||
// instead of MAXPASSWORD_RAR.
|
||||
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,L"",&Password,NULL);
|
||||
eprintf(L"\n");
|
||||
}
|
||||
break;
|
||||
@@ -415,7 +485,7 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
case 'I':
|
||||
if (wcsnicomp(Switch+1,L"LOG",3)==0)
|
||||
{
|
||||
wcsncpyz(LogName,Switch[4]!=0 ? Switch+4:DefLogName,ASIZE(LogName));
|
||||
LogName=Switch[4]!=0 ? Switch+4:DefLogName;
|
||||
break;
|
||||
}
|
||||
if (wcsnicomp(Switch+1,L"SND",3)==0)
|
||||
@@ -433,12 +503,12 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
}
|
||||
if (wcsnicomp(Switch+1,L"EML",3)==0)
|
||||
{
|
||||
wcsncpyz(EmailTo,Switch[4]!=0 ? Switch+4:L"@",ASIZE(EmailTo));
|
||||
EmailTo=Switch[4]!=0 ? Switch+4:L"@";
|
||||
break;
|
||||
}
|
||||
if (wcsicomp(Switch+1,L"M")==0)
|
||||
if (wcsicomp(Switch+1,L"M")==0) // For compatibility with pre-WinRAR 6.0 -im syntax. Replaced with -idv.
|
||||
{
|
||||
MoreInfo=true;
|
||||
VerboseOutput=true;
|
||||
break;
|
||||
}
|
||||
if (wcsicomp(Switch+1,L"NUL")==0)
|
||||
@@ -465,6 +535,12 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
case 'P':
|
||||
DisablePercentage=true;
|
||||
break;
|
||||
case 'N':
|
||||
DisableNames=true;
|
||||
break;
|
||||
case 'V':
|
||||
VerboseOutput=true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -534,13 +610,14 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
}
|
||||
switch(toupperw(*(Str++)))
|
||||
{
|
||||
case 'T': Type=FILTER_PPM; break;
|
||||
// case 'T': Type=FILTER_TEXT; break;
|
||||
case 'E': Type=FILTER_E8; break;
|
||||
case 'D': Type=FILTER_DELTA; break;
|
||||
case 'A': Type=FILTER_AUDIO; break;
|
||||
case 'C': Type=FILTER_RGB; break;
|
||||
case 'I': Type=FILTER_ITANIUM; break;
|
||||
case 'R': Type=FILTER_ARM; break;
|
||||
// case 'A': Type=FILTER_AUDIO; break;
|
||||
// case 'C': Type=FILTER_RGB; break;
|
||||
// case 'R': Type=FILTER_ARM; break;
|
||||
case 'L': Type=FILTER_LONGRANGE; break;
|
||||
case 'X': Type=FILTER_EXHAUSTIVE; break;
|
||||
}
|
||||
if (*Str=='+' || *Str=='-')
|
||||
State=*(Str++)=='+' ? FILTER_FORCE:FILTER_DISABLE;
|
||||
@@ -550,42 +627,74 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'M':
|
||||
break;
|
||||
case 'D':
|
||||
break;
|
||||
case 'S':
|
||||
{
|
||||
wchar StoreNames[1024];
|
||||
wcsncpyz(StoreNames,(Switch[2]==0 ? DefaultStoreList:Switch+2),ASIZE(StoreNames));
|
||||
wchar *Names=StoreNames;
|
||||
while (*Names!=0)
|
||||
bool SetDictLimit=toupperw(Switch[2])=='X';
|
||||
|
||||
uint64 Size=atoiw(Switch+(SetDictLimit ? 3 : 2));
|
||||
wchar LastChar=toupperw(Switch[wcslen(Switch)-1]);
|
||||
if (IsDigit(LastChar))
|
||||
LastChar=SetDictLimit ? 'G':'M'; // Treat -md128 as -md128m and -mdx32 as -mdx32g.
|
||||
switch(LastChar)
|
||||
{
|
||||
wchar *End=wcschr(Names,';');
|
||||
if (End!=NULL)
|
||||
*End=0;
|
||||
if (*Names=='.')
|
||||
Names++;
|
||||
wchar Mask[NM];
|
||||
if (wcspbrk(Names,L"*?.")==NULL)
|
||||
swprintf(Mask,ASIZE(Mask),L"*.%ls",Names);
|
||||
else
|
||||
wcsncpyz(Mask,Names,ASIZE(Mask));
|
||||
StoreArgs.AddString(Mask);
|
||||
if (End==NULL)
|
||||
case 'K':
|
||||
Size*=1024;
|
||||
break;
|
||||
Names=End+1;
|
||||
case 'M':
|
||||
Size*=1024*1024;
|
||||
break;
|
||||
case 'G':
|
||||
Size*=1024*1024*1024;
|
||||
break;
|
||||
default:
|
||||
BadSwitch(Switch);
|
||||
}
|
||||
|
||||
// 2023.07.22: For 4 GB and less we also check that it is power of 2,
|
||||
// so archives are compatible with RAR 5.0+.
|
||||
// We allow Size>PACK_MAX_DICT here, so we can use -md[x] to unpack
|
||||
// archives created by future versions with higher PACK_MAX_DICT.
|
||||
uint Flags;
|
||||
if ((Size=Archive::GetWinSize(Size,Flags))==0 ||
|
||||
Size<=0x100000000ULL && !IsPow2(Size))
|
||||
BadSwitch(Switch);
|
||||
else
|
||||
if (SetDictLimit)
|
||||
WinSizeLimit=Size;
|
||||
else
|
||||
{
|
||||
WinSize=Size;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'E':
|
||||
if (toupperw(Switch[2])=='S' && Switch[3]==0)
|
||||
SkipEncrypted=true;
|
||||
break;
|
||||
case 'L':
|
||||
if (toupperw(Switch[2])=='P')
|
||||
{
|
||||
UseLargePages=true;
|
||||
if (!LargePageAlloc::IsPrivilegeAssigned() && LargePageAlloc::AssignConfirmation())
|
||||
{
|
||||
LargePageAlloc::AssignPrivilege();
|
||||
|
||||
// Quit immediately. We do not want to interrupt the current copy
|
||||
// archive processing with reboot after assigning privilege.
|
||||
SetupComplete=true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'M':
|
||||
break;
|
||||
case 'S':
|
||||
GetBriefMaskList(Switch[2]==0 ? DefaultStoreList:Switch+2,StoreArgs);
|
||||
break;
|
||||
#ifdef RAR_SMP
|
||||
case 'T':
|
||||
Threads=atoiw(Switch+2);
|
||||
if (Threads>MaxPoolThreads || Threads<1)
|
||||
BadSwitch(Switch);
|
||||
else
|
||||
{
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
@@ -631,8 +740,31 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
#ifdef SAVE_LINKS
|
||||
case 'L':
|
||||
SaveSymLinks=true;
|
||||
if (toupperw(Switch[2])=='A')
|
||||
AbsoluteLinks=true;
|
||||
for (uint I=2;Switch[I]!=0;I++)
|
||||
switch(toupperw(Switch[I]))
|
||||
{
|
||||
case 'A':
|
||||
AbsoluteLinks=true;
|
||||
break;
|
||||
case '-':
|
||||
SkipSymLinks=true;
|
||||
break;
|
||||
default:
|
||||
BadSwitch(Switch);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef PROPAGATE_MOTW
|
||||
case 'M':
|
||||
{
|
||||
MotwAllFields=Switch[2]=='1';
|
||||
const wchar *Sep=wcschr(Switch+2,'=');
|
||||
if (Switch[2]=='-')
|
||||
MotwList.Reset();
|
||||
else
|
||||
GetBriefMaskList(Sep==nullptr ? L"*":Sep+1,MotwList);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef _WIN_ALL
|
||||
@@ -641,6 +773,10 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
AllowIncompatNames=true;
|
||||
break;
|
||||
#endif
|
||||
case 'P':
|
||||
ExtrPath=Switch+2;
|
||||
AddEndSlash(ExtrPath);
|
||||
break;
|
||||
case 'R':
|
||||
Overwrite=OVERWRITE_AUTORENAME;
|
||||
break;
|
||||
@@ -660,11 +796,13 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
case 'P':
|
||||
if (Switch[1]==0)
|
||||
{
|
||||
uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password);
|
||||
uiGetPassword(UIPASSWORD_GLOBAL,L"",&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]));
|
||||
}
|
||||
@@ -731,7 +869,52 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
switch(toupperw(Switch[1]))
|
||||
{
|
||||
case 0:
|
||||
case '=':
|
||||
Solid|=SOLID_NORMAL;
|
||||
if (Switch[1]=='=')
|
||||
{
|
||||
uint Par=0;
|
||||
for (const wchar *S=Switch+2;*S!=0;S++)
|
||||
{
|
||||
if (IsDigit(*S))
|
||||
Par=Par*10+*S-'0';
|
||||
switch(toupperw(*S))
|
||||
{
|
||||
case '-':
|
||||
Solid=SOLID_NONE;
|
||||
break;
|
||||
case 'D':
|
||||
Solid|=SOLID_VOLUME_DEPENDENT;
|
||||
break;
|
||||
case 'E':
|
||||
Solid|=SOLID_FILEEXT;
|
||||
break;
|
||||
case 'F':
|
||||
Solid|=SOLID_COUNT;
|
||||
SolidCount=Par;
|
||||
break;
|
||||
case 'K':
|
||||
Solid|=SOLID_BLOCK_SIZE;
|
||||
SolidBlockSize=Par*1024LL;
|
||||
break;
|
||||
case 'M':
|
||||
Solid|=SOLID_BLOCK_SIZE;
|
||||
SolidBlockSize=Par*1024LL*1024LL;
|
||||
break;
|
||||
case 'G':
|
||||
Solid|=SOLID_BLOCK_SIZE;
|
||||
SolidBlockSize=Par*1024LL*1024LL*1024LL;
|
||||
break;
|
||||
case 'R':
|
||||
Solid=SOLID_RESET;
|
||||
break;
|
||||
case 'V':
|
||||
Solid|=SOLID_VOLUME_INDEPENDENT;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
Solid=SOLID_NONE;
|
||||
@@ -745,13 +928,22 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
case 'D':
|
||||
Solid|=SOLID_VOLUME_DEPENDENT;
|
||||
break;
|
||||
case 'I':
|
||||
ProhibitConsoleInput();
|
||||
// We do not assign the archive name automatically for -si
|
||||
// if archive name is omitted and require the archive name to
|
||||
// present always. Otherwise for"type arc.rar|rar x -si arc2.rar"
|
||||
// if arc2.rar is a dummy archive name or file inside of arc.rar,
|
||||
// which needs to be extracted.
|
||||
UseStdin=Switch[2] ? Switch+2:L"stdin";
|
||||
break;
|
||||
case 'L':
|
||||
if (IsDigit(Switch[2]))
|
||||
FileSizeLess=atoilw(Switch+2);
|
||||
FileSizeLess=GetModSize(Switch+2,1);
|
||||
break;
|
||||
case 'M':
|
||||
if (IsDigit(Switch[2]))
|
||||
FileSizeMore=atoilw(Switch+2);
|
||||
FileSizeMore=GetModSize(Switch+2,1);
|
||||
break;
|
||||
case 'C':
|
||||
{
|
||||
@@ -809,12 +1001,6 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
case 'T':
|
||||
switch(toupperw(Switch[1]))
|
||||
{
|
||||
case 'K':
|
||||
ArcTime=ARCTIME_KEEP;
|
||||
break;
|
||||
case 'L':
|
||||
ArcTime=ARCTIME_LATEST;
|
||||
break;
|
||||
case 'O':
|
||||
SetTimeFilters(Switch+2,true,true);
|
||||
break;
|
||||
@@ -866,8 +1052,8 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
}
|
||||
break;
|
||||
case 'W':
|
||||
wcsncpyz(TempPath,Switch+1,ASIZE(TempPath));
|
||||
AddEndSlash(TempPath,ASIZE(TempPath));
|
||||
TempPath=Switch+1;
|
||||
AddEndSlash(TempPath);
|
||||
break;
|
||||
case 'Y':
|
||||
AllYes=true;
|
||||
@@ -876,10 +1062,10 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
if (Switch[1]==0)
|
||||
{
|
||||
// If comment file is not specified, we read data from stdin.
|
||||
wcsncpyz(CommentFile,L"stdin",ASIZE(CommentFile));
|
||||
CommentFile=L"stdin";
|
||||
}
|
||||
else
|
||||
wcsncpyz(CommentFile,Switch+1,ASIZE(CommentFile));
|
||||
CommentFile=Switch+1;
|
||||
break;
|
||||
case '?' :
|
||||
OutHelp(RARX_SUCCESS);
|
||||
@@ -906,34 +1092,41 @@ void CommandData::ProcessCommand()
|
||||
#ifndef SFX_MODULE
|
||||
|
||||
const wchar *SingleCharCommands=L"FUADPXETK";
|
||||
if (Command[0]!=0 && Command[1]!=0 && wcschr(SingleCharCommands,Command[0])!=NULL || *ArcName==0)
|
||||
OutHelp(*Command==0 ? RARX_SUCCESS:RARX_USERERROR); // Return 'success' for 'rar' without parameters.
|
||||
|
||||
const wchar *ArcExt=GetExt(ArcName);
|
||||
// RAR -mlp command is the legitimate way to assign the required privilege.
|
||||
if (Command.empty() && UseLargePages || SetupComplete)
|
||||
return;
|
||||
|
||||
if (Command[0]!=0 && Command[1]!=0 && wcschr(SingleCharCommands,Command[0])!=NULL || ArcName.empty())
|
||||
OutHelp(Command.empty() ? RARX_SUCCESS:RARX_USERERROR); // Return 'success' for 'rar' without parameters.
|
||||
|
||||
size_t ExtPos=GetExtPos(ArcName);
|
||||
#ifdef _UNIX
|
||||
if (ArcExt==NULL && (!FileExist(ArcName) || IsDir(GetFileAttr(ArcName))))
|
||||
wcsncatz(ArcName,L".rar",ASIZE(ArcName));
|
||||
// If we want to update an archive without extension, in Windows we can use
|
||||
// "arcname." and it will be treated as "arcname". In Unix "arcname"
|
||||
// and "arcname." are two different names, so we check if "arcname" exists
|
||||
// and do not append ".rar", allowing user to update such archive.
|
||||
if (ExtPos==std::wstring::npos && (!FileExist(ArcName) || IsDir(GetFileAttr(ArcName))))
|
||||
ArcName+=L".rar";
|
||||
#else
|
||||
if (ArcExt==NULL)
|
||||
wcsncatz(ArcName,L".rar",ASIZE(ArcName));
|
||||
if (ExtPos==std::wstring::npos)
|
||||
ArcName+=L".rar";
|
||||
#endif
|
||||
// Treat arcname.part1 as arcname.part1.rar.
|
||||
if (ArcExt!=NULL && wcsnicomp(ArcExt,L".part",5)==0 && IsDigit(ArcExt[5]) &&
|
||||
!FileExist(ArcName))
|
||||
if (ExtPos!=std::wstring::npos && wcsnicomp(&ArcName[ExtPos],L".part",5)==0 &&
|
||||
IsDigit(ArcName[ExtPos+5]) && !FileExist(ArcName))
|
||||
{
|
||||
wchar Name[NM];
|
||||
wcsncpyz(Name,ArcName,ASIZE(Name));
|
||||
wcsncatz(Name,L".rar",ASIZE(Name));
|
||||
std::wstring Name=ArcName+L".rar";
|
||||
if (FileExist(Name))
|
||||
wcsncpyz(ArcName,Name,ASIZE(ArcName));
|
||||
ArcName=Name;
|
||||
}
|
||||
|
||||
if (wcschr(L"AFUMD",*Command)==NULL)
|
||||
if (wcschr(L"AFUMD",Command[0])==NULL && UseStdin.empty())
|
||||
{
|
||||
if (GenerateArcName)
|
||||
{
|
||||
const wchar *Mask=*GenerateMask!=0 ? GenerateMask:DefGenerateMask;
|
||||
GenerateArchiveName(ArcName,ASIZE(ArcName),Mask,false);
|
||||
GenerateArchiveName(ArcName,Mask,false);
|
||||
}
|
||||
|
||||
StringList ArcMasks;
|
||||
@@ -967,12 +1160,22 @@ void CommandData::ProcessCommand()
|
||||
OutHelp(RARX_USERERROR);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Since messages usually include '\n' in the beginning, we also issue
|
||||
// the final '\n'. It is especially important in Unix, where otherwise
|
||||
// the shell can display the prompt on the same line as the last message.
|
||||
// mprintf is blocked with -idq and if error messages had been displayed
|
||||
// in this mode, we use eprintf to separate them from shell prompt.
|
||||
// If nothing was displayed with -idq, we avoid the excessive empty line.
|
||||
if (!BareOutput)
|
||||
mprintf(L"\n");
|
||||
if (MsgStream==MSG_ERRONLY && IsConsoleOutputPresent())
|
||||
eprintf(L"\n");
|
||||
else
|
||||
mprintf(L"\n");
|
||||
}
|
||||
|
||||
|
||||
void CommandData::AddArcName(const wchar *Name)
|
||||
void CommandData::AddArcName(const std::wstring &Name)
|
||||
{
|
||||
ArcNames.AddString(Name);
|
||||
}
|
||||
@@ -984,9 +1187,15 @@ bool CommandData::GetArcName(wchar *Name,int MaxSize)
|
||||
}
|
||||
|
||||
|
||||
bool CommandData::GetArcName(std::wstring &Name)
|
||||
{
|
||||
return ArcNames.GetString(Name);
|
||||
}
|
||||
|
||||
|
||||
bool CommandData::IsSwitch(int Ch)
|
||||
{
|
||||
#if defined(_WIN_ALL) || defined(_EMX)
|
||||
#ifdef _WIN_ALL
|
||||
return Ch=='-' || Ch=='/';
|
||||
#else
|
||||
return Ch=='-';
|
||||
@@ -1012,7 +1221,7 @@ uint CommandData::GetExclAttr(const wchar *Str,bool &Dir)
|
||||
case 'V':
|
||||
Attr|=S_IFCHR;
|
||||
break;
|
||||
#elif defined(_WIN_ALL) || defined(_EMX)
|
||||
#elif defined(_WIN_ALL)
|
||||
case 'R':
|
||||
Attr|=0x1;
|
||||
break;
|
||||
@@ -1036,21 +1245,6 @@ uint CommandData::GetExclAttr(const wchar *Str,bool &Dir)
|
||||
|
||||
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
bool CommandData::CheckWinSize()
|
||||
{
|
||||
// Define 0x100000000 as macro to avoid troubles with older compilers.
|
||||
const uint64 MaxDictSize=INT32TO64(1,0);
|
||||
// Limit the dictionary size to 4 GB.
|
||||
for (uint64 I=0x10000;I<=MaxDictSize;I*=2)
|
||||
if (WinSize==I)
|
||||
return true;
|
||||
WinSize=0x400000;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
void CommandData::ReportWrongSwitches(RARFORMAT Format)
|
||||
{
|
||||
@@ -1080,3 +1274,57 @@ void CommandData::ReportWrongSwitches(RARFORMAT Format)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Get size for string with optional trailing modifiers like "100m".
|
||||
int64 CommandData::GetModSize(const wchar *S,uint DefMultiplier)
|
||||
{
|
||||
int64 Size=0,FloatingDivider=0;
|
||||
for (uint I=0;S[I]!=0;I++)
|
||||
if (IsDigit(S[I]))
|
||||
{
|
||||
Size=Size*10+S[I]-'0';
|
||||
FloatingDivider*=10;
|
||||
}
|
||||
else
|
||||
if (S[I]=='.')
|
||||
FloatingDivider=1;
|
||||
|
||||
if (*S!=0)
|
||||
{
|
||||
const wchar *ModList=L"bBkKmMgGtT";
|
||||
const wchar *Mod=wcschr(ModList,S[wcslen(S)-1]);
|
||||
if (Mod==nullptr)
|
||||
Size*=DefMultiplier;
|
||||
else
|
||||
for (ptrdiff_t I=2;I<=Mod-ModList;I+=2)
|
||||
Size*=((Mod-ModList)&1)!=0 ? 1000:1024;
|
||||
}
|
||||
if (FloatingDivider!=0)
|
||||
Size/=FloatingDivider;
|
||||
return Size;
|
||||
}
|
||||
|
||||
|
||||
// Treat the list like rar;zip as *.rar;*.zip for -ms and similar switches.
|
||||
void CommandData::GetBriefMaskList(const std::wstring &Masks,StringList &Args)
|
||||
{
|
||||
size_t Pos=0;
|
||||
while (Pos<Masks.size())
|
||||
{
|
||||
if (Masks[Pos]=='.')
|
||||
Pos++;
|
||||
size_t EndPos=Masks.find(';',Pos);
|
||||
std::wstring Mask=Masks.substr(Pos,EndPos==std::wstring::npos ? EndPos:EndPos-Pos);
|
||||
if (Mask.find_first_of(L"*?.")==std::wstring::npos)
|
||||
Mask.insert(0,L"*.");
|
||||
Args.AddString(Mask);
|
||||
if (EndPos==std::wstring::npos)
|
||||
break;
|
||||
Pos=EndPos+1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
#ifndef _RAR_CMDDATA_
|
||||
#define _RAR_CMDDATA_
|
||||
|
||||
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
|
||||
// In Windows we implement our own command line parser to avoid replacing
|
||||
// \" by " in standard parser. Such replacing corrupts destination paths
|
||||
// like "dest path\" in extraction commands.
|
||||
#define CUSTOM_CMDLINE_PARSER
|
||||
#endif
|
||||
|
||||
#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;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};
|
||||
|
||||
@@ -11,7 +17,6 @@ enum IS_PROCESS_FILE_FLAGS {IPFF_EXCLUDE_PARENT=1};
|
||||
class CommandData:public RAROptions
|
||||
{
|
||||
private:
|
||||
void ProcessSwitchesString(const wchar *Str);
|
||||
void ProcessSwitch(const wchar *Switch);
|
||||
void BadSwitch(const wchar *Switch);
|
||||
uint GetExclAttr(const wchar *Str,bool &Dir);
|
||||
@@ -19,6 +24,7 @@ class CommandData:public RAROptions
|
||||
void SetTimeFilters(const wchar *Mod,bool Before,bool Age);
|
||||
void SetStoreTimeMode(const wchar *S);
|
||||
#endif
|
||||
int64 GetModSize(const wchar *S,uint DefMultiplier);
|
||||
|
||||
bool FileLists;
|
||||
bool NoMoreSwitches;
|
||||
@@ -29,42 +35,69 @@ class CommandData:public RAROptions
|
||||
void Init();
|
||||
|
||||
void ParseCommandLine(bool Preprocess,int argc, char *argv[]);
|
||||
void ParseArg(wchar *ArgW);
|
||||
void ParseArg(const wchar *ArgW);
|
||||
void ParseDone();
|
||||
void ParseEnvVar();
|
||||
void ReadConfig();
|
||||
void PreprocessArg(const wchar *Arg);
|
||||
void ProcessSwitchesString(const std::wstring &Str);
|
||||
void OutTitle();
|
||||
void OutHelp(RAR_EXIT ExitCode);
|
||||
bool IsSwitch(int Ch);
|
||||
bool ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList);
|
||||
static bool CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode);
|
||||
bool ExclCheck(const std::wstring &CheckName,bool Dir,bool CheckFullPath,bool CheckInclList);
|
||||
static bool CheckArgs(StringList *Args,bool Dir,const std::wstring &CheckName,bool CheckFullPath,int MatchMode);
|
||||
bool ExclDirByAttr(uint FileAttr);
|
||||
bool TimeCheck(RarTime &ftm,RarTime &ftc,RarTime &fta);
|
||||
bool SizeCheck(int64 Size);
|
||||
bool AnyFiltersActive();
|
||||
int IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType,
|
||||
bool Flags,wchar *MatchedArg,uint MatchedArgSize);
|
||||
bool Flags,std::wstring *MatchedArg);
|
||||
void ProcessCommand();
|
||||
void AddArcName(const wchar *Name);
|
||||
void AddArcName(const std::wstring &Name);
|
||||
bool GetArcName(wchar *Name,int MaxSize);
|
||||
bool CheckWinSize();
|
||||
bool GetArcName(std::wstring &Name);
|
||||
|
||||
int GetRecoverySize(const wchar *Str,int DefSize);
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
void ReportWrongSwitches(RARFORMAT Format);
|
||||
#endif
|
||||
|
||||
wchar Command[NM+16];
|
||||
void GetBriefMaskList(const std::wstring &Masks,StringList &Args);
|
||||
|
||||
wchar ArcName[NM];
|
||||
|
||||
std::wstring Command;
|
||||
std::wstring ArcName;
|
||||
std::wstring ExtrPath;
|
||||
std::wstring TempPath;
|
||||
std::wstring SFXModule;
|
||||
std::wstring CommentFile;
|
||||
std::wstring ArcPath; // For -ap<path>.
|
||||
std::wstring ExclArcPath; // For -ep4<path> switch.
|
||||
std::wstring LogName;
|
||||
std::wstring EmailTo;
|
||||
|
||||
// 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.
|
||||
std::wstring UseStdin;
|
||||
|
||||
StringList FileArgs;
|
||||
StringList ExclArgs;
|
||||
StringList InclArgs;
|
||||
StringList ArcNames;
|
||||
StringList StoreArgs;
|
||||
#ifdef PROPAGATE_MOTW
|
||||
StringList MotwList; // Extensions to assign the mark of the web.
|
||||
#endif
|
||||
|
||||
SecPassword Password;
|
||||
|
||||
std::vector<int64> NextVolSizes;
|
||||
|
||||
|
||||
#ifdef RARDLL
|
||||
std::wstring DllDestName;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Return 'true' if we need to exclude the file from processing as result
|
||||
// of -x switch. If CheckInclList is true, we also check the file against
|
||||
// the include list created with -n switch.
|
||||
bool CommandData::ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList)
|
||||
bool CommandData::ExclCheck(const std::wstring &CheckName,bool Dir,bool CheckFullPath,bool CheckInclList)
|
||||
{
|
||||
if (CheckArgs(&ExclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
|
||||
return true;
|
||||
@@ -13,17 +13,21 @@ bool CommandData::ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,b
|
||||
}
|
||||
|
||||
|
||||
bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode)
|
||||
bool CommandData::CheckArgs(StringList *Args,bool Dir,const std::wstring &CheckName,bool CheckFullPath,int MatchMode)
|
||||
{
|
||||
wchar *Name=ConvertPath(CheckName,NULL,0);
|
||||
wchar FullName[NM];
|
||||
wchar CurMask[NM];
|
||||
*FullName=0;
|
||||
std::wstring Name,FullName,CurMask;
|
||||
ConvertPath(&CheckName,&Name);
|
||||
Args->Rewind();
|
||||
while (Args->GetString(CurMask,ASIZE(CurMask)))
|
||||
while (Args->GetString(CurMask))
|
||||
{
|
||||
wchar *LastMaskChar=PointToLastChar(CurMask);
|
||||
bool DirMask=IsPathDiv(*LastMaskChar); // Mask for directories only.
|
||||
#ifdef _WIN_ALL
|
||||
// 2025.09.11: Unix allows DOS slashes as a part of file name, so we do not
|
||||
// convert it for Unix. In Windows we wish -xdir\file and -xdir/file both
|
||||
// to exclude the file.
|
||||
UnixSlashToDos(CurMask,CurMask);
|
||||
#endif
|
||||
wchar LastMaskChar=GetLastChar(CurMask);
|
||||
bool DirMask=IsPathDiv(LastMaskChar); // Mask for directories only.
|
||||
|
||||
if (Dir)
|
||||
{
|
||||
@@ -33,16 +37,33 @@ bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,boo
|
||||
// We process the directory and have the directory exclusion mask.
|
||||
// So let's convert "mask\" to "mask" and process it normally.
|
||||
|
||||
*LastMaskChar=0;
|
||||
CurMask.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
// REMOVED, we want -npath\* to match empty folders too.
|
||||
// If mask has wildcards in name part and does not have the trailing
|
||||
// '\' character, we cannot use it for directories.
|
||||
|
||||
// if (IsWildcard(PointToName(CurMask)))
|
||||
// continue;
|
||||
// This code doesn't allow to apply -n and -x wildcard masks without
|
||||
// trailing slash to folders unless these masks are * and *.*.
|
||||
// See the changes history below.
|
||||
// 2023.03.26: Previously we removed this code completely to let
|
||||
// 'rar a arc dir -ndir\path\*' include empty folders in 'path' too.
|
||||
// But then we received an email from user not willing -x*.avi to
|
||||
// exclude folders like dir.avi with non-avi files. Also rar.txt
|
||||
// mentions that masks like *.avi exclude only files. Initially
|
||||
// we wanted masks like -npath\* or -xpath\* to match the entire
|
||||
// contents of path including empty folders and added the special
|
||||
// check for "*" and "*.*". But this is not very straightforward,
|
||||
// when *.* and *.avi are processed differently, especially taking
|
||||
// into account that we can specify the exact folder name without
|
||||
// wildcards to process it and masks like 'dir*\' can be used to
|
||||
// exclude folders. So we decided to skip all usual wildcard masks
|
||||
// for folders.
|
||||
// 2023.11.22: We returned the special check for "*" and "*.*",
|
||||
// because users expected 'rar a arc dir -xdir\*' to exclude
|
||||
// everything including subfolders in 'dir'. For now we returned it
|
||||
// both for -n and -x, but we can limit it to -x only if needed.
|
||||
std::wstring Name=PointToName(CurMask);
|
||||
if (IsWildcard(Name) && Name!=L"*" && Name!=L"*.*")
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -54,7 +75,7 @@ bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,boo
|
||||
// is excluded from further scanning.
|
||||
|
||||
if (DirMask)
|
||||
wcsncatz(CurMask,L"*",ASIZE(CurMask));
|
||||
CurMask+=L"*";
|
||||
}
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
@@ -66,19 +87,20 @@ bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,boo
|
||||
// correctly. Moreover, removing "*\" from mask would break
|
||||
// the comparison, because now all names have the path.
|
||||
|
||||
if (*FullName==0)
|
||||
ConvertNameToFull(CheckName,FullName,ASIZE(FullName));
|
||||
if (FullName.empty())
|
||||
ConvertNameToFull(CheckName,FullName);
|
||||
if (CmpName(CurMask,FullName,MatchMode))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
wchar NewName[NM+2],*CurName=Name;
|
||||
std::wstring CurName=Name;
|
||||
|
||||
// Important to convert before "*\" check below, so masks like
|
||||
// d:*\something are processed properly.
|
||||
wchar *CmpMask=ConvertPath(CurMask,NULL,0);
|
||||
size_t MaskOffset=ConvertPath(&CurMask,nullptr);
|
||||
std::wstring CmpMask=CurMask.substr(MaskOffset);
|
||||
|
||||
if (CmpMask[0]=='*' && IsPathDiv(CmpMask[1]))
|
||||
{
|
||||
@@ -86,10 +108,9 @@ bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,boo
|
||||
// but also in the current directory. We convert the name
|
||||
// from 'name' to '.\name' to be matched by "*\" part even if it is
|
||||
// in current directory.
|
||||
NewName[0]='.';
|
||||
NewName[1]=CPATHDIVIDER;
|
||||
wcsncpyz(NewName+2,Name,ASIZE(NewName)-2);
|
||||
CurName=NewName;
|
||||
CurName=L'.';
|
||||
CurName+=CPATHDIVIDER;
|
||||
CurName+=Name;
|
||||
}
|
||||
|
||||
if (CmpName(CmpMask,CurName,MatchMode))
|
||||
@@ -262,6 +283,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)
|
||||
@@ -275,10 +298,10 @@ bool CommandData::SizeCheck(int64 Size)
|
||||
|
||||
// Return 0 if file must not be processed or a number of matched parameter otherwise.
|
||||
int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType,
|
||||
bool Flags,wchar *MatchedArg,uint MatchedArgSize)
|
||||
bool Flags,std::wstring *MatchedArg)
|
||||
{
|
||||
if (MatchedArg!=NULL && MatchedArgSize>0)
|
||||
*MatchedArg=0;
|
||||
if (MatchedArg!=NULL)
|
||||
MatchedArg->clear();
|
||||
bool Dir=FileHead.Dir;
|
||||
if (ExclCheck(FileHead.FileName,Dir,false,true))
|
||||
return 0;
|
||||
@@ -287,23 +310,28 @@ 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;
|
||||
#endif
|
||||
wchar *ArgName;
|
||||
std::wstring ArgName;
|
||||
FileArgs.Rewind();
|
||||
for (int StringCount=1;(ArgName=FileArgs.GetString())!=NULL;StringCount++)
|
||||
for (int StringCount=1;FileArgs.GetString(ArgName);StringCount++)
|
||||
{
|
||||
// Ensure that both parameters of CmpName are either C++ strings or
|
||||
// pointers, so we avoid time consuming string construction for one of
|
||||
// parameters in this expensive loop.
|
||||
if (CmpName(ArgName,FileHead.FileName,MatchType))
|
||||
{
|
||||
if (ExactMatch!=NULL)
|
||||
*ExactMatch=wcsicompc(ArgName,FileHead.FileName)==0;
|
||||
if (MatchedArg!=NULL)
|
||||
wcsncpyz(MatchedArg,ArgName,MatchedArgSize);
|
||||
*MatchedArg=ArgName;
|
||||
return StringCount;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ void CommandData::OutTitle()
|
||||
{
|
||||
if (BareOutput || DisableCopyright)
|
||||
return;
|
||||
#if defined(__GNUC__) && defined(SFX_MODULE)
|
||||
#ifdef SFX_MODULE
|
||||
mprintf(St(MCopyrightS));
|
||||
#else
|
||||
#ifndef SILENT
|
||||
@@ -61,26 +61,24 @@ 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,MCHelpSwMLP,
|
||||
MCHelpSwN,MCHelpSwNa,MCHelpSwNal,MCHelpSwO,MCHelpSwOC,MCHelpSwOL,
|
||||
MCHelpSwOM,MCHelpSwOP,MCHelpSwOR,MCHelpSwOW,MCHelpSwP,MCHelpSwR,
|
||||
MCHelpSwRI,MCHelpSwSC,MCHelpSwSI,MCHelpSwSL,MCHelpSwTA,
|
||||
MCHelpSwTB,MCHelpSwTN,MCHelpSwTO,MCHelpSwTS,MCHelpSwU,MCHelpSwVUnr,
|
||||
MCHelpSwVER,MCHelpSwVP,MCHelpSwX,MCHelpSwXa,MCHelpSwXal,MCHelpSwY
|
||||
#endif
|
||||
};
|
||||
|
||||
for (uint I=0;I<ASIZE(Help);I++)
|
||||
{
|
||||
#ifndef SFX_MODULE
|
||||
if (CmpMSGID(Help[I],MCHelpSwV))
|
||||
continue;
|
||||
#ifndef _WIN_ALL
|
||||
static MSGID Win32Only[]={
|
||||
MCHelpSwIEML,MCHelpSwVD,MCHelpSwAO,MCHelpSwOS,MCHelpSwIOFF,
|
||||
MCHelpSwEP2,MCHelpSwOC,MCHelpSwONI,MCHelpSwDR,MCHelpSwRI
|
||||
MCHelpSwEP2,MCHelpSwMLP,MCHelpSwOC,MCHelpSwONI,MCHelpSwDR,MCHelpSwRI
|
||||
};
|
||||
bool Found=false;
|
||||
for (uint J=0;J<ASIZE(Win32Only);J++)
|
||||
@@ -92,11 +90,18 @@ 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;
|
||||
#endif
|
||||
#if !defined(_WIN_ALL) && !defined(_EMX)
|
||||
#ifndef _WIN_ALL
|
||||
if (CmpMSGID(Help[I],MCHelpSwAC))
|
||||
continue;
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
|
||||
|
||||
inline unsigned int RangeCoder::GetChar()
|
||||
inline byte RangeCoder::GetChar()
|
||||
{
|
||||
return(UnpackRead->GetChar());
|
||||
return UnpackRead->GetChar();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ void RangeCoder::InitDecoder(Unpack *UnpackRead)
|
||||
RangeCoder::UnpackRead=UnpackRead;
|
||||
|
||||
low=code=0;
|
||||
range=uint(-1);
|
||||
for (int i=0;i < 4;i++)
|
||||
range=0xffffffff;
|
||||
for (uint i = 0; i < 4; i++)
|
||||
code=(code << 8) | GetChar();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ class RangeCoder
|
||||
inline uint GetCurrentShiftCount(uint SHIFT);
|
||||
inline void Decode();
|
||||
inline void PutChar(unsigned int c);
|
||||
inline unsigned int GetChar();
|
||||
inline byte GetChar();
|
||||
|
||||
uint low, code, range;
|
||||
struct SUBRANGE
|
||||
|
||||
@@ -17,13 +17,16 @@ 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} */
|
||||
static const uint DC = 64;
|
||||
static const uint DCB = 64; // Base distance codes up to 4 GB.
|
||||
static const uint DCX = 80; // Extended distance codes up to 1 TB.
|
||||
static const uint LDC = 16;
|
||||
static const uint RC = 44;
|
||||
static const uint HUFF_TABLE_SIZE = NC + DC + RC + LDC;
|
||||
static const uint HUFF_TABLE_SIZEB = NC + DCB + RC + LDC;
|
||||
static const uint HUFF_TABLE_SIZEX = NC + DCX + RC + LDC;
|
||||
static const uint BC = 20;
|
||||
|
||||
static const uint NC30 = 299; /* alphabet = {0, 1, 2, ..., NC - 1} */
|
||||
@@ -42,10 +45,6 @@ class PackDef
|
||||
// Largest alphabet size among all values listed above.
|
||||
static const uint LARGEST_TABLE_SIZE = 306;
|
||||
|
||||
enum {
|
||||
CODE_HUFFMAN, CODE_LZ, CODE_REPEATLZ, CODE_CACHELZ, CODE_STARTFILE,
|
||||
CODE_ENDFILE, CODE_FILTER, CODE_FILTERDATA
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -53,7 +52,10 @@ enum FilterType {
|
||||
// These values must not be changed, because we use them directly
|
||||
// in RAR5 compression and decompression code.
|
||||
FILTER_DELTA=0, FILTER_E8, FILTER_E8E9, FILTER_ARM,
|
||||
FILTER_AUDIO, FILTER_RGB, FILTER_ITANIUM, FILTER_PPM, FILTER_NONE
|
||||
FILTER_AUDIO, FILTER_RGB, FILTER_ITANIUM, FILTER_TEXT,
|
||||
|
||||
// These values can be changed.
|
||||
FILTER_LONGRANGE,FILTER_EXHAUSTIVE,FILTER_NONE
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
239
unrar/consio.cpp
239
unrar/consio.cpp
@@ -3,8 +3,8 @@
|
||||
|
||||
static MESSAGE_TYPE MsgStream=MSG_STDOUT;
|
||||
static RAR_CHARSET RedirectCharset=RCH_DEFAULT;
|
||||
|
||||
const int MaxMsgSize=2*NM+2048;
|
||||
static bool ProhibitInput=false;
|
||||
static bool ConsoleOutputPresent=false;
|
||||
|
||||
static bool StdoutRedirected=false,StderrRedirected=false,StdinRedirected=false;
|
||||
|
||||
@@ -61,47 +61,53 @@ void SetConsoleRedirectCharset(RAR_CHARSET RedirectCharset)
|
||||
}
|
||||
|
||||
|
||||
void ProhibitConsoleInput()
|
||||
{
|
||||
ProhibitInput=true;
|
||||
}
|
||||
|
||||
|
||||
#ifndef SILENT
|
||||
static void cvt_wprintf(FILE *dest,const wchar *fmt,va_list arglist)
|
||||
{
|
||||
// This buffer is for format string only, not for entire output,
|
||||
// so it can be short enough.
|
||||
wchar fmtw[1024];
|
||||
PrintfPrepareFmt(fmt,fmtw,ASIZE(fmtw));
|
||||
ConsoleOutputPresent=true;
|
||||
|
||||
// No need for PrintfPrepareFmt here, vwstrprintf calls it.
|
||||
std::wstring s=vwstrprintf(fmt,arglist);
|
||||
|
||||
ReplaceEsc(s);
|
||||
|
||||
#ifdef _WIN_ALL
|
||||
safebuf wchar Msg[MaxMsgSize];
|
||||
if (dest==stdout && StdoutRedirected || dest==stderr && StderrRedirected)
|
||||
{
|
||||
HANDLE hOut=GetStdHandle(dest==stdout ? STD_OUTPUT_HANDLE:STD_ERROR_HANDLE);
|
||||
vswprintf(Msg,ASIZE(Msg),fmtw,arglist);
|
||||
DWORD Written;
|
||||
if (RedirectCharset==RCH_UNICODE)
|
||||
WriteFile(hOut,Msg,(DWORD)wcslen(Msg)*sizeof(*Msg),&Written,NULL);
|
||||
WriteFile(hOut,s.data(),(DWORD)s.size()*sizeof(s[0]),&Written,NULL);
|
||||
else
|
||||
{
|
||||
// Avoid Unicode for redirect in Windows, it does not work with pipes.
|
||||
safebuf char MsgA[MaxMsgSize];
|
||||
std::string MsgA;
|
||||
if (RedirectCharset==RCH_UTF8)
|
||||
WideToUtf(Msg,MsgA,ASIZE(MsgA));
|
||||
WideToUtf(s,MsgA);
|
||||
else
|
||||
WideToChar(Msg,MsgA,ASIZE(MsgA));
|
||||
WideToChar(s,MsgA);
|
||||
if (RedirectCharset==RCH_DEFAULT || RedirectCharset==RCH_OEM)
|
||||
CharToOemA(MsgA,MsgA); // Console tools like 'more' expect OEM encoding.
|
||||
CharToOemA(&MsgA[0],&MsgA[0]); // Console tools like 'more' expect OEM encoding.
|
||||
|
||||
// We already converted \n to \r\n above, so we use WriteFile instead
|
||||
// of C library to avoid unnecessary additional conversion.
|
||||
WriteFile(hOut,MsgA,(DWORD)strlen(MsgA),&Written,NULL);
|
||||
WriteFile(hOut,MsgA.data(),(DWORD)MsgA.size(),&Written,NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// MSVC2008 vfwprintf writes every character to console separately
|
||||
// and it is too slow. We use direct WriteConsole call instead.
|
||||
vswprintf(Msg,ASIZE(Msg),fmtw,arglist);
|
||||
HANDLE hOut=GetStdHandle(dest==stderr ? STD_ERROR_HANDLE:STD_OUTPUT_HANDLE);
|
||||
DWORD Written;
|
||||
WriteConsole(hOut,Msg,(DWORD)wcslen(Msg),&Written,NULL);
|
||||
WriteConsole(hOut,s.data(),(DWORD)s.size(),&Written,NULL);
|
||||
#else
|
||||
vfwprintf(dest,fmtw,arglist);
|
||||
fputws(s.c_str(),dest);
|
||||
// We do not use setbuf(NULL) in Unix (see comments in InitConsole).
|
||||
fflush(dest);
|
||||
#endif
|
||||
@@ -141,81 +147,109 @@ void eprintf(const wchar *fmt,...)
|
||||
|
||||
|
||||
#ifndef SILENT
|
||||
static void GetPasswordText(wchar *Str,uint MaxLength)
|
||||
static void QuitIfInputProhibited()
|
||||
{
|
||||
if (MaxLength==0)
|
||||
return;
|
||||
// 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(std::wstring &Str)
|
||||
{
|
||||
QuitIfInputProhibited();
|
||||
if (StdinRedirected)
|
||||
getwstr(Str,MaxLength); // Read from pipe or redirected file.
|
||||
getwstr(Str); // 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.
|
||||
|
||||
std::vector<wchar> Buf(MAXPASSWORD);
|
||||
|
||||
// We prefer ReadConsole to ReadFile, so we can read Unicode input.
|
||||
DWORD Read=0;
|
||||
ReadConsole(hConIn,Buf.data(),(DWORD)Buf.size()-1,&Read,NULL);
|
||||
Buf[Read]=0;
|
||||
Str=Buf.data();
|
||||
cleandata(Buf.data(),Buf.size()*sizeof(Buf[0]));
|
||||
|
||||
ReadConsole(hConIn,Str,MaxLength-1,&Read,NULL);
|
||||
Str[Read]=0;
|
||||
SetConsoleMode(hConIn,ConInMode);
|
||||
SetConsoleMode(hConOut,ConOutMode);
|
||||
|
||||
// 2023.03.12: Previously we checked for presence of "\n" in entered
|
||||
// passwords, supposing that truncated strings do not include it.
|
||||
// We did it to read the rest of excessively long string, so it is not
|
||||
// read later as the second password for -p switch. But this "\n" check
|
||||
// doesn't seem to work in Windows 10 anymore and "\r" is present even
|
||||
// in truncated strings. Also we increased MAXPASSWORD, so it is larger
|
||||
// than MAXPASSWORD_RAR. Thus we removed this check as not working
|
||||
// and not that necessary. 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.
|
||||
#else
|
||||
char StrA[MAXPASSWORD];
|
||||
#if defined(_EMX) || defined (__VMS)
|
||||
fgets(StrA,ASIZE(StrA)-1,stdin);
|
||||
std::vector<char> StrA(MAXPASSWORD*4); // "*4" for multibyte UTF-8 characters.
|
||||
#ifdef __VMS
|
||||
fgets(StrA.data(),StrA.size()-1,stdin);
|
||||
#elif defined(__sun)
|
||||
strncpyz(StrA,getpassphrase(""),ASIZE(StrA));
|
||||
strncpyz(StrA.data(),getpassphrase(""),StrA.size());
|
||||
#else
|
||||
strncpyz(StrA,getpass(""),ASIZE(StrA));
|
||||
strncpyz(StrA.data(),getpass(""),StrA.size());
|
||||
#endif
|
||||
CharToWide(StrA,Str,MaxLength);
|
||||
cleandata(StrA,sizeof(StrA));
|
||||
CharToWide(StrA.data(),Str);
|
||||
cleandata(StrA.data(),StrA.size()*sizeof(StrA[0]));
|
||||
#endif
|
||||
}
|
||||
Str[MaxLength-1]=0;
|
||||
RemoveLF(Str);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef SILENT
|
||||
bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password)
|
||||
bool GetConsolePassword(UIPASSWORD_TYPE Type,const std::wstring &FileName,SecPassword *Password)
|
||||
{
|
||||
if (!StdinRedirected)
|
||||
uiAlarm(UIALARM_QUESTION);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!StdinRedirected)
|
||||
// if (!StdinRedirected)
|
||||
if (Type==UIPASSWORD_GLOBAL)
|
||||
eprintf(L"\n%s: ",St(MAskPsw));
|
||||
else
|
||||
eprintf(St(MAskPswFor),FileName);
|
||||
eprintf(St(MAskPswFor),FileName.c_str());
|
||||
|
||||
wchar PlainPsw[MAXPASSWORD];
|
||||
GetPasswordText(PlainPsw,ASIZE(PlainPsw));
|
||||
if (*PlainPsw==0 && Type==UIPASSWORD_GLOBAL)
|
||||
std::wstring PlainPsw;
|
||||
GetPasswordText(PlainPsw);
|
||||
if (PlainPsw.empty() && Type==UIPASSWORD_GLOBAL)
|
||||
return false;
|
||||
if (PlainPsw.size()>=MAXPASSWORD)
|
||||
{
|
||||
PlainPsw.erase(MAXPASSWORD-1);
|
||||
uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1);
|
||||
}
|
||||
if (!StdinRedirected && Type==UIPASSWORD_GLOBAL)
|
||||
{
|
||||
eprintf(St(MReAskPsw));
|
||||
wchar CmpStr[MAXPASSWORD];
|
||||
GetPasswordText(CmpStr,ASIZE(CmpStr));
|
||||
if (*CmpStr==0 || wcscmp(PlainPsw,CmpStr)!=0)
|
||||
std::wstring CmpStr;
|
||||
GetPasswordText(CmpStr);
|
||||
if (CmpStr.empty() || PlainPsw!=CmpStr)
|
||||
{
|
||||
eprintf(St(MNotMatchPsw));
|
||||
cleandata(PlainPsw,sizeof(PlainPsw));
|
||||
cleandata(CmpStr,sizeof(CmpStr));
|
||||
cleandata(&PlainPsw[0],PlainPsw.size()*sizeof(PlainPsw[0]));
|
||||
cleandata(&CmpStr[0],CmpStr.size()*sizeof(CmpStr[0]));
|
||||
continue;
|
||||
}
|
||||
cleandata(CmpStr,sizeof(CmpStr));
|
||||
cleandata(&CmpStr[0],CmpStr.size()*sizeof(CmpStr[0]));
|
||||
}
|
||||
Password->Set(PlainPsw);
|
||||
cleandata(PlainPsw,sizeof(PlainPsw));
|
||||
Password->Set(PlainPsw.c_str());
|
||||
cleandata(&PlainPsw[0],PlainPsw.size()*sizeof(PlainPsw[0]));
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
@@ -224,12 +258,17 @@ bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *
|
||||
|
||||
|
||||
#ifndef SILENT
|
||||
bool getwstr(wchar *str,size_t n)
|
||||
void getwstr(std::wstring &str)
|
||||
{
|
||||
// Print buffered prompt title function before waiting for input.
|
||||
fflush(stderr);
|
||||
|
||||
*str=0;
|
||||
QuitIfInputProhibited();
|
||||
|
||||
str.clear();
|
||||
|
||||
const size_t MaxRead=MAXPATHSIZE; // Large enough to read a file name.
|
||||
|
||||
#if defined(_WIN_ALL)
|
||||
// fgetws does not work well with non-English text in Windows,
|
||||
// so we do not use it.
|
||||
@@ -237,33 +276,50 @@ bool getwstr(wchar *str,size_t n)
|
||||
{
|
||||
// fgets does not work well with pipes in Windows in our test.
|
||||
// Let's use files.
|
||||
Array<char> StrA(n*4); // Up to 4 UTF-8 characters per wchar_t.
|
||||
std::vector<char> StrA(MaxRead*4); // Up to 4 UTF-8 characters per wchar_t.
|
||||
File SrcFile;
|
||||
SrcFile.SetHandleType(FILE_HANDLESTD);
|
||||
int ReadSize=SrcFile.Read(&StrA[0],StrA.Size()-1);
|
||||
SrcFile.SetLineInputMode(true);
|
||||
int ReadSize=SrcFile.Read(&StrA[0],StrA.size()-1);
|
||||
if (ReadSize<=0)
|
||||
{
|
||||
// Looks like stdin is a null device. We can enter to infinite loop
|
||||
// calling Ask(), so let's better exit.
|
||||
ErrHandler.Exit(RARX_USERBREAK);
|
||||
// calling Ask() or set an empty password, so let's better exit.
|
||||
ErrHandler.ReadError(L"stdin");
|
||||
}
|
||||
StrA[ReadSize]=0;
|
||||
CharToWide(&StrA[0],str,n);
|
||||
cleandata(&StrA[0],StrA.Size()); // We can use this function to enter passwords.
|
||||
|
||||
// We expect ANSI encoding here, but "echo text|rar ..." to pipe to RAR,
|
||||
// such as send passwords, we get OEM encoding by default, unless we
|
||||
// use "chcp" in console. But we avoid OEM to ANSI conversion,
|
||||
// because we also want to handle ANSI files redirection correctly,
|
||||
// like "rar ... < ansifile.txt".
|
||||
CharToWide(&StrA[0],str);
|
||||
cleandata(&StrA[0],StrA.size()); // We can use this function to enter passwords.
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<wchar> Buf(MaxRead); // Up to 4 UTF-8 characters per wchar_t.
|
||||
DWORD SizeToRead=(DWORD)Buf.size()-1;
|
||||
|
||||
// ReadConsole fails in Windows 7 for requested input exceeding 30 KB.
|
||||
// Not certain about Windows 8, so check for Windows 10 here.
|
||||
if (WinNT()<=WNT_W10)
|
||||
SizeToRead=Min(SizeToRead,0x4000);
|
||||
|
||||
DWORD ReadSize=0;
|
||||
if (ReadConsole(GetStdHandle(STD_INPUT_HANDLE),str,DWORD(n-1),&ReadSize,NULL)==0)
|
||||
return false;
|
||||
str[ReadSize]=0;
|
||||
if (ReadConsole(GetStdHandle(STD_INPUT_HANDLE),&Buf[0],SizeToRead,&ReadSize,NULL)==0)
|
||||
ErrHandler.ReadError(L"stdin"); // Unknown user input, safer to abort.
|
||||
Buf[ReadSize]=0;
|
||||
str=Buf.data();
|
||||
}
|
||||
#else
|
||||
if (fgetws(str,n,stdin)==NULL)
|
||||
ErrHandler.Exit(RARX_USERBREAK); // Avoid infinite Ask() loop.
|
||||
std::vector<wchar> Buf(MaxRead); // Up to 4 UTF-8 characters per wchar_t.
|
||||
if (fgetws(&Buf[0],Buf.size(),stdin)==NULL)
|
||||
ErrHandler.ReadError(L"stdin"); // Avoid infinite Ask() loop.
|
||||
str=Buf.data();
|
||||
#endif
|
||||
RemoveLF(str);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -277,22 +333,22 @@ int Ask(const wchar *AskStr)
|
||||
{
|
||||
uiAlarm(UIALARM_QUESTION);
|
||||
|
||||
const int MaxItems=10;
|
||||
const uint MaxItems=10;
|
||||
wchar Item[MaxItems][40];
|
||||
int ItemKeyPos[MaxItems],NumItems=0;
|
||||
uint ItemKeyPos[MaxItems],NumItems=0;
|
||||
|
||||
for (const wchar *NextItem=AskStr;NextItem!=NULL;NextItem=wcschr(NextItem+1,'_'))
|
||||
for (const wchar *NextItem=AskStr;NextItem!=nullptr;NextItem=wcschr(NextItem+1,'_'))
|
||||
{
|
||||
wchar *CurItem=Item[NumItems];
|
||||
wcsncpyz(CurItem,NextItem+1,ASIZE(Item[0]));
|
||||
wchar *EndItem=wcschr(CurItem,'_');
|
||||
if (EndItem!=NULL)
|
||||
if (EndItem!=nullptr)
|
||||
*EndItem=0;
|
||||
int KeyPos=0,CurKey;
|
||||
uint KeyPos=0,CurKey;
|
||||
while ((CurKey=CurItem[KeyPos])!=0)
|
||||
{
|
||||
bool Found=false;
|
||||
for (int I=0;I<NumItems && !Found;I++)
|
||||
for (uint I=0;I<NumItems && !Found;I++)
|
||||
if (toupperw(Item[I][ItemKeyPos[I]])==toupperw(CurKey))
|
||||
Found=true;
|
||||
if (!Found && CurKey!=' ')
|
||||
@@ -303,19 +359,19 @@ int Ask(const wchar *AskStr)
|
||||
NumItems++;
|
||||
}
|
||||
|
||||
for (int I=0;I<NumItems;I++)
|
||||
for (uint I=0;I<NumItems;I++)
|
||||
{
|
||||
eprintf(I==0 ? (NumItems>4 ? L"\n":L" "):L", ");
|
||||
int KeyPos=ItemKeyPos[I];
|
||||
for (int J=0;J<KeyPos;J++)
|
||||
eprintf(I==0 ? (NumItems>3 ? L"\n":L" "):L", ");
|
||||
uint KeyPos=ItemKeyPos[I];
|
||||
for (uint J=0;J<KeyPos;J++)
|
||||
eprintf(L"%c",Item[I][J]);
|
||||
eprintf(L"[%c]%ls",Item[I][KeyPos],&Item[I][KeyPos+1]);
|
||||
}
|
||||
eprintf(L" ");
|
||||
wchar Str[50];
|
||||
getwstr(Str,ASIZE(Str));
|
||||
std::wstring Str;
|
||||
getwstr(Str);
|
||||
wchar Ch=toupperw(Str[0]);
|
||||
for (int I=0;I<NumItems;I++)
|
||||
for (uint I=0;I<NumItems;I++)
|
||||
if (Ch==Item[I][ItemKeyPos[I]])
|
||||
return I+1;
|
||||
return 0;
|
||||
@@ -323,11 +379,11 @@ int Ask(const wchar *AskStr)
|
||||
#endif
|
||||
|
||||
|
||||
static bool IsCommentUnsafe(const wchar *Data,size_t Size)
|
||||
static bool IsCommentUnsafe(const std::wstring &Data)
|
||||
{
|
||||
for (size_t I=0;I<Size;I++)
|
||||
for (size_t I=0;I<Data.size();I++)
|
||||
if (Data[I]==27 && Data[I+1]=='[')
|
||||
for (size_t J=I+2;J<Size;J++)
|
||||
for (size_t J=I+2;J<Data.size();J++)
|
||||
{
|
||||
// Return true for <ESC>[{key};"{string}"p used to redefine
|
||||
// a keyboard key on some terminals.
|
||||
@@ -340,18 +396,21 @@ static bool IsCommentUnsafe(const wchar *Data,size_t Size)
|
||||
}
|
||||
|
||||
|
||||
void OutComment(const wchar *Comment,size_t Size)
|
||||
void OutComment(const std::wstring &Comment)
|
||||
{
|
||||
if (IsCommentUnsafe(Comment,Size))
|
||||
if (IsCommentUnsafe(Comment))
|
||||
return;
|
||||
const size_t MaxOutSize=0x400;
|
||||
for (size_t I=0;I<Size;I+=MaxOutSize)
|
||||
for (size_t I=0;I<Comment.size();I+=MaxOutSize)
|
||||
{
|
||||
wchar Msg[MaxOutSize+1];
|
||||
size_t CopySize=Min(MaxOutSize,Size-I);
|
||||
wcsncpy(Msg,Comment+I,CopySize);
|
||||
Msg[CopySize]=0;
|
||||
mprintf(L"%s",Msg);
|
||||
size_t CopySize=Min(MaxOutSize,Comment.size()-I);
|
||||
mprintf(L"%s",Comment.substr(I,CopySize).c_str());
|
||||
}
|
||||
mprintf(L"\n");
|
||||
}
|
||||
|
||||
|
||||
bool IsConsoleOutputPresent()
|
||||
{
|
||||
return ConsoleOutputPresent;
|
||||
}
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
void InitConsole();
|
||||
void SetConsoleMsgStream(MESSAGE_TYPE MsgStream);
|
||||
void SetConsoleRedirectCharset(RAR_CHARSET RedirectCharset);
|
||||
void OutComment(const wchar *Comment,size_t Size);
|
||||
void ProhibitConsoleInput();
|
||||
void OutComment(const std::wstring &Comment);
|
||||
bool IsConsoleOutputPresent();
|
||||
|
||||
#ifndef SILENT
|
||||
bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password);
|
||||
bool GetConsolePassword(UIPASSWORD_TYPE Type,const std::wstring &FileName,SecPassword *Password);
|
||||
#endif
|
||||
|
||||
#ifdef SILENT
|
||||
@@ -15,13 +17,13 @@ bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *
|
||||
inline void eprintf(const wchar *fmt,...) {}
|
||||
inline void Alarm() {}
|
||||
inline int Ask(const wchar *AskStr) {return 0;}
|
||||
inline bool getwstr(wchar *str,size_t n) {return false;}
|
||||
inline void getwstr(std::wstring &str) {}
|
||||
#else
|
||||
void mprintf(const wchar *fmt,...);
|
||||
void eprintf(const wchar *fmt,...);
|
||||
void Alarm();
|
||||
int Ask(const wchar *AskStr);
|
||||
bool getwstr(wchar *str,size_t n);
|
||||
void getwstr(std::wstring &str);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
210
unrar/crc.cpp
210
unrar/crc.cpp
@@ -14,7 +14,17 @@
|
||||
|
||||
#include "rar.hpp"
|
||||
|
||||
static uint crc_tables[8][256]; // Tables for Slicing-by-8.
|
||||
#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[16][256]; // Tables for Slicing-by-16.
|
||||
|
||||
#ifdef USE_NEON_CRC32
|
||||
static bool CRC_Neon;
|
||||
#endif
|
||||
|
||||
|
||||
// Build the classic CRC32 lookup table.
|
||||
@@ -30,6 +40,19 @@ void InitCRC32(uint *CRCTab)
|
||||
C=(C & 1) ? (C>>1)^0xEDB88320 : (C>>1);
|
||||
CRCTab[I]=C;
|
||||
}
|
||||
|
||||
#ifdef USE_NEON_CRC32
|
||||
#ifdef _APPLE
|
||||
// getauxval isn't available in OS X
|
||||
uint Value=0;
|
||||
size_t Size=sizeof(Value);
|
||||
int RetCode=sysctlbyname("hw.optional.armv8_crc32",&Value,&Size,NULL,0);
|
||||
CRC_Neon=RetCode==0 && Value!=0;
|
||||
#else
|
||||
CRC_Neon=(getauxval(AT_HWCAP) & HWCAP_CRC32)!=0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -37,15 +60,17 @@ 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];
|
||||
for (uint J=1;J<8;J++)
|
||||
for (uint J=1;J<16;J++)
|
||||
{
|
||||
C=crc_tables[0][(byte)C]^(C>>8);
|
||||
crc_tables[J][I]=C;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -55,28 +80,68 @@ uint CRC32(uint 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);Size--,Data++)
|
||||
#ifdef USE_NEON_CRC32
|
||||
if (CRC_Neon)
|
||||
{
|
||||
for (;Size>=8;Size-=8,Data+=8)
|
||||
#ifdef __clang__
|
||||
StartCRC = __builtin_arm_crc32d(StartCRC, RawGet8(Data));
|
||||
#else
|
||||
StartCRC = __builtin_aarch64_crc32x(StartCRC, RawGet8(Data));
|
||||
#endif
|
||||
for (;Size>0;Size--,Data++) // Process left data.
|
||||
#ifdef __clang__
|
||||
StartCRC = __builtin_arm_crc32b(StartCRC, *Data);
|
||||
#else
|
||||
StartCRC = __builtin_aarch64_crc32b(StartCRC, *Data);
|
||||
#endif
|
||||
return StartCRC;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_SLICING
|
||||
// Align Data to 16 for better performance and to avoid ALLOW_MISALIGNED
|
||||
// check below.
|
||||
for (;Size>0 && ((size_t)Data & 15)!=0;Size--,Data++)
|
||||
StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);
|
||||
|
||||
for (;Size>=8;Size-=8,Data+=8)
|
||||
// 2023.12.06: We switched to slicing-by-16, which seems to be faster than
|
||||
// slicing-by-8 on modern CPUs. Slicing-by-32 would require 32 KB for tables
|
||||
// and could be limited by L1 cache size on some CPUs.
|
||||
for (;Size>=16;Size-=16,Data+=16)
|
||||
{
|
||||
#ifdef BIG_ENDIAN
|
||||
StartCRC ^= Data[0]|(Data[1] << 8)|(Data[2] << 16)|(Data[3] << 24);
|
||||
uint NextData = Data[4]|(Data[5] << 8)|(Data[6] << 16)|(Data[7] << 24);
|
||||
StartCRC ^= RawGet4(Data);
|
||||
uint D1 = RawGet4(Data+4);
|
||||
uint D2 = RawGet4(Data+8);
|
||||
uint D3 = RawGet4(Data+12);
|
||||
#else
|
||||
// We avoid RawGet4 here for performance reason, to access uint32
|
||||
// directly even if ALLOW_MISALIGNED isn't defined. We can do it,
|
||||
// because we aligned 'Data' above.
|
||||
StartCRC ^= *(uint32 *) Data;
|
||||
uint NextData = *(uint32 *) (Data+4);
|
||||
uint D1 = *(uint32 *) (Data+4);
|
||||
uint D2 = *(uint32 *) (Data+8);
|
||||
uint D3 = *(uint32 *) (Data+12);
|
||||
#endif
|
||||
StartCRC = crc_tables[7][(byte) StartCRC ] ^
|
||||
crc_tables[6][(byte)(StartCRC >> 8) ] ^
|
||||
crc_tables[5][(byte)(StartCRC >> 16)] ^
|
||||
crc_tables[4][(byte)(StartCRC >> 24)] ^
|
||||
crc_tables[3][(byte) NextData ] ^
|
||||
crc_tables[2][(byte)(NextData >> 8) ] ^
|
||||
crc_tables[1][(byte)(NextData >> 16)] ^
|
||||
crc_tables[0][(byte)(NextData >> 24)];
|
||||
StartCRC = crc_tables[15][(byte) StartCRC ] ^
|
||||
crc_tables[14][(byte)(StartCRC >> 8) ] ^
|
||||
crc_tables[13][(byte)(StartCRC >> 16)] ^
|
||||
crc_tables[12][(byte)(StartCRC >> 24)] ^
|
||||
crc_tables[11][(byte) D1 ] ^
|
||||
crc_tables[10][(byte)(D1 >> 8) ] ^
|
||||
crc_tables[ 9][(byte)(D1 >> 16)] ^
|
||||
crc_tables[ 8][(byte)(D1 >> 24)] ^
|
||||
crc_tables[ 7][(byte) D2 ] ^
|
||||
crc_tables[ 6][(byte)(D2 >> 8)] ^
|
||||
crc_tables[ 5][(byte)(D2 >> 16)] ^
|
||||
crc_tables[ 4][(byte)(D2 >> 24)] ^
|
||||
crc_tables[ 3][(byte) D3 ] ^
|
||||
crc_tables[ 2][(byte)(D3 >> 8)] ^
|
||||
crc_tables[ 1][(byte)(D3 >> 16)] ^
|
||||
crc_tables[ 0][(byte)(D3 >> 24)];
|
||||
}
|
||||
#endif
|
||||
|
||||
for (;Size>0;Size--,Data++) // Process left data.
|
||||
StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);
|
||||
@@ -100,3 +165,116 @@ ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
static void TestCRC();
|
||||
struct TestCRCStruct {TestCRCStruct() {TestCRC();exit(0);}} GlobalTesCRC;
|
||||
|
||||
void TestCRC()
|
||||
{
|
||||
// This function is invoked from global object and _SSE_Version is global
|
||||
// and can be initialized after this function. So we explicitly initialize
|
||||
// it here to enable SSE support in Blake2sp.
|
||||
_SSE_Version=GetSSEVersion();
|
||||
|
||||
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];
|
||||
GetRnd(Buf,BufSize);
|
||||
|
||||
clock_t StartTime=clock();
|
||||
r32=0xffffffff;
|
||||
const uint64 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: %llu MB/s",BufCount*CLOCKS_PER_SEC/(clock()-StartTime));
|
||||
|
||||
StartTime=clock();
|
||||
DataHash Hash;
|
||||
Hash.Init(HASH_CRC32,MaxPoolThreads);
|
||||
const uint64 BufCountMT=20000;
|
||||
for (uint I=0;I<BufCountMT;I++)
|
||||
Hash.Update(Buf,BufSize);
|
||||
HashValue Result;
|
||||
Hash.Result(&Result);
|
||||
mprintf(L"\nCRC32 MT speed: %llu MB/s",BufCountMT*CLOCKS_PER_SEC/(clock()-StartTime));
|
||||
|
||||
StartTime=clock();
|
||||
Hash.Init(HASH_BLAKE2,MaxPoolThreads);
|
||||
for (uint I=0;I<BufCount;I++)
|
||||
Hash.Update(Buf,BufSize);
|
||||
Hash.Result(&Result);
|
||||
mprintf(L"\nBlake2sp speed: %llu MB/s",BufCount*CLOCKS_PER_SEC/(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: %llu MB/s",BufCount*CLOCKS_PER_SEC/(clock()-StartTime));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -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,16 +47,28 @@ 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));
|
||||
|
||||
// Display this warning only when encrypting. Users complained that
|
||||
// it is distracting when decrypting. It still can be useful when encrypting,
|
||||
// so users do not waste time to excessively long passwords.
|
||||
if (Encrypt && wcslen(PwdW)>=MAXPASSWORD_RAR)
|
||||
uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD_RAR-1);
|
||||
|
||||
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.
|
||||
|
||||
bool Success=true;
|
||||
|
||||
switch(Method)
|
||||
{
|
||||
#ifndef SFX_MODULE
|
||||
@@ -83,12 +86,12 @@ bool CryptData::SetCryptKeys(bool Encrypt,CRYPT_METHOD Method,
|
||||
SetKey30(Encrypt,Password,PwdW,Salt);
|
||||
break;
|
||||
case CRYPT_RAR50:
|
||||
SetKey50(Encrypt,Password,PwdW,Salt,InitV,Lg2Cnt,HashKey,PswCheck);
|
||||
Success=SetKey50(Encrypt,Password,PwdW,Salt,InitV,Lg2Cnt,HashKey,PswCheck);
|
||||
break;
|
||||
}
|
||||
cleandata(PwdA,sizeof(PwdA));
|
||||
cleandata(PwdW,sizeof(PwdW));
|
||||
return true;
|
||||
return Success;
|
||||
}
|
||||
|
||||
|
||||
@@ -117,7 +120,7 @@ void GetRnd(byte *RndBuf,size_t BufSize)
|
||||
HCRYPTPROV hProvider = 0;
|
||||
if (CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
|
||||
{
|
||||
Success=CryptGenRandom(hProvider, (DWORD)BufSize, RndBuf) == TRUE;
|
||||
Success=CryptGenRandom(hProvider, (DWORD)BufSize, RndBuf) != FALSE;
|
||||
CryptReleaseContext(hProvider, 0);
|
||||
}
|
||||
#elif defined(_UNIX)
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
|
||||
|
||||
enum CRYPT_METHOD {
|
||||
CRYPT_NONE,CRYPT_RAR13,CRYPT_RAR15,CRYPT_RAR20,CRYPT_RAR30,CRYPT_RAR50
|
||||
CRYPT_NONE,CRYPT_RAR13,CRYPT_RAR15,CRYPT_RAR20,CRYPT_RAR30,CRYPT_RAR50,
|
||||
CRYPT_UNKNOWN
|
||||
};
|
||||
|
||||
#define SIZE_SALT50 16
|
||||
@@ -30,6 +31,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 +52,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));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -56,7 +80,7 @@ class CryptData
|
||||
void DecryptBlock20(byte *Buf);
|
||||
|
||||
void SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt);
|
||||
void SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck);
|
||||
bool SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck);
|
||||
|
||||
KDF3CacheItem KDF3Cache[4];
|
||||
uint KDF3CachePos;
|
||||
@@ -77,17 +101,63 @@ 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);
|
||||
void SetAV15Encryption();
|
||||
void SetCmt13Encryption();
|
||||
void EncryptBlock(byte *Buf,size_t Size);
|
||||
void DecryptBlock(byte *Buf,size_t Size);
|
||||
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,
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
extern uint CRCTab[256];
|
||||
|
||||
void CryptData::SetKey13(const char *Password)
|
||||
{
|
||||
Key13[0]=Key13[1]=Key13[2]=0;
|
||||
@@ -25,22 +23,11 @@ void CryptData::SetKey15(const char *Password)
|
||||
{
|
||||
byte P=Password[I];
|
||||
Key15[2]^=P^CRCTab[P];
|
||||
Key15[3]+=P+(CRCTab[P]>>16);
|
||||
Key15[3]+=ushort(P+(CRCTab[P]>>16));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CryptData::SetAV15Encryption()
|
||||
{
|
||||
InitCRC32(CRCTab);
|
||||
Method=CRYPT_RAR15;
|
||||
Key15[0]=0x4765;
|
||||
Key15[1]=0x9021;
|
||||
Key15[2]=0x7382;
|
||||
Key15[3]=0x5215;
|
||||
}
|
||||
|
||||
|
||||
void CryptData::SetCmt13Encryption()
|
||||
{
|
||||
Method=CRYPT_RAR13;
|
||||
@@ -68,7 +55,7 @@ void CryptData::Crypt15(byte *Data,size_t Count)
|
||||
{
|
||||
Key15[0]+=0x1234;
|
||||
Key15[1]^=CRCTab[(Key15[0] & 0x1fe)>>1];
|
||||
Key15[2]-=CRCTab[(Key15[0] & 0x1fe)>>1]>>16;
|
||||
Key15[2]-=ushort(CRCTab[(Key15[0] & 0x1fe)>>1]>>16);
|
||||
Key15[0]^=Key15[2];
|
||||
Key15[3]=rotrs(Key15[3]&0xffff,1,16)^Key15[1];
|
||||
Key15[3]=rotrs(Key15[3]&0xffff,1,16);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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];
|
||||
@@ -128,19 +128,19 @@ void pbkdf2(const byte *Pwd, size_t PwdLength,
|
||||
}
|
||||
|
||||
|
||||
void CryptData::SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,
|
||||
bool CryptData::SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,
|
||||
const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *HashKey,
|
||||
byte *PswCheck)
|
||||
{
|
||||
if (Lg2Cnt>CRYPT5_KDF_LG2_COUNT_MAX)
|
||||
return;
|
||||
return false;
|
||||
|
||||
byte Key[32],PswCheckValue[SHA256_DIGEST_SIZE],HashKeyValue[SHA256_DIGEST_SIZE];
|
||||
bool Found=false;
|
||||
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));
|
||||
@@ -186,6 +186,7 @@ void CryptData::SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,
|
||||
rin.Init(Encrypt, Key, 256, InitV);
|
||||
|
||||
cleandata(Key,sizeof(Key));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -200,6 +201,7 @@ void ConvertHashToMAC(HashValue *Value,byte *Key)
|
||||
Value->CRC32=0;
|
||||
for (uint I=0;I<ASIZE(Digest);I++)
|
||||
Value->CRC32^=Digest[I] << ((I & 3) * 8);
|
||||
Value->CRC32&=0xffffffff; // In case the variable size is larger than 32-bit.
|
||||
}
|
||||
if (Value->Type==HASH_BLAKE2)
|
||||
{
|
||||
|
||||
116
unrar/dll.cpp
116
unrar/dll.cpp
@@ -16,8 +16,7 @@ struct DataSet
|
||||
|
||||
HANDLE PASCAL RAROpenArchive(struct RAROpenArchiveData *r)
|
||||
{
|
||||
RAROpenArchiveDataEx rx;
|
||||
memset(&rx,0,sizeof(rx));
|
||||
RAROpenArchiveDataEx rx{};
|
||||
rx.ArcName=r->ArcName;
|
||||
rx.OpenMode=r->OpenMode;
|
||||
rx.CmtBuf=r->CmtBuf;
|
||||
@@ -32,7 +31,7 @@ HANDLE PASCAL RAROpenArchive(struct RAROpenArchiveData *r)
|
||||
|
||||
HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
|
||||
{
|
||||
DataSet *Data=NULL;
|
||||
DataSet *Data=nullptr;
|
||||
try
|
||||
{
|
||||
ErrHandler.Clean();
|
||||
@@ -44,22 +43,21 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
|
||||
Data->Cmd.FileArgs.AddString(L"*");
|
||||
Data->Cmd.KeepBroken=(r->OpFlags&ROADOF_KEEPBROKEN)!=0;
|
||||
|
||||
char AnsiArcName[NM];
|
||||
*AnsiArcName=0;
|
||||
if (r->ArcName!=NULL)
|
||||
std::string AnsiArcName;
|
||||
if (r->ArcName!=nullptr)
|
||||
{
|
||||
strncpyz(AnsiArcName,r->ArcName,ASIZE(AnsiArcName));
|
||||
AnsiArcName=r->ArcName;
|
||||
#ifdef _WIN_ALL
|
||||
if (!AreFileApisANSI())
|
||||
{
|
||||
OemToCharBuffA(r->ArcName,AnsiArcName,ASIZE(AnsiArcName));
|
||||
AnsiArcName[ASIZE(AnsiArcName)-1]=0;
|
||||
}
|
||||
OemToExt(r->ArcName,AnsiArcName);
|
||||
#endif
|
||||
}
|
||||
|
||||
wchar ArcName[NM];
|
||||
GetWideName(AnsiArcName,r->ArcNameW,ArcName,ASIZE(ArcName));
|
||||
std::wstring ArcName;
|
||||
if (r->ArcNameW!=nullptr && *r->ArcNameW!=0)
|
||||
ArcName=r->ArcNameW;
|
||||
else
|
||||
CharToWide(AnsiArcName,ArcName);
|
||||
|
||||
Data->Cmd.AddArcName(ArcName);
|
||||
Data->Cmd.Overwrite=OVERWRITE_ALL;
|
||||
@@ -75,7 +73,7 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
|
||||
{
|
||||
r->OpenResult=ERAR_EOPEN;
|
||||
delete Data;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
if (!Data->Arc.IsArchive(true))
|
||||
{
|
||||
@@ -90,7 +88,7 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
|
||||
r->OpenResult=ERAR_BAD_ARCHIVE;
|
||||
}
|
||||
delete Data;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
r->Flags=0;
|
||||
|
||||
@@ -113,35 +111,47 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
|
||||
if (Data->Arc.FirstVolume)
|
||||
r->Flags|=ROADF_FIRSTVOLUME;
|
||||
|
||||
Array<wchar> CmtDataW;
|
||||
if (r->CmtBufSize!=0 && Data->Arc.GetComment(&CmtDataW))
|
||||
std::wstring CmtDataW;
|
||||
if (r->CmtBufSize!=0 && Data->Arc.GetComment(CmtDataW))
|
||||
{
|
||||
if (r->CmtBufW!=NULL)
|
||||
if (r->CmtBufW!=nullptr)
|
||||
{
|
||||
CmtDataW.Push(0);
|
||||
size_t Size=wcslen(&CmtDataW[0])+1;
|
||||
// CmtDataW.push_back(0);
|
||||
size_t Size=wcslen(CmtDataW.data())+1;
|
||||
|
||||
r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1;
|
||||
r->CmtSize=(uint)Min(Size,r->CmtBufSize);
|
||||
memcpy(r->CmtBufW,&CmtDataW[0],(r->CmtSize-1)*sizeof(*r->CmtBufW));
|
||||
memcpy(r->CmtBufW,CmtDataW.data(),(r->CmtSize-1)*sizeof(*r->CmtBufW));
|
||||
r->CmtBufW[r->CmtSize-1]=0;
|
||||
}
|
||||
else
|
||||
if (r->CmtBuf!=NULL)
|
||||
{
|
||||
Array<char> CmtData(CmtDataW.Size()*4+1);
|
||||
memset(&CmtData[0],0,CmtData.Size());
|
||||
WideToChar(&CmtDataW[0],&CmtData[0],CmtData.Size()-1);
|
||||
size_t Size=strlen(&CmtData[0])+1;
|
||||
std::vector<char> CmtData(CmtDataW.size()*4+1);
|
||||
WideToChar(&CmtDataW[0],&CmtData[0],CmtData.size()-1);
|
||||
size_t Size=strlen(CmtData.data())+1;
|
||||
|
||||
r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1;
|
||||
r->CmtSize=(uint)Min(Size,r->CmtBufSize);
|
||||
memcpy(r->CmtBuf,&CmtData[0],r->CmtSize-1);
|
||||
memcpy(r->CmtBuf,CmtData.data(),r->CmtSize-1);
|
||||
r->CmtBuf[r->CmtSize-1]=0;
|
||||
}
|
||||
}
|
||||
else
|
||||
r->CmtState=r->CmtSize=0;
|
||||
|
||||
#ifdef PROPAGATE_MOTW
|
||||
if (r->MarkOfTheWeb!=nullptr)
|
||||
{
|
||||
Data->Cmd.MotwAllFields=r->MarkOfTheWeb[0]=='1';
|
||||
const wchar *Sep=wcschr(r->MarkOfTheWeb,'=');
|
||||
if (r->MarkOfTheWeb[0]=='-')
|
||||
Data->Cmd.MotwList.Reset();
|
||||
else
|
||||
Data->Cmd.GetBriefMaskList(Sep==nullptr ? L"*":Sep+1,Data->Cmd.MotwList);
|
||||
}
|
||||
#endif
|
||||
|
||||
Data->Extract.ExtractArchiveInit(Data->Arc);
|
||||
return (HANDLE)Data;
|
||||
}
|
||||
@@ -183,8 +193,7 @@ int PASCAL RARCloseArchive(HANDLE hArcData)
|
||||
|
||||
int PASCAL RARReadHeader(HANDLE hArcData,struct RARHeaderData *D)
|
||||
{
|
||||
struct RARHeaderDataEx X;
|
||||
memset(&X,0,sizeof(X));
|
||||
struct RARHeaderDataEx X{};
|
||||
|
||||
int Code=RARReadHeaderEx(hArcData,&X);
|
||||
|
||||
@@ -242,14 +251,18 @@ int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D)
|
||||
else
|
||||
return Code;
|
||||
}
|
||||
wcsncpy(D->ArcNameW,Data->Arc.FileName,ASIZE(D->ArcNameW));
|
||||
wcsncpyz(D->ArcNameW,Data->Arc.FileName.c_str(),ASIZE(D->ArcNameW));
|
||||
WideToChar(D->ArcNameW,D->ArcName,ASIZE(D->ArcName));
|
||||
if (D->ArcNameEx!=nullptr)
|
||||
wcsncpyz(D->ArcNameEx,Data->Arc.FileName.c_str(),D->ArcNameExSize);
|
||||
|
||||
wcsncpy(D->FileNameW,hd->FileName,ASIZE(D->FileNameW));
|
||||
wcsncpyz(D->FileNameW,hd->FileName.c_str(),ASIZE(D->FileNameW));
|
||||
WideToChar(D->FileNameW,D->FileName,ASIZE(D->FileName));
|
||||
#ifdef _WIN_ALL
|
||||
CharToOemA(D->FileName,D->FileName);
|
||||
#endif
|
||||
if (D->FileNameEx!=nullptr)
|
||||
wcsncpyz(D->FileNameEx,hd->FileName.c_str(),D->FileNameExSize);
|
||||
|
||||
D->Flags=0;
|
||||
if (hd->SplitBefore)
|
||||
@@ -311,14 +324,14 @@ int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D)
|
||||
// this RedirNameSize check sometimes later.
|
||||
if (hd->RedirType!=FSREDIR_NONE && D->RedirName!=NULL &&
|
||||
D->RedirNameSize>0 && D->RedirNameSize<100000)
|
||||
wcsncpyz(D->RedirName,hd->RedirName,D->RedirNameSize);
|
||||
wcsncpyz(D->RedirName,hd->RedirName.c_str(),D->RedirNameSize);
|
||||
D->DirTarget=hd->DirTarget;
|
||||
}
|
||||
catch (RAR_EXIT ErrCode)
|
||||
{
|
||||
return Data->Cmd.DllError!=0 ? Data->Cmd.DllError : RarErrorToDll(ErrCode);
|
||||
}
|
||||
return ERAR_SUCCESS;
|
||||
return Data->Cmd.DllError!=0 ? Data->Cmd.DllError : RarErrorToDll(ErrHandler.GetErrorCode());
|
||||
}
|
||||
|
||||
|
||||
@@ -346,50 +359,52 @@ int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestNa
|
||||
{
|
||||
Data->Cmd.DllOpMode=Operation;
|
||||
|
||||
*Data->Cmd.ExtrPath=0;
|
||||
*Data->Cmd.DllDestName=0;
|
||||
Data->Cmd.ExtrPath.clear();
|
||||
Data->Cmd.DllDestName.clear();
|
||||
|
||||
if (DestPath!=NULL)
|
||||
{
|
||||
char ExtrPathA[NM];
|
||||
strncpyz(ExtrPathA,DestPath,ASIZE(ExtrPathA)-2);
|
||||
std::string ExtrPathA=DestPath;
|
||||
#ifdef _WIN_ALL
|
||||
// We must not apply OemToCharBuffA directly to DestPath,
|
||||
// because we do not know DestPath length and OemToCharBuffA
|
||||
// does not stop at 0.
|
||||
OemToCharA(ExtrPathA,ExtrPathA);
|
||||
OemToExt(ExtrPathA,ExtrPathA);
|
||||
#endif
|
||||
CharToWide(ExtrPathA,Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath));
|
||||
AddEndSlash(Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath));
|
||||
CharToWide(ExtrPathA,Data->Cmd.ExtrPath);
|
||||
AddEndSlash(Data->Cmd.ExtrPath);
|
||||
}
|
||||
if (DestName!=NULL)
|
||||
{
|
||||
char DestNameA[NM];
|
||||
strncpyz(DestNameA,DestName,ASIZE(DestNameA)-2);
|
||||
std::string DestNameA=DestName;
|
||||
#ifdef _WIN_ALL
|
||||
// We must not apply OemToCharBuffA directly to DestName,
|
||||
// because we do not know DestName length and OemToCharBuffA
|
||||
// does not stop at 0.
|
||||
OemToCharA(DestNameA,DestNameA);
|
||||
OemToExt(DestNameA,DestNameA);
|
||||
#endif
|
||||
CharToWide(DestNameA,Data->Cmd.DllDestName,ASIZE(Data->Cmd.DllDestName));
|
||||
CharToWide(DestNameA,Data->Cmd.DllDestName);
|
||||
}
|
||||
|
||||
if (DestPathW!=NULL)
|
||||
{
|
||||
wcsncpy(Data->Cmd.ExtrPath,DestPathW,ASIZE(Data->Cmd.ExtrPath));
|
||||
AddEndSlash(Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath));
|
||||
Data->Cmd.ExtrPath=DestPathW;
|
||||
AddEndSlash(Data->Cmd.ExtrPath);
|
||||
}
|
||||
|
||||
if (DestNameW!=NULL)
|
||||
wcsncpyz(Data->Cmd.DllDestName,DestNameW,ASIZE(Data->Cmd.DllDestName));
|
||||
Data->Cmd.DllDestName=DestNameW;
|
||||
|
||||
wcsncpyz(Data->Cmd.Command,Operation==RAR_EXTRACT ? L"X":L"T",ASIZE(Data->Cmd.Command));
|
||||
Data->Cmd.Command=Operation==RAR_EXTRACT ? L"X":L"T";
|
||||
Data->Cmd.Test=Operation!=RAR_EXTRACT;
|
||||
bool Repeat=false;
|
||||
Data->Extract.ExtractCurrentFile(Data->Arc,Data->HeaderSize,Repeat);
|
||||
|
||||
// Now we process extra file information if any.
|
||||
// It is important to do it in the same ProcessFile(), because caller
|
||||
// app can rely on this behavior, for example, to overwrite
|
||||
// the extracted Mark of the Web with propagated from archive
|
||||
// immediately after ProcessFile() call.
|
||||
//
|
||||
// Archive can be closed if we process volumes, next volume is missing
|
||||
// and current one is already removed or deleted. So we need to check
|
||||
@@ -413,7 +428,7 @@ int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestNa
|
||||
{
|
||||
return Data->Cmd.DllError!=0 ? Data->Cmd.DllError : RarErrorToDll(ErrCode);
|
||||
}
|
||||
return Data->Cmd.DllError;
|
||||
return Data->Cmd.DllError!=0 ? Data->Cmd.DllError : RarErrorToDll(ErrHandler.GetErrorCode());
|
||||
}
|
||||
|
||||
|
||||
@@ -456,7 +471,7 @@ void PASCAL RARSetPassword(HANDLE hArcData,char *Password)
|
||||
#ifndef RAR_NOCRYPT
|
||||
DataSet *Data=(DataSet *)hArcData;
|
||||
wchar PasswordW[MAXPASSWORD];
|
||||
GetWideName(Password,NULL,PasswordW,ASIZE(PasswordW));
|
||||
CharToWide(Password,PasswordW,ASIZE(PasswordW));
|
||||
Data->Cmd.Password.Set(PasswordW);
|
||||
cleandata(PasswordW,sizeof(PasswordW));
|
||||
#endif
|
||||
@@ -474,6 +489,7 @@ static int RarErrorToDll(RAR_EXIT ErrCode)
|
||||
switch(ErrCode)
|
||||
{
|
||||
case RARX_FATAL:
|
||||
case RARX_READ:
|
||||
return ERAR_EREAD;
|
||||
case RARX_CRC:
|
||||
return ERAR_BAD_DATA;
|
||||
@@ -489,6 +505,8 @@ static int RarErrorToDll(RAR_EXIT ErrCode)
|
||||
return ERAR_BAD_PASSWORD;
|
||||
case RARX_SUCCESS:
|
||||
return ERAR_SUCCESS; // 0.
|
||||
case RARX_BADARC:
|
||||
return ERAR_BAD_ARCHIVE;
|
||||
default:
|
||||
return ERAR_UNKNOWN;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#define ERAR_MISSING_PASSWORD 22
|
||||
#define ERAR_EREFERENCE 23
|
||||
#define ERAR_BAD_PASSWORD 24
|
||||
#define ERAR_LARGE_DICT 25
|
||||
|
||||
#define RAR_OM_LIST 0
|
||||
#define RAR_OM_EXTRACT 1
|
||||
@@ -31,7 +32,7 @@
|
||||
#define RAR_VOL_ASK 0
|
||||
#define RAR_VOL_NOTIFY 1
|
||||
|
||||
#define RAR_DLL_VERSION 8
|
||||
#define RAR_DLL_VERSION 9
|
||||
|
||||
#define RAR_HASH_NONE 0
|
||||
#define RAR_HASH_CRC32 1
|
||||
@@ -108,7 +109,11 @@ struct RARHeaderDataEx
|
||||
unsigned int CtimeHigh;
|
||||
unsigned int AtimeLow;
|
||||
unsigned int AtimeHigh;
|
||||
unsigned int Reserved[988];
|
||||
wchar_t *ArcNameEx;
|
||||
unsigned int ArcNameExSize;
|
||||
wchar_t *FileNameEx;
|
||||
unsigned int FileNameExSize;
|
||||
unsigned int Reserved[982];
|
||||
};
|
||||
|
||||
|
||||
@@ -152,12 +157,13 @@ struct RAROpenArchiveDataEx
|
||||
LPARAM UserData;
|
||||
unsigned int OpFlags;
|
||||
wchar_t *CmtBufW;
|
||||
unsigned int Reserved[25];
|
||||
wchar_t *MarkOfTheWeb;
|
||||
unsigned int Reserved[23];
|
||||
};
|
||||
|
||||
enum UNRARCALLBACK_MESSAGES {
|
||||
UCM_CHANGEVOLUME,UCM_PROCESSDATA,UCM_NEEDPASSWORD,UCM_CHANGEVOLUMEW,
|
||||
UCM_NEEDPASSWORDW
|
||||
UCM_NEEDPASSWORDW,UCM_LARGEDICT
|
||||
};
|
||||
|
||||
typedef int (PASCAL *CHANGEVOLPROC)(char *ArcName,int Mode);
|
||||
|
||||
10
unrar/dll.rc
10
unrar/dll.rc
@@ -2,8 +2,8 @@
|
||||
#include <commctrl.h>
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 5, 91, 100, 3470
|
||||
PRODUCTVERSION 5, 91, 100, 3470
|
||||
FILEVERSION 7, 20, 100, 1861
|
||||
PRODUCTVERSION 7, 20, 100, 1861
|
||||
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", "5.91.0\0"
|
||||
VALUE "ProductVersion", "5.91.0\0"
|
||||
VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2020\0"
|
||||
VALUE "FileVersion", "7.20.0\0"
|
||||
VALUE "ProductVersion", "7.20.0\0"
|
||||
VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2026\0"
|
||||
VALUE "OriginalFilename", "Unrar.dll\0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,17 +11,16 @@ EncodeFileName::EncodeFileName()
|
||||
|
||||
|
||||
|
||||
void EncodeFileName::Decode(char *Name,size_t NameSize,byte *EncName,size_t EncSize,
|
||||
wchar *NameW,size_t MaxDecSize)
|
||||
void EncodeFileName::Decode(const char *Name,size_t NameSize,
|
||||
const byte *EncName,size_t EncSize,
|
||||
std::wstring &NameW)
|
||||
{
|
||||
size_t EncPos=0,DecPos=0;
|
||||
byte HighByte=EncPos<EncSize ? EncName[EncPos++] : 0;
|
||||
while (EncPos<EncSize && DecPos<MaxDecSize)
|
||||
while (EncPos<EncSize)
|
||||
{
|
||||
if (FlagBits==0)
|
||||
{
|
||||
if (EncPos>=EncSize)
|
||||
break;
|
||||
Flags=EncName[EncPos++];
|
||||
FlagBits=8;
|
||||
}
|
||||
@@ -30,16 +29,20 @@ void EncodeFileName::Decode(char *Name,size_t NameSize,byte *EncName,size_t EncS
|
||||
case 0:
|
||||
if (EncPos>=EncSize)
|
||||
break;
|
||||
// We need DecPos also for ASCII "Name", so resize() instead of push_back().
|
||||
NameW.resize(DecPos+1);
|
||||
NameW[DecPos++]=EncName[EncPos++];
|
||||
break;
|
||||
case 1:
|
||||
if (EncPos>=EncSize)
|
||||
break;
|
||||
NameW.resize(DecPos+1);
|
||||
NameW[DecPos++]=EncName[EncPos++]+(HighByte<<8);
|
||||
break;
|
||||
case 2:
|
||||
if (EncPos+1>=EncSize)
|
||||
break;
|
||||
NameW.resize(DecPos+1);
|
||||
NameW[DecPos++]=EncName[EncPos]+(EncName[EncPos+1]<<8);
|
||||
EncPos+=2;
|
||||
break;
|
||||
@@ -53,17 +56,22 @@ void EncodeFileName::Decode(char *Name,size_t NameSize,byte *EncName,size_t EncS
|
||||
if (EncPos>=EncSize)
|
||||
break;
|
||||
byte Correction=EncName[EncPos++];
|
||||
for (Length=(Length&0x7f)+2;Length>0 && DecPos<MaxDecSize && DecPos<NameSize;Length--,DecPos++)
|
||||
for (Length=(Length&0x7f)+2;Length>0 && DecPos<NameSize;Length--,DecPos++)
|
||||
{
|
||||
NameW.resize(DecPos+1);
|
||||
NameW[DecPos]=((Name[DecPos]+Correction)&0xff)+(HighByte<<8);
|
||||
}
|
||||
}
|
||||
else
|
||||
for (Length+=2;Length>0 && DecPos<MaxDecSize && DecPos<NameSize;Length--,DecPos++)
|
||||
for (Length+=2;Length>0 && DecPos<NameSize;Length--,DecPos++)
|
||||
{
|
||||
NameW.resize(DecPos+1);
|
||||
NameW[DecPos]=Name[DecPos];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
Flags<<=2;
|
||||
FlagBits-=2;
|
||||
}
|
||||
NameW[DecPos<MaxDecSize ? DecPos:MaxDecSize-1]=0;
|
||||
}
|
||||
|
||||
@@ -4,17 +4,16 @@
|
||||
class EncodeFileName
|
||||
{
|
||||
private:
|
||||
void AddFlags(int Value);
|
||||
void AddFlags(byte Value,std::vector<byte> &EncName);
|
||||
|
||||
byte *EncName;
|
||||
byte Flags;
|
||||
uint FlagBits;
|
||||
size_t FlagsPos;
|
||||
size_t DestSize;
|
||||
public:
|
||||
EncodeFileName();
|
||||
size_t Encode(char *Name,wchar *NameW,byte *EncName);
|
||||
void Decode(char *Name,size_t NameSize,byte *EncName,size_t EncSize,wchar *NameW,size_t MaxDecSize);
|
||||
void Encode(const std::string &Name,const std::wstring &NameW,std::vector<byte> &EncName);
|
||||
void Decode(const char *Name,size_t NameSize,const byte *EncName,size_t EncSize,std::wstring &NameW);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
142
unrar/errhnd.cpp
142
unrar/errhnd.cpp
@@ -15,6 +15,7 @@ void ErrorHandler::Clean()
|
||||
UserBreak=false;
|
||||
MainExit=false;
|
||||
DisableShutdown=false;
|
||||
ReadErrIgnoreAll=false;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +26,7 @@ void ErrorHandler::MemoryError()
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::OpenError(const wchar *FileName)
|
||||
void ErrorHandler::OpenError(const std::wstring &FileName)
|
||||
{
|
||||
#ifndef SILENT
|
||||
OpenErrorMsg(FileName);
|
||||
@@ -34,7 +35,7 @@ void ErrorHandler::OpenError(const wchar *FileName)
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::CloseError(const wchar *FileName)
|
||||
void ErrorHandler::CloseError(const std::wstring &FileName)
|
||||
{
|
||||
if (!UserBreak)
|
||||
{
|
||||
@@ -50,34 +51,44 @@ void ErrorHandler::CloseError(const wchar *FileName)
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::ReadError(const wchar *FileName)
|
||||
void ErrorHandler::ReadError(const std::wstring &FileName)
|
||||
{
|
||||
#ifndef SILENT
|
||||
ReadErrorMsg(FileName);
|
||||
#endif
|
||||
#if !defined(SILENT) || defined(RARDLL)
|
||||
Exit(RARX_FATAL);
|
||||
Exit(RARX_READ);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool ErrorHandler::AskRepeatRead(const wchar *FileName)
|
||||
void ErrorHandler::AskRepeatRead(const std::wstring &FileName,bool &Ignore,bool &Retry,bool &Quit)
|
||||
{
|
||||
SetErrorCode(RARX_READ);
|
||||
#if !defined(SILENT) && !defined(SFX_MODULE)
|
||||
if (!Silent)
|
||||
{
|
||||
uiMsg(UIERROR_FILEREAD,L"",FileName);
|
||||
SysErrMsg();
|
||||
bool Repeat=uiAskRepeatRead(FileName);
|
||||
if (!Repeat) // Disable shutdown if user pressed Cancel in error dialog.
|
||||
DisableShutdown=true;
|
||||
return Repeat;
|
||||
if (ReadErrIgnoreAll)
|
||||
Ignore=true;
|
||||
else
|
||||
{
|
||||
bool All=false;
|
||||
uiAskRepeatRead(FileName,Ignore,All,Retry,Quit);
|
||||
if (All)
|
||||
ReadErrIgnoreAll=Ignore=true;
|
||||
if (Quit) // Disable shutdown if user select Quit in read error prompt.
|
||||
DisableShutdown=true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
Ignore=true; // Saving the file part for -y or -inul or "Ignore all" choice.
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::WriteError(const wchar *ArcName,const wchar *FileName)
|
||||
void ErrorHandler::WriteError(const std::wstring &ArcName,const std::wstring &FileName)
|
||||
{
|
||||
#ifndef SILENT
|
||||
WriteErrorMsg(ArcName,FileName);
|
||||
@@ -89,7 +100,7 @@ void ErrorHandler::WriteError(const wchar *ArcName,const wchar *FileName)
|
||||
|
||||
|
||||
#ifdef _WIN_ALL
|
||||
void ErrorHandler::WriteErrorFAT(const wchar *FileName)
|
||||
void ErrorHandler::WriteErrorFAT(const std::wstring &FileName)
|
||||
{
|
||||
SysErrMsg();
|
||||
uiMsg(UIERROR_NTFSREQUIRED,FileName);
|
||||
@@ -100,7 +111,7 @@ void ErrorHandler::WriteErrorFAT(const wchar *FileName)
|
||||
#endif
|
||||
|
||||
|
||||
bool ErrorHandler::AskRepeatWrite(const wchar *FileName,bool DiskFull)
|
||||
bool ErrorHandler::AskRepeatWrite(const std::wstring &FileName,bool DiskFull)
|
||||
{
|
||||
#ifndef SILENT
|
||||
if (!Silent)
|
||||
@@ -118,7 +129,7 @@ bool ErrorHandler::AskRepeatWrite(const wchar *FileName,bool DiskFull)
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::SeekError(const wchar *FileName)
|
||||
void ErrorHandler::SeekError(const std::wstring &FileName)
|
||||
{
|
||||
if (!UserBreak)
|
||||
{
|
||||
@@ -133,13 +144,16 @@ void ErrorHandler::SeekError(const wchar *FileName)
|
||||
|
||||
void ErrorHandler::GeneralErrMsg(const wchar *fmt,...)
|
||||
{
|
||||
#ifndef RARDLL
|
||||
va_list arglist;
|
||||
va_start(arglist,fmt);
|
||||
wchar Msg[1024];
|
||||
vswprintf(Msg,ASIZE(Msg),fmt,arglist);
|
||||
|
||||
std::wstring Msg=vwstrprintf(fmt,arglist);
|
||||
uiMsg(UIERROR_GENERALERRMSG,Msg);
|
||||
SysErrMsg();
|
||||
|
||||
va_end(arglist);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -150,28 +164,31 @@ void ErrorHandler::MemoryErrorMsg()
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::OpenErrorMsg(const wchar *FileName)
|
||||
void ErrorHandler::OpenErrorMsg(const std::wstring &FileName)
|
||||
{
|
||||
OpenErrorMsg(NULL,FileName);
|
||||
OpenErrorMsg(L"",FileName);
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::OpenErrorMsg(const wchar *ArcName,const wchar *FileName)
|
||||
void ErrorHandler::OpenErrorMsg(const std::wstring &ArcName,const std::wstring &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();
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::CreateErrorMsg(const wchar *FileName)
|
||||
void ErrorHandler::CreateErrorMsg(const std::wstring &FileName)
|
||||
{
|
||||
CreateErrorMsg(NULL,FileName);
|
||||
CreateErrorMsg(L"",FileName);
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::CreateErrorMsg(const wchar *ArcName,const wchar *FileName)
|
||||
void ErrorHandler::CreateErrorMsg(const std::wstring &ArcName,const std::wstring &FileName)
|
||||
{
|
||||
uiMsg(UIERROR_FILECREATE,ArcName,FileName);
|
||||
SysErrMsg();
|
||||
@@ -179,21 +196,21 @@ void ErrorHandler::CreateErrorMsg(const wchar *ArcName,const wchar *FileName)
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::ReadErrorMsg(const wchar *FileName)
|
||||
void ErrorHandler::ReadErrorMsg(const std::wstring &FileName)
|
||||
{
|
||||
ReadErrorMsg(NULL,FileName);
|
||||
ReadErrorMsg(L"",FileName);
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::ReadErrorMsg(const wchar *ArcName,const wchar *FileName)
|
||||
void ErrorHandler::ReadErrorMsg(const std::wstring &ArcName,const std::wstring &FileName)
|
||||
{
|
||||
uiMsg(UIERROR_FILEREAD,ArcName,FileName);
|
||||
SysErrMsg();
|
||||
SetErrorCode(RARX_FATAL);
|
||||
SetErrorCode(RARX_READ);
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::WriteErrorMsg(const wchar *ArcName,const wchar *FileName)
|
||||
void ErrorHandler::WriteErrorMsg(const std::wstring &ArcName,const std::wstring &FileName)
|
||||
{
|
||||
uiMsg(UIERROR_FILEWRITE,ArcName,FileName);
|
||||
SysErrMsg();
|
||||
@@ -201,21 +218,21 @@ void ErrorHandler::WriteErrorMsg(const wchar *ArcName,const wchar *FileName)
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::ArcBrokenMsg(const wchar *ArcName)
|
||||
void ErrorHandler::ArcBrokenMsg(const std::wstring &ArcName)
|
||||
{
|
||||
uiMsg(UIERROR_ARCBROKEN,ArcName);
|
||||
SetErrorCode(RARX_CRC);
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::ChecksumFailedMsg(const wchar *ArcName,const wchar *FileName)
|
||||
void ErrorHandler::ChecksumFailedMsg(const std::wstring &ArcName,const std::wstring &FileName)
|
||||
{
|
||||
uiMsg(UIERROR_CHECKSUM,ArcName,FileName);
|
||||
SetErrorCode(RARX_CRC);
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::UnknownMethodMsg(const wchar *ArcName,const wchar *FileName)
|
||||
void ErrorHandler::UnknownMethodMsg(const std::wstring &ArcName,const std::wstring &FileName)
|
||||
{
|
||||
uiMsg(UIERROR_UNKNOWNMETHOD,ArcName,FileName);
|
||||
ErrHandler.SetErrorCode(RARX_FATAL);
|
||||
@@ -239,7 +256,8 @@ void ErrorHandler::SetErrorCode(RAR_EXIT Code)
|
||||
ExitCode=Code;
|
||||
break;
|
||||
case RARX_CRC:
|
||||
if (ExitCode!=RARX_BADPWD)
|
||||
// 2025.10.25: RARX_OPEN is set if next volume is missing.
|
||||
if (ExitCode!=RARX_BADPWD && ExitCode!=RARX_OPEN)
|
||||
ExitCode=Code;
|
||||
break;
|
||||
case RARX_FATAL:
|
||||
@@ -318,33 +336,44 @@ void ErrorHandler::Throw(RAR_EXIT Code)
|
||||
if (Code==RARX_USERBREAK && !EnableBreak)
|
||||
return;
|
||||
#if !defined(SILENT)
|
||||
// Do not write "aborted" when just displaying online help.
|
||||
if (Code!=RARX_SUCCESS && Code!=RARX_USERERROR)
|
||||
mprintf(L"\n%s\n",St(MProgAborted));
|
||||
if (Code!=RARX_SUCCESS)
|
||||
if (Code==RARX_USERERROR) // Do not write "aborted" when just displaying the online help.
|
||||
mprintf(L"\n"); // For consistency with other errors, which print the final "\n".
|
||||
else
|
||||
mprintf(L"\n%s\n",St(MProgAborted));
|
||||
#endif
|
||||
SetErrorCode(Code);
|
||||
throw Code;
|
||||
}
|
||||
|
||||
|
||||
bool ErrorHandler::GetSysErrMsg(wchar *Msg,size_t Size)
|
||||
bool ErrorHandler::GetSysErrMsg(std::wstring &Msg)
|
||||
{
|
||||
#ifndef SILENT
|
||||
#ifdef _WIN_ALL
|
||||
int ErrType=GetLastError();
|
||||
if (ErrType!=0)
|
||||
return FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,ErrType,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
|
||||
Msg,(DWORD)Size,NULL)!=0;
|
||||
{
|
||||
wchar *Buf=nullptr;
|
||||
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||||
NULL,ErrType,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
|
||||
(LPTSTR)&Buf,0,NULL)!=0)
|
||||
{
|
||||
Msg=Buf;
|
||||
LocalFree(Buf);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_UNIX) || defined(_EMX)
|
||||
#ifdef _UNIX
|
||||
if (errno!=0)
|
||||
{
|
||||
char *err=strerror(errno);
|
||||
if (err!=NULL)
|
||||
{
|
||||
CharToWide(err,Msg,Size);
|
||||
CharToWide(err,Msg);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -356,32 +385,27 @@ bool ErrorHandler::GetSysErrMsg(wchar *Msg,size_t Size)
|
||||
|
||||
void ErrorHandler::SysErrMsg()
|
||||
{
|
||||
#if !defined(SFX_MODULE) && !defined(SILENT)
|
||||
wchar Msg[1024];
|
||||
if (!GetSysErrMsg(Msg,ASIZE(Msg)))
|
||||
#ifndef SILENT
|
||||
std::wstring Msg;
|
||||
if (!GetSysErrMsg(Msg))
|
||||
return;
|
||||
#ifdef _WIN_ALL
|
||||
wchar *CurMsg=Msg;
|
||||
while (CurMsg!=NULL) // Print string with \r\n as several strings to multiple lines.
|
||||
// Print string with \r\n as several strings to multiple lines.
|
||||
size_t Pos=0;
|
||||
while (Pos!=std::wstring::npos)
|
||||
{
|
||||
while (*CurMsg=='\r' || *CurMsg=='\n')
|
||||
CurMsg++;
|
||||
if (*CurMsg==0)
|
||||
while (Msg[Pos]=='\r' || Msg[Pos]=='\n')
|
||||
Pos++;
|
||||
if (Pos==Msg.size())
|
||||
break;
|
||||
wchar *EndMsg=wcschr(CurMsg,'\r');
|
||||
if (EndMsg==NULL)
|
||||
EndMsg=wcschr(CurMsg,'\n');
|
||||
if (EndMsg!=NULL)
|
||||
{
|
||||
*EndMsg=0;
|
||||
EndMsg++;
|
||||
}
|
||||
size_t EndPos=Msg.find_first_of(L"\r\n",Pos);
|
||||
std::wstring CurMsg=Msg.substr(Pos,EndPos==std::wstring::npos ? EndPos:EndPos-Pos);
|
||||
uiMsg(UIERROR_SYSERRMSG,CurMsg);
|
||||
CurMsg=EndMsg;
|
||||
Pos=EndPos;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_UNIX) || defined(_EMX)
|
||||
#ifdef _UNIX
|
||||
uiMsg(UIERROR_SYSERRMSG,Msg);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -15,9 +15,12 @@ enum RAR_EXIT // RAR exit code.
|
||||
RARX_CREATE = 9,
|
||||
RARX_NOFILES = 10,
|
||||
RARX_BADPWD = 11,
|
||||
RARX_READ = 12,
|
||||
RARX_BADARC = 13,
|
||||
RARX_USERBREAK = 255
|
||||
};
|
||||
|
||||
|
||||
class ErrorHandler
|
||||
{
|
||||
private:
|
||||
@@ -26,30 +29,31 @@ class ErrorHandler
|
||||
bool EnableBreak;
|
||||
bool Silent;
|
||||
bool DisableShutdown; // Shutdown is not suitable after last error.
|
||||
bool ReadErrIgnoreAll;
|
||||
public:
|
||||
ErrorHandler();
|
||||
void Clean();
|
||||
void MemoryError();
|
||||
void OpenError(const wchar *FileName);
|
||||
void CloseError(const wchar *FileName);
|
||||
void ReadError(const wchar *FileName);
|
||||
bool AskRepeatRead(const wchar *FileName);
|
||||
void WriteError(const wchar *ArcName,const wchar *FileName);
|
||||
void WriteErrorFAT(const wchar *FileName);
|
||||
bool AskRepeatWrite(const wchar *FileName,bool DiskFull);
|
||||
void SeekError(const wchar *FileName);
|
||||
void OpenError(const std::wstring &FileName);
|
||||
void CloseError(const std::wstring &FileName);
|
||||
void ReadError(const std::wstring &FileName);
|
||||
void AskRepeatRead(const std::wstring &FileName,bool &Ignore,bool &Retry,bool &Quit);
|
||||
void WriteError(const std::wstring &ArcName,const std::wstring &FileName);
|
||||
void WriteErrorFAT(const std::wstring &FileName);
|
||||
bool AskRepeatWrite(const std::wstring &FileName,bool DiskFull);
|
||||
void SeekError(const std::wstring &FileName);
|
||||
void GeneralErrMsg(const wchar *fmt,...);
|
||||
void MemoryErrorMsg();
|
||||
void OpenErrorMsg(const wchar *FileName);
|
||||
void OpenErrorMsg(const wchar *ArcName,const wchar *FileName);
|
||||
void CreateErrorMsg(const wchar *FileName);
|
||||
void CreateErrorMsg(const wchar *ArcName,const wchar *FileName);
|
||||
void ReadErrorMsg(const wchar *FileName);
|
||||
void ReadErrorMsg(const wchar *ArcName,const wchar *FileName);
|
||||
void WriteErrorMsg(const wchar *ArcName,const wchar *FileName);
|
||||
void ArcBrokenMsg(const wchar *ArcName);
|
||||
void ChecksumFailedMsg(const wchar *ArcName,const wchar *FileName);
|
||||
void UnknownMethodMsg(const wchar *ArcName,const wchar *FileName);
|
||||
void OpenErrorMsg(const std::wstring &FileName);
|
||||
void OpenErrorMsg(const std::wstring &ArcName,const std::wstring &FileName);
|
||||
void CreateErrorMsg(const std::wstring &FileName);
|
||||
void CreateErrorMsg(const std::wstring &ArcName,const std::wstring &FileName);
|
||||
void ReadErrorMsg(const std::wstring &FileName);
|
||||
void ReadErrorMsg(const std::wstring &ArcName,const std::wstring &FileName);
|
||||
void WriteErrorMsg(const std::wstring &ArcName,const std::wstring &FileName);
|
||||
void ArcBrokenMsg(const std::wstring &ArcName);
|
||||
void ChecksumFailedMsg(const std::wstring &ArcName,const std::wstring &FileName);
|
||||
void UnknownMethodMsg(const std::wstring &ArcName,const std::wstring &FileName);
|
||||
void Exit(RAR_EXIT ExitCode);
|
||||
void SetErrorCode(RAR_EXIT Code);
|
||||
RAR_EXIT GetErrorCode() {return ExitCode;}
|
||||
@@ -57,7 +61,7 @@ class ErrorHandler
|
||||
void SetSignalHandlers(bool Enable);
|
||||
void Throw(RAR_EXIT Code);
|
||||
void SetSilent(bool Mode) {Silent=Mode;}
|
||||
bool GetSysErrMsg(wchar *Msg,size_t Size);
|
||||
bool GetSysErrMsg(std::wstring &Msg);
|
||||
void SysErrMsg();
|
||||
int GetSystemErrorCode();
|
||||
void SetSystemErrorCode(int Code);
|
||||
|
||||
@@ -19,19 +19,13 @@
|
||||
|
||||
// RAR2 service header extra records.
|
||||
#ifndef SFX_MODULE
|
||||
void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *Name)
|
||||
void SetExtraInfo20(CommandData *Cmd,Archive &Arc,const std::wstring &Name)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
if (Cmd->Test)
|
||||
return;
|
||||
switch(Arc.SubBlockHead.SubType)
|
||||
{
|
||||
#ifdef _UNIX
|
||||
case UO_HEAD:
|
||||
if (Cmd->ProcessOwners)
|
||||
ExtractUnixOwner20(Arc,Name);
|
||||
break;
|
||||
#endif
|
||||
#ifdef _WIN_ALL
|
||||
case NTACL_HEAD:
|
||||
if (Cmd->ProcessOwners)
|
||||
ExtractACL20(Arc,Name);
|
||||
@@ -39,19 +33,19 @@ void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *Name)
|
||||
case STREAM_HEAD:
|
||||
ExtractStreams20(Arc,Name);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// RAR3 and RAR5 service header extra records.
|
||||
void SetExtraInfo(CommandData *Cmd,Archive &Arc,wchar *Name)
|
||||
void SetExtraInfo(CommandData *Cmd,Archive &Arc,const std::wstring &Name)
|
||||
{
|
||||
#ifdef _UNIX
|
||||
if (!Cmd->Test && Cmd->ProcessOwners && Arc.Format==RARFMT15 &&
|
||||
Arc.SubHead.CmpName(SUBHEAD_TYPE_UOWNER))
|
||||
ExtractUnixOwner30(Arc,Name);
|
||||
ExtractUnixOwner30(Arc,Name.c_str());
|
||||
#endif
|
||||
#ifdef _WIN_ALL
|
||||
if (!Cmd->Test && Cmd->ProcessOwners && Arc.SubHead.CmpName(SUBHEAD_TYPE_ACL))
|
||||
@@ -63,7 +57,7 @@ void SetExtraInfo(CommandData *Cmd,Archive &Arc,wchar *Name)
|
||||
|
||||
|
||||
// Extra data stored directly in file header.
|
||||
void SetFileHeaderExtra(CommandData *Cmd,Archive &Arc,wchar *Name)
|
||||
void SetFileHeaderExtra(CommandData *Cmd,Archive &Arc,const std::wstring &Name)
|
||||
{
|
||||
#ifdef _UNIX
|
||||
if (Cmd->ProcessOwners && Arc.Format==RARFMT50 && Arc.FileHead.UnixOwnerSet)
|
||||
@@ -74,36 +68,34 @@ void SetFileHeaderExtra(CommandData *Cmd,Archive &Arc,wchar *Name)
|
||||
|
||||
|
||||
|
||||
// Calculate a number of path components except \. and \..
|
||||
static int CalcAllowedDepth(const wchar *Name)
|
||||
// Calculate the number of path components except \. and \..
|
||||
static int CalcAllowedDepth(const std::wstring &Name)
|
||||
{
|
||||
int AllowedDepth=0;
|
||||
while (*Name!=0)
|
||||
{
|
||||
if (IsPathDiv(Name[0]) && Name[1]!=0 && !IsPathDiv(Name[1]))
|
||||
for (size_t I=0;I<Name.size();I++)
|
||||
if (IsPathDiv(Name[I]))
|
||||
{
|
||||
bool Dot=Name[1]=='.' && (IsPathDiv(Name[2]) || Name[2]==0);
|
||||
bool Dot2=Name[1]=='.' && Name[2]=='.' && (IsPathDiv(Name[3]) || Name[3]==0);
|
||||
bool Dot=Name[I+1]=='.' && (IsPathDiv(Name[I+2]) || Name[I+2]==0);
|
||||
bool Dot2=Name[I+1]=='.' && Name[I+2]=='.' && (IsPathDiv(Name[I+3]) || Name[I+3]==0);
|
||||
if (!Dot && !Dot2)
|
||||
AllowedDepth++;
|
||||
else
|
||||
if (Dot2)
|
||||
AllowedDepth--;
|
||||
}
|
||||
Name++;
|
||||
}
|
||||
return AllowedDepth;
|
||||
return AllowedDepth < 0 ? 0 : AllowedDepth;
|
||||
}
|
||||
|
||||
|
||||
// Check if all existing path components are directories and not links.
|
||||
static bool LinkInPath(const wchar *Name)
|
||||
static bool LinkInPath(std::wstring Path)
|
||||
{
|
||||
wchar Path[NM];
|
||||
if (wcslen(Name)>=ASIZE(Path))
|
||||
return true; // It should not be that long, skip.
|
||||
wcsncpyz(Path,Name,ASIZE(Path));
|
||||
for (wchar *s=Path+wcslen(Path)-1;s>Path;s--)
|
||||
if (IsPathDiv(*s))
|
||||
if (Path.empty()) // So we can safely use Path.size()-1 below.
|
||||
return false;
|
||||
for (size_t I=Path.size()-1;I>0;I--)
|
||||
if (IsPathDiv(Path[I]))
|
||||
{
|
||||
*s=0;
|
||||
Path.erase(I);
|
||||
FindData FD;
|
||||
if (FindFile::FastFind(Path,&FD,true) && (FD.IsLink || !FD.IsDir))
|
||||
return true;
|
||||
@@ -112,7 +104,7 @@ static bool LinkInPath(const wchar *Name)
|
||||
}
|
||||
|
||||
|
||||
bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName)
|
||||
bool IsRelativeSymlinkSafe(CommandData *Cmd,const std::wstring &SrcName,std::wstring PrepSrcName,const std::wstring &TargetName)
|
||||
{
|
||||
// Catch root dir based /path/file paths also as stuff like \\?\.
|
||||
// Do not check PrepSrcName here, it can be root based if destination path
|
||||
@@ -122,19 +114,22 @@ bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *Pr
|
||||
|
||||
// Number of ".." in link target.
|
||||
int UpLevels=0;
|
||||
for (int Pos=0;*TargetName!=0;Pos++)
|
||||
for (uint Pos=0;Pos<TargetName.size();Pos++)
|
||||
{
|
||||
bool Dot2=TargetName[0]=='.' && TargetName[1]=='.' &&
|
||||
(IsPathDiv(TargetName[2]) || TargetName[2]==0) &&
|
||||
(Pos==0 || IsPathDiv(*(TargetName-1)));
|
||||
bool Dot2=TargetName[Pos]=='.' && TargetName[Pos+1]=='.' &&
|
||||
(IsPathDiv(TargetName[Pos+2]) || TargetName[Pos+2]==0) &&
|
||||
(Pos==0 || IsPathDiv(TargetName[Pos-1]));
|
||||
if (Dot2)
|
||||
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;
|
||||
|
||||
@@ -147,12 +142,12 @@ bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *Pr
|
||||
// Remove the destination path from prepared name if any. We should not
|
||||
// count the destination path depth, because the link target must point
|
||||
// inside of this path, not outside of it.
|
||||
size_t ExtrPathLength=wcslen(Cmd->ExtrPath);
|
||||
if (ExtrPathLength>0 && wcsncmp(PrepSrcName,Cmd->ExtrPath,ExtrPathLength)==0)
|
||||
size_t ExtrPathLength=Cmd->ExtrPath.size();
|
||||
if (ExtrPathLength>0 && PrepSrcName.compare(0,ExtrPathLength,Cmd->ExtrPath)==0)
|
||||
{
|
||||
PrepSrcName+=ExtrPathLength;
|
||||
while (IsPathDiv(*PrepSrcName))
|
||||
PrepSrcName++;
|
||||
while (IsPathDiv(PrepSrcName[ExtrPathLength]))
|
||||
ExtrPathLength++;
|
||||
PrepSrcName.erase(0,ExtrPathLength);
|
||||
}
|
||||
int PrepAllowedDepth=CalcAllowedDepth(PrepSrcName);
|
||||
|
||||
@@ -160,19 +155,30 @@ 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 std::wstring &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=Arc.FileHead.RedirName.find(L"..")!=std::wstring::npos;
|
||||
#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.c_str(),UpLink);
|
||||
if (Arc.Format==RARFMT50)
|
||||
return ExtractUnixLink50(Cmd,LinkName,&Arc.FileHead);
|
||||
#elif defined _WIN_ALL
|
||||
return ExtractUnixLink50(Cmd,LinkName.c_str(),&Arc.FileHead);
|
||||
#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)
|
||||
return CreateReparsePoint(Cmd,LinkName,&Arc.FileHead);
|
||||
return CreateReparsePoint(Cmd,LinkName.c_str(),&Arc.FileHead);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,23 +1,19 @@
|
||||
#ifndef _RAR_EXTINFO_
|
||||
#define _RAR_EXTINFO_
|
||||
|
||||
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 IsRelativeSymlinkSafe(CommandData *Cmd,const std::wstring &SrcName,std::wstring PrepSrcName,const std::wstring &TargetName);
|
||||
bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const std::wstring &LinkName,bool &UpLink);
|
||||
#ifdef _UNIX
|
||||
void SetUnixOwner(Archive &Arc,const wchar *FileName);
|
||||
void SetUnixOwner(Archive &Arc,const std::wstring &FileName);
|
||||
#endif
|
||||
|
||||
bool ExtractHardlink(wchar *NameNew,wchar *NameExisting,size_t NameExistingSize);
|
||||
bool ExtractHardlink(CommandData *Cmd,const std::wstring &NameNew,const std::wstring &NameExisting);
|
||||
|
||||
void GetStreamNameNTFS(Archive &Arc,wchar *StreamName,size_t MaxSize);
|
||||
std::wstring GetStreamNameNTFS(Archive &Arc);
|
||||
|
||||
#ifdef _WIN_ALL
|
||||
bool SetPrivilege(LPCTSTR PrivName);
|
||||
#endif
|
||||
|
||||
void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *Name);
|
||||
void SetExtraInfo(CommandData *Cmd,Archive &Arc,wchar *Name);
|
||||
void SetFileHeaderExtra(CommandData *Cmd,Archive &Arc,wchar *Name);
|
||||
void SetExtraInfo20(CommandData *Cmd,Archive &Arc,const std::wstring &Name);
|
||||
void SetExtraInfo(CommandData *Cmd,Archive &Arc,const std::wstring &Name);
|
||||
void SetFileHeaderExtra(CommandData *Cmd,Archive &Arc,const std::wstring &Name);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
1078
unrar/extract.cpp
1078
unrar/extract.cpp
File diff suppressed because it is too large
Load Diff
@@ -6,22 +6,46 @@ enum EXTRACT_ARC_CODE {EXTRACT_ARC_NEXT,EXTRACT_ARC_REPEAT};
|
||||
class CmdExtract
|
||||
{
|
||||
private:
|
||||
struct ExtractRef
|
||||
{
|
||||
std::wstring RefName;
|
||||
std::wstring TmpName;
|
||||
uint64 RefCount;
|
||||
};
|
||||
std::vector<ExtractRef> RefList;
|
||||
|
||||
struct AnalyzeData
|
||||
{
|
||||
std::wstring StartName;
|
||||
uint64 StartPos;
|
||||
std::wstring EndName;
|
||||
uint64 EndPos;
|
||||
} Analyze;
|
||||
|
||||
bool ArcAnalyzed;
|
||||
|
||||
void FreeAnalyzeData();
|
||||
EXTRACT_ARC_CODE ExtractArchive();
|
||||
bool ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize);
|
||||
void ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize);
|
||||
bool ExtractFileCopy(File &New,const std::wstring &ArcName,const std::wstring &RedirName,const std::wstring &NameNew,const std::wstring &NameExisting,int64 UnpSize);
|
||||
void ExtrPrepareName(Archive &Arc,const std::wstring &ArcFileName,std::wstring &DestName);
|
||||
#ifdef RARDLL
|
||||
bool ExtrDllGetPassword();
|
||||
#else
|
||||
bool ExtrGetPassword(Archive &Arc,const wchar *ArcFileName);
|
||||
bool ExtrGetPassword(Archive &Arc,const std::wstring &ArcFileName,RarCheckPassword *CheckPwd);
|
||||
#endif
|
||||
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
|
||||
void ConvertDosPassword(Archive &Arc,SecPassword &DestPwd);
|
||||
#endif
|
||||
void ExtrCreateDir(Archive &Arc,const wchar *ArcFileName);
|
||||
bool ExtrCreateFile(Archive &Arc,File &CurFile);
|
||||
bool CheckUnpVer(Archive &Arc,const wchar *ArcFileName);
|
||||
void ExtrCreateDir(Archive &Arc,const std::wstring &ArcFileName);
|
||||
bool ExtrCreateFile(Archive &Arc,File &CurFile,bool WriteOnly);
|
||||
bool CheckUnpVer(Archive &Arc,const std::wstring &ArcFileName);
|
||||
#ifndef SFX_MODULE
|
||||
void AnalyzeArchive(const std::wstring &ArcName,bool Volume,bool NewNumbering);
|
||||
void GetFirstVolIfFullSet(const std::wstring &SrcName,bool NewNumbering,std::wstring &DestName);
|
||||
#endif
|
||||
bool CheckWinLimit(Archive &Arc,std::wstring &ArcFileName);
|
||||
|
||||
RarTime StartTime; // time when extraction started
|
||||
RarTime StartTime; // Time when extraction started.
|
||||
|
||||
CommandData *Cmd;
|
||||
|
||||
@@ -34,6 +58,7 @@ class CmdExtract
|
||||
bool FirstFile;
|
||||
bool AllMatchesExact;
|
||||
bool ReconstructDone;
|
||||
bool UseExactVolName;
|
||||
|
||||
// If any non-zero solid file was successfully unpacked before current.
|
||||
// If true and if current encrypted file is broken, obviously
|
||||
@@ -41,12 +66,21 @@ class CmdExtract
|
||||
// any wrong password hints.
|
||||
bool AnySolidDataUnpackedWell;
|
||||
|
||||
wchar ArcName[NM];
|
||||
std::wstring ArcName;
|
||||
|
||||
bool GlobalPassword;
|
||||
bool PrevProcessed; // If previous file was successfully extracted or tested.
|
||||
wchar DestFileName[NM];
|
||||
bool PasswordCancelled;
|
||||
std::wstring DestFileName;
|
||||
bool SuppressNoFilesMessage;
|
||||
|
||||
// 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
|
||||
|
||||
@@ -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,std::wstring &Name,
|
||||
bool *UserReject,int64 FileSize,RarTime *FileTime,bool WriteOnly)
|
||||
{
|
||||
if (UserReject!=NULL)
|
||||
@@ -29,7 +29,7 @@ bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
|
||||
// autorename below can change the name, so we need to check it again.
|
||||
ShortNameChanged=false;
|
||||
#endif
|
||||
UIASKREP_RESULT Choice=uiAskReplaceEx(Cmd,Name,MaxNameSize,FileSize,FileTime,(NewFile==NULL ? UIASKREP_F_NORENAME:0));
|
||||
UIASKREP_RESULT Choice=uiAskReplaceEx(Cmd,Name,FileSize,FileTime,(NewFile==NULL ? UIASKREP_F_NORENAME:0));
|
||||
|
||||
if (Choice==UIASKREP_R_REPLACE)
|
||||
break;
|
||||
@@ -44,95 +44,82 @@ 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;
|
||||
|
||||
CreatePath(Name,true);
|
||||
CreatePath(Name,true,Cmd->DisableNames);
|
||||
return NewFile!=NULL ? NewFile->Create(Name,FileMode):DelFile(Name);
|
||||
}
|
||||
|
||||
|
||||
bool GetAutoRenamedName(wchar *Name,size_t MaxNameSize)
|
||||
{
|
||||
wchar NewName[NM];
|
||||
size_t NameLength=wcslen(Name);
|
||||
wchar *Ext=GetExt(Name);
|
||||
if (Ext==NULL)
|
||||
Ext=Name+NameLength;
|
||||
for (uint FileVer=1;;FileVer++)
|
||||
{
|
||||
swprintf(NewName,ASIZE(NewName),L"%.*ls(%u)%ls",uint(Ext-Name),Name,FileVer,Ext);
|
||||
if (!FileExist(NewName))
|
||||
{
|
||||
wcsncpyz(Name,NewName,MaxNameSize);
|
||||
break;
|
||||
}
|
||||
if (FileVer>=1000000)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#if defined(_WIN_ALL)
|
||||
// If we find a file, which short name is equal to 'Name', we try to change
|
||||
// its short name, while preserving the long name. It helps when unpacking
|
||||
// an archived file, which long name is equal to short name of already
|
||||
// existing file. Otherwise we would overwrite the already existing file,
|
||||
// even though its long name does not match the name of unpacking file.
|
||||
bool UpdateExistingShortName(const wchar *Name)
|
||||
bool UpdateExistingShortName(const std::wstring &Name)
|
||||
{
|
||||
wchar LongPathName[NM];
|
||||
DWORD Res=GetLongPathName(Name,LongPathName,ASIZE(LongPathName));
|
||||
if (Res==0 || Res>=ASIZE(LongPathName))
|
||||
DWORD Res=GetLongPathName(Name.c_str(),NULL,0);
|
||||
if (Res==0)
|
||||
return false;
|
||||
wchar ShortPathName[NM];
|
||||
Res=GetShortPathName(Name,ShortPathName,ASIZE(ShortPathName));
|
||||
if (Res==0 || Res>=ASIZE(ShortPathName))
|
||||
std::vector<wchar> LongPathBuf(Res);
|
||||
Res=GetLongPathName(Name.c_str(),LongPathBuf.data(),(DWORD)LongPathBuf.size());
|
||||
if (Res==0 || Res>=LongPathBuf.size())
|
||||
return false;
|
||||
wchar *LongName=PointToName(LongPathName);
|
||||
wchar *ShortName=PointToName(ShortPathName);
|
||||
Res=GetShortPathName(Name.c_str(),NULL,0);
|
||||
if (Res==0)
|
||||
return false;
|
||||
std::vector<wchar> ShortPathBuf(Res);
|
||||
Res=GetShortPathName(Name.c_str(),ShortPathBuf.data(),(DWORD)ShortPathBuf.size());
|
||||
if (Res==0 || Res>=ShortPathBuf.size())
|
||||
return false;
|
||||
std::wstring LongPathName=LongPathBuf.data();
|
||||
std::wstring ShortPathName=ShortPathBuf.data();
|
||||
|
||||
std::wstring LongName=PointToName(LongPathName);
|
||||
std::wstring ShortName=PointToName(ShortPathName);
|
||||
|
||||
// We continue only if file has a short name, which does not match its
|
||||
// long name, and this short name is equal to name of file which we need
|
||||
// to create.
|
||||
if (*ShortName==0 || wcsicomp(LongName,ShortName)==0 ||
|
||||
if (ShortName.empty() || wcsicomp(LongName,ShortName)==0 ||
|
||||
wcsicomp(PointToName(Name),ShortName)!=0)
|
||||
return false;
|
||||
|
||||
// Generate the temporary new name for existing file.
|
||||
wchar NewName[NM];
|
||||
*NewName=0;
|
||||
for (int I=0;I<10000 && *NewName==0;I+=123)
|
||||
std::wstring NewName;
|
||||
for (uint I=0;I<10000 && NewName.empty();I+=123)
|
||||
{
|
||||
// Here we copy the path part of file to create. We'll make the temporary
|
||||
// file in the same folder.
|
||||
wcsncpyz(NewName,Name,ASIZE(NewName));
|
||||
NewName=Name;
|
||||
|
||||
// Here we set the random name part.
|
||||
swprintf(PointToName(NewName),ASIZE(NewName),L"rtmp%d",I);
|
||||
SetName(NewName,std::wstring(L"rtmp") + std::to_wstring(I));
|
||||
|
||||
// If such file is already exist, try next random name.
|
||||
if (FileExist(NewName))
|
||||
*NewName=0;
|
||||
NewName.clear();
|
||||
}
|
||||
|
||||
// If we could not generate the name not used by any other file, we return.
|
||||
if (*NewName==0)
|
||||
if (NewName.empty())
|
||||
return false;
|
||||
|
||||
// FastFind returns the name without path, but we need the fully qualified
|
||||
// name for renaming, so we use the path from file to create and long name
|
||||
// from existing file.
|
||||
wchar FullName[NM];
|
||||
wcsncpyz(FullName,Name,ASIZE(FullName));
|
||||
SetName(FullName,LongName,ASIZE(FullName));
|
||||
std::wstring FullName=Name;
|
||||
SetName(FullName,LongName);
|
||||
|
||||
// Rename the existing file to randomly generated name. Normally it changes
|
||||
// the short name too.
|
||||
if (!MoveFile(FullName,NewName))
|
||||
if (!MoveFile(FullName.c_str(),NewName.c_str()))
|
||||
return false;
|
||||
|
||||
// Now we need to create the temporary empty file with same name as
|
||||
@@ -147,7 +134,7 @@ bool UpdateExistingShortName(const wchar *Name)
|
||||
// Now we rename the existing file from temporary name to original long name.
|
||||
// Since its previous short name is occupied by another file, it should
|
||||
// get another short name.
|
||||
MoveFile(NewName,FullName);
|
||||
MoveFile(NewName.c_str(),FullName.c_str());
|
||||
|
||||
if (Created)
|
||||
{
|
||||
@@ -155,9 +142,9 @@ bool UpdateExistingShortName(const wchar *Name)
|
||||
KeepShortFile.Close();
|
||||
KeepShortFile.Delete();
|
||||
}
|
||||
// We successfully changed the short name. Maybe sometimes we'll simplify
|
||||
// this function by use of SetFileShortName Windows API call.
|
||||
// But SetFileShortName is not available in older Windows.
|
||||
// We successfully changed the short name. We do not use the simpler
|
||||
// SetFileShortName Windows API call, because it requires SE_RESTORE_NAME
|
||||
// privilege.
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
#ifndef _RAR_FILECREATE_
|
||||
#define _RAR_FILECREATE_
|
||||
|
||||
bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
|
||||
bool FileCreate(CommandData *Cmd,File *NewFile,std::wstring &Name,
|
||||
bool *UserReject,int64 FileSize=INT64NDF,
|
||||
RarTime *FileTime=NULL,bool WriteOnly=false);
|
||||
|
||||
bool GetAutoRenamedName(wchar *Name,size_t MaxNameSize);
|
||||
|
||||
#if defined(_WIN_ALL)
|
||||
bool UpdateExistingShortName(const wchar *Name);
|
||||
bool UpdateExistingShortName(const std::wstring &Name);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
242
unrar/file.cpp
242
unrar/file.cpp
@@ -3,21 +3,22 @@
|
||||
File::File()
|
||||
{
|
||||
hFile=FILE_BAD_HANDLE;
|
||||
*FileName=0;
|
||||
NewFile=false;
|
||||
LastWrite=false;
|
||||
HandleType=FILE_HANDLENORMAL;
|
||||
LineInput=false;
|
||||
SkipClose=false;
|
||||
IgnoreReadErrors=false;
|
||||
ErrorType=FILE_SUCCESS;
|
||||
OpenShared=false;
|
||||
AllowDelete=true;
|
||||
AllowExceptions=true;
|
||||
PreserveAtime=false;
|
||||
#ifdef _WIN_ALL
|
||||
NoSequentialRead=false;
|
||||
CreateMode=FMF_UNDEFINED;
|
||||
// CreateMode=FMF_UNDEFINED;
|
||||
#endif
|
||||
ReadErrorMode=FREM_ASK;
|
||||
TruncatedAfterReadError=false;
|
||||
CurFilePos=0;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,12 +38,13 @@ void File::operator = (File &SrcFile)
|
||||
NewFile=SrcFile.NewFile;
|
||||
LastWrite=SrcFile.LastWrite;
|
||||
HandleType=SrcFile.HandleType;
|
||||
wcsncpyz(FileName,SrcFile.FileName,ASIZE(FileName));
|
||||
TruncatedAfterReadError=SrcFile.TruncatedAfterReadError;
|
||||
FileName=SrcFile.FileName;
|
||||
SrcFile.SkipClose=true;
|
||||
}
|
||||
|
||||
|
||||
bool File::Open(const wchar *Name,uint Mode)
|
||||
bool File::Open(const std::wstring &Name,uint Mode)
|
||||
{
|
||||
ErrorType=FILE_SUCCESS;
|
||||
FileHandle hNewFile;
|
||||
@@ -56,21 +58,21 @@ 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.
|
||||
hNewFile=CreateFile(Name,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
|
||||
hNewFile=CreateFile(Name.c_str(),Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
|
||||
|
||||
DWORD LastError;
|
||||
if (hNewFile==FILE_BAD_HANDLE)
|
||||
{
|
||||
LastError=GetLastError();
|
||||
|
||||
wchar LongName[NM];
|
||||
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
|
||||
std::wstring LongName;
|
||||
if (GetWinLongPath(Name,LongName))
|
||||
{
|
||||
hNewFile=CreateFile(LongName,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
|
||||
hNewFile=CreateFile(LongName.c_str(),Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
|
||||
|
||||
// For archive names longer than 260 characters first CreateFile
|
||||
// (without \\?\) fails and sets LastError to 3 (access denied).
|
||||
@@ -98,6 +100,12 @@ bool File::Open(const wchar *Name,uint Mode)
|
||||
|
||||
#else
|
||||
int flags=UpdateMode ? O_RDWR:(WriteMode ? O_WRONLY:O_RDONLY);
|
||||
|
||||
// 2025.06.09: We can't just set O_DIRECT for Unix like we set
|
||||
// FILE_FLAG_SEQUENTIAL_SCAN for Windows to minimize disk caching.
|
||||
// O_DIRECT might impose alignment requirements for data size, data address
|
||||
// and file offset. Also it might not be supported by some file systems
|
||||
// and fail with an error.
|
||||
#ifdef O_BINARY
|
||||
flags|=O_BINARY;
|
||||
#if defined(_AIX) && defined(_LARGE_FILE_API)
|
||||
@@ -109,21 +117,21 @@ bool File::Open(const wchar *Name,uint Mode)
|
||||
if (PreserveAtime)
|
||||
flags|=O_NOATIME;
|
||||
#endif
|
||||
char NameA[NM];
|
||||
WideToChar(Name,NameA,ASIZE(NameA));
|
||||
std::string NameA;
|
||||
WideToChar(Name,NameA);
|
||||
|
||||
int handle=open(NameA,flags);
|
||||
int handle=open(NameA.c_str(),flags);
|
||||
#ifdef LOCK_EX
|
||||
|
||||
#ifdef _OSF_SOURCE
|
||||
extern "C" int flock(int, int);
|
||||
#endif
|
||||
|
||||
if (!OpenShared && UpdateMode && handle>=0 && flock(handle,LOCK_EX|LOCK_NB)==-1)
|
||||
{
|
||||
close(handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
if (handle==-1)
|
||||
hNewFile=FILE_BAD_HANDLE;
|
||||
@@ -145,14 +153,15 @@ bool File::Open(const wchar *Name,uint Mode)
|
||||
if (Success)
|
||||
{
|
||||
hFile=hNewFile;
|
||||
wcsncpyz(FileName,Name,ASIZE(FileName));
|
||||
FileName=Name;
|
||||
TruncatedAfterReadError=false;
|
||||
}
|
||||
return Success;
|
||||
}
|
||||
|
||||
|
||||
#if !defined(SFX_MODULE)
|
||||
void File::TOpen(const wchar *Name)
|
||||
void File::TOpen(const std::wstring &Name)
|
||||
{
|
||||
if (!WOpen(Name))
|
||||
ErrHandler.Exit(RARX_OPEN);
|
||||
@@ -160,7 +169,7 @@ void File::TOpen(const wchar *Name)
|
||||
#endif
|
||||
|
||||
|
||||
bool File::WOpen(const wchar *Name)
|
||||
bool File::WOpen(const std::wstring &Name)
|
||||
{
|
||||
if (Open(Name))
|
||||
return true;
|
||||
@@ -169,8 +178,9 @@ bool File::WOpen(const wchar *Name)
|
||||
}
|
||||
|
||||
|
||||
bool File::Create(const wchar *Name,uint Mode)
|
||||
bool File::Create(const std::wstring &Name,uint Mode)
|
||||
{
|
||||
// 2025.09.03: Likely outdated info, see https://www.illumos.org/issues/2000
|
||||
// OpenIndiana based NAS and CIFS shares fail to set the file time if file
|
||||
// was created in read+write mode and some data was written and not flushed
|
||||
// before SetFileTime call. So we should use the write only mode if we plan
|
||||
@@ -178,46 +188,46 @@ bool File::Create(const wchar *Name,uint Mode)
|
||||
bool WriteMode=(Mode & FMF_WRITE)!=0;
|
||||
bool ShareRead=(Mode & FMF_SHAREREAD)!=0 || File::OpenShared;
|
||||
#ifdef _WIN_ALL
|
||||
CreateMode=Mode;
|
||||
// CreateMode=Mode;
|
||||
uint Access=WriteMode ? GENERIC_WRITE:GENERIC_READ|GENERIC_WRITE;
|
||||
DWORD ShareMode=ShareRead ? FILE_SHARE_READ:0;
|
||||
|
||||
// Windows automatically removes dots and spaces in the end of file name,
|
||||
// So we detect such names and process them with \\?\ prefix.
|
||||
wchar *LastChar=PointToLastChar(Name);
|
||||
bool Special=*LastChar=='.' || *LastChar==' ';
|
||||
wchar LastChar=GetLastChar(Name);
|
||||
bool Special=LastChar=='.' || LastChar==' ';
|
||||
|
||||
if (Special && (Mode & FMF_STANDARDNAMES)==0)
|
||||
hFile=FILE_BAD_HANDLE;
|
||||
else
|
||||
hFile=CreateFile(Name,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
|
||||
hFile=CreateFile(Name.c_str(),Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
|
||||
|
||||
if (hFile==FILE_BAD_HANDLE)
|
||||
{
|
||||
wchar LongName[NM];
|
||||
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
|
||||
hFile=CreateFile(LongName,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
|
||||
std::wstring LongName;
|
||||
if (GetWinLongPath(Name,LongName))
|
||||
hFile=CreateFile(LongName.c_str(),Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
|
||||
}
|
||||
|
||||
#else
|
||||
char NameA[NM];
|
||||
WideToChar(Name,NameA,ASIZE(NameA));
|
||||
#ifdef FILE_USE_OPEN
|
||||
hFile=open(NameA,(O_CREAT|O_TRUNC) | (WriteMode ? O_WRONLY : O_RDWR),0666);
|
||||
std::string NameA;
|
||||
WideToChar(Name,NameA);
|
||||
hFile=open(NameA.c_str(),(O_CREAT|O_TRUNC) | (WriteMode ? O_WRONLY : O_RDWR),0666);
|
||||
#else
|
||||
hFile=fopen(NameA,WriteMode ? WRITEBINARY:CREATEBINARY);
|
||||
hFile=fopen(NameA.c_str(),WriteMode ? WRITEBINARY:CREATEBINARY);
|
||||
#endif
|
||||
#endif
|
||||
NewFile=true;
|
||||
HandleType=FILE_HANDLENORMAL;
|
||||
SkipClose=false;
|
||||
wcsncpyz(FileName,Name,ASIZE(FileName));
|
||||
FileName=Name;
|
||||
return hFile!=FILE_BAD_HANDLE;
|
||||
}
|
||||
|
||||
|
||||
#if !defined(SFX_MODULE)
|
||||
void File::TCreate(const wchar *Name,uint Mode)
|
||||
void File::TCreate(const std::wstring &Name,uint Mode)
|
||||
{
|
||||
if (!WCreate(Name,Mode))
|
||||
ErrHandler.Exit(RARX_FATAL);
|
||||
@@ -225,7 +235,7 @@ void File::TCreate(const wchar *Name,uint Mode)
|
||||
#endif
|
||||
|
||||
|
||||
bool File::WCreate(const wchar *Name,uint Mode)
|
||||
bool File::WCreate(const std::wstring &Name,uint Mode)
|
||||
{
|
||||
if (Create(Name,Mode))
|
||||
return true;
|
||||
@@ -246,7 +256,7 @@ bool File::Close()
|
||||
// We use the standard system handle for stdout in Windows
|
||||
// and it must not be closed here.
|
||||
if (HandleType==FILE_HANDLENORMAL)
|
||||
Success=CloseHandle(hFile)==TRUE;
|
||||
Success=CloseHandle(hFile)!=FALSE;
|
||||
#else
|
||||
#ifdef FILE_USE_OPEN
|
||||
Success=close(hFile)!=-1;
|
||||
@@ -276,16 +286,16 @@ bool File::Delete()
|
||||
}
|
||||
|
||||
|
||||
bool File::Rename(const wchar *NewName)
|
||||
bool File::Rename(const std::wstring &NewName)
|
||||
{
|
||||
// No need to rename if names are already same.
|
||||
bool Success=wcscmp(FileName,NewName)==0;
|
||||
bool Success=(NewName==FileName);
|
||||
|
||||
if (!Success)
|
||||
Success=RenameFile(FileName,NewName);
|
||||
|
||||
if (Success)
|
||||
wcsncpyz(FileName,NewName,ASIZE(FileName));
|
||||
FileName=NewName;
|
||||
|
||||
return Success;
|
||||
}
|
||||
@@ -323,13 +333,13 @@ bool File::Write(const void *Data,size_t Size)
|
||||
const size_t MaxSize=0x4000;
|
||||
for (size_t I=0;I<Size;I+=MaxSize)
|
||||
{
|
||||
Success=WriteFile(hFile,(byte *)Data+I,(DWORD)Min(Size-I,MaxSize),&Written,NULL)==TRUE;
|
||||
Success=WriteFile(hFile,(byte *)Data+I,(DWORD)Min(Size-I,MaxSize),&Written,NULL)!=FALSE;
|
||||
if (!Success)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
Success=WriteFile(hFile,Data,(DWORD)Size,&Written,NULL)==TRUE;
|
||||
Success=WriteFile(hFile,Data,(DWORD)Size,&Written,NULL)!=FALSE;
|
||||
#else
|
||||
#ifdef FILE_USE_OPEN
|
||||
ssize_t Written=write(hFile,Data,Size);
|
||||
@@ -358,7 +368,7 @@ bool File::Write(const void *Data,size_t Size)
|
||||
Seek(Tell()-Written,SEEK_SET);
|
||||
continue;
|
||||
}
|
||||
ErrHandler.WriteError(NULL,FileName);
|
||||
ErrHandler.WriteError(L"",FileName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -369,19 +379,23 @@ bool File::Write(const void *Data,size_t Size)
|
||||
|
||||
int File::Read(void *Data,size_t Size)
|
||||
{
|
||||
if (TruncatedAfterReadError)
|
||||
return 0;
|
||||
|
||||
int64 FilePos=0; // Initialized only to suppress some compilers warning.
|
||||
|
||||
if (IgnoreReadErrors)
|
||||
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;
|
||||
if (AllowExceptions)
|
||||
if (IgnoreReadErrors)
|
||||
if (ReadErrorMode==FREM_IGNORE)
|
||||
{
|
||||
ReadSize=0;
|
||||
for (size_t I=0;I<Size;I+=512)
|
||||
@@ -390,18 +404,49 @@ 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
|
||||
{
|
||||
if (HandleType==FILE_HANDLENORMAL && ErrHandler.AskRepeatRead(FileName))
|
||||
continue;
|
||||
bool Ignore=false,Retry=false,Quit=false;
|
||||
if (ReadErrorMode==FREM_ASK && HandleType==FILE_HANDLENORMAL && IsOpened())
|
||||
{
|
||||
ErrHandler.AskRepeatRead(FileName,Ignore,Retry,Quit);
|
||||
if (Retry)
|
||||
continue;
|
||||
}
|
||||
if (Ignore || ReadErrorMode==FREM_TRUNCATE)
|
||||
{
|
||||
TruncatedAfterReadError=true;
|
||||
return 0;
|
||||
}
|
||||
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.
|
||||
}
|
||||
|
||||
|
||||
@@ -483,6 +528,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;
|
||||
@@ -517,6 +592,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);
|
||||
@@ -575,7 +652,7 @@ void File::PutByte(byte Byte)
|
||||
bool File::Truncate()
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
return SetEndOfFile(hFile)==TRUE;
|
||||
return SetEndOfFile(hFile)!=FALSE;
|
||||
#else
|
||||
return ftruncate(GetFD(),(off_t)Tell())==0;
|
||||
#endif
|
||||
@@ -601,8 +678,10 @@ void File::SetOpenFileTime(RarTime *ftm,RarTime *ftc,RarTime *fta)
|
||||
// Workaround for OpenIndiana NAS time bug. If we cannot create a file
|
||||
// in write only mode, we need to flush the write buffer before calling
|
||||
// SetFileTime or file time will not be changed.
|
||||
if (CreateMode!=FMF_UNDEFINED && (CreateMode & FMF_WRITE)==0)
|
||||
FlushFileBuffers(hFile);
|
||||
// 2025.09.03: Removed this code as likely redundant now,
|
||||
// see https://www.illumos.org/issues/2000
|
||||
// if (CreateMode!=FMF_UNDEFINED && (CreateMode & FMF_WRITE)==0)
|
||||
// FlushFileBuffers(hFile);
|
||||
|
||||
bool sm=ftm!=NULL && ftm->IsSet();
|
||||
bool sc=ftc!=NULL && ftc->IsSet();
|
||||
@@ -633,15 +712,15 @@ void File::SetCloseFileTime(RarTime *ftm,RarTime *fta)
|
||||
}
|
||||
|
||||
|
||||
void File::SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta)
|
||||
void File::SetCloseFileTimeByName(const std::wstring &Name,RarTime *ftm,RarTime *fta)
|
||||
{
|
||||
#ifdef _UNIX
|
||||
bool setm=ftm!=NULL && ftm->IsSet();
|
||||
bool seta=fta!=NULL && fta->IsSet();
|
||||
if (setm || seta)
|
||||
{
|
||||
char NameA[NM];
|
||||
WideToChar(Name,NameA,ASIZE(NameA));
|
||||
std::string NameA;
|
||||
WideToChar(Name,NameA);
|
||||
|
||||
#ifdef UNIX_TIME_NS
|
||||
timespec times[2];
|
||||
@@ -649,7 +728,7 @@ void File::SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta)
|
||||
times[0].tv_nsec=seta ? long(fta->GetUnixNS()%1000000000) : UTIME_NOW;
|
||||
times[1].tv_sec=setm ? ftm->GetUnix() : 0;
|
||||
times[1].tv_nsec=setm ? long(ftm->GetUnixNS()%1000000000) : UTIME_NOW;
|
||||
utimensat(AT_FDCWD,NameA,times,0);
|
||||
utimensat(AT_FDCWD,NameA.c_str(),times,0);
|
||||
#else
|
||||
utimbuf ut;
|
||||
if (setm)
|
||||
@@ -660,24 +739,47 @@ void File::SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta)
|
||||
ut.actime=fta->GetUnix();
|
||||
else
|
||||
ut.actime=ut.modtime; // Need to set something, cannot left it 0.
|
||||
utime(NameA,&ut);
|
||||
utime(NameA.c_str(),&ut);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -708,15 +810,23 @@ bool File::IsDevice()
|
||||
#ifndef SFX_MODULE
|
||||
int64 File::Copy(File &Dest,int64 Length)
|
||||
{
|
||||
Array<byte> Buffer(File::CopyBufferSize());
|
||||
int64 CopySize=0;
|
||||
bool CopyAll=(Length==INT64NDF);
|
||||
|
||||
// Adjust the buffer size to data size. So we do not waste too much time
|
||||
// to vector initialization when copying many small data blocks like
|
||||
// when updating an archive with many small files.
|
||||
size_t BufSize=File::CopyBufferSize();
|
||||
if (!CopyAll && Length<(int64)BufSize)
|
||||
BufSize=(size_t)Length;
|
||||
|
||||
std::vector<byte> Buffer(BufSize);
|
||||
int64 CopySize=0;
|
||||
|
||||
while (CopyAll || Length>0)
|
||||
{
|
||||
Wait();
|
||||
size_t SizeToRead=(!CopyAll && Length<(int64)Buffer.Size()) ? (size_t)Length:Buffer.Size();
|
||||
byte *Buf=&Buffer[0];
|
||||
size_t SizeToRead=(!CopyAll && Length<(int64)Buffer.size()) ? (size_t)Length:Buffer.size();
|
||||
byte *Buf=Buffer.data();
|
||||
int ReadSize=Read(Buf,SizeToRead);
|
||||
if (ReadSize==0)
|
||||
break;
|
||||
|
||||
@@ -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};
|
||||
@@ -43,7 +41,13 @@ enum FILE_MODE_FLAGS {
|
||||
FMF_STANDARDNAMES=32,
|
||||
|
||||
// Mode flags are not defined yet.
|
||||
FMF_UNDEFINED=256
|
||||
// FMF_UNDEFINED=256
|
||||
};
|
||||
|
||||
enum FILE_READ_ERROR_MODE {
|
||||
FREM_ASK, // Propose to use the already read part, retry or abort.
|
||||
FREM_TRUNCATE, // Use the already read part without additional prompt.
|
||||
FREM_IGNORE // Try to skip unreadable block and read further.
|
||||
};
|
||||
|
||||
|
||||
@@ -53,20 +57,32 @@ 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;
|
||||
bool IgnoreReadErrors;
|
||||
FILE_READ_ERROR_MODE ReadErrorMode;
|
||||
bool NewFile;
|
||||
bool AllowDelete;
|
||||
bool AllowExceptions;
|
||||
#ifdef _WIN_ALL
|
||||
bool NoSequentialRead;
|
||||
uint CreateMode;
|
||||
// uint CreateMode;
|
||||
#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];
|
||||
std::wstring FileName;
|
||||
|
||||
FILE_ERRORTYPE ErrorType;
|
||||
public:
|
||||
@@ -76,15 +92,15 @@ class File
|
||||
|
||||
// Several functions below are 'virtual', because they are redefined
|
||||
// by Archive for QOpen and by MultiFile for split files in WinRAR.
|
||||
virtual bool Open(const wchar *Name,uint Mode=FMF_READ);
|
||||
void TOpen(const wchar *Name);
|
||||
bool WOpen(const wchar *Name);
|
||||
bool Create(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
|
||||
void TCreate(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
|
||||
bool WCreate(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
|
||||
virtual bool Open(const std::wstring &Name,uint Mode=FMF_READ);
|
||||
void TOpen(const std::wstring &Name);
|
||||
bool WOpen(const std::wstring &Name);
|
||||
bool Create(const std::wstring &Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
|
||||
void TCreate(const std::wstring &Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
|
||||
bool WCreate(const std::wstring &Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
|
||||
virtual bool Close(); // 'virtual' for MultiFile class.
|
||||
bool Delete();
|
||||
bool Rename(const wchar *NewName);
|
||||
bool Rename(const std::wstring &NewName);
|
||||
bool Write(const void *Data,size_t Size);
|
||||
virtual int Read(void *Data,size_t Size);
|
||||
int DirectRead(void *Data,size_t Size);
|
||||
@@ -98,24 +114,27 @@ class File
|
||||
void Flush();
|
||||
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);
|
||||
static void SetCloseFileTimeByName(const std::wstring &Name,RarTime *ftm,RarTime *fta);
|
||||
#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();
|
||||
virtual int64 FileLength(); // 'virtual' for MultiFile class.
|
||||
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;}
|
||||
void SetHandle(FileHandle Handle) {Close();hFile=Handle;}
|
||||
void SetIgnoreReadErrors(bool Mode) {IgnoreReadErrors=Mode;}
|
||||
void SetReadErrorMode(FILE_READ_ERROR_MODE Mode) {ReadErrorMode=Mode;}
|
||||
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
|
||||
int GetFD()
|
||||
{
|
||||
@@ -128,14 +147,9 @@ class File
|
||||
#endif
|
||||
static size_t CopyBufferSize()
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
// USB flash performance is poor with 64 KB buffer, 256+ KB resolved it.
|
||||
// For copying from HDD to same HDD the best performance was with 256 KB
|
||||
// buffer in XP and with 1 MB buffer in Win10.
|
||||
return WinNT()==WNT_WXP ? 0x40000:0x100000;
|
||||
#else
|
||||
return 0x100000;
|
||||
#endif
|
||||
// Values in 0x100000 - 0x400000 range are ok, but multithreaded CRC32
|
||||
// seems to benefit from 0x400000, especially on ARM CPUs.
|
||||
return 0x400000;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
368
unrar/filefn.cpp
368
unrar/filefn.cpp
@@ -1,18 +1,18 @@
|
||||
#include "rar.hpp"
|
||||
|
||||
MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr)
|
||||
MKDIR_CODE MakeDir(const std::wstring &Name,bool SetAttr,uint Attr)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
// Windows automatically removes dots and spaces in the end of directory
|
||||
// name. So we detect such names and process them with \\?\ prefix.
|
||||
wchar *LastChar=PointToLastChar(Name);
|
||||
bool Special=*LastChar=='.' || *LastChar==' ';
|
||||
BOOL RetCode=Special ? FALSE : CreateDirectory(Name,NULL);
|
||||
wchar LastChar=GetLastChar(Name);
|
||||
bool Special=LastChar=='.' || LastChar==' ';
|
||||
BOOL RetCode=Special ? FALSE : CreateDirectory(Name.c_str(),NULL);
|
||||
if (RetCode==0 && !FileExist(Name))
|
||||
{
|
||||
wchar LongName[NM];
|
||||
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
|
||||
RetCode=CreateDirectory(LongName,NULL);
|
||||
std::wstring LongName;
|
||||
if (GetWinLongPath(Name,LongName))
|
||||
RetCode=CreateDirectory(LongName.c_str(),NULL);
|
||||
}
|
||||
if (RetCode!=0) // Non-zero return code means success for CreateDirectory.
|
||||
{
|
||||
@@ -25,10 +25,10 @@ MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr)
|
||||
return MKDIR_BADPATH;
|
||||
return MKDIR_ERROR;
|
||||
#elif defined(_UNIX)
|
||||
char NameA[NM];
|
||||
WideToChar(Name,NameA,ASIZE(NameA));
|
||||
std::string NameA;
|
||||
WideToChar(Name,NameA);
|
||||
mode_t uattr=SetAttr ? (mode_t)Attr:0777;
|
||||
int ErrCode=mkdir(NameA,uattr);
|
||||
int ErrCode=mkdir(NameA.c_str(),uattr);
|
||||
if (ErrCode==-1)
|
||||
return errno==ENOENT ? MKDIR_BADPATH:MKDIR_ERROR;
|
||||
return MKDIR_SUCCESS;
|
||||
@@ -38,12 +38,19 @@ MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr)
|
||||
}
|
||||
|
||||
|
||||
bool CreatePath(const wchar *Path,bool SkipLastName)
|
||||
// Simplified version of MakeDir().
|
||||
bool CreateDir(const std::wstring &Name)
|
||||
{
|
||||
if (Path==NULL || *Path==0)
|
||||
return MakeDir(Name,false,0)==MKDIR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
bool CreatePath(const std::wstring &Path,bool SkipLastName,bool Silent)
|
||||
{
|
||||
if (Path.empty())
|
||||
return false;
|
||||
|
||||
#if defined(_WIN_ALL) || defined(_EMX)
|
||||
#ifdef _WIN_ALL
|
||||
uint DirAttr=0;
|
||||
#else
|
||||
uint DirAttr=0777;
|
||||
@@ -51,42 +58,36 @@ bool CreatePath(const wchar *Path,bool SkipLastName)
|
||||
|
||||
bool Success=true;
|
||||
|
||||
for (const wchar *s=Path;*s!=0;s++)
|
||||
for (size_t I=0;I<Path.size();I++)
|
||||
{
|
||||
wchar DirName[NM];
|
||||
if (s-Path>=ASIZE(DirName))
|
||||
break;
|
||||
|
||||
// Process all kinds of path separators, so user can enter Unix style
|
||||
// path in Windows or Windows in Unix. s>Path check avoids attempting
|
||||
// path in Windows or Windows in Unix. I>0 check avoids attempting
|
||||
// creating an empty directory for paths starting from path separator.
|
||||
if (IsPathDiv(*s) && s>Path)
|
||||
if (IsPathDiv(Path[I]) && I>0)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
// We must not attempt to create "D:" directory, because first
|
||||
// CreateDirectory will fail, so we'll use \\?\D:, which forces Wine
|
||||
// to create "D:" directory.
|
||||
if (s==Path+2 && Path[1]==':')
|
||||
if (I==2 && Path[1]==':')
|
||||
continue;
|
||||
#endif
|
||||
wcsncpy(DirName,Path,s-Path);
|
||||
DirName[s-Path]=0;
|
||||
|
||||
std::wstring DirName=Path.substr(0,I);
|
||||
Success=MakeDir(DirName,true,DirAttr)==MKDIR_SUCCESS;
|
||||
if (Success)
|
||||
if (Success && !Silent)
|
||||
{
|
||||
mprintf(St(MCreatDir),DirName);
|
||||
mprintf(St(MCreatDir),DirName.c_str());
|
||||
mprintf(L" %s",St(MOk));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!SkipLastName && !IsPathDiv(*PointToLastChar(Path)))
|
||||
if (!SkipLastName && !IsPathDiv(GetLastChar(Path)))
|
||||
Success=MakeDir(Path,true,DirAttr)==MKDIR_SUCCESS;
|
||||
return Success;
|
||||
}
|
||||
|
||||
|
||||
void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta)
|
||||
void SetDirTime(const std::wstring &Name,RarTime *ftm,RarTime *ftc,RarTime *fta)
|
||||
{
|
||||
#if defined(_WIN_ALL)
|
||||
bool sm=ftm!=NULL && ftm->IsSet();
|
||||
@@ -98,13 +99,13 @@ void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta)
|
||||
if (ResetAttr)
|
||||
SetFileAttr(Name,0);
|
||||
|
||||
HANDLE hFile=CreateFile(Name,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
|
||||
HANDLE hFile=CreateFile(Name.c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
|
||||
NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL);
|
||||
if (hFile==INVALID_HANDLE_VALUE)
|
||||
{
|
||||
wchar LongName[NM];
|
||||
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
|
||||
hFile=CreateFile(LongName,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
|
||||
std::wstring LongName;
|
||||
if (GetWinLongPath(Name,LongName))
|
||||
hFile=CreateFile(LongName.c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
|
||||
NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL);
|
||||
}
|
||||
|
||||
@@ -122,18 +123,20 @@ void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta)
|
||||
if (ResetAttr)
|
||||
SetFileAttr(Name,DirAttr);
|
||||
#endif
|
||||
#if defined(_UNIX) || defined(_EMX)
|
||||
#ifdef _UNIX
|
||||
File::SetCloseFileTimeByName(Name,ftm,fta);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool IsRemovable(const wchar *Name)
|
||||
|
||||
|
||||
bool IsRemovable(const std::wstring &Name)
|
||||
{
|
||||
#if defined(_WIN_ALL)
|
||||
wchar Root[NM];
|
||||
GetPathRoot(Name,Root,ASIZE(Root));
|
||||
int Type=GetDriveType(*Root!=0 ? Root:NULL);
|
||||
std::wstring Root;
|
||||
GetPathRoot(Name,Root);
|
||||
int Type=GetDriveType(Root.empty() ? nullptr : Root.c_str());
|
||||
return Type==DRIVE_REMOVABLE || Type==DRIVE_CDROM;
|
||||
#else
|
||||
return false;
|
||||
@@ -142,25 +145,25 @@ bool IsRemovable(const wchar *Name)
|
||||
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
int64 GetFreeDisk(const wchar *Name)
|
||||
int64 GetFreeDisk(const std::wstring &Name)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
wchar Root[NM];
|
||||
GetFilePath(Name,Root,ASIZE(Root));
|
||||
std::wstring Root;
|
||||
GetPathWithSep(Name,Root);
|
||||
|
||||
ULARGE_INTEGER uiTotalSize,uiTotalFree,uiUserFree;
|
||||
uiUserFree.u.LowPart=uiUserFree.u.HighPart=0;
|
||||
if (GetDiskFreeSpaceEx(*Root!=0 ? Root:NULL,&uiUserFree,&uiTotalSize,&uiTotalFree) &&
|
||||
if (GetDiskFreeSpaceEx(Root.empty() ? NULL:Root.c_str(),&uiUserFree,&uiTotalSize,&uiTotalFree) &&
|
||||
uiUserFree.u.HighPart<=uiTotalFree.u.HighPart)
|
||||
return INT32TO64(uiUserFree.u.HighPart,uiUserFree.u.LowPart);
|
||||
return 0;
|
||||
#elif defined(_UNIX)
|
||||
wchar Root[NM];
|
||||
GetFilePath(Name,Root,ASIZE(Root));
|
||||
char RootA[NM];
|
||||
WideToChar(Root,RootA,ASIZE(RootA));
|
||||
std::wstring Root;
|
||||
GetPathWithSep(Name,Root);
|
||||
std::string RootA;
|
||||
WideToChar(Root,RootA);
|
||||
struct statvfs sfs;
|
||||
if (statvfs(*RootA!=0 ? RootA:".",&sfs)!=0)
|
||||
if (statvfs(RootA.empty() ? ".":RootA.c_str(),&sfs)!=0)
|
||||
return 0;
|
||||
int64 FreeSize=sfs.f_bsize;
|
||||
FreeSize=FreeSize*sfs.f_bavail;
|
||||
@@ -175,26 +178,27 @@ int64 GetFreeDisk(const wchar *Name)
|
||||
#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT)
|
||||
// Return 'true' for FAT and FAT32, so we can adjust the maximum supported
|
||||
// file size to 4 GB for these file systems.
|
||||
bool IsFAT(const wchar *Name)
|
||||
bool IsFAT(const std::wstring &Name)
|
||||
{
|
||||
wchar Root[NM];
|
||||
GetPathRoot(Name,Root,ASIZE(Root));
|
||||
std::wstring Root;
|
||||
GetPathRoot(Name,Root);
|
||||
wchar FileSystem[MAX_PATH+1];
|
||||
if (GetVolumeInformation(Root,NULL,0,NULL,NULL,NULL,FileSystem,ASIZE(FileSystem)))
|
||||
// Root can be empty, when we create volumes with -v in the current folder.
|
||||
if (GetVolumeInformation(Root.empty() ? NULL:Root.c_str(),NULL,0,NULL,NULL,NULL,FileSystem,ASIZE(FileSystem)))
|
||||
return wcscmp(FileSystem,L"FAT")==0 || wcscmp(FileSystem,L"FAT32")==0;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool FileExist(const wchar *Name)
|
||||
bool FileExist(const std::wstring &Name)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
return GetFileAttr(Name)!=0xffffffff;
|
||||
#elif defined(ENABLE_ACCESS)
|
||||
char NameA[NM];
|
||||
WideToChar(Name,NameA,ASIZE(NameA));
|
||||
return access(NameA,0)==0;
|
||||
std::string NameA;
|
||||
WideToChar(Name,NameA);
|
||||
return access(NameA.c_str(),0)==0;
|
||||
#else
|
||||
FindData FD;
|
||||
return FindFile::FastFind(Name,&FD);
|
||||
@@ -202,7 +206,7 @@ bool FileExist(const wchar *Name)
|
||||
}
|
||||
|
||||
|
||||
bool WildFileExist(const wchar *Name)
|
||||
bool WildFileExist(const std::wstring &Name)
|
||||
{
|
||||
if (IsWildcard(Name))
|
||||
{
|
||||
@@ -230,8 +234,9 @@ bool IsUnreadable(uint Attr)
|
||||
{
|
||||
#if defined(_UNIX) && defined(S_ISFIFO) && defined(S_ISSOCK) && defined(S_ISCHR)
|
||||
return S_ISFIFO(Attr) || S_ISSOCK(Attr) || S_ISCHR(Attr);
|
||||
#endif
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -261,70 +266,66 @@ bool IsDeleteAllowed(uint FileAttr)
|
||||
}
|
||||
|
||||
|
||||
void PrepareToDelete(const wchar *Name)
|
||||
void PrepareToDelete(const std::wstring &Name)
|
||||
{
|
||||
#if defined(_WIN_ALL) || defined(_EMX)
|
||||
#ifdef _WIN_ALL
|
||||
SetFileAttr(Name,0);
|
||||
#endif
|
||||
#ifdef _UNIX
|
||||
if (Name!=NULL)
|
||||
{
|
||||
char NameA[NM];
|
||||
WideToChar(Name,NameA,ASIZE(NameA));
|
||||
chmod(NameA,S_IRUSR|S_IWUSR|S_IXUSR);
|
||||
}
|
||||
std::string NameA;
|
||||
WideToChar(Name,NameA);
|
||||
chmod(NameA.c_str(),S_IRUSR|S_IWUSR|S_IXUSR);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
uint GetFileAttr(const wchar *Name)
|
||||
uint GetFileAttr(const std::wstring &Name)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
DWORD Attr=GetFileAttributes(Name);
|
||||
DWORD Attr=GetFileAttributes(Name.c_str());
|
||||
if (Attr==0xffffffff)
|
||||
{
|
||||
wchar LongName[NM];
|
||||
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
|
||||
Attr=GetFileAttributes(LongName);
|
||||
std::wstring LongName;
|
||||
if (GetWinLongPath(Name,LongName))
|
||||
Attr=GetFileAttributes(LongName.c_str());
|
||||
}
|
||||
return Attr;
|
||||
#else
|
||||
char NameA[NM];
|
||||
WideToChar(Name,NameA,ASIZE(NameA));
|
||||
std::string NameA;
|
||||
WideToChar(Name,NameA);
|
||||
struct stat st;
|
||||
if (stat(NameA,&st)!=0)
|
||||
if (stat(NameA.c_str(),&st)!=0)
|
||||
return 0;
|
||||
return st.st_mode;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool SetFileAttr(const wchar *Name,uint Attr)
|
||||
bool SetFileAttr(const std::wstring &Name,uint Attr)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
bool Success=SetFileAttributes(Name,Attr)!=0;
|
||||
bool Success=SetFileAttributes(Name.c_str(),Attr)!=0;
|
||||
if (!Success)
|
||||
{
|
||||
wchar LongName[NM];
|
||||
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
|
||||
Success=SetFileAttributes(LongName,Attr)!=0;
|
||||
std::wstring LongName;
|
||||
if (GetWinLongPath(Name,LongName))
|
||||
Success=SetFileAttributes(LongName.c_str(),Attr)!=0;
|
||||
}
|
||||
return Success;
|
||||
#elif defined(_UNIX)
|
||||
char NameA[NM];
|
||||
WideToChar(Name,NameA,ASIZE(NameA));
|
||||
return chmod(NameA,(mode_t)Attr)==0;
|
||||
std::string NameA;
|
||||
WideToChar(Name,NameA);
|
||||
return chmod(NameA.c_str(),(mode_t)Attr)==0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
wchar *MkTemp(wchar *Name,size_t MaxSize)
|
||||
// Ext is the extension with the leading dot, like L".bat", or nullptr to use
|
||||
// the default extension.
|
||||
bool MkTemp(std::wstring &Name,const wchar *Ext)
|
||||
{
|
||||
size_t Length=wcslen(Name);
|
||||
|
||||
RarTime CurTime;
|
||||
CurTime.SetCurrentTime();
|
||||
|
||||
@@ -343,18 +344,28 @@ wchar *MkTemp(wchar *Name,size_t MaxSize)
|
||||
|
||||
for (uint Attempt=0;;Attempt++)
|
||||
{
|
||||
uint Ext=Random%50000+Attempt;
|
||||
wchar RndText[50];
|
||||
swprintf(RndText,ASIZE(RndText),L"%u.%03u",PID,Ext);
|
||||
if (Length+wcslen(RndText)>=MaxSize || Attempt==1000)
|
||||
return NULL;
|
||||
wcsncpyz(Name+Length,RndText,MaxSize-Length);
|
||||
if (!FileExist(Name))
|
||||
uint RandomExt=Random%50000+Attempt;
|
||||
if (Attempt==1000)
|
||||
return false;
|
||||
|
||||
// User asked to specify the single extension for all temporary files,
|
||||
// so it can be added to server ransomware protection exceptions.
|
||||
// He wrote, this protection blocks temporary files when adding
|
||||
// a file to RAR archive with drag and drop. So unless a calling code
|
||||
// requires a specific extension, like .bat file when uninstalling,
|
||||
// we set the uniform extension here.
|
||||
if (Ext==nullptr)
|
||||
Ext=L".rartemp";
|
||||
|
||||
std::wstring NewName=Name + std::to_wstring(PID) + L"." + std::to_wstring(RandomExt) + Ext;
|
||||
if (!FileExist(NewName))
|
||||
{
|
||||
Name=NewName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Name;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(SFX_MODULE)
|
||||
@@ -372,8 +383,7 @@ void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,
|
||||
SrcFile->Seek(0,SEEK_SET);
|
||||
|
||||
const size_t BufSize=0x100000;
|
||||
Array<byte> Data(BufSize);
|
||||
|
||||
std::vector<byte> Data(BufSize);
|
||||
|
||||
DataHash HashCRC,HashBlake2;
|
||||
HashCRC.Init(HASH_CRC32,Threads);
|
||||
@@ -388,7 +398,7 @@ void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,
|
||||
SizeToRead=BufSize; // Then always attempt to read the entire buffer.
|
||||
else
|
||||
SizeToRead=(size_t)Min((int64)BufSize,Size);
|
||||
int ReadSize=SrcFile->Read(&Data[0],SizeToRead);
|
||||
int ReadSize=SrcFile->Read(Data.data(),SizeToRead);
|
||||
if (ReadSize==0)
|
||||
break;
|
||||
TotalRead+=ReadSize;
|
||||
@@ -397,7 +407,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)
|
||||
@@ -408,9 +422,9 @@ void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,
|
||||
}
|
||||
|
||||
if (CRC32!=NULL)
|
||||
HashCRC.Update(&Data[0],ReadSize);
|
||||
HashCRC.Update(Data.data(),ReadSize);
|
||||
if (Blake2!=NULL)
|
||||
HashBlake2.Update(&Data[0],ReadSize);
|
||||
HashBlake2.Update(Data.data(),ReadSize);
|
||||
|
||||
if (Size!=INT64NDF)
|
||||
Size-=ReadSize;
|
||||
@@ -432,73 +446,109 @@ void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,
|
||||
#endif
|
||||
|
||||
|
||||
bool RenameFile(const wchar *SrcName,const wchar *DestName)
|
||||
bool RenameFile(const std::wstring &SrcName,const std::wstring &DestName)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
bool Success=MoveFile(SrcName,DestName)!=0;
|
||||
bool Success=MoveFile(SrcName.c_str(),DestName.c_str())!=0;
|
||||
if (!Success)
|
||||
{
|
||||
wchar LongName1[NM],LongName2[NM];
|
||||
if (GetWinLongPath(SrcName,LongName1,ASIZE(LongName1)) &&
|
||||
GetWinLongPath(DestName,LongName2,ASIZE(LongName2)))
|
||||
Success=MoveFile(LongName1,LongName2)!=0;
|
||||
std::wstring LongName1,LongName2;
|
||||
if (GetWinLongPath(SrcName,LongName1) && GetWinLongPath(DestName,LongName2))
|
||||
Success=MoveFile(LongName1.c_str(),LongName2.c_str())!=0;
|
||||
}
|
||||
return Success;
|
||||
#else
|
||||
char SrcNameA[NM],DestNameA[NM];
|
||||
WideToChar(SrcName,SrcNameA,ASIZE(SrcNameA));
|
||||
WideToChar(DestName,DestNameA,ASIZE(DestNameA));
|
||||
bool Success=rename(SrcNameA,DestNameA)==0;
|
||||
std::string SrcNameA,DestNameA;
|
||||
WideToChar(SrcName,SrcNameA);
|
||||
WideToChar(DestName,DestNameA);
|
||||
bool Success=rename(SrcNameA.c_str(),DestNameA.c_str())==0;
|
||||
return Success;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool DelFile(const wchar *Name)
|
||||
bool DelFile(const std::wstring &Name)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
bool Success=DeleteFile(Name)!=0;
|
||||
bool Success=DeleteFile(Name.c_str())!=0;
|
||||
if (!Success)
|
||||
{
|
||||
wchar LongName[NM];
|
||||
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
|
||||
Success=DeleteFile(LongName)!=0;
|
||||
std::wstring LongName;
|
||||
if (GetWinLongPath(Name,LongName))
|
||||
Success=DeleteFile(LongName.c_str())!=0;
|
||||
}
|
||||
return Success;
|
||||
#else
|
||||
char NameA[NM];
|
||||
WideToChar(Name,NameA,ASIZE(NameA));
|
||||
bool Success=remove(NameA)==0;
|
||||
std::string NameA;
|
||||
WideToChar(Name,NameA);
|
||||
bool Success=remove(NameA.c_str())==0;
|
||||
return Success;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool DelDir(const std::wstring &Name)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
bool Success=RemoveDirectory(Name.c_str())!=0;
|
||||
if (!Success)
|
||||
{
|
||||
std::wstring LongName;
|
||||
if (GetWinLongPath(Name,LongName))
|
||||
Success=RemoveDirectory(LongName.c_str())!=0;
|
||||
}
|
||||
return Success;
|
||||
#else
|
||||
std::string NameA;
|
||||
WideToChar(Name,NameA);
|
||||
bool Success=rmdir(NameA.c_str())==0;
|
||||
return Success;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
|
||||
bool SetFileCompression(const wchar *Name,bool State)
|
||||
bool SetFileCompression(const std::wstring &Name,bool State)
|
||||
{
|
||||
HANDLE hFile=CreateFile(Name,FILE_READ_DATA|FILE_WRITE_DATA,
|
||||
HANDLE hFile=CreateFile(Name.c_str(),FILE_READ_DATA|FILE_WRITE_DATA,
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
|
||||
if (hFile==INVALID_HANDLE_VALUE)
|
||||
{
|
||||
wchar LongName[NM];
|
||||
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
|
||||
hFile=CreateFile(LongName,FILE_READ_DATA|FILE_WRITE_DATA,
|
||||
std::wstring LongName;
|
||||
if (GetWinLongPath(Name,LongName))
|
||||
hFile=CreateFile(LongName.c_str(),FILE_READ_DATA|FILE_WRITE_DATA,
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
|
||||
if (hFile==INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
}
|
||||
if (hFile==INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
bool Success=SetFileCompression(hFile,State);
|
||||
CloseHandle(hFile);
|
||||
return Success;
|
||||
}
|
||||
|
||||
|
||||
bool SetFileCompression(HANDLE hFile,bool State)
|
||||
{
|
||||
SHORT NewState=State ? COMPRESSION_FORMAT_DEFAULT:COMPRESSION_FORMAT_NONE;
|
||||
DWORD Result;
|
||||
int RetCode=DeviceIoControl(hFile,FSCTL_SET_COMPRESSION,&NewState,
|
||||
sizeof(NewState),NULL,0,&Result,NULL);
|
||||
CloseHandle(hFile);
|
||||
return RetCode!=0;
|
||||
}
|
||||
|
||||
|
||||
void ResetFileCache(const std::wstring &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.c_str(),GENERIC_READ,
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
||||
NULL,OPEN_EXISTING,FILE_FLAG_NO_BUFFERING,NULL);
|
||||
if (hSrc!=INVALID_HANDLE_VALUE)
|
||||
CloseHandle(hSrc);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -510,3 +560,71 @@ bool SetFileCompression(const wchar *Name,bool State)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 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 std::wstring &SrcName,const std::wstring &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
|
||||
std::wstring Path=SrcName;
|
||||
|
||||
size_t SkipLength=SkipPart.size();
|
||||
|
||||
if (SkipLength>0 && !starts_with(Path,SkipPart))
|
||||
SkipLength=0; // Parameter validation, not really needed now.
|
||||
|
||||
// Do not check parts already checked in previous path to improve performance.
|
||||
for (size_t I=0;I<Path.size() && I<LastChecked.size() && Path[I]==LastChecked[I];I++)
|
||||
if (IsPathDiv(Path[I]) && I>SkipLength)
|
||||
SkipLength=I;
|
||||
|
||||
// Avoid converting symlinks in destination path part specified by user.
|
||||
while (SkipLength<Path.size() && IsPathDiv(Path[SkipLength]))
|
||||
SkipLength++;
|
||||
|
||||
if (Path.size()>0)
|
||||
for (size_t I=Path.size()-1;I>SkipLength;I--)
|
||||
if (IsPathDiv(Path[I]))
|
||||
{
|
||||
Path.erase(I);
|
||||
FindData FD;
|
||||
if (FindFile::FastFind(Path,&FD,true) && FD.IsLink)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
// Normally Windows symlinks to directory look like a directory
|
||||
// and are deleted with DelDir(). It is possible to create
|
||||
// a file-like symlink pointing at directory, which can be deleted
|
||||
// only with && DelFile, but such symlink isn't really functional.
|
||||
// Here we prefer to fail deleting such symlink and skip extracting
|
||||
// a file.
|
||||
if (!DelDir(Path))
|
||||
#else
|
||||
if (!DelFile(Path))
|
||||
#endif
|
||||
{
|
||||
ErrHandler.CreateErrorMsg(SrcName); // Extraction command will skip this file or directory.
|
||||
return false; // Couldn't delete the symlink to replace it with directory.
|
||||
}
|
||||
}
|
||||
}
|
||||
LastChecked=SrcName;
|
||||
//#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3,48 +3,55 @@
|
||||
|
||||
enum MKDIR_CODE {MKDIR_SUCCESS,MKDIR_ERROR,MKDIR_BADPATH};
|
||||
|
||||
MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr);
|
||||
bool CreatePath(const wchar *Path,bool SkipLastName);
|
||||
void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta);
|
||||
bool IsRemovable(const wchar *Name);
|
||||
MKDIR_CODE MakeDir(const std::wstring &Name,bool SetAttr,uint Attr);
|
||||
bool CreateDir(const std::wstring &Name);
|
||||
bool CreatePath(const std::wstring &Path,bool SkipLastName,bool Silent);
|
||||
|
||||
void SetDirTime(const std::wstring &Name,RarTime *ftm,RarTime *ftc,RarTime *fta);
|
||||
|
||||
|
||||
bool IsRemovable(const std::wstring &Name);
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
int64 GetFreeDisk(const wchar *Name);
|
||||
int64 GetFreeDisk(const std::wstring &Name);
|
||||
#endif
|
||||
|
||||
#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT)
|
||||
bool IsFAT(const wchar *Root);
|
||||
bool IsFAT(const std::wstring &Root);
|
||||
#endif
|
||||
|
||||
bool FileExist(const wchar *Name);
|
||||
bool WildFileExist(const wchar *Name);
|
||||
bool FileExist(const std::wstring &Name);
|
||||
bool WildFileExist(const std::wstring &Name);
|
||||
bool IsDir(uint Attr);
|
||||
bool IsUnreadable(uint Attr);
|
||||
bool IsLink(uint Attr);
|
||||
void SetSFXMode(const wchar *FileName);
|
||||
void EraseDiskContents(const wchar *FileName);
|
||||
void SetSFXMode(const std::wstring &FileName);
|
||||
void EraseDiskContents(const std::wstring &FileName);
|
||||
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
|
||||
void PrepareToDelete(const std::wstring &Name);
|
||||
uint GetFileAttr(const std::wstring &Name);
|
||||
bool SetFileAttr(const std::wstring &Name,uint Attr);
|
||||
bool MkTemp(std::wstring &Name,const wchar *Ext);
|
||||
|
||||
enum CALCFSUM_FLAGS {CALCFSUM_SHOWTEXT=1,CALCFSUM_SHOWPERCENT=2,CALCFSUM_SHOWPROGRESS=4,CALCFSUM_CURPOS=8};
|
||||
|
||||
void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size=INT64NDF,uint Flags=0);
|
||||
|
||||
bool RenameFile(const wchar *SrcName,const wchar *DestName);
|
||||
bool DelFile(const wchar *Name);
|
||||
bool DelDir(const wchar *Name);
|
||||
bool RenameFile(const std::wstring &SrcName,const std::wstring &DestName);
|
||||
bool DelFile(const std::wstring &Name);
|
||||
bool DelDir(const std::wstring &Name);
|
||||
|
||||
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
|
||||
bool SetFileCompression(const wchar *Name,bool State);
|
||||
bool SetFileCompression(const std::wstring &Name,bool State);
|
||||
bool SetFileCompression(HANDLE hFile,bool State);
|
||||
void ResetFileCache(const std::wstring &Name);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Keep it here and not in extinfo.cpp, because it is invoked from Zip.SFX too.
|
||||
bool LinksToDirs(const std::wstring &SrcName,const std::wstring &SkipPart,std::wstring &LastChecked);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "rar.hpp"
|
||||
|
||||
bool ReadTextFile(
|
||||
const wchar *Name,
|
||||
const std::wstring &Name,
|
||||
StringList *List,
|
||||
bool Config,
|
||||
bool AbortOnError,
|
||||
@@ -10,17 +10,15 @@ bool ReadTextFile(
|
||||
bool SkipComments,
|
||||
bool ExpandEnvStr)
|
||||
{
|
||||
wchar FileName[NM];
|
||||
*FileName=0;
|
||||
std::wstring FileName;
|
||||
|
||||
if (Name!=NULL)
|
||||
if (Config)
|
||||
GetConfigName(Name,FileName,ASIZE(FileName),true,false);
|
||||
else
|
||||
wcsncpyz(FileName,Name,ASIZE(FileName));
|
||||
if (Config)
|
||||
GetConfigName(Name,FileName,true,false);
|
||||
else
|
||||
FileName=Name;
|
||||
|
||||
File SrcFile;
|
||||
if (*FileName!=0)
|
||||
if (!FileName.empty())
|
||||
{
|
||||
bool OpenCode=AbortOnError ? SrcFile.WOpen(FileName):SrcFile.Open(FileName,0);
|
||||
|
||||
@@ -34,36 +32,36 @@ bool ReadTextFile(
|
||||
else
|
||||
SrcFile.SetHandleType(FILE_HANDLESTD);
|
||||
|
||||
uint DataSize=0,ReadSize;
|
||||
size_t DataSize=0,ReadSize;
|
||||
const int ReadBlock=4096;
|
||||
|
||||
Array<byte> Data(ReadBlock);
|
||||
std::vector<byte> Data(ReadBlock);
|
||||
while ((ReadSize=SrcFile.Read(&Data[DataSize],ReadBlock))!=0)
|
||||
{
|
||||
DataSize+=ReadSize;
|
||||
Data.Add(ReadSize); // Always have ReadBlock available for next data.
|
||||
Data.resize(DataSize+ReadBlock); // Always have ReadBlock available for next data.
|
||||
}
|
||||
// Set to really read size, so we can zero terminate it correctly.
|
||||
Data.Alloc(DataSize);
|
||||
Data.resize(DataSize);
|
||||
|
||||
int LittleEndian=DataSize>=2 && Data[0]==255 && Data[1]==254 ? 1:0;
|
||||
int BigEndian=DataSize>=2 && Data[0]==254 && Data[1]==255 ? 1:0;
|
||||
bool Utf8=DataSize>=3 && Data[0]==0xef && Data[1]==0xbb && Data[2]==0xbf;
|
||||
|
||||
if (SrcCharset==RCH_DEFAULT)
|
||||
SrcCharset=DetectTextEncoding(&Data[0],DataSize);
|
||||
SrcCharset=DetectTextEncoding(Data.data(),DataSize);
|
||||
|
||||
Array<wchar> DataW;
|
||||
std::vector<wchar> DataW(ReadBlock);
|
||||
|
||||
if (SrcCharset==RCH_DEFAULT || SrcCharset==RCH_OEM || SrcCharset==RCH_ANSI)
|
||||
{
|
||||
Data.Push(0); // Zero terminate.
|
||||
Data.push_back(0); // Zero terminate.
|
||||
#if defined(_WIN_ALL)
|
||||
if (SrcCharset==RCH_OEM)
|
||||
OemToCharA((char *)&Data[0],(char *)&Data[0]);
|
||||
OemToCharA((char *)Data.data(),(char *)Data.data());
|
||||
#endif
|
||||
DataW.Alloc(Data.Size());
|
||||
CharToWide((char *)&Data[0],&DataW[0],DataW.Size());
|
||||
DataW.resize(Data.size());
|
||||
CharToWide((char *)Data.data(),DataW.data(),DataW.size());
|
||||
}
|
||||
|
||||
if (SrcCharset==RCH_UNICODE)
|
||||
@@ -75,8 +73,8 @@ bool ReadTextFile(
|
||||
LittleEndian=1;
|
||||
}
|
||||
|
||||
DataW.Alloc(Data.Size()/2+1);
|
||||
size_t End=Data.Size() & ~1; // We need even bytes number for UTF-16.
|
||||
DataW.resize(Data.size()/2+1);
|
||||
size_t End=Data.size() & ~1; // We need even bytes number for UTF-16.
|
||||
for (size_t I=Start;I<End;I+=2)
|
||||
DataW[(I-Start)/2]=Data[I+BigEndian]+Data[I+LittleEndian]*256;
|
||||
DataW[(End-Start)/2]=0;
|
||||
@@ -84,12 +82,12 @@ bool ReadTextFile(
|
||||
|
||||
if (SrcCharset==RCH_UTF8)
|
||||
{
|
||||
Data.Push(0); // Zero terminate data.
|
||||
DataW.Alloc(Data.Size());
|
||||
UtfToWide((const char *)(Data+(Utf8 ? 3:0)),&DataW[0],DataW.Size());
|
||||
Data.push_back(0); // Zero terminate data.
|
||||
DataW.resize(Data.size());
|
||||
UtfToWide((const char *)(Data.data()+(Utf8 ? 3:0)),DataW.data(),DataW.size());
|
||||
}
|
||||
|
||||
wchar *CurStr=&DataW[0];
|
||||
wchar *CurStr=DataW.data();
|
||||
|
||||
while (*CurStr!=0)
|
||||
{
|
||||
@@ -127,12 +125,11 @@ bool ReadTextFile(
|
||||
#if defined(_WIN_ALL)
|
||||
if (ExpandEnvStr && *CurStr=='%') // Expand environment variables in Windows.
|
||||
{
|
||||
wchar ExpName[NM];
|
||||
*ExpName=0;
|
||||
DWORD Result=ExpandEnvironmentStrings(CurStr,ExpName,ASIZE(ExpName));
|
||||
Expanded=Result!=0 && Result<ASIZE(ExpName);
|
||||
if (Expanded && *ExpName!=0)
|
||||
std::wstring ExpName=CurStr;
|
||||
ExpandEnvironmentStr(ExpName);
|
||||
if (!ExpName.empty())
|
||||
List->AddString(ExpName);
|
||||
Expanded=true;
|
||||
}
|
||||
#endif
|
||||
if (!Expanded && *CurStr!=0)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define _RAR_FILESTR_
|
||||
|
||||
bool ReadTextFile(
|
||||
const wchar *Name,
|
||||
const std::wstring &Name,
|
||||
StringList *List,
|
||||
bool Config,
|
||||
bool AbortOnError=false,
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
FindFile::FindFile()
|
||||
{
|
||||
*FindMask=0;
|
||||
FirstCall=true;
|
||||
#ifdef _WIN_ALL
|
||||
hFind=INVALID_HANDLE_VALUE;
|
||||
@@ -24,9 +23,9 @@ FindFile::~FindFile()
|
||||
}
|
||||
|
||||
|
||||
void FindFile::SetMask(const wchar *Mask)
|
||||
void FindFile::SetMask(const std::wstring &Mask)
|
||||
{
|
||||
wcsncpyz(FindMask,Mask,ASIZE(FindMask));
|
||||
FindMask=Mask;
|
||||
FirstCall=true;
|
||||
}
|
||||
|
||||
@@ -34,7 +33,7 @@ void FindFile::SetMask(const wchar *Mask)
|
||||
bool FindFile::Next(FindData *fd,bool GetSymLink)
|
||||
{
|
||||
fd->Error=false;
|
||||
if (*FindMask==0)
|
||||
if (FindMask.empty())
|
||||
return false;
|
||||
#ifdef _WIN_ALL
|
||||
if (FirstCall)
|
||||
@@ -48,14 +47,14 @@ bool FindFile::Next(FindData *fd,bool GetSymLink)
|
||||
#else
|
||||
if (FirstCall)
|
||||
{
|
||||
wchar DirName[NM];
|
||||
wcsncpyz(DirName,FindMask,ASIZE(DirName));
|
||||
std::wstring DirName;
|
||||
DirName=FindMask;
|
||||
RemoveNameFromPath(DirName);
|
||||
if (*DirName==0)
|
||||
wcsncpyz(DirName,L".",ASIZE(DirName));
|
||||
char DirNameA[NM];
|
||||
WideToChar(DirName,DirNameA,ASIZE(DirNameA));
|
||||
if ((dirp=opendir(DirNameA))==NULL)
|
||||
if (DirName.empty())
|
||||
DirName=L".";
|
||||
std::string DirNameA;
|
||||
WideToChar(DirName,DirNameA);
|
||||
if ((dirp=opendir(DirNameA.c_str()))==NULL)
|
||||
{
|
||||
fd->Error=(errno!=ENOENT);
|
||||
return false;
|
||||
@@ -63,32 +62,31 @@ bool FindFile::Next(FindData *fd,bool GetSymLink)
|
||||
}
|
||||
while (1)
|
||||
{
|
||||
wchar Name[NM];
|
||||
std::wstring Name;
|
||||
struct dirent *ent=readdir(dirp);
|
||||
if (ent==NULL)
|
||||
return false;
|
||||
if (strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0)
|
||||
continue;
|
||||
if (!CharToWide(ent->d_name,Name,ASIZE(Name)))
|
||||
uiMsg(UIERROR_INVALIDNAME,UINULL,Name);
|
||||
if (!CharToWide(std::string(ent->d_name),Name))
|
||||
uiMsg(UIERROR_INVALIDNAME,L"",Name);
|
||||
|
||||
if (CmpName(FindMask,Name,MATCH_NAMES))
|
||||
{
|
||||
wchar FullName[NM];
|
||||
wcsncpyz(FullName,FindMask,ASIZE(FullName));
|
||||
*PointToName(FullName)=0;
|
||||
if (wcslen(FullName)+wcslen(Name)>=ASIZE(FullName)-1)
|
||||
std::wstring FullName=FindMask;
|
||||
FullName.erase(GetNamePos(FullName));
|
||||
if (FullName.size()+Name.size()>=MAXPATHSIZE)
|
||||
{
|
||||
uiMsg(UIERROR_PATHTOOLONG,FullName,L"",Name);
|
||||
return false;
|
||||
}
|
||||
wcsncatz(FullName,Name,ASIZE(FullName));
|
||||
FullName+=Name;
|
||||
if (!FastFind(FullName,fd,GetSymLink))
|
||||
{
|
||||
ErrHandler.OpenErrorMsg(FullName);
|
||||
continue;
|
||||
}
|
||||
wcsncpyz(fd->Name,FullName,ASIZE(fd->Name));
|
||||
fd->Name=FullName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -98,14 +96,14 @@ bool FindFile::Next(FindData *fd,bool GetSymLink)
|
||||
fd->IsLink=IsLink(fd->FileAttr);
|
||||
|
||||
FirstCall=false;
|
||||
wchar *NameOnly=PointToName(fd->Name);
|
||||
if (wcscmp(NameOnly,L".")==0 || wcscmp(NameOnly,L"..")==0)
|
||||
std::wstring NameOnly=PointToName(fd->Name);
|
||||
if (NameOnly==L"." || NameOnly==L"..")
|
||||
return Next(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink)
|
||||
bool FindFile::FastFind(const std::wstring &FindMask,FindData *fd,bool GetSymLink)
|
||||
{
|
||||
fd->Error=false;
|
||||
#ifndef _UNIX
|
||||
@@ -117,17 +115,17 @@ bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink)
|
||||
if (hFind==INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
FindClose(hFind);
|
||||
#else
|
||||
char FindMaskA[NM];
|
||||
WideToChar(FindMask,FindMaskA,ASIZE(FindMaskA));
|
||||
#elif defined(_UNIX)
|
||||
std::string FindMaskA;
|
||||
WideToChar(FindMask,FindMaskA);
|
||||
|
||||
struct stat st;
|
||||
if (GetSymLink)
|
||||
{
|
||||
#ifdef SAVE_LINKS
|
||||
if (lstat(FindMaskA,&st)!=0)
|
||||
if (lstat(FindMaskA.c_str(),&st)!=0)
|
||||
#else
|
||||
if (stat(FindMaskA,&st)!=0)
|
||||
if (stat(FindMaskA.c_str(),&st)!=0)
|
||||
#endif
|
||||
{
|
||||
fd->Error=(errno!=ENOENT);
|
||||
@@ -135,7 +133,7 @@ bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink)
|
||||
}
|
||||
}
|
||||
else
|
||||
if (stat(FindMaskA,&st)!=0)
|
||||
if (stat(FindMaskA.c_str(),&st)!=0)
|
||||
{
|
||||
fd->Error=(errno!=ENOENT);
|
||||
return false;
|
||||
@@ -143,17 +141,9 @@ 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));
|
||||
fd->Name=FindMask;
|
||||
#endif
|
||||
fd->Flags=0;
|
||||
fd->IsDir=IsDir(fd->FileAttr);
|
||||
@@ -164,17 +154,17 @@ bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink)
|
||||
|
||||
|
||||
#ifdef _WIN_ALL
|
||||
HANDLE FindFile::Win32Find(HANDLE hFind,const wchar *Mask,FindData *fd)
|
||||
HANDLE FindFile::Win32Find(HANDLE hFind,const std::wstring &Mask,FindData *fd)
|
||||
{
|
||||
WIN32_FIND_DATA FindData;
|
||||
if (hFind==INVALID_HANDLE_VALUE)
|
||||
{
|
||||
hFind=FindFirstFile(Mask,&FindData);
|
||||
hFind=FindFirstFile(Mask.c_str(),&FindData);
|
||||
if (hFind==INVALID_HANDLE_VALUE)
|
||||
{
|
||||
wchar LongMask[NM];
|
||||
if (GetWinLongPath(Mask,LongMask,ASIZE(LongMask)))
|
||||
hFind=FindFirstFile(LongMask,&FindData);
|
||||
std::wstring LongMask;
|
||||
if (GetWinLongPath(Mask,LongMask))
|
||||
hFind=FindFirstFile(LongMask.c_str(),&FindData);
|
||||
}
|
||||
if (hFind==INVALID_HANDLE_VALUE)
|
||||
{
|
||||
@@ -198,8 +188,8 @@ HANDLE FindFile::Win32Find(HANDLE hFind,const wchar *Mask,FindData *fd)
|
||||
|
||||
if (hFind!=INVALID_HANDLE_VALUE)
|
||||
{
|
||||
wcsncpyz(fd->Name,Mask,ASIZE(fd->Name));
|
||||
SetName(fd->Name,FindData.cFileName,ASIZE(fd->Name));
|
||||
fd->Name=Mask;
|
||||
SetName(fd->Name,FindData.cFileName);
|
||||
fd->Size=INT32TO64(FindData.nFileSizeHigh,FindData.nFileSizeLow);
|
||||
fd->FileAttr=FindData.dwFileAttributes;
|
||||
fd->ftCreationTime=FindData.ftCreationTime;
|
||||
|
||||
@@ -7,7 +7,7 @@ enum FINDDATA_FLAGS {
|
||||
|
||||
struct FindData
|
||||
{
|
||||
wchar Name[NM];
|
||||
std::wstring Name;
|
||||
uint64 Size;
|
||||
uint FileAttr;
|
||||
bool IsDir;
|
||||
@@ -28,10 +28,10 @@ class FindFile
|
||||
{
|
||||
private:
|
||||
#ifdef _WIN_ALL
|
||||
static HANDLE Win32Find(HANDLE hFind,const wchar *Mask,FindData *fd);
|
||||
static HANDLE Win32Find(HANDLE hFind,const std::wstring &Mask,FindData *fd);
|
||||
#endif
|
||||
|
||||
wchar FindMask[NM];
|
||||
std::wstring FindMask;
|
||||
bool FirstCall;
|
||||
#ifdef _WIN_ALL
|
||||
HANDLE hFind;
|
||||
@@ -41,9 +41,9 @@ class FindFile
|
||||
public:
|
||||
FindFile();
|
||||
~FindFile();
|
||||
void SetMask(const wchar *Mask);
|
||||
void SetMask(const std::wstring &Mask);
|
||||
bool Next(FindData *fd,bool GetSymLink=false);
|
||||
static bool FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink=false);
|
||||
static bool FastFind(const std::wstring &FindMask,FindData *fd,bool GetSymLink=false);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,11 +5,11 @@ BitInput::BitInput(bool AllocBuffer)
|
||||
ExternalBuffer=false;
|
||||
if (AllocBuffer)
|
||||
{
|
||||
// getbits32 attempts to read data from InAddr, ... InAddr+3 positions.
|
||||
// So let's allocate 3 additional bytes for situation, when we need to
|
||||
// getbits*() attempt to read data from InAddr, ... InAddr+8 positions.
|
||||
// So let's allocate 8 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.
|
||||
size_t BufSize=MAX_SIZE+3;
|
||||
// from access to next 8 bytes, which contents we do not need.
|
||||
size_t BufSize=MAX_SIZE+8;
|
||||
InBuf=new byte[BufSize];
|
||||
|
||||
// Ensure that we get predictable results when accessing bytes in area
|
||||
@@ -17,7 +17,7 @@ BitInput::BitInput(bool AllocBuffer)
|
||||
memset(InBuf,0,BufSize);
|
||||
}
|
||||
else
|
||||
InBuf=NULL;
|
||||
InBuf=nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,21 +30,21 @@ BitInput::~BitInput()
|
||||
|
||||
void BitInput::faddbits(uint Bits)
|
||||
{
|
||||
// Function wrapped version of inline addbits to save code size.
|
||||
// Function wrapped version of inline addbits to reduce the code size.
|
||||
addbits(Bits);
|
||||
}
|
||||
|
||||
|
||||
uint BitInput::fgetbits()
|
||||
{
|
||||
// Function wrapped version of inline getbits to save code size.
|
||||
// Function wrapped version of inline getbits to reduce the code size.
|
||||
return getbits();
|
||||
}
|
||||
|
||||
|
||||
void BitInput::SetExternalBuffer(byte *Buf)
|
||||
{
|
||||
if (InBuf!=NULL && !ExternalBuffer)
|
||||
if (InBuf!=nullptr && !ExternalBuffer)
|
||||
delete[] InBuf;
|
||||
InBuf=Buf;
|
||||
ExternalBuffer=true;
|
||||
|
||||
@@ -28,30 +28,43 @@ class BitInput
|
||||
InAddr+=Bits>>3;
|
||||
InBit=Bits&7;
|
||||
}
|
||||
|
||||
|
||||
// Return 16 bits from current position in the buffer.
|
||||
// Bit at (InAddr,InBit) has the highest position in returning data.
|
||||
uint getbits()
|
||||
{
|
||||
#if defined(LITTLE_ENDIAN) && defined(ALLOW_MISALIGNED)
|
||||
uint32 BitField=RawGetBE4(InBuf+InAddr);
|
||||
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()
|
||||
{
|
||||
uint BitField=(uint)InBuf[InAddr] << 24;
|
||||
BitField|=(uint)InBuf[InAddr+1] << 16;
|
||||
BitField|=(uint)InBuf[InAddr+2] << 8;
|
||||
BitField|=(uint)InBuf[InAddr+3];
|
||||
uint BitField=RawGetBE4(InBuf+InAddr);
|
||||
BitField <<= InBit;
|
||||
BitField|=(uint)InBuf[InAddr+4] >> (8-InBit);
|
||||
return BitField & 0xffffffff;
|
||||
}
|
||||
|
||||
// Return 64 bits from current position in the buffer.
|
||||
// Bit at (InAddr,InBit) has the highest position in returning data.
|
||||
uint64 getbits64()
|
||||
{
|
||||
uint64 BitField=RawGetBE8(InBuf+InAddr);
|
||||
BitField <<= InBit;
|
||||
BitField|=(uint)InBuf[InAddr+8] >> (8-InBit);
|
||||
return BitField;
|
||||
}
|
||||
|
||||
void faddbits(uint Bits);
|
||||
uint fgetbits();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define INCLUDEGLOBAL
|
||||
|
||||
#if defined(__BORLANDC__) || defined(_MSC_VER)
|
||||
#ifdef _MSC_VER
|
||||
#pragma hdrstop
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
bool ExtractHardlink(wchar *NameNew,wchar *NameExisting,size_t NameExistingSize)
|
||||
bool ExtractHardlink(CommandData *Cmd,const std::wstring &NameNew,const std::wstring &NameExisting)
|
||||
{
|
||||
SlashToNative(NameExisting,NameExisting,NameExistingSize); // Not needed for RAR 5.1+ archives.
|
||||
|
||||
if (!FileExist(NameExisting))
|
||||
{
|
||||
uiMsg(UIERROR_HLINKCREATE,NameNew);
|
||||
@@ -9,10 +7,10 @@ bool ExtractHardlink(wchar *NameNew,wchar *NameExisting,size_t NameExistingSize)
|
||||
ErrHandler.SetErrorCode(RARX_CREATE);
|
||||
return false;
|
||||
}
|
||||
CreatePath(NameNew,true);
|
||||
CreatePath(NameNew,true,Cmd->DisableNames);
|
||||
|
||||
#ifdef _WIN_ALL
|
||||
bool Success=CreateHardLink(NameNew,NameExisting,NULL)!=0;
|
||||
bool Success=CreateHardLink(NameNew.c_str(),NameExisting.c_str(),NULL)!=0;
|
||||
if (!Success)
|
||||
{
|
||||
uiMsg(UIERROR_HLINKCREATE,NameNew);
|
||||
@@ -21,10 +19,10 @@ bool ExtractHardlink(wchar *NameNew,wchar *NameExisting,size_t NameExistingSize)
|
||||
}
|
||||
return Success;
|
||||
#elif defined(_UNIX)
|
||||
char NameExistingA[NM],NameNewA[NM];
|
||||
WideToChar(NameExisting,NameExistingA,ASIZE(NameExistingA));
|
||||
WideToChar(NameNew,NameNewA,ASIZE(NameNewA));
|
||||
bool Success=link(NameExistingA,NameNewA)==0;
|
||||
std::string NameExistingA,NameNewA;
|
||||
WideToChar(NameExisting,NameExistingA);
|
||||
WideToChar(NameNew,NameNewA);
|
||||
bool Success=link(NameExistingA.c_str(),NameNewA.c_str())==0;
|
||||
if (!Success)
|
||||
{
|
||||
uiMsg(UIERROR_HLINKCREATE,NameNew);
|
||||
|
||||
158
unrar/hash.cpp
158
unrar/hash.cpp
@@ -26,7 +26,7 @@ void HashValue::Init(HASH_TYPE Type)
|
||||
}
|
||||
|
||||
|
||||
bool HashValue::operator == (const HashValue &cmp)
|
||||
bool HashValue::operator == (const HashValue &cmp) const
|
||||
{
|
||||
if (Type==HASH_NONE || cmp.Type==HASH_NONE)
|
||||
return true;
|
||||
@@ -76,7 +76,7 @@ void DataHash::Init(HASH_TYPE Type,uint MaxThreads)
|
||||
if (Type==HASH_BLAKE2)
|
||||
blake2sp_init(blake2ctx);
|
||||
#ifdef RAR_SMP
|
||||
DataHash::MaxThreads=Min(MaxThreads,MaxHashThreads);
|
||||
DataHash::MaxThreads=Min(MaxThreads,HASH_POOL_THREADS);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -88,13 +88,19 @@ void DataHash::Update(const void *Data,size_t DataSize)
|
||||
CurCRC32=Checksum14((ushort)CurCRC32,Data,DataSize);
|
||||
#endif
|
||||
if (HashType==HASH_CRC32)
|
||||
{
|
||||
#ifdef RAR_SMP
|
||||
UpdateCRC32MT(Data,DataSize);
|
||||
#else
|
||||
CurCRC32=CRC32(CurCRC32,Data,DataSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (HashType==HASH_BLAKE2)
|
||||
{
|
||||
#ifdef RAR_SMP
|
||||
if (MaxThreads>1 && ThPool==NULL)
|
||||
ThPool=new ThreadPool(BLAKE2_THREADS_NUMBER);
|
||||
if (MaxThreads>1 && ThPool==nullptr)
|
||||
ThPool=new ThreadPool(HASH_POOL_THREADS);
|
||||
blake2ctx->ThPool=ThPool;
|
||||
blake2ctx->MaxThreads=MaxThreads;
|
||||
#endif
|
||||
@@ -103,6 +109,146 @@ void DataHash::Update(const void *Data,size_t DataSize)
|
||||
}
|
||||
|
||||
|
||||
#ifdef RAR_SMP
|
||||
THREAD_PROC(BuildCRC32Thread)
|
||||
{
|
||||
DataHash::CRC32ThreadData *td=(DataHash::CRC32ThreadData *)Data;
|
||||
|
||||
// Use 0 initial value to simplify combining the result with existing CRC32.
|
||||
// It doesn't affect the first initial 0xffffffff in the data beginning.
|
||||
// If we used 0xffffffff here, we would need to shift 0xffffffff left to
|
||||
// block width and XOR it with block CRC32 to reset its initial value to 0.
|
||||
td->DataCRC=CRC32(0,td->Data,td->DataSize);
|
||||
}
|
||||
|
||||
|
||||
// CRC is linear and distributive over addition, so CRC(a+b)=CRC(a)+CRC(b).
|
||||
// Since addition in finite field is XOR, we have CRC(a^b)=CRC(a)^CRC(b).
|
||||
// So CRC(aaabbb) = CRC(aaa000) ^ CRC(000bbb) = CRC(aaa000) ^ CRC(bbb),
|
||||
// because CRC ignores leading zeroes. Thus to split CRC calculations
|
||||
// to "aaa" and "bbb" blocks and then to threads we need to be able to
|
||||
// find CRC(aaa000) knowing "aaa" quickly. We use Galois finite field to
|
||||
// calculate the power of 2 to get "1000" and multiply it by "aaa".
|
||||
void DataHash::UpdateCRC32MT(const void *Data,size_t DataSize)
|
||||
{
|
||||
const size_t MinBlock=0x4000;
|
||||
if (DataSize<2*MinBlock || MaxThreads<2)
|
||||
{
|
||||
CurCRC32=CRC32(CurCRC32,Data,DataSize);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ThPool==nullptr)
|
||||
ThPool=new ThreadPool(HASH_POOL_THREADS);
|
||||
|
||||
size_t Threads=MaxThreads;
|
||||
size_t BlockSize=DataSize/Threads;
|
||||
if (BlockSize<MinBlock)
|
||||
{
|
||||
BlockSize=MinBlock;
|
||||
Threads=DataSize/BlockSize;
|
||||
}
|
||||
|
||||
CRC32ThreadData td[MaxPoolThreads];
|
||||
|
||||
//#undef USE_THREADS
|
||||
for (size_t I=0;I<Threads;I++)
|
||||
{
|
||||
td[I].Data=(byte*)Data+I*BlockSize;
|
||||
td[I].DataSize=(I+1==Threads) ? DataSize-I*BlockSize : BlockSize;
|
||||
#ifdef USE_THREADS
|
||||
ThPool->AddTask(BuildCRC32Thread,(void*)&td[I]);
|
||||
#else
|
||||
BuildCRC32Thread((void*)&td[I]);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_THREADS
|
||||
ThPool->WaitDone();
|
||||
#endif // USE_THREADS
|
||||
|
||||
uint StdShift=gfExpCRC(uint(8*td[0].DataSize));
|
||||
for (size_t I=0;I<Threads;I++)
|
||||
{
|
||||
// Prepare the multiplier to shift CRC to proper position.
|
||||
uint ShiftMult;
|
||||
if (td[I].DataSize==td[0].DataSize)
|
||||
ShiftMult=StdShift; // Reuse the shift value for typical block size.
|
||||
else
|
||||
ShiftMult=gfExpCRC(uint(8*td[I].DataSize)); // 2 power "shift bits".
|
||||
|
||||
// To combine the cumulative total and current block CRC32, we multiply
|
||||
// the total data CRC32 to shift value to place it to proper position.
|
||||
// Invoke BitReverse32(), because 0xEDB88320 is the reversed polynomial.
|
||||
// Alternatively we could adjust the multiplication function for reversed
|
||||
// polynomials, but it would make it less readable without real speed gain.
|
||||
// If CRC32 threads used 0xffffffff initial value, we would need
|
||||
// to XOR the total data CRC32 with 0xffffffff before multiplication,
|
||||
// so 0xffffffff is also shifted left to current block width and replaces
|
||||
// the initial 0xffffffff CRC32 value with 0 in the current block CRC32
|
||||
// after XOR'ing it with total data CRC32. Since now CRC32 threads use 0
|
||||
// initial value, this is not necessary.
|
||||
CurCRC32=BitReverse32(gfMulCRC(BitReverse32(CurCRC32), ShiftMult));
|
||||
|
||||
// Combine the total data and current block CRC32.
|
||||
CurCRC32^=td[I].DataCRC;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
uint DataHash::BitReverse32(uint N)
|
||||
{
|
||||
uint Reversed=0;
|
||||
for (uint I=0;I<32;I++,N>>=1)
|
||||
Reversed|=(N & 1)<<(31-I);
|
||||
return Reversed;
|
||||
}
|
||||
|
||||
|
||||
// Galois field multiplication modulo POLY.
|
||||
uint DataHash::gfMulCRC(uint A, uint B)
|
||||
{
|
||||
// For reversed 0xEDB88320 polynomial we bit reverse CRC32 before passing
|
||||
// to this function, so we must use the normal polynomial here.
|
||||
// We set the highest polynomial bit 33 for proper multiplication
|
||||
// in case uint is larger than 32-bit.
|
||||
const uint POLY=uint(0x104c11db7);
|
||||
|
||||
uint R = 0 ; // Multiplication result.
|
||||
while (A != 0 && B != 0) // If any of multipliers becomes 0, quit early.
|
||||
{
|
||||
// For non-zero lowest B bit, add A to result.
|
||||
R ^= (B & 1)!=0 ? A : 0;
|
||||
|
||||
// Make A twice larger before the next iteration.
|
||||
// Subtract POLY to keep it modulo POLY if high bit is set.
|
||||
A = (A << 1) ^ ((A & 0x80000000)!=0 ? POLY : 0);
|
||||
|
||||
B >>= 1; // Move next B bit to lowest position.
|
||||
}
|
||||
return R;
|
||||
}
|
||||
|
||||
|
||||
// Calculate 2 power N with square-and-multiply algorithm.
|
||||
uint DataHash::gfExpCRC(uint N)
|
||||
{
|
||||
uint S = 2; // Starts from base value and contains the current square.
|
||||
uint R = 1; // Exponentiation result.
|
||||
while (N > 1)
|
||||
{
|
||||
if ((N & 1)!=0) // If N is odd.
|
||||
R = gfMulCRC(R, S);
|
||||
S = gfMulCRC(S, S); // Next square.
|
||||
N >>= 1;
|
||||
}
|
||||
// We could change the loop condition to N > 0 and return R at expense
|
||||
// of one additional gfMulCRC(S, S).
|
||||
return gfMulCRC(R, S);
|
||||
}
|
||||
|
||||
|
||||
void DataHash::Result(HashValue *Result)
|
||||
{
|
||||
Result->Type=HashType;
|
||||
@@ -129,7 +275,9 @@ bool DataHash::Cmp(HashValue *CmpValue,byte *Key)
|
||||
{
|
||||
HashValue Final;
|
||||
Result(&Final);
|
||||
if (Key!=NULL)
|
||||
#ifndef RAR_NOCRYPT
|
||||
if (Key!=nullptr)
|
||||
ConvertHashToMAC(&Final,Key);
|
||||
#endif
|
||||
return Final==*CmpValue;
|
||||
}
|
||||
|
||||
@@ -6,8 +6,16 @@ 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.
|
||||
// Can be removed after switching to C++20, which automatically provides "!="
|
||||
// if operator == is defined.
|
||||
bool operator != (const HashValue &cmp) const {return !(*this==cmp);}
|
||||
|
||||
HASH_TYPE Type;
|
||||
union
|
||||
@@ -26,7 +34,24 @@ class DataHash;
|
||||
|
||||
class DataHash
|
||||
{
|
||||
public:
|
||||
struct CRC32ThreadData
|
||||
{
|
||||
void *Data;
|
||||
size_t DataSize;
|
||||
uint DataCRC;
|
||||
};
|
||||
private:
|
||||
void UpdateCRC32MT(const void *Data,size_t DataSize);
|
||||
uint BitReverse32(uint N);
|
||||
uint gfMulCRC(uint A, uint B);
|
||||
uint gfExpCRC(uint N);
|
||||
|
||||
// Speed gain seems to vanish above 8 CRC32 threads.
|
||||
static const uint CRC32_POOL_THREADS=8;
|
||||
// Thread pool must allow at least BLAKE2_THREADS_NUMBER threads.
|
||||
static const uint HASH_POOL_THREADS=Max(BLAKE2_THREADS_NUMBER,CRC32_POOL_THREADS);
|
||||
|
||||
HASH_TYPE HashType;
|
||||
uint CurCRC32;
|
||||
blake2sp_state *blake2ctx;
|
||||
@@ -35,8 +60,6 @@ class DataHash
|
||||
ThreadPool *ThPool;
|
||||
|
||||
uint MaxThreads;
|
||||
// Upper limit for maximum threads to prevent wasting threads in pool.
|
||||
static const uint MaxHashThreads=8;
|
||||
#endif
|
||||
public:
|
||||
DataHash();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
void FileHeader::Reset(size_t SubDataSize)
|
||||
{
|
||||
SubData.Alloc(SubDataSize);
|
||||
SubData.resize(SubDataSize);
|
||||
BaseBlock::Reset();
|
||||
FileHash.Init(HASH_NONE);
|
||||
mtime.Reset();
|
||||
@@ -37,6 +37,7 @@ void FileHeader::Reset(size_t SubDataSize)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
FileHeader& FileHeader::operator = (FileHeader &hd)
|
||||
{
|
||||
SubData.Reset();
|
||||
@@ -45,17 +46,10 @@ FileHeader& FileHeader::operator = (FileHeader &hd)
|
||||
SubData=hd.SubData;
|
||||
return *this;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
void MainHeader::Reset()
|
||||
{
|
||||
HighPosAV=0;
|
||||
PosAV=0;
|
||||
CommentInHeader=false;
|
||||
PackComment=false;
|
||||
Locator=false;
|
||||
QOpenOffset=0;
|
||||
QOpenMaxSize=0;
|
||||
RROffset=0;
|
||||
RRMaxSize=0;
|
||||
*this={};
|
||||
}
|
||||
|
||||
@@ -6,18 +6,19 @@
|
||||
#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
|
||||
#define SIZEOF_PROTECTHEAD 26
|
||||
#define SIZEOF_UOHEAD 18
|
||||
#define SIZEOF_STREAMHEAD 26
|
||||
|
||||
#define VER_PACK 29U
|
||||
#define VER_PACK5 50U // It is stored as 0, but we subtract 50 when saving an archive.
|
||||
#define VER_PACK7 70U // It is stored as 1, but we subtract 70 when saving an archive.
|
||||
#define VER_UNPACK 29U
|
||||
#define VER_UNPACK5 50U // It is stored as 0, but we add 50 when reading an archive.
|
||||
#define VER_UNPACK7 70U // It is stored as 1, but we add 50 when reading an archive.
|
||||
#define VER_UNKNOWN 9999U // Just some large value.
|
||||
|
||||
#define MHD_VOLUME 0x0001U
|
||||
@@ -83,7 +84,7 @@ enum HEADER_TYPE {
|
||||
};
|
||||
|
||||
|
||||
// RAR 2.9 and earlier.
|
||||
// RAR 2.9 and earlier service haeders, mostly outdated and not supported.
|
||||
enum { EA_HEAD=0x100,UO_HEAD=0x101,MAC_HEAD=0x102,BEEA_HEAD=0x103,
|
||||
NTACL_HEAD=0x104,STREAM_HEAD=0x105 };
|
||||
|
||||
@@ -148,6 +149,14 @@ struct BaseBlock
|
||||
{
|
||||
SkipIfUnknown=false;
|
||||
}
|
||||
|
||||
// We use it to assign this block data to inherited blocks.
|
||||
// Such function seems to be cleaner than '(BaseBlock&)' cast or adding
|
||||
// 'using BaseBlock::operator=;' to every inherited header.
|
||||
void SetBaseBlock(BaseBlock &Src)
|
||||
{
|
||||
*this=Src;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -162,12 +171,16 @@ struct MainHeader:BaseBlock
|
||||
ushort HighPosAV;
|
||||
uint PosAV;
|
||||
bool CommentInHeader;
|
||||
bool PackComment; // For RAR 1.4 archive format only.
|
||||
bool PackComment; // For RAR 1.4 archive format only.
|
||||
bool Locator;
|
||||
uint64 QOpenOffset; // Offset of quick list record.
|
||||
uint64 QOpenMaxSize; // Maximum size of QOpen offset in locator extra field.
|
||||
uint64 RROffset; // Offset of recovery record.
|
||||
uint64 RRMaxSize; // Maximum size of RR offset in locator extra field.
|
||||
uint64 QOpenOffset; // Offset of quick list record.
|
||||
uint64 QOpenMaxSize; // Maximum size of QOpen offset in locator extra field.
|
||||
uint64 RROffset; // Offset of recovery record.
|
||||
uint64 RRMaxSize; // Maximum size of RR offset in locator extra field.
|
||||
size_t MetaNameMaxSize; // Maximum size of archive name in metadata extra field.
|
||||
std::wstring OrigName; // Original archive name.
|
||||
RarTime OrigTime; // Original archive time.
|
||||
|
||||
void Reset();
|
||||
};
|
||||
|
||||
@@ -181,9 +194,9 @@ struct FileHeader:BlockHeader
|
||||
uint FileAttr;
|
||||
uint SubFlags;
|
||||
};
|
||||
wchar FileName[NM];
|
||||
std::wstring FileName;
|
||||
|
||||
Array<byte> SubData;
|
||||
std::vector<byte> SubData;
|
||||
|
||||
RarTime mtime;
|
||||
RarTime ctime;
|
||||
@@ -223,20 +236,20 @@ struct FileHeader:BlockHeader
|
||||
bool Dir;
|
||||
bool CommentInHeader; // RAR 2.0 file comment.
|
||||
bool Version; // name.ext;ver file name containing the version number.
|
||||
size_t WinSize;
|
||||
uint64 WinSize;
|
||||
bool Inherited; // New file inherits a subblock when updating a host file (for subblocks only).
|
||||
|
||||
// 'true' if file sizes use 8 bytes instead of 4. Not used in RAR 5.0.
|
||||
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;
|
||||
|
||||
FILE_SYSTEM_REDIRECT RedirType;
|
||||
wchar RedirName[NM];
|
||||
std::wstring RedirName;
|
||||
bool DirTarget;
|
||||
|
||||
bool UnixOwnerSet,UnixOwnerNumeric,UnixGroupNumeric;
|
||||
@@ -253,10 +266,10 @@ struct FileHeader:BlockHeader
|
||||
|
||||
bool CmpName(const wchar *Name)
|
||||
{
|
||||
return(wcscmp(FileName,Name)==0);
|
||||
return FileName==Name;
|
||||
}
|
||||
|
||||
FileHeader& operator = (FileHeader &hd);
|
||||
// FileHeader& operator = (FileHeader &hd);
|
||||
};
|
||||
|
||||
|
||||
@@ -321,16 +334,6 @@ struct ProtectHeader:BlockHeader
|
||||
};
|
||||
|
||||
|
||||
struct UnixOwnersHeader:SubBlockHeader
|
||||
{
|
||||
ushort OwnerNameSize;
|
||||
ushort GroupNameSize;
|
||||
/* dummy */
|
||||
char OwnerName[256];
|
||||
char GroupName[256];
|
||||
};
|
||||
|
||||
|
||||
struct EAHeader:SubBlockHeader
|
||||
{
|
||||
uint UnpSize;
|
||||
@@ -347,7 +350,7 @@ struct StreamHeader:SubBlockHeader
|
||||
byte Method;
|
||||
uint StreamCRC;
|
||||
ushort StreamNameSize;
|
||||
char StreamName[260];
|
||||
std::string StreamName;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -42,28 +42,42 @@
|
||||
|
||||
|
||||
// RAR 5.0 file compression flags.
|
||||
#define FCI_ALGO_BIT0 0x0001 // Version of compression algorithm.
|
||||
#define FCI_ALGO_BIT1 0x0002 // 0 .. 63.
|
||||
#define FCI_ALGO_BIT2 0x0004
|
||||
#define FCI_ALGO_BIT3 0x0008
|
||||
#define FCI_ALGO_BIT4 0x0010
|
||||
#define FCI_ALGO_BIT5 0x0020
|
||||
#define FCI_SOLID 0x0040 // Solid flag.
|
||||
#define FCI_METHOD_BIT0 0x0080 // Compression method.
|
||||
#define FCI_METHOD_BIT1 0x0100 // 0 .. 5 (6 and 7 are not used).
|
||||
#define FCI_METHOD_BIT2 0x0200
|
||||
#define FCI_DICT_BIT0 0x0400 // Dictionary size.
|
||||
#define FCI_DICT_BIT1 0x0800 // 128 KB .. 4 GB.
|
||||
#define FCI_DICT_BIT2 0x1000
|
||||
#define FCI_DICT_BIT3 0x2000
|
||||
#define FCI_ALGO_BIT0 0x00000001 // Version of compression algorithm.
|
||||
#define FCI_ALGO_BIT1 0x00000002 // 0 .. 63.
|
||||
#define FCI_ALGO_BIT2 0x00000004
|
||||
#define FCI_ALGO_BIT3 0x00000008
|
||||
#define FCI_ALGO_BIT4 0x00000010
|
||||
#define FCI_ALGO_BIT5 0x00000020
|
||||
#define FCI_SOLID 0x00000040 // Solid flag.
|
||||
#define FCI_METHOD_BIT0 0x00000080 // Compression method.
|
||||
#define FCI_METHOD_BIT1 0x00000100 // 0 .. 5 (6 and 7 are not used).
|
||||
#define FCI_METHOD_BIT2 0x00000200
|
||||
#define FCI_DICT_BIT0 0x00000400 // Dictionary size.
|
||||
#define FCI_DICT_BIT1 0x00000800 // 128 KB .. 1 TB.
|
||||
#define FCI_DICT_BIT2 0x00001000
|
||||
#define FCI_DICT_BIT3 0x00002000
|
||||
#define FCI_DICT_BIT4 0x00004000
|
||||
#define FCI_DICT_FRACT0 0x00008000 // Dictionary fraction in 1/32 of size.
|
||||
#define FCI_DICT_FRACT1 0x00010000
|
||||
#define FCI_DICT_FRACT2 0x00020000
|
||||
#define FCI_DICT_FRACT3 0x00040000
|
||||
#define FCI_DICT_FRACT4 0x00080000
|
||||
#define FCI_RAR5_COMPAT 0x00100000 // RAR7 compression flags and RAR5 compression algorithm.
|
||||
|
||||
// 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.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "rar.hpp"
|
||||
|
||||
#ifdef _WIN_ALL
|
||||
DWORD WinNT()
|
||||
{
|
||||
static int dwPlatformId=-1;
|
||||
@@ -13,6 +12,7 @@ DWORD WinNT()
|
||||
dwPlatformId=WinVer.dwPlatformId;
|
||||
dwMajorVersion=WinVer.dwMajorVersion;
|
||||
dwMinorVersion=WinVer.dwMinorVersion;
|
||||
|
||||
}
|
||||
DWORD Result=0;
|
||||
if (dwPlatformId==VER_PLATFORM_WIN32_NT)
|
||||
@@ -21,4 +21,91 @@ DWORD WinNT()
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
// Since Windows 10 development is stopped, we can assume that its build
|
||||
// number never reaches 22000. So we do not need WMI anymore.
|
||||
#if 0
|
||||
// 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;
|
||||
|
||||
hres = pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"),NULL,NULL,NULL,0,NULL,NULL,&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;
|
||||
hres = pSvc->ExecQuery(bstr_t("WQL"), bstr_t("SELECT * FROM Win32_OperatingSystem"),
|
||||
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
|
||||
|
||||
if (FAILED(hres) || pEnumerator==NULL)
|
||||
{
|
||||
pSvc->Release();
|
||||
pLoc->Release();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Win10=false;
|
||||
|
||||
IWbemClassObject *pclsObj = NULL;
|
||||
ULONG uReturn = 0;
|
||||
pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
|
||||
if (pclsObj!=NULL && uReturn>0)
|
||||
{
|
||||
VARIANT vtProp;
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -10,4 +10,7 @@ enum WINNT_VERSION {
|
||||
DWORD WinNT();
|
||||
|
||||
|
||||
// Replace it with actual check when available.
|
||||
bool IsWindows11OrGreater();
|
||||
|
||||
#endif
|
||||
|
||||
201
unrar/largepage.cpp
Normal file
201
unrar/largepage.cpp
Normal file
@@ -0,0 +1,201 @@
|
||||
#include "rar.hpp"
|
||||
|
||||
/*
|
||||
To enable, disable or check Large Memory pages manually:
|
||||
- open "Local Security Policy" from "Start Menu";
|
||||
- open "Lock Pages in Memory" in "Local Policies\User Rights Assignment";
|
||||
- add or remove the user and sign out and sign in or restart Windows.
|
||||
*/
|
||||
|
||||
#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(RARDLL)
|
||||
#define ALLOW_LARGE_PAGES
|
||||
#endif
|
||||
|
||||
LargePageAlloc::LargePageAlloc()
|
||||
{
|
||||
UseLargePages=false;
|
||||
#ifdef ALLOW_LARGE_PAGES
|
||||
PageSize=0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void LargePageAlloc::AllowLargePages(bool Allow)
|
||||
{
|
||||
#ifdef ALLOW_LARGE_PAGES
|
||||
if (Allow && PageSize==0)
|
||||
{
|
||||
HMODULE hKernel=GetModuleHandle(L"kernel32.dll");
|
||||
if (hKernel!=nullptr)
|
||||
{
|
||||
typedef SIZE_T (*GETLARGEPAGEMINIMUM)();
|
||||
GETLARGEPAGEMINIMUM pGetLargePageMinimum=(GETLARGEPAGEMINIMUM)GetProcAddress(hKernel, "GetLargePageMinimum");
|
||||
if (pGetLargePageMinimum!=nullptr)
|
||||
PageSize=pGetLargePageMinimum();
|
||||
}
|
||||
if (PageSize==0 || !SetPrivilege(SE_LOCK_MEMORY_NAME))
|
||||
{
|
||||
UseLargePages=false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
UseLargePages=Allow;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool LargePageAlloc::IsPrivilegeAssigned()
|
||||
{
|
||||
#ifdef ALLOW_LARGE_PAGES
|
||||
return SetPrivilege(SE_LOCK_MEMORY_NAME);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool LargePageAlloc::AssignPrivilege()
|
||||
{
|
||||
#ifdef ALLOW_LARGE_PAGES
|
||||
HANDLE hToken = NULL;
|
||||
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
|
||||
return false;
|
||||
|
||||
// Get the required buffer size.
|
||||
DWORD BufSize=0;
|
||||
GetTokenInformation(hToken, TokenUser, NULL, 0, &BufSize);
|
||||
if (BufSize==0 || BufSize>1000000) // Sanity check for returned value.
|
||||
{
|
||||
CloseHandle(hToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
TOKEN_USER *TokenInfo = (TOKEN_USER*)malloc(BufSize);
|
||||
|
||||
// Get the current user token information.
|
||||
if (GetTokenInformation(hToken,TokenUser,TokenInfo,BufSize,&BufSize)==0)
|
||||
{
|
||||
CloseHandle(hToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get SID string for the current user.
|
||||
LPWSTR ApiSidStr;
|
||||
ConvertSidToStringSid(TokenInfo->User.Sid, &ApiSidStr);
|
||||
|
||||
// Convert SID to C++ string and release API based buffer.
|
||||
std::wstring SidStr=ApiSidStr;
|
||||
LocalFree(ApiSidStr);
|
||||
CloseHandle(hToken);
|
||||
|
||||
if (IsUserAdmin())
|
||||
AssignPrivilegeBySid(SidStr);
|
||||
else
|
||||
{
|
||||
// Define here, so they survive until ShellExecuteEx call.
|
||||
std::wstring ExeName=GetModuleFileStr();
|
||||
std::wstring Param=std::wstring(L"-") + LOCKMEM_SWITCH + SidStr;
|
||||
|
||||
SHELLEXECUTEINFO shExecInfo{};
|
||||
shExecInfo.cbSize = sizeof(shExecInfo);
|
||||
|
||||
shExecInfo.hwnd = NULL; // Specifying WinRAR main window here does not work well in command line mode.
|
||||
shExecInfo.lpVerb = L"runas";
|
||||
shExecInfo.lpFile = ExeName.c_str();
|
||||
shExecInfo.lpParameters = Param.c_str();
|
||||
shExecInfo.nShow = SW_SHOWNORMAL;
|
||||
BOOL Result=ShellExecuteEx(&shExecInfo);
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool LargePageAlloc::AssignPrivilegeBySid(const std::wstring &Sid)
|
||||
{
|
||||
#ifdef ALLOW_LARGE_PAGES
|
||||
LSA_HANDLE PolicyHandle;
|
||||
LSA_OBJECT_ATTRIBUTES ObjectAttributes{}; // Docs require to zero initalize it.
|
||||
|
||||
#ifndef STATUS_SUCCESS // Can be defined through WIL package in WinRAR.
|
||||
// We define STATUS_SUCCESS here instead of including ntstatus.h to avoid
|
||||
// macro redefinition warnings. We tried UMDF_USING_NTSTATUS define
|
||||
// and other workarounds, but it didn't help.
|
||||
const uint STATUS_SUCCESS=0;
|
||||
#endif
|
||||
|
||||
if (LsaOpenPolicy(NULL,&ObjectAttributes,POLICY_CREATE_ACCOUNT|
|
||||
POLICY_LOOKUP_NAMES,&PolicyHandle)!=STATUS_SUCCESS)
|
||||
return false;
|
||||
|
||||
PSID UserSid;
|
||||
ConvertStringSidToSid(Sid.c_str(),&UserSid);
|
||||
|
||||
LSA_UNICODE_STRING LsaString;
|
||||
LsaString.Buffer=(PWSTR)SE_LOCK_MEMORY_NAME;
|
||||
// It must be in bytes, so multiple it to sizeof(wchar_t).
|
||||
LsaString.Length=(USHORT)wcslen(LsaString.Buffer)*sizeof(LsaString.Buffer[0]);
|
||||
LsaString.MaximumLength=LsaString.Length;
|
||||
|
||||
bool Success=LsaAddAccountRights(PolicyHandle,UserSid,&LsaString,1)==STATUS_SUCCESS;
|
||||
|
||||
LocalFree(UserSid);
|
||||
LsaClose(PolicyHandle);
|
||||
|
||||
mprintf(St(MPrivilegeAssigned));
|
||||
if (Ask(St(MYesNo)) == 1)
|
||||
Shutdown(POWERMODE_RESTART);
|
||||
|
||||
return Success;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool LargePageAlloc::AssignConfirmation()
|
||||
{
|
||||
#ifdef ALLOW_LARGE_PAGES
|
||||
mprintf(St(MLockInMemoryNeeded));
|
||||
return Ask(St(MYesNo)) == 1;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void* LargePageAlloc::new_large(size_t Size)
|
||||
{
|
||||
void *Allocated=nullptr;
|
||||
|
||||
#ifdef ALLOW_LARGE_PAGES
|
||||
if (UseLargePages && Size>=PageSize)
|
||||
{
|
||||
// VirtualAlloc fails if allocation size isn't multiple of page size.
|
||||
SIZE_T AllocSize=Size%PageSize==0 ? Size:(Size/PageSize+1)*PageSize;
|
||||
Allocated=VirtualAlloc(nullptr,AllocSize,MEM_COMMIT|MEM_RESERVE|MEM_LARGE_PAGES,PAGE_READWRITE);
|
||||
if (Allocated!=nullptr)
|
||||
LargeAlloc.push_back(Allocated);
|
||||
}
|
||||
#endif
|
||||
return Allocated;
|
||||
}
|
||||
|
||||
|
||||
bool LargePageAlloc::delete_large(void *Addr)
|
||||
{
|
||||
#ifdef ALLOW_LARGE_PAGES
|
||||
if (Addr!=nullptr)
|
||||
for (size_t I=0;I<LargeAlloc.size();I++)
|
||||
if (LargeAlloc[I]==Addr)
|
||||
{
|
||||
LargeAlloc[I]=nullptr;
|
||||
VirtualFree(Addr,0,MEM_RELEASE);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
54
unrar/largepage.hpp
Normal file
54
unrar/largepage.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef _RAR_LARGEPAGE_
|
||||
#define _RAR_LARGEPAGE_
|
||||
|
||||
class LargePageAlloc
|
||||
{
|
||||
private:
|
||||
static constexpr const wchar *LOCKMEM_SWITCH=L"isetup_privilege_lockmem";
|
||||
|
||||
void* new_large(size_t Size);
|
||||
bool delete_large(void *Addr);
|
||||
#ifdef _WIN_ALL
|
||||
std::vector<void*> LargeAlloc;
|
||||
SIZE_T PageSize;
|
||||
#endif
|
||||
bool UseLargePages;
|
||||
public:
|
||||
LargePageAlloc();
|
||||
void AllowLargePages(bool Allow);
|
||||
static bool IsPrivilegeAssigned();
|
||||
static bool AssignPrivilege();
|
||||
static bool AssignPrivilegeBySid(const std::wstring &Sid);
|
||||
static bool AssignConfirmation();
|
||||
|
||||
static bool ProcessSwitch(CommandData *Cmd,const wchar *Switch)
|
||||
{
|
||||
if (Switch[0]==LOCKMEM_SWITCH[0])
|
||||
{
|
||||
size_t Length=wcslen(LOCKMEM_SWITCH);
|
||||
if (wcsncmp(Switch,LOCKMEM_SWITCH,Length)==0)
|
||||
{
|
||||
LargePageAlloc::AssignPrivilegeBySid(Switch+Length);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T> T* new_l(size_t Size,bool Clear=false)
|
||||
{
|
||||
T *Allocated=(T*)new_large(Size*sizeof(T));
|
||||
if (Allocated==nullptr)
|
||||
Allocated=Clear ? new T[Size]{} : new T[Size];
|
||||
return Allocated;
|
||||
}
|
||||
|
||||
template <class T> void delete_l(T *Addr)
|
||||
{
|
||||
if (!delete_large(Addr))
|
||||
delete[] Addr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
232
unrar/list.cpp
232
unrar/list.cpp
@@ -1,7 +1,6 @@
|
||||
#include "rar.hpp"
|
||||
|
||||
static void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare);
|
||||
static void ListSymLink(Archive &Arc);
|
||||
static void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare,bool DisableNames);
|
||||
static void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize);
|
||||
static void ListOldSubHeader(Archive &Arc);
|
||||
static void ListNewSubHeader(CommandData *Cmd,Archive &Arc);
|
||||
@@ -15,20 +14,17 @@ void ListArchive(CommandData *Cmd)
|
||||
bool Bare=(Cmd->Command[1]=='B');
|
||||
bool Verbose=(Cmd->Command[0]=='V');
|
||||
|
||||
wchar ArcName[NM];
|
||||
while (Cmd->GetArcName(ArcName,ASIZE(ArcName)))
|
||||
std::wstring ArcName;
|
||||
while (Cmd->GetArcName(ArcName))
|
||||
{
|
||||
if (Cmd->ManualPassword)
|
||||
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;
|
||||
while (1)
|
||||
while (true)
|
||||
{
|
||||
int64 TotalPackSize=0,TotalUnpSize=0;
|
||||
uint FileCount=0;
|
||||
@@ -38,38 +34,47 @@ void ListArchive(CommandData *Cmd)
|
||||
if (!Bare)
|
||||
{
|
||||
Arc.ViewComment();
|
||||
mprintf(L"\n%s: %s",St(MListArchive),Arc.FileName);
|
||||
mprintf(L"\n%s: %s",St(MListArchive),Arc.FileName.c_str());
|
||||
|
||||
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");
|
||||
mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", Fmt);
|
||||
const wchar *Fmt=Arc.Format==RARFMT14 ? L"RAR 1.4":(Arc.Format==RARFMT15 ? L"RAR 1.5":L"RAR 5");
|
||||
mprintf(L"%s", Fmt);
|
||||
if (Arc.Solid)
|
||||
mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListSolid));
|
||||
mprintf(L", %s", St(MListSolid));
|
||||
if (Arc.SFXSize>0)
|
||||
mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListSFX));
|
||||
mprintf(L", %s", St(MListSFX));
|
||||
if (Arc.Volume)
|
||||
if (Arc.Format==RARFMT50)
|
||||
{
|
||||
// RAR 5.0 archives store the volume number in main header,
|
||||
// so it is already available now.
|
||||
if (SetCount++ > 0)
|
||||
mprintf(L", ");
|
||||
mprintf(L", ");
|
||||
mprintf(St(MVolumeNumber),Arc.VolNumber+1);
|
||||
}
|
||||
else
|
||||
mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListVolume));
|
||||
mprintf(L", %s", St(MListVolume));
|
||||
if (Arc.Protected)
|
||||
mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListRR));
|
||||
mprintf(L", %s", St(MListRR));
|
||||
if (Arc.Locked)
|
||||
mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListLock));
|
||||
mprintf(L", %s", St(MListLock));
|
||||
if (Arc.Encrypted)
|
||||
mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListEncHead));
|
||||
mprintf(L", %s", 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");
|
||||
}
|
||||
|
||||
wchar VolNumText[50];
|
||||
*VolNumText=0;
|
||||
while(Arc.ReadHeader()>0)
|
||||
while (Arc.ReadHeader()>0)
|
||||
{
|
||||
Wait(); // Allow quit listing with Ctrl+C.
|
||||
HEADER_TYPE HeaderType=Arc.GetHeaderType();
|
||||
@@ -92,10 +97,10 @@ void ListArchive(CommandData *Cmd)
|
||||
switch(HeaderType)
|
||||
{
|
||||
case HEAD_FILE:
|
||||
FileMatched=Cmd->IsProcessFile(Arc.FileHead,NULL,MATCH_WILDSUBPATH,0,NULL,0)!=0;
|
||||
FileMatched=Cmd->IsProcessFile(Arc.FileHead,NULL,MATCH_WILDSUBPATH,0,NULL)!=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;
|
||||
@@ -105,10 +110,21 @@ void ListArchive(CommandData *Cmd)
|
||||
}
|
||||
break;
|
||||
case HEAD_SERVICE:
|
||||
// For service blocks dependent on previous block, such as ACL
|
||||
// or NTFS stream, we use "file matched" flag of host file.
|
||||
// Independent blocks like RR are matched separately,
|
||||
// so we can list them by their name. Also we match even
|
||||
// dependent blocks separately if "vta -idn" are set. User may
|
||||
// want to see service blocks only in this case.
|
||||
if (!Arc.SubHead.SubBlock || Cmd->DisableNames)
|
||||
FileMatched=Cmd->IsProcessFile(Arc.SubHead,NULL,MATCH_WILDSUBPATH,0,NULL)!=0;
|
||||
if (FileMatched && !Bare)
|
||||
{
|
||||
// Here we set DisableNames parameter to true regardless of
|
||||
// Cmd->DisableNames. If "vta -idn" are set together, user
|
||||
// wants to see service blocks like RR only.
|
||||
if (Technical && ShowService)
|
||||
ListFileHeader(Arc,Arc.SubHead,TitleShown,Verbose,true,false);
|
||||
ListFileHeader(Arc,Arc.SubHead,TitleShown,Verbose,true,false,false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -125,15 +141,15 @@ void ListArchive(CommandData *Cmd)
|
||||
|
||||
if (Verbose)
|
||||
{
|
||||
mprintf(L"\n----------- --------- -------- ----- ---------- ----- -------- ----");
|
||||
mprintf(L"\n%21ls %9ls %3d%% %-27ls %u",UnpSizeText,
|
||||
mprintf(L"\n----------- ---------- ---------- ----- ---------- ----- -------- ----");
|
||||
mprintf(L"\n%22ls %10ls %3d%% %-27ls %u",UnpSizeText,
|
||||
PackSizeText,ToPercentUnlim(TotalPackSize,TotalUnpSize),
|
||||
VolNumText,FileCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
mprintf(L"\n----------- --------- ---------- ----- ----");
|
||||
mprintf(L"\n%21ls %-16ls %u",UnpSizeText,VolNumText,FileCount);
|
||||
mprintf(L"\n----------- ---------- ---------- ----- ----");
|
||||
mprintf(L"\n%22ls %-16ls %u",UnpSizeText,VolNumText,FileCount);
|
||||
}
|
||||
|
||||
SumFileCount+=FileCount;
|
||||
@@ -147,7 +163,7 @@ void ListArchive(CommandData *Cmd)
|
||||
ArcCount++;
|
||||
|
||||
#ifndef NOVOLUME
|
||||
if (Cmd->VolSize!=0 && (Arc.FileHead.SplitAfter ||
|
||||
if (Cmd->VolSize==VOLSIZE_AUTO && (Arc.FileHead.SplitAfter ||
|
||||
Arc.GetHeaderType()==HEAD_ENDARC && Arc.EndArcHead.NextVolume) &&
|
||||
MergeArchive(Arc,NULL,false,Cmd->Command[0]))
|
||||
Arc.Seek(0,SEEK_SET);
|
||||
@@ -158,7 +174,7 @@ void ListArchive(CommandData *Cmd)
|
||||
else
|
||||
{
|
||||
if (Cmd->ArcNames.ItemsCount()<2 && !Bare)
|
||||
mprintf(St(MNotRAR),Arc.FileName);
|
||||
mprintf(St(MNotRAR),Arc.FileName.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -188,9 +204,30 @@ enum LISTCOL_TYPE {
|
||||
};
|
||||
|
||||
|
||||
void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare)
|
||||
void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare,bool DisableNames)
|
||||
{
|
||||
wchar *Name=hd.FileName;
|
||||
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;
|
||||
|
||||
const wchar *Name=hd.FileName.c_str();
|
||||
RARFORMAT Format=Arc.Format;
|
||||
|
||||
if (Bare)
|
||||
@@ -199,21 +236,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));
|
||||
@@ -238,7 +260,7 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
|
||||
if (hd.SplitAfter)
|
||||
wcsncpyz(RatioStr,L"-->",ASIZE(RatioStr));
|
||||
else
|
||||
swprintf(RatioStr,ASIZE(RatioStr),L"%d%%",ToPercentUnlim(hd.PackSize,hd.UnpSize));
|
||||
swprintf(RatioStr,ASIZE(RatioStr),L"%u%%",ToPercentUnlim(hd.PackSize,hd.UnpSize));
|
||||
|
||||
wchar DateStr[50];
|
||||
hd.mtime.GetText(DateStr,ASIZE(DateStr),Technical);
|
||||
@@ -252,9 +274,8 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
|
||||
if (!FileBlock && Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM))
|
||||
{
|
||||
mprintf(L"\n%12ls: %ls",St(MListType),St(MListStream));
|
||||
wchar StreamName[NM];
|
||||
GetStreamNameNTFS(Arc,StreamName,ASIZE(StreamName));
|
||||
mprintf(L"\n%12ls: %ls",St(MListTarget),StreamName);
|
||||
std::wstring StreamName=GetStreamNameNTFS(Arc);
|
||||
mprintf(L"\n%12ls: %ls",St(MListTarget),StreamName.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -278,43 +299,57 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
|
||||
if (hd.RedirType!=FSREDIR_NONE)
|
||||
if (Format==RARFMT15)
|
||||
{
|
||||
char LinkTargetA[NM];
|
||||
std::string LinkTargetA;
|
||||
if (Arc.FileHead.Encrypted)
|
||||
{
|
||||
// Link data are encrypted. We would need to ask for password
|
||||
// and initialize decryption routine to display the link target.
|
||||
strncpyz(LinkTargetA,"*<-?->",ASIZE(LinkTargetA));
|
||||
LinkTargetA="*<-?->";
|
||||
}
|
||||
else
|
||||
{
|
||||
int DataSize=(int)Min(hd.PackSize,ASIZE(LinkTargetA)-1);
|
||||
Arc.Read(LinkTargetA,DataSize);
|
||||
LinkTargetA[DataSize > 0 ? DataSize : 0] = 0;
|
||||
size_t DataSize=(size_t)Min(hd.PackSize,MAXPATHSIZE);
|
||||
std::vector<char> Buf(DataSize+1);
|
||||
Arc.Read(Buf.data(),DataSize);
|
||||
Buf[DataSize] = 0;
|
||||
LinkTargetA=Buf.data();
|
||||
}
|
||||
wchar LinkTarget[NM];
|
||||
CharToWide(LinkTargetA,LinkTarget,ASIZE(LinkTarget));
|
||||
mprintf(L"\n%12ls: %ls",St(MListTarget),LinkTarget);
|
||||
std::wstring LinkTarget;
|
||||
CharToWide(LinkTargetA,LinkTarget);
|
||||
mprintf(L"\n%12ls: %ls",St(MListTarget),LinkTarget.c_str());
|
||||
}
|
||||
else
|
||||
mprintf(L"\n%12ls: %ls",St(MListTarget),hd.RedirName);
|
||||
mprintf(L"\n%12ls: %ls",St(MListTarget),hd.RedirName.c_str());
|
||||
}
|
||||
if (!hd.Dir)
|
||||
{
|
||||
mprintf(L"\n%12ls: %ls",St(MListSize),UnpSizeText);
|
||||
mprintf(L"\n%12ls: %ls",St(MListPacked),PackSizeText);
|
||||
mprintf(L"\n%12ls: %ls",St(MListRatio),RatioStr);
|
||||
|
||||
if (!FileBlock && Arc.SubHead.CmpName(SUBHEAD_TYPE_RR))
|
||||
{
|
||||
// Display the original -rrN percent if available.
|
||||
int RecoveryPercent=Arc.GetRecoveryPercent();
|
||||
if (RecoveryPercent>0) // It can be -1 if failed to detect.
|
||||
mprintf(L"\n%12ls: %u%%",L"RR%", RecoveryPercent);
|
||||
}
|
||||
}
|
||||
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)
|
||||
@@ -323,11 +358,11 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
|
||||
hd.FileHash.CRC32);
|
||||
if (hd.FileHash.Type==HASH_BLAKE2)
|
||||
{
|
||||
wchar BlakeStr[BLAKE2_DIGEST_SIZE*2+1];
|
||||
BinToHex(hd.FileHash.Digest,BLAKE2_DIGEST_SIZE,NULL,BlakeStr,ASIZE(BlakeStr));
|
||||
std::wstring BlakeStr;
|
||||
BinToHex(hd.FileHash.Digest,BLAKE2_DIGEST_SIZE,BlakeStr);
|
||||
mprintf(L"\n%12ls: %ls",
|
||||
hd.UseHashKey ? L"BLAKE2 MAC":hd.SplitAfter ? L"Pack-BLAKE2":L"BLAKE2",
|
||||
BlakeStr);
|
||||
BlakeStr.c_str());
|
||||
}
|
||||
|
||||
const wchar *HostOS=L"";
|
||||
@@ -344,11 +379,22 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
|
||||
if (*HostOS!=0)
|
||||
mprintf(L"\n%12ls: %ls",St(MListHostOS),HostOS);
|
||||
|
||||
mprintf(L"\n%12ls: RAR %ls(v%d) -m%d -md=%d%s",St(MListCompInfo),
|
||||
std::wstring WinSize;
|
||||
if (!hd.Dir)
|
||||
if (hd.WinSize%1073741824==0)
|
||||
WinSize=L" -md=" + std::to_wstring(hd.WinSize/1073741824) + L"g";
|
||||
else
|
||||
if (hd.WinSize%1048576==0)
|
||||
WinSize=L" -md=" + std::to_wstring(hd.WinSize/1048576) + L"m";
|
||||
else
|
||||
if (hd.WinSize>=1024)
|
||||
WinSize=L" -md=" + std::to_wstring(hd.WinSize/1024) + L"k";
|
||||
else
|
||||
WinSize=L" -md=?";
|
||||
|
||||
mprintf(L"\n%12ls: RAR %ls(v%d) -m%d%s",St(MListCompInfo),
|
||||
Format==RARFMT15 ? L"1.5":L"5.0",
|
||||
hd.UnpVer==VER_UNKNOWN ? 0 : hd.UnpVer,hd.Method,
|
||||
hd.WinSize>=0x100000 ? hd.WinSize/0x100000:hd.WinSize/0x400,
|
||||
hd.WinSize>=0x100000 ? L"M":L"K");
|
||||
hd.UnpVer==VER_UNKNOWN ? 0 : hd.UnpVer,hd.Method,WinSize.c_str());
|
||||
|
||||
if (hd.Solid || hd.Encrypted)
|
||||
{
|
||||
@@ -361,7 +407,7 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
|
||||
|
||||
if (hd.Version)
|
||||
{
|
||||
uint Version=ParseVersionFileName(Name,false);
|
||||
uint Version=ParseVersionFileName(hd.FileName,false);
|
||||
if (Version!=0)
|
||||
mprintf(L"\n%12ls: %u",St(MListFileVer),Version);
|
||||
}
|
||||
@@ -370,25 +416,27 @@ 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).c_str());
|
||||
else
|
||||
if (hd.UnixOwnerNumeric)
|
||||
mprintf(L"#%d",hd.UnixOwnerID);
|
||||
mprintf(L":");
|
||||
if (*hd.UnixGroupName!=0)
|
||||
mprintf(L"%ls",GetWide(hd.UnixGroupName));
|
||||
if ((*hd.UnixOwnerName!=0 || *hd.UnixGroupName!=0) && (hd.UnixOwnerNumeric || hd.UnixGroupNumeric))
|
||||
mprintf(L" ");
|
||||
if (hd.UnixOwnerNumeric)
|
||||
mprintf(L"#%d:",hd.UnixOwnerID);
|
||||
if (hd.UnixGroupNumeric)
|
||||
mprintf(L"#%d:",hd.UnixGroupID);
|
||||
mprintf(L"%ls",GetWide(hd.UnixGroupName).c_str());
|
||||
else
|
||||
if (hd.UnixGroupNumeric)
|
||||
mprintf(L"#%d",hd.UnixGroupID);
|
||||
}
|
||||
|
||||
mprintf(L"\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mprintf(L"\n%c%10ls %9ls ",hd.Encrypted ? '*' : ' ',AttrStr,UnpSizeText);
|
||||
// 2025.12.01: Size field width incremented to properly align 1+ GB sizes.
|
||||
mprintf(L"\n%c%10ls %10ls ",hd.Encrypted ? '*' : ' ',AttrStr,UnpSizeText);
|
||||
|
||||
if (Verbose)
|
||||
mprintf(L"%9ls %4ls ",PackSizeText,RatioStr);
|
||||
mprintf(L"%10ls %4ls ",PackSizeText,RatioStr);
|
||||
|
||||
mprintf(L" %ls ",DateStr);
|
||||
|
||||
@@ -403,31 +451,11 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
|
||||
mprintf(L"%02x%02x..%02x ",S[0],S[1],S[31]);
|
||||
}
|
||||
else
|
||||
mprintf(L"???????? ");
|
||||
mprintf(hd.Dir ? L" ":L"???????? "); // Missing checksum is ok for folder, not for file.
|
||||
}
|
||||
mprintf(L"%ls",Name);
|
||||
}
|
||||
|
||||
/*
|
||||
void ListSymLink(Archive &Arc)
|
||||
{
|
||||
if (Arc.FileHead.HSType==HSYS_UNIX && (Arc.FileHead.FileAttr & 0xF000)==0xA000)
|
||||
if (Arc.FileHead.Encrypted)
|
||||
{
|
||||
// Link data are encrypted. We would need to ask for password
|
||||
// and initialize decryption routine to display the link target.
|
||||
mprintf(L"\n%22ls %ls",L"-->",L"*<-?->");
|
||||
}
|
||||
else
|
||||
{
|
||||
char FileName[NM];
|
||||
uint DataSize=(uint)Min(Arc.FileHead.PackSize,sizeof(FileName)-1);
|
||||
Arc.Read(FileName,DataSize);
|
||||
FileName[DataSize]=0;
|
||||
mprintf(L"\n%22ls %ls",L"-->",GetWide(FileName));
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize)
|
||||
{
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
#define MYesNoAllRenQ L"_Yes_No_All_nEver_Rename_Quit"
|
||||
#define MContinueQuit L"_Continue_Quit"
|
||||
#define MRetryAbort L"_Retry_Abort"
|
||||
#define MCopyright L"\nRAR %s Copyright (c) 1993-%d Alexander Roshal %d %s %d"
|
||||
#define MIgnoreAllRetryQuit L"_Ignore_iGnore all_Retry_Quit"
|
||||
#define MCopyright L"\nRAR %s Copyright (c) 1993-%d Alexander Roshal %d %.3s %d"
|
||||
#define MRegTo L"\nRegistered to %s\n"
|
||||
#define MShare L"\nTrial version Type 'rar -?' for help\n"
|
||||
#define MRegKeyWarning L"\nAvailable license key is valid only for %s\n"
|
||||
@@ -12,21 +13,29 @@
|
||||
#define MBeta L"beta"
|
||||
#define Mx86 L"x86"
|
||||
#define Mx64 L"x64"
|
||||
#define MMonthJan L"Jan"
|
||||
#define MMonthFeb L"Feb"
|
||||
#define MMonthMar L"Mar"
|
||||
#define MMonthApr L"Apr"
|
||||
#define MMonthJan L"January"
|
||||
#define MMonthFeb L"February"
|
||||
#define MMonthMar L"March"
|
||||
#define MMonthApr L"April"
|
||||
#define MMonthMay L"May"
|
||||
#define MMonthJun L"Jun"
|
||||
#define MMonthJul L"Jul"
|
||||
#define MMonthAug L"Aug"
|
||||
#define MMonthSep L"Sep"
|
||||
#define MMonthOct L"Oct"
|
||||
#define MMonthNov L"Nov"
|
||||
#define MMonthDec L"Dec"
|
||||
#define MMonthJun L"June"
|
||||
#define MMonthJul L"July"
|
||||
#define MMonthAug L"August"
|
||||
#define MMonthSep L"September"
|
||||
#define MMonthOct L"October"
|
||||
#define MMonthNov L"November"
|
||||
#define MMonthDec L"December"
|
||||
#define MWeekDayMon L"Monday"
|
||||
#define MWeekDayTue L"Tuesday"
|
||||
#define MWeekDayWed L"Wednesday"
|
||||
#define MWeekDayThu L"Thursday"
|
||||
#define MWeekDayFri L"Friday"
|
||||
#define MWeekDaySat L"Saturday"
|
||||
#define MWeekDaySun L"Sunday"
|
||||
#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"
|
||||
@@ -54,9 +63,10 @@
|
||||
#define MCHelpSwm L"\n - Stop switches scanning"
|
||||
#define MCHelpSwAT L"\n @[+] Disable [enable] file lists"
|
||||
#define MCHelpSwAC L"\n ac Clear Archive attribute after compression or extraction"
|
||||
#define MCHelpSwAD L"\n ad Append archive name to destination path"
|
||||
#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"
|
||||
@@ -71,15 +81,15 @@
|
||||
#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"
|
||||
#define MCHelpSwIDP L"\n id[c,d,p,q] Disable messages"
|
||||
#define MCHelpSwIDP L"\n id[c,d,n,p,q] Display or disable messages"
|
||||
#define MCHelpSwIEML L"\n ieml[addr] Send archive by email"
|
||||
#define MCHelpSwIERR L"\n ierr Send all messages to stderr"
|
||||
#define MCHelpSwILOG L"\n ilog[name] Log errors to file"
|
||||
@@ -91,9 +101,10 @@
|
||||
#define MCHelpSwKB L"\n kb Keep broken extracted files"
|
||||
#define MCHelpSwLog L"\n log[f][=name] Write names to log file"
|
||||
#define MCHelpSwMn L"\n m<0..5> Set compression level (0-store...3-default...5-maximal)"
|
||||
#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 MCHelpSwMD L"\n md[x]<n>[kmg] Dictionary size in KB, MB or GB"
|
||||
#define MCHelpSwME L"\n me[par] Set encryption parameters"
|
||||
#define MCHelpSwMLP L"\n mlp Use large memory pages"
|
||||
#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"
|
||||
@@ -103,13 +114,14 @@
|
||||
#define MCHelpSwOC L"\n oc Set NTFS Compressed attribute"
|
||||
#define MCHelpSwOH L"\n oh Save hard links as the link instead of the file"
|
||||
#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 MCHelpSwOL L"\n ol[a,-] Process symbolic links as the link [absolute paths, skip]"
|
||||
#define MCHelpSwOM L"\n om[-|1][=lst] Propagate Mark of the Web"
|
||||
#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"
|
||||
@@ -117,15 +129,14 @@
|
||||
#define MCHelpSwRI L"\n ri<P>[:<S>] Set priority (0-default,1-min..15-max) and sleep time in ms"
|
||||
#define MCHelpSwRR L"\n rr[N] Add data recovery record"
|
||||
#define MCHelpSwRV L"\n rv[N] Create recovery volumes"
|
||||
#define MCHelpSwS L"\n s[<N>,v[-],e] Create solid archive"
|
||||
#define MCHelpSwSm L"\n s- Disable solid archiving"
|
||||
#define MCHelpSwS L"\n s[=<par>] Create solid archive"
|
||||
#define MCHelpSwSC L"\n sc<chr>[obj] Specify the character set"
|
||||
#define MCHelpSwSFX L"\n sfx[name] Create SFX archive"
|
||||
#define MCHelpSwSI L"\n si[name] Read data from standard input (stdin)"
|
||||
#define MCHelpSwSL L"\n sl<size> Process files with size less than specified"
|
||||
#define MCHelpSwSM L"\n sm<size> Process files with size more than specified"
|
||||
#define MCHelpSwSL L"\n sl<size>[u] Process files with size less than specified"
|
||||
#define MCHelpSwSM L"\n sm<size>[u] Process files with size more than specified"
|
||||
#define MCHelpSwT L"\n t Test files after archiving"
|
||||
#define MCHelpSwTK L"\n tk Keep original archive time"
|
||||
#define MCHelpSwTK L"\n tk[<date>] Keep the original or set the specified archive time"
|
||||
#define MCHelpSwTL L"\n tl Set archive time to latest file"
|
||||
#define MCHelpSwTN L"\n tn[mcao]<t> Process files newer than <t> time"
|
||||
#define MCHelpSwTO L"\n to[mcao]<t> Process files older than <t> time"
|
||||
@@ -135,10 +146,9 @@
|
||||
#define MCHelpSwU L"\n u Update files"
|
||||
#define MCHelpSwV L"\n v Create volumes with size autodetection or list all volumes"
|
||||
#define MCHelpSwVUnr L"\n v List all volumes"
|
||||
#define MCHelpSwVn L"\n v<size>[k,b] Create volumes with size=<size>*1000 [*1024, *1]"
|
||||
#define MCHelpSwVn L"\n v<size>[u] Create volumes with size in [bBkKmMgGtT] units"
|
||||
#define MCHelpSwVD L"\n vd Erase disk contents before creating volume"
|
||||
#define MCHelpSwVER L"\n ver[n] File version control"
|
||||
#define MCHelpSwVN L"\n vn Use the old style volume naming scheme"
|
||||
#define MCHelpSwVP L"\n vp Pause before each volume"
|
||||
#define MCHelpSwW L"\n w<path> Assign work directory"
|
||||
#define MCHelpSwX L"\n x<file> Exclude specified file"
|
||||
@@ -161,7 +171,7 @@
|
||||
#define MErrRename L"\nCannot rename %s to %s"
|
||||
#define MAbsNextVol L"\nCannot find volume %s"
|
||||
#define MBreak L"\nUser break\n"
|
||||
#define MAskCreatVol L"\nCreate next volume ?"
|
||||
#define MAskCreatVol L"\nCreate next volume?"
|
||||
#define MAskNextDisk L"\nDisk full. Insert next"
|
||||
#define MCreatVol L"\n\nCreating %sarchive %s\n"
|
||||
#define MAskNextVol L"\nInsert disk with %s"
|
||||
@@ -206,9 +216,9 @@
|
||||
#define MAddAnalyze L"\nAnalyzing archived files: "
|
||||
#define MRepacking L"\nRepacking archived files: "
|
||||
#define MCRCFailed L"\n%-20s - checksum error"
|
||||
#define MExtrTest L"\n\nTesting archive %s\n"
|
||||
#define MExtracting L"\n\nExtracting from %s\n"
|
||||
#define MUseCurPsw L"\n%s - use current password ?"
|
||||
#define MExtrTest L"\nTesting archive %s\n"
|
||||
#define MExtracting L"\nExtracting from %s\n"
|
||||
#define MUseCurPsw L"\n%s - use current password?"
|
||||
#define MCreatDir L"\nCreating %-56s"
|
||||
#define MExtrSkipFile L"\nSkipping %-56s"
|
||||
#define MExtrTestFile L"\nTesting %-56s"
|
||||
@@ -221,18 +231,17 @@
|
||||
#define MExtrAllOk L"\nAll OK"
|
||||
#define MExtrTotalErr L"\nTotal errors: %ld"
|
||||
#define MAskReplace L"\n\nWould you like to replace the existing file %s\n%6s bytes, modified on %s\nwith a new one\n%6s bytes, modified on %s\n"
|
||||
#define MAskOverwrite L"\nOverwrite %s ?"
|
||||
#define MAskOverwrite L"\nOverwrite %s?"
|
||||
#define MAskNewName L"\nEnter new name: "
|
||||
#define MHeaderBroken L"\nCorrupt header is found"
|
||||
#define MMainHeaderBroken L"\nMain archive header is corrupt"
|
||||
#define MLogFileHead L"\n%s - the file header is corrupt"
|
||||
#define MLogProtectHead L"The data recovery header is corrupt"
|
||||
#define MArcComment L"\nArchive comment"
|
||||
#define MReadStdinCmt L"\nReading comment from stdin\n"
|
||||
#define MReadCommFrom L"\nReading comment from %s"
|
||||
#define MDelComment L"\nDeleting comment from %s"
|
||||
#define MAddComment L"\nAdding comment to %s"
|
||||
#define MFCommAdd L"\nAdding file comments"
|
||||
#define MAskFComm L"\n\nReading comment for %s : %s from stdin\n"
|
||||
#define MDelComment L"\nDeleting a comment from %s"
|
||||
#define MAddComment L"\nAdding a comment to %s"
|
||||
#define MLogCommBrk L"\nThe archive comment is corrupt"
|
||||
#define MCommAskCont L"\nPress 'Enter' to continue or 'Q' to quit:"
|
||||
#define MWriteCommTo L"\nWrite comment to %s"
|
||||
@@ -252,8 +261,8 @@
|
||||
#define MListLock L"lock"
|
||||
#define MListEnc L"encrypted"
|
||||
#define MListEncHead L"encrypted headers"
|
||||
#define MListTitleL L" Attributes Size Date Time Name"
|
||||
#define MListTitleV L" Attributes Size Packed Ratio Date Time Checksum Name"
|
||||
#define MListTitleL L" Attributes Size Date Time Name"
|
||||
#define MListTitleV L" Attributes Size Packed Ratio Date Time Checksum Name"
|
||||
#define MListName L"Name"
|
||||
#define MListType L"Type"
|
||||
#define MListFile L"File"
|
||||
@@ -271,17 +280,18 @@
|
||||
#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"
|
||||
#define MListHostOS L"Host OS"
|
||||
#define MListFileVer L"File version"
|
||||
#define MListService L"Service"
|
||||
#define MListUOHead L"\n Unix Owner/Group data: %-14s %-14s"
|
||||
#define MListNTACLHead L"\n NTFS security data"
|
||||
#define MListStrmHead L"\n NTFS stream: %s"
|
||||
#define MListUnkHead L"\n Unknown subheader type: 0x%04x"
|
||||
#define MFileComment L"\nComment: "
|
||||
#define MYes L"Yes"
|
||||
#define MNo L"No"
|
||||
#define MListNoFiles L" 0 files\n"
|
||||
@@ -289,10 +299,10 @@
|
||||
#define MRprBuild L"\nBuilding %s"
|
||||
#define MRprOldFormat L"\nCannot repair archive with old format"
|
||||
#define MRprFind L"\nFound %s"
|
||||
#define MRprAskIsSol L"\nThe archive header is corrupt. Mark archive as solid ?"
|
||||
#define MRprAskIsSol L"\nThe archive header is corrupt. Mark archive as solid?"
|
||||
#define MRprNoFiles L"\nNo files found"
|
||||
#define MLogUnexpEOF L"\nUnexpected end of archive"
|
||||
#define MRepAskReconst L"\nReconstruct archive structure ?"
|
||||
#define MRepAskReconst L"\nReconstruct archive structure?"
|
||||
#define MRRSearch L"\nSearching for recovery record"
|
||||
#define MAnalyzeFileData L"\nAnalyzing file data"
|
||||
#define MRecRNotFound L"\nData recovery record not found"
|
||||
@@ -300,7 +310,7 @@
|
||||
#define MRecSecDamage L"\nSector %ld (offsets %lX...%lX) damaged"
|
||||
#define MRecCorrected L" - data recovered"
|
||||
#define MRecFailed L" - cannot recover data"
|
||||
#define MAddRecRec L"\nAdding data recovery record"
|
||||
#define MAddRecRec L"\nAdding the data recovery record"
|
||||
#define MEraseForVolume L"\n\nErasing contents of drive %c:\n"
|
||||
#define MGetOwnersError L"\nWARNING: Cannot get %s owner and group\n"
|
||||
#define MErrGetOwnerID L"\nWARNING: Cannot get owner %s ID\n"
|
||||
@@ -309,7 +319,7 @@
|
||||
#define MSetOwnersError L"\nWARNING: Cannot set %s owner and group\n"
|
||||
#define MErrLnkRead L"\nWARNING: Cannot read symbolic link %s"
|
||||
#define MSymLinkExists L"\nWARNING: Symbolic link %s already exists"
|
||||
#define MAskRetryCreate L"\nCannot create %s. Retry ?"
|
||||
#define MAskRetryCreate L"\nCannot create %s. Retry?"
|
||||
#define MDataBadCRC L"\n%-20s : packed data checksum error in volume %s"
|
||||
#define MFileRO L"\n%s is read-only"
|
||||
#define MACLGetError L"\nWARNING: Cannot get %s security data\n"
|
||||
@@ -319,14 +329,14 @@
|
||||
#define MStreamBroken L"\nERROR: %s stream data are corrupt\n"
|
||||
#define MStreamUnknown L"\nWARNING: Unknown format of %s stream data\n"
|
||||
#define MInvalidName L"\nERROR: Invalid file name %s"
|
||||
#define MProcessArc L"\n\nProcessing archive %s"
|
||||
#define MCorrectingName L"\nWARNING: Attempting to correct the invalid file name"
|
||||
#define MProcessArc L"\nProcessing archive %s"
|
||||
#define MCorrectingName L"\nWARNING: Attempting to correct the invalid file or directory name"
|
||||
#define MUnpCannotMerge L"\nWARNING: You need to start extraction from a previous volume to unpack %s"
|
||||
#define MUnknownOption L"\nERROR: Unknown option: %s"
|
||||
#define MSwSyntaxError L"\nERROR: '-' is expected in the beginning of: %s"
|
||||
#define MSubHeadCorrupt L"\nERROR: Corrupt data header found, ignored"
|
||||
#define MSubHeadUnknown L"\nWARNING: Unknown data header format, ignored"
|
||||
#define MSubHeadDataCRC L"\nERROR: Corrupt %s data block"
|
||||
#define MSubHeadType L"\nData header type: %s"
|
||||
#define MScanError L"\nCannot read contents of %s"
|
||||
#define MNotVolume L"\n%s is not volume"
|
||||
#define MRecVolDiffSets L"\nERROR: %s and %s belong to different sets"
|
||||
@@ -351,7 +361,7 @@
|
||||
#define MRecVolLimit L"\nTotal number of usual and recovery volumes must not exceed %d"
|
||||
#define MVolumeNumber L"volume %d"
|
||||
#define MCannotDelete L"\nCannot delete %s"
|
||||
#define MRecycleFailed L"\nCannot move some files and folders to Recycle Bin"
|
||||
#define MRecycleFailed L"\nCannot move some files and directories to Recycle Bin"
|
||||
#define MCalcCRC L"\nCalculating the checksum"
|
||||
#define MTooLargeSFXArc L"\nToo large SFX archive. Windows cannot run the executable file exceeding 4 GB."
|
||||
#define MCalcCRCAllVol L"\nCalculating checksums of all volumes."
|
||||
@@ -379,4 +389,28 @@
|
||||
#define MNeedAdmin L"\nYou may need to run RAR as administrator"
|
||||
#define MDictOutMem L"\nNot enough memory for %d MB compression dictionary, changed to %d MB."
|
||||
#define MUseSmalllerDict L"\nPlease use a smaller compression dictionary."
|
||||
#define MOpenErrAtime L"\nYou may need to remove -tsp switch to open this file."
|
||||
#define MExtrDictOutMem L"\nNot enough memory to unpack the archive with %u GB compression dictionary."
|
||||
#define MSuggest64bit L"\n64-bit RAR version is necessary."
|
||||
#define MOpenErrAtime L"\nYou may need to remove -tsp switch or run RAR as administrator to open this file."
|
||||
#define MErrReadInfo L"\nChoose 'Ignore' to continue with the already read file part only, 'Ignore all' to do it for all read errors, 'Retry' to repeat read and 'Quit' to abort."
|
||||
#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"
|
||||
#define MDictNotAllowed L"\n%u GB dictionary exceeds %u GB limit and needs more than %u GB memory to unpack."
|
||||
#define MDictExtrAnyway L"\nUse -md%ug or -mdx%ug switches to extract anyway."
|
||||
#define MDictComprLimit L"\n%u GB dictionary exceeds %u GB limit and not allowed when compressing data."
|
||||
#define MNeedSFX64 L"\n64-bit self-extracting module is necessary for %u GB compression dictionary."
|
||||
#define MSkipUnsafeLink L"\nSkipping the potentially unsafe %s -> %s link. For archives from a trustworthy source use -ola to extract it anyway."
|
||||
#define MTruncService L"\nTruncated at the service block: %s"
|
||||
#define MHeaderQO L"quick open information"
|
||||
#define MHeaderRR L"recovery record"
|
||||
#define MLockInMemoryNeeded L"-mlp switch requires ""Lock pages in memory"" privilege. Do you wish to assign it to the current user account?"
|
||||
#define MPrivilegeAssigned L"User privilege has been successfully assigned and will be activated after Windows restart. Restart now?"
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#include "rar.hpp"
|
||||
|
||||
|
||||
static wchar LogName[NM];
|
||||
static RAR_CHARSET LogCharset=RCH_DEFAULT;
|
||||
|
||||
void InitLogOptions(const wchar *LogFileName,RAR_CHARSET CSet)
|
||||
void InitLogOptions(const std::wstring &LogFileName,RAR_CHARSET CSet)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void CloseLogOptions()
|
||||
{
|
||||
wcsncpyz(LogName,LogFileName,ASIZE(LogName));
|
||||
LogCharset=CSet;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,17 +20,15 @@ void Log(const wchar *ArcName,const wchar *fmt,...)
|
||||
|
||||
uiAlarm(UIALARM_ERROR);
|
||||
|
||||
// This buffer is for format string only, not for entire output,
|
||||
// so it can be short enough.
|
||||
wchar fmtw[1024];
|
||||
PrintfPrepareFmt(fmt,fmtw,ASIZE(fmtw));
|
||||
|
||||
safebuf wchar Msg[2*NM+1024];
|
||||
va_list arglist;
|
||||
va_start(arglist,fmt);
|
||||
vswprintf(Msg,ASIZE(Msg),fmtw,arglist);
|
||||
|
||||
std::wstring s=vwstrprintf(fmt,arglist);
|
||||
|
||||
ReplaceEsc(s);
|
||||
|
||||
va_end(arglist);
|
||||
eprintf(L"%ls",Msg);
|
||||
eprintf(L"%ls",s.c_str());
|
||||
ErrHandler.SetSystemErrorCode(Code);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#ifndef _RAR_LOG_
|
||||
#define _RAR_LOG_
|
||||
|
||||
void InitLogOptions(const wchar *LogFileName,RAR_CHARSET CSet);
|
||||
void InitLogOptions(const std::wstring &LogFileName,RAR_CHARSET CSet);
|
||||
void CloseLogOptions();
|
||||
|
||||
#ifdef SILENT
|
||||
inline void Log(const wchar *ArcName,const wchar *fmt,...) {}
|
||||
|
||||
119
unrar/makefile
119
unrar/makefile
@@ -2,8 +2,11 @@
|
||||
# Makefile for UNIX - unrar
|
||||
|
||||
# Linux using GCC
|
||||
# 2024.08.19: -march=native isn't recognized on some platforms such as RISCV64.
|
||||
# Thus we removed it. Clang ARM users can add -march=armv8-a+crypto to enable
|
||||
# ARM NEON crypto.
|
||||
CXX=c++
|
||||
CXXFLAGS=-O2 -Wno-logical-op-parentheses -Wno-switch -Wno-dangling-else
|
||||
CXXFLAGS=-O2 -std=c++11 -Wno-logical-op-parentheses -Wno-switch -Wno-dangling-else
|
||||
LIBFLAGS=-fPIC
|
||||
DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -DRAR_SMP
|
||||
STRIP=strip
|
||||
@@ -11,107 +14,6 @@ AR=ar
|
||||
LDFLAGS=-pthread
|
||||
DESTDIR=/usr
|
||||
|
||||
# Linux using LCC
|
||||
#CXX=lcc
|
||||
#CXXFLAGS=-O2
|
||||
#DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
#STRIP=strip
|
||||
#AR=ar
|
||||
#DESTDIR=/usr
|
||||
|
||||
# CYGWIN using GCC
|
||||
#CXX=c++
|
||||
#CXXFLAGS=-O2
|
||||
#LIBFLAGS=
|
||||
#DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -DRAR_SMP
|
||||
#STRIP=strip
|
||||
#AR=ar
|
||||
#LDFLAGS=-pthread
|
||||
#DESTDIR=/usr
|
||||
|
||||
# HP UX using aCC
|
||||
#CXX=aCC
|
||||
#CXXFLAGS=-AA +O2 +Onolimit
|
||||
#DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
#STRIP=strip
|
||||
#AR=ar
|
||||
#DESTDIR=/usr
|
||||
|
||||
# IRIX using GCC
|
||||
#CXX=g++
|
||||
#CXXFLAGS=-O2
|
||||
#DEFINES=-DBIG_ENDIAN -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_BSD_COMPAT -D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED=1
|
||||
#STRIP=strip
|
||||
#AR=ar
|
||||
#DESTDIR=/usr
|
||||
|
||||
# IRIX using MIPSPro (experimental)
|
||||
#CXX=CC
|
||||
#CXXFLAGS=-O2 -mips3 -woff 1234,1156,3284 -LANG:std
|
||||
#DEFINES=-DBIG_ENDIAN -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_BSD_COMPAT -Dint64=int64_t
|
||||
#STRIP=strip
|
||||
#AR=ar
|
||||
#DESTDIR=/usr
|
||||
|
||||
# AIX using xlC (IBM VisualAge C++ 5.0)
|
||||
#CXX=xlC
|
||||
#CXXFLAGS=-O -qinline -qro -qroconst -qmaxmem=16384 -qcpluscmt
|
||||
#DEFINES=-D_LARGE_FILES -D_LARGE_FILE_API
|
||||
#LIBS=-lbsd
|
||||
#STRIP=strip
|
||||
#AR=ar
|
||||
#DESTDIR=/usr
|
||||
|
||||
# Solaris using CC
|
||||
#CXX=CC
|
||||
#CXXFLAGS=-fast -erroff=wvarhidemem
|
||||
#DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
#STRIP=strip
|
||||
#AR=ar
|
||||
#DESTDIR=/usr
|
||||
|
||||
# Solaris using GCC (optimized for UltraSPARC 1 CPU)
|
||||
#CXX=g++
|
||||
#CXXFLAGS=-O3 -mcpu=v9 -mtune=ultrasparc -m32
|
||||
#DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
#STRIP=/usr/ccs/bin/strip
|
||||
#AR=/usr/ccs/bin/ar
|
||||
#DESTDIR=/usr
|
||||
|
||||
# Tru64 5.1B using GCC3
|
||||
#CXX=g++
|
||||
#CXXFLAGS=-O2 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_XOPEN_SOURCE=500
|
||||
#STRIP=strip
|
||||
#AR=ar
|
||||
#LDFLAGS=-rpath /usr/local/gcc/lib
|
||||
#DESTDIR=/usr
|
||||
|
||||
# Tru64 5.1B using DEC C++
|
||||
#CXX=cxx
|
||||
#CXXFLAGS=-O4 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -Dint64=long
|
||||
#STRIP=strip
|
||||
#AR=ar
|
||||
#LDFLAGS=
|
||||
#DESTDIR=/usr
|
||||
|
||||
# QNX 6.x using GCC
|
||||
#CXX=g++
|
||||
#CXXFLAGS=-O2 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fexceptions
|
||||
#STRIP=strip
|
||||
#AR=ar
|
||||
#LDFLAGS=-fexceptions
|
||||
#DESTDIR=/usr
|
||||
|
||||
# Cross-compile
|
||||
# Linux using arm-linux-g++
|
||||
#CXX=arm-linux-g++
|
||||
#CXXFLAGS=-O2
|
||||
#DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
#STRIP=arm-linux-strip
|
||||
#AR=arm-linux-ar
|
||||
#LDFLAGS=-static
|
||||
#DESTDIR=/usr
|
||||
|
||||
##########################
|
||||
|
||||
COMPILE=$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(DEFINES)
|
||||
@@ -123,10 +25,10 @@ UNRAR_OBJ=filestr.o recvol.o rs.o scantree.o qopen.o
|
||||
LIB_OBJ=filestr.o scantree.o dll.o qopen.o
|
||||
|
||||
OBJECTS=rar.o strlist.o strfn.o pathfn.o smallfn.o global.o file.o filefn.o filcreat.o \
|
||||
archive.o arcread.o unicode.o system.o isnt.o crypt.o crc.o rawread.o encname.o \
|
||||
archive.o arcread.o unicode.o system.o crypt.o crc.o rawread.o encname.o \
|
||||
resource.o match.o timefn.o rdwrfn.o consio.o options.o errhnd.o rarvm.o secpassword.o \
|
||||
rijndael.o getbits.o sha1.o sha256.o blake2s.o hash.o extinfo.o extract.o volume.o \
|
||||
list.o find.o unpack.o headers.o threadpool.o rs16.o cmddata.o ui.o
|
||||
list.o find.o unpack.o headers.o threadpool.o rs16.o cmddata.o ui.o largepage.o
|
||||
|
||||
.cpp.o:
|
||||
$(COMPILE) -D$(WHAT) -c $<
|
||||
@@ -142,20 +44,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)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
static bool match(const wchar *pattern,const wchar *string,bool ForceCase);
|
||||
static int mwcsicompc(const wchar *Str1,const wchar *Str2,bool ForceCase);
|
||||
static int mwcsnicompc(const wchar *Str1,const wchar *Str2,size_t N,bool ForceCase);
|
||||
static bool IsWildcard(const wchar *Str,size_t CheckSize);
|
||||
|
||||
inline uint touppercw(uint ch,bool ForceCase)
|
||||
{
|
||||
@@ -16,12 +17,15 @@ inline uint touppercw(uint ch,bool ForceCase)
|
||||
}
|
||||
|
||||
|
||||
bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode)
|
||||
bool CmpName(const wchar *Wildcard,const wchar *Name,uint CmpMode)
|
||||
{
|
||||
bool ForceCase=(CmpMode&MATCH_FORCECASESENSITIVE)!=0;
|
||||
|
||||
CmpMode&=MATCH_MODEMASK;
|
||||
|
||||
wchar *Name1=PointToName(Wildcard);
|
||||
wchar *Name2=PointToName(Name);
|
||||
|
||||
if (CmpMode!=MATCH_NAMES)
|
||||
{
|
||||
size_t WildLength=wcslen(Wildcard);
|
||||
@@ -32,47 +36,48 @@ bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode)
|
||||
// "path1" mask must match "path1\path2\filename.ext" and "path1" names.
|
||||
wchar NextCh=Name[WildLength];
|
||||
if (NextCh==L'\\' || NextCh==L'/' || NextCh==0)
|
||||
return(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Nothing more to compare for MATCH_SUBPATHONLY.
|
||||
if (CmpMode==MATCH_SUBPATHONLY)
|
||||
return(false);
|
||||
return false;
|
||||
|
||||
// 2023.08.29: We tried std::wstring Path1 and Path2 here, but performance
|
||||
// impact for O(n^2) complexity loop in CmdExtract::AnalyzeArchive()
|
||||
// was rather noticeable, 1.7s instead of 0.9s when extracting ~300 files
|
||||
// with @listfile from archive with ~7000 files.
|
||||
// This function can be invoked from other O(n^2) loops. So for now
|
||||
// we prefer to avoid wstring and use pointers and path sizes here.
|
||||
// Another option could be using std::wstring_view.
|
||||
|
||||
wchar Path1[NM],Path2[NM];
|
||||
GetFilePath(Wildcard,Path1,ASIZE(Path1));
|
||||
GetFilePath(Name,Path2,ASIZE(Path2));
|
||||
size_t Path1Size=Name1-Wildcard;
|
||||
size_t Path2Size=Name2-Name;
|
||||
|
||||
if ((CmpMode==MATCH_EXACT || CmpMode==MATCH_EXACTPATH) &&
|
||||
mwcsicompc(Path1,Path2,ForceCase)!=0)
|
||||
return(false);
|
||||
if ((CmpMode==MATCH_EXACT || CmpMode==MATCH_EXACTPATH) &&
|
||||
(Path1Size!=Path2Size ||
|
||||
mwcsnicompc(Wildcard,Name,Path1Size,ForceCase)!=0))
|
||||
return false;
|
||||
if (CmpMode==MATCH_ALLWILD)
|
||||
return match(Wildcard,Name,ForceCase);
|
||||
if (CmpMode==MATCH_SUBPATH || CmpMode==MATCH_WILDSUBPATH)
|
||||
if (IsWildcard(Path1))
|
||||
return(match(Wildcard,Name,ForceCase));
|
||||
if (IsWildcard(Wildcard,Path1Size))
|
||||
return match(Wildcard,Name,ForceCase);
|
||||
else
|
||||
if (CmpMode==MATCH_SUBPATH || IsWildcard(Wildcard))
|
||||
{
|
||||
if (*Path1 && mwcsnicompc(Path1,Path2,wcslen(Path1),ForceCase)!=0)
|
||||
return(false);
|
||||
if (Path1Size>0 && mwcsnicompc(Wildcard,Name,Path1Size,ForceCase)!=0)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
if (mwcsicompc(Path1,Path2,ForceCase)!=0)
|
||||
return(false);
|
||||
if (Path1Size!=Path2Size || mwcsnicompc(Wildcard,Name,Path1Size,ForceCase)!=0)
|
||||
return false;
|
||||
}
|
||||
wchar *Name1=PointToName(Wildcard);
|
||||
wchar *Name2=PointToName(Name);
|
||||
|
||||
// Always return false for RAR temporary files to exclude them
|
||||
// from archiving operations.
|
||||
// if (mwcsnicompc(L"__rar_",Name2,6,false)==0)
|
||||
// return(false);
|
||||
|
||||
if (CmpMode==MATCH_EXACT)
|
||||
return(mwcsicompc(Name1,Name2,ForceCase)==0);
|
||||
return mwcsicompc(Name1,Name2,ForceCase)==0;
|
||||
|
||||
return(match(Name1,Name2,ForceCase));
|
||||
return match(Name1,Name2,ForceCase);
|
||||
}
|
||||
|
||||
|
||||
@@ -85,18 +90,18 @@ bool match(const wchar *pattern,const wchar *string,bool ForceCase)
|
||||
switch (patternc)
|
||||
{
|
||||
case 0:
|
||||
return(stringc==0);
|
||||
return stringc==0;
|
||||
case '?':
|
||||
if (stringc == 0)
|
||||
return(false);
|
||||
return false;
|
||||
break;
|
||||
case '*':
|
||||
if (*pattern==0)
|
||||
return(true);
|
||||
return true;
|
||||
if (*pattern=='.')
|
||||
{
|
||||
if (pattern[1]=='*' && pattern[2]==0)
|
||||
return(true);
|
||||
return true;
|
||||
const wchar *dot=wcschr(string,'.');
|
||||
if (pattern[1]==0)
|
||||
return (dot==NULL || dot[1]==0);
|
||||
@@ -104,22 +109,22 @@ bool match(const wchar *pattern,const wchar *string,bool ForceCase)
|
||||
{
|
||||
string=dot;
|
||||
if (wcspbrk(pattern,L"*?")==NULL && wcschr(string+1,'.')==NULL)
|
||||
return(mwcsicompc(pattern+1,string+1,ForceCase)==0);
|
||||
return mwcsicompc(pattern+1,string+1,ForceCase)==0;
|
||||
}
|
||||
}
|
||||
|
||||
while (*string)
|
||||
if (match(pattern,string++,ForceCase))
|
||||
return(true);
|
||||
return(false);
|
||||
return true;
|
||||
return false;
|
||||
default:
|
||||
if (patternc != stringc)
|
||||
{
|
||||
// Allow "name." mask match "name" and "name.\" match "name\".
|
||||
if (patternc=='.' && (stringc==0 || stringc=='\\' || stringc=='.'))
|
||||
return(match(pattern,string,ForceCase));
|
||||
return match(pattern,string,ForceCase);
|
||||
else
|
||||
return(false);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -145,3 +150,18 @@ int mwcsnicompc(const wchar *Str1,const wchar *Str2,size_t N,bool ForceCase)
|
||||
return wcsnicomp(Str1,Str2,N);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool IsWildcard(const wchar *Str,size_t CheckSize)
|
||||
{
|
||||
size_t CheckPos=0;
|
||||
#ifdef _WIN_ALL
|
||||
// Not treat the special NTFS \\?\d: path prefix as a wildcard.
|
||||
if (Str[0]=='\\' && Str[1]=='\\' && Str[2]=='?' && Str[3]=='\\')
|
||||
CheckPos+=4;
|
||||
#endif
|
||||
for (size_t I=CheckPos;I<CheckSize && Str[I]!=0;I++)
|
||||
if (Str[I]=='*' || Str[I]=='?')
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,11 @@ enum {
|
||||
#define MATCH_MODEMASK 0x0000ffff
|
||||
#define MATCH_FORCECASESENSITIVE 0x80000000
|
||||
|
||||
bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode);
|
||||
bool CmpName(const wchar *Wildcard,const wchar *Name,uint CmpMode);
|
||||
|
||||
inline bool CmpName(const std::wstring &Wildcard,const std::wstring &Name,uint CmpMode)
|
||||
{
|
||||
return CmpName(Wildcard.c_str(),Name.c_str(),CmpMode);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -339,13 +339,13 @@ inline void ModelPPM::UpdateModel()
|
||||
else
|
||||
{
|
||||
cf=4+(cf >= 9*sf)+(cf >= 12*sf)+(cf >= 15*sf);
|
||||
pc->U.SummFreq += cf;
|
||||
pc->U.SummFreq += (ushort)cf;
|
||||
}
|
||||
p=pc->U.Stats+ns1;
|
||||
p->Successor=Successor;
|
||||
p->Symbol = fs.Symbol;
|
||||
p->Freq = cf;
|
||||
pc->NumStats=++ns1;
|
||||
p->Freq = (byte)cf;
|
||||
pc->NumStats=(ushort)++ns1;
|
||||
}
|
||||
MaxContext=MinContext=fs.Successor;
|
||||
return;
|
||||
@@ -532,15 +532,17 @@ 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;
|
||||
psee2c->Summ += (ushort)Model->Coder.SubRange.scale;
|
||||
Model->NumMasked = NumStats;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -25,7 +25,7 @@ struct RARPPM_SEE2_CONTEXT : RARPPM_DEF
|
||||
}
|
||||
uint getMean()
|
||||
{
|
||||
uint RetVal=GET_SHORT16(Summ) >> Shift;
|
||||
short RetVal=GET_SHORT16(Summ) >> Shift;
|
||||
Summ -= RetVal;
|
||||
return RetVal+(RetVal == 0);
|
||||
}
|
||||
|
||||
134
unrar/motw.cpp
Normal file
134
unrar/motw.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
#include "rar.hpp"
|
||||
|
||||
/* Zone.Identifier stream can include the text like:
|
||||
|
||||
[ZoneTransfer]
|
||||
ZoneId=3
|
||||
HostUrl=https://site/path/file.ext
|
||||
ReferrerUrl=d:\path\archive.ext
|
||||
|
||||
Where ZoneId can be:
|
||||
|
||||
0 = My Computer
|
||||
1 = Local intranet
|
||||
2 = Trusted sites
|
||||
3 = Internet
|
||||
4 = Restricted sites
|
||||
*/
|
||||
|
||||
MarkOfTheWeb::MarkOfTheWeb()
|
||||
{
|
||||
ZoneIdValue=-1; // -1 indicates the missing MOTW.
|
||||
AllFields=false;
|
||||
}
|
||||
|
||||
|
||||
void MarkOfTheWeb::Clear()
|
||||
{
|
||||
ZoneIdValue=-1;
|
||||
}
|
||||
|
||||
|
||||
void MarkOfTheWeb::ReadZoneIdStream(const std::wstring &FileName,bool AllFields)
|
||||
{
|
||||
MarkOfTheWeb::AllFields=AllFields;
|
||||
ZoneIdValue=-1;
|
||||
ZoneIdStream.clear();
|
||||
|
||||
std::wstring StreamName=FileName+MOTW_STREAM_NAME;
|
||||
|
||||
File SrcFile;
|
||||
if (SrcFile.Open(StreamName))
|
||||
{
|
||||
ZoneIdStream.resize(MOTW_STREAM_MAX_SIZE);
|
||||
int BufSize=SrcFile.Read(&ZoneIdStream[0],ZoneIdStream.size());
|
||||
ZoneIdStream.resize(BufSize<0 ? 0:BufSize);
|
||||
|
||||
if (BufSize<=0)
|
||||
return;
|
||||
|
||||
ZoneIdValue=ParseZoneIdStream(ZoneIdStream);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 'Stream' contains the raw "Zone.Identifier" NTFS stream data on input
|
||||
// and either raw or cleaned stream data on output.
|
||||
int MarkOfTheWeb::ParseZoneIdStream(std::string &Stream)
|
||||
{
|
||||
if (!starts_with(Stream,"[ZoneTransfer]"))
|
||||
return -1; // Not a valid Mark of the Web. Prefer the archive MOTW if any.
|
||||
|
||||
std::string::size_type ZoneId=Stream.find("ZoneId=",0);
|
||||
if (ZoneId==std::string::npos || !IsDigit(Stream[ZoneId+7]))
|
||||
return -1; // Not a valid Mark of the Web.
|
||||
int ZoneIdValue=atoi(&Stream[ZoneId+7]);
|
||||
if (ZoneIdValue<0 || ZoneIdValue>4)
|
||||
return -1; // Not a valid Mark of the Web.
|
||||
|
||||
if (!AllFields)
|
||||
Stream="[ZoneTransfer]\r\nZoneId=" + std::to_string(ZoneIdValue) + "\r\n";
|
||||
|
||||
return ZoneIdValue;
|
||||
}
|
||||
|
||||
|
||||
void MarkOfTheWeb::CreateZoneIdStream(const std::wstring &Name,StringList &MotwList)
|
||||
{
|
||||
if (ZoneIdValue==-1)
|
||||
return;
|
||||
|
||||
size_t ExtPos=GetExtPos(Name);
|
||||
const wchar *Ext=ExtPos==std::wstring::npos ? L"":&Name[ExtPos+1];
|
||||
|
||||
bool Matched=false;
|
||||
const wchar *CurMask;
|
||||
MotwList.Rewind();
|
||||
while ((CurMask=MotwList.GetString())!=nullptr)
|
||||
{
|
||||
// Perform the fast extension comparison for simple *.ext masks.
|
||||
// Also we added the fast path to wcsicomp for English only strings.
|
||||
// When extracting 100000 files with "Exe and office" masks set
|
||||
// this loop spent 85ms with this optimization and wcsicomp optimized
|
||||
// for English strings, 415ms with this optimization only, 475ms with
|
||||
// wcsicomp optimized only and 795ms without both optimizations.
|
||||
bool FastCmp=CurMask[0]=='*' && CurMask[1]=='.' && wcspbrk(CurMask+2,L"*?")==NULL;
|
||||
if (FastCmp && wcsicomp(Ext,CurMask+2)==0 || !FastCmp && CmpName(CurMask,Name,MATCH_NAMES))
|
||||
{
|
||||
Matched=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Matched)
|
||||
return;
|
||||
|
||||
std::wstring StreamName=Name+MOTW_STREAM_NAME;
|
||||
|
||||
File StreamFile;
|
||||
if (StreamFile.Create(StreamName)) // Can fail on FAT.
|
||||
{
|
||||
// We got a report that write to stream failed on Synology 2411+ NAS drive.
|
||||
// So we handle it silently instead of aborting.
|
||||
StreamFile.SetExceptions(false);
|
||||
if (StreamFile.Write(&ZoneIdStream[0],ZoneIdStream.size()))
|
||||
StreamFile.Close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool MarkOfTheWeb::IsNameConflicting(const std::wstring &StreamName)
|
||||
{
|
||||
// We must use the case insensitive comparison for L":Zone.Identifier"
|
||||
// to catch specially crafted archived streams like L":zone.identifier".
|
||||
return wcsicomp(StreamName,MOTW_STREAM_NAME)==0 && ZoneIdValue!=-1;
|
||||
}
|
||||
|
||||
|
||||
// Return true and prepare the file stream to write if its ZoneId is stricter
|
||||
// than archive ZoneId. If it is missing, less or equally strict, return false.
|
||||
bool MarkOfTheWeb::IsFileStreamMoreSecure(std::string &FileStream)
|
||||
{
|
||||
int StreamZone=ParseZoneIdStream(FileStream);
|
||||
return StreamZone>ZoneIdValue;
|
||||
}
|
||||
26
unrar/motw.hpp
Normal file
26
unrar/motw.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef _RAR_MOTW_
|
||||
#define _RAR_MOTW_
|
||||
|
||||
class MarkOfTheWeb
|
||||
{
|
||||
private:
|
||||
const size_t MOTW_STREAM_MAX_SIZE=1024;
|
||||
const wchar* MOTW_STREAM_NAME=L":Zone.Identifier"; // Must start from ':'.
|
||||
|
||||
int ParseZoneIdStream(std::string &Stream);
|
||||
|
||||
std::string ZoneIdStream; // Store archive ":Zone.Identifier" NTFS stream data.
|
||||
int ZoneIdValue; // -1 if missing.
|
||||
bool AllFields; // Copy all MOTW fields or ZoneId only.
|
||||
public:
|
||||
MarkOfTheWeb();
|
||||
void Clear();
|
||||
void ReadZoneIdStream(const std::wstring &FileName,bool AllFields);
|
||||
void CreateZoneIdStream(const std::wstring &Name,StringList &MotwList);
|
||||
bool IsNameConflicting(const std::wstring &StreamName);
|
||||
bool IsFileStreamMoreSecure(std::string &FileStream);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -6,18 +6,11 @@ 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));
|
||||
WinSize=0x2000000;
|
||||
WinSizeLimit=0x100000000;
|
||||
Overwrite=OVERWRITE_DEFAULT;
|
||||
Method=3;
|
||||
MsgStream=MSG_STDOUT;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef _RAR_OPTIONS_
|
||||
#define _RAR_OPTIONS_
|
||||
|
||||
#define DEFAULT_RECOVERY -3
|
||||
#define DEFAULT_RECOVERY 3
|
||||
|
||||
#define DEFAULT_RECVOLUMES -10
|
||||
|
||||
@@ -15,10 +15,18 @@ enum PATH_EXCL_MODE {
|
||||
EXCL_ABSPATH // -ep3 (the full path with the disk letter)
|
||||
};
|
||||
|
||||
enum {SOLID_NONE=0,SOLID_NORMAL=1,SOLID_COUNT=2,SOLID_FILEEXT=4,
|
||||
SOLID_VOLUME_DEPENDENT=8,SOLID_VOLUME_INDEPENDENT=16};
|
||||
enum {
|
||||
SOLID_NONE=0, // Non-solid mode.
|
||||
SOLID_NORMAL=1, // Standard solid mode.
|
||||
SOLID_COUNT=2, // Reset the solid data after specified file count.
|
||||
SOLID_FILEEXT=4, // Reset the solid data for every new file extension.
|
||||
SOLID_VOLUME_DEPENDENT=8, // Preserve solid data in all volumes.
|
||||
SOLID_VOLUME_INDEPENDENT=16, // Reset solid data in all volumes.
|
||||
SOLID_RESET=32, // Reset solid data for newly added files.
|
||||
SOLID_BLOCK_SIZE=64 // Reset solid data after the specified size.
|
||||
};
|
||||
|
||||
enum {ARCTIME_NONE=0,ARCTIME_KEEP,ARCTIME_LATEST};
|
||||
enum ARCTIME_MODE {ARCTIME_NONE=0,ARCTIME_KEEP,ARCTIME_LATEST,ARCTIME_SPECIFIED};
|
||||
|
||||
enum EXTTIME_MODE {
|
||||
EXTTIME_NONE=0,EXTTIME_1S,EXTTIME_MAX
|
||||
@@ -33,7 +41,7 @@ enum RECURSE_MODE
|
||||
RECURSE_NONE=0, // no recurse switches
|
||||
RECURSE_DISABLE, // switch -r-
|
||||
RECURSE_ALWAYS, // switch -r
|
||||
RECURSE_WILDCARDS, // switch -r0
|
||||
RECURSE_WILDCARDS // switch -r0
|
||||
};
|
||||
|
||||
enum OVERWRITE_MODE
|
||||
@@ -45,13 +53,25 @@ 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 };
|
||||
enum QOPEN_MODE { QOPEN_NONE=0, QOPEN_AUTO, QOPEN_ALWAYS };
|
||||
|
||||
enum RAR_CHARSET { RCH_DEFAULT=0,RCH_ANSI,RCH_OEM,RCH_UNICODE,RCH_UTF8 };
|
||||
|
||||
#define MAX_FILTER_TYPES 16
|
||||
enum FilterState {FILTER_DEFAULT=0,FILTER_AUTO,FILTER_FORCE,FILTER_DISABLE};
|
||||
|
||||
enum FilterState {
|
||||
FILTER_DEFAULT=0, // No -mc<filter> switch.
|
||||
FILTER_AUTO, // -mc<filter> switch is present.
|
||||
FILTER_FORCE, // -mc<filter>+ switch is present.
|
||||
FILTER_DISABLE // -mc<filter>- switch is present.
|
||||
};
|
||||
|
||||
|
||||
enum SAVECOPY_MODE {
|
||||
@@ -61,7 +81,8 @@ enum SAVECOPY_MODE {
|
||||
|
||||
enum APPENDARCNAME_MODE
|
||||
{
|
||||
APPENDARCNAME_NONE=0,APPENDARCNAME_DESTPATH,APPENDARCNAME_OWNDIR
|
||||
APPENDARCNAME_NONE=0,APPENDARCNAME_DESTPATH,APPENDARCNAME_OWNSUBDIR,
|
||||
APPENDARCNAME_OWNDIR
|
||||
};
|
||||
|
||||
enum POWER_MODE {
|
||||
@@ -83,13 +104,15 @@ 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;
|
||||
uint InclFileAttr;
|
||||
|
||||
@@ -99,42 +122,40 @@ class RAROptions
|
||||
bool InclDir;
|
||||
|
||||
bool InclAttrSet;
|
||||
size_t WinSize;
|
||||
wchar TempPath[NM];
|
||||
wchar SFXModule[NM];
|
||||
uint64 WinSize;
|
||||
uint64 WinSizeLimit; // Switch -mdx<size>.
|
||||
|
||||
#ifdef USE_QOPEN
|
||||
QOPEN_MODE QOpenMode;
|
||||
#endif
|
||||
|
||||
bool ConfigDisabled; // Switch -cfg-.
|
||||
wchar ExtrPath[NM];
|
||||
wchar CommentFile[NM];
|
||||
RAR_CHARSET CommentCharset;
|
||||
RAR_CHARSET FilelistCharset;
|
||||
RAR_CHARSET ErrlogCharset;
|
||||
RAR_CHARSET RedirectCharset;
|
||||
|
||||
wchar ArcPath[NM];
|
||||
SecPassword Password;
|
||||
bool EncryptHeaders;
|
||||
bool SkipEncrypted;
|
||||
|
||||
bool ManualPassword; // Password entered manually during operation, might need to clean for next archive.
|
||||
|
||||
wchar LogName[NM];
|
||||
MESSAGE_TYPE MsgStream;
|
||||
SOUND_NOTIFY_MODE Sound;
|
||||
OVERWRITE_MODE Overwrite;
|
||||
int Method;
|
||||
HASH_TYPE HashType;
|
||||
int Recovery;
|
||||
uint Recovery;
|
||||
int RecVolNumber;
|
||||
ARC_METADATA ArcMetadata;
|
||||
bool DisablePercentage;
|
||||
bool DisableCopyright;
|
||||
bool DisableDone;
|
||||
bool DisableNames;
|
||||
bool PrintVersion;
|
||||
int Solid;
|
||||
int SolidCount;
|
||||
uint Solid;
|
||||
uint SolidCount;
|
||||
uint64 SolidBlockSize;
|
||||
bool ClearArc;
|
||||
bool AddArcOnly;
|
||||
bool DisableComment;
|
||||
@@ -143,19 +164,26 @@ class RAROptions
|
||||
PATH_EXCL_MODE ExclPath;
|
||||
RECURSE_MODE Recurse;
|
||||
int64 VolSize;
|
||||
Array<int64> NextVolSizes;
|
||||
uint CurVolNum;
|
||||
bool AllYes;
|
||||
bool MoreInfo; // -im, show more information, used only in "WinRAR t" now.
|
||||
bool VerboseOutput; // -iv, display verbose output, used only in "WinRAR t" now.
|
||||
bool DisableSortSolid;
|
||||
int ArcTime;
|
||||
int ConvertNames;
|
||||
bool ProcessOwners;
|
||||
bool SaveSymLinks;
|
||||
bool SaveHardLinks;
|
||||
bool AbsoluteLinks;
|
||||
bool SkipSymLinks;
|
||||
int Priority;
|
||||
int SleepTime;
|
||||
|
||||
bool UseLargePages;
|
||||
|
||||
// Quit after processing some system integration related switch,
|
||||
// like enabling the large memory pages privilege.
|
||||
// menu for non-admin user and quit.
|
||||
bool SetupComplete;
|
||||
|
||||
bool KeepBroken;
|
||||
bool OpenShared;
|
||||
bool DeleteFiles;
|
||||
@@ -173,6 +201,9 @@ class RAROptions
|
||||
bool SyncFiles;
|
||||
bool ProcessEA;
|
||||
bool SaveStreams;
|
||||
#ifdef PROPAGATE_MOTW
|
||||
bool MotwAllFields;
|
||||
#endif
|
||||
bool SetCompressedAttr;
|
||||
bool IgnoreGeneralAttr;
|
||||
RarTime FileMtimeBefore,FileCtimeBefore,FileAtimeBefore;
|
||||
@@ -185,7 +216,6 @@ class RAROptions
|
||||
bool Test;
|
||||
bool VolumePause;
|
||||
FilterMode FilterModes[MAX_FILTER_TYPES];
|
||||
wchar EmailTo[NM];
|
||||
uint VersionControl;
|
||||
APPENDARCNAME_MODE AppendArcNameToPath;
|
||||
POWER_MODE Shutdown;
|
||||
@@ -193,7 +223,6 @@ class RAROptions
|
||||
EXTTIME_MODE xctime;
|
||||
EXTTIME_MODE xatime;
|
||||
bool PreserveAtime;
|
||||
wchar CompressStdin[NM];
|
||||
|
||||
uint Threads; // We use it to init hash even if RAR_SMP is not defined.
|
||||
|
||||
@@ -202,7 +231,6 @@ class RAROptions
|
||||
|
||||
|
||||
#ifdef RARDLL
|
||||
wchar DllDestName[NM];
|
||||
int DllOpMode;
|
||||
int DllError;
|
||||
LPARAM UserData;
|
||||
@@ -210,5 +238,6 @@ class RAROptions
|
||||
CHANGEVOLPROC ChangeVolProc;
|
||||
PROCESSDATAPROC ProcessDataProc;
|
||||
#endif
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
119
unrar/os.hpp
119
unrar/os.hpp
@@ -4,24 +4,22 @@
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
#ifdef __EMX__
|
||||
#define INCL_BASE
|
||||
#endif
|
||||
|
||||
#if defined(RARDLL) && !defined(SILENT)
|
||||
#define SILENT
|
||||
#endif
|
||||
|
||||
|
||||
#include <new>
|
||||
|
||||
|
||||
#if defined(_WIN_ALL) || defined(_EMX)
|
||||
|
||||
#define LITTLE_ENDIAN
|
||||
#define NM 2048
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <memory> // For automatic pointers.
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef _WIN_ALL
|
||||
|
||||
#define LITTLE_ENDIAN
|
||||
|
||||
|
||||
// We got a report that just "#define STRICT" is incompatible with
|
||||
// "#define STRICT 1" in Windows 10 SDK minwindef.h and depending on the order
|
||||
@@ -36,12 +34,11 @@
|
||||
// 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
|
||||
#undef _WIN32_WINNT
|
||||
#define WINVER 0x0501
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#define WINVER _WIN32_WINNT_WINXP
|
||||
#define _WIN32_WINNT _WIN32_WINNT_WINXP
|
||||
|
||||
#if !defined(ZIPSFX)
|
||||
#define RAR_SMP
|
||||
@@ -55,35 +52,35 @@
|
||||
#pragma comment(lib, "Shlwapi.lib")
|
||||
#include <PowrProf.h>
|
||||
#pragma comment(lib, "PowrProf.lib")
|
||||
#include <psapi.h>
|
||||
#pragma comment(lib, "Psapi.lib") // For GetProcessMemoryInfo().
|
||||
#include <shellapi.h>
|
||||
#include <shlobj.h>
|
||||
#include <winioctl.h>
|
||||
#include <wincrypt.h>
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
#include <Sddl.h>
|
||||
#include <ntsecapi.h>
|
||||
|
||||
|
||||
#endif // _WIN_ALL
|
||||
// For WMI requests.
|
||||
#include <comdef.h>
|
||||
#include <Wbemidl.h>
|
||||
#pragma comment(lib, "wbemuuid.lib")
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dos.h>
|
||||
#include <direct.h>
|
||||
#include <intrin.h>
|
||||
|
||||
#if !defined(_EMX) && !defined(_MSC_VER)
|
||||
#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
|
||||
#else
|
||||
#include <dirent.h>
|
||||
#endif // _MSC_VER
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -96,7 +93,6 @@
|
||||
#include <time.h>
|
||||
#include <signal.h>
|
||||
|
||||
|
||||
#define SAVE_LINKS
|
||||
|
||||
#define ENABLE_ACCESS
|
||||
@@ -106,7 +102,7 @@
|
||||
|
||||
|
||||
#define SPATHDIVIDER L"\\"
|
||||
#define CPATHDIVIDER '\\'
|
||||
#define CPATHDIVIDER L'\\'
|
||||
#define MASKALL L"*"
|
||||
|
||||
#define READBINARY "rb"
|
||||
@@ -116,25 +112,13 @@
|
||||
#define WRITEBINARY "wb"
|
||||
#define APPENDTEXT "at"
|
||||
|
||||
#if defined(_WIN_ALL)
|
||||
#ifdef _MSC_VER
|
||||
#define _stdfunction __cdecl
|
||||
#define _forceinline __forceinline
|
||||
#else
|
||||
#define _stdfunction _USERENTRY
|
||||
#define _forceinline inline
|
||||
#endif
|
||||
#else
|
||||
#define _stdfunction
|
||||
#define _forceinline inline
|
||||
#endif
|
||||
#define _stdfunction __cdecl
|
||||
#define _forceinline __forceinline
|
||||
|
||||
#endif // defined(_WIN_ALL) || defined(_EMX)
|
||||
#endif // _WIN_ALL
|
||||
|
||||
#ifdef _UNIX
|
||||
|
||||
#define NM 2048
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -142,7 +126,7 @@
|
||||
#if defined(__QNXNTO__)
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#if defined(RAR_SMP) && defined(__APPLE__)
|
||||
#ifdef _APPLE
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
#ifndef SFX_MODULE
|
||||
@@ -155,6 +139,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h> // Needed for ptrdiff_t in some UnRAR source builds.
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
@@ -165,6 +150,28 @@
|
||||
#include <utime.h>
|
||||
#include <locale.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#include <x86intrin.h>
|
||||
|
||||
#define USE_SSE
|
||||
#define SSE_ALIGNMENT 16
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__aarch64__) && (defined(__ARM_FEATURE_CRYPTO) || defined(__ARM_FEATURE_CRC32))
|
||||
#include <arm_neon.h>
|
||||
#ifndef _APPLE
|
||||
#include <sys/auxv.h>
|
||||
#include <asm/hwcap.h>
|
||||
#endif
|
||||
#ifdef __ARM_FEATURE_CRYPTO
|
||||
#define USE_NEON_AES
|
||||
#endif
|
||||
#ifdef __ARM_FEATURE_CRC32
|
||||
#define USE_NEON_CRC32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef S_IFLNK
|
||||
#define SAVE_LINKS
|
||||
@@ -182,7 +189,7 @@
|
||||
|
||||
|
||||
#define SPATHDIVIDER L"/"
|
||||
#define CPATHDIVIDER '/'
|
||||
#define CPATHDIVIDER L'/'
|
||||
#define MASKALL L"*"
|
||||
|
||||
#define READBINARY "r"
|
||||
@@ -212,25 +219,23 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if _POSIX_C_SOURCE >= 200809L
|
||||
#ifdef __VMS
|
||||
# define LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
// 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
|
||||
|
||||
#endif // _UNIX
|
||||
|
||||
#if 0
|
||||
#define MSGID_INT
|
||||
typedef int MSGID;
|
||||
#else
|
||||
typedef const wchar* MSGID;
|
||||
#endif
|
||||
|
||||
#ifndef SSE_ALIGNMENT // No SSE use and no special data alignment is required.
|
||||
#define SSE_ALIGNMENT 1
|
||||
#endif
|
||||
|
||||
#define safebuf static
|
||||
|
||||
// Solaris defines _LITTLE_ENDIAN or _BIG_ENDIAN.
|
||||
#if defined(_LITTLE_ENDIAN) && !defined(LITTLE_ENDIAN)
|
||||
#define LITTLE_ENDIAN
|
||||
@@ -261,8 +266,8 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(BIG_ENDIAN) && defined(_WIN_ALL) || defined(__i386__) || defined(__x86_64__)
|
||||
// Allow not aligned integer access, increases speed in some operations.
|
||||
#if !defined(BIG_ENDIAN) && defined(_WIN_ALL) || defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
|
||||
// Allow unaligned integer access, increases speed in some operations.
|
||||
#define ALLOW_MISALIGNED
|
||||
#endif
|
||||
|
||||
|
||||
1147
unrar/pathfn.cpp
1147
unrar/pathfn.cpp
File diff suppressed because it is too large
Load Diff
110
unrar/pathfn.hpp
110
unrar/pathfn.hpp
@@ -2,40 +2,52 @@
|
||||
#define _RAR_PATHFN_
|
||||
|
||||
wchar* PointToName(const wchar *Path);
|
||||
std::wstring PointToName(const std::wstring &Path);
|
||||
size_t GetNamePos(const std::wstring &Path);
|
||||
wchar* PointToLastChar(const wchar *Path);
|
||||
wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath,size_t DestSize);
|
||||
void SetName(wchar *FullName,const wchar *Name,size_t MaxSize);
|
||||
void SetExt(wchar *Name,const wchar *NewExt,size_t MaxSize);
|
||||
void SetSFXExt(wchar *SFXName,size_t MaxSize);
|
||||
wchar GetLastChar(const std::wstring &Path);
|
||||
size_t ConvertPath(const std::wstring *SrcPath,std::wstring *DestPath);
|
||||
void SetName(std::wstring &FullName,const std::wstring &Name);
|
||||
void SetExt(std::wstring &Name,std::wstring NewExt);
|
||||
void RemoveExt(std::wstring &Name);
|
||||
void SetSFXExt(std::wstring &SFXName);
|
||||
wchar *GetExt(const wchar *Name);
|
||||
bool CmpExt(const wchar *Name,const wchar *Ext);
|
||||
bool IsWildcard(const wchar *Str);
|
||||
std::wstring GetExt(const std::wstring &Name);
|
||||
std::wstring::size_type GetExtPos(const std::wstring &Name);
|
||||
bool CmpExt(const std::wstring &Name,const std::wstring &Ext);
|
||||
bool IsWildcard(const std::wstring &Str);
|
||||
bool IsPathDiv(int Ch);
|
||||
bool IsDriveDiv(int Ch);
|
||||
bool IsDriveLetter(const wchar *Path);
|
||||
int GetPathDisk(const wchar *Path);
|
||||
void AddEndSlash(wchar *Path,size_t MaxLength);
|
||||
void MakeName(const wchar *Path,const wchar *Name,wchar *Pathname,size_t MaxSize);
|
||||
void GetFilePath(const wchar *FullName,wchar *Path,size_t MaxLength);
|
||||
void RemoveNameFromPath(wchar *Path);
|
||||
bool IsDriveLetter(const std::wstring &Path);
|
||||
int GetPathDisk(const std::wstring &Path);
|
||||
void AddEndSlash(std::wstring &Path);
|
||||
void MakeName(const std::wstring &Path,const std::wstring &Name,std::wstring &Pathname);
|
||||
void GetPathWithSep(const std::wstring &FullName,std::wstring &Path);
|
||||
void RemoveNameFromPath(std::wstring &Path);
|
||||
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
|
||||
bool GetAppDataPath(wchar *Path,size_t MaxSize,bool Create);
|
||||
void GetRarDataPath(wchar *Path,size_t MaxSize,bool Create);
|
||||
bool GetAppDataPath(std::wstring &Path,bool Create);
|
||||
void GetRarDataPath(std::wstring &Path,bool Create);
|
||||
#endif
|
||||
#ifdef _WIN_ALL
|
||||
bool SHGetPathStrFromIDList(PCIDLIST_ABSOLUTE pidl,std::wstring &Path);
|
||||
#endif
|
||||
#ifndef SFX_MODULE
|
||||
bool EnumConfigPaths(uint Number,wchar *Path,size_t MaxSize,bool Create);
|
||||
void GetConfigName(const wchar *Name,wchar *FullName,size_t MaxSize,bool CheckExist,bool Create);
|
||||
bool EnumConfigPaths(uint Number,std::wstring &Path,bool Create);
|
||||
void GetConfigName(const std::wstring &Name,std::wstring &FullName,bool CheckExist,bool Create);
|
||||
#endif
|
||||
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);
|
||||
size_t GetVolNumPos(const std::wstring &ArcName);
|
||||
void NextVolumeName(std::wstring &ArcName,bool OldNumbering);
|
||||
bool IsNameUsable(const std::wstring &Name);
|
||||
void MakeNameUsable(std::wstring &Name,bool Extended);
|
||||
|
||||
void UnixSlashToDos(const char *SrcName,char *DestName,size_t MaxLength);
|
||||
void DosSlashToUnix(const char *SrcName,char *DestName,size_t MaxLength);
|
||||
void UnixSlashToDos(const wchar *SrcName,wchar *DestName,size_t MaxLength);
|
||||
void UnixSlashToDos(const std::string &SrcName,std::string &DestName);
|
||||
void UnixSlashToDos(const std::wstring &SrcName,std::wstring &DestName);
|
||||
void DosSlashToUnix(const char *SrcName,char *DestName,size_t MaxLength);
|
||||
void DosSlashToUnix(const wchar *SrcName,wchar *DestName,size_t MaxLength);
|
||||
void DosSlashToUnix(const std::string &SrcName,std::string &DestName);
|
||||
void DosSlashToUnix(const std::wstring &SrcName,std::wstring &DestName);
|
||||
|
||||
inline void SlashToNative(const char *SrcName,char *DestName,size_t MaxLength)
|
||||
{
|
||||
@@ -46,6 +58,15 @@ inline void SlashToNative(const char *SrcName,char *DestName,size_t MaxLength)
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void SlashToNative(const std::string &SrcName,std::string &DestName)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
UnixSlashToDos(SrcName,DestName);
|
||||
#else
|
||||
DosSlashToUnix(SrcName,DestName);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void SlashToNative(const wchar *SrcName,wchar *DestName,size_t MaxLength)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
@@ -55,22 +76,45 @@ inline void SlashToNative(const wchar *SrcName,wchar *DestName,size_t MaxLength)
|
||||
#endif
|
||||
}
|
||||
|
||||
void ConvertNameToFull(const wchar *Src,wchar *Dest,size_t MaxSize);
|
||||
bool IsFullPath(const wchar *Path);
|
||||
bool IsFullRootPath(const wchar *Path);
|
||||
void GetPathRoot(const wchar *Path,wchar *Root,size_t MaxSize);
|
||||
int ParseVersionFileName(wchar *Name,bool Truncate);
|
||||
wchar* VolNameToFirstName(const wchar *VolName,wchar *FirstName,size_t MaxSize,bool NewNumbering);
|
||||
wchar* GetWideName(const char *Name,const wchar *NameW,wchar *DestW,size_t DestSize);
|
||||
inline void SlashToNative(const std::wstring &SrcName,std::wstring &DestName)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
UnixSlashToDos(SrcName,DestName);
|
||||
#else
|
||||
DosSlashToUnix(SrcName,DestName);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ConvertNameToFull(const std::wstring &Src,std::wstring &Dest);
|
||||
bool IsFullPath(const std::wstring &Path);
|
||||
bool IsFullRootPath(const std::wstring &Path);
|
||||
void GetPathRoot(const std::wstring &Path,std::wstring &Root);
|
||||
int ParseVersionFileName(std::wstring &Name,bool Truncate);
|
||||
size_t VolNameToFirstName(const std::wstring &VolName,std::wstring &FirstName,bool NewNumbering);
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
void GenerateArchiveName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,bool Archiving);
|
||||
void GenerateArchiveName(std::wstring &ArcName,const std::wstring &GenerateMask,bool Archiving);
|
||||
#endif
|
||||
|
||||
#ifdef _WIN_ALL
|
||||
bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize);
|
||||
void ConvertToPrecomposed(wchar *Name,size_t NameSize);
|
||||
void MakeNameCompatible(wchar *Name);
|
||||
bool GetWinLongPath(const std::wstring &Src,std::wstring &Dest);
|
||||
void ConvertToPrecomposed(std::wstring &Name);
|
||||
void MakeNameCompatible(std::wstring &Name);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _WIN_ALL
|
||||
std::wstring GetModuleFileStr();
|
||||
std::wstring GetProgramFile(const std::wstring &Name);
|
||||
#endif
|
||||
|
||||
#if defined(_WIN_ALL)
|
||||
bool SetCurDir(const std::wstring &Dir);
|
||||
#endif
|
||||
|
||||
#ifdef _WIN_ALL
|
||||
bool GetCurDir(std::wstring &Dir);
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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,
|
||||
@@ -114,7 +114,7 @@ void QuickOpen::Load(uint64 BlockPos)
|
||||
RawDataPos=0;
|
||||
ReadBufSize=0;
|
||||
ReadBufPos=0;
|
||||
LastReadHeader.Reset();
|
||||
LastReadHeader.clear();
|
||||
LastReadHeaderPos=0;
|
||||
|
||||
ReadBuffer();
|
||||
@@ -126,7 +126,7 @@ bool QuickOpen::Read(void *Data,size_t Size,size_t &Result)
|
||||
if (!Loaded)
|
||||
return false;
|
||||
// Find next suitable cached block.
|
||||
while (LastReadHeaderPos+LastReadHeader.Size()<=SeekPos)
|
||||
while (LastReadHeaderPos+LastReadHeader.size()<=SeekPos)
|
||||
if (!ReadNext())
|
||||
break;
|
||||
if (!Loaded)
|
||||
@@ -138,9 +138,9 @@ bool QuickOpen::Read(void *Data,size_t Size,size_t &Result)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SeekPos>=LastReadHeaderPos && SeekPos+Size<=LastReadHeaderPos+LastReadHeader.Size())
|
||||
if (SeekPos>=LastReadHeaderPos && SeekPos+Size<=LastReadHeaderPos+LastReadHeader.size())
|
||||
{
|
||||
memcpy(Data,LastReadHeader+size_t(SeekPos-LastReadHeaderPos),Size);
|
||||
memcpy(Data,&LastReadHeader[size_t(SeekPos-LastReadHeaderPos)],Size);
|
||||
Result=Size;
|
||||
SeekPos+=Size;
|
||||
UnsyncSeekPos=true;
|
||||
@@ -292,8 +292,8 @@ bool QuickOpen::ReadNext()
|
||||
size_t HeaderSize=(size_t)Raw.GetV();
|
||||
if (HeaderSize>MAX_HEADER_SIZE_RAR5)
|
||||
return false;
|
||||
LastReadHeader.Alloc(HeaderSize);
|
||||
Raw.GetB(&LastReadHeader[0],HeaderSize);
|
||||
LastReadHeader.resize(HeaderSize);
|
||||
Raw.GetB(LastReadHeader.data(),HeaderSize);
|
||||
// Calculate the absolute position as offset from quick open service header.
|
||||
LastReadHeaderPos=QOHeaderPos-Offset;
|
||||
return true;
|
||||
|
||||
@@ -43,7 +43,7 @@ class QuickOpen
|
||||
uint64 RawDataPos; // Current read position in QO data.
|
||||
size_t ReadBufSize; // Size of Buf data currently read from QO.
|
||||
size_t ReadBufPos; // Current read position in Buf data.
|
||||
Array<byte> LastReadHeader;
|
||||
std::vector<byte> LastReadHeader;
|
||||
uint64 LastReadHeaderPos;
|
||||
uint64 SeekPos;
|
||||
bool UnsyncSeekPos; // QOpen SeekPos does not match an actual file pointer.
|
||||
|
||||
@@ -12,11 +12,11 @@ int main(int argc, char *argv[])
|
||||
ErrHandler.SetSignalHandlers(true);
|
||||
|
||||
#ifdef SFX_MODULE
|
||||
wchar ModuleName[NM];
|
||||
std::wstring ModuleName;
|
||||
#ifdef _WIN_ALL
|
||||
GetModuleFileName(NULL,ModuleName,ASIZE(ModuleName));
|
||||
ModuleName=GetModuleFileStr();
|
||||
#else
|
||||
CharToWide(argv[0],ModuleName,ASIZE(ModuleName));
|
||||
CharToWide(argv[0],ModuleName);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -35,9 +35,10 @@ int main(int argc, char *argv[])
|
||||
try
|
||||
{
|
||||
|
||||
CommandData *Cmd=new CommandData;
|
||||
// Use std::unique_ptr to free Cmd in case of exception.
|
||||
std::unique_ptr<CommandData> Cmd(new CommandData);
|
||||
#ifdef SFX_MODULE
|
||||
wcsncpyz(Cmd->Command,L"X",ASIZE(Cmd->Command));
|
||||
Cmd->Command=L"X";
|
||||
char *Switch=argc>1 ? argv[1]:NULL;
|
||||
if (Switch!=NULL && Cmd->IsSwitch(Switch[0]))
|
||||
{
|
||||
@@ -46,7 +47,10 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
case 'T':
|
||||
case 'V':
|
||||
Cmd->Command[0]=UpperCmd;
|
||||
// Also copy 't' and 'a' modifiers for -v[t,a], if present.
|
||||
Cmd->Command.clear();
|
||||
for (char *c=Switch+1;*c!=0;c++)
|
||||
Cmd->Command+=etoupper(*c);
|
||||
break;
|
||||
case '?':
|
||||
Cmd->OutHelp(RARX_SUCCESS);
|
||||
@@ -68,7 +72,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
|
||||
ShutdownOnClose=Cmd->Shutdown;
|
||||
if (ShutdownOnClose)
|
||||
if (ShutdownOnClose!=POWERMODE_KEEP)
|
||||
ShutdownCheckAnother(true);
|
||||
#endif
|
||||
|
||||
@@ -78,7 +82,6 @@ int main(int argc, char *argv[])
|
||||
|
||||
Cmd->OutTitle();
|
||||
Cmd->ProcessCommand();
|
||||
delete Cmd;
|
||||
}
|
||||
catch (RAR_EXIT ErrCode)
|
||||
{
|
||||
@@ -100,6 +103,7 @@ int main(int argc, char *argv[])
|
||||
Shutdown(ShutdownOnClose);
|
||||
#endif
|
||||
ErrHandler.MainExit=true;
|
||||
CloseLogOptions();
|
||||
return ErrHandler.GetErrorCode();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -12,10 +12,11 @@
|
||||
#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 +29,14 @@
|
||||
#include "headers.hpp"
|
||||
#include "pathfn.hpp"
|
||||
#include "strfn.hpp"
|
||||
#include "strlist.hpp"
|
||||
#ifdef _WIN_ALL
|
||||
#include "isnt.hpp"
|
||||
#endif
|
||||
#ifdef PROPAGATE_MOTW
|
||||
#include "motw.hpp"
|
||||
#endif
|
||||
#include "file.hpp"
|
||||
#include "crc.hpp"
|
||||
#include "ui.hpp"
|
||||
#include "filefn.hpp"
|
||||
#include "filestr.hpp"
|
||||
#include "find.hpp"
|
||||
@@ -47,11 +49,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"
|
||||
@@ -62,6 +64,8 @@
|
||||
|
||||
#include "threadpool.hpp"
|
||||
|
||||
#include "largepage.hpp"
|
||||
|
||||
#include "unpack.hpp"
|
||||
|
||||
|
||||
@@ -85,9 +89,6 @@
|
||||
|
||||
#include "global.hpp"
|
||||
|
||||
#if 0
|
||||
#include "benchmark.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -9,17 +9,36 @@
|
||||
|
||||
#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
|
||||
// Set some arbitrary sensible limit to maximum path length to prevent
|
||||
// the excessive memory allocation for dynamically allocated strings.
|
||||
#define MAXPATHSIZE 0x10000
|
||||
|
||||
#define MAXSFXSIZE 0x400000
|
||||
|
||||
#define MAXCMTSIZE 0x40000
|
||||
|
||||
#ifdef _WIN_32
|
||||
#define DefSFXName L"default32.sfx"
|
||||
#else
|
||||
#define DefSFXName L"default.sfx"
|
||||
#endif
|
||||
#define DefSortListName L"rarfiles.lst"
|
||||
|
||||
// Maximum dictionary allowed by compression. Can be less than
|
||||
// maximum dictionary supported by decompression.
|
||||
#define PACK_MAX_DICT 0x1000000000ULL // 64 GB.
|
||||
|
||||
// Maximum dictionary allowed by decompression.
|
||||
#define UNPACK_MAX_DICT 0x1000000000ULL // 64 GB.
|
||||
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
#define USE_QOPEN
|
||||
@@ -28,4 +47,8 @@
|
||||
// Produce the value, which is equal or larger than 'v' and aligned to 'a'.
|
||||
#define ALIGN_VALUE(v,a) (size_t(v) + ( (~size_t(v) + 1) & (a - 1) ) )
|
||||
|
||||
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
|
||||
#define PROPAGATE_MOTW // Propagate the archive Mark of the Web.
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,15 +1,6 @@
|
||||
#ifndef _RAR_RAROS_
|
||||
#define _RAR_RAROS_
|
||||
|
||||
#ifdef __EMX__
|
||||
#define _EMX
|
||||
#endif
|
||||
|
||||
#ifdef __DJGPP__
|
||||
#define _DJGPP
|
||||
#define _EMX
|
||||
#endif
|
||||
|
||||
#if defined(__WIN32__) || defined(_WIN32)
|
||||
#define _WIN_ALL // Defined for all Windows platforms, 32 and 64 bit, mobile and desktop.
|
||||
#ifdef _M_X64
|
||||
@@ -29,7 +20,7 @@
|
||||
#define _APPLE
|
||||
#endif
|
||||
|
||||
#if !defined(_EMX) && !defined(_WIN_ALL) && !defined(_BEOS) && !defined(_APPLE)
|
||||
#if !defined(_WIN_ALL) && !defined(_UNIX)
|
||||
#define _UNIX
|
||||
#endif
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
typedef uint8_t byte; // Unsigned 8 bits.
|
||||
typedef uint16_t ushort; // Preferably 16 bits, but can be more.
|
||||
typedef unsigned int uint; // 32 bits or more.
|
||||
typedef unsigned int uint; // Preferably 32 bits, likely can be more.
|
||||
typedef uint32_t uint32; // 32 bits exactly.
|
||||
typedef int32_t int32; // Signed 32 bits exactly.
|
||||
typedef uint64_t uint64; // 64 bits exactly.
|
||||
|
||||
@@ -246,7 +246,7 @@ bool RarVM::ExecuteStandardFilter(VM_StandardFilters FilterType)
|
||||
}
|
||||
else
|
||||
Predicted=PrevByte;
|
||||
DestData[I]=PrevByte=(byte)(Predicted-*(SrcData++));
|
||||
PrevByte=DestData[I]=(byte)(Predicted-*(SrcData++));
|
||||
}
|
||||
}
|
||||
for (uint I=PosR,Border=DataSize-2;I<Border;I+=3)
|
||||
|
||||
@@ -43,7 +43,7 @@ inline void RawPut2(uint Field,void *Data)
|
||||
}
|
||||
|
||||
|
||||
inline void RawPut4(uint32 Field,void *Data)
|
||||
inline void RawPut4(uint Field,void *Data)
|
||||
{
|
||||
#if defined(BIG_ENDIAN) || !defined(ALLOW_MISALIGNED)
|
||||
byte *D=(byte *)Data;
|
||||
@@ -52,7 +52,7 @@ inline void RawPut4(uint32 Field,void *Data)
|
||||
D[2]=(byte)(Field>>16);
|
||||
D[3]=(byte)(Field>>24);
|
||||
#else
|
||||
*(uint32 *)Data=Field;
|
||||
*(uint32 *)Data=(uint32)Field;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -84,21 +84,35 @@ 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];
|
||||
return uint32(m[0])<<24 | uint32(m[1])<<16 | uint32(m[2])<<8 | m[3];
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Load 8 big endian bytes from memory and return uint64.
|
||||
inline uint64 RawGetBE8(const byte *m)
|
||||
{
|
||||
#if defined(USE_MEM_BYTESWAP) && defined(_MSC_VER)
|
||||
return _byteswap_uint64(*(uint64 *)m);
|
||||
#elif defined(USE_MEM_BYTESWAP) && (defined(__clang__) || defined(__GNUC__))
|
||||
return __builtin_bswap64(*(uint64 *)m);
|
||||
#else
|
||||
return uint64(m[0])<<56 | uint64(m[1])<<48 | uint64(m[2])<<40 | uint64(m[3])<<32 |
|
||||
uint64(m[4])<<24 | uint64(m[5])<<16 | uint64(m[6])<<8 | m[7];
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Save integer to memory as big endian.
|
||||
inline void RawPutBE4(uint32 i,byte *mem)
|
||||
inline void RawPutBE4(uint 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)
|
||||
*(uint32*)mem = __builtin_bswap32(i);
|
||||
*(uint32*)mem = _byteswap_ulong((uint32)i);
|
||||
#elif defined(USE_MEM_BYTESWAP) && (defined(__clang__) || defined(__GNUC__))
|
||||
*(uint32*)mem = __builtin_bswap32((uint32)i);
|
||||
#else
|
||||
mem[0]=byte(i>>24);
|
||||
mem[1]=byte(i>>16);
|
||||
@@ -108,15 +122,60 @@ inline void RawPutBE4(uint32 i,byte *mem)
|
||||
}
|
||||
|
||||
|
||||
// Save integer to memory as big endian.
|
||||
inline void RawPutBE8(uint64 i,byte *mem)
|
||||
{
|
||||
#if defined(USE_MEM_BYTESWAP) && defined(_MSC_VER)
|
||||
*(uint64*)mem = _byteswap_uint64(i);
|
||||
#elif defined(USE_MEM_BYTESWAP) && (defined(__clang__) || defined(__GNUC__))
|
||||
*(uint64*)mem = __builtin_bswap64(i);
|
||||
#else
|
||||
mem[0]=byte(i>>56);
|
||||
mem[1]=byte(i>>48);
|
||||
mem[2]=byte(i>>40);
|
||||
mem[3]=byte(i>>32);
|
||||
mem[4]=byte(i>>24);
|
||||
mem[5]=byte(i>>16);
|
||||
mem[6]=byte(i>>8);
|
||||
mem[7]=byte(i);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
inline bool IsPow2(uint64 n) // Check if 'n' is power of 2.
|
||||
{
|
||||
return (n & (n-1))==0;
|
||||
}
|
||||
|
||||
|
||||
inline uint64 GetGreaterOrEqualPow2(uint64 n)
|
||||
{
|
||||
uint64 p=1;
|
||||
while (p<n)
|
||||
p*=2;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
inline uint64 GetLessOrEqualPow2(uint64 n)
|
||||
{
|
||||
uint64 p=1;
|
||||
while (p*2<=n)
|
||||
p*=2;
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
RawRead::RawRead()
|
||||
{
|
||||
RawRead::SrcFile=NULL;
|
||||
RawRead::SrcFile=nullptr;
|
||||
Reset();
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ RawRead::RawRead(File *SrcFile)
|
||||
|
||||
void RawRead::Reset()
|
||||
{
|
||||
Data.SoftReset();
|
||||
Data.clear();
|
||||
ReadPos=0;
|
||||
DataSize=0;
|
||||
Crypt=NULL;
|
||||
@@ -31,7 +31,7 @@ size_t RawRead::Read(size_t Size)
|
||||
{
|
||||
// Full size of buffer with already read data including data read
|
||||
// for encryption block alignment.
|
||||
size_t FullSize=Data.Size();
|
||||
size_t FullSize=Data.size();
|
||||
|
||||
// Data read for alignment and not processed yet.
|
||||
size_t DataLeft=FullSize-DataSize;
|
||||
@@ -40,7 +40,7 @@ size_t RawRead::Read(size_t Size)
|
||||
{
|
||||
size_t SizeToRead=Size-DataLeft;
|
||||
size_t AlignedReadSize=SizeToRead+((~SizeToRead+1) & CRYPT_BLOCK_MASK);
|
||||
Data.Add(AlignedReadSize);
|
||||
Data.resize(FullSize+AlignedReadSize);
|
||||
ReadSize=SrcFile->Read(&Data[FullSize],AlignedReadSize);
|
||||
Crypt->DecryptBlock(&Data[FullSize],AlignedReadSize);
|
||||
DataSize+=ReadSize==0 ? 0:Size;
|
||||
@@ -55,7 +55,7 @@ size_t RawRead::Read(size_t Size)
|
||||
#endif
|
||||
if (Size!=0)
|
||||
{
|
||||
Data.Add(Size);
|
||||
Data.resize(Data.size()+Size);
|
||||
ReadSize=SrcFile->Read(&Data[DataSize],Size);
|
||||
DataSize+=ReadSize;
|
||||
}
|
||||
@@ -67,13 +67,24 @@ void RawRead::Read(byte *SrcData,size_t Size)
|
||||
{
|
||||
if (Size!=0)
|
||||
{
|
||||
Data.Add(Size);
|
||||
Data.resize(Data.size()+Size);
|
||||
memcpy(&Data[DataSize],SrcData,Size);
|
||||
DataSize+=Size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Move unread data to beginning of buffer and adjust buffer size.
|
||||
void RawRead::Compact()
|
||||
{
|
||||
if (ReadPos<DataSize) // We would access beyond the vector end otherwise.
|
||||
memmove(&Data[0],&Data[ReadPos],DataSize-ReadPos);
|
||||
DataSize-=ReadPos;
|
||||
ReadPos=0;
|
||||
Data.resize(DataSize);
|
||||
}
|
||||
|
||||
|
||||
byte RawRead::Get1()
|
||||
{
|
||||
return ReadPos<DataSize ? Data[ReadPos++]:0;
|
||||
@@ -96,8 +107,7 @@ uint RawRead::Get4()
|
||||
{
|
||||
if (ReadPos+3<DataSize)
|
||||
{
|
||||
uint Result=Data[ReadPos]+(Data[ReadPos+1]<<8)+(Data[ReadPos+2]<<16)+
|
||||
(Data[ReadPos+3]<<24);
|
||||
uint Result=RawGet4(&Data[ReadPos]);
|
||||
ReadPos+=4;
|
||||
return Result;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
class RawRead
|
||||
{
|
||||
private:
|
||||
Array<byte> Data;
|
||||
std::vector<byte> Data;
|
||||
File *SrcFile;
|
||||
size_t DataSize;
|
||||
size_t ReadPos;
|
||||
@@ -15,6 +15,7 @@ class RawRead
|
||||
void Reset();
|
||||
size_t Read(size_t Size);
|
||||
void Read(byte *SrcData,size_t Size);
|
||||
void Compact();
|
||||
byte Get1();
|
||||
ushort Get2();
|
||||
uint Get4();
|
||||
@@ -27,7 +28,7 @@ class RawRead
|
||||
uint GetCRC50();
|
||||
byte* GetDataPtr() {return &Data[0];}
|
||||
size_t Size() {return DataSize;}
|
||||
size_t PaddedSize() {return Data.Size()-DataSize;}
|
||||
size_t PaddedSize() {return Data.size()-DataSize;}
|
||||
size_t DataLeft() {return DataSize-ReadPos;}
|
||||
size_t GetPos() {return ReadPos;}
|
||||
void SetPos(size_t Pos) {ReadPos=Pos;}
|
||||
|
||||
121
unrar/rdwrfn.cpp
121
unrar/rdwrfn.cpp
@@ -16,6 +16,7 @@ void ComprDataIO::Init()
|
||||
UnpackFromMemory=false;
|
||||
UnpackToMemory=false;
|
||||
UnpPackedSize=0;
|
||||
UnpPackedLeft=0;
|
||||
ShowProgress=true;
|
||||
TestMode=false;
|
||||
SkipUnpCRC=false;
|
||||
@@ -35,7 +36,9 @@ void ComprDataIO::Init()
|
||||
SubHead=NULL;
|
||||
SubHeadPos=NULL;
|
||||
CurrentCommand=0;
|
||||
ProcessedArcSize=TotalArcSize=0;
|
||||
ProcessedArcSize=0;
|
||||
LastArcSize=0;
|
||||
TotalArcSize=0;
|
||||
}
|
||||
|
||||
|
||||
@@ -75,10 +78,10 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count)
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t SizeToRead=((int64)Count>UnpPackedSize) ? (size_t)UnpPackedSize:Count;
|
||||
size_t SizeToRead=((int64)Count>UnpPackedLeft) ? (size_t)UnpPackedLeft:Count;
|
||||
if (SizeToRead > 0)
|
||||
{
|
||||
if (UnpVolume && Decryption && (int64)Count>UnpPackedSize)
|
||||
if (UnpVolume && Decryption && (int64)Count>UnpPackedLeft)
|
||||
{
|
||||
// We need aligned blocks for decryption and we want "Keep broken
|
||||
// files" to work efficiently with missing encrypted volumes.
|
||||
@@ -109,7 +112,7 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count)
|
||||
ReadAddr+=ReadSize;
|
||||
Count-=ReadSize;
|
||||
#endif
|
||||
UnpPackedSize-=ReadSize;
|
||||
UnpPackedLeft-=ReadSize;
|
||||
|
||||
// Do not ask for next volume if we read something from current volume.
|
||||
// If next volume is missing, we need to process all data from current
|
||||
@@ -118,7 +121,7 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count)
|
||||
// we ask for next volume also if we have non-aligned encryption block.
|
||||
// Since we adjust data size for decryption earlier above,
|
||||
// it does not hurt "Keep broken files" mode efficiency.
|
||||
if (UnpVolume && UnpPackedSize == 0 &&
|
||||
if (UnpVolume && UnpPackedLeft == 0 &&
|
||||
(ReadSize==0 || Decryption && (TotalRead & CRYPT_BLOCK_MASK) != 0) )
|
||||
{
|
||||
#ifndef NOVOLUME
|
||||
@@ -134,7 +137,7 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count)
|
||||
}
|
||||
Archive *SrcArc=(Archive *)SrcFile;
|
||||
if (SrcArc!=NULL)
|
||||
ShowUnpRead(SrcArc->CurBlockPos+CurUnpRead,UnpArcSize);
|
||||
ShowUnpRead(SrcArc->NextBlockPos-UnpPackedSize+CurUnpRead,TotalArcSize);
|
||||
if (ReadSize!=-1)
|
||||
{
|
||||
ReadSize=TotalRead;
|
||||
@@ -148,18 +151,11 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count)
|
||||
}
|
||||
|
||||
|
||||
#if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
|
||||
// Disable the run time stack check for unrar.dll, so we can manipulate
|
||||
// with ProcessDataProc call type below. Run time check would intercept
|
||||
// a wrong ESP before we restore it.
|
||||
#pragma runtime_checks( "s", off )
|
||||
#endif
|
||||
|
||||
void ComprDataIO::UnpWrite(byte *Addr,size_t Count)
|
||||
{
|
||||
|
||||
#ifdef RARDLL
|
||||
RAROptions *Cmd=((Archive *)SrcFile)->GetRAROptions();
|
||||
CommandData *Cmd=((Archive *)SrcFile)->GetCommandData();
|
||||
if (Cmd->DllOpMode!=RAR_SKIP)
|
||||
{
|
||||
if (Cmd->Callback!=NULL &&
|
||||
@@ -167,28 +163,7 @@ void ComprDataIO::UnpWrite(byte *Addr,size_t Count)
|
||||
ErrHandler.Exit(RARX_USERBREAK);
|
||||
if (Cmd->ProcessDataProc!=NULL)
|
||||
{
|
||||
// Here we preserve ESP value. It is necessary for those developers,
|
||||
// who still define ProcessDataProc callback as "C" type function,
|
||||
// even though in year 2001 we announced in unrar.dll whatsnew.txt
|
||||
// that it will be PASCAL type (for compatibility with Visual Basic).
|
||||
#if defined(_MSC_VER)
|
||||
#ifndef _WIN_64
|
||||
__asm mov ebx,esp
|
||||
#endif
|
||||
#elif defined(_WIN_ALL) && defined(__BORLANDC__)
|
||||
_EBX=_ESP;
|
||||
#endif
|
||||
int RetCode=Cmd->ProcessDataProc(Addr,(int)Count);
|
||||
|
||||
// Restore ESP after ProcessDataProc with wrongly defined calling
|
||||
// convention broken it.
|
||||
#if defined(_MSC_VER)
|
||||
#ifndef _WIN_64
|
||||
__asm mov esp,ebx
|
||||
#endif
|
||||
#elif defined(_WIN_ALL) && defined(__BORLANDC__)
|
||||
_ESP=_EBX;
|
||||
#endif
|
||||
if (RetCode==0)
|
||||
ErrHandler.Exit(RARX_USERBREAK);
|
||||
}
|
||||
@@ -216,11 +191,6 @@ void ComprDataIO::UnpWrite(byte *Addr,size_t Count)
|
||||
Wait();
|
||||
}
|
||||
|
||||
#if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
|
||||
// Restore the run time stack check for unrar.dll.
|
||||
#pragma runtime_checks( "s", restore )
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -230,15 +200,11 @@ void ComprDataIO::ShowUnpRead(int64 ArcPos,int64 ArcSize)
|
||||
{
|
||||
if (ShowProgress && SrcFile!=NULL)
|
||||
{
|
||||
if (TotalArcSize!=0)
|
||||
{
|
||||
// important when processing several archives or multivolume archive
|
||||
ArcSize=TotalArcSize;
|
||||
ArcPos+=ProcessedArcSize;
|
||||
}
|
||||
// Important when processing several archives or multivolume archive.
|
||||
ArcPos+=ProcessedArcSize;
|
||||
|
||||
Archive *SrcArc=(Archive *)SrcFile;
|
||||
RAROptions *Cmd=SrcArc->GetRAROptions();
|
||||
CommandData *Cmd=SrcArc->GetCommandData();
|
||||
|
||||
int CurPercent=ToPercent(ArcPos,ArcSize);
|
||||
if (!Cmd->DisablePercentage && CurPercent!=LastPercent)
|
||||
@@ -280,28 +246,28 @@ void ComprDataIO::GetUnpackedData(byte **Data,size_t *Size)
|
||||
}
|
||||
|
||||
|
||||
void ComprDataIO::SetEncryption(bool Encrypt,CRYPT_METHOD Method,
|
||||
// Return true if encryption or decryption mode is set correctly.
|
||||
bool ComprDataIO::SetEncryption(bool Encrypt,CRYPT_METHOD Method,
|
||||
SecPassword *Password,const byte *Salt,const byte *InitV,
|
||||
uint Lg2Cnt,byte *HashKey,byte *PswCheck)
|
||||
{
|
||||
#ifndef RAR_NOCRYPT
|
||||
#ifdef RAR_NOCRYPT
|
||||
return false;
|
||||
#else
|
||||
if (Encrypt)
|
||||
{
|
||||
Encryption=Crypt->SetCryptKeys(true,Method,Password,Salt,InitV,Lg2Cnt,HashKey,PswCheck);
|
||||
return Encryption;
|
||||
}
|
||||
else
|
||||
{
|
||||
Decryption=Decrypt->SetCryptKeys(false,Method,Password,Salt,InitV,Lg2Cnt,HashKey,PswCheck);
|
||||
return Decryption;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if !defined(SFX_MODULE) && !defined(RAR_NOCRYPT)
|
||||
void ComprDataIO::SetAV15Encryption()
|
||||
{
|
||||
Decryption=true;
|
||||
Decrypt->SetAV15Encryption();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(SFX_MODULE) && !defined(RAR_NOCRYPT)
|
||||
void ComprDataIO::SetCmt13Encryption()
|
||||
{
|
||||
@@ -319,3 +285,42 @@ void ComprDataIO::SetUnpackToMemory(byte *Addr,uint Size)
|
||||
UnpackToMemoryAddr=Addr;
|
||||
UnpackToMemorySize=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.
|
||||
uint64 ArcLength=Arc->IsSeekable() ? Arc->FileLength() : 0;
|
||||
// QO is always preceding RR record.
|
||||
// Also we check QO and RR to be less than archive length to prevent
|
||||
// negative "ArcLength-LastArcSize" and possible signed integer overflow
|
||||
// when calculating TotalArcSize.
|
||||
if (Arc->MainHead.QOpenOffset>0 && Arc->MainHead.QOpenOffset<ArcLength)
|
||||
LastArcSize=Arc->MainHead.QOpenOffset;
|
||||
else
|
||||
if (Arc->MainHead.RROffset>0 && Arc->MainHead.RROffset<ArcLength)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
#ifndef _RAR_DATAIO_
|
||||
#define _RAR_DATAIO_
|
||||
|
||||
class Archive;
|
||||
class CmdAdd;
|
||||
class Unpack;
|
||||
class ArcFileSearch;
|
||||
|
||||
#if 0
|
||||
// We use external i/o calls for Benchmark command.
|
||||
#define COMPRDATAIO_EXTIO
|
||||
#endif
|
||||
|
||||
class ComprDataIO
|
||||
{
|
||||
@@ -29,6 +26,7 @@ class ComprDataIO
|
||||
byte *UnpWrAddr;
|
||||
|
||||
int64 UnpPackedSize;
|
||||
int64 UnpPackedLeft;
|
||||
|
||||
bool ShowProgress;
|
||||
bool TestMode;
|
||||
@@ -61,25 +59,24 @@ 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;}
|
||||
void SetFiles(File *SrcFile,File *DestFile);
|
||||
void SetCommand(CmdAdd *Cmd) {Command=Cmd;}
|
||||
void SetSubHeader(FileHeader *hd,int64 *Pos) {SubHead=hd;SubHeadPos=Pos;}
|
||||
void SetEncryption(bool Encrypt,CRYPT_METHOD Method,SecPassword *Password,
|
||||
bool SetEncryption(bool Encrypt,CRYPT_METHOD Method,SecPassword *Password,
|
||||
const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck);
|
||||
void SetAV15Encryption();
|
||||
void SetCmt13Encryption();
|
||||
void SetUnpackToMemory(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;
|
||||
|
||||
|
||||
@@ -87,6 +84,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.
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#include "rar.hpp"
|
||||
|
||||
|
||||
#include "recvol3.cpp"
|
||||
#include "recvol5.cpp"
|
||||
|
||||
|
||||
|
||||
bool RecVolumesRestore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
||||
bool RecVolumesRestore(CommandData *Cmd,const std::wstring &Name,bool Silent)
|
||||
{
|
||||
Archive Arc(Cmd);
|
||||
if (!Arc.Open(Name))
|
||||
@@ -42,24 +43,20 @@ 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 std::wstring &Name)
|
||||
{
|
||||
wchar RevName[NM];
|
||||
*RevName=0;
|
||||
if (Arc!=NULL)
|
||||
std::wstring RevName;
|
||||
if (Arc==NULL)
|
||||
RevName=Name;
|
||||
else
|
||||
{
|
||||
// We received .rar or .exe volume as a parameter, trying to find
|
||||
// the matching .rev file number 1.
|
||||
bool NewNumbering=Arc->NewNumbering;
|
||||
|
||||
wchar ArcName[NM];
|
||||
wcsncpyz(ArcName,Name,ASIZE(ArcName));
|
||||
|
||||
wchar *VolNumStart=VolNameToFirstName(ArcName,ArcName,ASIZE(ArcName),NewNumbering);
|
||||
wchar RecVolMask[NM];
|
||||
wcsncpyz(RecVolMask,ArcName,ASIZE(RecVolMask));
|
||||
size_t BaseNamePartLength=VolNumStart-ArcName;
|
||||
wcsncpyz(RecVolMask+BaseNamePartLength,L"*.rev",ASIZE(RecVolMask)-BaseNamePartLength);
|
||||
std::wstring RecVolMask;
|
||||
size_t VolNumStart=VolNameToFirstName(Name,RecVolMask,NewNumbering);
|
||||
RecVolMask.replace(VolNumStart, std::wstring::npos, L"*.rev");
|
||||
|
||||
FindFile Find;
|
||||
Find.SetMask(RecVolMask);
|
||||
@@ -67,31 +64,30 @@ void RecVolumesTest(RAROptions *Cmd,Archive *Arc,const wchar *Name)
|
||||
|
||||
while (Find.Next(&RecData))
|
||||
{
|
||||
wchar *Num=GetVolNumPart(RecData.Name);
|
||||
if (*Num!='1') // Name must have "0...01" numeric part.
|
||||
size_t NumPos=GetVolNumPos(RecData.Name);
|
||||
if (RecData.Name[NumPos]!='1') // Name must have "0...01" numeric part.
|
||||
continue;
|
||||
bool FirstVol=true;
|
||||
while (--Num>=RecData.Name && IsDigit(*Num))
|
||||
if (*Num!='0')
|
||||
while (NumPos>0 && IsDigit(RecData.Name[--NumPos]))
|
||||
if (RecData.Name[NumPos]!='0')
|
||||
{
|
||||
FirstVol=false;
|
||||
break;
|
||||
}
|
||||
if (FirstVol)
|
||||
{
|
||||
wcsncpyz(RevName,RecData.Name,ASIZE(RevName));
|
||||
Name=RevName;
|
||||
RevName=RecData.Name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*RevName==0) // First .rev file not found.
|
||||
if (RevName.empty()) // First .rev file not found.
|
||||
return;
|
||||
}
|
||||
|
||||
File RevFile;
|
||||
if (!RevFile.Open(Name))
|
||||
if (!RevFile.Open(RevName))
|
||||
{
|
||||
ErrHandler.OpenErrorMsg(Name); // It also sets RARX_OPEN.
|
||||
ErrHandler.OpenErrorMsg(RevName); // It also sets RARX_OPEN.
|
||||
return;
|
||||
}
|
||||
mprintf(L"\n");
|
||||
@@ -101,11 +97,11 @@ void RecVolumesTest(RAROptions *Cmd,Archive *Arc,const wchar *Name)
|
||||
if (Rev5)
|
||||
{
|
||||
RecVolumes5 RecVol(Cmd,true);
|
||||
RecVol.Test(Cmd,Name);
|
||||
RecVol.Test(Cmd,RevName);
|
||||
}
|
||||
else
|
||||
{
|
||||
RecVolumes3 RecVol(Cmd,true);
|
||||
RecVol.Test(Cmd,Name);
|
||||
RecVol.Test(Cmd,RevName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,24 +8,24 @@ class RecVolumes3
|
||||
{
|
||||
private:
|
||||
File *SrcFile[256];
|
||||
Array<byte> Buf;
|
||||
std::vector<byte> Buf;
|
||||
|
||||
#ifdef RAR_SMP
|
||||
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,std::wstring ArcName);
|
||||
bool Restore(CommandData *Cmd,const std::wstring &Name,bool Silent);
|
||||
void Test(CommandData *Cmd,const std::wstring &Name);
|
||||
};
|
||||
|
||||
|
||||
struct RecVolItem
|
||||
{
|
||||
File *f;
|
||||
wchar Name[NM];
|
||||
std::wstring Name;
|
||||
uint CRC;
|
||||
uint64 FileSize;
|
||||
bool New; // Newly created RAR volume.
|
||||
@@ -48,11 +48,11 @@ 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;
|
||||
std::vector<RecVolItem> RecItems;
|
||||
|
||||
byte *RealReadBuffer; // Real pointer returned by 'new'.
|
||||
byte *ReadBuffer; // Pointer aligned for SSE instructions.
|
||||
@@ -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 std::wstring &Name,bool Silent);
|
||||
void Test(CommandData *Cmd,const std::wstring &Name);
|
||||
};
|
||||
|
||||
bool RecVolumesRestore(RAROptions *Cmd,const wchar *Name,bool Silent);
|
||||
void RecVolumesTest(RAROptions *Cmd,Archive *Arc,const wchar *Name);
|
||||
bool RecVolumesRestore(CommandData *Cmd,const std::wstring &Name,bool Silent);
|
||||
void RecVolumesTest(CommandData *Cmd,Archive *Arc,const std::wstring &Name);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,12 +23,6 @@ class RSEncode // Encode or decode data area, one object per one thread.
|
||||
|
||||
|
||||
#ifdef RAR_SMP
|
||||
THREAD_PROC(RSEncodeThread)
|
||||
{
|
||||
RSEncode *rs=(RSEncode *)Data;
|
||||
rs->EncodeBuf();
|
||||
}
|
||||
|
||||
THREAD_PROC(RSDecodeThread)
|
||||
{
|
||||
RSEncode *rs=(RSEncode *)Data;
|
||||
@@ -36,7 +30,7 @@ THREAD_PROC(RSDecodeThread)
|
||||
}
|
||||
#endif
|
||||
|
||||
RecVolumes3::RecVolumes3(RAROptions *Cmd,bool TestOnly)
|
||||
RecVolumes3::RecVolumes3(CommandData *Cmd,bool TestOnly)
|
||||
{
|
||||
memset(SrcFile,0,sizeof(SrcFile));
|
||||
if (TestOnly)
|
||||
@@ -47,8 +41,7 @@ RecVolumes3::RecVolumes3(RAROptions *Cmd,bool TestOnly)
|
||||
}
|
||||
else
|
||||
{
|
||||
Buf.Alloc(TotalBufferSize);
|
||||
memset(SrcFile,0,sizeof(SrcFile));
|
||||
Buf.resize(TotalBufferSize);
|
||||
#ifdef RAR_SMP
|
||||
RSThreadPool=new ThreadPool(Cmd->Threads);
|
||||
#endif
|
||||
@@ -68,30 +61,16 @@ RecVolumes3::~RecVolumes3()
|
||||
|
||||
|
||||
|
||||
void RSEncode::EncodeBuf()
|
||||
{
|
||||
for (int BufPos=BufStart;BufPos<BufEnd;BufPos++)
|
||||
{
|
||||
byte Data[256],Code[256];
|
||||
for (int I=0;I<FileNumber;I++)
|
||||
Data[I]=Buf[I*RecBufferSize+BufPos];
|
||||
RSC.Encode(Data,FileNumber,Code);
|
||||
for (int I=0;I<RecVolNumber;I++)
|
||||
OutBuf[I*RecBufferSize+BufPos]=Code[I];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check for names like arc5_3_1.rev created by RAR 3.0.
|
||||
static bool IsNewStyleRev(const wchar *Name)
|
||||
static bool IsNewStyleRev(const std::wstring &Name)
|
||||
{
|
||||
wchar *Ext=GetExt(Name);
|
||||
if (Ext==NULL)
|
||||
size_t ExtPos=GetExtPos(Name);
|
||||
if (ExtPos==std::wstring::npos || ExtPos==0)
|
||||
return true;
|
||||
int DigitGroup=0;
|
||||
for (Ext--;Ext>Name;Ext--)
|
||||
if (!IsDigit(*Ext))
|
||||
if (*Ext=='_' && IsDigit(*(Ext-1)))
|
||||
for (ExtPos--;ExtPos>0;ExtPos--)
|
||||
if (!IsDigit(Name[ExtPos]))
|
||||
if (Name[ExtPos]=='_' && IsDigit(Name[ExtPos-1]))
|
||||
DigitGroup++;
|
||||
else
|
||||
break;
|
||||
@@ -99,19 +78,19 @@ static bool IsNewStyleRev(const wchar *Name)
|
||||
}
|
||||
|
||||
|
||||
bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
||||
bool RecVolumes3::Restore(CommandData *Cmd,const std::wstring &Name,bool Silent)
|
||||
{
|
||||
wchar ArcName[NM];
|
||||
wcsncpyz(ArcName,Name,ASIZE(ArcName));
|
||||
wchar *Ext=GetExt(ArcName);
|
||||
std::wstring ArcName=Name;
|
||||
bool NewStyle=false; // New style .rev volumes are supported since RAR 3.10.
|
||||
bool RevName=Ext!=NULL && wcsicomp(Ext,L".rev")==0;
|
||||
bool RevName=CmpExt(ArcName,L"rev");
|
||||
if (RevName)
|
||||
{
|
||||
NewStyle=IsNewStyleRev(ArcName);
|
||||
while (Ext>ArcName+1 && (IsDigit(*(Ext-1)) || *(Ext-1)=='_'))
|
||||
Ext--;
|
||||
wcsncpyz(Ext,L"*.*",ASIZE(ArcName)-(Ext-ArcName));
|
||||
|
||||
size_t ExtPos=GetExtPos(ArcName);
|
||||
while (ExtPos>1 && (IsDigit(ArcName[ExtPos-1]) || ArcName[ExtPos-1]=='_'))
|
||||
ExtPos--;
|
||||
ArcName.replace(ExtPos,std::wstring::npos,L"*.*");
|
||||
|
||||
FindFile Find;
|
||||
Find.SetMask(ArcName);
|
||||
@@ -121,7 +100,7 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
||||
Archive Arc(Cmd);
|
||||
if (Arc.WOpen(fd.Name) && Arc.IsArchive(true))
|
||||
{
|
||||
wcsncpyz(ArcName,fd.Name,ASIZE(ArcName));
|
||||
ArcName=fd.Name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -138,11 +117,10 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
||||
bool NewNumbering=Arc.NewNumbering;
|
||||
Arc.Close();
|
||||
|
||||
wchar *VolNumStart=VolNameToFirstName(ArcName,ArcName,ASIZE(ArcName),NewNumbering);
|
||||
wchar RecVolMask[NM];
|
||||
wcsncpyz(RecVolMask,ArcName,ASIZE(RecVolMask));
|
||||
size_t BaseNamePartLength=VolNumStart-ArcName;
|
||||
wcsncpyz(RecVolMask+BaseNamePartLength,L"*.rev",ASIZE(RecVolMask)-BaseNamePartLength);
|
||||
size_t VolNumStart=VolNameToFirstName(ArcName,ArcName,NewNumbering);
|
||||
std::wstring RecVolMask=ArcName;
|
||||
RecVolMask.replace(VolNumStart,std::wstring::npos,L"*.rev");
|
||||
size_t BaseNamePartLength=VolNumStart;
|
||||
|
||||
int64 RecFileSize=0;
|
||||
|
||||
@@ -155,25 +133,25 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
||||
Find.SetMask(RecVolMask);
|
||||
FindData RecData;
|
||||
int FileNumber=0,RecVolNumber=0,FoundRecVolumes=0,MissingVolumes=0;
|
||||
wchar PrevName[NM];
|
||||
std::wstring PrevName;
|
||||
while (Find.Next(&RecData))
|
||||
{
|
||||
wchar *CurName=RecData.Name;
|
||||
std::wstring CurName=RecData.Name;
|
||||
int P[3];
|
||||
if (!RevName && !NewStyle)
|
||||
{
|
||||
NewStyle=true;
|
||||
|
||||
wchar *Dot=GetExt(CurName);
|
||||
if (Dot!=NULL)
|
||||
size_t DotPos=GetExtPos(CurName);
|
||||
if (DotPos!=std::wstring::npos)
|
||||
{
|
||||
int LineCount=0;
|
||||
Dot--;
|
||||
while (Dot>CurName && *Dot!='.')
|
||||
uint LineCount=0;
|
||||
DotPos--;
|
||||
while (DotPos>0 && CurName[DotPos]!='.')
|
||||
{
|
||||
if (*Dot=='_')
|
||||
if (CurName[DotPos]=='_')
|
||||
LineCount++;
|
||||
Dot--;
|
||||
DotPos--;
|
||||
}
|
||||
if (LineCount==2)
|
||||
NewStyle=false;
|
||||
@@ -209,24 +187,24 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
||||
}
|
||||
else
|
||||
{
|
||||
wchar *Dot=GetExt(CurName);
|
||||
if (Dot==NULL)
|
||||
size_t DotPos=GetExtPos(CurName);
|
||||
if (DotPos==std::wstring::npos)
|
||||
continue;
|
||||
bool WrongParam=false;
|
||||
for (size_t I=0;I<ASIZE(P);I++)
|
||||
{
|
||||
do
|
||||
{
|
||||
Dot--;
|
||||
} while (IsDigit(*Dot) && Dot>=CurName+BaseNamePartLength);
|
||||
P[I]=atoiw(Dot+1);
|
||||
DotPos--;
|
||||
} while (IsDigit(CurName[DotPos]) && DotPos>=BaseNamePartLength);
|
||||
P[I]=atoiw(&CurName[DotPos+1]);
|
||||
if (P[I]==0 || P[I]>255)
|
||||
WrongParam=true;
|
||||
}
|
||||
if (WrongParam)
|
||||
continue;
|
||||
}
|
||||
if (P[1]+P[2]>255)
|
||||
if (P[0]<=0 || P[1]<=0 || P[2]<=0 || P[1]+P[2]>255 || P[0]+P[2]-1>255)
|
||||
continue;
|
||||
if (RecVolNumber!=0 && RecVolNumber!=P[1] || FileNumber!=0 && FileNumber!=P[2])
|
||||
{
|
||||
@@ -235,10 +213,17 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
||||
}
|
||||
RecVolNumber=P[1];
|
||||
FileNumber=P[2];
|
||||
wcsncpyz(PrevName,CurName,ASIZE(PrevName));
|
||||
PrevName=CurName;
|
||||
File *NewFile=new File;
|
||||
NewFile->TOpen(CurName);
|
||||
SrcFile[FileNumber+P[0]-1]=NewFile;
|
||||
|
||||
// This check is redundant taking into account P[I]>255 and P[0]+P[2]-1>255
|
||||
// checks above. Still we keep it here for better clarity and security.
|
||||
int SrcPos=FileNumber+P[0]-1;
|
||||
if (SrcPos<0 || SrcPos>=ASIZE(SrcFile))
|
||||
continue;
|
||||
SrcFile[SrcPos]=NewFile;
|
||||
|
||||
FoundRecVolumes++;
|
||||
|
||||
if (RecFileSize==0)
|
||||
@@ -249,11 +234,9 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
||||
if (FoundRecVolumes==0)
|
||||
return false;
|
||||
|
||||
bool WriteFlags[256];
|
||||
memset(WriteFlags,0,sizeof(WriteFlags));
|
||||
bool WriteFlags[256]{};
|
||||
|
||||
wchar LastVolName[NM];
|
||||
*LastVolName=0;
|
||||
std::wstring LastVolName;
|
||||
|
||||
for (int CurArcNum=0;CurArcNum<FileNumber;CurArcNum++)
|
||||
{
|
||||
@@ -289,9 +272,7 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
||||
if (!ValidVolume)
|
||||
{
|
||||
NewFile->Close();
|
||||
wchar NewName[NM];
|
||||
wcsncpyz(NewName,ArcName,ASIZE(NewName));
|
||||
wcsncatz(NewName,L".bad",ASIZE(NewName));
|
||||
std::wstring NewName=ArcName+L".bad";
|
||||
|
||||
uiMsg(UIMSG_BADARCHIVE,ArcName);
|
||||
uiMsg(UIMSG_RENAMING,ArcName,NewName);
|
||||
@@ -322,13 +303,13 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
||||
MissingVolumes++;
|
||||
|
||||
if (CurArcNum==FileNumber-1)
|
||||
wcsncpyz(LastVolName,ArcName,ASIZE(LastVolName));
|
||||
LastVolName=ArcName;
|
||||
|
||||
uiMsg(UIMSG_MISSINGVOL,ArcName);
|
||||
uiMsg(UIEVENT_NEWARCHIVE,ArcName);
|
||||
}
|
||||
SrcFile[CurArcNum]=(File*)NewFile;
|
||||
NextVolumeName(ArcName,ASIZE(ArcName),!NewNumbering);
|
||||
NextVolumeName(ArcName,!NewNumbering);
|
||||
}
|
||||
|
||||
uiMsg(UIMSG_RECVOLMISSING,MissingVolumes);
|
||||
@@ -453,7 +434,7 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
||||
CurFile->Close();
|
||||
SrcFile[I]=NULL;
|
||||
}
|
||||
if (*LastVolName!=0)
|
||||
if (!LastVolName.empty())
|
||||
{
|
||||
// Truncate the last volume to its real size.
|
||||
Archive Arc(Cmd);
|
||||
@@ -497,7 +478,7 @@ void RSEncode::DecodeBuf()
|
||||
}
|
||||
|
||||
|
||||
void RecVolumes3::Test(RAROptions *Cmd,const wchar *Name)
|
||||
void RecVolumes3::Test(CommandData *Cmd,const std::wstring &Name)
|
||||
{
|
||||
if (!IsNewStyleRev(Name)) // RAR 3.0 name#_#_#.rev do not include CRC32.
|
||||
{
|
||||
@@ -505,8 +486,7 @@ void RecVolumes3::Test(RAROptions *Cmd,const wchar *Name)
|
||||
return;
|
||||
}
|
||||
|
||||
wchar VolName[NM];
|
||||
wcsncpyz(VolName,Name,ASIZE(VolName));
|
||||
std::wstring VolName=Name;
|
||||
|
||||
while (FileExist(VolName))
|
||||
{
|
||||
@@ -518,7 +498,7 @@ void RecVolumes3::Test(RAROptions *Cmd,const wchar *Name)
|
||||
}
|
||||
if (!uiStartFileExtract(VolName,false,true,false))
|
||||
return;
|
||||
mprintf(St(MExtrTestFile),VolName);
|
||||
mprintf(St(MExtrTestFile),VolName.c_str());
|
||||
mprintf(L" ");
|
||||
CurFile.Seek(0,SEEK_END);
|
||||
int64 Length=CurFile.Tell();
|
||||
@@ -539,6 +519,6 @@ void RecVolumes3::Test(RAROptions *Cmd,const wchar *Name)
|
||||
ErrHandler.SetErrorCode(RARX_CRC);
|
||||
}
|
||||
|
||||
NextVolumeName(VolName,ASIZE(VolName),false);
|
||||
NextVolumeName(VolName,false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -44,8 +48,8 @@ RecVolumes5::~RecVolumes5()
|
||||
{
|
||||
delete[] RealBuf;
|
||||
delete[] RealReadBuffer;
|
||||
for (uint I=0;I<RecItems.Size();I++)
|
||||
delete RecItems[I].f;
|
||||
for (RecVolItem &Item : RecItems)
|
||||
delete Item.f;
|
||||
for (uint I=0;I<MaxUserThreads;I++)
|
||||
delete ThreadData[I].RS;
|
||||
delete[] ThreadData;
|
||||
@@ -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,20 +141,19 @@ void RecVolumes5::ProcessAreaRS(RecRSThreadData *td)
|
||||
|
||||
|
||||
|
||||
bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
||||
bool RecVolumes5::Restore(CommandData *Cmd,const std::wstring &Name,bool Silent)
|
||||
{
|
||||
wchar ArcName[NM];
|
||||
wcsncpyz(ArcName,Name,ASIZE(ArcName));
|
||||
std::wstring ArcName=Name;
|
||||
|
||||
wchar *Num=GetVolNumPart(ArcName);
|
||||
while (Num>ArcName && IsDigit(*(Num-1)))
|
||||
Num--;
|
||||
if (Num==ArcName)
|
||||
size_t NumPos=GetVolNumPos(ArcName);
|
||||
while (NumPos>0 && IsDigit(ArcName[NumPos-1]))
|
||||
NumPos--;
|
||||
if (NumPos<=GetNamePos(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));
|
||||
ArcName.replace(NumPos,std::wstring::npos,L"*.*");
|
||||
|
||||
wchar FirstVolName[NM];
|
||||
*FirstVolName=0;
|
||||
std::wstring FirstVolName;
|
||||
std::wstring LongestRevName;
|
||||
|
||||
int64 RecFileSize=0;
|
||||
|
||||
@@ -164,7 +167,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 +179,9 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
||||
|
||||
ItemPos=RecNum;
|
||||
FoundRecVolumes++;
|
||||
|
||||
if (fd.Name.size()>LongestRevName.size())
|
||||
LongestRevName=fd.Name;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -194,35 +200,35 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
||||
|
||||
// RAR volume found. Get its number, store the handle in appropriate
|
||||
// array slot, clean slots in between if we had to grow the array.
|
||||
wchar *Num=GetVolNumPart(fd.Name);
|
||||
size_t NumPos=GetVolNumPos(fd.Name);
|
||||
uint VolNum=0;
|
||||
for (uint K=1;Num>=fd.Name && IsDigit(*Num);K*=10,Num--)
|
||||
VolNum+=(*Num-'0')*K;
|
||||
for (uint K=1;(int)NumPos>=0 && IsDigit(fd.Name[NumPos]);K*=10,NumPos--)
|
||||
VolNum+=(fd.Name[NumPos]-'0')*K;
|
||||
if (VolNum==0 || VolNum>MaxVolumes)
|
||||
continue;
|
||||
size_t CurSize=RecItems.Size();
|
||||
size_t CurSize=RecItems.size();
|
||||
if (VolNum>CurSize)
|
||||
{
|
||||
RecItems.Alloc(VolNum);
|
||||
for (size_t I=CurSize;I<VolNum;I++)
|
||||
RecItems[I].f=NULL;
|
||||
RecItems.resize(VolNum);
|
||||
// for (size_t I=CurSize;I<VolNum;I++)
|
||||
// RecItems[I].f=NULL;
|
||||
}
|
||||
ItemPos=VolNum-1;
|
||||
|
||||
if (*FirstVolName==0)
|
||||
VolNameToFirstName(fd.Name,FirstVolName,ASIZE(FirstVolName),true);
|
||||
if (FirstVolName.empty())
|
||||
VolNameToFirstName(fd.Name,FirstVolName,true);
|
||||
}
|
||||
}
|
||||
if (ItemPos==-1)
|
||||
delete Vol; // Skip found file, it is not RAR or REV volume.
|
||||
else
|
||||
if ((uint)ItemPos<RecItems.Size()) // Check if found more REV than needed.
|
||||
if ((uint)ItemPos<RecItems.size()) // Check if found more REV than needed.
|
||||
{
|
||||
// Store found RAR or REV volume.
|
||||
RecVolItem *Item=RecItems+ItemPos;
|
||||
RecVolItem *Item=&RecItems[ItemPos];
|
||||
Item->f=Vol;
|
||||
Item->New=false;
|
||||
wcsncpyz(Item->Name,fd.Name,ASIZE(Item->Name));
|
||||
Item->Name=fd.Name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,6 +237,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.empty())
|
||||
{
|
||||
SetExt(LongestRevName,L"rar");
|
||||
VolNameToFirstName(LongestRevName,FirstVolName,true);
|
||||
}
|
||||
|
||||
uiMsg(UIMSG_RECVOLCALCCHECKSUM);
|
||||
|
||||
MissingVolumes=0;
|
||||
@@ -290,9 +305,8 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
||||
{
|
||||
Item->f->Close();
|
||||
|
||||
wchar NewName[NM];
|
||||
wcsncpyz(NewName,Item->Name,ASIZE(NewName));
|
||||
wcsncatz(NewName,L".bad",ASIZE(NewName));
|
||||
std::wstring NewName;
|
||||
NewName=Item->Name+L".bad";
|
||||
|
||||
uiMsg(UIMSG_BADARCHIVE,Item->Name);
|
||||
uiMsg(UIMSG_RENAMING,Item->Name,NewName);
|
||||
@@ -301,14 +315,14 @@ 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));
|
||||
Item->Name=FirstVolName;
|
||||
uiMsg(UIMSG_CREATING,Item->Name);
|
||||
uiMsg(UIEVENT_NEWARCHIVE,Item->Name);
|
||||
File *NewVol=new File;
|
||||
bool UserReject;
|
||||
if (!FileCreate(Cmd,NewVol,Item->Name,ASIZE(Item->Name),&UserReject))
|
||||
if (!FileCreate(Cmd,NewVol,Item->Name,&UserReject))
|
||||
{
|
||||
if (!UserReject)
|
||||
ErrHandler.CreateErrorMsg(Item->Name);
|
||||
@@ -316,9 +330,8 @@ 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);
|
||||
NextVolumeName(FirstVolName,false);
|
||||
}
|
||||
|
||||
|
||||
@@ -346,13 +359,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.
|
||||
}
|
||||
|
||||
@@ -373,7 +384,7 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
||||
J++;
|
||||
VolNum=J++; // Use next valid REV volume data instead of RAR.
|
||||
}
|
||||
RecVolItem *Item=RecItems+VolNum;
|
||||
RecVolItem *Item=&RecItems[VolNum];
|
||||
|
||||
byte *B=&ReadBuf[0];
|
||||
int ReadSize=0;
|
||||
@@ -395,7 +406,7 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
||||
for (uint I=0,J=0;I<DataCount;I++)
|
||||
if (!ValidFlags[I])
|
||||
{
|
||||
RecVolItem *Item=RecItems+I;
|
||||
RecVolItem *Item=&RecItems[I];
|
||||
size_t WriteSize=(size_t)Min(MaxRead,Item->FileSize);
|
||||
Item->f->Write(Buf+(J++)*RecBufferSize,WriteSize);
|
||||
Item->FileSize-=WriteSize;
|
||||
@@ -415,7 +426,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%%");
|
||||
@@ -462,10 +472,10 @@ uint RecVolumes5::ReadHeader(File *RecFile,bool FirstRev)
|
||||
{
|
||||
// If we have read the first valid REV file, init data structures
|
||||
// using information from REV header.
|
||||
size_t CurSize=RecItems.Size();
|
||||
RecItems.Alloc(TotalCount);
|
||||
for (size_t I=CurSize;I<TotalCount;I++)
|
||||
RecItems[I].f=NULL;
|
||||
size_t CurSize=RecItems.size();
|
||||
RecItems.resize(TotalCount);
|
||||
// for (size_t I=CurSize;I<TotalCount;I++)
|
||||
// RecItems[I].f=NULL;
|
||||
for (uint I=0;I<DataCount;I++)
|
||||
{
|
||||
RecItems[I].FileSize=Raw.Get8();
|
||||
@@ -479,10 +489,9 @@ uint RecVolumes5::ReadHeader(File *RecFile,bool FirstRev)
|
||||
}
|
||||
|
||||
|
||||
void RecVolumes5::Test(RAROptions *Cmd,const wchar *Name)
|
||||
void RecVolumes5::Test(CommandData *Cmd,const std::wstring &Name)
|
||||
{
|
||||
wchar VolName[NM];
|
||||
wcsncpyz(VolName,Name,ASIZE(VolName));
|
||||
std::wstring VolName=Name;
|
||||
|
||||
uint FoundRecVolumes=0;
|
||||
while (FileExist(VolName))
|
||||
@@ -495,7 +504,7 @@ void RecVolumes5::Test(RAROptions *Cmd,const wchar *Name)
|
||||
}
|
||||
if (!uiStartFileExtract(VolName,false,true,false))
|
||||
return;
|
||||
mprintf(St(MExtrTestFile),VolName);
|
||||
mprintf(St(MExtrTestFile),VolName.c_str());
|
||||
mprintf(L" ");
|
||||
bool Valid=false;
|
||||
uint RecNum=ReadHeader(&CurFile,FoundRecVolumes==0);
|
||||
@@ -518,6 +527,6 @@ void RecVolumes5::Test(RAROptions *Cmd,const wchar *Name)
|
||||
ErrHandler.SetErrorCode(RARX_CRC);
|
||||
}
|
||||
|
||||
NextVolumeName(VolName,ASIZE(VolName),false);
|
||||
NextVolumeName(VolName,false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,14 +9,5 @@ const wchar* St(MSGID StringId)
|
||||
{
|
||||
return StringId;
|
||||
}
|
||||
|
||||
|
||||
// Needed for Unix swprintf to convert %s to %ls in legacy language resources.
|
||||
const wchar *StF(MSGID StringId)
|
||||
{
|
||||
static wchar FormattedStr[512];
|
||||
PrintfPrepareFmt(St(StringId),FormattedStr,ASIZE(FormattedStr));
|
||||
return FormattedStr;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -3,10 +3,8 @@
|
||||
|
||||
#ifdef RARDLL
|
||||
#define St(x) (L"")
|
||||
#define StF(x) (L"")
|
||||
#else
|
||||
const wchar *St(MSGID StringId);
|
||||
const wchar *StF(MSGID StringId);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -1,22 +1,41 @@
|
||||
/***************************************************************************
|
||||
* 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
|
||||
|
||||
static byte S[256],S5[256],rcon[30];
|
||||
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)
|
||||
{
|
||||
#ifdef ALLOW_MISALIGNED
|
||||
@@ -63,26 +82,53 @@ inline void Copy128(byte *dest,const byte *src)
|
||||
|
||||
Rijndael::Rijndael()
|
||||
{
|
||||
if (S[0]==0)
|
||||
if (S5[0]==0)
|
||||
GenerateTables();
|
||||
m_uRounds = 0;
|
||||
CBCMode = true; // Always true for RAR.
|
||||
#ifdef USE_SSE
|
||||
AES_NI=false;
|
||||
#endif
|
||||
#ifdef USE_NEON_AES
|
||||
AES_Neon=false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
|
||||
#ifdef _MSC_VER
|
||||
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(__GNUC__)
|
||||
AES_NI=__builtin_cpu_supports("aes");
|
||||
#endif
|
||||
|
||||
#elif defined(USE_NEON_AES)
|
||||
#ifdef _APPLE
|
||||
// getauxval isn't available in OS X
|
||||
uint Value=0;
|
||||
size_t Size=sizeof(Value);
|
||||
int RetCode=sysctlbyname("hw.optional.arm.FEAT_AES",&Value,&Size,NULL,0);
|
||||
|
||||
// We treat sysctlbyname failure with -1 return code as AES presence,
|
||||
// because "hw.optional.arm.FEAT_AES" was missing in OS X 11, but AES
|
||||
// still was supported by Neon.
|
||||
AES_Neon=RetCode!=0 || Value!=0;
|
||||
#else
|
||||
AES_Neon=(getauxval(AT_HWCAP) & HWCAP_AES)!=0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Other developers asked us to initialize it to suppress "may be used
|
||||
@@ -122,18 +168,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_AES)
|
||||
if (AES_Neon)
|
||||
{
|
||||
blockEncryptNeon(input,numBlocks,outBuffer);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
byte *prevBlock = m_initVector;
|
||||
@@ -220,6 +273,40 @@ void Rijndael::blockEncryptSSE(const byte *input,size_t numBlocks,byte *outBuffe
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_NEON_AES
|
||||
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)
|
||||
{
|
||||
@@ -227,12 +314,18 @@ void Rijndael::blockDecrypt(const byte *input, size_t inputLen, byte *outBuffer)
|
||||
return;
|
||||
|
||||
size_t numBlocks=inputLen/16;
|
||||
#ifdef USE_SSE
|
||||
#if defined(USE_SSE)
|
||||
if (AES_NI)
|
||||
{
|
||||
blockDecryptSSE(input,numBlocks,outBuffer);
|
||||
return;
|
||||
}
|
||||
#elif defined(USE_NEON_AES)
|
||||
if (AES_Neon)
|
||||
{
|
||||
blockDecryptNeon(input,numBlocks,outBuffer);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
byte block[16], iv[4][4];
|
||||
@@ -324,6 +417,41 @@ void Rijndael::blockDecryptSSE(const byte *input, size_t numBlocks, byte *outBuf
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_NEON_AES
|
||||
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
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -416,51 +544,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
|
||||
for (int I=0;I<256;I++)
|
||||
S5[S[I]]=I;
|
||||
|
||||
for (int I=0;I<256;I++)
|
||||
{
|
||||
pow[i] = (byte)w;
|
||||
pow[i + 255] = (byte)w;
|
||||
log[w] = (byte)i++;
|
||||
w ^= (w << 1) ^ (w & ff_hi ? ff_poly : 0);
|
||||
} while (w != 1);
|
||||
|
||||
for (int i = 0,w = 1; i < sizeof(rcon)/sizeof(rcon[0]); i++)
|
||||
{
|
||||
rcon[i] = w;
|
||||
w = (w << 1) ^ (w & ff_hi ? ff_poly : 0);
|
||||
}
|
||||
for(int i = 0; i < 256; ++i)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,16 +610,16 @@ void TestRijndael()
|
||||
for (uint L=0;L<3;L++)
|
||||
{
|
||||
byte Out[16];
|
||||
wchar Str[sizeof(Out)*2+1];
|
||||
std::wstring Str;
|
||||
|
||||
uint KeyLength=128+L*64;
|
||||
rij.Init(true,Key[L],KeyLength,IV);
|
||||
for (uint I=0;I<sizeof(PT);I+=16)
|
||||
rij.blockEncrypt(PT+I,16,Out);
|
||||
BinToHex(Chk[L],16,NULL,Str,ASIZE(Str));
|
||||
mprintf(L"\nAES-%d expected: %s",KeyLength,Str);
|
||||
BinToHex(Out,sizeof(Out),NULL,Str,ASIZE(Str));
|
||||
mprintf(L"\nAES-%d result: %s",KeyLength,Str);
|
||||
BinToHex(Chk[L],16,Str);
|
||||
mprintf(L"\nAES-%d expected: %s",KeyLength,Str.c_str());
|
||||
BinToHex(Out,sizeof(Out),Str);
|
||||
mprintf(L"\nAES-%d result: %s",KeyLength,Str.c_str());
|
||||
if (memcmp(Out,Chk[L],16)==0)
|
||||
mprintf(L" OK");
|
||||
else
|
||||
|
||||
@@ -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)
|
||||
@@ -16,12 +12,31 @@
|
||||
class Rijndael
|
||||
{
|
||||
private:
|
||||
|
||||
#ifdef USE_SSE
|
||||
#ifdef __GNUC__
|
||||
__attribute__((target("aes")))
|
||||
#endif
|
||||
void blockEncryptSSE(const byte *input,size_t numBlocks,byte *outBuffer);
|
||||
#ifdef __GNUC__
|
||||
__attribute__((target("aes")))
|
||||
#endif
|
||||
void blockDecryptSSE(const byte *input, size_t numBlocks, byte *outBuffer);
|
||||
|
||||
bool AES_NI;
|
||||
#endif
|
||||
|
||||
#ifdef USE_NEON_AES
|
||||
// In Android we must specify -march=armv8-a+crypto compiler switch
|
||||
// to support Neon AES commands, "crypto" attribute seems to be optional.
|
||||
__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();
|
||||
|
||||
@@ -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;
|
||||
@@ -144,7 +146,7 @@ void RSCoder16::MakeDecoderMatrix()
|
||||
}
|
||||
|
||||
|
||||
// Apply Gauss–Jordan elimination to find inverse of decoder matrix.
|
||||
// Apply Gauss-Jordan elimination to find inverse of decoder matrix.
|
||||
// We have the square NDxND matrix, but we do not store its trivial
|
||||
// diagonal "1" rows matching valid data, so we work with NExND matrix.
|
||||
// Our original Cauchy matrix does not contain 0, so we skip search
|
||||
@@ -331,14 +333,14 @@ bool RSCoder16::SSE_UpdateECC(uint DataNum, uint ECCNum, const byte *Data, byte
|
||||
|
||||
for (uint I=0;I<16;I++)
|
||||
{
|
||||
((byte *)&T0L)[I]=gfMul(I,M);
|
||||
((byte *)&T0H)[I]=gfMul(I,M)>>8;
|
||||
((byte *)&T1L)[I]=gfMul(I<<4,M);
|
||||
((byte *)&T1H)[I]=gfMul(I<<4,M)>>8;
|
||||
((byte *)&T2L)[I]=gfMul(I<<8,M);
|
||||
((byte *)&T2H)[I]=gfMul(I<<8,M)>>8;
|
||||
((byte *)&T3L)[I]=gfMul(I<<12,M);
|
||||
((byte *)&T3H)[I]=gfMul(I<<12,M)>>8;
|
||||
((byte *)&T0L)[I]=byte(gfMul(I,M));
|
||||
((byte *)&T0H)[I]=byte(gfMul(I,M)>>8);
|
||||
((byte *)&T1L)[I]=byte(gfMul(I<<4,M));
|
||||
((byte *)&T1H)[I]=byte(gfMul(I<<4,M)>>8);
|
||||
((byte *)&T2L)[I]=byte(gfMul(I<<8,M));
|
||||
((byte *)&T2H)[I]=byte(gfMul(I<<8,M)>>8);
|
||||
((byte *)&T3L)[I]=byte(gfMul(I<<12,M));
|
||||
((byte *)&T3H)[I]=byte(gfMul(I<<12,M)>>8);
|
||||
}
|
||||
|
||||
size_t Pos=0;
|
||||
|
||||
@@ -17,6 +17,9 @@ class RSCoder16
|
||||
void InvertDecoderMatrix();
|
||||
|
||||
#ifdef USE_SSE
|
||||
#if defined(USE_SSE) && defined(__GNUC__)
|
||||
__attribute__((target("ssse3")))
|
||||
#endif
|
||||
bool SSE_UpdateECC(uint DataNum, uint ECCNum, const byte *Data, byte *ECC, size_t BlockSize);
|
||||
#endif
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user