mirror of
https://github.com/Cisco-Talos/clamav.git
synced 2025-10-19 18:33:16 +00:00
Update to UnRAR v6.2.10
This commit is contained in:
parent
95df41b5bf
commit
6e5db6eaaa
86 changed files with 1434 additions and 586 deletions
|
@ -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>
|
||||
|
|
|
@ -3,15 +3,15 @@
|
|||
#include "arccmt.cpp"
|
||||
|
||||
|
||||
Archive::Archive(RAROptions *InitCmd)
|
||||
Archive::Archive(CommandData *InitCmd)
|
||||
{
|
||||
Cmd=NULL; // Just in case we'll have an exception in 'new' below.
|
||||
|
||||
DummyCmd=(InitCmd==NULL);
|
||||
Cmd=DummyCmd ? (new RAROptions):InitCmd;
|
||||
Cmd=DummyCmd ? (new CommandData):InitCmd;
|
||||
|
||||
OpenShared=Cmd->OpenShared;
|
||||
Format=RARFMT15;
|
||||
Format=RARFMT_NONE;
|
||||
Solid=false;
|
||||
Volume=false;
|
||||
MainComment=false;
|
||||
|
@ -31,9 +31,9 @@ Archive::Archive(RAROptions *InitCmd)
|
|||
NextBlockPos=0;
|
||||
|
||||
|
||||
memset(&MainHead,0,sizeof(MainHead));
|
||||
memset(&CryptHead,0,sizeof(CryptHead));
|
||||
memset(&EndArcHead,0,sizeof(EndArcHead));
|
||||
MainHead.Reset();
|
||||
CryptHead={};
|
||||
EndArcHead.Reset();
|
||||
|
||||
VolNumber=0;
|
||||
VolWrite=0;
|
||||
|
|
|
@ -32,8 +32,8 @@ class Archive:public File
|
|||
size_t ReadHeader14();
|
||||
size_t ReadHeader15();
|
||||
size_t ReadHeader50();
|
||||
void ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb);
|
||||
void RequestArcPassword();
|
||||
void ProcessExtra50(RawRead *Raw,size_t ExtraSize,const BaseBlock *bb);
|
||||
void RequestArcPassword(RarCheckPassword *SelPwd);
|
||||
void UnexpEndArcMsg();
|
||||
void BrokenHeaderMsg();
|
||||
void UnkEncVerMsg(const wchar *Name,const wchar *Info);
|
||||
|
@ -45,7 +45,7 @@ class Archive:public File
|
|||
#endif
|
||||
ComprDataIO SubDataIO;
|
||||
bool DummyCmd;
|
||||
RAROptions *Cmd;
|
||||
CommandData *Cmd;
|
||||
|
||||
|
||||
RarTime LatestTime;
|
||||
|
@ -58,7 +58,7 @@ class Archive:public File
|
|||
bool ProhibitQOpen;
|
||||
#endif
|
||||
public:
|
||||
Archive(RAROptions *InitCmd=NULL);
|
||||
Archive(CommandData *InitCmd=NULL);
|
||||
~Archive();
|
||||
static RARFORMAT IsSignature(const byte *D,size_t Size);
|
||||
bool IsArchive(bool EnableBroken);
|
||||
|
@ -83,7 +83,7 @@ class Archive:public File
|
|||
const wchar *Name,uint Flags);
|
||||
bool ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode);
|
||||
HEADER_TYPE GetHeaderType() {return CurHeaderType;}
|
||||
RAROptions* GetRAROptions() {return Cmd;}
|
||||
CommandData* GetCommandData() {return Cmd;}
|
||||
void SetSilentOpen(bool Mode) {SilentOpen=Mode;}
|
||||
#if 0
|
||||
void GetRecoveryInfo(bool Required,int64 *Size,int *Percent);
|
||||
|
@ -107,7 +107,6 @@ class Archive:public File
|
|||
FileHeader SubHead;
|
||||
CommentHeader CommHead;
|
||||
ProtectHeader ProtectHead;
|
||||
UnixOwnersHeader UOHead;
|
||||
EAHeader EAHead;
|
||||
StreamHeader StreamHead;
|
||||
|
||||
|
|
|
@ -100,6 +100,9 @@ void Archive::UnexpEndArcMsg()
|
|||
// If block positions are equal to file size, this is not an error.
|
||||
// It can happen when we reached the end of older RAR 1.5 archive,
|
||||
// which did not have the end of archive block.
|
||||
// We can't replace this check by checking that read size is exactly 0
|
||||
// in the beginning of file header, because in this case the read position
|
||||
// still can be beyond the end of archive.
|
||||
if (CurBlockPos!=ArcSize || NextBlockPos!=ArcSize)
|
||||
{
|
||||
uiMsg(UIERROR_UNEXPEOF,FileName);
|
||||
|
@ -145,7 +148,7 @@ size_t Archive::ReadHeader15()
|
|||
#ifdef RAR_NOCRYPT // For rarext.dll and unrar_nocrypt.dll.
|
||||
return 0;
|
||||
#else
|
||||
RequestArcPassword();
|
||||
RequestArcPassword(NULL);
|
||||
|
||||
byte Salt[SIZE_SALT30];
|
||||
if (Read(Salt,SIZE_SALT30)!=SIZE_SALT30)
|
||||
|
@ -251,7 +254,11 @@ size_t Archive::ReadHeader15()
|
|||
hd->SplitAfter=(hd->Flags & LHD_SPLIT_AFTER)!=0;
|
||||
hd->Encrypted=(hd->Flags & LHD_PASSWORD)!=0;
|
||||
hd->SaltSet=(hd->Flags & LHD_SALT)!=0;
|
||||
|
||||
// RAR versions earlier than 2.0 do not set the solid flag
|
||||
// in file header. They use only a global solid archive flag.
|
||||
hd->Solid=FileBlock && (hd->Flags & LHD_SOLID)!=0;
|
||||
|
||||
hd->SubBlock=!FileBlock && (hd->Flags & LHD_SOLID)!=0;
|
||||
hd->Dir=(hd->Flags & LHD_WINDOWMASK)==LHD_DIRECTORY;
|
||||
hd->WinSize=hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5);
|
||||
|
@ -469,19 +476,6 @@ size_t Archive::ReadHeader15()
|
|||
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();
|
||||
|
@ -513,8 +507,12 @@ size_t Archive::ReadHeader15()
|
|||
ushort 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)
|
||||
|
@ -577,14 +575,20 @@ size_t Archive::ReadHeader50()
|
|||
// in -p<pwd> to not stop batch processing for encrypted archives.
|
||||
bool GlobalPassword=Cmd->Password.IsSet() || uiIsGlobalPasswordSet();
|
||||
|
||||
RarCheckPassword CheckPwd;
|
||||
if (CryptHead.UsePswCheck && !BrokenHeader)
|
||||
CheckPwd.Set(CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,CryptHead.PswCheck);
|
||||
|
||||
while (true) // Repeat the password prompt for wrong passwords.
|
||||
{
|
||||
RequestArcPassword();
|
||||
RequestArcPassword(CheckPwd.IsSet() ? &CheckPwd:NULL);
|
||||
|
||||
byte PswCheck[SIZE_PSWCHECK];
|
||||
HeadersCrypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,NULL,PswCheck);
|
||||
// Verify password validity.
|
||||
if (CryptHead.UsePswCheck && memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0)
|
||||
// Verify password validity. If header is damaged, we cannot rely on
|
||||
// password check value, because it can be damaged too.
|
||||
if (CryptHead.UsePswCheck && !BrokenHeader &&
|
||||
memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0)
|
||||
{
|
||||
if (GlobalPassword) // For -p<pwd> or Ctrl+P.
|
||||
{
|
||||
|
@ -850,8 +854,6 @@ size_t Archive::ReadHeader50()
|
|||
hd->Dir=(hd->FileFlags & FHFL_DIRECTORY)!=0;
|
||||
hd->WinSize=hd->Dir ? 0:size_t(0x20000)<<((CompInfo>>10)&0xf);
|
||||
|
||||
hd->CryptMethod=hd->Encrypted ? CRYPT_RAR50:CRYPT_NONE;
|
||||
|
||||
char FileName[NM*4];
|
||||
size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
|
||||
Raw.GetB((byte *)FileName,ReadNameSize);
|
||||
|
@ -875,25 +877,6 @@ size_t Archive::ReadHeader50()
|
|||
if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_CMT))
|
||||
MainComment=true;
|
||||
|
||||
#if 0
|
||||
// For RAR5 format we read the user specified recovery percent here.
|
||||
// It would be useful to do it for shell extension too, so we display
|
||||
// the correct recovery record size in archive properties. But then
|
||||
// we would need to include the entire recovery record processing
|
||||
// code to shell extension, which is not done now.
|
||||
if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_RR) && hd->SubData.Size()>0)
|
||||
{
|
||||
// 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[0],hd->SubData.Size());
|
||||
RecoveryPercent=(int)RawPercent.GetV();
|
||||
|
||||
RSBlockHeader Header;
|
||||
GetRRInfo(this,&Header);
|
||||
RecoverySize=Header.RecSectionSize*Header.RecCount;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (BadCRC) // Add the file name to broken header message displayed above.
|
||||
uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName);
|
||||
|
@ -916,7 +899,7 @@ size_t Archive::ReadHeader50()
|
|||
|
||||
|
||||
#if !defined(RAR_NOCRYPT)
|
||||
void Archive::RequestArcPassword()
|
||||
void Archive::RequestArcPassword(RarCheckPassword *CheckPwd)
|
||||
{
|
||||
if (!Cmd->Password.IsSet())
|
||||
{
|
||||
|
@ -946,7 +929,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.
|
||||
|
@ -959,7 +942,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;
|
||||
|
@ -982,7 +965,9 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
|
|||
if (bb->HeaderType==HEAD_MAIN)
|
||||
{
|
||||
MainHeader *hd=(MainHeader *)bb;
|
||||
if (FieldType==MHEXTRA_LOCATOR)
|
||||
switch(FieldType)
|
||||
{
|
||||
case MHEXTRA_LOCATOR:
|
||||
{
|
||||
hd->Locator=true;
|
||||
uint Flags=(uint)Raw->GetV();
|
||||
|
@ -999,6 +984,39 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
|
|||
hd->RROffset=Offset+CurBlockPos;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MHEXTRA_METADATA:
|
||||
{
|
||||
uint Flags=(uint)Raw->GetV();
|
||||
if ((Flags & MHEXTRA_METADATA_NAME)!=0)
|
||||
{
|
||||
uint64 NameSize=Raw->GetV();
|
||||
if (NameSize<0x10000) // Prevent excessive allocation.
|
||||
{
|
||||
std::vector<char> NameU((size_t)NameSize); // UTF-8 name.
|
||||
Raw->GetB(&NameU[0],(size_t)NameSize);
|
||||
// If starts from 0, the name was longer than reserved space
|
||||
// when saving this extra field.
|
||||
if (NameU[0]!=0)
|
||||
{
|
||||
NameU.push_back(0);
|
||||
std::vector<wchar> NameW(NameU.size()*4);
|
||||
UtfToWide(&NameU[0],&NameW[0],NameW.size());
|
||||
hd->OrigName.assign(&NameW[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((Flags & MHEXTRA_METADATA_CTIME)!=0)
|
||||
if ((Flags & MHEXTRA_METADATA_UNIXTIME)!=0)
|
||||
if ((Flags & MHEXTRA_METADATA_UNIX_NS)!=0)
|
||||
hd->OrigTime.SetUnixNS(Raw->Get8());
|
||||
else
|
||||
hd->OrigTime.SetUnix((time_t)Raw->Get4());
|
||||
else
|
||||
hd->OrigTime.SetWin(Raw->Get8());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bb->HeaderType==HEAD_FILE || bb->HeaderType==HEAD_SERVICE)
|
||||
|
@ -1453,7 +1471,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;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ template <class T> class Array
|
|||
size_t BufSize;
|
||||
size_t AllocSize;
|
||||
size_t MaxSize;
|
||||
bool Secure; // Clean memory if true.
|
||||
public:
|
||||
Array();
|
||||
Array(size_t Size);
|
||||
|
@ -24,14 +23,13 @@ template <class T> class Array
|
|||
void Alloc(size_t Items);
|
||||
void Reset();
|
||||
void SoftReset();
|
||||
void operator = (Array<T> &Src);
|
||||
Array<T>& operator = (const Array<T> &Src);
|
||||
void Push(T Item);
|
||||
void Append(T *Item,size_t Count);
|
||||
T* Addr(size_t Item) {return Buffer+Item;}
|
||||
void SetMaxSize(size_t Size) {MaxSize=Size;}
|
||||
T* Begin() {return Buffer;}
|
||||
T* End() {return Buffer==NULL ? NULL:Buffer+BufSize;}
|
||||
void SetSecure() {Secure=true;}
|
||||
};
|
||||
|
||||
|
||||
|
@ -41,7 +39,6 @@ template <class T> void Array<T>::CleanData()
|
|||
BufSize=0;
|
||||
AllocSize=0;
|
||||
MaxSize=0;
|
||||
Secure=false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -71,11 +68,7 @@ template <class T> Array<T>::Array(const Array &Src)
|
|||
template <class T> Array<T>::~Array()
|
||||
{
|
||||
if (Buffer!=NULL)
|
||||
{
|
||||
if (Secure)
|
||||
cleandata(Buffer,AllocSize*sizeof(T));
|
||||
free(Buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -111,25 +104,9 @@ template <class T> void Array<T>::Add(size_t Items)
|
|||
size_t Suggested=AllocSize+AllocSize/4+32;
|
||||
size_t NewSize=Max(BufSize,Suggested);
|
||||
|
||||
T *NewBuffer;
|
||||
if (Secure)
|
||||
{
|
||||
NewBuffer=(T *)malloc(NewSize*sizeof(T));
|
||||
T *NewBuffer=(T *)realloc(Buffer,NewSize*sizeof(T));
|
||||
if (NewBuffer==NULL)
|
||||
ErrHandler.MemoryError();
|
||||
if (Buffer!=NULL)
|
||||
{
|
||||
memcpy(NewBuffer,Buffer,AllocSize*sizeof(T));
|
||||
cleandata(Buffer,AllocSize*sizeof(T));
|
||||
free(Buffer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NewBuffer=(T *)realloc(Buffer,NewSize*sizeof(T));
|
||||
if (NewBuffer==NULL)
|
||||
ErrHandler.MemoryError();
|
||||
}
|
||||
Buffer=NewBuffer;
|
||||
AllocSize=NewSize;
|
||||
}
|
||||
|
@ -165,12 +142,13 @@ template <class T> void Array<T>::SoftReset()
|
|||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::operator =(Array<T> &Src)
|
||||
template <class T> Array<T>& Array<T>::operator =(const Array<T> &Src)
|
||||
{
|
||||
Reset();
|
||||
Alloc(Src.BufSize);
|
||||
if (Src.BufSize!=0)
|
||||
memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -20,10 +20,15 @@ enum blake2s_constant
|
|||
// 'new' operator.
|
||||
struct blake2s_state
|
||||
{
|
||||
enum { BLAKE_ALIGNMENT = 64 };
|
||||
// Use constexpr instead of enums, because otherwise clang -std=c++20
|
||||
// issues a warning about "arithmetic between different enumeration types"
|
||||
// in ubuf[BLAKE_DATA_SIZE + BLAKE_ALIGNMENT] declaration.
|
||||
static constexpr size_t BLAKE_ALIGNMENT = 64;
|
||||
|
||||
// buffer and uint32 h[8], t[2], f[2];
|
||||
enum { BLAKE_DATA_SIZE = 48 + 2 * BLAKE2S_BLOCKBYTES };
|
||||
// 2 * BLAKE2S_BLOCKBYTES is the buf size in blake2_code_20140114.zip.
|
||||
// It might differ in later versions.
|
||||
static constexpr size_t BLAKE_DATA_SIZE = 48 + 2 * BLAKE2S_BLOCKBYTES;
|
||||
|
||||
byte ubuf[BLAKE_DATA_SIZE + BLAKE_ALIGNMENT];
|
||||
|
||||
|
|
|
@ -26,9 +26,10 @@ void CommandData::Init()
|
|||
FileArgs.Reset();
|
||||
ExclArgs.Reset();
|
||||
InclArgs.Reset();
|
||||
StoreArgs.Reset();
|
||||
ArcNames.Reset();
|
||||
NextVolSizes.Reset();
|
||||
StoreArgs.Reset();
|
||||
Password.Clean();
|
||||
NextVolSizes.clear();
|
||||
}
|
||||
|
||||
|
||||
|
@ -314,6 +315,21 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
|||
case 'I':
|
||||
IgnoreGeneralAttr=true;
|
||||
break;
|
||||
case 'M':
|
||||
switch(toupperw(Switch[2]))
|
||||
{
|
||||
case 0:
|
||||
case 'S':
|
||||
ArcMetadata=ARCMETA_SAVE;
|
||||
break;
|
||||
case 'R':
|
||||
ArcMetadata=ARCMETA_RESTORE;
|
||||
break;
|
||||
default:
|
||||
BadSwitch(Switch);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'N': // Reserved for archive name.
|
||||
break;
|
||||
case 'O':
|
||||
|
@ -415,7 +431,7 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
|||
else
|
||||
if (!Password.IsSet())
|
||||
{
|
||||
uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password);
|
||||
uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password,NULL);
|
||||
eprintf(L"\n");
|
||||
}
|
||||
break;
|
||||
|
@ -685,7 +701,7 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
|||
case 'P':
|
||||
if (Switch[1]==0)
|
||||
{
|
||||
uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password);
|
||||
uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password,NULL);
|
||||
eprintf(L"\n");
|
||||
}
|
||||
else
|
||||
|
@ -927,6 +943,7 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
|||
void CommandData::BadSwitch(const wchar *Switch)
|
||||
{
|
||||
mprintf(St(MUnknownOption),Switch);
|
||||
mprintf(L"\n");
|
||||
ErrHandler.Exit(RARX_USERERROR);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define _RAR_CMDDATA_
|
||||
|
||||
|
||||
#define DefaultStoreList L"7z;ace;arj;bz2;cab;gz;jpeg;jpg;lha;lz;lzh;mp3;rar;taz;tgz;xz;z;zip;zipx"
|
||||
#define DefaultStoreList L"7z;ace;arj;bz2;cab;gz;jpeg;jpg;lha;lz;lzh;mp3;rar;taz;tbz;tbz2;tgz;txz;xz;z;zip;zipx;zst;tzst"
|
||||
|
||||
enum RAR_CMD_LIST_MODE {RCLM_AUTO,RCLM_REJECT_LISTS,RCLM_ACCEPT_LISTS};
|
||||
|
||||
|
@ -65,6 +65,10 @@ class CommandData:public RAROptions
|
|||
StringList InclArgs;
|
||||
StringList ArcNames;
|
||||
StringList StoreArgs;
|
||||
|
||||
SecPassword Password;
|
||||
|
||||
std::vector<int64> NextVolSizes;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -289,8 +289,8 @@ int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchTy
|
|||
return 0;
|
||||
if ((FileHead.FileAttr & ExclFileAttr)!=0 || FileHead.Dir && ExclDir)
|
||||
return 0;
|
||||
if (InclAttrSet && (!FileHead.Dir && (FileHead.FileAttr & InclFileAttr)==0 ||
|
||||
FileHead.Dir && !InclDir))
|
||||
if (InclAttrSet && (FileHead.FileAttr & InclFileAttr)==0 &&
|
||||
(!FileHead.Dir || !InclDir))
|
||||
return 0;
|
||||
if (!Dir && SizeCheck(FileHead.UnpSize))
|
||||
return 0;
|
||||
|
|
|
@ -92,6 +92,13 @@ void CommandData::OutHelp(RAR_EXIT ExitCode)
|
|||
if (Found)
|
||||
continue;
|
||||
#endif
|
||||
#ifdef _UNIX
|
||||
if (CmpMSGID(Help[I],MRARTitle2))
|
||||
{
|
||||
mprintf(St(MFwrSlTitle2));
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
#if !defined(_UNIX) && !defined(_WIN_ALL)
|
||||
if (CmpMSGID(Help[I],MCHelpSwOW))
|
||||
continue;
|
||||
|
|
|
@ -17,6 +17,7 @@ class PackDef
|
|||
static const uint MAX_INC_LZ_MATCH = MAX_LZ_MATCH + 3;
|
||||
|
||||
static const uint MAX3_LZ_MATCH = 0x101; // Maximum match length for RAR v3.
|
||||
static const uint MAX3_INC_LZ_MATCH = MAX3_LZ_MATCH + 3;
|
||||
static const uint LOW_DIST_REP_COUNT = 16;
|
||||
|
||||
static const uint NC = 306; /* alphabet = {0, 1, 2, ..., NC - 1} */
|
||||
|
|
|
@ -110,3 +110,164 @@ ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size)
|
|||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
static uint64 crc64_tables[8][256]; // Tables for Slicing-by-8 for CRC64.
|
||||
|
||||
void InitCRC64(uint64 *CRCTab)
|
||||
{
|
||||
const uint64 poly=INT32TO64(0xC96C5795, 0xD7870F42); // 0xC96C5795D7870F42;
|
||||
for (uint I=0;I<256;I++)
|
||||
{
|
||||
uint64 C=I;
|
||||
for (uint J=0;J<8;J++)
|
||||
C=(C & 1) ? (C>>1)^poly: (C>>1);
|
||||
CRCTab[I]=C;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void InitTables64()
|
||||
{
|
||||
InitCRC64(crc64_tables[0]);
|
||||
|
||||
for (uint I=0;I<256;I++) // Build additional lookup tables.
|
||||
{
|
||||
uint64 C=crc64_tables[0][I];
|
||||
for (uint J=1;J<8;J++)
|
||||
{
|
||||
C=crc64_tables[0][(byte)C]^(C>>8);
|
||||
crc64_tables[J][I]=C;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// We cannot place the intialization to CRC64(), because we use this function
|
||||
// in multithreaded mode and it conflicts with multithreading.
|
||||
struct CallInitCRC64 {CallInitCRC64() {InitTables64();}} static CallInit64;
|
||||
|
||||
uint64 CRC64(uint64 StartCRC,const void *Addr,size_t Size)
|
||||
{
|
||||
byte *Data=(byte *)Addr;
|
||||
|
||||
// Align Data to 8 for better performance.
|
||||
for (;Size>0 && ((size_t)Data & 7)!=0;Size--,Data++)
|
||||
StartCRC=crc64_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);
|
||||
|
||||
for (byte *DataEnd=Data+Size/8*8; Data<DataEnd; Data+=8 )
|
||||
{
|
||||
uint64 Index=StartCRC;
|
||||
#ifdef BIG_ENDIAN
|
||||
Index ^= (uint64(Data[0])|(uint64(Data[1])<<8)|(uint64(Data[2])<<16)|(uint64(Data[3])<<24))|
|
||||
(uint64(Data[4])<<32)|(uint64(Data[5])<<40)|(uint64(Data[6])<<48)|(uint64(Data[7])<<56);
|
||||
#else
|
||||
Index ^= *(uint64 *)Data;
|
||||
#endif
|
||||
StartCRC = crc64_tables[ 7 ] [ ( byte ) (Index ) ] ^
|
||||
crc64_tables[ 6 ] [ ( byte ) (Index >> 8 ) ] ^
|
||||
crc64_tables[ 5 ] [ ( byte ) (Index >> 16 ) ] ^
|
||||
crc64_tables[ 4 ] [ ( byte ) (Index >> 24 ) ] ^
|
||||
crc64_tables[ 3 ] [ ( byte ) (Index >> 32 ) ] ^
|
||||
crc64_tables[ 2 ] [ ( byte ) (Index >> 40 ) ] ^
|
||||
crc64_tables[ 1 ] [ ( byte ) (Index >> 48 ) ] ^
|
||||
crc64_tables[ 0 ] [ ( byte ) (Index >> 56 ) ] ;
|
||||
}
|
||||
|
||||
for (Size%=8;Size>0;Size--,Data++) // Process left data.
|
||||
StartCRC=crc64_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);
|
||||
|
||||
return StartCRC;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static void TestCRC();
|
||||
struct TestCRCStruct {TestCRCStruct() {TestCRC();exit(0);}} GlobalTesCRC;
|
||||
|
||||
void TestCRC()
|
||||
{
|
||||
const uint FirstSize=300;
|
||||
byte b[FirstSize];
|
||||
|
||||
if ((CRC32(0xffffffff,(byte*)"testtesttest",12)^0xffffffff)==0x44608e84)
|
||||
mprintf(L"\nCRC32 test1 OK");
|
||||
else
|
||||
mprintf(L"\nCRC32 test1 FAILED");
|
||||
|
||||
if (CRC32(0,(byte*)"te\x80st",5)==0xB2E5C5AE)
|
||||
mprintf(L"\nCRC32 test2 OK");
|
||||
else
|
||||
mprintf(L"\nCRC32 test2 FAILED");
|
||||
|
||||
for (uint I=0;I<14;I++) // Check for possible int sign extension.
|
||||
b[I]=(byte)0x7f+I;
|
||||
if ((CRC32(0xffffffff,b,14)^0xffffffff)==0x1DFA75DA)
|
||||
mprintf(L"\nCRC32 test3 OK");
|
||||
else
|
||||
mprintf(L"\nCRC32 test3 FAILED");
|
||||
|
||||
for (uint I=0;I<FirstSize;I++)
|
||||
b[I]=(byte)I;
|
||||
uint r32=CRC32(0xffffffff,b,FirstSize);
|
||||
for (uint I=FirstSize;I<1024;I++)
|
||||
{
|
||||
b[0]=(byte)I;
|
||||
r32=CRC32(r32,b,1);
|
||||
}
|
||||
if ((r32^0xffffffff)==0xB70B4C26)
|
||||
mprintf(L"\nCRC32 test4 OK");
|
||||
else
|
||||
mprintf(L"\nCRC32 test4 FAILED");
|
||||
|
||||
if ((CRC64(0xffffffffffffffff,(byte*)"testtesttest",12)^0xffffffffffffffff)==0x7B1C2D230EDEB436)
|
||||
mprintf(L"\nCRC64 test1 OK");
|
||||
else
|
||||
mprintf(L"\nCRC64 test1 FAILED");
|
||||
|
||||
if (CRC64(0,(byte*)"te\x80st",5)==0xB5DBF9583A6EED4A)
|
||||
mprintf(L"\nCRC64 test2 OK");
|
||||
else
|
||||
mprintf(L"\nCRC64 test2 FAILED");
|
||||
|
||||
for (uint I=0;I<14;I++) // Check for possible int sign extension.
|
||||
b[I]=(byte)0x7f+I;
|
||||
if ((CRC64(0xffffffffffffffff,b,14)^0xffffffffffffffff)==0xE019941C05B2820C)
|
||||
mprintf(L"\nCRC64 test3 OK");
|
||||
else
|
||||
mprintf(L"\nCRC64 test3 FAILED");
|
||||
|
||||
for (uint I=0;I<FirstSize;I++)
|
||||
b[I]=(byte)I;
|
||||
uint64 r64=CRC64(0xffffffffffffffff,b,FirstSize);
|
||||
for (uint I=FirstSize;I<1024;I++)
|
||||
{
|
||||
b[0]=(byte)I;
|
||||
r64=CRC64(r64,b,1);
|
||||
}
|
||||
if ((r64^0xffffffffffffffff)==0xD51FB58DC789C400)
|
||||
mprintf(L"\nCRC64 test4 OK");
|
||||
else
|
||||
mprintf(L"\nCRC64 test4 FAILED");
|
||||
|
||||
const size_t BufSize=0x100000;
|
||||
byte *Buf=new byte[BufSize];
|
||||
memset(Buf,0,BufSize);
|
||||
|
||||
clock_t StartTime=clock();
|
||||
r32=0xffffffff;
|
||||
const uint BufCount=5000;
|
||||
for (uint I=0;I<BufCount;I++)
|
||||
r32=CRC32(r32,Buf,BufSize);
|
||||
if (r32!=0) // Otherwise compiler optimizer removes CRC calculation.
|
||||
mprintf(L"\nCRC32 speed: %d MB/s",BufCount*1000/(clock()-StartTime));
|
||||
|
||||
StartTime=clock();
|
||||
r64=0xffffffffffffffff;
|
||||
for (uint I=0;I<BufCount;I++)
|
||||
r64=CRC64(r64,Buf,BufSize);
|
||||
if (r64!=0) // Otherwise compiler optimizer removes CRC calculation.
|
||||
mprintf(L"\nCRC64 speed: %d MB/s",BufCount*1000/(clock()-StartTime));
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,5 +11,9 @@ uint CRC32(uint StartCRC,const void *Addr,size_t Size);
|
|||
ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
void InitCRC64(uint64 *CRCTab);
|
||||
uint64 CRC64(uint64 StartCRC,const void *Addr,size_t Size);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,21 +11,12 @@
|
|||
CryptData::CryptData()
|
||||
{
|
||||
Method=CRYPT_NONE;
|
||||
memset(KDF3Cache,0,sizeof(KDF3Cache));
|
||||
memset(KDF5Cache,0,sizeof(KDF5Cache));
|
||||
KDF3CachePos=0;
|
||||
KDF5CachePos=0;
|
||||
memset(CRCTab,0,sizeof(CRCTab));
|
||||
}
|
||||
|
||||
|
||||
CryptData::~CryptData()
|
||||
{
|
||||
cleandata(KDF3Cache,sizeof(KDF3Cache));
|
||||
cleandata(KDF5Cache,sizeof(KDF5Cache));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void CryptData::DecryptBlock(byte *Buf,size_t Size)
|
||||
|
@ -56,15 +47,18 @@ bool CryptData::SetCryptKeys(bool Encrypt,CRYPT_METHOD Method,
|
|||
SecPassword *Password,const byte *Salt,
|
||||
const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck)
|
||||
{
|
||||
if (!Password->IsSet() || Method==CRYPT_NONE)
|
||||
if (Method==CRYPT_NONE || !Password->IsSet())
|
||||
return false;
|
||||
|
||||
CryptData::Method=Method;
|
||||
|
||||
wchar PwdW[MAXPASSWORD];
|
||||
Password->Get(PwdW,ASIZE(PwdW));
|
||||
PwdW[Min(MAXPASSWORD_RAR,MAXPASSWORD)-1]=0; // For compatibility with existing archives.
|
||||
|
||||
char PwdA[MAXPASSWORD];
|
||||
WideToChar(PwdW,PwdA,ASIZE(PwdA));
|
||||
PwdA[Min(MAXPASSWORD_RAR,MAXPASSWORD)-1]=0; // For compatibility with existing archives.
|
||||
|
||||
switch(Method)
|
||||
{
|
||||
|
|
|
@ -30,6 +30,18 @@ class CryptData
|
|||
uint Lg2Count; // Log2 of PBKDF2 repetition count.
|
||||
byte PswCheckValue[SHA256_DIGEST_SIZE];
|
||||
byte HashKeyValue[SHA256_DIGEST_SIZE];
|
||||
|
||||
KDF5CacheItem() {Clean();}
|
||||
~KDF5CacheItem() {Clean();}
|
||||
|
||||
void Clean()
|
||||
{
|
||||
cleandata(Salt,sizeof(Salt));
|
||||
cleandata(Key,sizeof(Key));
|
||||
cleandata(&Lg2Count,sizeof(Lg2Count));
|
||||
cleandata(PswCheckValue,sizeof(PswCheckValue));
|
||||
cleandata(HashKeyValue,sizeof(HashKeyValue));
|
||||
}
|
||||
};
|
||||
|
||||
struct KDF3CacheItem
|
||||
|
@ -39,6 +51,17 @@ class CryptData
|
|||
byte Key[16];
|
||||
byte Init[16];
|
||||
bool SaltPresent;
|
||||
|
||||
KDF3CacheItem() {Clean();}
|
||||
~KDF3CacheItem() {Clean();}
|
||||
|
||||
void Clean()
|
||||
{
|
||||
cleandata(Salt,sizeof(Salt));
|
||||
cleandata(Key,sizeof(Key));
|
||||
cleandata(Init,sizeof(Init));
|
||||
cleandata(&SaltPresent,sizeof(SaltPresent));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -77,7 +100,6 @@ class CryptData
|
|||
ushort Key15[4];
|
||||
public:
|
||||
CryptData();
|
||||
~CryptData();
|
||||
bool SetCryptKeys(bool Encrypt,CRYPT_METHOD Method,SecPassword *Password,
|
||||
const byte *Salt,const byte *InitV,uint Lg2Cnt,
|
||||
byte *HashKey,byte *PswCheck);
|
||||
|
@ -88,6 +110,54 @@ class CryptData
|
|||
static void SetSalt(byte *Salt,size_t SaltSize);
|
||||
};
|
||||
|
||||
|
||||
class CheckPassword
|
||||
{
|
||||
public:
|
||||
enum CONFIDENCE {CONFIDENCE_HIGH,CONFIDENCE_MEDIUM,CONFIDENCE_LOW};
|
||||
virtual CONFIDENCE GetConfidence()=0;
|
||||
virtual bool Check(SecPassword *Password)=0;
|
||||
};
|
||||
|
||||
class RarCheckPassword:public CheckPassword
|
||||
{
|
||||
private:
|
||||
CryptData *Crypt;
|
||||
uint Lg2Count;
|
||||
byte Salt[SIZE_SALT50];
|
||||
byte InitV[SIZE_INITV];
|
||||
byte PswCheck[SIZE_PSWCHECK];
|
||||
public:
|
||||
RarCheckPassword()
|
||||
{
|
||||
Crypt=NULL;
|
||||
}
|
||||
~RarCheckPassword()
|
||||
{
|
||||
delete Crypt;
|
||||
}
|
||||
void Set(byte *Salt,byte *InitV,uint Lg2Count,byte *PswCheck)
|
||||
{
|
||||
if (Crypt==NULL)
|
||||
Crypt=new CryptData;
|
||||
memcpy(this->Salt,Salt,sizeof(this->Salt));
|
||||
memcpy(this->InitV,InitV,sizeof(this->InitV));
|
||||
this->Lg2Count=Lg2Count;
|
||||
memcpy(this->PswCheck,PswCheck,sizeof(this->PswCheck));
|
||||
}
|
||||
bool IsSet() {return Crypt!=NULL;}
|
||||
|
||||
// RAR5 provides the higly reliable 64 bit password verification value.
|
||||
CONFIDENCE GetConfidence() {return CONFIDENCE_HIGH;}
|
||||
|
||||
bool Check(SecPassword *Password)
|
||||
{
|
||||
byte PswCheck[SIZE_PSWCHECK];
|
||||
Crypt->SetCryptKeys(false,CRYPT_RAR50,Password,Salt,InitV,Lg2Count,NULL,PswCheck);
|
||||
return memcmp(PswCheck,this->PswCheck,sizeof(this->PswCheck))==0;
|
||||
}
|
||||
};
|
||||
|
||||
void GetRnd(byte *RndBuf,size_t BufSize);
|
||||
|
||||
void hmac_sha256(const byte *Key,size_t KeyLength,const byte *Data,
|
||||
|
|
|
@ -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];
|
||||
|
@ -140,7 +140,7 @@ void CryptData::SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,
|
|||
for (uint I=0;I<ASIZE(KDF5Cache);I++)
|
||||
{
|
||||
KDF5CacheItem *Item=KDF5Cache+I;
|
||||
if (Item->Lg2Count==Lg2Cnt && Item->Pwd==*Password &&
|
||||
if (Item->Pwd==*Password && Item->Lg2Count==Lg2Cnt &&
|
||||
memcmp(Item->Salt,Salt,SIZE_SALT50)==0)
|
||||
{
|
||||
memcpy(Key,Item->Key,sizeof(Key));
|
||||
|
|
|
@ -329,7 +329,7 @@ int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestNa
|
|||
{
|
||||
Data->Cmd.DllError=0;
|
||||
if (Data->OpenMode==RAR_OM_LIST || Data->OpenMode==RAR_OM_LIST_INCSPLIT ||
|
||||
Operation==RAR_SKIP) // && !Data->Arc.Solid)
|
||||
Operation==RAR_SKIP && !Data->Arc.Solid)
|
||||
{
|
||||
if (Data->Arc.Volume && Data->Arc.GetHeaderType()==HEAD_FILE &&
|
||||
Data->Arc.FileHead.SplitAfter)
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
#include <commctrl.h>
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 6, 12, 100, 489
|
||||
PRODUCTVERSION 6, 12, 100, 489
|
||||
FILEVERSION 6, 23, 100, 944
|
||||
PRODUCTVERSION 6, 23, 100, 944
|
||||
FILEOS VOS__WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
{
|
||||
|
@ -14,9 +14,9 @@ FILETYPE VFT_APP
|
|||
VALUE "CompanyName", "Alexander Roshal\0"
|
||||
VALUE "ProductName", "RAR decompression library\0"
|
||||
VALUE "FileDescription", "RAR decompression library\0"
|
||||
VALUE "FileVersion", "6.12.0\0"
|
||||
VALUE "ProductVersion", "6.12.0\0"
|
||||
VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2022\0"
|
||||
VALUE "FileVersion", "6.23.0\0"
|
||||
VALUE "ProductVersion", "6.23.0\0"
|
||||
VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2023\0"
|
||||
VALUE "OriginalFilename", "Unrar.dll\0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -169,10 +169,13 @@ void ErrorHandler::OpenErrorMsg(const wchar *FileName)
|
|||
|
||||
void ErrorHandler::OpenErrorMsg(const wchar *ArcName,const wchar *FileName)
|
||||
{
|
||||
Wait(); // Keep GUI responsive if many files cannot be opened when archiving.
|
||||
uiMsg(UIERROR_FILEOPEN,ArcName,FileName);
|
||||
SysErrMsg();
|
||||
SetErrorCode(RARX_OPEN);
|
||||
|
||||
// Keep GUI responsive if many files cannot be opened when archiving.
|
||||
// Call after SysErrMsg to avoid modifying the error code and SysErrMsg text.
|
||||
Wait();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -21,17 +21,11 @@
|
|||
#ifndef SFX_MODULE
|
||||
void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *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,8 +33,8 @@ void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *Name)
|
|||
case STREAM_HEAD:
|
||||
ExtractStreams20(Arc,Name);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -112,6 +106,68 @@ static bool LinkInPath(const wchar *Name)
|
|||
}
|
||||
|
||||
|
||||
// Delete symbolic links in file path, if any, and replace them by directories.
|
||||
// Prevents extracting files outside of destination folder with symlink chains.
|
||||
bool LinksToDirs(const wchar *SrcName,const wchar *SkipPart,std::wstring &LastChecked)
|
||||
{
|
||||
// Unlike Unix, Windows doesn't expand lnk1 in symlink targets like
|
||||
// "lnk1/../dir", but converts the path to "dir". In Unix we need to call
|
||||
// this function to prevent placing unpacked files outside of destination
|
||||
// folder if previously we unpacked "dir/lnk1" -> "..",
|
||||
// "dir/lnk2" -> "lnk1/.." and "dir/lnk2/anypath/poc.txt".
|
||||
// We may still need this function to prevent abusing symlink chains
|
||||
// in link source path if we remove detection of such chains
|
||||
// in IsRelativeSymlinkSafe. This function seems to make other symlink
|
||||
// related safety checks redundant, but for now we prefer to keep them too.
|
||||
//
|
||||
// 2022.12.01: the performance impact is minimized after adding the check
|
||||
// against the previous path and enabling this verification only after
|
||||
// extracting a symlink with ".." in target. So we enabled it for Windows
|
||||
// as well for extra safety.
|
||||
//#ifdef _UNIX
|
||||
wchar Path[NM];
|
||||
if (wcslen(SrcName)>=ASIZE(Path))
|
||||
return false; // It should not be that long, skip.
|
||||
wcsncpyz(Path,SrcName,ASIZE(Path));
|
||||
|
||||
size_t SkipLength=wcslen(SkipPart);
|
||||
|
||||
if (SkipLength>0 && wcsncmp(Path,SkipPart,SkipLength)!=0)
|
||||
SkipLength=0; // Parameter validation, not really needed now.
|
||||
|
||||
// Do not check parts already checked in previous path to improve performance.
|
||||
for (uint I=0;Path[I]!=0 && I<LastChecked.size() && Path[I]==LastChecked[I];I++)
|
||||
if (IsPathDiv(Path[I]) && I>SkipLength)
|
||||
SkipLength=I;
|
||||
|
||||
wchar *Name=Path;
|
||||
if (SkipLength>0)
|
||||
{
|
||||
// Avoid converting symlinks in destination path part specified by user.
|
||||
Name+=SkipLength;
|
||||
while (IsPathDiv(*Name))
|
||||
Name++;
|
||||
}
|
||||
|
||||
for (wchar *s=Path+wcslen(Path)-1;s>Name;s--)
|
||||
if (IsPathDiv(*s))
|
||||
{
|
||||
*s=0;
|
||||
FindData FD;
|
||||
if (FindFile::FastFind(Path,&FD,true) && FD.IsLink)
|
||||
#ifdef _WIN_ALL
|
||||
if (!DelDir(Path))
|
||||
#else
|
||||
if (!DelFile(Path))
|
||||
#endif
|
||||
return false; // Couldn't delete the symlink to replace it with directory.
|
||||
}
|
||||
LastChecked=SrcName;
|
||||
//#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName)
|
||||
{
|
||||
// Catch root dir based /path/file paths also as stuff like \\?\.
|
||||
|
@ -131,10 +187,14 @@ bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *Pr
|
|||
UpLevels++;
|
||||
TargetName++;
|
||||
}
|
||||
// If link target includes "..", it must not have another links
|
||||
// in the path, because they can bypass our safety check. For example,
|
||||
// If link target includes "..", it must not have another links in its
|
||||
// source path, because they can bypass our safety check. For example,
|
||||
// suppose we extracted "lnk1" -> "." first and "lnk1/lnk2" -> ".." next
|
||||
// or "dir/lnk1" -> ".." first and "dir/lnk1/lnk2" -> ".." next.
|
||||
// or "dir/lnk1" -> ".." first, "dir/lnk1/lnk2" -> ".." next and
|
||||
// file "dir/lnk1/lnk2/poc.txt" last.
|
||||
// Do not confuse with link chains in target, this is in link source path.
|
||||
// It is important for Windows too, though this check can be omitted
|
||||
// if LinksToDirs is invoked in Windows as well.
|
||||
if (UpLevels>0 && LinkInPath(PrepSrcName))
|
||||
return false;
|
||||
|
||||
|
@ -160,15 +220,26 @@ bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *Pr
|
|||
}
|
||||
|
||||
|
||||
bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName)
|
||||
bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName,bool &UpLink)
|
||||
{
|
||||
// Returning true in Uplink indicates that link target might include ".."
|
||||
// and enables additional checks. It is ok to falsely return true here,
|
||||
// as it implies only the minor performance penalty. But we shall always
|
||||
// return true for links with ".." in target for security reason.
|
||||
|
||||
UpLink=true; // Assume the target might include potentially unsafe "..".
|
||||
#if defined(SAVE_LINKS) && defined(_UNIX) || defined(_WIN_ALL)
|
||||
if (Arc.Format==RARFMT50) // For RAR5 archives we can check RedirName for both Unix and Windows.
|
||||
UpLink=wcsstr(Arc.FileHead.RedirName,L"..")!=NULL;
|
||||
#endif
|
||||
|
||||
#if defined(SAVE_LINKS) && defined(_UNIX)
|
||||
// For RAR 3.x archives we process links even in test mode to skip link data.
|
||||
if (Arc.Format==RARFMT15)
|
||||
return ExtractUnixLink30(Cmd,DataIO,Arc,LinkName);
|
||||
return ExtractUnixLink30(Cmd,DataIO,Arc,LinkName,UpLink);
|
||||
if (Arc.Format==RARFMT50)
|
||||
return ExtractUnixLink50(Cmd,LinkName,&Arc.FileHead);
|
||||
#elif defined _WIN_ALL
|
||||
#elif defined(_WIN_ALL)
|
||||
// RAR 5.0 archives store link information in file header, so there is
|
||||
// no need to additionally test it if we do not create a file.
|
||||
if (Arc.Format==RARFMT50)
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#ifndef _RAR_EXTINFO_
|
||||
#define _RAR_EXTINFO_
|
||||
|
||||
bool LinksToDirs(const wchar *SrcName,const wchar *SkipPart,std::wstring &LastChecked);
|
||||
bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName);
|
||||
bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName);
|
||||
bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName,bool &UpLink);
|
||||
#ifdef _UNIX
|
||||
void SetUnixOwner(Archive &Arc,const wchar *FileName);
|
||||
#endif
|
||||
|
|
|
@ -5,10 +5,30 @@ CmdExtract::CmdExtract(CommandData *Cmd)
|
|||
CmdExtract::Cmd=Cmd;
|
||||
|
||||
*ArcName=0;
|
||||
|
||||
*DestFileName=0;
|
||||
|
||||
ArcAnalyzed=false;
|
||||
Analyze=new AnalyzeData;
|
||||
memset(Analyze,0,sizeof(*Analyze));
|
||||
|
||||
TotalFileCount=0;
|
||||
|
||||
// Common for all archives involved. Set here instead of DoExtract()
|
||||
// to use in unrar.dll too. Allows to avoid LinksToDirs() calls
|
||||
// and save CPU time in no symlinks including ".." in target were extracted.
|
||||
#if defined(_WIN_ALL)
|
||||
// We can't expand symlink path components in another symlink target
|
||||
// in Windows. We can't create symlinks in Android now. Even though we do not
|
||||
// really need LinksToDirs() calls in these systems, we still call it
|
||||
// for extra safety, but only if symlink with ".." in target was extracted.
|
||||
ConvertSymlinkPaths=false;
|
||||
#else
|
||||
// We enable it by default in Unix to care about the case when several
|
||||
// archives are unpacked to same directory with several independent RAR runs.
|
||||
// Worst case performance penalty for a lot of small files seems to be ~3%.
|
||||
ConvertSymlinkPaths=true;
|
||||
#endif
|
||||
|
||||
Unp=new Unpack(&DataIO);
|
||||
#ifdef RAR_SMP
|
||||
Unp->SetThreads(Cmd->Threads);
|
||||
|
@ -18,7 +38,26 @@ CmdExtract::CmdExtract(CommandData *Cmd)
|
|||
|
||||
CmdExtract::~CmdExtract()
|
||||
{
|
||||
FreeAnalyzeData();
|
||||
delete Unp;
|
||||
delete Analyze;
|
||||
}
|
||||
|
||||
|
||||
void CmdExtract::FreeAnalyzeData()
|
||||
{
|
||||
for (size_t I=0;I<RefList.Size();I++)
|
||||
{
|
||||
// We can have undeleted temporary reference source here if extraction
|
||||
// was interrupted early or if user refused to overwrite prompt.
|
||||
if (RefList[I].TmpName!=NULL)
|
||||
DelFile(RefList[I].TmpName);
|
||||
free(RefList[I].RefName);
|
||||
free(RefList[I].TmpName);
|
||||
}
|
||||
RefList.Reset();
|
||||
|
||||
memset(Analyze,0,sizeof(*Analyze));
|
||||
}
|
||||
|
||||
|
||||
|
@ -30,10 +69,13 @@ void CmdExtract::DoExtract()
|
|||
PasswordCancelled=false;
|
||||
DataIO.SetCurrentCommand(Cmd->Command[0]);
|
||||
|
||||
if (*Cmd->UseStdin==0)
|
||||
{
|
||||
FindData FD;
|
||||
while (Cmd->GetArcName(ArcName,ASIZE(ArcName)))
|
||||
if (FindFile::FastFind(ArcName,&FD))
|
||||
DataIO.TotalArcSize+=FD.Size;
|
||||
}
|
||||
|
||||
Cmd->ArcNames.Rewind();
|
||||
while (Cmd->GetArcName(ArcName,ASIZE(ArcName)))
|
||||
|
@ -97,7 +139,11 @@ void CmdExtract::ExtractArchiveInit(Archive &Arc)
|
|||
AllMatchesExact=true;
|
||||
AnySolidDataUnpackedWell=false;
|
||||
|
||||
ArcAnalyzed=false;
|
||||
|
||||
StartTime.SetCurrentTime();
|
||||
|
||||
LastCheckedSymlink.clear();
|
||||
}
|
||||
|
||||
|
||||
|
@ -168,15 +214,28 @@ EXTRACT_ARC_CODE CmdExtract::ExtractArchive()
|
|||
}
|
||||
#endif
|
||||
|
||||
Arc.ViewComment(); // Must be before possible EXTRACT_ARC_REPEAT.
|
||||
|
||||
int64 VolumeSetSize=0; // Total size of volumes after the current volume.
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
if (!ArcAnalyzed && *Cmd->UseStdin==0)
|
||||
{
|
||||
AnalyzeArchive(Arc.FileName,Arc.Volume,Arc.NewNumbering);
|
||||
ArcAnalyzed=true; // Avoid repeated analysis on EXTRACT_ARC_REPEAT.
|
||||
}
|
||||
#endif
|
||||
|
||||
if (Arc.Volume)
|
||||
{
|
||||
#ifndef SFX_MODULE
|
||||
// Try to speed up extraction for independent solid volumes by starting
|
||||
// extraction from non-first volume if we can.
|
||||
if (!UseExactVolName && Arc.Solid && DetectStartVolume(Arc.FileName,Arc.NewNumbering))
|
||||
if (*Analyze->StartName!=0)
|
||||
{
|
||||
wcsncpyz(ArcName,Analyze->StartName,ASIZE(ArcName));
|
||||
*Analyze->StartName=0;
|
||||
|
||||
UseExactVolName=true;
|
||||
return EXTRACT_ARC_REPEAT;
|
||||
}
|
||||
|
@ -216,7 +275,13 @@ EXTRACT_ARC_CODE CmdExtract::ExtractArchive()
|
|||
else
|
||||
uiStartArchiveExtract(!Cmd->Test,ArcName);
|
||||
|
||||
Arc.ViewComment();
|
||||
#ifndef SFX_MODULE
|
||||
if (Analyze->StartPos!=0)
|
||||
{
|
||||
Arc.Seek(Analyze->StartPos,SEEK_SET);
|
||||
Analyze->StartPos=0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
while (1)
|
||||
|
@ -272,7 +337,14 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
|
|||
return false;
|
||||
|
||||
HEADER_TYPE HeaderType=Arc.GetHeaderType();
|
||||
if (HeaderType!=HEAD_FILE)
|
||||
if (HeaderType==HEAD_FILE)
|
||||
{
|
||||
// Unlike Arc.FileName, ArcName might store an old volume name here.
|
||||
if (Analyze->EndPos!=0 && Analyze->EndPos==Arc.CurBlockPos &&
|
||||
(*Analyze->EndName==0 || wcscmp(Analyze->EndName,Arc.FileName)==0))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef SFX_MODULE
|
||||
if (Arc.Format==RARFMT15 && HeaderType==HEAD3_OLDSERVICE && PrevProcessed)
|
||||
|
@ -315,6 +387,9 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
|
|||
if (Arc.FileHead.UnpSize<0)
|
||||
Arc.FileHead.UnpSize=0;
|
||||
|
||||
// 2022.03.20: We might remove this check in the future.
|
||||
// It duplicates Analyze->EndPos and Analyze->EndName in all cases except
|
||||
// volumes on removable media.
|
||||
if (!Cmd->Recurse && MatchedArgs>=Cmd->FileArgs.ItemsCount() && AllMatchesExact)
|
||||
return false;
|
||||
|
||||
|
@ -413,13 +488,39 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
|
|||
FirstFile=false;
|
||||
#endif
|
||||
|
||||
bool RefTarget=false;
|
||||
if (!MatchFound)
|
||||
for (size_t I=0;I<RefList.Size();I++)
|
||||
if (wcscmp(ArcFileName,RefList[I].RefName)==0)
|
||||
{
|
||||
ExtractRef *MatchedRef=&RefList[I];
|
||||
|
||||
if (!Cmd->Test) // While harmless, it is useless for 't'.
|
||||
{
|
||||
// If reference source isn't selected, but target is selected,
|
||||
// we unpack the source under the temporary name and then rename
|
||||
// or copy it to target name. We do not unpack it under the target
|
||||
// name immediately, because the same source can be used by multiple
|
||||
// targets and it is possible that first target isn't unpacked
|
||||
// for some reason. Also targets might have associated service blocks
|
||||
// like ACLs. All this would complicate processing a lot.
|
||||
wcsncpyz(DestFileName,*Cmd->TempPath!=0 ? Cmd->TempPath:Cmd->ExtrPath,ASIZE(DestFileName));
|
||||
AddEndSlash(DestFileName,ASIZE(DestFileName));
|
||||
wcsncatz(DestFileName,L"__tmp_reference_source_",ASIZE(DestFileName));
|
||||
MkTemp(DestFileName,ASIZE(DestFileName));
|
||||
MatchedRef->TmpName=wcsdup(DestFileName);
|
||||
}
|
||||
RefTarget=true; // Need it even for 't' to test the reference source.
|
||||
break;
|
||||
}
|
||||
|
||||
if (Arc.FileHead.Encrypted && Cmd->SkipEncrypted)
|
||||
if (Arc.Solid)
|
||||
return false; // Abort the entire extraction for solid archive.
|
||||
else
|
||||
MatchFound=false; // Skip only the current file for non-solid archive.
|
||||
|
||||
if (MatchFound || (SkipSolid=Arc.Solid)!=0)
|
||||
if (MatchFound || RefTarget || (SkipSolid=Arc.Solid)!=0)
|
||||
{
|
||||
// First common call of uiStartFileExtract. It is done before overwrite
|
||||
// prompts, so if SkipSolid state is changed below, we'll need to make
|
||||
|
@ -427,6 +528,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
|
|||
if (!uiStartFileExtract(ArcFileName,!Cmd->Test,Cmd->Test && Command!='I',SkipSolid))
|
||||
return false;
|
||||
|
||||
if (!RefTarget)
|
||||
ExtrPrepareName(Arc,ArcFileName,DestFileName,ASIZE(DestFileName));
|
||||
|
||||
// DestFileName can be set empty in case of excessive -ap switch.
|
||||
|
@ -464,9 +566,13 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
|
|||
return !Arc.Solid; // Can try extracting next file only in non-solid archive.
|
||||
}
|
||||
|
||||
while (true) // Repeat the password prompt for wrong and empty passwords.
|
||||
{
|
||||
if (Arc.FileHead.Encrypted)
|
||||
{
|
||||
RarCheckPassword CheckPwd;
|
||||
if (Arc.Format==RARFMT50 && Arc.FileHead.UsePswCheck && !Arc.BrokenHeader)
|
||||
CheckPwd.Set(Arc.FileHead.Salt,Arc.FileHead.InitV,Arc.FileHead.Lg2Count,Arc.FileHead.PswCheck);
|
||||
|
||||
while (true) // Repeat the password prompt for wrong and empty passwords.
|
||||
{
|
||||
// Stop archive extracting if user cancelled a password prompt.
|
||||
#ifdef RARDLL
|
||||
|
@ -476,20 +582,19 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
|
|||
return false;
|
||||
}
|
||||
#else
|
||||
if (!ExtrGetPassword(Arc,ArcFileName))
|
||||
if (!ExtrGetPassword(Arc,ArcFileName,CheckPwd.IsSet() ? &CheckPwd:NULL))
|
||||
{
|
||||
PasswordCancelled=true;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Set a password before creating the file, so we can skip creating
|
||||
// in case of wrong password.
|
||||
SecPassword FilePassword=Cmd->Password;
|
||||
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
|
||||
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
|
||||
ConvertDosPassword(Arc,FilePassword);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
byte PswCheck[SIZE_PSWCHECK];
|
||||
DataIO.SetEncryption(false,Arc.FileHead.CryptMethod,&FilePassword,
|
||||
|
@ -499,9 +604,8 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
|
|||
|
||||
// If header is damaged, we cannot rely on password check value,
|
||||
// because it can be damaged too.
|
||||
if (Arc.FileHead.Encrypted && Arc.FileHead.UsePswCheck &&
|
||||
memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0 &&
|
||||
!Arc.BrokenHeader)
|
||||
if (Arc.FileHead.UsePswCheck && !Arc.BrokenHeader &&
|
||||
memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0)
|
||||
{
|
||||
if (GlobalPassword) // For -p<pwd> or Ctrl+P to avoid the infinite loop.
|
||||
{
|
||||
|
@ -518,35 +622,43 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
|
|||
|
||||
// Avoid new requests for unrar.dll to prevent the infinite loop
|
||||
// if app always returns the same password.
|
||||
#ifndef RARDLL
|
||||
#ifndef RARDLL
|
||||
continue; // Request a password again.
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#ifdef RARDLL
|
||||
#ifdef RARDLL
|
||||
// If we already have ERAR_EOPEN as result of missing volume,
|
||||
// we should not replace it with less precise ERAR_BAD_PASSWORD.
|
||||
if (Cmd->DllError!=ERAR_EOPEN)
|
||||
Cmd->DllError=ERAR_BAD_PASSWORD;
|
||||
#endif
|
||||
#endif
|
||||
ErrHandler.SetErrorCode(RARX_BADPWD);
|
||||
ExtrFile=false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
DataIO.SetEncryption(false,CRYPT_NONE,NULL,NULL,NULL,0,NULL,NULL);
|
||||
|
||||
#ifdef RARDLL
|
||||
if (*Cmd->DllDestName!=0)
|
||||
wcsncpyz(DestFileName,Cmd->DllDestName,ASIZE(DestFileName));
|
||||
#endif
|
||||
|
||||
if (ExtrFile && Command!='P' && !Cmd->Test && !Cmd->AbsoluteLinks &&
|
||||
ConvertSymlinkPaths)
|
||||
ExtrFile=LinksToDirs(DestFileName,Cmd->ExtrPath,LastCheckedSymlink);
|
||||
|
||||
File CurFile;
|
||||
|
||||
bool LinkEntry=Arc.FileHead.RedirType!=FSREDIR_NONE;
|
||||
if (LinkEntry && Arc.FileHead.RedirType!=FSREDIR_FILECOPY)
|
||||
if (LinkEntry && (Arc.FileHead.RedirType!=FSREDIR_FILECOPY))
|
||||
{
|
||||
if (ExtrFile && Command!='P' && !Cmd->Test)
|
||||
{
|
||||
// Overwrite prompt for symbolic and hard links.
|
||||
// Overwrite prompt for symbolic and hard links and when we move
|
||||
// a temporary file to the file reference instead of copying it.
|
||||
bool UserReject=false;
|
||||
if (FileExist(DestFileName) && !UserReject)
|
||||
FileCreate(Cmd,NULL,DestFileName,ASIZE(DestFileName),&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime);
|
||||
|
@ -667,7 +779,17 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
|
|||
if (Type==FSREDIR_HARDLINK || Type==FSREDIR_FILECOPY)
|
||||
{
|
||||
wchar RedirName[NM];
|
||||
ConvertPath(Arc.FileHead.RedirName,RedirName,ASIZE(RedirName));
|
||||
|
||||
// 2022.11.15: Might be needed when unpacking WinRAR 5.0 links with
|
||||
// Unix RAR. WinRAR 5.0 used \ path separators here, when beginning
|
||||
// from 5.10 even Windows version uses / internally and converts
|
||||
// them to \ when reading FHEXTRA_REDIR.
|
||||
// We must perform this conversion before ConvertPath call,
|
||||
// so paths mixing different slashes like \dir1/dir2\file are
|
||||
// processed correctly.
|
||||
SlashToNative(Arc.FileHead.RedirName,RedirName,ASIZE(RedirName));
|
||||
|
||||
ConvertPath(RedirName,RedirName,ASIZE(RedirName));
|
||||
|
||||
wchar NameExisting[NM];
|
||||
ExtrPrepareName(Arc,RedirName,NameExisting,ASIZE(NameExisting));
|
||||
|
@ -675,17 +797,37 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
|
|||
if (Type==FSREDIR_HARDLINK)
|
||||
LinkSuccess=ExtractHardlink(Cmd,DestFileName,NameExisting,ASIZE(NameExisting));
|
||||
else
|
||||
LinkSuccess=ExtractFileCopy(CurFile,Arc.FileName,DestFileName,NameExisting,ASIZE(NameExisting));
|
||||
LinkSuccess=ExtractFileCopy(CurFile,Arc.FileName,RedirName,DestFileName,NameExisting,ASIZE(NameExisting),Arc.FileHead.UnpSize);
|
||||
}
|
||||
else
|
||||
if (Type==FSREDIR_UNIXSYMLINK || Type==FSREDIR_WINSYMLINK || Type==FSREDIR_JUNCTION)
|
||||
{
|
||||
if (FileCreateMode)
|
||||
LinkSuccess=ExtractSymlink(Cmd,DataIO,Arc,DestFileName);
|
||||
{
|
||||
bool UpLink;
|
||||
LinkSuccess=ExtractSymlink(Cmd,DataIO,Arc,DestFileName,UpLink);
|
||||
|
||||
// Unix symlink can have its own owner data.
|
||||
if (LinkSuccess)
|
||||
SetFileHeaderExtra(Cmd,Arc,DestFileName);
|
||||
|
||||
ConvertSymlinkPaths|=LinkSuccess && UpLink;
|
||||
|
||||
// We do not actually need to reset the cache here if we cache
|
||||
// only the single last checked path, because at this point
|
||||
// it will always contain the link own path and link can't
|
||||
// overwrite its parent folder. But if we ever decide to cache
|
||||
// several already checked paths, we'll need to reset them here.
|
||||
// Otherwise if no files were created in one of such paths,
|
||||
// let's say because of file create error, it might be possible
|
||||
// to overwrite the path with link and avoid checks. We keep this
|
||||
// code here as a reminder in case of possible modifications.
|
||||
LastCheckedSymlink.clear(); // Reset cache for safety reason.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uiMsg(UIERROR_UNKNOWNEXTRA,Arc.FileName,DestFileName);
|
||||
uiMsg(UIERROR_UNKNOWNEXTRA,Arc.FileName,ArcFileName);
|
||||
LinkSuccess=false;
|
||||
}
|
||||
|
||||
|
@ -709,6 +851,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
|
|||
Unp->Init(Arc.FileHead.WinSize,Arc.FileHead.Solid);
|
||||
Unp->SetDestSize(Arc.FileHead.UnpSize);
|
||||
#ifndef SFX_MODULE
|
||||
// RAR 1.3 - 1.5 archives do not set per file solid flag.
|
||||
if (Arc.Format!=RARFMT50 && Arc.FileHead.UnpVer<=15)
|
||||
Unp->DoUnpack(15,FileCount>1 && Arc.Solid);
|
||||
else
|
||||
|
@ -866,13 +1009,54 @@ void CmdExtract::UnstoreFile(ComprDataIO &DataIO,int64 DestUnpSize)
|
|||
}
|
||||
|
||||
|
||||
bool CmdExtract::ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize)
|
||||
bool CmdExtract::ExtractFileCopy(File &New,wchar *ArcName,const wchar *RedirName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize,int64 UnpSize)
|
||||
{
|
||||
SlashToNative(NameExisting,NameExisting,NameExistingSize); // Not needed for RAR 5.1+ archives.
|
||||
|
||||
File Existing;
|
||||
if (!Existing.WOpen(NameExisting))
|
||||
if (!Existing.Open(NameExisting))
|
||||
{
|
||||
bool OpenFailed=true;
|
||||
// If we couldn't find the existing file, check if match is present
|
||||
// in temporary reference sources list.
|
||||
for (size_t I=0;I<RefList.Size();I++)
|
||||
if (wcscmp(RedirName,RefList[I].RefName)==0 && RefList[I].TmpName!=NULL)
|
||||
{
|
||||
// If only one reference left targeting to this temporary file,
|
||||
// it is faster to move the file instead of copying and deleting it.
|
||||
bool RefMove=RefList[I].RefCount-- == 1;
|
||||
NameExisting=RefList[I].TmpName;
|
||||
if (RefMove) // Only one reference left for this temporary file.
|
||||
{
|
||||
New.Delete(); // Delete the previously opened destination file.
|
||||
// Try moving the file first.
|
||||
bool MoveFailed=!RenameFile(NameExisting,NameNew);
|
||||
if (MoveFailed)
|
||||
{
|
||||
// If move failed, re-create the destination and try coping.
|
||||
if (!New.WCreate(NameNew,FMF_WRITE|FMF_SHAREREAD))
|
||||
return false;
|
||||
RefMove=false; // Try copying below.
|
||||
}
|
||||
else
|
||||
{
|
||||
// If moved successfully, reopen the destination file and seek to
|
||||
// end for SetOpenFileTime() and possible Truncate() calls later.
|
||||
if (New.Open(NameNew))
|
||||
New.Seek(0,SEEK_END);
|
||||
// We already moved the file, so clean the name to not try
|
||||
// deleting non-existent temporary file later.
|
||||
free(RefList[I].TmpName);
|
||||
RefList[I].TmpName=NULL;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!RefMove)
|
||||
OpenFailed=!Existing.Open(NameExisting);
|
||||
break;
|
||||
}
|
||||
|
||||
if (OpenFailed)
|
||||
{
|
||||
ErrHandler.OpenErrorMsg(NameExisting);
|
||||
uiMsg(UIERROR_FILECOPY,ArcName,NameExisting,NameNew);
|
||||
uiMsg(UIERROR_FILECOPYHINT,ArcName);
|
||||
#ifdef RARDLL
|
||||
|
@ -880,8 +1064,9 @@ bool CmdExtract::ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *
|
|||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Array<char> Buffer(0x100000);
|
||||
Array<byte> Buffer(0x100000);
|
||||
int64 CopySize=0;
|
||||
|
||||
while (true)
|
||||
|
@ -890,6 +1075,10 @@ bool CmdExtract::ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *
|
|||
int ReadSize=Existing.Read(&Buffer[0],Buffer.Size());
|
||||
if (ReadSize==0)
|
||||
break;
|
||||
// Update only the current file progress in WinRAR, set the total to 0
|
||||
// to keep it as is. It looks better for WinRAR.
|
||||
uiExtractProgress(CopySize,UnpSize,0,0);
|
||||
|
||||
New.Write(&Buffer[0],ReadSize);
|
||||
CopySize+=ReadSize;
|
||||
}
|
||||
|
@ -900,6 +1089,16 @@ bool CmdExtract::ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *
|
|||
|
||||
void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize)
|
||||
{
|
||||
if (Cmd->Test)
|
||||
{
|
||||
// Destination name conversion isn't needed for simple archive test.
|
||||
// This check also allows to avoid issuing "Attempting to correct...
|
||||
// Renaming..." messages in MakeNameCompatible() below for problematic
|
||||
// names like aux.txt when testing an archive.
|
||||
wcsncpyz(DestName,ArcFileName,DestSize);
|
||||
return;
|
||||
}
|
||||
|
||||
wcsncpyz(DestName,Cmd->ExtrPath,DestSize);
|
||||
|
||||
if (*Cmd->ExtrPath!=0)
|
||||
|
@ -1033,11 +1232,11 @@ bool CmdExtract::ExtrDllGetPassword()
|
|||
|
||||
|
||||
#ifndef RARDLL
|
||||
bool CmdExtract::ExtrGetPassword(Archive &Arc,const wchar *ArcFileName)
|
||||
bool CmdExtract::ExtrGetPassword(Archive &Arc,const wchar *ArcFileName,RarCheckPassword *CheckPwd)
|
||||
{
|
||||
if (!Cmd->Password.IsSet())
|
||||
{
|
||||
if (!uiGetPassword(UIPASSWORD_FILE,ArcFileName,&Cmd->Password)/* || !Cmd->Password.IsSet()*/)
|
||||
if (!uiGetPassword(UIPASSWORD_FILE,ArcFileName,&Cmd->Password,CheckPwd)/* || !Cmd->Password.IsSet()*/)
|
||||
{
|
||||
// Suppress "test is ok" message if user cancelled the password prompt.
|
||||
uiMsg(UIERROR_INCERRCOUNT);
|
||||
|
@ -1055,7 +1254,7 @@ bool CmdExtract::ExtrGetPassword(Archive &Arc,const wchar *ArcFileName)
|
|||
case -1:
|
||||
ErrHandler.Exit(RARX_USERBREAK);
|
||||
case 2:
|
||||
if (!uiGetPassword(UIPASSWORD_FILE,ArcFileName,&Cmd->Password))
|
||||
if (!uiGetPassword(UIPASSWORD_FILE,ArcFileName,&Cmd->Password,CheckPwd))
|
||||
return false;
|
||||
break;
|
||||
case 3:
|
||||
|
@ -1131,6 +1330,8 @@ void CmdExtract::ExtrCreateDir(Archive &Arc,const wchar *ArcFileName)
|
|||
DirExist=FileExist(DestFileName) && IsDir(GetFileAttr(DestFileName));
|
||||
if (!DirExist)
|
||||
{
|
||||
if (!Cmd->AbsoluteLinks && ConvertSymlinkPaths)
|
||||
LinksToDirs(DestFileName,Cmd->ExtrPath,LastCheckedSymlink);
|
||||
CreatePath(DestFileName,true,Cmd->DisableNames);
|
||||
MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,Arc.FileHead.FileAttr);
|
||||
}
|
||||
|
@ -1212,6 +1413,8 @@ bool CmdExtract::ExtrCreateFile(Archive &Arc,File &CurFile)
|
|||
|
||||
MakeNameUsable(DestFileName,true);
|
||||
|
||||
if (!Cmd->AbsoluteLinks && ConvertSymlinkPaths)
|
||||
LinksToDirs(DestFileName,Cmd->ExtrPath,LastCheckedSymlink);
|
||||
CreatePath(DestFileName,true,Cmd->DisableNames);
|
||||
if (FileCreate(Cmd,&CurFile,DestFileName,ASIZE(DestFileName),&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime,true))
|
||||
{
|
||||
|
@ -1258,31 +1461,59 @@ bool CmdExtract::CheckUnpVer(Archive &Arc,const wchar *ArcFileName)
|
|||
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
// To speed up solid volumes extraction, try to find a non-first start volume,
|
||||
// which still allows to unpack all files. It is possible for independent
|
||||
// solid volumes with solid statistics reset in the beginning.
|
||||
bool CmdExtract::DetectStartVolume(const wchar *VolName,bool NewNumbering)
|
||||
// Find non-matched reference sources in solid and non-solid archives.
|
||||
// Detect the optimal start position for semi-solid archives
|
||||
// and optimal start volume for independent solid volumes.
|
||||
//
|
||||
// Alternatively we could collect references while extracting an archive
|
||||
// and perform the second extraction pass for references only.
|
||||
// But it would be slower for solid archives than scaning headers
|
||||
// in first pass and extracting everything in second, as implemented now.
|
||||
//
|
||||
void CmdExtract::AnalyzeArchive(const wchar *ArcName,bool Volume,bool NewNumbering)
|
||||
{
|
||||
FreeAnalyzeData(); // If processing non-first archive in multiple archives set.
|
||||
|
||||
wchar *ArgName=Cmd->FileArgs.GetString();
|
||||
Cmd->FileArgs.Rewind();
|
||||
if (ArgName!=NULL && (wcscmp(ArgName,L"*")==0 || wcscmp(ArgName,L"*.*")==0))
|
||||
return false; // No need to check further for * and *.* masks.
|
||||
|
||||
wchar StartName[NM];
|
||||
*StartName=0;
|
||||
return; // No need to check further for * and *.* masks.
|
||||
|
||||
// Start search from first volume if all volumes preceding current are available.
|
||||
wchar NextName[NM];
|
||||
GetFirstVolIfFullSet(VolName,NewNumbering,NextName,ASIZE(NextName));
|
||||
if (Volume)
|
||||
GetFirstVolIfFullSet(ArcName,NewNumbering,NextName,ASIZE(NextName));
|
||||
else
|
||||
wcsncpyz(NextName,ArcName,ASIZE(NextName));
|
||||
|
||||
bool Matched=false;
|
||||
while (!Matched)
|
||||
bool MatchFound=false;
|
||||
bool PrevMatched=false;
|
||||
bool OpenNext=false;
|
||||
|
||||
bool FirstVolume=true;
|
||||
|
||||
// We shall set FirstFile once for all volumes and not for each volume.
|
||||
// So we do not reuse the outdated Analyze->StartPos from previous volume
|
||||
// if extracted file resides completely in the beginning of current one.
|
||||
bool FirstFile=true;
|
||||
|
||||
while (true)
|
||||
{
|
||||
Archive Arc(Cmd);
|
||||
if (!Arc.Open(NextName) || !Arc.IsArchive(false) || !Arc.Volume)
|
||||
if (!Arc.Open(NextName) || !Arc.IsArchive(false))
|
||||
{
|
||||
if (OpenNext)
|
||||
{
|
||||
// If we couldn't open trailing volumes, we can't set early exit
|
||||
// parameters. It is possible that some volume are on removable media
|
||||
// and will be provided by user when extracting.
|
||||
*Analyze->EndName=0;
|
||||
Analyze->EndPos=0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
bool OpenNext=false;
|
||||
OpenNext=false;
|
||||
while (Arc.ReadHeader()>0)
|
||||
{
|
||||
Wait();
|
||||
|
@ -1295,17 +1526,88 @@ bool CmdExtract::DetectStartVolume(const wchar *VolName,bool NewNumbering)
|
|||
}
|
||||
if (HeaderType==HEAD_FILE)
|
||||
{
|
||||
if ((Arc.Format==RARFMT14 || Arc.Format==RARFMT15) && Arc.FileHead.UnpVer<=15)
|
||||
{
|
||||
// RAR versions earlier than 2.0 do not set per file solid flag.
|
||||
// They have only the global archive solid flag, so we can't
|
||||
// reliably analyze them here.
|
||||
OpenNext=false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!Arc.FileHead.SplitBefore)
|
||||
{
|
||||
if (!Arc.FileHead.Solid) // Can start extraction from here.
|
||||
wcsncpyz(StartName,NextName,ASIZE(StartName));
|
||||
if (!MatchFound && !Arc.FileHead.Solid) // Can start extraction from here.
|
||||
{
|
||||
// We would gain nothing and unnecessarily complicate extraction
|
||||
// if we set StartName for first volume or StartPos for first
|
||||
// archived file.
|
||||
if (!FirstVolume)
|
||||
wcsncpyz(Analyze->StartName,NextName,ASIZE(Analyze->StartName));
|
||||
|
||||
// We shall set FirstFile once for all volumes for this code
|
||||
// to work properly. Alternatively we could append
|
||||
// "|| Analyze->StartPos!=0" to the condition, so we do not reuse
|
||||
// the outdated Analyze->StartPos value from previous volume.
|
||||
if (!FirstFile)
|
||||
Analyze->StartPos=Arc.CurBlockPos;
|
||||
}
|
||||
|
||||
if (Cmd->IsProcessFile(Arc.FileHead,NULL,MATCH_WILDSUBPATH,0,NULL,0)!=0)
|
||||
{
|
||||
Matched=true; // First matched file found, must stop further scan.
|
||||
MatchFound = true;
|
||||
PrevMatched = true;
|
||||
|
||||
// Reset the previously set early exit position, if any, because
|
||||
// we found a new matched file.
|
||||
Analyze->EndPos=0;
|
||||
|
||||
// Matched file reference pointing at maybe non-matched source file.
|
||||
// Even though we know RedirName, we can't check if source file
|
||||
// is certainly non-matched, because it can be filtered out by
|
||||
// date or attributes, which we do not know here.
|
||||
if (Arc.FileHead.RedirType==FSREDIR_FILECOPY)
|
||||
{
|
||||
bool AlreadyAdded=false;
|
||||
for (size_t I=0;I<RefList.Size();I++)
|
||||
if (wcscmp(Arc.FileHead.RedirName,RefList[I].RefName)==0)
|
||||
{
|
||||
// Increment the reference count if we added such reference
|
||||
// source earlier.
|
||||
RefList[I].RefCount++;
|
||||
AlreadyAdded=true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Limit the maximum size of reference sources list to some
|
||||
// sensible value to prevent the excessive memory allocation.
|
||||
size_t MaxListSize=1000000;
|
||||
|
||||
if (!AlreadyAdded && RefList.Size()<MaxListSize)
|
||||
{
|
||||
ExtractRef Ref={0};
|
||||
Ref.RefName=wcsdup(Arc.FileHead.RedirName);
|
||||
Ref.RefCount=1;
|
||||
RefList.Push(Ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PrevMatched) // First non-matched item after matched.
|
||||
{
|
||||
// We would perform the unnecessarily string comparison
|
||||
// when extracting if we set this value for first volume
|
||||
// or non-volume archive.
|
||||
if (!FirstVolume)
|
||||
wcsncpyz(Analyze->EndName,NextName,ASIZE(Analyze->EndName));
|
||||
Analyze->EndPos=Arc.CurBlockPos;
|
||||
}
|
||||
PrevMatched=false;
|
||||
}
|
||||
}
|
||||
|
||||
FirstFile=false;
|
||||
if (Arc.FileHead.SplitAfter)
|
||||
{
|
||||
OpenNext=true; // Allow open next volume.
|
||||
|
@ -1316,16 +1618,25 @@ bool CmdExtract::DetectStartVolume(const wchar *VolName,bool NewNumbering)
|
|||
}
|
||||
Arc.Close();
|
||||
|
||||
if (!OpenNext)
|
||||
break;
|
||||
|
||||
if (Volume && OpenNext)
|
||||
{
|
||||
NextVolumeName(NextName,ASIZE(NextName),!Arc.NewNumbering);
|
||||
}
|
||||
bool NewStartFound=wcscmp(VolName,StartName)!=0;
|
||||
if (NewStartFound) // Found a new volume to start extraction.
|
||||
wcsncpyz(ArcName,StartName,ASIZE(ArcName));
|
||||
FirstVolume=false;
|
||||
|
||||
return NewStartFound;
|
||||
// Needed for multivolume archives. Added in case some 'break'
|
||||
// will quit early from loop above, so we do not set it in the loop.
|
||||
// Now it can happen for hypothetical archive without file records
|
||||
// and with HEAD_ENDARC record.
|
||||
FirstFile=false;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// If file references are present, we can't reliably skip in semi-solid
|
||||
// archives, because reference source can be present in skipped data.
|
||||
if (RefList.Size()!=0)
|
||||
memset(Analyze,0,sizeof(*Analyze));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -6,13 +6,32 @@ enum EXTRACT_ARC_CODE {EXTRACT_ARC_NEXT,EXTRACT_ARC_REPEAT};
|
|||
class CmdExtract
|
||||
{
|
||||
private:
|
||||
struct ExtractRef
|
||||
{
|
||||
wchar *RefName;
|
||||
wchar *TmpName;
|
||||
uint64 RefCount;
|
||||
};
|
||||
Array<ExtractRef> RefList;
|
||||
|
||||
struct AnalyzeData
|
||||
{
|
||||
wchar StartName[NM];
|
||||
uint64 StartPos;
|
||||
wchar EndName[NM];
|
||||
uint64 EndPos;
|
||||
} *Analyze;
|
||||
|
||||
bool ArcAnalyzed;
|
||||
|
||||
void FreeAnalyzeData();
|
||||
EXTRACT_ARC_CODE ExtractArchive();
|
||||
bool ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize);
|
||||
bool ExtractFileCopy(File &New,wchar *ArcName,const wchar *RedirName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize,int64 UnpSize);
|
||||
void ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize);
|
||||
#ifdef RARDLL
|
||||
bool ExtrDllGetPassword();
|
||||
#else
|
||||
bool ExtrGetPassword(Archive &Arc,const wchar *ArcFileName);
|
||||
bool ExtrGetPassword(Archive &Arc,const wchar *ArcFileName,RarCheckPassword *CheckPwd);
|
||||
#endif
|
||||
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
|
||||
void ConvertDosPassword(Archive &Arc,SecPassword &DestPwd);
|
||||
|
@ -21,7 +40,7 @@ class CmdExtract
|
|||
bool ExtrCreateFile(Archive &Arc,File &CurFile);
|
||||
bool CheckUnpVer(Archive &Arc,const wchar *ArcFileName);
|
||||
#ifndef SFX_MODULE
|
||||
bool DetectStartVolume(const wchar *VolName,bool NewNumbering);
|
||||
void AnalyzeArchive(const wchar *ArcName,bool Volume,bool NewNumbering);
|
||||
void GetFirstVolIfFullSet(const wchar *SrcName,bool NewNumbering,wchar *DestName,size_t DestSize);
|
||||
#endif
|
||||
|
||||
|
@ -52,6 +71,15 @@ class CmdExtract
|
|||
bool PrevProcessed; // If previous file was successfully extracted or tested.
|
||||
wchar DestFileName[NM];
|
||||
bool PasswordCancelled;
|
||||
|
||||
// In Windows it is set to true if at least one symlink with ".."
|
||||
// in target was extracted.
|
||||
bool ConvertSymlinkPaths;
|
||||
|
||||
// Last path checked for symlinks. We use it to improve the performance,
|
||||
// so we do not check recently checked folders again.
|
||||
std::wstring LastCheckedSymlink;
|
||||
|
||||
#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT)
|
||||
bool Fat32,NotFat32;
|
||||
#endif
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// If NewFile==NULL, we delete created file after user confirmation.
|
||||
// It is useful if we need to overwrite an existing folder or file,
|
||||
// but need user confirmation for that.
|
||||
bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
|
||||
bool FileCreate(CommandData *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
|
||||
bool *UserReject,int64 FileSize,RarTime *FileTime,bool WriteOnly)
|
||||
{
|
||||
if (UserReject!=NULL)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef _RAR_FILECREATE_
|
||||
#define _RAR_FILECREATE_
|
||||
|
||||
bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
|
||||
bool FileCreate(CommandData *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
|
||||
bool *UserReject,int64 FileSize=INT64NDF,
|
||||
RarTime *FileTime=NULL,bool WriteOnly=false);
|
||||
|
||||
|
|
|
@ -522,29 +522,35 @@ bool File::RawSeek(int64 Offset,int Method)
|
|||
{
|
||||
if (hFile==FILE_BAD_HANDLE)
|
||||
return true;
|
||||
if (!IsSeekable())
|
||||
{
|
||||
if (Method==SEEK_CUR)
|
||||
{
|
||||
Offset+=CurFilePos;
|
||||
Method=SEEK_SET;
|
||||
}
|
||||
if (Method==SEEK_SET && Offset>=CurFilePos) // Reading for seek forward.
|
||||
{
|
||||
uint64 SkipSize=Offset-CurFilePos;
|
||||
while (SkipSize>0)
|
||||
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;
|
||||
}
|
||||
CurFilePos=Offset;
|
||||
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 or end of file seek on unseekable file.
|
||||
return false; // Backward seek on unseekable file.
|
||||
}
|
||||
if (Offset<0 && Method!=SEEK_SET)
|
||||
{
|
||||
|
@ -732,17 +738,40 @@ void File::SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta)
|
|||
}
|
||||
|
||||
|
||||
void File::GetOpenFileTime(RarTime *ft)
|
||||
#ifdef _UNIX
|
||||
void File::StatToRarTime(struct stat &st,RarTime *ftm,RarTime *ftc,RarTime *fta)
|
||||
{
|
||||
#ifdef UNIX_TIME_NS
|
||||
#if defined(_APPLE)
|
||||
if (ftm!=NULL) ftm->SetUnixNS(st.st_mtimespec.tv_sec*(uint64)1000000000+st.st_mtimespec.tv_nsec);
|
||||
if (ftc!=NULL) ftc->SetUnixNS(st.st_ctimespec.tv_sec*(uint64)1000000000+st.st_ctimespec.tv_nsec);
|
||||
if (fta!=NULL) fta->SetUnixNS(st.st_atimespec.tv_sec*(uint64)1000000000+st.st_atimespec.tv_nsec);
|
||||
#else
|
||||
if (ftm!=NULL) ftm->SetUnixNS(st.st_mtim.tv_sec*(uint64)1000000000+st.st_mtim.tv_nsec);
|
||||
if (ftc!=NULL) ftc->SetUnixNS(st.st_ctim.tv_sec*(uint64)1000000000+st.st_ctim.tv_nsec);
|
||||
if (fta!=NULL) fta->SetUnixNS(st.st_atim.tv_sec*(uint64)1000000000+st.st_atim.tv_nsec);
|
||||
#endif
|
||||
#else
|
||||
if (ftm!=NULL) ftm->SetUnix(st.st_mtime);
|
||||
if (ftc!=NULL) ftc->SetUnix(st.st_ctime);
|
||||
if (fta!=NULL) fta->SetUnix(st.st_atime);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void File::GetOpenFileTime(RarTime *ftm,RarTime *ftc,RarTime *fta)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
FILETIME FileTime;
|
||||
GetFileTime(hFile,NULL,NULL,&FileTime);
|
||||
ft->SetWinFT(&FileTime);
|
||||
#endif
|
||||
#if defined(_UNIX) || defined(_EMX)
|
||||
FILETIME ctime,atime,mtime;
|
||||
GetFileTime(hFile,&ctime,&atime,&mtime);
|
||||
if (ftm!=NULL) ftm->SetWinFT(&mtime);
|
||||
if (ftc!=NULL) ftc->SetWinFT(&ctime);
|
||||
if (fta!=NULL) fta->SetWinFT(&atime);
|
||||
#elif defined(_UNIX)
|
||||
struct stat st;
|
||||
fstat(GetFD(),&st);
|
||||
ft->SetUnix(st.st_mtime);
|
||||
StatToRarTime(st,ftm,ftc,fta);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -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};
|
||||
|
@ -88,6 +86,9 @@ class File
|
|||
wchar FileName[NM];
|
||||
|
||||
FILE_ERRORTYPE ErrorType;
|
||||
|
||||
byte *SeekBuf; // To read instead of seek for stdin files.
|
||||
static const size_t SeekBufSize=0x10000;
|
||||
public:
|
||||
File();
|
||||
virtual ~File();
|
||||
|
@ -118,7 +119,10 @@ class File
|
|||
void SetOpenFileTime(RarTime *ftm,RarTime *ftc=NULL,RarTime *fta=NULL);
|
||||
void SetCloseFileTime(RarTime *ftm,RarTime *fta=NULL);
|
||||
static void SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta);
|
||||
void GetOpenFileTime(RarTime *ft);
|
||||
#ifdef _UNIX
|
||||
static void StatToRarTime(struct stat &st,RarTime *ftm,RarTime *ftc,RarTime *fta);
|
||||
#endif
|
||||
void GetOpenFileTime(RarTime *ftm,RarTime *ftc=NULL,RarTime *fta=NULL);
|
||||
virtual bool IsOpened() {return hFile!=FILE_BAD_HANDLE;} // 'virtual' for MultiFile class.
|
||||
int64 FileLength();
|
||||
void SetHandleType(FILE_HANDLETYPE Type) {HandleType=Type;}
|
||||
|
|
|
@ -320,7 +320,6 @@ bool SetFileAttr(const wchar *Name,uint Attr)
|
|||
}
|
||||
|
||||
|
||||
#if 0
|
||||
wchar *MkTemp(wchar *Name,size_t MaxSize)
|
||||
{
|
||||
size_t Length=wcslen(Name);
|
||||
|
@ -354,7 +353,6 @@ wchar *MkTemp(wchar *Name,size_t MaxSize)
|
|||
}
|
||||
return Name;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(SFX_MODULE)
|
||||
|
@ -399,7 +397,7 @@ void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,
|
|||
if ((Flags & CALCFSUM_SHOWPROGRESS)!=0)
|
||||
{
|
||||
// Update only the current file progress in WinRAR, set the total to 0
|
||||
// to keep it as is. It looks better for WinRAR,
|
||||
// to keep it as is. It looks better for WinRAR.
|
||||
uiExtractProgress(TotalRead,FileLength,0,0);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -27,9 +27,7 @@ bool IsDeleteAllowed(uint FileAttr);
|
|||
void PrepareToDelete(const wchar *Name);
|
||||
uint GetFileAttr(const wchar *Name);
|
||||
bool SetFileAttr(const wchar *Name,uint Attr);
|
||||
#if 0
|
||||
wchar* MkTemp(wchar *Name,size_t MaxSize);
|
||||
#endif
|
||||
|
||||
enum CALCFSUM_FLAGS {CALCFSUM_SHOWTEXT=1,CALCFSUM_SHOWPERCENT=2,CALCFSUM_SHOWPROGRESS=4,CALCFSUM_CURPOS=8};
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink)
|
|||
if (hFind==INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
FindClose(hFind);
|
||||
#else
|
||||
#elif defined(_UNIX)
|
||||
char FindMaskA[NM];
|
||||
WideToChar(FindMask,FindMaskA,ASIZE(FindMaskA));
|
||||
|
||||
|
@ -143,21 +143,7 @@ bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink)
|
|||
fd->FileAttr=st.st_mode;
|
||||
fd->Size=st.st_size;
|
||||
|
||||
#ifdef UNIX_TIME_NS
|
||||
#if defined(_APPLE)
|
||||
fd->mtime.SetUnixNS(st.st_mtimespec.tv_sec*(uint64)1000000000+st.st_mtimespec.tv_nsec);
|
||||
fd->atime.SetUnixNS(st.st_atimespec.tv_sec*(uint64)1000000000+st.st_atimespec.tv_nsec);
|
||||
fd->ctime.SetUnixNS(st.st_ctimespec.tv_sec*(uint64)1000000000+st.st_ctimespec.tv_nsec);
|
||||
#else
|
||||
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);
|
||||
#endif
|
||||
#else
|
||||
fd->mtime.SetUnix(st.st_mtime);
|
||||
fd->atime.SetUnix(st.st_atime);
|
||||
fd->ctime.SetUnix(st.st_ctime);
|
||||
#endif
|
||||
File::StatToRarTime(st,&fd->mtime,&fd->ctime,&fd->atime);
|
||||
|
||||
wcsncpyz(fd->Name,FindMask,ASIZE(fd->Name));
|
||||
#endif
|
||||
|
|
|
@ -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+4 positions.
|
||||
// So let's allocate 4 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 4 bytes, which contents we do not need.
|
||||
size_t BufSize=MAX_SIZE+4;
|
||||
InBuf=new byte[BufSize];
|
||||
|
||||
// Ensure that we get predictable results when accessing bytes in area
|
||||
|
|
|
@ -33,21 +33,33 @@ class BitInput
|
|||
// Bit at (InAddr,InBit) has the highest position in returning data.
|
||||
uint getbits()
|
||||
{
|
||||
#if defined(LITTLE_ENDIAN) && defined(ALLOW_MISALIGNED)
|
||||
uint32 BitField=*(uint32*)(InBuf+InAddr);
|
||||
BitField=ByteSwap32(BitField);
|
||||
BitField >>= (16-InBit);
|
||||
#else
|
||||
uint BitField=(uint)InBuf[InAddr] << 16;
|
||||
BitField|=(uint)InBuf[InAddr+1] << 8;
|
||||
BitField|=(uint)InBuf[InAddr+2];
|
||||
BitField >>= (8-InBit);
|
||||
#endif
|
||||
return BitField & 0xffff;
|
||||
}
|
||||
|
||||
|
||||
// Return 32 bits from current position in the buffer.
|
||||
// Bit at (InAddr,InBit) has the highest position in returning data.
|
||||
uint getbits32()
|
||||
{
|
||||
#if defined(LITTLE_ENDIAN) && defined(ALLOW_MISALIGNED)
|
||||
uint32 BitField=*(uint32*)(InBuf+InAddr);
|
||||
BitField=ByteSwap32(BitField);
|
||||
#else
|
||||
uint BitField=(uint)InBuf[InAddr] << 24;
|
||||
BitField|=(uint)InBuf[InAddr+1] << 16;
|
||||
BitField|=(uint)InBuf[InAddr+2] << 8;
|
||||
BitField|=(uint)InBuf[InAddr+3];
|
||||
#endif
|
||||
BitField <<= InBit;
|
||||
BitField|=(uint)InBuf[InAddr+4] >> (8-InBit);
|
||||
return BitField & 0xffffffff;
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
bool ExtractHardlink(CommandData *Cmd,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize)
|
||||
{
|
||||
SlashToNative(NameExisting,NameExisting,NameExistingSize); // Not needed for RAR 5.1+ archives.
|
||||
|
||||
if (!FileExist(NameExisting))
|
||||
{
|
||||
uiMsg(UIERROR_HLINKCREATE,NameNew);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -6,8 +6,14 @@ enum HASH_TYPE {HASH_NONE,HASH_RAR14,HASH_CRC32,HASH_BLAKE2};
|
|||
struct HashValue
|
||||
{
|
||||
void Init(HASH_TYPE Type);
|
||||
bool operator == (const HashValue &cmp);
|
||||
bool operator != (const HashValue &cmp) {return !(*this==cmp);}
|
||||
|
||||
// Use the const member, so types on both sides of "==" match.
|
||||
// Otherwise clang -std=c++20 issues "ambiguity is between a regular call
|
||||
// to this operator and a call with the argument order reversed" warning.
|
||||
bool operator == (const HashValue &cmp) const;
|
||||
|
||||
// Not actually used now. Const member for same reason as operator == above.
|
||||
bool operator != (const HashValue &cmp) const {return !(*this==cmp);}
|
||||
|
||||
HASH_TYPE Type;
|
||||
union
|
||||
|
|
|
@ -49,13 +49,5 @@ FileHeader& FileHeader::operator = (FileHeader &hd)
|
|||
|
||||
void MainHeader::Reset()
|
||||
{
|
||||
HighPosAV=0;
|
||||
PosAV=0;
|
||||
CommentInHeader=false;
|
||||
PackComment=false;
|
||||
Locator=false;
|
||||
QOpenOffset=0;
|
||||
QOpenMaxSize=0;
|
||||
RROffset=0;
|
||||
RRMaxSize=0;
|
||||
*this={};
|
||||
}
|
||||
|
|
|
@ -6,12 +6,11 @@
|
|||
#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
|
||||
|
@ -168,6 +167,10 @@ struct MainHeader:BaseBlock
|
|||
uint64 QOpenMaxSize; // Maximum size of QOpen offset in locator extra field.
|
||||
uint64 RROffset; // Offset of recovery record.
|
||||
uint64 RRMaxSize; // Maximum size of RR offset in locator extra field.
|
||||
size_t MetaNameMaxSize; // Maximum size of archive name in metadata extra field.
|
||||
std::wstring OrigName; // Original archive name.
|
||||
RarTime OrigTime; // Original archive time.
|
||||
|
||||
void Reset();
|
||||
};
|
||||
|
||||
|
@ -230,7 +233,7 @@ struct FileHeader:BlockHeader
|
|||
bool LargeFile;
|
||||
|
||||
// 'true' for HEAD_SERVICE block, which is a child of preceding file block.
|
||||
// RAR 4.x uses 'solid' flag to indicate child subheader blocks in archives.
|
||||
// RAR 4.x uses 'solid' flag to indicate children subheader blocks in archives.
|
||||
bool SubBlock;
|
||||
|
||||
HOST_SYSTEM_TYPE HSType;
|
||||
|
@ -321,16 +324,6 @@ struct ProtectHeader:BlockHeader
|
|||
};
|
||||
|
||||
|
||||
struct UnixOwnersHeader:SubBlockHeader
|
||||
{
|
||||
ushort OwnerNameSize;
|
||||
ushort GroupNameSize;
|
||||
/* dummy */
|
||||
char OwnerName[256];
|
||||
char GroupName[256];
|
||||
};
|
||||
|
||||
|
||||
struct EAHeader:SubBlockHeader
|
||||
{
|
||||
uint UnpSize;
|
||||
|
|
|
@ -59,11 +59,18 @@
|
|||
|
||||
// Main header extra field values.
|
||||
#define MHEXTRA_LOCATOR 0x01 // Position of quick list and other blocks.
|
||||
#define MHEXTRA_METADATA 0x02 // Archive metadata.
|
||||
|
||||
// Flags for MHEXTRA_LOCATOR.
|
||||
#define MHEXTRA_LOCATOR_QLIST 0x01 // Quick open offset is present.
|
||||
#define MHEXTRA_LOCATOR_RR 0x02 // Recovery record offset is present.
|
||||
|
||||
// Flags for MHEXTRA_METADATA.
|
||||
#define MHEXTRA_METADATA_NAME 0x01 // Archive name is present.
|
||||
#define MHEXTRA_METADATA_CTIME 0x02 // Archive creation time is present.
|
||||
#define MHEXTRA_METADATA_UNIXTIME 0x04 // Use Unix nanosecond time format.
|
||||
#define MHEXTRA_METADATA_UNIX_NS 0x08 // Unix format with nanosecond precision.
|
||||
|
||||
// File and service header extra field values.
|
||||
#define FHEXTRA_CRYPT 0x01 // Encryption parameters.
|
||||
#define FHEXTRA_HASH 0x02 // File hash.
|
||||
|
|
|
@ -40,7 +40,7 @@ static bool WMI_IsWindows10()
|
|||
|
||||
IWbemServices *pSvc = NULL;
|
||||
|
||||
hres = pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"),NULL,NULL,0,NULL,0,0,&pSvc);
|
||||
hres = pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"),NULL,NULL,NULL,NULL,0,0,&pSvc);
|
||||
|
||||
if (FAILED(hres))
|
||||
{
|
||||
|
|
|
@ -36,6 +36,7 @@ void ListArchive(CommandData *Cmd)
|
|||
{
|
||||
Arc.ViewComment();
|
||||
mprintf(L"\n%s: %s",St(MListArchive),Arc.FileName);
|
||||
|
||||
mprintf(L"\n%s: ",St(MListDetails));
|
||||
uint SetCount=0;
|
||||
const wchar *Fmt=Arc.Format==RARFMT14 ? L"RAR 1.4":(Arc.Format==RARFMT15 ? L"RAR 4":L"RAR 5");
|
||||
|
@ -61,6 +62,16 @@ void ListArchive(CommandData *Cmd)
|
|||
mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListLock));
|
||||
if (Arc.Encrypted)
|
||||
mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListEncHead));
|
||||
|
||||
if (!Arc.MainHead.OrigName.empty())
|
||||
mprintf(L"\n%s: %s",St(MOrigName),Arc.MainHead.OrigName.c_str());
|
||||
if (Arc.MainHead.OrigTime.IsSet())
|
||||
{
|
||||
wchar DateStr[50];
|
||||
Arc.MainHead.OrigTime.GetText(DateStr,ASIZE(DateStr),Technical);
|
||||
mprintf(L"\n%s: %s",St(MOriginalTime),DateStr);
|
||||
}
|
||||
|
||||
mprintf(L"\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#define MRARTitle1 L"\nUsage: rar <command> -<switch 1> -<switch N> <archive> <files...>"
|
||||
#define MUNRARTitle1 L"\nUsage: unrar <command> -<switch 1> -<switch N> <archive> <files...>"
|
||||
#define MRARTitle2 L"\n <@listfiles...> <path_to_extract\\>"
|
||||
#define MFwrSlTitle2 L"\n <@listfiles...> <path_to_extract/>"
|
||||
#define MCHelpCmd L"\n\n<Commands>"
|
||||
#define MCHelpCmdA L"\n a Add files to archive"
|
||||
#define MCHelpCmdC L"\n c Add archive comment"
|
||||
|
@ -44,7 +45,7 @@
|
|||
#define MCHelpCmdR L"\n r Repair archive"
|
||||
#define MCHelpCmdRC L"\n rc Reconstruct missing volumes"
|
||||
#define MCHelpCmdRN L"\n rn Rename archived files"
|
||||
#define MCHelpCmdRR L"\n rr[N] Add data recovery record"
|
||||
#define MCHelpCmdRR L"\n rr[N] Add the data recovery record"
|
||||
#define MCHelpCmdRV L"\n rv[N] Create recovery volumes"
|
||||
#define MCHelpCmdS L"\n s[name|-] Convert archive to or from SFX"
|
||||
#define MCHelpCmdT L"\n t Test archive files"
|
||||
|
@ -58,6 +59,7 @@
|
|||
#define MCHelpSwAD L"\n ad[1,2] Alternate destination path"
|
||||
#define MCHelpSwAG L"\n ag[format] Generate archive name using the current date"
|
||||
#define MCHelpSwAI L"\n ai Ignore file attributes"
|
||||
#define MCHelpSwAM L"\n am[s,r] Archive name and time [save, restore]"
|
||||
#define MCHelpSwAO L"\n ao Add files with Archive attribute set"
|
||||
#define MCHelpSwAP L"\n ap<path> Set path inside archive"
|
||||
#define MCHelpSwAS L"\n as Synchronize archive contents"
|
||||
|
@ -394,3 +396,6 @@
|
|||
#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"
|
||||
|
|
|
@ -142,20 +142,23 @@ clean:
|
|||
@rm -f $(OBJECTS) $(UNRAR_OBJ) $(LIB_OBJ)
|
||||
@rm -f unrar libunrar.*
|
||||
|
||||
unrar: clean $(OBJECTS) $(UNRAR_OBJ)
|
||||
# We removed 'clean' from dependencies, because it prevented parallel
|
||||
# 'make -Jn' builds.
|
||||
|
||||
unrar: $(OBJECTS) $(UNRAR_OBJ)
|
||||
@rm -f unrar
|
||||
$(LINK) -o unrar $(LDFLAGS) $(OBJECTS) $(UNRAR_OBJ) $(LIBS)
|
||||
$(STRIP) unrar
|
||||
|
||||
sfx: WHAT=SFX_MODULE
|
||||
sfx: clean $(OBJECTS)
|
||||
sfx: $(OBJECTS)
|
||||
@rm -f default.sfx
|
||||
$(LINK) -o default.sfx $(LDFLAGS) $(OBJECTS)
|
||||
$(STRIP) default.sfx
|
||||
|
||||
lib: WHAT=RARDLL
|
||||
lib: CXXFLAGS+=$(LIBFLAGS)
|
||||
lib: clean $(OBJECTS) $(LIB_OBJ)
|
||||
lib: $(OBJECTS) $(LIB_OBJ)
|
||||
@rm -f libunrar.*
|
||||
$(LINK) -shared -o libunrar.so $(LDFLAGS) $(OBJECTS) $(LIB_OBJ)
|
||||
$(AR) rcs libunrar.a $(OBJECTS) $(LIB_OBJ)
|
||||
|
|
|
@ -532,13 +532,15 @@ inline bool RARPPM_CONTEXT::decodeSymbol2(ModelPPM *Model)
|
|||
Model->Coder.SubRange.LowCount=HiCnt;
|
||||
Model->Coder.SubRange.HighCount=Model->Coder.SubRange.scale;
|
||||
i=NumStats-Model->NumMasked;
|
||||
pps--;
|
||||
|
||||
// 2022.12.02: we removed pps-- here and changed the code below to avoid
|
||||
// "array subscript -1 is outside array bounds" warning in some compilers.
|
||||
do
|
||||
{
|
||||
pps++;
|
||||
if (pps>=ps+ASIZE(ps)) // Extra safety check.
|
||||
return false;
|
||||
Model->CharMask[(*pps)->Symbol]=Model->EscCount;
|
||||
pps++;
|
||||
} while ( --i );
|
||||
psee2c->Summ += Model->Coder.SubRange.scale;
|
||||
Model->NumMasked = NumStats;
|
||||
|
|
|
@ -6,14 +6,6 @@ RAROptions::RAROptions()
|
|||
}
|
||||
|
||||
|
||||
RAROptions::~RAROptions()
|
||||
{
|
||||
// It is important for security reasons, so we do not have the unnecessary
|
||||
// password data left in memory.
|
||||
memset(this,0,sizeof(RAROptions));
|
||||
}
|
||||
|
||||
|
||||
void RAROptions::Init()
|
||||
{
|
||||
memset(this,0,sizeof(RAROptions));
|
||||
|
|
|
@ -45,6 +45,12 @@ enum OVERWRITE_MODE
|
|||
OVERWRITE_FORCE_ASK
|
||||
};
|
||||
|
||||
enum ARC_METADATA
|
||||
{
|
||||
ARCMETA_NONE=0,
|
||||
ARCMETA_SAVE, // -ams
|
||||
ARCMETA_RESTORE // -amr
|
||||
};
|
||||
|
||||
enum QOPEN_MODE { QOPEN_NONE, QOPEN_AUTO, QOPEN_ALWAYS };
|
||||
|
||||
|
@ -84,11 +90,12 @@ struct FilterMode
|
|||
#define MAX_GENERATE_MASK 128
|
||||
|
||||
|
||||
// Here we store simple data types, which we can clear and move all together
|
||||
// quickly. Rest of data types goes to CommandData.
|
||||
class RAROptions
|
||||
{
|
||||
public:
|
||||
RAROptions();
|
||||
~RAROptions();
|
||||
void Init();
|
||||
|
||||
uint ExclFileAttr;
|
||||
|
@ -118,7 +125,6 @@ class RAROptions
|
|||
|
||||
wchar ArcPath[NM]; // For -ap<path>.
|
||||
wchar ExclArcPath[NM]; // For -ep4<path> switch.
|
||||
SecPassword Password;
|
||||
bool EncryptHeaders;
|
||||
bool SkipEncrypted;
|
||||
|
||||
|
@ -132,6 +138,7 @@ class RAROptions
|
|||
HASH_TYPE HashType;
|
||||
int Recovery;
|
||||
int RecVolNumber;
|
||||
ARC_METADATA ArcMetadata;
|
||||
bool DisablePercentage;
|
||||
bool DisableCopyright;
|
||||
bool DisableDone;
|
||||
|
@ -147,7 +154,6 @@ class RAROptions
|
|||
PATH_EXCL_MODE ExclPath;
|
||||
RECURSE_MODE Recurse;
|
||||
int64 VolSize;
|
||||
Array<int64> NextVolSizes;
|
||||
uint CurVolNum;
|
||||
bool AllYes;
|
||||
bool VerboseOutput; // -iv, display verbose output, used only in "WinRAR t" now.
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#endif
|
||||
|
||||
#include <new>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
#if defined(_WIN_ALL) || defined(_EMX)
|
||||
|
@ -39,8 +41,15 @@
|
|||
#define _UNICODE // Set _T() macro to convert from narrow to wide strings.
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// 2021.09.05: Allow newer Vista+ APIs like IFileOpenDialog for WinRAR,
|
||||
// but still keep SFX modules XP compatible.
|
||||
#define WINVER _WIN32_WINNT_VISTA
|
||||
#define _WIN32_WINNT _WIN32_WINNT_VISTA
|
||||
#else
|
||||
#define WINVER _WIN32_WINNT_WINXP
|
||||
#define _WIN32_WINNT _WIN32_WINNT_WINXP
|
||||
#endif
|
||||
|
||||
#if !defined(ZIPSFX)
|
||||
#define RAR_SMP
|
||||
|
@ -72,9 +81,6 @@
|
|||
#include <dir.h>
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER<1500
|
||||
#define for if (0) ; else for
|
||||
#endif
|
||||
#include <direct.h>
|
||||
#include <intrin.h>
|
||||
|
||||
|
@ -98,7 +104,6 @@
|
|||
#include <time.h>
|
||||
#include <signal.h>
|
||||
|
||||
|
||||
#define SAVE_LINKS
|
||||
|
||||
#define ENABLE_ACCESS
|
||||
|
|
|
@ -31,11 +31,17 @@ wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath,size_t DestSize)
|
|||
const wchar *s=DestPtr;
|
||||
if (s[0]!=0 && IsDriveDiv(s[1]))
|
||||
s+=2;
|
||||
if (s[0]=='\\' && s[1]=='\\')
|
||||
|
||||
// Skip UNC Windows \\server\share\ or Unix //server/share/
|
||||
if (IsPathDiv(s[0]) && IsPathDiv(s[1]))
|
||||
{
|
||||
const wchar *Slash=wcschr(s+2,'\\');
|
||||
if (Slash!=NULL && (Slash=wcschr(Slash+1,'\\'))!=NULL)
|
||||
s=Slash+1;
|
||||
uint SlashCount=0;
|
||||
for (const wchar *t=s+2;*t!=0;t++)
|
||||
if (IsPathDiv(*t) && ++SlashCount==2)
|
||||
{
|
||||
s=t+1; // Found two more path separators after leading two.
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (const wchar *t=s;*t!=0;t++)
|
||||
if (IsPathDiv(*t))
|
||||
|
@ -422,50 +428,39 @@ void NextVolumeName(wchar *ArcName,uint MaxLength,bool OldNumbering)
|
|||
|
||||
bool IsNameUsable(const wchar *Name)
|
||||
{
|
||||
#ifndef _UNIX
|
||||
if (Name[0] && Name[1] && wcschr(Name+2,':')!=NULL)
|
||||
// We were asked to apply Windows-like conversion in Linux in case
|
||||
// files are unpacked to Windows share. This code is invoked only
|
||||
// if file failed to be created, so it doesn't affect extraction
|
||||
// of Unix compatible names to native Unix drives.
|
||||
#ifdef _UNIX
|
||||
// Windows shares in Unix do not allow the drive letter,
|
||||
// so unlike Windows version, we check all characters here.
|
||||
if (wcschr(Name,':')!=NULL)
|
||||
return false;
|
||||
#else
|
||||
if (Name[0]!=0 && Name[1]!=0 && wcschr(Name+2,':')!=NULL)
|
||||
return false;
|
||||
#endif
|
||||
for (const wchar *s=Name;*s!=0;s++)
|
||||
{
|
||||
if ((uint)*s<32)
|
||||
return false;
|
||||
|
||||
// It is for Windows shares in Unix. We can create such names in Windows.
|
||||
#ifdef _UNIX
|
||||
// No spaces or dots before the path separator are allowed in Windows
|
||||
// shares. But they are allowed and automtically removed at the end of
|
||||
// file or folder name, so it is useless to replace them here.
|
||||
// Since such files or folders are created successfully, a supposed
|
||||
// conversion here would never be invoked.
|
||||
if ((*s==' ' || *s=='.') && IsPathDiv(s[1]))
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return *Name!=0 && wcspbrk(Name,L"?*<>|\"")==NULL;
|
||||
}
|
||||
|
||||
|
||||
void MakeNameUsable(char *Name,bool Extended)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
// In Windows we also need to convert characters not defined in current
|
||||
// code page. This double conversion changes them to '?', which is
|
||||
// catched by code below.
|
||||
size_t NameLength=strlen(Name);
|
||||
wchar NameW[NM];
|
||||
CharToWide(Name,NameW,ASIZE(NameW));
|
||||
WideToChar(NameW,Name,NameLength+1);
|
||||
Name[NameLength]=0;
|
||||
#endif
|
||||
for (char *s=Name;*s!=0;s=charnext(s))
|
||||
{
|
||||
if (strchr(Extended ? "?*<>|\"":"?*",*s)!=NULL || Extended && (byte)*s<32)
|
||||
*s='_';
|
||||
#ifdef _EMX
|
||||
if (*s=='=')
|
||||
*s='_';
|
||||
#endif
|
||||
#ifndef _UNIX
|
||||
if (s-Name>1 && *s==':')
|
||||
*s='_';
|
||||
// Remove ' ' and '.' before path separator, but allow .\ and ..\.
|
||||
if ((*s==' ' || *s=='.' && s>Name && !IsPathDiv(s[-1]) && s[-1]!='.') && IsPathDiv(s[1]))
|
||||
*s='_';
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MakeNameUsable(wchar *Name,bool Extended)
|
||||
|
@ -474,7 +469,27 @@ void MakeNameUsable(wchar *Name,bool Extended)
|
|||
{
|
||||
if (wcschr(Extended ? L"?*<>|\"":L"?*",*s)!=NULL || Extended && (uint)*s<32)
|
||||
*s='_';
|
||||
#ifndef _UNIX
|
||||
#ifdef _UNIX
|
||||
// We were asked to apply Windows-like conversion in Linux in case
|
||||
// files are unpacked to Windows share. This code is invoked only
|
||||
// if file failed to be created, so it doesn't affect extraction
|
||||
// of Unix compatible names to native Unix drives.
|
||||
if (Extended)
|
||||
{
|
||||
// Windows shares in Unix do not allow the drive letter,
|
||||
// so unlike Windows version, we check all characters here.
|
||||
if (*s==':')
|
||||
*s='_';
|
||||
|
||||
// No spaces or dots before the path separator are allowed on Windows
|
||||
// shares. But they are allowed and automatically removed at the end of
|
||||
// file or folder name, so it is useless to replace them here.
|
||||
// Since such files or folders are created successfully, a supposed
|
||||
// conversion here would never be invoked.
|
||||
if ((*s==' ' || *s=='.') && IsPathDiv(s[1]))
|
||||
*s='_';
|
||||
}
|
||||
#else
|
||||
if (s-Name>1 && *s==':')
|
||||
*s='_';
|
||||
#if 0 // We already can create such files.
|
||||
|
@ -731,7 +746,7 @@ static void GenArcName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,u
|
|||
// Here we ensure that we have enough 'N' characters to fit all digits
|
||||
// of archive number. We'll replace them by actual number later
|
||||
// in this function.
|
||||
if (NCount<Digits)
|
||||
if (NCount<Digits && wcslen(Mask)+Digits-NCount<ASIZE(Mask))
|
||||
{
|
||||
wmemmove(Mask+I+Digits,Mask+I+NCount,wcslen(Mask+I+NCount)+1);
|
||||
wmemset(Mask+I,'N',Digits);
|
||||
|
@ -768,7 +783,7 @@ static void GenArcName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,u
|
|||
if (StartWeekDay%7>=4)
|
||||
CurWeek++;
|
||||
|
||||
char Field[10][6];
|
||||
char Field[10][11];
|
||||
|
||||
sprintf(Field[0],"%04u",rlt.Year);
|
||||
sprintf(Field[1],"%02u",rlt.Month);
|
||||
|
|
|
@ -29,7 +29,6 @@ void GetConfigName(const wchar *Name,wchar *FullName,size_t MaxSize,bool CheckEx
|
|||
wchar* GetVolNumPart(const wchar *ArcName);
|
||||
void NextVolumeName(wchar *ArcName,uint MaxLength,bool OldNumbering);
|
||||
bool IsNameUsable(const wchar *Name);
|
||||
void MakeNameUsable(char *Name,bool Extended);
|
||||
void MakeNameUsable(wchar *Name,bool Extended);
|
||||
|
||||
void UnixSlashToDos(const char *SrcName,char *DestName,size_t MaxLength);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "version.hpp"
|
||||
#include "rardefs.hpp"
|
||||
#include "rarlang.hpp"
|
||||
#include "rawint.hpp"
|
||||
#include "unicode.hpp"
|
||||
#include "errhnd.hpp"
|
||||
#include "secpassword.hpp"
|
||||
|
@ -34,7 +35,6 @@
|
|||
#endif
|
||||
#include "file.hpp"
|
||||
#include "crc.hpp"
|
||||
#include "ui.hpp"
|
||||
#include "filefn.hpp"
|
||||
#include "filestr.hpp"
|
||||
#include "find.hpp"
|
||||
|
@ -47,11 +47,11 @@
|
|||
#include "archive.hpp"
|
||||
#include "match.hpp"
|
||||
#include "cmddata.hpp"
|
||||
#include "ui.hpp"
|
||||
#include "filcreat.hpp"
|
||||
#include "consio.hpp"
|
||||
#include "system.hpp"
|
||||
#include "log.hpp"
|
||||
#include "rawint.hpp"
|
||||
#include "rawread.hpp"
|
||||
#include "encname.hpp"
|
||||
#include "resource.hpp"
|
||||
|
|
|
@ -9,9 +9,13 @@
|
|||
|
||||
#define ASIZE(x) (sizeof(x)/sizeof(x[0]))
|
||||
|
||||
// MAXPASSWORD is expected to be multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE (16)
|
||||
// for CryptProtectMemory in SecPassword.
|
||||
#define MAXPASSWORD 128
|
||||
// MAXPASSWORD and MAXPASSWORD_RAR are expected to be multiple of
|
||||
// CRYPTPROTECTMEMORY_BLOCK_SIZE (16) for CryptProtectMemory in SecPassword.
|
||||
// We allow a larger MAXPASSWORD to unpack archives with lengthy passwords
|
||||
// in non-RAR formats in GUI versions. For RAR format we set MAXPASSWORD_RAR
|
||||
// to 128 for compatibility and because it is enough for AES-256.
|
||||
#define MAXPASSWORD 512
|
||||
#define MAXPASSWORD_RAR 128
|
||||
|
||||
#define MAXSFXSIZE 0x200000
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ inline uint32 RawGetBE4(const byte *m)
|
|||
{
|
||||
#if defined(USE_MEM_BYTESWAP) && defined(_MSC_VER)
|
||||
return _byteswap_ulong(*(uint32 *)m);
|
||||
#elif defined(USE_MEM_BYTESWAP) && (__GNUC__ > 3) && (__GNUC_MINOR__ > 2)
|
||||
#elif defined(USE_MEM_BYTESWAP) && (defined(__clang__) || defined(__GNUC__))
|
||||
return __builtin_bswap32(*(uint32 *)m);
|
||||
#else
|
||||
return uint32(m[0]<<24) | uint32(m[1]<<16) | uint32(m[2]<<8) | m[3];
|
||||
|
@ -97,7 +97,7 @@ inline void RawPutBE4(uint32 i,byte *mem)
|
|||
{
|
||||
#if defined(USE_MEM_BYTESWAP) && defined(_MSC_VER)
|
||||
*(uint32*)mem = _byteswap_ulong(i);
|
||||
#elif defined(USE_MEM_BYTESWAP) && (__GNUC__ > 3) && (__GNUC_MINOR__ > 2)
|
||||
#elif defined(USE_MEM_BYTESWAP) && (defined(__clang__) || defined(__GNUC__))
|
||||
*(uint32*)mem = __builtin_bswap32(i);
|
||||
#else
|
||||
mem[0]=byte(i>>24);
|
||||
|
@ -112,7 +112,7 @@ inline uint32 ByteSwap32(uint32 i)
|
|||
{
|
||||
#ifdef _MSC_VER
|
||||
return _byteswap_ulong(i);
|
||||
#elif (__GNUC__ > 3) && (__GNUC_MINOR__ > 2)
|
||||
#elif defined(__clang__) || defined(__GNUC__)
|
||||
return __builtin_bswap32(i);
|
||||
#else
|
||||
return (rotl32(i,24)&0xFF00FF00)|(rotl32(i,8)&0x00FF00FF);
|
||||
|
|
|
@ -155,7 +155,7 @@ 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 &&
|
||||
|
@ -204,7 +204,7 @@ void ComprDataIO::ShowUnpRead(int64 ArcPos,int64 ArcSize)
|
|||
ArcPos+=ProcessedArcSize;
|
||||
|
||||
Archive *SrcArc=(Archive *)SrcFile;
|
||||
RAROptions *Cmd=SrcArc->GetRAROptions();
|
||||
CommandData *Cmd=SrcArc->GetCommandData();
|
||||
|
||||
int CurPercent=ToPercent(ArcPos,ArcSize);
|
||||
if (!Cmd->DisablePercentage && CurPercent!=LastPercent)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
|
||||
|
||||
bool RecVolumesRestore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
||||
bool RecVolumesRestore(CommandData *Cmd,const wchar *Name,bool Silent)
|
||||
{
|
||||
Archive Arc(Cmd);
|
||||
if (!Arc.Open(Name))
|
||||
|
@ -42,7 +42,7 @@ bool RecVolumesRestore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
|||
}
|
||||
|
||||
|
||||
void RecVolumesTest(RAROptions *Cmd,Archive *Arc,const wchar *Name)
|
||||
void RecVolumesTest(CommandData *Cmd,Archive *Arc,const wchar *Name)
|
||||
{
|
||||
wchar RevName[NM];
|
||||
*RevName=0;
|
||||
|
|
|
@ -14,11 +14,11 @@ class RecVolumes3
|
|||
ThreadPool *RSThreadPool;
|
||||
#endif
|
||||
public:
|
||||
RecVolumes3(RAROptions *Cmd,bool TestOnly);
|
||||
RecVolumes3(CommandData *Cmd,bool TestOnly);
|
||||
~RecVolumes3();
|
||||
void Make(RAROptions *Cmd,wchar *ArcName);
|
||||
bool Restore(RAROptions *Cmd,const wchar *Name,bool Silent);
|
||||
void Test(RAROptions *Cmd,const wchar *Name);
|
||||
void Make(CommandData *Cmd,wchar *ArcName);
|
||||
bool Restore(CommandData *Cmd,const wchar *Name,bool Silent);
|
||||
void Test(CommandData *Cmd,const wchar *Name);
|
||||
};
|
||||
|
||||
|
||||
|
@ -48,8 +48,8 @@ struct RecRSThreadData
|
|||
class RecVolumes5
|
||||
{
|
||||
private:
|
||||
void ProcessRS(RAROptions *Cmd,uint DataNum,const byte *Data,uint MaxRead,bool Encode);
|
||||
void ProcessRS(RAROptions *Cmd,uint MaxRead,bool Encode);
|
||||
void ProcessRS(CommandData *Cmd,uint DataNum,const byte *Data,uint MaxRead,bool Encode);
|
||||
void ProcessRS(CommandData *Cmd,uint MaxRead,bool Encode);
|
||||
uint ReadHeader(File *RecFile,bool FirstRev);
|
||||
|
||||
Array<RecVolItem> RecItems;
|
||||
|
@ -76,13 +76,13 @@ class RecVolumes5
|
|||
public: // 'public' only because called from thread functions.
|
||||
void ProcessAreaRS(RecRSThreadData *td);
|
||||
public:
|
||||
RecVolumes5(RAROptions *Cmd,bool TestOnly);
|
||||
RecVolumes5(CommandData *Cmd,bool TestOnly);
|
||||
~RecVolumes5();
|
||||
bool Restore(RAROptions *Cmd,const wchar *Name,bool Silent);
|
||||
void Test(RAROptions *Cmd,const wchar *Name);
|
||||
bool Restore(CommandData *Cmd,const wchar *Name,bool Silent);
|
||||
void Test(CommandData *Cmd,const wchar *Name);
|
||||
};
|
||||
|
||||
bool RecVolumesRestore(RAROptions *Cmd,const wchar *Name,bool Silent);
|
||||
void RecVolumesTest(RAROptions *Cmd,Archive *Arc,const wchar *Name);
|
||||
bool RecVolumesRestore(CommandData *Cmd,const wchar *Name,bool Silent);
|
||||
void RecVolumesTest(CommandData *Cmd,Archive *Arc,const wchar *Name);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -36,7 +36,7 @@ THREAD_PROC(RSDecodeThread)
|
|||
}
|
||||
#endif
|
||||
|
||||
RecVolumes3::RecVolumes3(RAROptions *Cmd,bool TestOnly)
|
||||
RecVolumes3::RecVolumes3(CommandData *Cmd,bool TestOnly)
|
||||
{
|
||||
memset(SrcFile,0,sizeof(SrcFile));
|
||||
if (TestOnly)
|
||||
|
@ -99,7 +99,7 @@ static bool IsNewStyleRev(const wchar *Name)
|
|||
}
|
||||
|
||||
|
||||
bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
||||
bool RecVolumes3::Restore(CommandData *Cmd,const wchar *Name,bool Silent)
|
||||
{
|
||||
wchar ArcName[NM];
|
||||
wcsncpyz(ArcName,Name,ASIZE(ArcName));
|
||||
|
@ -226,7 +226,7 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
|||
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])
|
||||
{
|
||||
|
@ -238,7 +238,14 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
|||
wcsncpyz(PrevName,CurName,ASIZE(PrevName));
|
||||
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)
|
||||
|
@ -497,7 +504,7 @@ void RSEncode::DecodeBuf()
|
|||
}
|
||||
|
||||
|
||||
void RecVolumes3::Test(RAROptions *Cmd,const wchar *Name)
|
||||
void RecVolumes3::Test(CommandData *Cmd,const wchar *Name)
|
||||
{
|
||||
if (!IsNewStyleRev(Name)) // RAR 3.0 name#_#_#.rev do not include CRC32.
|
||||
{
|
||||
|
|
|
@ -4,7 +4,7 @@ static const uint MaxVolumes=65535;
|
|||
// rev files by mistake.
|
||||
#define MAX_REV_TO_DATA_RATIO 10 // 1000% of rev files.
|
||||
|
||||
RecVolumes5::RecVolumes5(RAROptions *Cmd,bool TestOnly)
|
||||
RecVolumes5::RecVolumes5(CommandData *Cmd,bool TestOnly)
|
||||
{
|
||||
RealBuf=NULL;
|
||||
RealReadBuffer=NULL;
|
||||
|
@ -70,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;
|
||||
|
@ -141,7 +141,7 @@ void RecVolumes5::ProcessAreaRS(RecRSThreadData *td)
|
|||
|
||||
|
||||
|
||||
bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
|
||||
bool RecVolumes5::Restore(CommandData *Cmd,const wchar *Name,bool Silent)
|
||||
{
|
||||
wchar ArcName[NM];
|
||||
wcsncpyz(ArcName,Name,ASIZE(ArcName));
|
||||
|
@ -494,7 +494,7 @@ uint RecVolumes5::ReadHeader(File *RecFile,bool FirstRev)
|
|||
}
|
||||
|
||||
|
||||
void RecVolumes5::Test(RAROptions *Cmd,const wchar *Name)
|
||||
void RecVolumes5::Test(CommandData *Cmd,const wchar *Name)
|
||||
{
|
||||
wchar VolName[NM];
|
||||
wcsncpyz(VolName,Name,ASIZE(VolName));
|
||||
|
|
|
@ -90,18 +90,20 @@ Rijndael::Rijndael()
|
|||
|
||||
void Rijndael::Init(bool Encrypt,const byte *key,uint keyLen,const byte * initVector)
|
||||
{
|
||||
#ifdef USE_SSE
|
||||
// Check SSE here instead of constructor, so if object is a part of some
|
||||
// structure memset'ed before use, this variable is not lost.
|
||||
// Check SIMD here instead of constructor, so if object is a part of some
|
||||
// structure memset'ed before use, these variables are not lost.
|
||||
#if defined(USE_SSE)
|
||||
int CPUInfo[4];
|
||||
__cpuid(CPUInfo, 0x80000000); // Get the maximum supported cpuid function.
|
||||
if ((CPUInfo[0] & 0x7fffffff)>=1)
|
||||
__cpuid(CPUInfo, 0);
|
||||
if (CPUInfo[0]>=1) // Check the maximum supported cpuid function.
|
||||
{
|
||||
__cpuid(CPUInfo, 1);
|
||||
AES_NI=(CPUInfo[2] & 0x2000000)!=0;
|
||||
}
|
||||
else
|
||||
AES_NI=false;
|
||||
#elif defined(USE_NEON)
|
||||
AES_Neon=(getauxval(AT_HWCAP) & HWCAP_AES)!=0;
|
||||
#endif
|
||||
|
||||
// Other developers asked us to initialize it to suppress "may be used
|
||||
|
@ -141,18 +143,25 @@ void Rijndael::Init(bool Encrypt,const byte *key,uint keyLen,const byte * initVe
|
|||
keyEncToDec();
|
||||
}
|
||||
|
||||
|
||||
void Rijndael::blockEncrypt(const byte *input,size_t inputLen,byte *outBuffer)
|
||||
{
|
||||
if (inputLen <= 0)
|
||||
return;
|
||||
|
||||
size_t numBlocks = inputLen/16;
|
||||
#ifdef USE_SSE
|
||||
#if defined(USE_SSE)
|
||||
if (AES_NI)
|
||||
{
|
||||
blockEncryptSSE(input,numBlocks,outBuffer);
|
||||
return;
|
||||
}
|
||||
#elif defined(USE_NEON)
|
||||
if (AES_Neon)
|
||||
{
|
||||
blockEncryptNeon(input,numBlocks,outBuffer);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
byte *prevBlock = m_initVector;
|
||||
|
@ -240,18 +249,58 @@ void Rijndael::blockEncryptSSE(const byte *input,size_t numBlocks,byte *outBuffe
|
|||
#endif
|
||||
|
||||
|
||||
#ifdef USE_NEON
|
||||
void Rijndael::blockEncryptNeon(const byte *input,size_t numBlocks,byte *outBuffer)
|
||||
{
|
||||
byte *prevBlock = m_initVector;
|
||||
while (numBlocks > 0)
|
||||
{
|
||||
byte block[16];
|
||||
if (CBCMode)
|
||||
vst1q_u8(block, veorq_u8(vld1q_u8(prevBlock), vld1q_u8(input)));
|
||||
else
|
||||
vst1q_u8(block, vld1q_u8(input));
|
||||
|
||||
uint8x16_t data = vld1q_u8(block);
|
||||
for (uint i = 0; i < m_uRounds-1; i++)
|
||||
{
|
||||
data = vaeseq_u8(data, vld1q_u8((byte *)m_expandedKey[i]));
|
||||
data = vaesmcq_u8(data);
|
||||
}
|
||||
data = vaeseq_u8(data, vld1q_u8((byte *)(m_expandedKey[m_uRounds-1])));
|
||||
data = veorq_u8(data, vld1q_u8((byte *)(m_expandedKey[m_uRounds])));
|
||||
vst1q_u8(outBuffer, data);
|
||||
|
||||
prevBlock=outBuffer;
|
||||
|
||||
outBuffer += 16;
|
||||
input += 16;
|
||||
numBlocks--;
|
||||
}
|
||||
vst1q_u8(m_initVector, vld1q_u8(prevBlock));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void Rijndael::blockDecrypt(const byte *input, size_t inputLen, byte *outBuffer)
|
||||
{
|
||||
if (inputLen <= 0)
|
||||
return;
|
||||
|
||||
size_t numBlocks=inputLen/16;
|
||||
#ifdef USE_SSE
|
||||
#if defined(USE_SSE)
|
||||
if (AES_NI)
|
||||
{
|
||||
blockDecryptSSE(input,numBlocks,outBuffer);
|
||||
return;
|
||||
}
|
||||
#elif defined(USE_NEON)
|
||||
if (AES_Neon)
|
||||
{
|
||||
blockDecryptNeon(input,numBlocks,outBuffer);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
byte block[16], iv[4][4];
|
||||
|
@ -343,6 +392,41 @@ void Rijndael::blockDecryptSSE(const byte *input, size_t numBlocks, byte *outBuf
|
|||
#endif
|
||||
|
||||
|
||||
#ifdef USE_NEON
|
||||
void Rijndael::blockDecryptNeon(const byte *input, size_t numBlocks, byte *outBuffer)
|
||||
{
|
||||
byte iv[16];
|
||||
memcpy(iv,m_initVector,16);
|
||||
|
||||
while (numBlocks > 0)
|
||||
{
|
||||
uint8x16_t data = vld1q_u8(input);
|
||||
|
||||
for (int i=m_uRounds-1; i>0; i--)
|
||||
{
|
||||
data = vaesdq_u8(data, vld1q_u8((byte *)m_expandedKey[i+1]));
|
||||
data = vaesimcq_u8(data);
|
||||
}
|
||||
|
||||
data = vaesdq_u8(data, vld1q_u8((byte *)m_expandedKey[1]));
|
||||
data = veorq_u8(data, vld1q_u8((byte *)m_expandedKey[0]));
|
||||
|
||||
if (CBCMode)
|
||||
data = veorq_u8(data, vld1q_u8(iv));
|
||||
|
||||
vst1q_u8(iv, vld1q_u8(input));
|
||||
vst1q_u8(outBuffer, data);
|
||||
|
||||
input += 16;
|
||||
outBuffer += 16;
|
||||
numBlocks--;
|
||||
}
|
||||
|
||||
memcpy(m_initVector,iv,16);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ALGORITHM
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -18,6 +18,16 @@ class Rijndael
|
|||
|
||||
bool AES_NI;
|
||||
#endif
|
||||
#ifdef USE_NEON
|
||||
// Set "crypto" attribute as replacement of -march=armv8-a+crypto switch.
|
||||
__attribute__((target("crypto")))
|
||||
void blockEncryptNeon(const byte *input,size_t numBlocks,byte *outBuffer);
|
||||
__attribute__((target("crypto")))
|
||||
void blockDecryptNeon(const byte *input, size_t numBlocks, byte *outBuffer);
|
||||
|
||||
bool AES_Neon;
|
||||
#endif
|
||||
|
||||
void keySched(byte key[_MAX_KEY_COLUMNS][4]);
|
||||
void keyEncToDec();
|
||||
void GenerateTables();
|
||||
|
|
|
@ -215,11 +215,22 @@ bool ScanTree::GetNextMask()
|
|||
UnixSlashToDos(CurMask,CurMask,ASIZE(CurMask));
|
||||
#endif
|
||||
|
||||
// We wish to scan entire disk if mask like c:\ is specified
|
||||
// regardless of recursion mode. Use c:\*.* mask when need to scan only
|
||||
// the root directory.
|
||||
// We prefer to scan entire disk if mask like \\server\share\ or c:\
|
||||
// is specified regardless of recursion mode. Use \\server\share\*.*
|
||||
// or c:\*.* mask to scan only the root directory.
|
||||
if (CurMask[0]=='\\' && CurMask[1]=='\\')
|
||||
{
|
||||
const wchar *Slash=wcschr(CurMask+2,'\\');
|
||||
if (Slash!=NULL)
|
||||
{
|
||||
Slash=wcschr(Slash+1,'\\');
|
||||
ScanEntireDisk=Slash!=NULL && *(Slash+1)==0;
|
||||
}
|
||||
}
|
||||
else
|
||||
ScanEntireDisk=IsDriveLetter(CurMask) && IsPathDiv(CurMask[2]) && CurMask[3]==0;
|
||||
|
||||
|
||||
wchar *Name=PointToName(CurMask);
|
||||
if (*Name==0)
|
||||
wcsncatz(CurMask,MASKALL,ASIZE(CurMask));
|
||||
|
|
|
@ -56,7 +56,6 @@ static CryptLoader GlobalCryptLoader;
|
|||
|
||||
SecPassword::SecPassword()
|
||||
{
|
||||
CrossProcess=false;
|
||||
Set(L"");
|
||||
}
|
||||
|
||||
|
@ -70,7 +69,8 @@ SecPassword::~SecPassword()
|
|||
void SecPassword::Clean()
|
||||
{
|
||||
PasswordSet=false;
|
||||
cleandata(Password,sizeof(Password));
|
||||
if (Password.size()>0)
|
||||
cleandata(&Password[0],Password.size()*sizeof(Password[0]));
|
||||
}
|
||||
|
||||
|
||||
|
@ -104,7 +104,7 @@ void SecPassword::Process(const wchar *Src,size_t SrcSize,wchar *Dst,size_t DstS
|
|||
// Source string can be shorter than destination as in case when we process
|
||||
// -p<pwd> parameter, so we need to take into account both sizes.
|
||||
memcpy(Dst,Src,Min(SrcSize,DstSize)*sizeof(*Dst));
|
||||
SecHideData(Dst,DstSize*sizeof(*Dst),Encode,CrossProcess);
|
||||
SecHideData(Dst,DstSize*sizeof(*Dst),Encode,false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -112,7 +112,7 @@ void SecPassword::Get(wchar *Psw,size_t MaxSize)
|
|||
{
|
||||
if (PasswordSet)
|
||||
{
|
||||
Process(Password,ASIZE(Password),Psw,MaxSize,false);
|
||||
Process(&Password[0],Password.size(),Psw,MaxSize,false);
|
||||
Psw[MaxSize-1]=0;
|
||||
}
|
||||
else
|
||||
|
@ -124,15 +124,14 @@ void SecPassword::Get(wchar *Psw,size_t MaxSize)
|
|||
|
||||
void SecPassword::Set(const wchar *Psw)
|
||||
{
|
||||
if (*Psw==0)
|
||||
{
|
||||
PasswordSet=false;
|
||||
memset(Password,0,sizeof(Password));
|
||||
}
|
||||
else
|
||||
// Eliminate any traces of previously stored password for security reason
|
||||
// in case it was longer than new one.
|
||||
Clean();
|
||||
|
||||
if (*Psw!=0)
|
||||
{
|
||||
PasswordSet=true;
|
||||
Process(Psw,wcslen(Psw)+1,Password,ASIZE(Password),true);
|
||||
Process(Psw,wcslen(Psw)+1,&Password[0],Password.size(),true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,7 +141,7 @@ size_t SecPassword::Length()
|
|||
wchar Plain[MAXPASSWORD];
|
||||
Get(Plain,ASIZE(Plain));
|
||||
size_t Length=wcslen(Plain);
|
||||
cleandata(Plain,ASIZE(Plain));
|
||||
cleandata(Plain,sizeof(Plain));
|
||||
return Length;
|
||||
}
|
||||
|
||||
|
@ -157,12 +156,15 @@ bool SecPassword::operator == (SecPassword &psw)
|
|||
Get(Plain1,ASIZE(Plain1));
|
||||
psw.Get(Plain2,ASIZE(Plain2));
|
||||
bool Result=wcscmp(Plain1,Plain2)==0;
|
||||
cleandata(Plain1,ASIZE(Plain1));
|
||||
cleandata(Plain2,ASIZE(Plain2));
|
||||
cleandata(Plain1,sizeof(Plain1));
|
||||
cleandata(Plain2,sizeof(Plain2));
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
// Set CrossProcess to true if we need to pass a password to another process.
|
||||
// We use CrossProcess when transferring parameters to UAC elevated WinRAR
|
||||
// and Windows GUI SFX modules.
|
||||
void SecHideData(void *Data,size_t DataSize,bool Encode,bool CrossProcess)
|
||||
{
|
||||
// CryptProtectMemory is not available in UWP and CryptProtectData
|
||||
|
|
|
@ -8,10 +8,7 @@ class SecPassword
|
|||
private:
|
||||
void Process(const wchar *Src,size_t SrcSize,wchar *Dst,size_t DstSize,bool Encode);
|
||||
|
||||
wchar Password[MAXPASSWORD];
|
||||
|
||||
// It is important to have this 'bool' value, so if our object is cleaned
|
||||
// with memset as a part of larger structure, it is handled correctly.
|
||||
std::vector<wchar> Password = std::vector<wchar>(MAXPASSWORD);
|
||||
bool PasswordSet;
|
||||
public:
|
||||
SecPassword();
|
||||
|
@ -22,10 +19,6 @@ class SecPassword
|
|||
bool IsSet() {return PasswordSet;}
|
||||
size_t Length();
|
||||
bool operator == (SecPassword &psw);
|
||||
|
||||
// Set to true if we need to pass a password to another process.
|
||||
// We use it when transferring parameters to UAC elevated WinRAR.
|
||||
bool CrossProcess;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -357,6 +357,32 @@ void itoa(int64 n,wchar *Str,size_t MaxSize)
|
|||
}
|
||||
|
||||
|
||||
// Convert the number to string using thousand separators.
|
||||
void fmtitoa(int64 n,wchar *Str,size_t MaxSize)
|
||||
{
|
||||
static wchar ThSep=0; // Thousands separator.
|
||||
#ifdef _WIN_ALL
|
||||
wchar Info[10];
|
||||
if (!ThSep!=0 && GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_STHOUSAND,Info,ASIZE(Info))>0)
|
||||
ThSep=*Info;
|
||||
#elif defined(_UNIX)
|
||||
ThSep=*localeconv()->thousands_sep;
|
||||
#endif
|
||||
if (ThSep==0) // If failed to detect the actual separator value.
|
||||
ThSep=' ';
|
||||
wchar RawText[30]; // 20 characters are enough for largest unsigned 64 bit int.
|
||||
itoa(n,RawText,ASIZE(RawText));
|
||||
uint S=0,D=0,L=wcslen(RawText)%3;
|
||||
while (RawText[S]!=0 && D+1<MaxSize)
|
||||
{
|
||||
if (S!=0 && (S+3-L)%3==0)
|
||||
Str[D++]=ThSep;
|
||||
Str[D++]=RawText[S++];
|
||||
}
|
||||
Str[D]=0;
|
||||
}
|
||||
|
||||
|
||||
const wchar* GetWide(const char *Src)
|
||||
{
|
||||
const size_t MaxLength=NM;
|
||||
|
|
|
@ -42,6 +42,7 @@ int wcsnicompc(const wchar *s1,const wchar *s2,size_t n);
|
|||
|
||||
void itoa(int64 n,char *Str,size_t MaxSize);
|
||||
void itoa(int64 n,wchar *Str,size_t MaxSize);
|
||||
void fmtitoa(int64 n,wchar *Str,size_t MaxSize);
|
||||
const wchar* GetWide(const char *Src);
|
||||
const wchar* GetCmdParam(const wchar *CmdLine,wchar *Param,size_t MaxSize);
|
||||
#ifndef RARDLL
|
||||
|
|
|
@ -187,10 +187,10 @@ SSE_VERSION _SSE_Version=GetSSEVersion();
|
|||
SSE_VERSION GetSSEVersion()
|
||||
{
|
||||
int CPUInfo[4];
|
||||
__cpuid(CPUInfo, 0x80000000);
|
||||
__cpuid(CPUInfo, 0);
|
||||
|
||||
// Maximum supported cpuid function. For example, Pentium M 755 returns 4 here.
|
||||
uint MaxSupported=CPUInfo[0] & 0x7fffffff;
|
||||
// Maximum supported cpuid function.
|
||||
uint MaxSupported=CPUInfo[0];
|
||||
|
||||
if (MaxSupported>=7)
|
||||
{
|
||||
|
|
|
@ -149,3 +149,5 @@ uint GetNumberOfThreads()
|
|||
return NumCPU;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -22,6 +22,17 @@ class RarTime
|
|||
|
||||
// Internal time representation in 1/TICKS_PER_SECOND since 01.01.1601.
|
||||
// We use nanoseconds here to handle the high precision Unix time.
|
||||
// It allows dates up to July 2185.
|
||||
//
|
||||
// If we'll ever need to extend the date range, we can define a lower
|
||||
// precision Windows version of TICKS_PER_SECOND. But then Unix and Windows
|
||||
// versions can differ in least significant digits of "lt" time output
|
||||
// for Unix archives.
|
||||
// Alternatively we can introduce 'bool HighPrecision' set to true
|
||||
// in SetUnixNS() and TicksPerSecond() instead of constant above.
|
||||
// It might be more reliable than defining TicksPerSecond variable,
|
||||
// which wouldn't survive memset of any structure hosting RarTime.
|
||||
// We would need to eliminate all such memsets in the entire code first.
|
||||
uint64 itime;
|
||||
public:
|
||||
// RarLocalTime::Reminder precision. Must be equal to TICKS_PER_SECOND.
|
||||
|
|
|
@ -49,7 +49,7 @@ enum UIMESSAGE_CODE {
|
|||
UIMSG_CORRECTINGNAME, UIMSG_BADARCHIVE, UIMSG_CREATING, UIMSG_RENAMING,
|
||||
UIMSG_RECVOLCALCCHECKSUM, UIMSG_RECVOLFOUND, UIMSG_RECVOLMISSING,
|
||||
UIMSG_MISSINGVOL, UIMSG_RECONSTRUCTING, UIMSG_CHECKSUM, UIMSG_FAT32SIZE,
|
||||
UIMSG_SKIPENCARC,
|
||||
UIMSG_SKIPENCARC, UIMSG_FILERENAME,
|
||||
|
||||
UIWAIT_FIRST,
|
||||
UIWAIT_DISKFULLNEXT, UIWAIT_FCREATEERROR, UIWAIT_BADPSW,
|
||||
|
@ -77,7 +77,7 @@ enum UIASKREP_RESULT {
|
|||
};
|
||||
|
||||
UIASKREP_RESULT uiAskReplace(wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags);
|
||||
UIASKREP_RESULT uiAskReplaceEx(RAROptions *Cmd,wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags);
|
||||
UIASKREP_RESULT uiAskReplaceEx(CommandData *Cmd,wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags);
|
||||
|
||||
void uiInit(SOUND_NOTIFY_MODE Sound);
|
||||
|
||||
|
@ -88,7 +88,7 @@ void uiExtractProgress(int64 CurFileSize,int64 TotalFileSize,int64 CurSize,int64
|
|||
void uiProcessProgress(const char *Command,int64 CurSize,int64 TotalSize);
|
||||
|
||||
enum UIPASSWORD_TYPE {UIPASSWORD_GLOBAL,UIPASSWORD_FILE,UIPASSWORD_ARCHIVE};
|
||||
bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password);
|
||||
bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password,CheckPassword *CheckPwd);
|
||||
bool uiIsGlobalPasswordSet();
|
||||
|
||||
enum UIALARM_TYPE {UIALARM_ERROR, UIALARM_INFO, UIALARM_QUESTION};
|
||||
|
@ -145,30 +145,31 @@ class uiMsgStore
|
|||
// Templates recognize usual NULL as integer, not wchar*.
|
||||
#define UINULL ((wchar *)NULL)
|
||||
|
||||
inline void uiMsg(UIMESSAGE_CODE Code)
|
||||
inline void uiMsgBase(uiMsgStore &Store)
|
||||
{
|
||||
uiMsgStore Store(Code);
|
||||
Store.Msg();
|
||||
// Called last, when no parameters are left.
|
||||
}
|
||||
|
||||
template<class T1> void uiMsg(UIMESSAGE_CODE Code,T1 a1)
|
||||
template<class T1,class... TN> void uiMsgBase(uiMsgStore &Store,T1&& a1,TN&&... aN)
|
||||
{
|
||||
uiMsgStore Store(Code);
|
||||
// Process first parameter and pass the rest to same uiMsgBase.
|
||||
Store<<a1;
|
||||
Store.Msg();
|
||||
uiMsgBase(Store,aN...);
|
||||
}
|
||||
|
||||
template<class T1,class T2> void uiMsg(UIMESSAGE_CODE Code,T1 a1,T2 a2)
|
||||
|
||||
// Use variadic templates.
|
||||
//
|
||||
// We must pass variable parameters by reference, so no temporary copies are
|
||||
// created for custom string objects like CStringBase in 7-Zip decompression
|
||||
// code. Such temporary copies would be destroyed inside of recursive
|
||||
// uiMsgBase calls, leaving us with Str[] items pointing at released memory.
|
||||
// Since we pass integer values as well, we can't use & references
|
||||
// and must resort to && rvalue references.
|
||||
template<class... TN> void uiMsg(UIMESSAGE_CODE Code,TN&&... aN)
|
||||
{
|
||||
uiMsgStore Store(Code);
|
||||
Store<<a1<<a2;
|
||||
Store.Msg();
|
||||
}
|
||||
|
||||
template<class T1,class T2,class T3> void uiMsg(UIMESSAGE_CODE code,T1 a1,T2 a2,T3 a3)
|
||||
{
|
||||
uiMsgStore Store(code);
|
||||
Store<<a1<<a2<<a3;
|
||||
uiMsgBase(Store,aN...);
|
||||
Store.Msg();
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ void uiInit(SOUND_NOTIFY_MODE Sound)
|
|||
|
||||
// Additionally to handling user input, it analyzes and sets command options.
|
||||
// Returns only 'replace', 'skip' and 'cancel' codes.
|
||||
UIASKREP_RESULT uiAskReplaceEx(RAROptions *Cmd,wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags)
|
||||
UIASKREP_RESULT uiAskReplaceEx(CommandData *Cmd,wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags)
|
||||
{
|
||||
if (Cmd->Overwrite==OVERWRITE_NONE)
|
||||
return UIASKREP_R_SKIP;
|
||||
|
|
|
@ -183,6 +183,7 @@ void uiMsgStore::Msg()
|
|||
Log(NULL,St(MNeedAdmin));
|
||||
break;
|
||||
case UIERROR_ARCBROKEN:
|
||||
mprintf(L"\n"); // So it is not merged with preceding UIERROR_HEADERBROKEN.
|
||||
Log(Str[0],St(MErrBrokenArc));
|
||||
break;
|
||||
case UIERROR_HEADERBROKEN:
|
||||
|
@ -262,6 +263,7 @@ void uiMsgStore::Msg()
|
|||
break;
|
||||
case UIERROR_MISSINGVOL:
|
||||
Log(Str[0],St(MAbsNextVol),Str[0]);
|
||||
mprintf(L" "); // For progress percent.
|
||||
break;
|
||||
#ifndef SFX_MODULE
|
||||
case UIERROR_NEEDPREVVOL:
|
||||
|
@ -395,7 +397,8 @@ void uiMsgStore::Msg()
|
|||
}
|
||||
|
||||
|
||||
bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password)
|
||||
bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,
|
||||
SecPassword *Password,CheckPassword *CheckPwd)
|
||||
{
|
||||
// Unlike GUI we cannot provide Cancel button here, so we use the empty
|
||||
// password to abort. Otherwise user not knowing a password would need to
|
||||
|
|
|
@ -33,7 +33,8 @@ void uiMsgStore::Msg()
|
|||
}
|
||||
|
||||
|
||||
bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password)
|
||||
bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,
|
||||
SecPassword *Password,CheckPassword *CheckPwd)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -70,7 +70,8 @@ static bool SafeCharToWide(const char *Src,wchar *Dest,size_t DestSize)
|
|||
}
|
||||
|
||||
|
||||
bool ExtractUnixLink30(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName)
|
||||
static bool ExtractUnixLink30(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,
|
||||
const wchar *LinkName,bool &UpLink)
|
||||
{
|
||||
char Target[NM];
|
||||
if (IsLink(Arc.FileHead.FileAttr))
|
||||
|
@ -100,13 +101,14 @@ bool ExtractUnixLink30(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const w
|
|||
if (!Cmd->AbsoluteLinks && (IsFullPath(TargetW) ||
|
||||
!IsRelativeSymlinkSafe(Cmd,Arc.FileHead.FileName,LinkName,TargetW)))
|
||||
return false;
|
||||
UpLink=strstr(Target,"..")!=NULL;
|
||||
return UnixSymlink(Cmd,Target,LinkName,&Arc.FileHead.mtime,&Arc.FileHead.atime);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool ExtractUnixLink50(CommandData *Cmd,const wchar *Name,FileHeader *hd)
|
||||
static bool ExtractUnixLink50(CommandData *Cmd,const wchar *Name,FileHeader *hd)
|
||||
{
|
||||
char Target[NM];
|
||||
WideToChar(hd->RedirName,Target,ASIZE(Target));
|
||||
|
@ -127,8 +129,6 @@ bool ExtractUnixLink50(CommandData *Cmd,const wchar *Name,FileHeader *hd)
|
|||
// Use hd->FileName instead of LinkName, since LinkName can include
|
||||
// the destination path as a prefix, which can confuse
|
||||
// IsRelativeSymlinkSafe algorithm.
|
||||
// 2022.05.04: Use TargetW instead of previously used hd->RedirName
|
||||
// for security reason.
|
||||
if (!Cmd->AbsoluteLinks && (IsFullPath(TargetW) ||
|
||||
!IsRelativeSymlinkSafe(Cmd,hd->FileName,Name,TargetW)))
|
||||
return false;
|
||||
|
|
|
@ -229,10 +229,11 @@ void CharToWideMap(const char *Src,wchar *Dest,size_t DestSize,bool &Success)
|
|||
#endif
|
||||
|
||||
|
||||
// SrcSize is in wide characters, not in bytes.
|
||||
byte* WideToRaw(const wchar *Src,byte *Dest,size_t SrcSize)
|
||||
// SrcSize is source data size in wide characters, not in bytes.
|
||||
// DestSize is the maximum allowed destination size.
|
||||
byte* WideToRaw(const wchar *Src,size_t SrcSize,byte *Dest,size_t DestSize)
|
||||
{
|
||||
for (size_t I=0;I<SrcSize;I++,Src++)
|
||||
for (size_t I=0;I<SrcSize && I*2+1<DestSize;I++,Src++)
|
||||
{
|
||||
Dest[I*2]=(byte)*Src;
|
||||
Dest[I*2+1]=(byte)(*Src>>8);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
bool WideToChar(const wchar *Src,char *Dest,size_t DestSize);
|
||||
bool CharToWide(const char *Src,wchar *Dest,size_t DestSize);
|
||||
byte* WideToRaw(const wchar *Src,byte *Dest,size_t SrcSize);
|
||||
byte* WideToRaw(const wchar *Src,size_t SrcSize,byte *Dest,size_t DestSize);
|
||||
wchar* RawToWide(const byte *Src,wchar *Dest,size_t DestSize);
|
||||
void WideToUtf(const wchar *Src,char *Dest,size_t DestSize);
|
||||
size_t WideToUtfSize(const wchar *Src);
|
||||
|
|
|
@ -91,12 +91,6 @@ void Unpack::Init(size_t WinSize,bool Solid)
|
|||
if ((WinSize>>16)>0x10000) // Window size must not exceed 4 GB.
|
||||
return;
|
||||
|
||||
// Unrar does not support window size greather than 1GB at this time.
|
||||
// Any request for a window larger than 1GB should be ignored.
|
||||
const size_t MaxAllocSize=0x40000000;
|
||||
if (WinSize>MaxAllocSize)
|
||||
WinSize=MaxAllocSize;
|
||||
|
||||
// Archiving code guarantees that window size does not grow in the same
|
||||
// solid stream. So if we are here, we are either creating a new window
|
||||
// or increasing the size of non-solid window. So we could safely reject
|
||||
|
@ -315,7 +309,7 @@ void Unpack::MakeDecodeTables(byte *LengthTable,DecodeTable *Dec,uint Size)
|
|||
Dec->QuickBits=MAX_QUICK_DECODE_BITS;
|
||||
break;
|
||||
default:
|
||||
Dec->QuickBits=MAX_QUICK_DECODE_BITS-3;
|
||||
Dec->QuickBits=MAX_QUICK_DECODE_BITS>3 ? MAX_QUICK_DECODE_BITS-3 : 0;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -93,17 +93,17 @@ struct UnpackBlockTables
|
|||
|
||||
#ifdef RAR_SMP
|
||||
enum UNP_DEC_TYPE {
|
||||
UNPDT_LITERAL,UNPDT_MATCH,UNPDT_FULLREP,UNPDT_REP,UNPDT_FILTER
|
||||
UNPDT_LITERAL=0,UNPDT_MATCH,UNPDT_FULLREP,UNPDT_REP,UNPDT_FILTER
|
||||
};
|
||||
|
||||
struct UnpackDecodedItem
|
||||
{
|
||||
UNP_DEC_TYPE Type;
|
||||
byte Type; // 'byte' instead of enum type to reduce memory use.
|
||||
ushort Length;
|
||||
union
|
||||
{
|
||||
uint Distance;
|
||||
byte Literal[4];
|
||||
byte Literal[8]; // Store up to 8 chars here to speed up extraction.
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ void Unpack::Unpack29(bool Solid)
|
|||
if (!UnpReadBuf30())
|
||||
break;
|
||||
}
|
||||
if (((WrPtr-UnpPtr) & MaxWinMask)<260 && WrPtr!=UnpPtr)
|
||||
if (((WrPtr-UnpPtr) & MaxWinMask)<=MAX3_INC_LZ_MATCH && WrPtr!=UnpPtr)
|
||||
{
|
||||
UnpWriteBuf30();
|
||||
if (WrittenFileSize>DestUnpSize)
|
||||
|
|
|
@ -42,7 +42,7 @@ void Unpack::Unpack5(bool Solid)
|
|||
break;
|
||||
}
|
||||
|
||||
if (((WriteBorder-UnpPtr) & MaxWinMask)<MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr)
|
||||
if (((WriteBorder-UnpPtr) & MaxWinMask)<=MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr)
|
||||
{
|
||||
UnpWriteBuf();
|
||||
if (WrittenFileSize>DestUnpSize)
|
||||
|
@ -93,7 +93,7 @@ void Unpack::Unpack5(bool Solid)
|
|||
}
|
||||
else
|
||||
{
|
||||
Distance+=Inp.getbits32()>>(32-DBits);
|
||||
Distance+=Inp.getbits()>>(16-DBits);
|
||||
Inp.addbits(DBits);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -345,7 +345,7 @@ void Unpack::UnpackDecode(UnpackThreadData &D)
|
|||
if (D.DecodedSize>1)
|
||||
{
|
||||
UnpackDecodedItem *PrevItem=CurItem-1;
|
||||
if (PrevItem->Type==UNPDT_LITERAL && PrevItem->Length<3)
|
||||
if (PrevItem->Type==UNPDT_LITERAL && PrevItem->Length<ASIZE(PrevItem->Literal)-1)
|
||||
{
|
||||
PrevItem->Length++;
|
||||
PrevItem->Literal[PrevItem->Length]=(byte)MainSlot;
|
||||
|
@ -388,7 +388,7 @@ void Unpack::UnpackDecode(UnpackThreadData &D)
|
|||
}
|
||||
else
|
||||
{
|
||||
Distance+=D.Inp.getbits32()>>(32-DBits);
|
||||
Distance+=D.Inp.getbits()>>(16-DBits);
|
||||
D.Inp.addbits(DBits);
|
||||
}
|
||||
}
|
||||
|
@ -451,7 +451,7 @@ bool Unpack::ProcessDecoded(UnpackThreadData &D)
|
|||
while (Item<Border)
|
||||
{
|
||||
UnpPtr&=MaxWinMask;
|
||||
if (((WriteBorder-UnpPtr) & MaxWinMask)<MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr)
|
||||
if (((WriteBorder-UnpPtr) & MaxWinMask)<=MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr)
|
||||
{
|
||||
UnpWriteBuf();
|
||||
if (WrittenFileSize>DestUnpSize)
|
||||
|
@ -461,10 +461,10 @@ bool Unpack::ProcessDecoded(UnpackThreadData &D)
|
|||
if (Item->Type==UNPDT_LITERAL)
|
||||
{
|
||||
#if defined(LITTLE_ENDIAN) && defined(ALLOW_MISALIGNED)
|
||||
if (Item->Length==3 && UnpPtr<MaxWinSize-4)
|
||||
if (Item->Length==7 && UnpPtr<MaxWinSize-8)
|
||||
{
|
||||
*(uint32 *)(Window+UnpPtr)=*(uint32 *)Item->Literal;
|
||||
UnpPtr+=4;
|
||||
*(uint64 *)(Window+UnpPtr)=*(uint64 *)(Item->Literal);
|
||||
UnpPtr+=8;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
@ -559,7 +559,7 @@ bool Unpack::UnpackLargeBlock(UnpackThreadData &D)
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (((WriteBorder-UnpPtr) & MaxWinMask)<MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr)
|
||||
if (((WriteBorder-UnpPtr) & MaxWinMask)<=MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr)
|
||||
{
|
||||
UnpWriteBuf();
|
||||
if (WrittenFileSize>DestUnpSize)
|
||||
|
|
|
@ -1,57 +1,13 @@
|
|||
|
||||
|
||||
void ExtractUnixOwner20(Archive &Arc,const wchar *FileName)
|
||||
{
|
||||
char NameA[NM];
|
||||
WideToChar(FileName,NameA,ASIZE(NameA));
|
||||
|
||||
if (Arc.BrokenHeader)
|
||||
{
|
||||
uiMsg(UIERROR_UOWNERBROKEN,Arc.FileName,FileName);
|
||||
ErrHandler.SetErrorCode(RARX_CRC);
|
||||
return;
|
||||
}
|
||||
|
||||
struct passwd *pw;
|
||||
errno=0; // Required by getpwnam specification if we need to check errno.
|
||||
if ((pw=getpwnam(Arc.UOHead.OwnerName))==NULL)
|
||||
{
|
||||
uiMsg(UIERROR_UOWNERGETOWNERID,Arc.FileName,GetWide(Arc.UOHead.OwnerName));
|
||||
ErrHandler.SysErrMsg();
|
||||
ErrHandler.SetErrorCode(RARX_WARNING);
|
||||
return;
|
||||
}
|
||||
uid_t OwnerID=pw->pw_uid;
|
||||
|
||||
struct group *gr;
|
||||
errno=0; // Required by getgrnam specification if we need to check errno.
|
||||
if ((gr=getgrnam(Arc.UOHead.GroupName))==NULL)
|
||||
{
|
||||
uiMsg(UIERROR_UOWNERGETGROUPID,Arc.FileName,GetWide(Arc.UOHead.GroupName));
|
||||
ErrHandler.SysErrMsg();
|
||||
ErrHandler.SetErrorCode(RARX_CRC);
|
||||
return;
|
||||
}
|
||||
uint Attr=GetFileAttr(FileName);
|
||||
gid_t GroupID=gr->gr_gid;
|
||||
#if defined(SAVE_LINKS) && !defined(_APPLE)
|
||||
if (lchown(NameA,OwnerID,GroupID)!=0)
|
||||
#else
|
||||
if (chown(NameA,OwnerID,GroupID)!=0)
|
||||
#endif
|
||||
{
|
||||
uiMsg(UIERROR_UOWNERSET,Arc.FileName,FileName);
|
||||
ErrHandler.SetErrorCode(RARX_CREATE);
|
||||
}
|
||||
SetFileAttr(FileName,Attr);
|
||||
}
|
||||
|
||||
|
||||
void ExtractUnixOwner30(Archive &Arc,const wchar *FileName)
|
||||
{
|
||||
char NameA[NM];
|
||||
WideToChar(FileName,NameA,ASIZE(NameA));
|
||||
|
||||
if (memchr(&Arc.SubHead.SubData[0],0,Arc.SubHead.SubData.Size())==NULL)
|
||||
return;
|
||||
|
||||
char *OwnerName=(char *)&Arc.SubHead.SubData[0];
|
||||
int OwnerSize=strlen(OwnerName)+1;
|
||||
int GroupSize=Arc.SubHead.SubData.Size()-OwnerSize;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#define RARVER_MAJOR 6
|
||||
#define RARVER_MINOR 12
|
||||
#define RARVER_MINOR 23
|
||||
#define RARVER_BETA 0
|
||||
#define RARVER_DAY 4
|
||||
#define RARVER_MONTH 5
|
||||
#define RARVER_YEAR 2022
|
||||
#define RARVER_DAY 1
|
||||
#define RARVER_MONTH 8
|
||||
#define RARVER_YEAR 2023
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
#include "rar.hpp"
|
||||
|
||||
#ifdef RARDLL
|
||||
static bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize);
|
||||
static bool DllVolNotify(RAROptions *Cmd,wchar *NextName);
|
||||
static bool DllVolChange(CommandData *Cmd,wchar *NextName,size_t NameSize);
|
||||
static bool DllVolNotify(CommandData *Cmd,wchar *NextName);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Command)
|
||||
{
|
||||
RAROptions *Cmd=Arc.GetRAROptions();
|
||||
CommandData *Cmd=Arc.GetCommandData();
|
||||
|
||||
HEADER_TYPE HeaderType=Arc.GetHeaderType();
|
||||
FileHeader *hd=HeaderType==HEAD_SERVICE ? &Arc.SubHead:&Arc.FileHead;
|
||||
|
@ -190,7 +190,7 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma
|
|||
|
||||
|
||||
#ifdef RARDLL
|
||||
bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize)
|
||||
bool DllVolChange(CommandData *Cmd,wchar *NextName,size_t NameSize)
|
||||
{
|
||||
bool DllVolChanged=false,DllVolAborted=false;
|
||||
|
||||
|
@ -246,7 +246,7 @@ bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize)
|
|||
|
||||
|
||||
#ifdef RARDLL
|
||||
bool DllVolNotify(RAROptions *Cmd,wchar *NextName)
|
||||
bool DllVolNotify(CommandData *Cmd,wchar *NextName)
|
||||
{
|
||||
char NextNameA[NM];
|
||||
WideToChar(NextName,NextNameA,ASIZE(NextNameA));
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
#ifndef _RAR_VOLUME_
|
||||
#define _RAR_VOLUME_
|
||||
|
||||
void SplitArchive(Archive &Arc,FileHeader *fh,int64 *HeaderPos,
|
||||
ComprDataIO *DataIO);
|
||||
bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,
|
||||
wchar Command);
|
||||
void SetVolWrite(Archive &Dest,int64 VolSize);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -40,7 +40,7 @@ bool CreateReparsePoint(CommandData *Cmd,const wchar *Name,FileHeader *hd)
|
|||
PrivSet=true;
|
||||
}
|
||||
|
||||
const DWORD BufSize=sizeof(REPARSE_DATA_BUFFER)+2*NM+1024;
|
||||
const DWORD BufSize=sizeof(REPARSE_DATA_BUFFER)+2*NM*sizeof(wchar)+1024;
|
||||
Array<byte> Buf(BufSize);
|
||||
REPARSE_DATA_BUFFER *rdb=(REPARSE_DATA_BUFFER *)&Buf[0];
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ void ExtractStreams20(Archive &Arc,const wchar *FileName)
|
|||
CharToWide(Arc.StreamHead.StreamName,StoredName,ASIZE(StoredName));
|
||||
ConvertPath(StoredName+1,StoredName+1,ASIZE(StoredName)-1);
|
||||
|
||||
|
||||
wcsncatz(StreamName,StoredName,ASIZE(StreamName));
|
||||
|
||||
FindData fd;
|
||||
|
@ -111,16 +112,23 @@ void ExtractStreams(Archive &Arc,const wchar *FileName,bool TestMode)
|
|||
|
||||
wcsncatz(FullName,StreamName,ASIZE(FullName));
|
||||
|
||||
|
||||
FindData fd;
|
||||
bool Found=FindFile::FastFind(FileName,&fd);
|
||||
bool HostFound=FindFile::FastFind(FileName,&fd);
|
||||
|
||||
if ((fd.FileAttr & FILE_ATTRIBUTE_READONLY)!=0)
|
||||
SetFileAttr(FileName,fd.FileAttr & ~FILE_ATTRIBUTE_READONLY);
|
||||
File CurFile;
|
||||
if (CurFile.WCreate(FullName) && Arc.ReadSubData(NULL,&CurFile,false))
|
||||
|
||||
if (CurFile.WCreate(FullName))
|
||||
{
|
||||
if (Arc.ReadSubData(NULL,&CurFile,false))
|
||||
CurFile.Close();
|
||||
}
|
||||
|
||||
// Restoring original file timestamps.
|
||||
File HostFile;
|
||||
if (Found && HostFile.Open(FileName,FMF_OPENSHARED|FMF_UPDATE))
|
||||
if (HostFound && HostFile.Open(FileName,FMF_OPENSHARED|FMF_UPDATE))
|
||||
SetFileTime(HostFile.GetHandle(),&fd.ftCreationTime,&fd.ftLastAccessTime,
|
||||
&fd.ftLastWriteTime);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue