diff -ur unrar-6.1.7/UnRARDll.vcxproj unrar-6.2.7/UnRARDll.vcxproj
--- unrar-6.1.7/UnRARDll.vcxproj 2022-10-19 22:05:12
+++ unrar-6.2.7/UnRARDll.vcxproj 2022-05-17 22:04:05
@@ -138,7 +138,7 @@
Sync
EnableFastChecks
MultiThreadedDebug
- 4Bytes
+ Default
false
Use
rar.hpp
@@ -168,7 +168,7 @@
Sync
EnableFastChecks
MultiThreadedDebug
- 4Bytes
+ Default
false
Use
rar.hpp
@@ -198,7 +198,7 @@
false
Sync
MultiThreaded
- 4Bytes
+ Default
true
true
NoExtensions
@@ -239,7 +239,7 @@
false
Sync
MultiThreaded
- 4Bytes
+ Default
true
true
false
@@ -274,7 +274,7 @@
false
Sync
MultiThreaded
- 4Bytes
+ Default
true
true
NoExtensions
@@ -315,7 +315,7 @@
false
Sync
MultiThreaded
- 4Bytes
+ Default
true
true
false
diff -ur unrar-6.1.7/archive.cpp unrar-6.2.7/archive.cpp
--- unrar-6.1.7/archive.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/archive.cpp 2023-05-14 13:10:33
@@ -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 @@
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;
diff -ur unrar-6.1.7/archive.hpp unrar-6.2.7/archive.hpp
--- unrar-6.1.7/archive.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/archive.hpp 2023-05-14 13:10:33
@@ -32,8 +32,8 @@
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 @@
#endif
ComprDataIO SubDataIO;
bool DummyCmd;
- RAROptions *Cmd;
+ CommandData *Cmd;
RarTime LatestTime;
@@ -58,7 +58,7 @@
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 @@
const wchar *Name,uint Flags);
bool ReadSubData(Array *UnpData,File *DestFile,bool TestMode);
HEADER_TYPE GetHeaderType() {return CurHeaderType;}
- RAROptions* GetRAROptions() {return Cmd;}
+ CommandData* GetCommandData() {return Cmd;}
void SetSilentOpen(bool Mode) {SilentOpen=Mode;}
#if 0
void GetRecoveryInfo(bool Required,int64 *Size,int *Percent);
diff -ur unrar-6.1.7/arcread.cpp unrar-6.2.7/arcread.cpp
--- unrar-6.1.7/arcread.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/arcread.cpp 2023-05-14 13:10:34
@@ -100,6 +100,9 @@
// 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 @@
#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 @@
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);
@@ -577,14 +584,20 @@
// in -p to not stop batch processing for encrypted archives.
bool GlobalPassword=Cmd->Password.IsSet() || uiIsGlobalPasswordSet();
+ RarCheckPassword CheckPwd;
+ if (CryptHead.UsePswCheck && !BrokenHeader)
+ CheckPwd.Set(CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,CryptHead.PswCheck);
+
while (true) // Repeat the password prompt for wrong passwords.
{
- RequestArcPassword();
+ RequestArcPassword(CheckPwd.IsSet() ? &CheckPwd:NULL);
byte PswCheck[SIZE_PSWCHECK];
HeadersCrypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,NULL,PswCheck);
- // Verify password validity.
- if (CryptHead.UsePswCheck && memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0)
+ // Verify password validity. If header is damaged, we cannot rely on
+ // password check value, because it can be damaged too.
+ if (CryptHead.UsePswCheck && !BrokenHeader &&
+ memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0)
{
if (GlobalPassword) // For -p or Ctrl+P.
{
@@ -850,8 +863,6 @@
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,26 +886,7 @@
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 +908,7 @@
#if !defined(RAR_NOCRYPT)
-void Archive::RequestArcPassword()
+void Archive::RequestArcPassword(RarCheckPassword *CheckPwd)
{
if (!Cmd->Password.IsSet())
{
@@ -946,7 +938,7 @@
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 +951,7 @@
#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,22 +974,57 @@
if (bb->HeaderType==HEAD_MAIN)
{
MainHeader *hd=(MainHeader *)bb;
- if (FieldType==MHEXTRA_LOCATOR)
+ switch(FieldType)
{
- hd->Locator=true;
- uint Flags=(uint)Raw->GetV();
- if ((Flags & MHEXTRA_LOCATOR_QLIST)!=0)
- {
- uint64 Offset=Raw->GetV();
- if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
- hd->QOpenOffset=Offset+CurBlockPos;
- }
- if ((Flags & MHEXTRA_LOCATOR_RR)!=0)
- {
- uint64 Offset=Raw->GetV();
- if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
- hd->RROffset=Offset+CurBlockPos;
- }
+ case MHEXTRA_LOCATOR:
+ {
+ hd->Locator=true;
+ uint Flags=(uint)Raw->GetV();
+ if ((Flags & MHEXTRA_LOCATOR_QLIST)!=0)
+ {
+ uint64 Offset=Raw->GetV();
+ if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
+ hd->QOpenOffset=Offset+CurBlockPos;
+ }
+ if ((Flags & MHEXTRA_LOCATOR_RR)!=0)
+ {
+ uint64 Offset=Raw->GetV();
+ if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
+ hd->RROffset=Offset+CurBlockPos;
+ }
+ }
+ break;
+ case MHEXTRA_METADATA:
+ {
+ uint Flags=(uint)Raw->GetV();
+ if ((Flags & MHEXTRA_METADATA_NAME)!=0)
+ {
+ uint64 NameSize=Raw->GetV();
+ if (NameSize<0x10000) // Prevent excessive allocation.
+ {
+ std::vector NameU((size_t)NameSize); // UTF-8 name.
+ Raw->GetB(&NameU[0],(size_t)NameSize);
+ // If starts from 0, the name was longer than reserved space
+ // when saving this extra field.
+ if (NameU[0]!=0)
+ {
+ NameU.push_back(0);
+ std::vector NameW(NameU.size()*4);
+ UtfToWide(&NameU[0],&NameW[0],NameW.size());
+ hd->OrigName.assign(&NameW[0]);
+ }
+ }
+ }
+ if ((Flags & MHEXTRA_METADATA_CTIME)!=0)
+ if ((Flags & MHEXTRA_METADATA_UNIXTIME)!=0)
+ if ((Flags & MHEXTRA_METADATA_UNIX_NS)!=0)
+ hd->OrigTime.SetUnixNS(Raw->Get8());
+ else
+ hd->OrigTime.SetUnix((time_t)Raw->Get4());
+ else
+ hd->OrigTime.SetWin(Raw->Get8());
+ }
+ break;
}
}
@@ -1453,7 +1480,9 @@
{
if (SubHead.UnpSize>0x1000000)
{
- // So huge allocation must never happen in valid archives.
+ // Prevent the excessive allocation. When reading to memory, normally
+ // this function operates with reasonably small blocks, such as
+ // the archive comment, NTFS ACL or "Zone.Identifier" NTFS stream.
uiMsg(UIERROR_SUBHEADERUNKNOWN,FileName);
return false;
}
diff -ur unrar-6.1.7/array.hpp unrar-6.2.7/array.hpp
--- unrar-6.1.7/array.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/array.hpp 2023-05-14 13:10:34
@@ -10,7 +10,6 @@
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 @@
void Alloc(size_t Items);
void Reset();
void SoftReset();
- void operator = (Array &Src);
+ Array& operator = (const Array &Src);
void Push(T Item);
void Append(T *Item,size_t Count);
T* Addr(size_t Item) {return Buffer+Item;}
void SetMaxSize(size_t Size) {MaxSize=Size;}
T* Begin() {return Buffer;}
T* End() {return Buffer==NULL ? NULL:Buffer+BufSize;}
- void SetSecure() {Secure=true;}
};
@@ -41,7 +39,6 @@
BufSize=0;
AllocSize=0;
MaxSize=0;
- Secure=false;
}
@@ -71,11 +68,7 @@
template Array::~Array()
{
if (Buffer!=NULL)
- {
- if (Secure)
- cleandata(Buffer,AllocSize*sizeof(T));
free(Buffer);
- }
}
@@ -111,25 +104,9 @@
size_t Suggested=AllocSize+AllocSize/4+32;
size_t NewSize=Max(BufSize,Suggested);
- T *NewBuffer;
- if (Secure)
- {
- NewBuffer=(T *)malloc(NewSize*sizeof(T));
- if (NewBuffer==NULL)
- ErrHandler.MemoryError();
- if (Buffer!=NULL)
- {
- memcpy(NewBuffer,Buffer,AllocSize*sizeof(T));
- cleandata(Buffer,AllocSize*sizeof(T));
- free(Buffer);
- }
- }
- else
- {
- NewBuffer=(T *)realloc(Buffer,NewSize*sizeof(T));
- if (NewBuffer==NULL)
- ErrHandler.MemoryError();
- }
+ T *NewBuffer=(T *)realloc(Buffer,NewSize*sizeof(T));
+ if (NewBuffer==NULL)
+ ErrHandler.MemoryError();
Buffer=NewBuffer;
AllocSize=NewSize;
}
@@ -165,12 +142,13 @@
}
-template void Array::operator =(Array &Src)
+template Array& Array::operator =(const Array &Src)
{
Reset();
Alloc(Src.BufSize);
if (Src.BufSize!=0)
memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T));
+ return *this;
}
diff -ur unrar-6.1.7/blake2s.hpp unrar-6.2.7/blake2s.hpp
--- unrar-6.1.7/blake2s.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/blake2s.hpp 2023-05-14 13:10:34
@@ -20,10 +20,15 @@
// 'new' operator.
struct blake2s_state
{
- enum { BLAKE_ALIGNMENT = 64 };
+ // Use constexpr instead of enums, because otherwise clang -std=c++20
+ // issues a warning about "arithmetic between different enumeration types"
+ // in ubuf[BLAKE_DATA_SIZE + BLAKE_ALIGNMENT] declaration.
+ static constexpr size_t BLAKE_ALIGNMENT = 64;
// buffer and uint32 h[8], t[2], f[2];
- enum { BLAKE_DATA_SIZE = 48 + 2 * BLAKE2S_BLOCKBYTES };
+ // 2 * BLAKE2S_BLOCKBYTES is the buf size in blake2_code_20140114.zip.
+ // It might differ in later versions.
+ static constexpr size_t BLAKE_DATA_SIZE = 48 + 2 * BLAKE2S_BLOCKBYTES;
byte ubuf[BLAKE_DATA_SIZE + BLAKE_ALIGNMENT];
diff -ur unrar-6.1.7/cmddata.cpp unrar-6.2.7/cmddata.cpp
--- unrar-6.1.7/cmddata.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/cmddata.cpp 2023-05-14 13:10:34
@@ -26,9 +26,10 @@
FileArgs.Reset();
ExclArgs.Reset();
InclArgs.Reset();
- StoreArgs.Reset();
ArcNames.Reset();
- NextVolSizes.Reset();
+ StoreArgs.Reset();
+ Password.Clean();
+ NextVolSizes.clear();
}
@@ -314,6 +315,21 @@
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 @@
else
if (!Password.IsSet())
{
- uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password);
+ uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password,NULL);
eprintf(L"\n");
}
break;
@@ -685,7 +701,7 @@
case 'P':
if (Switch[1]==0)
{
- uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password);
+ uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password,NULL);
eprintf(L"\n");
}
else
diff -ur unrar-6.1.7/cmddata.hpp unrar-6.2.7/cmddata.hpp
--- unrar-6.1.7/cmddata.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/cmddata.hpp 2023-05-14 13:10:34
@@ -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 @@
StringList InclArgs;
StringList ArcNames;
StringList StoreArgs;
+
+ SecPassword Password;
+
+ std::vector NextVolSizes;
};
#endif
diff -ur unrar-6.1.7/cmdfilter.cpp unrar-6.2.7/cmdfilter.cpp
--- unrar-6.1.7/cmdfilter.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/cmdfilter.cpp 2023-05-14 13:10:34
@@ -289,8 +289,8 @@
return 0;
if ((FileHead.FileAttr & ExclFileAttr)!=0 || FileHead.Dir && ExclDir)
return 0;
- if (InclAttrSet && (!FileHead.Dir && (FileHead.FileAttr & InclFileAttr)==0 ||
- FileHead.Dir && !InclDir))
+ if (InclAttrSet && (FileHead.FileAttr & InclFileAttr)==0 &&
+ (!FileHead.Dir || !InclDir))
return 0;
if (!Dir && SizeCheck(FileHead.UnpSize))
return 0;
diff -ur unrar-6.1.7/cmdmix.cpp unrar-6.2.7/cmdmix.cpp
--- unrar-6.1.7/cmdmix.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/cmdmix.cpp 2023-05-14 13:10:34
@@ -92,6 +92,13 @@
if (Found)
continue;
#endif
+#ifdef _UNIX
+ if (CmpMSGID(Help[I],MRARTitle2))
+ {
+ mprintf(St(MFwrSlTitle2));
+ continue;
+ }
+#endif
#if !defined(_UNIX) && !defined(_WIN_ALL)
if (CmpMSGID(Help[I],MCHelpSwOW))
continue;
diff -ur unrar-6.1.7/compress.hpp unrar-6.2.7/compress.hpp
--- unrar-6.1.7/compress.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/compress.hpp 2023-05-14 13:10:34
@@ -17,6 +17,7 @@
static const uint MAX_INC_LZ_MATCH = MAX_LZ_MATCH + 3;
static const uint MAX3_LZ_MATCH = 0x101; // Maximum match length for RAR v3.
+ static const uint MAX3_INC_LZ_MATCH = MAX3_LZ_MATCH + 3;
static const uint LOW_DIST_REP_COUNT = 16;
static const uint NC = 306; /* alphabet = {0, 1, 2, ..., NC - 1} */
diff -ur unrar-6.1.7/crc.cpp unrar-6.2.7/crc.cpp
--- unrar-6.1.7/crc.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/crc.cpp 2023-05-14 13:10:34
@@ -110,3 +110,164 @@
#endif
+#if 0
+static uint64 crc64_tables[8][256]; // Tables for Slicing-by-8 for CRC64.
+
+void InitCRC64(uint64 *CRCTab)
+{
+ const uint64 poly=INT32TO64(0xC96C5795, 0xD7870F42); // 0xC96C5795D7870F42;
+ for (uint I=0;I<256;I++)
+ {
+ uint64 C=I;
+ for (uint J=0;J<8;J++)
+ C=(C & 1) ? (C>>1)^poly: (C>>1);
+ CRCTab[I]=C;
+ }
+}
+
+
+static void InitTables64()
+{
+ InitCRC64(crc64_tables[0]);
+
+ for (uint I=0;I<256;I++) // Build additional lookup tables.
+ {
+ uint64 C=crc64_tables[0][I];
+ for (uint J=1;J<8;J++)
+ {
+ C=crc64_tables[0][(byte)C]^(C>>8);
+ crc64_tables[J][I]=C;
+ }
+ }
+}
+
+
+// We cannot place the intialization to CRC64(), because we use this function
+// in multithreaded mode and it conflicts with multithreading.
+struct CallInitCRC64 {CallInitCRC64() {InitTables64();}} static CallInit64;
+
+uint64 CRC64(uint64 StartCRC,const void *Addr,size_t Size)
+{
+ byte *Data=(byte *)Addr;
+
+ // Align Data to 8 for better performance.
+ for (;Size>0 && ((size_t)Data & 7)!=0;Size--,Data++)
+ StartCRC=crc64_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);
+
+ for (byte *DataEnd=Data+Size/8*8; Data> 8 ) ] ^
+ crc64_tables[ 5 ] [ ( byte ) (Index >> 16 ) ] ^
+ crc64_tables[ 4 ] [ ( byte ) (Index >> 24 ) ] ^
+ crc64_tables[ 3 ] [ ( byte ) (Index >> 32 ) ] ^
+ crc64_tables[ 2 ] [ ( byte ) (Index >> 40 ) ] ^
+ crc64_tables[ 1 ] [ ( byte ) (Index >> 48 ) ] ^
+ crc64_tables[ 0 ] [ ( byte ) (Index >> 56 ) ] ;
+ }
+
+ for (Size%=8;Size>0;Size--,Data++) // Process left data.
+ StartCRC=crc64_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);
+
+ return StartCRC;
+}
+
+
+#if 0
+static void TestCRC();
+struct TestCRCStruct {TestCRCStruct() {TestCRC();exit(0);}} GlobalTesCRC;
+
+void TestCRC()
+{
+ const uint FirstSize=300;
+ byte b[FirstSize];
+
+ if ((CRC32(0xffffffff,(byte*)"testtesttest",12)^0xffffffff)==0x44608e84)
+ mprintf(L"\nCRC32 test1 OK");
+ else
+ mprintf(L"\nCRC32 test1 FAILED");
+
+ if (CRC32(0,(byte*)"te\x80st",5)==0xB2E5C5AE)
+ mprintf(L"\nCRC32 test2 OK");
+ else
+ mprintf(L"\nCRC32 test2 FAILED");
+
+ for (uint I=0;I<14;I++) // Check for possible int sign extension.
+ b[I]=(byte)0x7f+I;
+ if ((CRC32(0xffffffff,b,14)^0xffffffff)==0x1DFA75DA)
+ mprintf(L"\nCRC32 test3 OK");
+ else
+ mprintf(L"\nCRC32 test3 FAILED");
+
+ for (uint I=0;IIsSet() || Method==CRYPT_NONE)
+ if (Method==CRYPT_NONE || !Password->IsSet())
return false;
CryptData::Method=Method;
wchar PwdW[MAXPASSWORD];
Password->Get(PwdW,ASIZE(PwdW));
+ PwdW[Min(MAXPASSWORD_RAR,MAXPASSWORD)-1]=0; // For compatibility with existing archives.
+
char PwdA[MAXPASSWORD];
WideToChar(PwdW,PwdA,ASIZE(PwdA));
+ PwdA[Min(MAXPASSWORD_RAR,MAXPASSWORD)-1]=0; // For compatibility with existing archives.
switch(Method)
{
diff -ur unrar-6.1.7/crypt.hpp unrar-6.2.7/crypt.hpp
--- unrar-6.1.7/crypt.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/crypt.hpp 2023-05-14 13:10:34
@@ -30,6 +30,18 @@
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 @@
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 @@
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);
@@ -86,6 +108,54 @@
void EncryptBlock(byte *Buf,size_t Size);
void DecryptBlock(byte *Buf,size_t Size);
static void SetSalt(byte *Salt,size_t SaltSize);
+};
+
+
+class CheckPassword
+{
+ public:
+ enum CONFIDENCE {CONFIDENCE_HIGH,CONFIDENCE_MEDIUM,CONFIDENCE_LOW};
+ virtual CONFIDENCE GetConfidence()=0;
+ virtual bool Check(SecPassword *Password)=0;
+};
+
+class RarCheckPassword:public CheckPassword
+{
+ private:
+ CryptData *Crypt;
+ uint Lg2Count;
+ byte Salt[SIZE_SALT50];
+ byte InitV[SIZE_INITV];
+ byte PswCheck[SIZE_PSWCHECK];
+ public:
+ RarCheckPassword()
+ {
+ Crypt=NULL;
+ }
+ ~RarCheckPassword()
+ {
+ delete Crypt;
+ }
+ void Set(byte *Salt,byte *InitV,uint Lg2Count,byte *PswCheck)
+ {
+ if (Crypt==NULL)
+ Crypt=new CryptData;
+ memcpy(this->Salt,Salt,sizeof(this->Salt));
+ memcpy(this->InitV,InitV,sizeof(this->InitV));
+ this->Lg2Count=Lg2Count;
+ memcpy(this->PswCheck,PswCheck,sizeof(this->PswCheck));
+ }
+ bool IsSet() {return Crypt!=NULL;}
+
+ // RAR5 provides the higly reliable 64 bit password verification value.
+ CONFIDENCE GetConfidence() {return CONFIDENCE_HIGH;}
+
+ bool Check(SecPassword *Password)
+ {
+ byte PswCheck[SIZE_PSWCHECK];
+ Crypt->SetCryptKeys(false,CRYPT_RAR50,Password,Salt,InitV,Lg2Count,NULL,PswCheck);
+ return memcmp(PswCheck,this->PswCheck,sizeof(this->PswCheck))==0;
+ }
};
void GetRnd(byte *RndBuf,size_t BufSize);
diff -ur unrar-6.1.7/crypt3.cpp unrar-6.2.7/crypt3.cpp
--- unrar-6.1.7/crypt3.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/crypt3.cpp 2023-05-14 13:10:34
@@ -18,8 +18,9 @@
if (!Cached)
{
byte RawPsw[2*MAXPASSWORD+SIZE_SALT30];
- WideToRaw(PwdW,RawPsw,ASIZE(RawPsw));
- size_t RawLength=2*wcslen(PwdW);
+ size_t PswLength=wcslen(PwdW);
+ size_t RawLength=2*PswLength;
+ WideToRaw(PwdW,PswLength,RawPsw,RawLength);
if (Salt!=NULL)
{
memcpy(RawPsw+RawLength,Salt,SIZE_SALT30);
diff -ur unrar-6.1.7/crypt5.cpp unrar-6.2.7/crypt5.cpp
--- unrar-6.1.7/crypt5.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/crypt5.cpp 2023-05-14 13:10:34
@@ -21,7 +21,7 @@
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 @@
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 @@
for (uint I=0;ILg2Count==Lg2Cnt && Item->Pwd==*Password &&
+ if (Item->Pwd==*Password && Item->Lg2Count==Lg2Cnt &&
memcmp(Item->Salt,Salt,SIZE_SALT50)==0)
{
memcpy(Key,Item->Key,sizeof(Key));
diff -ur unrar-6.1.7/dll.rc unrar-6.2.7/dll.rc
--- unrar-6.1.7/dll.rc 2022-10-19 22:05:12
+++ unrar-6.2.7/dll.rc 2023-05-14 13:04:53
@@ -2,8 +2,8 @@
#include
VS_VERSION_INFO VERSIONINFO
-FILEVERSION 6, 12, 100, 489
-PRODUCTVERSION 6, 12, 100, 489
+FILEVERSION 6, 22, 1, 865
+PRODUCTVERSION 6, 22, 1, 865
FILEOS VOS__WINDOWS32
FILETYPE VFT_APP
{
@@ -14,9 +14,9 @@
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.22.1\0"
+ VALUE "ProductVersion", "6.22.1\0"
+ VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2023\0"
VALUE "OriginalFilename", "Unrar.dll\0"
}
}
diff -ur unrar-6.1.7/errhnd.cpp unrar-6.2.7/errhnd.cpp
--- unrar-6.1.7/errhnd.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/errhnd.cpp 2023-05-14 13:10:34
@@ -169,10 +169,13 @@
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();
}
diff -ur unrar-6.1.7/extinfo.cpp unrar-6.2.7/extinfo.cpp
--- unrar-6.1.7/extinfo.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/extinfo.cpp 2023-05-14 13:10:34
@@ -112,6 +112,68 @@
}
+// Delete symbolic links in file path, if any, and replace them by directories.
+// Prevents extracting files outside of destination folder with symlink chains.
+bool LinksToDirs(const wchar *SrcName,const wchar *SkipPart,std::wstring &LastChecked)
+{
+ // Unlike Unix, Windows doesn't expand lnk1 in symlink targets like
+ // "lnk1/../dir", but converts the path to "dir". In Unix we need to call
+ // this function to prevent placing unpacked files outside of destination
+ // folder if previously we unpacked "dir/lnk1" -> "..",
+ // "dir/lnk2" -> "lnk1/.." and "dir/lnk2/anypath/poc.txt".
+ // We may still need this function to prevent abusing symlink chains
+ // in link source path if we remove detection of such chains
+ // in IsRelativeSymlinkSafe. This function seems to make other symlink
+ // related safety checks redundant, but for now we prefer to keep them too.
+ //
+ // 2022.12.01: the performance impact is minimized after adding the check
+ // against the previous path and enabling this verification only after
+ // extracting a symlink with ".." in target. So we enabled it for Windows
+ // as well for extra safety.
+//#ifdef _UNIX
+ wchar Path[NM];
+ if (wcslen(SrcName)>=ASIZE(Path))
+ return false; // It should not be that long, skip.
+ wcsncpyz(Path,SrcName,ASIZE(Path));
+
+ size_t SkipLength=wcslen(SkipPart);
+
+ if (SkipLength>0 && wcsncmp(Path,SkipPart,SkipLength)!=0)
+ SkipLength=0; // Parameter validation, not really needed now.
+
+ // Do not check parts already checked in previous path to improve performance.
+ for (uint I=0;Path[I]!=0 && ISkipLength)
+ SkipLength=I;
+
+ wchar *Name=Path;
+ if (SkipLength>0)
+ {
+ // Avoid converting symlinks in destination path part specified by user.
+ Name+=SkipLength;
+ while (IsPathDiv(*Name))
+ Name++;
+ }
+
+ for (wchar *s=Path+wcslen(Path)-1;s>Name;s--)
+ if (IsPathDiv(*s))
+ {
+ *s=0;
+ FindData FD;
+ if (FindFile::FastFind(Path,&FD,true) && FD.IsLink)
+#ifdef _WIN_ALL
+ if (!DelDir(Path))
+#else
+ if (!DelFile(Path))
+#endif
+ return false; // Couldn't delete the symlink to replace it with directory.
+ }
+ LastChecked=SrcName;
+//#endif
+ return true;
+}
+
+
bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName)
{
// Catch root dir based /path/file paths also as stuff like \\?\.
@@ -131,10 +193,14 @@
UpLevels++;
TargetName++;
}
- // If link target includes "..", it must not have another links
- // in the path, because they can bypass our safety check. For example,
+ // If link target includes "..", it must not have another links in its
+ // source path, because they can bypass our safety check. For example,
// suppose we extracted "lnk1" -> "." first and "lnk1/lnk2" -> ".." next
- // or "dir/lnk1" -> ".." first and "dir/lnk1/lnk2" -> ".." next.
+ // or "dir/lnk1" -> ".." first, "dir/lnk1/lnk2" -> ".." next and
+ // file "dir/lnk1/lnk2/poc.txt" last.
+ // Do not confuse with link chains in target, this is in link source path.
+ // It is important for Windows too, though this check can be omitted
+ // if LinksToDirs is invoked in Windows as well.
if (UpLevels>0 && LinkInPath(PrepSrcName))
return false;
@@ -160,15 +226,26 @@
}
-bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName)
+bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName,bool &UpLink)
{
+ // Returning true in Uplink indicates that link target might include ".."
+ // and enables additional checks. It is ok to falsely return true here,
+ // as it implies only the minor performance penalty. But we shall always
+ // return true for links with ".." in target for security reason.
+
+ UpLink=true; // Assume the target might include potentially unsafe "..".
+#if defined(SAVE_LINKS) && defined(_UNIX) || defined(_WIN_ALL)
+ if (Arc.Format==RARFMT50) // For RAR5 archives we can check RedirName for both Unix and Windows.
+ UpLink=wcsstr(Arc.FileHead.RedirName,L"..")!=NULL;
+#endif
+
#if defined(SAVE_LINKS) && defined(_UNIX)
// For RAR 3.x archives we process links even in test mode to skip link data.
if (Arc.Format==RARFMT15)
- return ExtractUnixLink30(Cmd,DataIO,Arc,LinkName);
+ return ExtractUnixLink30(Cmd,DataIO,Arc,LinkName,UpLink);
if (Arc.Format==RARFMT50)
return ExtractUnixLink50(Cmd,LinkName,&Arc.FileHead);
-#elif defined _WIN_ALL
+#elif defined(_WIN_ALL)
// RAR 5.0 archives store link information in file header, so there is
// no need to additionally test it if we do not create a file.
if (Arc.Format==RARFMT50)
diff -ur unrar-6.1.7/extinfo.hpp unrar-6.2.7/extinfo.hpp
--- unrar-6.1.7/extinfo.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/extinfo.hpp 2023-05-14 13:10:34
@@ -1,8 +1,9 @@
#ifndef _RAR_EXTINFO_
#define _RAR_EXTINFO_
+bool LinksToDirs(const wchar *SrcName,const wchar *SkipPart,std::wstring &LastChecked);
bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName);
-bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName);
+bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName,bool &UpLink);
#ifdef _UNIX
void SetUnixOwner(Archive &Arc,const wchar *FileName);
#endif
diff -ur unrar-6.1.7/extract.cpp unrar-6.2.7/extract.cpp
--- unrar-6.1.7/extract.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/extract.cpp 2023-05-14 13:10:34
@@ -5,10 +5,30 @@
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,10 +38,29 @@
CmdExtract::~CmdExtract()
{
+ FreeAnalyzeData();
delete Unp;
+ delete Analyze;
}
+void CmdExtract::FreeAnalyzeData()
+{
+ for (size_t I=0;ICommand[0]);
- FindData FD;
- while (Cmd->GetArcName(ArcName,ASIZE(ArcName)))
- if (FindFile::FastFind(ArcName,&FD))
- DataIO.TotalArcSize+=FD.Size;
+ if (*Cmd->UseStdin==0)
+ {
+ FindData FD;
+ while (Cmd->GetArcName(ArcName,ASIZE(ArcName)))
+ if (FindFile::FastFind(ArcName,&FD))
+ DataIO.TotalArcSize+=FD.Size;
+ }
Cmd->ArcNames.Rewind();
while (Cmd->GetArcName(ArcName,ASIZE(ArcName)))
@@ -97,7 +139,11 @@
AllMatchesExact=true;
AnySolidDataUnpackedWell=false;
+ ArcAnalyzed=false;
+
StartTime.SetCurrentTime();
+
+ LastCheckedSymlink.clear();
}
@@ -168,20 +214,33 @@
}
#endif
+ Arc.ViewComment(); // Must be before possible EXTRACT_ARC_REPEAT.
+
int64 VolumeSetSize=0; // Total size of volumes after the current volume.
+#ifndef SFX_MODULE
+ if (!ArcAnalyzed && *Cmd->UseStdin==0)
+ {
+ AnalyzeArchive(Arc.FileName,Arc.Volume,Arc.NewNumbering);
+ ArcAnalyzed=true; // Avoid repeated analysis on EXTRACT_ARC_REPEAT.
+ }
+#endif
+
if (Arc.Volume)
{
#ifndef SFX_MODULE
// Try to speed up extraction for independent solid volumes by starting
// extraction from non-first volume if we can.
- if (!UseExactVolName && Arc.Solid && DetectStartVolume(Arc.FileName,Arc.NewNumbering))
+ if (*Analyze->StartName!=0)
{
+ wcsncpyz(ArcName,Analyze->StartName,ASIZE(ArcName));
+ *Analyze->StartName=0;
+
UseExactVolName=true;
return EXTRACT_ARC_REPEAT;
}
#endif
-
+
// Calculate the total size of all accessible volumes.
// This size is necessary to display the correct total progress indicator.
@@ -216,7 +275,13 @@
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,8 +337,15 @@
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)
SetExtraInfo20(Cmd,Arc,DestFileName);
@@ -315,6 +387,9 @@
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 @@
FirstFile=false;
#endif
+ bool RefTarget=false;
+ if (!MatchFound)
+ for (size_t I=0;ITest) // While harmless, it is useless for 't'.
+ {
+ // If reference source isn't selected, but target is selected,
+ // we unpack the source under the temporary name and then rename
+ // or copy it to target name. We do not unpack it under the target
+ // name immediately, because the same source can be used by multiple
+ // targets and it is possible that first target isn't unpacked
+ // for some reason. Also targets might have associated service blocks
+ // like ACLs. All this would complicate processing a lot.
+ wcsncpyz(DestFileName,*Cmd->TempPath!=0 ? Cmd->TempPath:Cmd->ExtrPath,ASIZE(DestFileName));
+ AddEndSlash(DestFileName,ASIZE(DestFileName));
+ wcsncatz(DestFileName,L"__tmp_reference_source_",ASIZE(DestFileName));
+ MkTemp(DestFileName,ASIZE(DestFileName));
+ MatchedRef->TmpName=wcsdup(DestFileName);
+ }
+ RefTarget=true; // Need it even for 't' to test the reference source.
+ break;
+ }
+
if (Arc.FileHead.Encrypted && Cmd->SkipEncrypted)
if (Arc.Solid)
return false; // Abort the entire extraction for solid archive.
else
MatchFound=false; // Skip only the current file for non-solid archive.
- if (MatchFound || (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,7 +528,8 @@
if (!uiStartFileExtract(ArcFileName,!Cmd->Test,Cmd->Test && Command!='I',SkipSolid))
return false;
- ExtrPrepareName(Arc,ArcFileName,DestFileName,ASIZE(DestFileName));
+ if (!RefTarget)
+ ExtrPrepareName(Arc,ArcFileName,DestFileName,ASIZE(DestFileName));
// DestFileName can be set empty in case of excessive -ap switch.
ExtrFile=!SkipSolid && *DestFileName!=0 && !Arc.FileHead.SplitBefore;
@@ -464,9 +566,13 @@
return !Arc.Solid; // Can try extracting next file only in non-solid archive.
}
- while (true) // Repeat the password prompt for wrong and empty passwords.
+ if (Arc.FileHead.Encrypted)
{
- if (Arc.FileHead.Encrypted)
+ RarCheckPassword CheckPwd;
+ if (Arc.Format==RARFMT50 && Arc.FileHead.UsePswCheck && !Arc.BrokenHeader)
+ CheckPwd.Set(Arc.FileHead.Salt,Arc.FileHead.InitV,Arc.FileHead.Lg2Count,Arc.FileHead.PswCheck);
+
+ while (true) // Repeat the password prompt for wrong and empty passwords.
{
// Stop archive extracting if user cancelled a password prompt.
#ifdef RARDLL
@@ -476,77 +582,83 @@
return false;
}
#else
- if (!ExtrGetPassword(Arc,ArcFileName))
+ if (!ExtrGetPassword(Arc,ArcFileName,CheckPwd.IsSet() ? &CheckPwd:NULL))
{
PasswordCancelled=true;
return false;
}
#endif
- }
- // Set a password before creating the file, so we can skip creating
- // in case of wrong password.
- SecPassword FilePassword=Cmd->Password;
-#if defined(_WIN_ALL) && !defined(SFX_MODULE)
- ConvertDosPassword(Arc,FilePassword);
-#endif
+ // Set a password before creating the file, so we can skip creating
+ // in case of wrong password.
+ SecPassword FilePassword=Cmd->Password;
+ #if defined(_WIN_ALL) && !defined(SFX_MODULE)
+ ConvertDosPassword(Arc,FilePassword);
+ #endif
- byte PswCheck[SIZE_PSWCHECK];
- DataIO.SetEncryption(false,Arc.FileHead.CryptMethod,&FilePassword,
- Arc.FileHead.SaltSet ? Arc.FileHead.Salt:NULL,
- Arc.FileHead.InitV,Arc.FileHead.Lg2Count,
- Arc.FileHead.HashKey,PswCheck);
+ byte PswCheck[SIZE_PSWCHECK];
+ DataIO.SetEncryption(false,Arc.FileHead.CryptMethod,&FilePassword,
+ Arc.FileHead.SaltSet ? Arc.FileHead.Salt:NULL,
+ Arc.FileHead.InitV,Arc.FileHead.Lg2Count,
+ Arc.FileHead.HashKey,PswCheck);
- // If header is damaged, we cannot rely on password check value,
- // because it can be damaged too.
- if (Arc.FileHead.Encrypted && Arc.FileHead.UsePswCheck &&
- memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0 &&
- !Arc.BrokenHeader)
- {
- if (GlobalPassword) // For -p or Ctrl+P to avoid the infinite loop.
+ // If header is damaged, we cannot rely on password check value,
+ // because it can be damaged too.
+ if (Arc.FileHead.UsePswCheck && !Arc.BrokenHeader &&
+ memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0)
{
- // This message is used by Android GUI to reset cached passwords.
- // Update appropriate code if changed.
- uiMsg(UIERROR_BADPSW,Arc.FileName,ArcFileName);
- }
- else // For passwords entered manually.
- {
- // This message is used by Android GUI and Windows GUI and SFX to
- // reset cached passwords. Update appropriate code if changed.
- uiMsg(UIWAIT_BADPSW,Arc.FileName,ArcFileName);
- Cmd->Password.Clean();
+ if (GlobalPassword) // For -p or Ctrl+P to avoid the infinite loop.
+ {
+ // This message is used by Android GUI to reset cached passwords.
+ // Update appropriate code if changed.
+ uiMsg(UIERROR_BADPSW,Arc.FileName,ArcFileName);
+ }
+ else // For passwords entered manually.
+ {
+ // This message is used by Android GUI and Windows GUI and SFX to
+ // reset cached passwords. Update appropriate code if changed.
+ uiMsg(UIWAIT_BADPSW,Arc.FileName,ArcFileName);
+ Cmd->Password.Clean();
- // Avoid new requests for unrar.dll to prevent the infinite loop
- // if app always returns the same password.
-#ifndef RARDLL
- continue; // Request a password again.
-#endif
+ // Avoid new requests for unrar.dll to prevent the infinite loop
+ // if app always returns the same password.
+ #ifndef RARDLL
+ continue; // Request a password again.
+ #endif
+ }
+ #ifdef RARDLL
+ // If we already have ERAR_EOPEN as result of missing volume,
+ // we should not replace it with less precise ERAR_BAD_PASSWORD.
+ if (Cmd->DllError!=ERAR_EOPEN)
+ Cmd->DllError=ERAR_BAD_PASSWORD;
+ #endif
+ ErrHandler.SetErrorCode(RARX_BADPWD);
+ ExtrFile=false;
}
-#ifdef RARDLL
- // If we already have ERAR_EOPEN as result of missing volume,
- // we should not replace it with less precise ERAR_BAD_PASSWORD.
- if (Cmd->DllError!=ERAR_EOPEN)
- Cmd->DllError=ERAR_BAD_PASSWORD;
-#endif
- ErrHandler.SetErrorCode(RARX_BADPWD);
- ExtrFile=false;
+ break;
}
- break;
}
+ else
+ DataIO.SetEncryption(false,CRYPT_NONE,NULL,NULL,NULL,0,NULL,NULL);
#ifdef RARDLL
if (*Cmd->DllDestName!=0)
wcsncpyz(DestFileName,Cmd->DllDestName,ASIZE(DestFileName));
#endif
+ if (ExtrFile && Command!='P' && !Cmd->Test && !Cmd->AbsoluteLinks &&
+ ConvertSymlinkPaths)
+ ExtrFile=LinksToDirs(DestFileName,Cmd->ExtrPath,LastCheckedSymlink);
+
File CurFile;
bool LinkEntry=Arc.FileHead.RedirType!=FSREDIR_NONE;
- if (LinkEntry && Arc.FileHead.RedirType!=FSREDIR_FILECOPY)
+ if (LinkEntry && (Arc.FileHead.RedirType!=FSREDIR_FILECOPY))
{
if (ExtrFile && Command!='P' && !Cmd->Test)
{
- // Overwrite prompt for symbolic and hard links.
+ // Overwrite prompt for symbolic and hard links and when we move
+ // a temporary file to the file reference instead of copying it.
bool UserReject=false;
if (FileExist(DestFileName) && !UserReject)
FileCreate(Cmd,NULL,DestFileName,ASIZE(DestFileName),&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime);
@@ -667,25 +779,50 @@
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));
if (FileCreateMode && *NameExisting!=0) // *NameExisting can be 0 in case of excessive -ap switch.
if (Type==FSREDIR_HARDLINK)
LinkSuccess=ExtractHardlink(Cmd,DestFileName,NameExisting,ASIZE(NameExisting));
else
- LinkSuccess=ExtractFileCopy(CurFile,Arc.FileName,DestFileName,NameExisting,ASIZE(NameExisting));
+ LinkSuccess=ExtractFileCopy(CurFile,Arc.FileName,RedirName,DestFileName,NameExisting,ASIZE(NameExisting),Arc.FileHead.UnpSize);
}
else
if (Type==FSREDIR_UNIXSYMLINK || Type==FSREDIR_WINSYMLINK || Type==FSREDIR_JUNCTION)
{
if (FileCreateMode)
- LinkSuccess=ExtractSymlink(Cmd,DataIO,Arc,DestFileName);
+ {
+ bool UpLink;
+ LinkSuccess=ExtractSymlink(Cmd,DataIO,Arc,DestFileName,UpLink);
+ ConvertSymlinkPaths|=LinkSuccess && UpLink;
+
+ // We do not actually need to reset the cache here if we cache
+ // only the single last checked path, because at this point
+ // it will always contain the link own path and link can't
+ // overwrite its parent folder. But if we ever decide to cache
+ // several already checked paths, we'll need to reset them here.
+ // Otherwise if no files were created in one of such paths,
+ // let's say because of file create error, it might be possible
+ // to overwrite the path with link and avoid checks. We keep this
+ // code here as a reminder in case of possible modifications.
+ LastCheckedSymlink.clear(); // Reset cache for safety reason.
+ }
}
else
{
- uiMsg(UIERROR_UNKNOWNEXTRA,Arc.FileName,DestFileName);
+ uiMsg(UIERROR_UNKNOWNEXTRA,Arc.FileName,ArcFileName);
LinkSuccess=false;
}
@@ -709,6 +846,7 @@
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,22 +1004,64 @@
}
-bool CmdExtract::ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize)
+bool CmdExtract::ExtractFileCopy(File &New,wchar *ArcName,const wchar *RedirName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize,int64 UnpSize)
{
- SlashToNative(NameExisting,NameExisting,NameExistingSize); // Not needed for RAR 5.1+ archives.
-
File Existing;
- if (!Existing.WOpen(NameExisting))
+ if (!Existing.Open(NameExisting))
{
- uiMsg(UIERROR_FILECOPY,ArcName,NameExisting,NameNew);
- uiMsg(UIERROR_FILECOPYHINT,ArcName);
+ bool OpenFailed=true;
+ // If we couldn't find the existing file, check if match is present
+ // in temporary reference sources list.
+ for (size_t I=0;IDllError=ERAR_EREFERENCE;
+ Cmd->DllError=ERAR_EREFERENCE;
#endif
- return false;
+ return false;
+ }
}
- Array Buffer(0x100000);
+ Array Buffer(0x100000);
int64 CopySize=0;
while (true)
@@ -890,6 +1070,10 @@
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 +1084,16 @@
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 +1227,11 @@
#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 +1249,7 @@
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 +1325,8 @@
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 +1408,8 @@
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 +1456,59 @@
#ifndef SFX_MODULE
-// To speed up solid volumes extraction, try to find a non-first start volume,
-// which still allows to unpack all files. It is possible for independent
-// solid volumes with solid statistics reset in the beginning.
-bool CmdExtract::DetectStartVolume(const wchar *VolName,bool NewNumbering)
+// Find non-matched reference sources in solid and non-solid archives.
+// Detect the optimal start position for semi-solid archives
+// and optimal start volume for independent solid volumes.
+//
+// Alternatively we could collect references while extracting an archive
+// and perform the second extraction pass for references only.
+// But it would be slower for solid archives than scaning headers
+// in first pass and extracting everything in second, as implemented now.
+//
+void CmdExtract::AnalyzeArchive(const wchar *ArcName,bool Volume,bool NewNumbering)
{
+ FreeAnalyzeData(); // If processing non-first archive in multiple archives set.
+
wchar *ArgName=Cmd->FileArgs.GetString();
Cmd->FileArgs.Rewind();
if (ArgName!=NULL && (wcscmp(ArgName,L"*")==0 || wcscmp(ArgName,L"*.*")==0))
- return false; // No need to check further for * and *.* masks.
+ return; // No need to check further for * and *.* masks.
- wchar StartName[NM];
- *StartName=0;
-
// Start search from first volume if all volumes preceding current are available.
wchar NextName[NM];
- GetFirstVolIfFullSet(VolName,NewNumbering,NextName,ASIZE(NextName));
+ if (Volume)
+ GetFirstVolIfFullSet(ArcName,NewNumbering,NextName,ASIZE(NextName));
+ else
+ wcsncpyz(NextName,ArcName,ASIZE(NextName));
+
+ bool MatchFound=false;
+ bool PrevMatched=false;
+ bool OpenNext=false;
- bool Matched=false;
- while (!Matched)
+ 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 +1521,88 @@
}
if (HeaderType==HEAD_FILE)
{
+ if ((Arc.Format==RARFMT14 || Arc.Format==RARFMT15) && Arc.FileHead.UnpVer<=15)
+ {
+ // RAR versions earlier than 2.0 do not set per file solid flag.
+ // They have only the global archive solid flag, so we can't
+ // reliably analyze them here.
+ OpenNext=false;
+ break;
+ }
+
if (!Arc.FileHead.SplitBefore)
{
- if (!Arc.FileHead.Solid) // Can start extraction from here.
- wcsncpyz(StartName,NextName,ASIZE(StartName));
+ if (!MatchFound && !Arc.FileHead.Solid) // Can start extraction from here.
+ {
+ // We would gain nothing and unnecessarily complicate extraction
+ // if we set StartName for first volume or StartPos for first
+ // archived file.
+ if (!FirstVolume)
+ wcsncpyz(Analyze->StartName,NextName,ASIZE(Analyze->StartName));
+ // We shall set FirstFile once for all volumes for this code
+ // to work properly. Alternatively we could append
+ // "|| Analyze->StartPos!=0" to the condition, so we do not reuse
+ // the outdated Analyze->StartPos value from previous volume.
+ if (!FirstFile)
+ Analyze->StartPos=Arc.CurBlockPos;
+ }
+
if (Cmd->IsProcessFile(Arc.FileHead,NULL,MATCH_WILDSUBPATH,0,NULL,0)!=0)
{
- Matched=true; // First matched file found, must stop further scan.
- break;
+ MatchFound = true;
+ PrevMatched = true;
+
+ // Reset the previously set early exit position, if any, because
+ // we found a new matched file.
+ Analyze->EndPos=0;
+
+ // Matched file reference pointing at maybe non-matched source file.
+ // Even though we know RedirName, we can't check if source file
+ // is certainly non-matched, because it can be filtered out by
+ // date or attributes, which we do not know here.
+ if (Arc.FileHead.RedirType==FSREDIR_FILECOPY)
+ {
+ bool AlreadyAdded=false;
+ for (size_t I=0;IEndName,NextName,ASIZE(Analyze->EndName));
+ Analyze->EndPos=Arc.CurBlockPos;
+ }
+ PrevMatched=false;
+ }
}
+
+ FirstFile=false;
if (Arc.FileHead.SplitAfter)
{
OpenNext=true; // Allow open next volume.
@@ -1316,16 +1613,25 @@
}
Arc.Close();
- if (!OpenNext)
- break;
+ if (Volume && OpenNext)
+ {
+ NextVolumeName(NextName,ASIZE(NextName),!Arc.NewNumbering);
+ FirstVolume=false;
- NextVolumeName(NextName,ASIZE(NextName),!Arc.NewNumbering);
+ // Needed for multivolume archives. Added in case some 'break'
+ // will quit early from loop above, so we do not set it in the loop.
+ // Now it can happen for hypothetical archive without file records
+ // and with HEAD_ENDARC record.
+ FirstFile=false;
+ }
+ else
+ break;
}
- bool NewStartFound=wcscmp(VolName,StartName)!=0;
- if (NewStartFound) // Found a new volume to start extraction.
- wcsncpyz(ArcName,StartName,ASIZE(ArcName));
-
- return NewStartFound;
+
+ // If file references are present, we can't reliably skip in semi-solid
+ // archives, because reference source can be present in skipped data.
+ if (RefList.Size()!=0)
+ memset(Analyze,0,sizeof(*Analyze));
}
#endif
diff -ur unrar-6.1.7/extract.hpp unrar-6.2.7/extract.hpp
--- unrar-6.1.7/extract.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/extract.hpp 2023-05-14 13:10:34
@@ -6,13 +6,32 @@
class CmdExtract
{
private:
+ struct ExtractRef
+ {
+ wchar *RefName;
+ wchar *TmpName;
+ uint64 RefCount;
+ };
+ Array RefList;
+
+ struct AnalyzeData
+ {
+ wchar StartName[NM];
+ uint64 StartPos;
+ wchar EndName[NM];
+ uint64 EndPos;
+ } *Analyze;
+
+ bool ArcAnalyzed;
+
+ void FreeAnalyzeData();
EXTRACT_ARC_CODE ExtractArchive();
- bool ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize);
+ bool ExtractFileCopy(File &New,wchar *ArcName,const wchar *RedirName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize,int64 UnpSize);
void ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize);
#ifdef RARDLL
bool ExtrDllGetPassword();
#else
- bool ExtrGetPassword(Archive &Arc,const wchar *ArcFileName);
+ bool ExtrGetPassword(Archive &Arc,const wchar *ArcFileName,RarCheckPassword *CheckPwd);
#endif
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
void ConvertDosPassword(Archive &Arc,SecPassword &DestPwd);
@@ -21,7 +40,7 @@
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 @@
bool PrevProcessed; // If previous file was successfully extracted or tested.
wchar DestFileName[NM];
bool PasswordCancelled;
+
+ // In Windows it is set to true if at least one symlink with ".."
+ // in target was extracted.
+ bool ConvertSymlinkPaths;
+
+ // Last path checked for symlinks. We use it to improve the performance,
+ // so we do not check recently checked folders again.
+ std::wstring LastCheckedSymlink;
+
#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT)
bool Fat32,NotFat32;
#endif
diff -ur unrar-6.1.7/filcreat.cpp unrar-6.2.7/filcreat.cpp
--- unrar-6.1.7/filcreat.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/filcreat.cpp 2023-05-14 13:10:34
@@ -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)
diff -ur unrar-6.1.7/filcreat.hpp unrar-6.2.7/filcreat.hpp
--- unrar-6.1.7/filcreat.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/filcreat.hpp 2023-05-14 13:10:34
@@ -1,7 +1,7 @@
#ifndef _RAR_FILECREATE_
#define _RAR_FILECREATE_
-bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
+bool FileCreate(CommandData *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
bool *UserReject,int64 FileSize=INT64NDF,
RarTime *FileTime=NULL,bool WriteOnly=false);
diff -ur unrar-6.1.7/file.cpp unrar-6.2.7/file.cpp
--- unrar-6.1.7/file.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/file.cpp 2023-05-14 13:10:34
@@ -522,29 +522,35 @@
{
if (hFile==FILE_BAD_HANDLE)
return true;
- if (!IsSeekable())
+ if (!IsSeekable()) // To extract archives from stdin with -si.
{
- if (Method==SEEK_CUR)
+ // 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)
{
- Offset+=CurFilePos;
- Method=SEEK_SET;
- }
- if (Method==SEEK_SET && Offset>=CurFilePos) // Reading for seek forward.
- {
- uint64 SkipSize=Offset-CurFilePos;
- while (SkipSize>0)
+ uint64 SkipSize=Method==SEEK_CUR ? Offset:Offset-CurFilePos;
+ while (SkipSize>0) // Reading to emulate seek forward.
{
- byte Buf[4096];
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::GetOpenFileTime(RarTime *ft)
+#ifdef _UNIX
+void File::StatToRarTime(struct stat &st,RarTime *ftm,RarTime *ftc,RarTime *fta)
{
-#ifdef _WIN_ALL
- FILETIME FileTime;
- GetFileTime(hFile,NULL,NULL,&FileTime);
- ft->SetWinFT(&FileTime);
+#ifdef UNIX_TIME_NS
+#if defined(_APPLE)
+ if (ftm!=NULL) ftm->SetUnixNS(st.st_mtimespec.tv_sec*(uint64)1000000000+st.st_mtimespec.tv_nsec);
+ if (ftc!=NULL) ftc->SetUnixNS(st.st_ctimespec.tv_sec*(uint64)1000000000+st.st_ctimespec.tv_nsec);
+ if (fta!=NULL) fta->SetUnixNS(st.st_atimespec.tv_sec*(uint64)1000000000+st.st_atimespec.tv_nsec);
+#else
+ if (ftm!=NULL) ftm->SetUnixNS(st.st_mtim.tv_sec*(uint64)1000000000+st.st_mtim.tv_nsec);
+ if (ftc!=NULL) ftc->SetUnixNS(st.st_ctim.tv_sec*(uint64)1000000000+st.st_ctim.tv_nsec);
+ if (fta!=NULL) fta->SetUnixNS(st.st_atim.tv_sec*(uint64)1000000000+st.st_atim.tv_nsec);
#endif
-#if defined(_UNIX) || defined(_EMX)
+#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 ctime,atime,mtime;
+ GetFileTime(hFile,&ctime,&atime,&mtime);
+ if (ftm!=NULL) ftm->SetWinFT(&mtime);
+ if (ftc!=NULL) ftc->SetWinFT(&ctime);
+ if (fta!=NULL) fta->SetWinFT(&atime);
+#elif defined(_UNIX)
struct stat st;
fstat(GetFD(),&st);
- ft->SetUnix(st.st_mtime);
+ StatToRarTime(st,ftm,ftc,fta);
#endif
}
diff -ur unrar-6.1.7/file.hpp unrar-6.2.7/file.hpp
--- unrar-6.1.7/file.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/file.hpp 2023-05-14 13:10:34
@@ -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 @@
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 @@
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;}
diff -ur unrar-6.1.7/filefn.cpp unrar-6.2.7/filefn.cpp
--- unrar-6.1.7/filefn.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/filefn.cpp 2023-05-14 13:10:34
@@ -320,7 +320,6 @@
}
-#if 0
wchar *MkTemp(wchar *Name,size_t MaxSize)
{
size_t Length=wcslen(Name);
@@ -354,7 +353,6 @@
}
return Name;
}
-#endif
#if !defined(SFX_MODULE)
@@ -399,7 +397,7 @@
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
diff -ur unrar-6.1.7/filefn.hpp unrar-6.2.7/filefn.hpp
--- unrar-6.1.7/filefn.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/filefn.hpp 2023-05-14 13:10:34
@@ -27,9 +27,7 @@
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};
diff -ur unrar-6.1.7/find.cpp unrar-6.2.7/find.cpp
--- unrar-6.1.7/find.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/find.cpp 2023-05-14 13:10:34
@@ -117,7 +117,7 @@
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 @@
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
diff -ur unrar-6.1.7/getbits.cpp unrar-6.2.7/getbits.cpp
--- unrar-6.1.7/getbits.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/getbits.cpp 2023-05-14 13:10:34
@@ -5,7 +5,7 @@
ExternalBuffer=false;
if (AllocBuffer)
{
- // getbits32 attempts to read data from InAddr, ... InAddr+3 positions.
+ // getbits*() attempt to read data from InAddr, ... InAddr+3 positions.
// So let's allocate 3 additional bytes for situation, when we need to
// read only 1 byte from the last position of buffer and avoid a crash
// from access to next 3 bytes, which contents we do not need.
diff -ur unrar-6.1.7/getbits.hpp unrar-6.2.7/getbits.hpp
--- unrar-6.1.7/getbits.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/getbits.hpp 2023-05-14 13:10:34
@@ -28,26 +28,38 @@
InAddr+=Bits>>3;
InBit=Bits&7;
}
-
+
// Return 16 bits from current position in the buffer.
// Bit at (InAddr,InBit) has the highest position in returning data.
uint getbits()
{
+#if defined(LITTLE_ENDIAN) && defined(ALLOW_MISALIGNED)
+ uint32 BitField=*(uint32*)(InBuf+InAddr);
+ BitField=ByteSwap32(BitField);
+ BitField >>= (16-InBit);
+#else
uint BitField=(uint)InBuf[InAddr] << 16;
BitField|=(uint)InBuf[InAddr+1] << 8;
BitField|=(uint)InBuf[InAddr+2];
BitField >>= (8-InBit);
+#endif
return BitField & 0xffff;
}
+
// Return 32 bits from current position in the buffer.
// Bit at (InAddr,InBit) has the highest position in returning data.
uint getbits32()
{
+#if defined(LITTLE_ENDIAN) && defined(ALLOW_MISALIGNED)
+ uint32 BitField=*(uint32*)(InBuf+InAddr);
+ BitField=ByteSwap32(BitField);
+#else
uint BitField=(uint)InBuf[InAddr] << 24;
BitField|=(uint)InBuf[InAddr+1] << 16;
BitField|=(uint)InBuf[InAddr+2] << 8;
BitField|=(uint)InBuf[InAddr+3];
+#endif
BitField <<= InBit;
BitField|=(uint)InBuf[InAddr+4] >> (8-InBit);
return BitField & 0xffffffff;
diff -ur unrar-6.1.7/hardlinks.cpp unrar-6.2.7/hardlinks.cpp
--- unrar-6.1.7/hardlinks.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/hardlinks.cpp 2023-05-14 13:10:34
@@ -1,7 +1,5 @@
bool ExtractHardlink(CommandData *Cmd,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize)
{
- SlashToNative(NameExisting,NameExisting,NameExistingSize); // Not needed for RAR 5.1+ archives.
-
if (!FileExist(NameExisting))
{
uiMsg(UIERROR_HLINKCREATE,NameNew);
diff -ur unrar-6.1.7/hash.cpp unrar-6.2.7/hash.cpp
--- unrar-6.1.7/hash.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/hash.cpp 2023-05-14 13:10:34
@@ -26,7 +26,7 @@
}
-bool HashValue::operator == (const HashValue &cmp)
+bool HashValue::operator == (const HashValue &cmp) const
{
if (Type==HASH_NONE || cmp.Type==HASH_NONE)
return true;
diff -ur unrar-6.1.7/hash.hpp unrar-6.2.7/hash.hpp
--- unrar-6.1.7/hash.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/hash.hpp 2023-05-14 13:10:34
@@ -6,8 +6,14 @@
struct HashValue
{
void Init(HASH_TYPE Type);
- bool operator == (const HashValue &cmp);
- bool operator != (const HashValue &cmp) {return !(*this==cmp);}
+
+ // Use the const member, so types on both sides of "==" match.
+ // Otherwise clang -std=c++20 issues "ambiguity is between a regular call
+ // to this operator and a call with the argument order reversed" warning.
+ bool operator == (const HashValue &cmp) const;
+
+ // Not actually used now. Const member for same reason as operator == above.
+ bool operator != (const HashValue &cmp) const {return !(*this==cmp);}
HASH_TYPE Type;
union
diff -ur unrar-6.1.7/headers.cpp unrar-6.2.7/headers.cpp
--- unrar-6.1.7/headers.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/headers.cpp 2023-05-14 13:10:34
@@ -49,13 +49,5 @@
void MainHeader::Reset()
{
- HighPosAV=0;
- PosAV=0;
- CommentInHeader=false;
- PackComment=false;
- Locator=false;
- QOpenOffset=0;
- QOpenMaxSize=0;
- RROffset=0;
- RRMaxSize=0;
+ *this={};
}
diff -ur unrar-6.1.7/headers.hpp unrar-6.2.7/headers.hpp
--- unrar-6.1.7/headers.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/headers.hpp 2023-05-14 13:10:34
@@ -6,7 +6,7 @@
#define SIZEOF_MAINHEAD3 13 // Size of RAR 4.x main archive header.
#define SIZEOF_FILEHEAD14 21 // Size of RAR 1.4 file header.
#define SIZEOF_FILEHEAD3 32 // Size of RAR 3.0 file header.
-#define SIZEOF_SHORTBLOCKHEAD 7
+#define SIZEOF_SHORTBLOCKHEAD 7 // Smallest RAR 4.x block size.
#define SIZEOF_LONGBLOCKHEAD 11
#define SIZEOF_SUBBLOCKHEAD 14
#define SIZEOF_COMMHEAD 13
@@ -162,12 +162,16 @@
ushort HighPosAV;
uint PosAV;
bool CommentInHeader;
- bool PackComment; // For RAR 1.4 archive format only.
+ bool PackComment; // For RAR 1.4 archive format only.
bool Locator;
- uint64 QOpenOffset; // Offset of quick list record.
- uint64 QOpenMaxSize; // Maximum size of QOpen offset in locator extra field.
- uint64 RROffset; // Offset of recovery record.
- uint64 RRMaxSize; // Maximum size of RR offset in locator extra field.
+ uint64 QOpenOffset; // Offset of quick list record.
+ uint64 QOpenMaxSize; // Maximum size of QOpen offset in locator extra field.
+ uint64 RROffset; // Offset of recovery record.
+ uint64 RRMaxSize; // Maximum size of RR offset in locator extra field.
+ size_t MetaNameMaxSize; // Maximum size of archive name in metadata extra field.
+ std::wstring OrigName; // Original archive name.
+ RarTime OrigTime; // Original archive time.
+
void Reset();
};
@@ -230,7 +234,7 @@
bool LargeFile;
// 'true' for HEAD_SERVICE block, which is a child of preceding file block.
- // RAR 4.x uses 'solid' flag to indicate child subheader blocks in archives.
+ // RAR 4.x uses 'solid' flag to indicate children subheader blocks in archives.
bool SubBlock;
HOST_SYSTEM_TYPE HSType;
diff -ur unrar-6.1.7/headers5.hpp unrar-6.2.7/headers5.hpp
--- unrar-6.1.7/headers5.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/headers5.hpp 2023-05-14 13:10:34
@@ -59,10 +59,17 @@
// 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.
diff -ur unrar-6.1.7/isnt.cpp unrar-6.2.7/isnt.cpp
--- unrar-6.1.7/isnt.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/isnt.cpp 2023-05-14 13:10:34
@@ -40,7 +40,7 @@
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))
{
diff -ur unrar-6.1.7/list.cpp unrar-6.2.7/list.cpp
--- unrar-6.1.7/list.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/list.cpp 2023-05-14 13:10:34
@@ -36,6 +36,7 @@
{
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 @@
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");
}
diff -ur unrar-6.1.7/loclang.hpp unrar-6.2.7/loclang.hpp
--- unrar-6.1.7/loclang.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/loclang.hpp 2023-05-14 13:10:34
@@ -28,6 +28,7 @@
#define MRARTitle1 L"\nUsage: rar - - "
#define MUNRARTitle1 L"\nUsage: unrar - - "
#define MRARTitle2 L"\n <@listfiles...> "
+#define MFwrSlTitle2 L"\n <@listfiles...> "
#define MCHelpCmd L"\n\n"
#define MCHelpCmdA L"\n a Add files to archive"
#define MCHelpCmdC L"\n c Add archive comment"
@@ -58,6 +59,7 @@
#define MCHelpSwAD L"\n ad[1,2] Alternate destination path"
#define MCHelpSwAG L"\n ag[format] Generate archive name using the current date"
#define MCHelpSwAI L"\n ai Ignore file attributes"
+#define MCHelpSwAM L"\n am[s,r] Archive name and time [save, restore]"
#define MCHelpSwAO L"\n ao Add files with Archive attribute set"
#define MCHelpSwAP L"\n ap Set path inside archive"
#define MCHelpSwAS L"\n as Synchronize archive contents"
@@ -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"
diff -ur unrar-6.1.7/makefile unrar-6.2.7/makefile
--- unrar-6.1.7/makefile 2022-10-19 22:05:12
+++ unrar-6.2.7/makefile 2023-02-06 13:31:30
@@ -126,7 +126,7 @@
archive.o arcread.o unicode.o system.o crypt.o crc.o rawread.o encname.o \
resource.o match.o timefn.o rdwrfn.o consio.o options.o errhnd.o rarvm.o secpassword.o \
rijndael.o getbits.o sha1.o sha256.o blake2s.o hash.o extinfo.o extract.o volume.o \
- list.o find.o unpack.o headers.o threadpool.o rs16.o cmddata.o ui.o
+ list.o find.o unpack.o headers.o threadpool.o rs16.o cmddata.o ui.o
.cpp.o:
$(COMPILE) -D$(WHAT) -c $<
@@ -142,20 +142,23 @@
@rm -f $(OBJECTS) $(UNRAR_OBJ) $(LIB_OBJ)
@rm -f unrar libunrar.*
-unrar: clean $(OBJECTS) $(UNRAR_OBJ)
+# We removed 'clean' from dependencies, because it prevented parallel
+# 'make -Jn' builds.
+
+unrar: $(OBJECTS) $(UNRAR_OBJ)
@rm -f unrar
$(LINK) -o unrar $(LDFLAGS) $(OBJECTS) $(UNRAR_OBJ) $(LIBS)
$(STRIP) unrar
sfx: WHAT=SFX_MODULE
-sfx: clean $(OBJECTS)
+sfx: $(OBJECTS)
@rm -f default.sfx
$(LINK) -o default.sfx $(LDFLAGS) $(OBJECTS)
$(STRIP) default.sfx
lib: WHAT=RARDLL
lib: CXXFLAGS+=$(LIBFLAGS)
-lib: clean $(OBJECTS) $(LIB_OBJ)
+lib: $(OBJECTS) $(LIB_OBJ)
@rm -f libunrar.*
$(LINK) -shared -o libunrar.so $(LDFLAGS) $(OBJECTS) $(LIB_OBJ)
$(AR) rcs libunrar.a $(OBJECTS) $(LIB_OBJ)
diff -ur unrar-6.1.7/model.cpp unrar-6.2.7/model.cpp
--- unrar-6.1.7/model.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/model.cpp 2023-05-14 13:10:34
@@ -532,13 +532,15 @@
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;
diff -ur unrar-6.1.7/options.cpp unrar-6.2.7/options.cpp
--- unrar-6.1.7/options.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/options.cpp 2023-05-14 13:10:34
@@ -6,14 +6,6 @@
}
-RAROptions::~RAROptions()
-{
- // It is important for security reasons, so we do not have the unnecessary
- // password data left in memory.
- memset(this,0,sizeof(RAROptions));
-}
-
-
void RAROptions::Init()
{
memset(this,0,sizeof(RAROptions));
diff -ur unrar-6.1.7/options.hpp unrar-6.2.7/options.hpp
--- unrar-6.1.7/options.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/options.hpp 2023-05-14 13:10:34
@@ -45,6 +45,12 @@
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 @@
#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 @@
wchar ArcPath[NM]; // For -ap.
wchar ExclArcPath[NM]; // For -ep4 switch.
- SecPassword Password;
bool EncryptHeaders;
bool SkipEncrypted;
@@ -132,6 +138,7 @@
HASH_TYPE HashType;
int Recovery;
int RecVolNumber;
+ ARC_METADATA ArcMetadata;
bool DisablePercentage;
bool DisableCopyright;
bool DisableDone;
@@ -147,7 +154,6 @@
PATH_EXCL_MODE ExclPath;
RECURSE_MODE Recurse;
int64 VolSize;
- Array NextVolSizes;
uint CurVolNum;
bool AllYes;
bool VerboseOutput; // -iv, display verbose output, used only in "WinRAR t" now.
diff -ur unrar-6.1.7/os.hpp unrar-6.2.7/os.hpp
--- unrar-6.1.7/os.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/os.hpp 2023-05-14 13:10:34
@@ -13,6 +13,8 @@
#endif
#include
+#include
+#include
#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
#endif
#ifdef _MSC_VER
- #if _MSC_VER<1500
- #define for if (0) ; else for
- #endif
#include
#include
@@ -97,7 +103,6 @@
#include
#include
#include
-
#define SAVE_LINKS
diff -ur unrar-6.1.7/pathfn.cpp unrar-6.2.7/pathfn.cpp
--- unrar-6.1.7/pathfn.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/pathfn.cpp 2023-05-14 13:10:34
@@ -31,11 +31,17 @@
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 @@
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 @@
{
if (wcschr(Extended ? L"?*<>|\"":L"?*",*s)!=NULL || Extended && (uint)*s<32)
*s='_';
-#ifndef _UNIX
+#ifdef _UNIX
+ // We were asked to apply Windows-like conversion in Linux in case
+ // files are unpacked to Windows share. This code is invoked only
+ // if file failed to be created, so it doesn't affect extraction
+ // of Unix compatible names to native Unix drives.
+ if (Extended)
+ {
+ // Windows shares in Unix do not allow the drive letter,
+ // so unlike Windows version, we check all characters here.
+ if (*s==':')
+ *s='_';
+
+ // No spaces or dots before the path separator are allowed on Windows
+ // shares. But they are allowed and automtically removed at the end of
+ // file or folder name, so it is useless to replace them here.
+ // Since such files or folders are created successfully, a supposed
+ // conversion here would never be invoked.
+ if ((*s==' ' || *s=='.') && IsPathDiv(s[1]))
+ *s='_';
+ }
+#else
if (s-Name>1 && *s==':')
*s='_';
#if 0 // We already can create such files.
diff -ur unrar-6.1.7/pathfn.hpp unrar-6.2.7/pathfn.hpp
--- unrar-6.1.7/pathfn.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/pathfn.hpp 2023-05-14 13:10:34
@@ -29,7 +29,6 @@
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);
diff -ur unrar-6.1.7/qopen.cpp unrar-6.2.7/qopen.cpp
--- unrar-6.1.7/qopen.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/qopen.cpp 2023-05-14 13:10:34
@@ -97,7 +97,7 @@
if (Arc->SubHead.Encrypted)
{
- RAROptions *Cmd=Arc->GetRAROptions();
+ CommandData *Cmd=Arc->GetCommandData();
#ifndef RAR_NOCRYPT
if (Cmd->Password.IsSet())
Crypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,Arc->SubHead.Salt,
diff -ur unrar-6.1.7/rar.hpp unrar-6.2.7/rar.hpp
--- unrar-6.1.7/rar.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/rar.hpp 2023-05-14 13:10:34
@@ -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"
diff -ur unrar-6.1.7/rardefs.hpp unrar-6.2.7/rardefs.hpp
--- unrar-6.1.7/rardefs.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/rardefs.hpp 2023-05-14 13:10:34
@@ -9,9 +9,13 @@
#define ASIZE(x) (sizeof(x)/sizeof(x[0]))
-// MAXPASSWORD is expected to be multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE (16)
-// for CryptProtectMemory in SecPassword.
-#define MAXPASSWORD 128
+// MAXPASSWORD and MAXPASSWORD_RAR are expected to be multiple of
+// CRYPTPROTECTMEMORY_BLOCK_SIZE (16) for CryptProtectMemory in SecPassword.
+// We allow a larger MAXPASSWORD to unpack archives with lengthy passwords
+// in non-RAR formats in GUI versions. For RAR format we set MAXPASSWORD_RAR
+// to 128 for compatibility and because it is enough for AES-256.
+#define MAXPASSWORD 512
+#define MAXPASSWORD_RAR 128
#define MAXSFXSIZE 0x200000
diff -ur unrar-6.1.7/rawint.hpp unrar-6.2.7/rawint.hpp
--- unrar-6.1.7/rawint.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/rawint.hpp 2023-05-14 13:10:35
@@ -84,7 +84,7 @@
{
#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 @@
{
#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 @@
{
#ifdef _MSC_VER
return _byteswap_ulong(i);
-#elif (__GNUC__ > 3) && (__GNUC_MINOR__ > 2)
+#elif defined(__clang__) || defined(__GNUC__)
return __builtin_bswap32(i);
#else
return (rotl32(i,24)&0xFF00FF00)|(rotl32(i,8)&0x00FF00FF);
diff -ur unrar-6.1.7/rdwrfn.cpp unrar-6.2.7/rdwrfn.cpp
--- unrar-6.1.7/rdwrfn.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/rdwrfn.cpp 2023-05-14 13:10:35
@@ -155,7 +155,7 @@
{
#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 @@
ArcPos+=ProcessedArcSize;
Archive *SrcArc=(Archive *)SrcFile;
- RAROptions *Cmd=SrcArc->GetRAROptions();
+ CommandData *Cmd=SrcArc->GetCommandData();
int CurPercent=ToPercent(ArcPos,ArcSize);
if (!Cmd->DisablePercentage && CurPercent!=LastPercent)
diff -ur unrar-6.1.7/recvol.cpp unrar-6.2.7/recvol.cpp
--- unrar-6.1.7/recvol.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/recvol.cpp 2023-05-14 13:10:35
@@ -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 @@
}
-void RecVolumesTest(RAROptions *Cmd,Archive *Arc,const wchar *Name)
+void RecVolumesTest(CommandData *Cmd,Archive *Arc,const wchar *Name)
{
wchar RevName[NM];
*RevName=0;
diff -ur unrar-6.1.7/recvol.hpp unrar-6.2.7/recvol.hpp
--- unrar-6.1.7/recvol.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/recvol.hpp 2023-05-14 13:10:35
@@ -14,11 +14,11 @@
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 @@
class RecVolumes5
{
private:
- void ProcessRS(RAROptions *Cmd,uint DataNum,const byte *Data,uint MaxRead,bool Encode);
- void ProcessRS(RAROptions *Cmd,uint MaxRead,bool Encode);
+ void ProcessRS(CommandData *Cmd,uint DataNum,const byte *Data,uint MaxRead,bool Encode);
+ void ProcessRS(CommandData *Cmd,uint MaxRead,bool Encode);
uint ReadHeader(File *RecFile,bool FirstRev);
Array RecItems;
@@ -76,13 +76,13 @@
public: // 'public' only because called from thread functions.
void ProcessAreaRS(RecRSThreadData *td);
public:
- RecVolumes5(RAROptions *Cmd,bool TestOnly);
+ RecVolumes5(CommandData *Cmd,bool TestOnly);
~RecVolumes5();
- bool Restore(RAROptions *Cmd,const wchar *Name,bool Silent);
- void Test(RAROptions *Cmd,const wchar *Name);
+ bool Restore(CommandData *Cmd,const wchar *Name,bool Silent);
+ void Test(CommandData *Cmd,const wchar *Name);
};
-bool RecVolumesRestore(RAROptions *Cmd,const wchar *Name,bool Silent);
-void RecVolumesTest(RAROptions *Cmd,Archive *Arc,const wchar *Name);
+bool RecVolumesRestore(CommandData *Cmd,const wchar *Name,bool Silent);
+void RecVolumesTest(CommandData *Cmd,Archive *Arc,const wchar *Name);
#endif
diff -ur unrar-6.1.7/recvol3.cpp unrar-6.2.7/recvol3.cpp
--- unrar-6.1.7/recvol3.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/recvol3.cpp 2023-05-14 13:10:35
@@ -36,7 +36,7 @@
}
#endif
-RecVolumes3::RecVolumes3(RAROptions *Cmd,bool TestOnly)
+RecVolumes3::RecVolumes3(CommandData *Cmd,bool TestOnly)
{
memset(SrcFile,0,sizeof(SrcFile));
if (TestOnly)
@@ -99,7 +99,7 @@
}
-bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
+bool RecVolumes3::Restore(CommandData *Cmd,const wchar *Name,bool Silent)
{
wchar ArcName[NM];
wcsncpyz(ArcName,Name,ASIZE(ArcName));
@@ -497,7 +497,7 @@
}
-void RecVolumes3::Test(RAROptions *Cmd,const wchar *Name)
+void RecVolumes3::Test(CommandData *Cmd,const wchar *Name)
{
if (!IsNewStyleRev(Name)) // RAR 3.0 name#_#_#.rev do not include CRC32.
{
diff -ur unrar-6.1.7/recvol5.cpp unrar-6.2.7/recvol5.cpp
--- unrar-6.1.7/recvol5.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/recvol5.cpp 2023-05-14 13:10:35
@@ -4,7 +4,7 @@
// 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 @@
#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 @@
-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 @@
}
-void RecVolumes5::Test(RAROptions *Cmd,const wchar *Name)
+void RecVolumes5::Test(CommandData *Cmd,const wchar *Name)
{
wchar VolName[NM];
wcsncpyz(VolName,Name,ASIZE(VolName));
diff -ur unrar-6.1.7/rijndael.cpp unrar-6.2.7/rijndael.cpp
--- unrar-6.1.7/rijndael.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/rijndael.cpp 2023-05-14 13:10:35
@@ -90,18 +90,20 @@
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 @@
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;
@@ -239,6 +248,40 @@
}
#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)
{
@@ -246,12 +289,18 @@
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];
@@ -339,6 +388,41 @@
numBlocks--;
}
_mm_storeu_si128((__m128i*)m_initVector,initVector);
+}
+#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
diff -ur unrar-6.1.7/rijndael.hpp unrar-6.2.7/rijndael.hpp
--- unrar-6.1.7/rijndael.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/rijndael.hpp 2023-05-14 13:10:35
@@ -18,6 +18,16 @@
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();
diff -ur unrar-6.1.7/scantree.cpp unrar-6.2.7/scantree.cpp
--- unrar-6.1.7/scantree.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/scantree.cpp 2023-05-14 13:10:35
@@ -215,10 +215,21 @@
UnixSlashToDos(CurMask,CurMask,ASIZE(CurMask));
#endif
- // We wish to scan entire disk if mask like c:\ is specified
- // regardless of recursion mode. Use c:\*.* mask when need to scan only
- // the root directory.
- ScanEntireDisk=IsDriveLetter(CurMask) && IsPathDiv(CurMask[2]) && CurMask[3]==0;
+ // We prefer to scan entire disk if mask like \\server\share\ or c:\
+ // is specified regardless of recursion mode. Use \\server\share\*.*
+ // or c:\*.* mask to scan only the root directory.
+ if (CurMask[0]=='\\' && CurMask[1]=='\\')
+ {
+ const wchar *Slash=wcschr(CurMask+2,'\\');
+ if (Slash!=NULL)
+ {
+ Slash=wcschr(Slash+1,'\\');
+ ScanEntireDisk=Slash!=NULL && *(Slash+1)==0;
+ }
+ }
+ else
+ ScanEntireDisk=IsDriveLetter(CurMask) && IsPathDiv(CurMask[2]) && CurMask[3]==0;
+
wchar *Name=PointToName(CurMask);
if (*Name==0)
diff -ur unrar-6.1.7/secpassword.cpp unrar-6.2.7/secpassword.cpp
--- unrar-6.1.7/secpassword.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/secpassword.cpp 2023-05-14 13:10:35
@@ -56,7 +56,6 @@
SecPassword::SecPassword()
{
- CrossProcess=false;
Set(L"");
}
@@ -70,7 +69,8 @@
void SecPassword::Clean()
{
PasswordSet=false;
- cleandata(Password,sizeof(Password));
+ if (Password.size()>0)
+ cleandata(&Password[0],Password.size());
}
@@ -104,7 +104,7 @@
// Source string can be shorter than destination as in case when we process
// -p parameter, so we need to take into account both sizes.
memcpy(Dst,Src,Min(SrcSize,DstSize)*sizeof(*Dst));
- SecHideData(Dst,DstSize*sizeof(*Dst),Encode,CrossProcess);
+ SecHideData(Dst,DstSize*sizeof(*Dst),Encode,false);
}
@@ -112,7 +112,7 @@
{
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::Set(const wchar *Psw)
{
- if (*Psw==0)
+ // Eliminate any traces of previously stored password for security reason
+ // in case it was longer than new one.
+ Clean();
+
+ if (*Psw!=0)
{
- PasswordSet=false;
- memset(Password,0,sizeof(Password));
- }
- else
- {
PasswordSet=true;
- Process(Psw,wcslen(Psw)+1,Password,ASIZE(Password),true);
+ Process(Psw,wcslen(Psw)+1,&Password[0],Password.size(),true);
}
}
@@ -163,6 +162,9 @@
}
+// Set CrossProcess to true if we need to pass a password to another process.
+// We use CrossProcess when transferring parameters to UAC elevated WinRAR
+// and Windows GUI SFX modules.
void SecHideData(void *Data,size_t DataSize,bool Encode,bool CrossProcess)
{
// CryptProtectMemory is not available in UWP and CryptProtectData
diff -ur unrar-6.1.7/secpassword.hpp unrar-6.2.7/secpassword.hpp
--- unrar-6.1.7/secpassword.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/secpassword.hpp 2023-05-14 13:10:35
@@ -8,10 +8,7 @@
private:
void Process(const wchar *Src,size_t SrcSize,wchar *Dst,size_t DstSize,bool Encode);
- wchar Password[MAXPASSWORD];
-
- // It is important to have this 'bool' value, so if our object is cleaned
- // with memset as a part of larger structure, it is handled correctly.
+ std::vector Password = std::vector(MAXPASSWORD);
bool PasswordSet;
public:
SecPassword();
@@ -22,10 +19,6 @@
bool IsSet() {return PasswordSet;}
size_t Length();
bool operator == (SecPassword &psw);
-
- // Set to true if we need to pass a password to another process.
- // We use it when transferring parameters to UAC elevated WinRAR.
- bool CrossProcess;
};
diff -ur unrar-6.1.7/strfn.cpp unrar-6.2.7/strfn.cpp
--- unrar-6.1.7/strfn.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/strfn.cpp 2023-05-14 13:10:35
@@ -357,6 +357,32 @@
}
+// Convert the number to string using thousand separators.
+void fmtitoa(int64 n,wchar *Str,size_t MaxSize)
+{
+ static wchar ThSep=0; // Thousands separator.
+#ifdef _WIN_ALL
+ wchar Info[10];
+ if (!ThSep!=0 && GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_STHOUSAND,Info,ASIZE(Info))>0)
+ ThSep=*Info;
+#elif defined(_UNIX)
+ ThSep=*localeconv()->thousands_sep;
+#endif
+ if (ThSep==0) // If failed to detect the actual separator value.
+ ThSep=' ';
+ wchar RawText[30]; // 20 characters are enough for largest unsigned 64 bit int.
+ itoa(n,RawText,ASIZE(RawText));
+ uint S=0,D=0,L=wcslen(RawText)%3;
+ while (RawText[S]!=0 && D+1=7)
{
diff -ur unrar-6.1.7/threadmisc.cpp unrar-6.2.7/threadmisc.cpp
--- unrar-6.1.7/threadmisc.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/threadmisc.cpp 2023-05-14 13:10:35
@@ -149,3 +149,5 @@
return NumCPU;
}
+
+
diff -ur unrar-6.1.7/timefn.hpp unrar-6.2.7/timefn.hpp
--- unrar-6.1.7/timefn.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/timefn.hpp 2023-05-14 13:10:35
@@ -22,6 +22,17 @@
// Internal time representation in 1/TICKS_PER_SECOND since 01.01.1601.
// We use nanoseconds here to handle the high precision Unix time.
+ // It allows dates up to July 2185.
+ //
+ // If we'll ever need to extend the date range, we can define a lower
+ // precision Windows version of TICKS_PER_SECOND. But then Unix and Windows
+ // versions can differ in least significant digits of "lt" time output
+ // for Unix archives.
+ // Alternatively we can introduce 'bool HighPrecision' set to true
+ // in SetUnixNS() and TicksPerSecond() instead of constant above.
+ // It might be more reliable than defining TicksPerSecond variable,
+ // which wouldn't survive memset of any structure hosting RarTime.
+ // We would need to eliminate all such memsets in the entire code first.
uint64 itime;
public:
// RarLocalTime::Reminder precision. Must be equal to TICKS_PER_SECOND.
diff -ur unrar-6.1.7/ui.hpp unrar-6.2.7/ui.hpp
--- unrar-6.1.7/ui.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/ui.hpp 2023-05-14 13:10:35
@@ -49,7 +49,7 @@
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 @@
};
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 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 @@
// Templates recognize usual NULL as integer, not wchar*.
#define UINULL ((wchar *)NULL)
-inline void uiMsg(UIMESSAGE_CODE Code)
+inline void uiMsgBase(uiMsgStore &Store)
{
- uiMsgStore Store(Code);
- Store.Msg();
+ // Called last, when no parameters are left.
}
-template void uiMsg(UIMESSAGE_CODE Code,T1 a1)
+template void uiMsgBase(uiMsgStore &Store,T1&& a1,TN&&... aN)
{
- uiMsgStore Store(Code);
+ // Process first parameter and pass the rest to same uiMsgBase.
Store< void uiMsg(UIMESSAGE_CODE Code,T1 a1,T2 a2)
-{
- uiMsgStore Store(Code);
- Store< void uiMsg(UIMESSAGE_CODE code,T1 a1,T2 a2,T3 a3)
+// Use variadic templates.
+//
+// We must pass variable parameters by reference, so no temporary copies are
+// created for custom string objects like CStringBase in 7-Zip decompression
+// code. Such temporary copies would be destroyed inside of recursive
+// uiMsgBase calls, leaving us with Str[] items pointing at released memory.
+// Since we pass integer values as well, we can't use & references
+// and must resort to && rvalue references.
+template void uiMsg(UIMESSAGE_CODE Code,TN&&... aN)
{
- uiMsgStore Store(code);
- Store<Overwrite==OVERWRITE_NONE)
return UIASKREP_R_SKIP;
diff -ur unrar-6.1.7/uiconsole.cpp unrar-6.2.7/uiconsole.cpp
--- unrar-6.1.7/uiconsole.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/uiconsole.cpp 2023-05-14 13:10:35
@@ -262,6 +262,7 @@
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 +396,8 @@
}
-bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password)
+bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,
+ SecPassword *Password,CheckPassword *CheckPwd)
{
// Unlike GUI we cannot provide Cancel button here, so we use the empty
// password to abort. Otherwise user not knowing a password would need to
diff -ur unrar-6.1.7/uisilent.cpp unrar-6.2.7/uisilent.cpp
--- unrar-6.1.7/uisilent.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/uisilent.cpp 2023-05-14 13:10:35
@@ -33,7 +33,8 @@
}
-bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password)
+bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,
+ SecPassword *Password,CheckPassword *CheckPwd)
{
return false;
}
diff -ur unrar-6.1.7/ulinks.cpp unrar-6.2.7/ulinks.cpp
--- unrar-6.1.7/ulinks.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/ulinks.cpp 2023-05-14 13:10:35
@@ -70,7 +70,8 @@
}
-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 @@
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 @@
// 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;
diff -ur unrar-6.1.7/unicode.cpp unrar-6.2.7/unicode.cpp
--- unrar-6.1.7/unicode.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/unicode.cpp 2023-05-14 13:10:35
@@ -229,10 +229,11 @@
#endif
-// SrcSize is in wide characters, not in bytes.
-byte* WideToRaw(const wchar *Src,byte *Dest,size_t SrcSize)
+// SrcSize is source data size in wide characters, not in bytes.
+// DestSize is the maximum allowed destination size.
+byte* WideToRaw(const wchar *Src,size_t SrcSize,byte *Dest,size_t DestSize)
{
- for (size_t I=0;I>8);
diff -ur unrar-6.1.7/unicode.hpp unrar-6.2.7/unicode.hpp
--- unrar-6.1.7/unicode.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/unicode.hpp 2023-05-14 13:10:35
@@ -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);
diff -ur unrar-6.1.7/unpack.cpp unrar-6.2.7/unpack.cpp
--- unrar-6.1.7/unpack.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/unpack.cpp 2023-05-14 13:10:35
@@ -309,7 +309,7 @@
Dec->QuickBits=MAX_QUICK_DECODE_BITS;
break;
default:
- Dec->QuickBits=MAX_QUICK_DECODE_BITS-3;
+ Dec->QuickBits=MAX_QUICK_DECODE_BITS>3 ? MAX_QUICK_DECODE_BITS-3 : 0;
break;
}
diff -ur unrar-6.1.7/unpack.hpp unrar-6.2.7/unpack.hpp
--- unrar-6.1.7/unpack.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/unpack.hpp 2023-05-14 13:10:35
@@ -93,17 +93,17 @@
#ifdef RAR_SMP
enum UNP_DEC_TYPE {
- UNPDT_LITERAL,UNPDT_MATCH,UNPDT_FULLREP,UNPDT_REP,UNPDT_FILTER
+ UNPDT_LITERAL=0,UNPDT_MATCH,UNPDT_FULLREP,UNPDT_REP,UNPDT_FILTER
};
struct UnpackDecodedItem
{
- UNP_DEC_TYPE Type;
+ byte Type; // 'byte' instead of enum type to reduce memory use.
ushort Length;
union
{
uint Distance;
- byte Literal[4];
+ byte Literal[8]; // Store up to 8 chars here to speed up extraction.
};
};
diff -ur unrar-6.1.7/unpack30.cpp unrar-6.2.7/unpack30.cpp
--- unrar-6.1.7/unpack30.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/unpack30.cpp 2023-05-14 13:10:35
@@ -55,7 +55,7 @@
if (!UnpReadBuf30())
break;
}
- if (((WrPtr-UnpPtr) & MaxWinMask)<260 && WrPtr!=UnpPtr)
+ if (((WrPtr-UnpPtr) & MaxWinMask)<=MAX3_INC_LZ_MATCH && WrPtr!=UnpPtr)
{
UnpWriteBuf30();
if (WrittenFileSize>DestUnpSize)
diff -ur unrar-6.1.7/unpack50.cpp unrar-6.2.7/unpack50.cpp
--- unrar-6.1.7/unpack50.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/unpack50.cpp 2023-05-14 13:10:35
@@ -42,7 +42,7 @@
break;
}
- if (((WriteBorder-UnpPtr) & MaxWinMask)DestUnpSize)
@@ -93,7 +93,7 @@
}
else
{
- Distance+=Inp.getbits32()>>(32-DBits);
+ Distance+=Inp.getbits()>>(16-DBits);
Inp.addbits(DBits);
}
}
diff -ur unrar-6.1.7/unpack50mt.cpp unrar-6.2.7/unpack50mt.cpp
--- unrar-6.1.7/unpack50mt.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/unpack50mt.cpp 2023-05-14 13:10:35
@@ -345,7 +345,7 @@
if (D.DecodedSize>1)
{
UnpackDecodedItem *PrevItem=CurItem-1;
- if (PrevItem->Type==UNPDT_LITERAL && PrevItem->Length<3)
+ if (PrevItem->Type==UNPDT_LITERAL && PrevItem->LengthLiteral)-1)
{
PrevItem->Length++;
PrevItem->Literal[PrevItem->Length]=(byte)MainSlot;
@@ -388,7 +388,7 @@
}
else
{
- Distance+=D.Inp.getbits32()>>(32-DBits);
+ Distance+=D.Inp.getbits()>>(16-DBits);
D.Inp.addbits(DBits);
}
}
@@ -451,7 +451,7 @@
while (ItemDestUnpSize)
@@ -461,10 +461,10 @@
if (Item->Type==UNPDT_LITERAL)
{
#if defined(LITTLE_ENDIAN) && defined(ALLOW_MISALIGNED)
- if (Item->Length==3 && UnpPtrLength==7 && UnpPtrLiteral;
- UnpPtr+=4;
+ *(uint64 *)(Window+UnpPtr)=*(uint64 *)(Item->Literal);
+ UnpPtr+=8;
}
else
#endif
@@ -559,7 +559,7 @@
break;
}
}
- if (((WriteBorder-UnpPtr) & MaxWinMask)DestUnpSize)
diff -ur unrar-6.1.7/version.hpp unrar-6.2.7/version.hpp
--- unrar-6.1.7/version.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/version.hpp 2023-05-14 13:10:35
@@ -1,6 +1,6 @@
#define RARVER_MAJOR 6
-#define RARVER_MINOR 12
-#define RARVER_BETA 0
-#define RARVER_DAY 4
+#define RARVER_MINOR 22
+#define RARVER_BETA 1
+#define RARVER_DAY 14
#define RARVER_MONTH 5
-#define RARVER_YEAR 2022
+#define RARVER_YEAR 2023
diff -ur unrar-6.1.7/volume.cpp unrar-6.2.7/volume.cpp
--- unrar-6.1.7/volume.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/volume.cpp 2023-05-14 13:10:35
@@ -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 @@
#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 @@
#ifdef RARDLL
-bool DllVolNotify(RAROptions *Cmd,wchar *NextName)
+bool DllVolNotify(CommandData *Cmd,wchar *NextName)
{
char NextNameA[NM];
WideToChar(NextName,NextNameA,ASIZE(NextNameA));
diff -ur unrar-6.1.7/volume.hpp unrar-6.2.7/volume.hpp
--- unrar-6.1.7/volume.hpp 2022-10-19 22:05:12
+++ unrar-6.2.7/volume.hpp 2023-05-14 13:10:35
@@ -1,10 +1,7 @@
#ifndef _RAR_VOLUME_
#define _RAR_VOLUME_
-void SplitArchive(Archive &Arc,FileHeader *fh,int64 *HeaderPos,
- ComprDataIO *DataIO);
bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,
wchar Command);
-void SetVolWrite(Archive &Dest,int64 VolSize);
#endif
diff -ur unrar-6.1.7/win32stm.cpp unrar-6.2.7/win32stm.cpp
--- unrar-6.1.7/win32stm.cpp 2022-10-19 22:05:12
+++ unrar-6.2.7/win32stm.cpp 2023-05-14 13:10:35
@@ -111,16 +111,23 @@
wcsncatz(FullName,StreamName,ASIZE(FullName));
+
FindData fd;
- bool Found=FindFile::FastFind(FileName,&fd);
+ bool HostFound=FindFile::FastFind(FileName,&fd);
if ((fd.FileAttr & FILE_ATTRIBUTE_READONLY)!=0)
SetFileAttr(FileName,fd.FileAttr & ~FILE_ATTRIBUTE_READONLY);
File CurFile;
- if (CurFile.WCreate(FullName) && Arc.ReadSubData(NULL,&CurFile,false))
- CurFile.Close();
+
+ if (CurFile.WCreate(FullName))
+ {
+ if (Arc.ReadSubData(NULL,&CurFile,false))
+ CurFile.Close();
+ }
+
+ // Restoring original file timestamps.
File HostFile;
- if (Found && HostFile.Open(FileName,FMF_OPENSHARED|FMF_UPDATE))
+ if (HostFound && HostFile.Open(FileName,FMF_OPENSHARED|FMF_UPDATE))
SetFileTime(HostFile.GetHandle(),&fd.ftCreationTime,&fd.ftLastAccessTime,
&fd.ftLastWriteTime);