ALT Linux Bugzilla
– Attachment 13312 Details for
Bug 46318
unrar version update to 6.2.7
New bug
|
Search
|
[?]
|
Help
Register
|
Log In
[x]
|
Forgot Password
Login:
[x]
|
EN
|
RU
[patch]
unrar patch
unrar-6.2.7.patch (text/plain), 128.98 KB, created by
aleksandrkarpunin0889
on 2023-05-31 01:08:12 MSK
(
hide
)
Description:
unrar patch
Filename:
MIME Type:
Creator:
aleksandrkarpunin0889
Created:
2023-05-31 01:08:12 MSK
Size:
128.98 KB
patch
obsolete
>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 @@ > <ExceptionHandling>Sync</ExceptionHandling> > <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> > <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> >- <StructMemberAlignment>4Bytes</StructMemberAlignment> >+ <StructMemberAlignment>Default</StructMemberAlignment> > <RuntimeTypeInfo>false</RuntimeTypeInfo> > <PrecompiledHeader>Use</PrecompiledHeader> > <PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile> >@@ -168,7 +168,7 @@ > <ExceptionHandling>Sync</ExceptionHandling> > <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> > <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> >- <StructMemberAlignment>4Bytes</StructMemberAlignment> >+ <StructMemberAlignment>Default</StructMemberAlignment> > <RuntimeTypeInfo>false</RuntimeTypeInfo> > <PrecompiledHeader>Use</PrecompiledHeader> > <PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile> >@@ -198,7 +198,7 @@ > <MinimalRebuild>false</MinimalRebuild> > <ExceptionHandling>Sync</ExceptionHandling> > <RuntimeLibrary>MultiThreaded</RuntimeLibrary> >- <StructMemberAlignment>4Bytes</StructMemberAlignment> >+ <StructMemberAlignment>Default</StructMemberAlignment> > <BufferSecurityCheck>true</BufferSecurityCheck> > <FunctionLevelLinking>true</FunctionLevelLinking> > <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet> >@@ -239,7 +239,7 @@ > <MinimalRebuild>false</MinimalRebuild> > <ExceptionHandling>Sync</ExceptionHandling> > <RuntimeLibrary>MultiThreaded</RuntimeLibrary> >- <StructMemberAlignment>4Bytes</StructMemberAlignment> >+ <StructMemberAlignment>Default</StructMemberAlignment> > <BufferSecurityCheck>true</BufferSecurityCheck> > <FunctionLevelLinking>true</FunctionLevelLinking> > <RuntimeTypeInfo>false</RuntimeTypeInfo> >@@ -274,7 +274,7 @@ > <MinimalRebuild>false</MinimalRebuild> > <ExceptionHandling>Sync</ExceptionHandling> > <RuntimeLibrary>MultiThreaded</RuntimeLibrary> >- <StructMemberAlignment>4Bytes</StructMemberAlignment> >+ <StructMemberAlignment>Default</StructMemberAlignment> > <BufferSecurityCheck>true</BufferSecurityCheck> > <FunctionLevelLinking>true</FunctionLevelLinking> > <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet> >@@ -315,7 +315,7 @@ > <MinimalRebuild>false</MinimalRebuild> > <ExceptionHandling>Sync</ExceptionHandling> > <RuntimeLibrary>MultiThreaded</RuntimeLibrary> >- <StructMemberAlignment>4Bytes</StructMemberAlignment> >+ <StructMemberAlignment>Default</StructMemberAlignment> > <BufferSecurityCheck>true</BufferSecurityCheck> > <FunctionLevelLinking>true</FunctionLevelLinking> > <RuntimeTypeInfo>false</RuntimeTypeInfo> >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<byte> *UnpData,File *DestFile,bool TestMode); > HEADER_TYPE GetHeaderType() {return CurHeaderType;} >- RAROptions* GetRAROptions() {return Cmd;} >+ CommandData* GetCommandData() {return Cmd;} > void SetSilentOpen(bool Mode) {SilentOpen=Mode;} > #if 0 > void GetRecoveryInfo(bool Required,int64 *Size,int *Percent); >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<pwd> to not stop batch processing for encrypted archives. > bool GlobalPassword=Cmd->Password.IsSet() || uiIsGlobalPasswordSet(); > >+ RarCheckPassword CheckPwd; >+ if (CryptHead.UsePswCheck && !BrokenHeader) >+ CheckPwd.Set(CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,CryptHead.PswCheck); >+ > while (true) // Repeat the password prompt for wrong passwords. > { >- RequestArcPassword(); >+ RequestArcPassword(CheckPwd.IsSet() ? &CheckPwd:NULL); > > byte PswCheck[SIZE_PSWCHECK]; > HeadersCrypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,NULL,PswCheck); >- // Verify password validity. >- if (CryptHead.UsePswCheck && memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0) >+ // Verify password validity. If header is damaged, we cannot rely on >+ // password check value, because it can be damaged too. >+ if (CryptHead.UsePswCheck && !BrokenHeader && >+ memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0) > { > if (GlobalPassword) // For -p<pwd> or Ctrl+P. > { >@@ -850,8 +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<char> NameU((size_t)NameSize); // UTF-8 name. >+ Raw->GetB(&NameU[0],(size_t)NameSize); >+ // If starts from 0, the name was longer than reserved space >+ // when saving this extra field. >+ if (NameU[0]!=0) >+ { >+ NameU.push_back(0); >+ std::vector<wchar> NameW(NameU.size()*4); >+ UtfToWide(&NameU[0],&NameW[0],NameW.size()); >+ hd->OrigName.assign(&NameW[0]); >+ } >+ } >+ } >+ if ((Flags & MHEXTRA_METADATA_CTIME)!=0) >+ if ((Flags & MHEXTRA_METADATA_UNIXTIME)!=0) >+ if ((Flags & MHEXTRA_METADATA_UNIX_NS)!=0) >+ hd->OrigTime.SetUnixNS(Raw->Get8()); >+ else >+ hd->OrigTime.SetUnix((time_t)Raw->Get4()); >+ else >+ hd->OrigTime.SetWin(Raw->Get8()); >+ } >+ break; > } > } > >@@ -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<T> &Src); >+ Array<T>& operator = (const Array<T> &Src); > void Push(T Item); > void Append(T *Item,size_t Count); > T* Addr(size_t Item) {return Buffer+Item;} > void SetMaxSize(size_t Size) {MaxSize=Size;} > T* Begin() {return Buffer;} > T* End() {return Buffer==NULL ? NULL:Buffer+BufSize;} >- void SetSecure() {Secure=true;} > }; > > >@@ -41,7 +39,6 @@ > BufSize=0; > AllocSize=0; > MaxSize=0; >- Secure=false; > } > > >@@ -71,11 +68,7 @@ > template <class T> Array<T>::~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 <class T> void Array<T>::operator =(Array<T> &Src) >+template <class T> Array<T>& Array<T>::operator =(const Array<T> &Src) > { > Reset(); > Alloc(Src.BufSize); > if (Src.BufSize!=0) > memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T)); >+ return *this; > } > > >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<int64> 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<DataEnd; Data+=8 ) >+ { >+ uint64 Index=StartCRC; >+#ifdef BIG_ENDIAN >+ Index ^= (uint64(Data[0])|(uint64(Data[1])<<8)|(uint64(Data[2])<<16)|(uint64(Data[3])<<24))| >+ (uint64(Data[4])<<32)|(uint64(Data[5])<<40)|(uint64(Data[6])<<48)|(uint64(Data[7])<<56); >+#else >+ Index ^= *(uint64 *)Data; >+#endif >+ StartCRC = crc64_tables[ 7 ] [ ( byte ) (Index ) ] ^ >+ crc64_tables[ 6 ] [ ( byte ) (Index >> 8 ) ] ^ >+ crc64_tables[ 5 ] [ ( byte ) (Index >> 16 ) ] ^ >+ crc64_tables[ 4 ] [ ( byte ) (Index >> 24 ) ] ^ >+ crc64_tables[ 3 ] [ ( byte ) (Index >> 32 ) ] ^ >+ crc64_tables[ 2 ] [ ( byte ) (Index >> 40 ) ] ^ >+ crc64_tables[ 1 ] [ ( byte ) (Index >> 48 ) ] ^ >+ crc64_tables[ 0 ] [ ( byte ) (Index >> 56 ) ] ; >+ } >+ >+ for (Size%=8;Size>0;Size--,Data++) // Process left data. >+ StartCRC=crc64_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8); >+ >+ return StartCRC; >+} >+ >+ >+#if 0 >+static void TestCRC(); >+struct TestCRCStruct {TestCRCStruct() {TestCRC();exit(0);}} GlobalTesCRC; >+ >+void TestCRC() >+{ >+ const uint FirstSize=300; >+ byte b[FirstSize]; >+ >+ if ((CRC32(0xffffffff,(byte*)"testtesttest",12)^0xffffffff)==0x44608e84) >+ mprintf(L"\nCRC32 test1 OK"); >+ else >+ mprintf(L"\nCRC32 test1 FAILED"); >+ >+ if (CRC32(0,(byte*)"te\x80st",5)==0xB2E5C5AE) >+ mprintf(L"\nCRC32 test2 OK"); >+ else >+ mprintf(L"\nCRC32 test2 FAILED"); >+ >+ for (uint I=0;I<14;I++) // Check for possible int sign extension. >+ b[I]=(byte)0x7f+I; >+ if ((CRC32(0xffffffff,b,14)^0xffffffff)==0x1DFA75DA) >+ mprintf(L"\nCRC32 test3 OK"); >+ else >+ mprintf(L"\nCRC32 test3 FAILED"); >+ >+ for (uint I=0;I<FirstSize;I++) >+ b[I]=(byte)I; >+ uint r32=CRC32(0xffffffff,b,FirstSize); >+ for (uint I=FirstSize;I<1024;I++) >+ { >+ b[0]=(byte)I; >+ r32=CRC32(r32,b,1); >+ } >+ if ((r32^0xffffffff)==0xB70B4C26) >+ mprintf(L"\nCRC32 test4 OK"); >+ else >+ mprintf(L"\nCRC32 test4 FAILED"); >+ >+ if ((CRC64(0xffffffffffffffff,(byte*)"testtesttest",12)^0xffffffffffffffff)==0x7B1C2D230EDEB436) >+ mprintf(L"\nCRC64 test1 OK"); >+ else >+ mprintf(L"\nCRC64 test1 FAILED"); >+ >+ if (CRC64(0,(byte*)"te\x80st",5)==0xB5DBF9583A6EED4A) >+ mprintf(L"\nCRC64 test2 OK"); >+ else >+ mprintf(L"\nCRC64 test2 FAILED"); >+ >+ for (uint I=0;I<14;I++) // Check for possible int sign extension. >+ b[I]=(byte)0x7f+I; >+ if ((CRC64(0xffffffffffffffff,b,14)^0xffffffffffffffff)==0xE019941C05B2820C) >+ mprintf(L"\nCRC64 test3 OK"); >+ else >+ mprintf(L"\nCRC64 test3 FAILED"); >+ >+ for (uint I=0;I<FirstSize;I++) >+ b[I]=(byte)I; >+ uint64 r64=CRC64(0xffffffffffffffff,b,FirstSize); >+ for (uint I=FirstSize;I<1024;I++) >+ { >+ b[0]=(byte)I; >+ r64=CRC64(r64,b,1); >+ } >+ if ((r64^0xffffffffffffffff)==0xD51FB58DC789C400) >+ mprintf(L"\nCRC64 test4 OK"); >+ else >+ mprintf(L"\nCRC64 test4 FAILED"); >+ >+ const size_t BufSize=0x100000; >+ byte *Buf=new byte[BufSize]; >+ memset(Buf,0,BufSize); >+ >+ clock_t StartTime=clock(); >+ r32=0xffffffff; >+ const uint BufCount=5000; >+ for (uint I=0;I<BufCount;I++) >+ r32=CRC32(r32,Buf,BufSize); >+ if (r32!=0) // Otherwise compiler optimizer removes CRC calculation. >+ mprintf(L"\nCRC32 speed: %d MB/s",BufCount*1000/(clock()-StartTime)); >+ >+ StartTime=clock(); >+ r64=0xffffffffffffffff; >+ for (uint I=0;I<BufCount;I++) >+ r64=CRC64(r64,Buf,BufSize); >+ if (r64!=0) // Otherwise compiler optimizer removes CRC calculation. >+ mprintf(L"\nCRC64 speed: %d MB/s",BufCount*1000/(clock()-StartTime)); >+} >+#endif >+ >+#endif >diff -ur unrar-6.1.7/crc.hpp unrar-6.2.7/crc.hpp >--- unrar-6.1.7/crc.hpp 2022-10-19 22:05:12 >+++ unrar-6.2.7/crc.hpp 2023-05-14 13:10:34 >@@ -11,5 +11,9 @@ > ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size); > #endif > >+#if 0 >+void InitCRC64(uint64 *CRCTab); >+uint64 CRC64(uint64 StartCRC,const void *Addr,size_t Size); >+#endif > > #endif >diff -ur unrar-6.1.7/crypt.cpp unrar-6.2.7/crypt.cpp >--- unrar-6.1.7/crypt.cpp 2022-10-19 22:05:12 >+++ unrar-6.2.7/crypt.cpp 2023-05-14 13:10:34 >@@ -11,23 +11,14 @@ > CryptData::CryptData() > { > Method=CRYPT_NONE; >- memset(KDF3Cache,0,sizeof(KDF3Cache)); >- memset(KDF5Cache,0,sizeof(KDF5Cache)); > KDF3CachePos=0; > KDF5CachePos=0; > memset(CRCTab,0,sizeof(CRCTab)); > } > > >-CryptData::~CryptData() >-{ >- cleandata(KDF3Cache,sizeof(KDF3Cache)); >- cleandata(KDF5Cache,sizeof(KDF5Cache)); >-} > > >- >- > void CryptData::DecryptBlock(byte *Buf,size_t Size) > { > switch(Method) >@@ -56,15 +47,18 @@ > SecPassword *Password,const byte *Salt, > const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck) > { >- if (!Password->IsSet() || Method==CRYPT_NONE) >+ if (Method==CRYPT_NONE || !Password->IsSet()) > return false; > > CryptData::Method=Method; > > wchar PwdW[MAXPASSWORD]; > Password->Get(PwdW,ASIZE(PwdW)); >+ PwdW[Min(MAXPASSWORD_RAR,MAXPASSWORD)-1]=0; // For compatibility with existing archives. >+ > char PwdA[MAXPASSWORD]; > WideToChar(PwdW,PwdA,ASIZE(PwdA)); >+ PwdA[Min(MAXPASSWORD_RAR,MAXPASSWORD)-1]=0; // For compatibility with existing archives. > > switch(Method) > { >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;I<ASIZE(KDF5Cache);I++) > { > KDF5CacheItem *Item=KDF5Cache+I; >- if (Item->Lg2Count==Lg2Cnt && Item->Pwd==*Password && >+ if (Item->Pwd==*Password && Item->Lg2Count==Lg2Cnt && > memcmp(Item->Salt,Salt,SIZE_SALT50)==0) > { > memcpy(Key,Item->Key,sizeof(Key)); >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 <commctrl.h> > > 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 && I<LastChecked.size() && Path[I]==LastChecked[I];I++) >+ if (IsPathDiv(Path[I]) && I>SkipLength) >+ SkipLength=I; >+ >+ wchar *Name=Path; >+ if (SkipLength>0) >+ { >+ // Avoid converting symlinks in destination path part specified by user. >+ Name+=SkipLength; >+ while (IsPathDiv(*Name)) >+ Name++; >+ } >+ >+ for (wchar *s=Path+wcslen(Path)-1;s>Name;s--) >+ if (IsPathDiv(*s)) >+ { >+ *s=0; >+ FindData FD; >+ if (FindFile::FastFind(Path,&FD,true) && FD.IsLink) >+#ifdef _WIN_ALL >+ if (!DelDir(Path)) >+#else >+ if (!DelFile(Path)) >+#endif >+ return false; // Couldn't delete the symlink to replace it with directory. >+ } >+ LastChecked=SrcName; >+//#endif >+ return true; >+} >+ >+ > bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName) > { > // Catch root dir based /path/file paths also as stuff like \\?\. >@@ -131,10 +193,14 @@ > 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;I<RefList.Size();I++) >+ { >+ // We can have undeleted temporary reference source here if extraction >+ // was interrupted early or if user refused to overwrite prompt. >+ if (RefList[I].TmpName!=NULL) >+ DelFile(RefList[I].TmpName); >+ free(RefList[I].RefName); >+ free(RefList[I].TmpName); >+ } >+ RefList.Reset(); >+ >+ memset(Analyze,0,sizeof(*Analyze)); >+} >+ >+ > void CmdExtract::DoExtract() > { > #if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT) >@@ -30,10 +69,13 @@ > PasswordCancelled=false; > DataIO.SetCurrentCommand(Cmd->Command[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;I<RefList.Size();I++) >+ if (wcscmp(ArcFileName,RefList[I].RefName)==0) >+ { >+ ExtractRef *MatchedRef=&RefList[I]; >+ >+ if (!Cmd->Test) // While harmless, it is useless for 't'. >+ { >+ // If reference source isn't selected, but target is selected, >+ // we unpack the source under the temporary name and then rename >+ // or copy it to target name. We do not unpack it under the target >+ // name immediately, because the same source can be used by multiple >+ // targets and it is possible that first target isn't unpacked >+ // for some reason. Also targets might have associated service blocks >+ // like ACLs. All this would complicate processing a lot. >+ wcsncpyz(DestFileName,*Cmd->TempPath!=0 ? Cmd->TempPath:Cmd->ExtrPath,ASIZE(DestFileName)); >+ AddEndSlash(DestFileName,ASIZE(DestFileName)); >+ wcsncatz(DestFileName,L"__tmp_reference_source_",ASIZE(DestFileName)); >+ MkTemp(DestFileName,ASIZE(DestFileName)); >+ MatchedRef->TmpName=wcsdup(DestFileName); >+ } >+ RefTarget=true; // Need it even for 't' to test the reference source. >+ break; >+ } >+ > if (Arc.FileHead.Encrypted && Cmd->SkipEncrypted) > if (Arc.Solid) > return false; // Abort the entire extraction for solid archive. > else > MatchFound=false; // Skip only the current file for non-solid archive. > >- if (MatchFound || (SkipSolid=Arc.Solid)!=0) >+ if (MatchFound || RefTarget || (SkipSolid=Arc.Solid)!=0) > { > // First common call of uiStartFileExtract. It is done before overwrite > // prompts, so if SkipSolid state is changed below, we'll need to make >@@ -427,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<pwd> 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<pwd> 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;I<RefList.Size();I++) >+ if (wcscmp(RedirName,RefList[I].RefName)==0 && RefList[I].TmpName!=NULL) >+ { >+ // If only one reference left targeting to this temporary file, >+ // it is faster to move the file instead of copying and deleting it. >+ bool RefMove=RefList[I].RefCount-- == 1; >+ NameExisting=RefList[I].TmpName; >+ if (RefMove) // Only one reference left for this temporary file. >+ { >+ New.Delete(); // Delete the previously opened destination file. >+ // Try moving the file first. >+ bool MoveFailed=!RenameFile(NameExisting,NameNew); >+ if (MoveFailed) >+ { >+ // If move failed, re-create the destination and try coping. >+ if (!New.WCreate(NameNew,FMF_WRITE|FMF_SHAREREAD)) >+ return false; >+ RefMove=false; // Try copying below. >+ } >+ else >+ { >+ // If moved successfully, reopen the destination file and seek to >+ // end for SetOpenFileTime() and possible Truncate() calls later. >+ if (New.Open(NameNew)) >+ New.Seek(0,SEEK_END); >+ // We already moved the file, so clean the name to not try >+ // deleting non-existent temporary file later. >+ free(RefList[I].TmpName); >+ RefList[I].TmpName=NULL; >+ return true; >+ } >+ } >+ if (!RefMove) >+ OpenFailed=!Existing.Open(NameExisting); >+ break; >+ } >+ >+ if (OpenFailed) >+ { >+ ErrHandler.OpenErrorMsg(NameExisting); >+ uiMsg(UIERROR_FILECOPY,ArcName,NameExisting,NameNew); >+ uiMsg(UIERROR_FILECOPYHINT,ArcName); > #ifdef RARDLL >- Cmd->DllError=ERAR_EREFERENCE; >+ Cmd->DllError=ERAR_EREFERENCE; > #endif >- return false; >+ return false; >+ } > } > >- Array<char> Buffer(0x100000); >+ Array<byte> 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;I<RefList.Size();I++) >+ if (wcscmp(Arc.FileHead.RedirName,RefList[I].RefName)==0) >+ { >+ // Increment the reference count if we added such reference >+ // source earlier. >+ RefList[I].RefCount++; >+ AlreadyAdded=true; >+ break; >+ } >+ >+ // Limit the maximum size of reference sources list to some >+ // sensible value to prevent the excessive memory allocation. >+ size_t MaxListSize=1000000; >+ >+ if (!AlreadyAdded && RefList.Size()<MaxListSize) >+ { >+ ExtractRef Ref={0}; >+ Ref.RefName=wcsdup(Arc.FileHead.RedirName); >+ Ref.RefCount=1; >+ RefList.Push(Ref); >+ } >+ } > } >+ else >+ { >+ if (PrevMatched) // First non-matched item after matched. >+ { >+ // We would perform the unnecessarily string comparison >+ // when extracting if we set this value for first volume >+ // or non-volume archive. >+ if (!FirstVolume) >+ wcsncpyz(Analyze->EndName,NextName,ASIZE(Analyze->EndName)); >+ Analyze->EndPos=Arc.CurBlockPos; >+ } >+ PrevMatched=false; >+ } > } >+ >+ FirstFile=false; > if (Arc.FileHead.SplitAfter) > { > OpenNext=true; // Allow open next volume. >@@ -1316,16 +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<ExtractRef> RefList; >+ >+ struct AnalyzeData >+ { >+ wchar StartName[NM]; >+ uint64 StartPos; >+ wchar EndName[NM]; >+ uint64 EndPos; >+ } *Analyze; >+ >+ bool ArcAnalyzed; >+ >+ void FreeAnalyzeData(); > EXTRACT_ARC_CODE ExtractArchive(); >- bool ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize); >+ bool ExtractFileCopy(File &New,wchar *ArcName,const wchar *RedirName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize,int64 UnpSize); > void ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize); > #ifdef RARDLL > bool ExtrDllGetPassword(); > #else >- bool ExtrGetPassword(Archive &Arc,const wchar *ArcFileName); >+ bool ExtrGetPassword(Archive &Arc,const wchar *ArcFileName,RarCheckPassword *CheckPwd); > #endif > #if defined(_WIN_ALL) && !defined(SFX_MODULE) > void ConvertDosPassword(Archive &Arc,SecPassword &DestPwd); >@@ -21,7 +40,7 @@ > 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 <command> -<switch 1> -<switch N> <archive> <files...>" > #define MUNRARTitle1 L"\nUsage: unrar <command> -<switch 1> -<switch N> <archive> <files...>" > #define MRARTitle2 L"\n <@listfiles...> <path_to_extract\\>" >+#define MFwrSlTitle2 L"\n <@listfiles...> <path_to_extract/>" > #define MCHelpCmd L"\n\n<Commands>" > #define MCHelpCmdA L"\n a Add files to archive" > #define MCHelpCmdC L"\n c Add archive comment" >@@ -58,6 +59,7 @@ > #define MCHelpSwAD L"\n ad[1,2] Alternate destination path" > #define MCHelpSwAG L"\n ag[format] Generate archive name using the current date" > #define MCHelpSwAI L"\n ai Ignore file attributes" >+#define MCHelpSwAM L"\n am[s,r] Archive name and time [save, restore]" > #define MCHelpSwAO L"\n ao Add files with Archive attribute set" > #define MCHelpSwAP L"\n ap<path> Set path inside archive" > #define MCHelpSwAS L"\n as Synchronize archive contents" >@@ -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<path>. > wchar ExclArcPath[NM]; // For -ep4<path> 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<int64> 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 <new> >+#include <string> >+#include <vector> > > > #if defined(_WIN_ALL) || defined(_EMX) >@@ -39,8 +41,15 @@ > #define _UNICODE // Set _T() macro to convert from narrow to wide strings. > #endif > >+#if 0 >+// 2021.09.05: Allow newer Vista+ APIs like IFileOpenDialog for WinRAR, >+// but still keep SFX modules XP compatible. >+#define WINVER _WIN32_WINNT_VISTA >+#define _WIN32_WINNT _WIN32_WINNT_VISTA >+#else > #define WINVER _WIN32_WINNT_WINXP > #define _WIN32_WINNT _WIN32_WINNT_WINXP >+#endif > > #if !defined(ZIPSFX) > #define RAR_SMP >@@ -72,9 +81,6 @@ > #include <dir.h> > #endif > #ifdef _MSC_VER >- #if _MSC_VER<1500 >- #define for if (0) ; else for >- #endif > #include <direct.h> > #include <intrin.h> > >@@ -97,7 +103,6 @@ > #include <io.h> > #include <time.h> > #include <signal.h> >- > > #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<RecVolItem> 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<pwd> parameter, so we need to take into account both sizes. > memcpy(Dst,Src,Min(SrcSize,DstSize)*sizeof(*Dst)); >- SecHideData(Dst,DstSize*sizeof(*Dst),Encode,CrossProcess); >+ SecHideData(Dst,DstSize*sizeof(*Dst),Encode,false); > } > > >@@ -112,7 +112,7 @@ > { > 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<wchar> Password = std::vector<wchar>(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<MaxSize) >+ { >+ if (S!=0 && (S+3-L)%3==0) >+ Str[D++]=ThSep; >+ Str[D++]=RawText[S++]; >+ } >+ Str[D]=0; >+} >+ >+ > const wchar* GetWide(const char *Src) > { > const size_t MaxLength=NM; >diff -ur unrar-6.1.7/strfn.hpp unrar-6.2.7/strfn.hpp >--- unrar-6.1.7/strfn.hpp 2022-10-19 22:05:12 >+++ unrar-6.2.7/strfn.hpp 2023-05-14 13:10:35 >@@ -42,6 +42,7 @@ > > void itoa(int64 n,char *Str,size_t MaxSize); > void itoa(int64 n,wchar *Str,size_t MaxSize); >+void fmtitoa(int64 n,wchar *Str,size_t MaxSize); > const wchar* GetWide(const char *Src); > const wchar* GetCmdParam(const wchar *CmdLine,wchar *Param,size_t MaxSize); > #ifndef RARDLL >diff -ur unrar-6.1.7/system.cpp unrar-6.2.7/system.cpp >--- unrar-6.1.7/system.cpp 2022-10-19 22:05:12 >+++ unrar-6.2.7/system.cpp 2023-05-14 13:10:35 >@@ -187,10 +187,10 @@ > SSE_VERSION GetSSEVersion() > { > int CPUInfo[4]; >- __cpuid(CPUInfo, 0x80000000); >+ __cpuid(CPUInfo, 0); > >- // Maximum supported cpuid function. For example, Pentium M 755 returns 4 here. >- uint MaxSupported=CPUInfo[0] & 0x7fffffff; >+ // Maximum supported cpuid function. >+ uint MaxSupported=CPUInfo[0]; > > if (MaxSupported>=7) > { >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<class T1> void uiMsg(UIMESSAGE_CODE Code,T1 a1) >+template<class T1,class... TN> void uiMsgBase(uiMsgStore &Store,T1&& a1,TN&&... aN) > { >- uiMsgStore Store(Code); >+ // Process first parameter and pass the rest to same uiMsgBase. > Store<<a1; >- Store.Msg(); >+ uiMsgBase(Store,aN...); > } > >-template<class T1,class T2> void uiMsg(UIMESSAGE_CODE Code,T1 a1,T2 a2) >-{ >- uiMsgStore Store(Code); >- Store<<a1<<a2; >- Store.Msg(); >-} > >-template<class T1,class T2,class T3> void uiMsg(UIMESSAGE_CODE code,T1 a1,T2 a2,T3 a3) >+// Use variadic templates. >+// >+// We must pass variable parameters by reference, so no temporary copies are >+// created for custom string objects like CStringBase in 7-Zip decompression >+// code. Such temporary copies would be destroyed inside of recursive >+// uiMsgBase calls, leaving us with Str[] items pointing at released memory. >+// Since we pass integer values as well, we can't use & references >+// and must resort to && rvalue references. >+template<class... TN> void uiMsg(UIMESSAGE_CODE Code,TN&&... aN) > { >- uiMsgStore Store(code); >- Store<<a1<<a2<<a3; >+ uiMsgStore Store(Code); >+ uiMsgBase(Store,aN...); > Store.Msg(); > } > >diff -ur unrar-6.1.7/uicommon.cpp unrar-6.2.7/uicommon.cpp >--- unrar-6.1.7/uicommon.cpp 2022-10-19 22:05:12 >+++ unrar-6.2.7/uicommon.cpp 2023-05-14 13:10:35 >@@ -8,7 +8,7 @@ > > // Additionally to handling user input, it analyzes and sets command options. > // Returns only 'replace', 'skip' and 'cancel' codes. >-UIASKREP_RESULT uiAskReplaceEx(RAROptions *Cmd,wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags) >+UIASKREP_RESULT uiAskReplaceEx(CommandData *Cmd,wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags) > { > if (Cmd->Overwrite==OVERWRITE_NONE) > return UIASKREP_R_SKIP; >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<SrcSize;I++,Src++) >+ for (size_t I=0;I<SrcSize && I*2+1<DestSize;I++,Src++) > { > Dest[I*2]=(byte)*Src; > Dest[I*2+1]=(byte)(*Src>>8); >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)<MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr) >+ if (((WriteBorder-UnpPtr) & MaxWinMask)<=MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr) > { > UnpWriteBuf(); > if (WrittenFileSize>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->Length<ASIZE(PrevItem->Literal)-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 (Item<Border) > { > UnpPtr&=MaxWinMask; >- if (((WriteBorder-UnpPtr) & MaxWinMask)<MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr) >+ if (((WriteBorder-UnpPtr) & MaxWinMask)<=MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr) > { > UnpWriteBuf(); > if (WrittenFileSize>DestUnpSize) >@@ -461,10 +461,10 @@ > if (Item->Type==UNPDT_LITERAL) > { > #if defined(LITTLE_ENDIAN) && defined(ALLOW_MISALIGNED) >- if (Item->Length==3 && UnpPtr<MaxWinSize-4) >+ if (Item->Length==7 && UnpPtr<MaxWinSize-8) > { >- *(uint32 *)(Window+UnpPtr)=*(uint32 *)Item->Literal; >- UnpPtr+=4; >+ *(uint64 *)(Window+UnpPtr)=*(uint64 *)(Item->Literal); >+ UnpPtr+=8; > } > else > #endif >@@ -559,7 +559,7 @@ > break; > } > } >- if (((WriteBorder-UnpPtr) & MaxWinMask)<MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr) >+ if (((WriteBorder-UnpPtr) & MaxWinMask)<=MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr) > { > UnpWriteBuf(); > if (WrittenFileSize>DestUnpSize) >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); >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 46318
:
13311
| 13312 |
13350