Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package unrar for openSUSE:Factory:NonFree 
checked in at 2026-09-16 17:39:37
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory:NonFree/unrar (Old)
 and      /work/SRC/openSUSE:Factory:NonFree/.unrar.new.383539 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "unrar"

Wed Sep 16 17:39:37 2026 rev:123 rq:1378006 version:7.3.1

Changes:
--------
--- /work/SRC/openSUSE:Factory:NonFree/unrar/unrar.changes      2026-08-27 
18:47:55.144365321 +0200
+++ /work/SRC/openSUSE:Factory:NonFree/.unrar.new.383539/unrar.changes  
2026-09-16 17:39:38.526279547 +0200
@@ -1,0 +2,24 @@
+Sat Sep 12 14:20:23 UTC 2026 - Martin Pluskal <[email protected]>
+
+- Update to version 7.3.1 (upstream tarball dated 2026-09-09):
+  * New -da switch deletes the archive after successful extraction.
+  * New -ed1 switch excludes only empty directories; -ed still
+    excludes all directories and -e+d adds directories only.
+  * The v and l commands accept the a modifier without t, so va
+    and la also list service blocks and NTFS stream names.
+  * Drop the weak time-based RNG fallback: key generation now fails
+    instead of silently using predictable bytes when no randomness
+    source is available.
+  * Harden parsing against crafted archives: out-of-range RAR5
+    header and redirect types are clamped, PPM decode and ACL sizes
+    gained bounds checks, undersized REV volumes are skipped.
+  * Extracted files lose SUID/SGID and directories lose SUID for
+    non-root users, with a warning if permissions cannot be set.
+  * An existing empty folder can now be replaced by an extracted
+    file after confirmation.
+- Rename libunrar7_2_7 to libunrar7_3_1: the soname carries the full
+  version (libunrar.so.7.3.1 via soname.patch, applies with no fuzz).
+  The library API version stays at 10 and no package in Factory
+  consumes libunrar, so there is no rebuild scope.
+
+-------------------------------------------------------------------

Old:
----
  unrarsrc-7.2.7.tar.gz

New:
----
  unrarsrc-7.3.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ unrar.spec ++++++
--- /var/tmp/diff_new_pack.joC8vm/_old  2026-09-16 17:39:40.939380375 +0200
+++ /var/tmp/diff_new_pack.joC8vm/_new  2026-09-16 17:39:40.940380417 +0200
@@ -18,9 +18,9 @@
 
 # majorversion should match the major version number.
 %define majorversion 7
-%define libsuffix 7_2_7
+%define libsuffix 7_3_1
 Name:           unrar
-Version:        7.2.7
+Version:        7.3.1
 Release:        0
 Summary:        A program to extract, test, and view RAR archives
 License:        NonFree

++++++ baselibs.conf ++++++
--- /var/tmp/diff_new_pack.joC8vm/_old  2026-09-16 17:39:41.037384470 +0200
+++ /var/tmp/diff_new_pack.joC8vm/_new  2026-09-16 17:39:41.054385181 +0200
@@ -1,2 +1,2 @@
-libunrar7_2_7
+libunrar7_3_1
 

++++++ unrarsrc-7.2.7.tar.gz -> unrarsrc-7.3.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/arcread.cpp new/unrar/arcread.cpp
--- old/unrar/arcread.cpp       2026-06-27 13:35:30.000000000 +0200
+++ new/unrar/arcread.cpp       2026-09-09 15:11:09.000000000 +0200
@@ -673,7 +673,12 @@
 
   uint HeaderCRC=Raw.GetCRC50();
 
-  ShortBlock.HeaderType=(HEADER_TYPE)Raw.GetV();
+  uint64 HeaderType=Raw.GetV();
+  // Adjust values larger than maximum enum type, because they might not be
+  // able to fit to udnerlying enum data type and storing them is undefined
+  // behavior in C++.
+  ShortBlock.HeaderType=Min((HEADER_TYPE)HeaderType,HEAD_UNKNOWN);
+
   ShortBlock.Flags=(uint)Raw.GetV();
   ShortBlock.SkipIfUnknown=(ShortBlock.Flags & HFL_SKIPIFUNKNOWN)!=0;
   ShortBlock.HeadSize=HeaderSize;
@@ -1171,14 +1176,15 @@
           break;
         case FHEXTRA_REDIR:
           {
-            FILE_SYSTEM_REDIRECT RedirType=(FILE_SYSTEM_REDIRECT)Raw->GetV();
+            uint64 RedirType=Raw->GetV();
             uint Flags=(uint)Raw->GetV();
             size_t NameSize=(size_t)Raw->GetV();
 
             if (NameSize>0 && NameSize<MAXPATHSIZE)
             {
               std::string UtfName(NameSize,0);
-              hd->RedirType=RedirType;
+              hd->RedirType=RedirType<FSREDIR_UNKNOWN ?
+                (FILE_SYSTEM_REDIRECT)RedirType:FSREDIR_UNKNOWN;
               hd->DirTarget=(Flags & FHEXTRA_REDIR_DIR)!=0;
               Raw->GetB(&UtfName[0],NameSize);
               UtfToWide(&UtfName[0],hd->RedirName);
@@ -1530,7 +1536,11 @@
       return false;
   SubDataIO.UnpHash.Init(SubHead.FileHash.Type,1);
   SubDataIO.SetPackedSizeToRead(SubHead.PackSize);
+
+  // We would need to either reuse extraction DataIO or set
+  // SubDataIO.TotalArcSize to display progress.
   SubDataIO.EnableShowProgress(false);
+
   SubDataIO.SetFiles(this,DestFile);
   SubDataIO.SetTestMode(TestMode);
   SubDataIO.UnpVolume=SubHead.SplitAfter;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/cmddata.cpp new/unrar/cmddata.cpp
--- old/unrar/cmddata.cpp       2026-06-27 13:35:30.000000000 +0200
+++ new/unrar/cmddata.cpp       2026-09-09 15:11:09.000000000 +0200
@@ -11,7 +11,11 @@
 
 void CommandData::Init()
 {
-  RAROptions::Init();
+  // "*this={}" in RAROptions constructor causes the constructor to call itself
+  // infinitely, so we do it in the derived class instead.
+  *(RAROptions*)this={}; // Initialize all fields to default values.
+
+  RAROptions::Init(); // Set all non-default values.
 
   Command.clear();
   ArcName.clear();
@@ -404,9 +408,16 @@
           case 'H':
             OpenShared=true;
             break;
-          case 'F':
-            DeleteFiles=true;
+          case 'A':
+            DeleteArchive=true;
+            break;
+
+#ifdef _WIN_ALL // Need it in UnRAR too for -da switch.
+          case 'R':
+            DeleteToRecycleBin=true;
             break;
+#endif
+
           default:
             BadSwitch(Switch);
             break;
@@ -442,11 +453,11 @@
         default:
           if (Switch[1]=='+')
           {
-            InclFileAttr|=GetExclAttr(Switch+2,InclDir);
+            InclFileAttr|=GetExclAttr(Switch+2,false,DirMode);
             InclAttrSet=true;
           }
           else
-            ExclFileAttr|=GetExclAttr(Switch+1,ExclDir);
+            ExclFileAttr|=GetExclAttr(Switch+1,true,DirMode);
           break;
       }
       break;
@@ -1208,7 +1219,7 @@
 
 
 #ifndef SFX_MODULE
-uint CommandData::GetExclAttr(const wchar *Str,bool &Dir)
+uint CommandData::GetExclAttr(const wchar *Str,bool Exclude,DIR_FILTER_MODE 
&DirMode)
 {
   if (IsDigit(*Str))
     return wcstol(Str,NULL,0);
@@ -1219,7 +1230,10 @@
     switch(toupperw(*Str))
     {
       case 'D':
-        Dir=true;
+        if (Exclude)
+          DirMode=Str[1]=='1' ? DIRFM_EXCLUDE_EMPTY:DIRFM_EXCLUDE_ALL;
+        else
+          DirMode=DIRFM_DIR_ONLY;
         break;
 #ifdef _UNIX
       case 'V':
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/cmddata.hpp new/unrar/cmddata.hpp
--- old/unrar/cmddata.hpp       2026-06-27 13:35:30.000000000 +0200
+++ new/unrar/cmddata.hpp       2026-09-09 15:11:09.000000000 +0200
@@ -19,7 +19,7 @@
   private:
     void ProcessSwitch(const wchar *Switch);
     void BadSwitch(const wchar *Switch);
-    uint GetExclAttr(const wchar *Str,bool &Dir);
+    uint GetExclAttr(const wchar *Str,bool Exclude,DIR_FILTER_MODE &DirMode);
 #if !defined(SFX_MODULE)
     void SetTimeFilters(const wchar *Mod,bool Before,bool Age);
     void SetStoreTimeMode(const wchar *S);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/cmdfilter.cpp new/unrar/cmdfilter.cpp
--- old/unrar/cmdfilter.cpp     2026-06-27 13:35:30.000000000 +0200
+++ new/unrar/cmdfilter.cpp     2026-09-09 15:11:09.000000000 +0200
@@ -308,10 +308,11 @@
 #ifndef SFX_MODULE
   if (TimeCheck(FileHead.mtime,FileHead.ctime,FileHead.atime))
     return 0;
-  if ((FileHead.FileAttr & ExclFileAttr)!=0 || FileHead.Dir && ExclDir)
+  if ((FileHead.FileAttr & ExclFileAttr)!=0 ||
+      FileHead.Dir && DirMode==DIRFM_EXCLUDE_ALL)
     return 0;
   if (InclAttrSet && (FileHead.FileAttr & InclFileAttr)==0 &&
-      (!FileHead.Dir || !InclDir))
+      (!FileHead.Dir || DirMode!=DIRFM_DIR_ONLY))
     return 0;
   if (!Dir && SizeCheck(FileHead.UnpSize))
     return 0;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/cmdmix.cpp new/unrar/cmdmix.cpp
--- old/unrar/cmdmix.cpp        2026-06-27 13:35:30.000000000 +0200
+++ new/unrar/cmdmix.cpp        2026-09-09 15:11:09.000000000 +0200
@@ -62,8 +62,8 @@
     MUNRARTitle1,MRARTitle2,MCHelpCmd,MCHelpCmdE,MCHelpCmdL,
     MCHelpCmdP,MCHelpCmdT,MCHelpCmdV,MCHelpCmdX,MCHelpSw,MCHelpSwm,
     MCHelpSwAT,MCHelpSwAC,MCHelpSwAD,MCHelpSwAG,MCHelpSwAI,MCHelpSwAP,
-    MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU,MCHelpSwDH,MCHelpSwEP,
-    MCHelpSwEP3,MCHelpSwEP4,MCHelpSwF,MCHelpSwIDP,MCHelpSwIERR,
+    MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU,MCHelpSwDA,MCHelpSwDH,
+    MCHelpSwEP,MCHelpSwEP3,MCHelpSwEP4,MCHelpSwF,MCHelpSwIDP,MCHelpSwIERR,
     MCHelpSwINUL,MCHelpSwIOFF,MCHelpSwKB,MCHelpSwME,MCHelpSwMLP,
     MCHelpSwN,MCHelpSwNa,MCHelpSwNal,MCHelpSwO,MCHelpSwOC,MCHelpSwOL,
     MCHelpSwOM,MCHelpSwOP,MCHelpSwOR,MCHelpSwOW,MCHelpSwP,MCHelpSwR,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/consio.cpp new/unrar/consio.cpp
--- old/unrar/consio.cpp        2026-06-27 13:35:30.000000000 +0200
+++ new/unrar/consio.cpp        2026-09-09 15:11:09.000000000 +0200
@@ -398,6 +398,8 @@
 
 void OutComment(const std::wstring &Comment)
 {
+  // After we added Esc filtering to mprintf, this check seems to be excessive.
+  // Still keeping it for now just in case.
   if (IsCommentUnsafe(Comment))
     return;
   const size_t MaxOutSize=0x400;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/crypt.cpp new/unrar/crypt.cpp
--- old/unrar/crypt.cpp 2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/crypt.cpp 2026-09-09 15:11:09.000000000 +0200
@@ -95,21 +95,6 @@
 }
 
 
-// Use the current system time to additionally randomize data.
-static void TimeRandomize(byte *RndBuf,size_t BufSize)
-{
-  static uint Count=0;
-  RarTime CurTime;
-  CurTime.SetCurrentTime();
-  uint64 Random=CurTime.GetWin()+clock();
-  for (size_t I=0;I<BufSize;I++)
-  {
-    byte RndByte = byte (Random >> ( (I & 7) * 8 ));
-    RndBuf[I]=byte( (RndByte ^ I) + Count++);
-  }
-}
-
-
 
 
 // Fill buffer with random data.
@@ -124,14 +109,21 @@
     CryptReleaseContext(hProvider, 0);
   }
 #elif defined(_UNIX)
-  FILE *rndf = fopen("/dev/urandom", "r");
+  FILE *rndf = fopen("/dev/urandom", "rb");
   if (rndf!=NULL)
   {
-    Success=fread(RndBuf, BufSize, 1, rndf) == BufSize;
+    Success=fread(RndBuf, 1, BufSize, rndf) == BufSize;
     fclose(rndf);
   }
 #endif
-  // We use this code only as the last resort if code above failed.
   if (!Success)
-    TimeRandomize(RndBuf,BufSize);
+  {
+#if defined(_WIN_ALL)
+    const wchar *ErrMsg=L"CryptGenRandom";
+#else
+    const wchar *ErrMsg=L"/dev/urandom";
+#endif
+    if (!Success)
+      ErrHandler.OpenError(ErrMsg);
+  }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/crypt.hpp new/unrar/crypt.hpp
--- old/unrar/crypt.hpp 2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/crypt.hpp 2026-09-09 15:11:09.000000000 +0200
@@ -153,7 +153,8 @@
     bool Check(SecPassword *Password)
     {
       byte PswCheck[SIZE_PSWCHECK];
-      
Crypt->SetCryptKeys(false,CRYPT_RAR50,Password,Salt,InitV,Lg2Count,NULL,PswCheck);
+      if 
(!Crypt->SetCryptKeys(false,CRYPT_RAR50,Password,Salt,InitV,Lg2Count,NULL,PswCheck))
+        return false;
       return memcmp(PswCheck,this->PswCheck,sizeof(this->PswCheck))==0;
     }
 };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/dll.rc new/unrar/dll.rc
--- old/unrar/dll.rc    2026-06-27 12:54:34.000000000 +0200
+++ new/unrar/dll.rc    2026-09-09 15:06:35.000000000 +0200
@@ -2,8 +2,8 @@
 #include <commctrl.h>
 
 VS_VERSION_INFO VERSIONINFO
-FILEVERSION 7, 23, 100, 2007
-PRODUCTVERSION 7, 23, 100, 2007
+FILEVERSION 7, 30, 1, 2082
+PRODUCTVERSION 7, 30, 1, 2082
 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", "7.23.0\0"
-      VALUE "ProductVersion", "7.23.0\0"
-      VALUE "LegalCopyright", "Copyright � Alexander Roshal 1993-2026\0"
+      VALUE "FileVersion", "7.30.1\0"
+      VALUE "ProductVersion", "7.30.1\0"
+      VALUE "LegalCopyright", "Copyright � Alexander Roshal 1993-2026\0"
       VALUE "OriginalFilename", "Unrar.dll\0"
     }
   }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/errhnd.hpp new/unrar/errhnd.hpp
--- old/unrar/errhnd.hpp        2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/errhnd.hpp        2026-09-09 15:11:10.000000000 +0200
@@ -17,6 +17,7 @@
   RARX_BADPWD    =  11,
   RARX_READ      =  12,
   RARX_BADARC    =  13,
+  RARX_DELETE    =  14,
   RARX_USERBREAK = 255
 };
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/extinfo.cpp new/unrar/extinfo.cpp
--- old/unrar/extinfo.cpp       2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/extinfo.cpp       2026-09-09 15:11:10.000000000 +0200
@@ -51,7 +51,7 @@
   if (!Cmd->Test && Cmd->ProcessOwners && 
Arc.SubHead.CmpName(SUBHEAD_TYPE_ACL))
     ExtractACL(Arc,Name);
   if (Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM))
-    ExtractStreams(Arc,Name,Cmd->Test);
+    ExtractStreams(Cmd,Arc,Name);
 #endif
 }
 
@@ -112,7 +112,8 @@
   // Catch root dir based /path/file paths also as stuff like \\?\.
   // Do not check PrepSrcName here, it can be root based if destination path
   // is a root based.
-  if (IsFullRootPath(SrcName) || IsFullRootPath(TargetName))
+  if (IsFullRootPath(SrcName) || IsFullRootPath(TargetName) || 
+      IsDriveLetter(TargetName))
     return false;
 
   // Number of ".." in link target.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/extract.cpp new/unrar/extract.cpp
--- old/unrar/extract.cpp       2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/extract.cpp       2026-09-09 15:11:10.000000000 +0200
@@ -119,6 +119,9 @@
 
 void CmdExtract::ExtractArchiveInit(Archive &Arc)
 {
+  // We do not set the test mode it for 'P' command here, because 'P' needs
+  // to perform the actual file write to stdout and test mode prevents
+  // file write.
   if (Cmd->Command[0]=='T' || Cmd->Command[0]=='I')
     Cmd->Test=true;
 
@@ -212,6 +215,10 @@
   if (Arc.FailedHeaderDecryption) // Bad archive password.
     return EXTRACT_ARC_NEXT;
 
+#if !defined(SFX_MODULE) && !defined(RARDLL)
+   bool FirstVolume=Arc.FirstVolume; // It can be changed while extracting, so 
preserve iot here for later checks.
+#endif
+
 #ifndef SFX_MODULE
   if (Arc.Volume && !Arc.FirstVolume && !UseExactVolName)
   {
@@ -318,12 +325,72 @@
 #if !defined(SFX_MODULE) && !defined(RARDLL)
   if (Cmd->Test && Arc.Volume)
     RecVolumesTest(Cmd,&Arc,ArcName);
+
+  // Delete archive if exit code is 0 and it is either a single archive
+  // or extraction started from first volume.
+  if (Cmd->DeleteArchive && !Cmd->Test && Cmd->Command[0]!='P' &&
+      ErrHandler.GetErrorCode()==RARX_SUCCESS && (!Arc.Volume || FirstVolume))
+    DeleteArchive(Arc,ArcName);
 #endif
 
   return EXTRACT_ARC_NEXT;
 }
 
 
+#if !defined(SFX_MODULE) && !defined(RARDLL)
+void CmdExtract::DeleteArchive(Archive &Arc,const std::wstring &ArcName)
+{
+  Arc.Close();
+
+  bool DelSuccess=false;
+
+  std::wstring NextName=ArcName; // Use ArcName, because Arc.FileName can 
refer to non-first volume.
+  while (true) // First archive must exist, so we do not call 
FileExist(NextName) here.
+  {
+#ifdef _WIN_ALL
+    if (Cmd->DeleteToRecycleBin)
+      DelSuccess=RecycleFile(NextName);
+    else
+      DelSuccess=DelFile(NextName);
+#else
+    DelSuccess=DelFile(NextName);
+#endif
+    uiMsg(UIEVENT_DELADDEDFILE,NextName,(int)DelSuccess,0);
+    if (!DelSuccess || !Arc.Volume)
+      break;
+    NextVolumeName(NextName,!Arc.NewNumbering);
+    if (!FileExist(NextName))
+      break;
+  }
+  if (DelSuccess && Arc.Volume)
+  {
+    // Delete recovery volumes. RAR5 uses the width of name numeric field
+    // in REV same as in RAR, so it is enough to set .rev extension to get
+    // teh first REV name.
+    NextName=ArcName;
+    SetExt(NextName,L"rev");
+    while (FileExist(NextName)) // It is ok for REV to be missing, check here.
+    {
+#ifdef _WIN_ALL
+      if (Cmd->DeleteToRecycleBin)
+        DelSuccess=RecycleFile(NextName);
+      else
+        DelSuccess=DelFile(NextName);
+#else
+      DelSuccess=DelFile(NextName);
+#endif
+      uiMsg(UIEVENT_DELADDEDFILE,NextName,(int)DelSuccess,0);
+      if (!DelSuccess)
+        break;
+      NextVolumeName(NextName,!Arc.NewNumbering);
+    }
+  }
+  if (!DelSuccess)
+    ErrHandler.SetErrorCode(RARX_DELETE);
+}
+#endif
+
+
 bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool 
&Repeat)
 {
   wchar Command=Cmd->Command[0];
@@ -1035,11 +1102,16 @@
         
         if (SetAttr)
         {
+          auto FileAttr=Arc.FileHead.FileAttr;
 #if defined(_WIN_ALL) && !defined(SFX_MODULE)
           if (Cmd->ClearArc)
-            Arc.FileHead.FileAttr&=~FILE_ATTRIBUTE_ARCHIVE;
+            FileAttr&=~FILE_ATTRIBUTE_ARCHIVE;
 #endif
-          if (!Cmd->IgnoreGeneralAttr && 
!SetFileAttr(DestFileName,Arc.FileHead.FileAttr))
+#ifdef _UNIX
+          if (geteuid()!=0) // Unless root.
+            FileAttr &= ~(S_ISUID|S_ISGID); // Strip SUID and SGID for 
standard users.
+#endif
+          if (!Cmd->IgnoreGeneralAttr && !SetFileAttr(DestFileName,FileAttr))
           {
             uiMsg(UIERROR_FILEATTR,Arc.FileName,DestFileName);
             // Android cannot set file attributes and while UIERROR_FILEATTR
@@ -1385,7 +1457,13 @@
     return;
   }
 
-  MKDIR_CODE 
MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,Arc.FileHead.FileAttr);
+  auto FileAttr=Arc.FileHead.FileAttr;
+#ifdef _UNIX
+  if (geteuid()!=0) // Unless root.
+    FileAttr &= ~S_ISUID; // Strip SUID and keep SGID for standard users.
+#endif
+  
+  MKDIR_CODE MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,FileAttr);
   bool DirExist=false;
   if (MDCode!=MKDIR_SUCCESS)
   {
@@ -1395,13 +1473,13 @@
       // File with name same as this directory exists. Propose user
       // to overwrite it.
       bool UserReject;
-      
FileCreate(Cmd,NULL,DestFileName,&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime);
+      
FileCreate(Cmd,nullptr,DestFileName,&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime,FILECR_FOLDER);
       DirExist=false;
     }
     if (!DirExist)
     {
       CreatePath(DestFileName,true,Cmd->DisableNames);
-      
MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,Arc.FileHead.FileAttr);
+      MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,FileAttr);
       if (MDCode!=MKDIR_SUCCESS && !IsNameUsable(DestFileName))
       {
         uiMsg(UIMSG_CORRECTINGNAME,Arc.FileName);
@@ -1415,7 +1493,7 @@
             LinksToDirs(DestFileName,Cmd->ExtrPath,LastCheckedSymlink)))
         {
           CreatePath(DestFileName,true,Cmd->DisableNames);
-          
MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,Arc.FileHead.FileAttr);
+          MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,FileAttr);
         }
       }
     }
@@ -1427,13 +1505,21 @@
       mprintf(St(MCreatDir),DestFileName.c_str());
       mprintf(L" %s",St(MOk));
     }
+#ifdef _UNIX
+    // We need to set Unix attributes for DirExist as well, because Unix mkdir
+    // strips all attributes not in umask(). Archives created by recent
+    // RAR versions store directories after their contents, so risk of setting
+    // attributes, which prevent us creating files, is minimal.
+    if (!Cmd->IgnoreGeneralAttr)
+      SetFileAttr(DestFileName,FileAttr);
+#endif
     PrevProcessed=true;
   }
   else
     if (DirExist)
     {
       if (!Cmd->IgnoreGeneralAttr)
-        SetFileAttr(DestFileName,Arc.FileHead.FileAttr);
+        SetFileAttr(DestFileName,FileAttr);
       PrevProcessed=true;
     }
     else
@@ -1449,7 +1535,7 @@
   {
 #if defined(_WIN_ALL) && !defined(SFX_MODULE)
     if (Cmd->SetCompressedAttr &&
-        (Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && 
WinNT()!=WNT_NONE)
+        (FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT()!=WNT_NONE)
       SetFileCompression(DestFileName,true);
 #endif
     SetFileHeaderExtra(Cmd,Arc,DestFileName);
@@ -1471,8 +1557,9 @@
 #endif
   if ((Command=='E' || Command=='X') && !Cmd->Test)
   {
+    FILECR_FLAGS Flags=WriteOnly ? FILECR_WRITEONLY:FILECR_DEFAULT;
     bool UserReject;
-    if 
(!FileCreate(Cmd,&CurFile,DestFileName,&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime,WriteOnly))
+    if 
(!FileCreate(Cmd,&CurFile,DestFileName,&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime,Flags))
     {
       Success=false;
       if (!UserReject)
@@ -1496,7 +1583,7 @@
               LinksToDirs(DestFileName,Cmd->ExtrPath,LastCheckedSymlink))
           {
             CreatePath(DestFileName,true,Cmd->DisableNames);
-            if 
(FileCreate(Cmd,&CurFile,DestFileName,&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime,true))
+            if 
(FileCreate(Cmd,&CurFile,DestFileName,&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime,Flags))
             {
 #ifndef SFX_MODULE
               uiMsg(UIERROR_RENAMING,Arc.FileName,OrigName,DestFileName);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/extract.hpp new/unrar/extract.hpp
--- old/unrar/extract.hpp       2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/extract.hpp       2026-09-09 15:11:10.000000000 +0200
@@ -44,6 +44,9 @@
     void GetFirstVolIfFullSet(const std::wstring &SrcName,bool 
NewNumbering,std::wstring &DestName);
 #endif
     bool CheckWinLimit(Archive &Arc,std::wstring &ArcFileName);
+#if !defined(SFX_MODULE) && !defined(RARDLL)
+    void DeleteArchive(Archive &Arc,const std::wstring &ArcName);
+#endif
 
     RarTime StartTime; // Time when extraction started.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/filcreat.cpp new/unrar/filcreat.cpp
--- old/unrar/filcreat.cpp      2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/filcreat.cpp      2026-09-09 15:11:10.000000000 +0200
@@ -1,11 +1,13 @@
 #include "rar.hpp"
 
-// 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.
+// If NewFile==NULL, we delete existing file or folder after user confirmation
+// without creating a new folder. It is useful when user needs to confirm
+// overwriting an existing file or folder to create a folder or link.
 bool FileCreate(CommandData *Cmd,File *NewFile,std::wstring &Name,
-                bool *UserReject,int64 FileSize,RarTime *FileTime,bool 
WriteOnly)
+                bool *UserReject,int64 FileSize,RarTime *FileTime,
+                FILECR_FLAGS Flags)
 {
+  bool WriteOnly=(Flags & FILECR_WRITEONLY)!=0;
   if (UserReject!=NULL)
     *UserReject=false;
 #ifdef _WIN_ALL
@@ -29,7 +31,12 @@
     // autorename below can change the name, so we need to check it again.
     ShortNameChanged=false;
 #endif
-    UIASKREP_RESULT 
Choice=uiAskReplaceEx(Cmd,Name,FileSize,FileTime,(NewFile==NULL ? 
UIASKREP_F_NORENAME:0));
+
+    // Hide "Rename" button if source file isn't defined.
+    uint AskRepFlags=(NewFile==nullptr ? UIASKREP_F_NORENAME:0);
+    if ((Flags & FILECR_FOLDER)!=0)
+      AskRepFlags|=UIASKREP_F_SRCFOLDER; // Source is folder.
+    UIASKREP_RESULT 
Choice=uiAskReplaceEx(Cmd,Name,FileSize,FileTime,(UIASKREP_FLAGS)AskRepFlags);
 
     if (Choice==UIASKREP_R_REPLACE)
       break;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/filcreat.hpp new/unrar/filcreat.hpp
--- old/unrar/filcreat.hpp      2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/filcreat.hpp      2026-09-09 15:11:10.000000000 +0200
@@ -1,9 +1,16 @@
 #ifndef _RAR_FILECREATE_
 #define _RAR_FILECREATE_
 
+enum FILECR_FLAGS
+{
+  FILECR_DEFAULT   = 0, // Default mode.
+  FILECR_WRITEONLY = 1, // Create a file in write only mode.
+  FILECR_FOLDER    = 2, // Delete the existing file, so caller can create a 
folder.
+};
+
 bool FileCreate(CommandData *Cmd,File *NewFile,std::wstring &Name,
                 bool *UserReject,int64 FileSize=INT64NDF,
-                RarTime *FileTime=NULL,bool WriteOnly=false);
+                RarTime *FileTime=nullptr,FILECR_FLAGS Flags=FILECR_DEFAULT);
 
 #if defined(_WIN_ALL)
 bool UpdateExistingShortName(const std::wstring &Name);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/filefn.cpp new/unrar/filefn.cpp
--- old/unrar/filefn.cpp        2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/filefn.cpp        2026-09-09 15:11:10.000000000 +0200
@@ -508,6 +508,19 @@
 
 
 #if defined(_WIN_ALL) && !defined(SFX_MODULE)
+bool RecycleFile(std::wstring &Name)
+{
+  Name.push_back(L'\0'); // SHFileOperation expects the name to end with \0\0.
+  SHFILEOPSTRUCT fop{};
+  fop.wFunc=FO_DELETE;
+  fop.fFlags=FOF_NOCONFIRMATION|FOF_SILENT|FOF_ALLOWUNDO;
+  fop.pFrom=Name.c_str();
+  return SHFileOperation(&fop)==0;
+}
+#endif
+
+
+#if defined(_WIN_ALL) && !defined(SFX_MODULE)
 bool SetFileCompression(const std::wstring &Name,bool State)
 {
   HANDLE hFile=CreateFile(Name.c_str(),FILE_READ_DATA|FILE_WRITE_DATA,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/filefn.hpp new/unrar/filefn.hpp
--- old/unrar/filefn.hpp        2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/filefn.hpp        2026-09-09 15:11:10.000000000 +0200
@@ -42,6 +42,7 @@
 bool DelDir(const std::wstring &Name);
 
 #if defined(_WIN_ALL) && !defined(SFX_MODULE)
+bool RecycleFile(std::wstring &Name);
 bool SetFileCompression(const std::wstring &Name,bool State);
 bool SetFileCompression(HANDLE hFile,bool State);
 void ResetFileCache(const std::wstring &Name);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/find.cpp new/unrar/find.cpp
--- old/unrar/find.cpp  2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/find.cpp  2026-09-09 15:11:10.000000000 +0200
@@ -37,13 +37,9 @@
     return false;
 #ifdef _WIN_ALL
   if (FirstCall)
-  {
-    if 
((hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,fd))==INVALID_HANDLE_VALUE)
-      return false;
-  }
-  else
-    if (Win32Find(hFind,FindMask,fd)==INVALID_HANDLE_VALUE)
-      return false;
+    hFind=INVALID_HANDLE_VALUE;
+  if (!Win32Find(hFind,FindMask,fd))
+    return false;
 #else
   if (FirstCall)
   {
@@ -111,8 +107,8 @@
     return false;
 #endif    
 #ifdef _WIN_ALL
-  HANDLE hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,fd);
-  if (hFind==INVALID_HANDLE_VALUE)
+  HANDLE hFind=INVALID_HANDLE_VALUE;
+  if (!Win32Find(hFind,FindMask,fd))
     return false;
   FindClose(hFind);
 #elif defined(_UNIX)
@@ -154,10 +150,12 @@
 
 
 #ifdef _WIN_ALL
-HANDLE FindFile::Win32Find(HANDLE hFind,const std::wstring &Mask,FindData *fd)
+bool FindFile::Win32Find(HANDLE &hFind,const std::wstring &Mask,FindData *fd)
 {
+  fd->Flags=0;
+
   WIN32_FIND_DATA FindData;
-  if (hFind==INVALID_HANDLE_VALUE)
+  if (hFind==INVALID_HANDLE_VALUE) // If first call.
   {
     hFind=FindFirstFile(Mask.c_str(),&FindData);
     if (hFind==INVALID_HANDLE_VALUE)
@@ -177,32 +175,31 @@
       fd->Error=SysErr!=ERROR_FILE_NOT_FOUND && 
                 SysErr!=ERROR_PATH_NOT_FOUND &&
                 SysErr!=ERROR_NO_MORE_FILES;
+      return false;
     }
   }
   else
     if (!FindNextFile(hFind,&FindData))
     {
+      FindClose(hFind);
       hFind=INVALID_HANDLE_VALUE;
       fd->Error=GetLastError()!=ERROR_NO_MORE_FILES;
+      return false;
     }
 
-  if (hFind!=INVALID_HANDLE_VALUE)
-  {
-    fd->Name=Mask;
-    SetName(fd->Name,FindData.cFileName);
-    fd->Size=INT32TO64(FindData.nFileSizeHigh,FindData.nFileSizeLow);
-    fd->FileAttr=FindData.dwFileAttributes;
-    fd->ftCreationTime=FindData.ftCreationTime;
-    fd->ftLastAccessTime=FindData.ftLastAccessTime;
-    fd->ftLastWriteTime=FindData.ftLastWriteTime;
-    fd->mtime.SetWinFT(&FindData.ftLastWriteTime);
-    fd->ctime.SetWinFT(&FindData.ftCreationTime);
-    fd->atime.SetWinFT(&FindData.ftLastAccessTime);
+  fd->Name=Mask;
+  SetName(fd->Name,FindData.cFileName);
+  fd->Size=INT32TO64(FindData.nFileSizeHigh,FindData.nFileSizeLow);
+  fd->FileAttr=FindData.dwFileAttributes;
+  fd->ftCreationTime=FindData.ftCreationTime;
+  fd->ftLastAccessTime=FindData.ftLastAccessTime;
+  fd->ftLastWriteTime=FindData.ftLastWriteTime;
+  fd->mtime.SetWinFT(&FindData.ftLastWriteTime);
+  fd->ctime.SetWinFT(&FindData.ftCreationTime);
+  fd->atime.SetWinFT(&FindData.ftLastAccessTime);
 
 
-  }
-  fd->Flags=0;
-  return hFind;
+  return true;
 }
 #endif
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/find.hpp new/unrar/find.hpp
--- old/unrar/find.hpp  2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/find.hpp  2026-09-09 15:11:10.000000000 +0200
@@ -28,7 +28,7 @@
 {
   private:
 #ifdef _WIN_ALL
-    static HANDLE Win32Find(HANDLE hFind,const std::wstring &Mask,FindData 
*fd);
+    static bool Win32Find(HANDLE &hFind,const std::wstring &Mask,FindData *fd);
 #endif
 
     std::wstring FindMask;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/headers.hpp new/unrar/headers.hpp
--- old/unrar/headers.hpp       2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/headers.hpp       2026-09-09 15:11:10.000000000 +0200
@@ -73,7 +73,8 @@
 #define  EARC_VOLNUMBER     0x0008U // Store a number of current volume.
 
 enum HEADER_TYPE {
-  // RAR 5.0 header types.
+  // RAR 5.0 header types. HEAD_UNKNOWN must be maximum value in enum,
+  // because we reject anything larger than it.
   HEAD_MARK=0x00, HEAD_MAIN=0x01, HEAD_FILE=0x02, HEAD_SERVICE=0x03,
   HEAD_CRYPT=0x04, HEAD_ENDARC=0x05, HEAD_UNKNOWN=0xff,
 
@@ -106,9 +107,11 @@
 
 
 // We also use these values in extra field, so do not modify them.
+// FSREDIR_UNKNOWN must be maximum value in enum, because we reject
+// anything larger than it.
 enum FILE_SYSTEM_REDIRECT {
   FSREDIR_NONE=0, FSREDIR_UNIXSYMLINK, FSREDIR_WINSYMLINK, FSREDIR_JUNCTION,
-  FSREDIR_HARDLINK, FSREDIR_FILECOPY
+  FSREDIR_HARDLINK, FSREDIR_FILECOPY, FSREDIR_UNKNOWN
 };
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/largepage.cpp new/unrar/largepage.cpp
--- old/unrar/largepage.cpp     2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/largepage.cpp     2026-09-09 15:11:10.000000000 +0200
@@ -132,7 +132,11 @@
     return false;
 
   PSID UserSid;
-  ConvertStringSidToSid(Sid.c_str(),&UserSid);
+  if (ConvertStringSidToSid(Sid.c_str(),&UserSid)==0)
+  {
+    LsaClose(PolicyHandle);
+    return false;
+  }
 
   LSA_UNICODE_STRING LsaString;
   LsaString.Buffer=(PWSTR)SE_LOCK_MEMORY_NAME;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/list.cpp new/unrar/list.cpp
--- old/unrar/list.cpp  2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/list.cpp  2026-09-09 15:11:10.000000000 +0200
@@ -9,10 +9,18 @@
 {
   int64 SumPackSize=0,SumUnpSize=0;
   uint ArcCount=0,SumFileCount=0;
-  bool Technical=(Cmd->Command[1]=='T');
-  bool ShowService=Technical && Cmd->Command[2]=='A';
-  bool Bare=(Cmd->Command[1]=='B');
-  bool Verbose=(Cmd->Command[0]=='V');
+
+  bool Verbose=(Cmd->Command[0]=='V'); // "v" command.
+
+  bool Technical=false;   // "vt" or "lt" technical details.
+  bool Bare=false;        // "vb" or "lb" bare output.
+  bool ShowService=false; // "va" or "vta" include service blocks.
+  for (wchar Ch : Cmd->Command)
+  {
+    Bare|=(Ch=='B');
+    Technical|=(Ch=='T');
+    ShowService|=(Ch=='A');
+  }
 
   std::wstring ArcName;
   while (Cmd->GetArcName(ArcName))
@@ -118,13 +126,13 @@
               // want to see service blocks only in this case.
               if (!Arc.SubHead.SubBlock || Cmd->DisableNames)
                 
FileMatched=Cmd->IsProcessFile(Arc.SubHead,NULL,MATCH_WILDSUBPATH,0,NULL)!=0;
-              if (FileMatched && !Bare)
+              if (FileMatched)
               {
                 // Here we set DisableNames parameter to true regardless of
                 // Cmd->DisableNames. If "vta -idn" are set together, user
                 // wants to see service blocks like RR only.
-                if (Technical && ShowService)
-                  
ListFileHeader(Arc,Arc.SubHead,TitleShown,Verbose,true,false,false);
+                if (Technical || ShowService)
+                  
ListFileHeader(Arc,Arc.SubHead,TitleShown,Verbose,Technical,Bare,false);
               }
               break;
           }
@@ -230,9 +238,15 @@
   const wchar *Name=hd.FileName.c_str();
   RARFORMAT Format=Arc.Format;
 
-  if (Bare)
+  bool FileBlock=hd.HeaderType==HEAD_FILE;
+
+  std::wstring StreamName; // NTFS stream name.
+  if (!FileBlock && Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM))
+    StreamName=GetStreamNameNTFS(Arc);
+
+  if (Bare) // Bare "vb" list mode.
   {
-    mprintf(L"%s\n",Name);
+    mprintf(L"%s%s\n",Name,StreamName.c_str()); // Print file name and NTFS 
stream name, if present.
     return;
   }
 
@@ -263,18 +277,18 @@
         
swprintf(RatioStr,ASIZE(RatioStr),L"%u%%",ToPercentUnlim(hd.PackSize,hd.UnpSize));
 
   wchar DateStr[50];
-  hd.mtime.GetText(DateStr,ASIZE(DateStr),Technical);
+  if (hd.mtime.IsSet())
+    hd.mtime.GetText(DateStr,ASIZE(DateStr),Technical);
+  else
+    wcsncpyz(DateStr,L"                ",ASIZE(DateStr));
 
   if (Technical)
   {
     mprintf(L"\n%12s: %s",St(MListName),Name);
 
-    bool FileBlock=hd.HeaderType==HEAD_FILE;
-
-    if (!FileBlock && Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM))
+    if (!StreamName.empty())
     {
       mprintf(L"\n%12ls: %ls",St(MListType),St(MListStream));
-      std::wstring StreamName=GetStreamNameNTFS(Arc);
       mprintf(L"\n%12ls: %ls",St(MListTarget),StreamName.c_str());
     }
     else
@@ -451,9 +465,12 @@
         mprintf(L"%02x%02x..%02x  ",S[0],S[1],S[31]);
       }
       else
-        mprintf(hd.Dir ? L"          ":L"????????  "); // Missing checksum is 
ok for folder, not for file.
+        mprintf(L"          "); // Missing checksum, such as for folders or 
service blocks.
   }
   mprintf(L"%ls",Name);
+
+  if (!StreamName.empty()) // Print NTFS stream name in non-technical "va" 
list mode.
+    mprintf(L"%ls",StreamName.c_str());
 }
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/loclang.hpp new/unrar/loclang.hpp
--- old/unrar/loclang.hpp       2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/loclang.hpp       2026-09-09 15:11:10.000000000 +0200
@@ -57,7 +57,7 @@
 #define   MCHelpCmdS         L"\n  s[name|-]     Convert archive to or from 
SFX"
 #define   MCHelpCmdT         L"\n  t             Test archive files"
 #define   MCHelpCmdU         L"\n  u             Update files in archive"
-#define   MCHelpCmdV         L"\n  v[t[a],b]     Verbosely list archive 
contents [technical[all],bare]"
+#define   MCHelpCmdV         L"\n  v[a,b,t]      Verbosely list archive 
contents [all,bare,technical]"
 #define   MCHelpCmdX         L"\n  x             Extract files with full path"
 #define   MCHelpSw           L"\n\n<Switches>"
 #define   MCHelpSwm          L"\n  -             Stop switches scanning"
@@ -74,13 +74,14 @@
 #define   MCHelpSwCFGm       L"\n  cfg-          Disable read configuration"
 #define   MCHelpSwCL         L"\n  cl            Convert names to lower case"
 #define   MCHelpSwCU         L"\n  cu            Convert names to upper case"
+#define   MCHelpSwDA         L"\n  da            Delete archive after 
extraction"
 #define   MCHelpSwDF         L"\n  df            Delete files after archiving"
 #define   MCHelpSwDH         L"\n  dh            Open shared files"
 #define   MCHelpSwDR         L"\n  dr            Delete files to Recycle Bin"
 #define   MCHelpSwDS         L"\n  ds            Disable name sort for solid 
archive"
 #define   MCHelpSwDW         L"\n  dw            Wipe files after archiving"
 #define   MCHelpSwEa         L"\n  e[+]<attr>    Set file exclude and include 
attributes"
-#define   MCHelpSwED         L"\n  ed            Do not add empty directories"
+#define   MCHelpSwED         L"\n  ed[1]         Exclude directories [empty 
only]"
 #define   MCHelpSwEP         L"\n  ep            Exclude paths from names"
 #define   MCHelpSwEP1        L"\n  ep1           Exclude base directory from 
names"
 #define   MCHelpSwEP2        L"\n  ep2           Expand paths to full"
@@ -145,7 +146,7 @@
 #define   MCHelpSwTS         L"\n  ts[m,c,a,p]   Save or restore time 
(modification, creation, access, preserve)"
 #define   MCHelpSwU          L"\n  u             Update files"
 #define   MCHelpSwV          L"\n  v             Create volumes with size 
autodetection or list all volumes"
-#define   MCHelpSwVUnr       L"\n  v             List all volumes"
+#define   MCHelpSwVUnr       L"\n  v             Apply list command to all 
volumes"
 #define   MCHelpSwVn         L"\n  v<size>[u]    Create volumes with size in 
[bBkKmMgGtT] units"
 #define   MCHelpSwVD         L"\n  vd            Erase disk contents before 
creating volume"
 #define   MCHelpSwVER        L"\n  ver[n]        File version control"
@@ -350,6 +351,7 @@
 #define   MNTFSRequired      L"\nWrite error: only NTFS file system supports 
files larger than 4 GB"
 #define   MFAT32Size         L"\nWARNING: FAT32 file system does not support 4 
GB or larger files"
 #define   MErrChangeAttr     L"\nWARNING: Cannot change attributes of %s"
+#define   MErrChangePerm     L"\nWARNING: Cannot change permissions of %s"
 #define   MWrongSFXVer       L"\nERROR: default SFX module does not support 
RAR %d.%d archives"
 #define   MHeadEncMismatch   L"\nCannot change the header encryption mode in 
already encrypted archive"
 #define   MCannotEmail       L"\nCannot email the file %s"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/match.cpp new/unrar/match.cpp
--- old/unrar/match.cpp 2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/match.cpp 2026-09-09 15:11:10.000000000 +0200
@@ -23,8 +23,8 @@
 
   CmpMode&=MATCH_MODEMASK;
 
-  wchar *Name1=PointToName(Wildcard);
-  wchar *Name2=PointToName(Name);
+  const wchar *Name1=PointToName(Wildcard);
+  const wchar *Name2=PointToName(Name);
 
   if (CmpMode!=MATCH_NAMES)
   {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/model.cpp new/unrar/model.cpp
--- old/unrar/model.cpp 2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/model.cpp 2026-09-09 15:11:10.000000000 +0200
@@ -489,6 +489,8 @@
 
 inline bool RARPPM_CONTEXT::decodeSymbol2(ModelPPM *Model)
 {
+  if (Model->NumMasked > NumStats) // 2026.07.24: extra security check.
+    return false;
   int count, HiCnt, i=NumStats-Model->NumMasked;
   RARPPM_SEE2_CONTEXT* psee2c=makeEscFreq2(Model,i);
   RARPPM_STATE* ps[256], ** pps=ps, * p=U.Stats-1;
@@ -498,6 +500,12 @@
     do 
     { 
       p++; 
+
+      // 2026.07.24: Ensure we don't read beyond the state array bounds.
+      // This check might be excessive, but we keep it for extra safety.
+      if (p >= U.Stats + NumStats)
+        return false;  // 'p' is at or past end of valid states.
+
     } while (Model->CharMask[p->Symbol] == Model->EscCount);
     HiCnt += p->Freq;
 
@@ -511,7 +519,7 @@
   Model->Coder.SubRange.scale += HiCnt;
   count=Model->Coder.GetCurrentCount();
   if (count>=(int)Model->Coder.SubRange.scale)
-    return(false);
+    return false;
   p=*(pps=ps);
   if (count < HiCnt) 
   {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/motw.cpp new/unrar/motw.cpp
--- old/unrar/motw.cpp  2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/motw.cpp  2026-09-09 15:11:10.000000000 +0200
@@ -57,14 +57,21 @@
 int MarkOfTheWeb::ParseZoneIdStream(std::string &Stream)
 {
   if (!starts_with(Stream,"[ZoneTransfer]"))
-    return -1; // Not a valid Mark of the Web. Prefer the archive MOTW if any.
+    return -1; // Not a valid Mark of the Web. Prefer the archive MOTW, if any.
 
   std::string::size_type ZoneId=Stream.find("ZoneId=",0);
   if (ZoneId==std::string::npos || !IsDigit(Stream[ZoneId+7]))
     return -1; // Not a valid Mark of the Web.
+  char E=Stream[ZoneId+8];
+  if (E!=0 && E!=' ' && E!='\t' && E!='\r' && E!='\n')
+    return -1; // Not a valid Mark of the Web.
+
   int ZoneIdValue=atoi(&Stream[ZoneId+7]);
   if (ZoneIdValue<0 || ZoneIdValue>4)
     return -1; // Not a valid Mark of the Web.
+  std::string::size_type ZoneId2=Stream.find("ZoneId=",ZoneId+8);
+  if (ZoneId2!=std::string::npos)
+    return -1; // Not a valid Mark of the Web.
 
   if (!AllFields)
     Stream="[ZoneTransfer]\r\nZoneId=" + std::to_string(ZoneIdValue) + "\r\n";
@@ -126,7 +133,8 @@
 
 
 // Return true and prepare the file stream to write if its ZoneId is stricter
-// than archive ZoneId. If it is missing, less or equally strict, return false.
+// than archive ZoneId. If it is missing, broken, less or equally strict,
+// return false and prefer an archive MOTW.
 bool MarkOfTheWeb::IsFileStreamMoreSecure(std::string &FileStream)
 {
   int StreamZone=ParseZoneIdStream(FileStream);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/motw.hpp new/unrar/motw.hpp
--- old/unrar/motw.hpp  2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/motw.hpp  2026-09-09 15:11:10.000000000 +0200
@@ -4,7 +4,7 @@
 class MarkOfTheWeb
 {
   private:
-    const size_t MOTW_STREAM_MAX_SIZE=1024;
+    const size_t MOTW_STREAM_MAX_SIZE=4096;
     const wchar* MOTW_STREAM_NAME=L":Zone.Identifier"; // Must start from ':'.
 
     int ParseZoneIdStream(std::string &Stream);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/options.cpp new/unrar/options.cpp
--- old/unrar/options.cpp       2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/options.cpp       2026-09-09 15:11:10.000000000 +0200
@@ -1,14 +1,9 @@
 #include "rar.hpp"
 
-RAROptions::RAROptions()
-{
-  Init();
-}
-
-
+// Set all non-default values here.
+// Default values are set from CommandData::Init().
 void RAROptions::Init()
 {
-  memset(this,0,sizeof(RAROptions));
   WinSize=0x2000000;
   WinSizeLimit=0x100000000;
   Overwrite=OVERWRITE_DEFAULT;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/options.hpp new/unrar/options.hpp
--- old/unrar/options.hpp       2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/options.hpp       2026-09-09 15:11:10.000000000 +0200
@@ -15,6 +15,15 @@
   EXCL_ABSPATH         // -ep3 (the full path with the disk letter)
 };
 
+
+enum DIR_FILTER_MODE
+{
+  DIRFM_INCLUDE_ALL=0, // Include all directories (default).
+  DIRFM_EXCLUDE_ALL,   // -ed,  exclude all directories.
+  DIRFM_EXCLUDE_EMPTY, // -ed1, exclude empty directories.
+  DIRFM_DIR_ONLY       // -e+d  add directories only, skip files.
+};
+
 enum {
   SOLID_NONE=0,    // Non-solid mode.
   SOLID_NORMAL=1,  // Standard solid mode.
@@ -104,22 +113,22 @@
 #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.
+// Store here those types, which we want to initialize all at once
+// from CommandData::Init(). Initializing them from own constructor using
+// *this={} falls into infinite recursion and we do not want to use memset
+// assuming POD types only, so we utilize the derived CommandData class.
 class RAROptions
 {
   public:
-    RAROptions();
     void Init();
 
 
     uint ExclFileAttr;
     uint InclFileAttr;
 
-    // We handle -ed and -e+d with special flags instead of attribute mask,
-    // so it works with both Windows and Unix archives.
-    bool ExclDir;
-    bool InclDir;
+    // We handle -ed and -e+d with the dedicated variable instead of attribute
+    // mask, so it works with both Windows and Unix archives.
+    DIR_FILTER_MODE DirMode;
 
     bool InclAttrSet;
     uint64 WinSize;
@@ -186,9 +195,10 @@
 
     bool KeepBroken;
     bool OpenShared;
-    bool DeleteFiles;
+    bool DeleteArchive;
 
 #ifdef _WIN_ALL
+    bool DeleteToRecycleBin;
     bool AllowIncompatNames; // Allow names with trailing dots and spaces.
 #endif
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/os.hpp new/unrar/os.hpp
--- old/unrar/os.hpp    2026-06-27 13:35:31.000000000 +0200
+++ new/unrar/os.hpp    2026-09-09 15:11:10.000000000 +0200
@@ -38,8 +38,6 @@
 #define _UNICODE // Set _T() macro to convert from narrow to wide strings.
 #endif
 
-#define WINVER _WIN32_WINNT_WINXP
-#define _WIN32_WINNT _WIN32_WINNT_WINXP
 
 #if !defined(ZIPSFX)
 #define RAR_SMP
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/pathfn.cpp new/unrar/pathfn.cpp
--- old/unrar/pathfn.cpp        2026-06-27 13:35:32.000000000 +0200
+++ new/unrar/pathfn.cpp        2026-09-09 15:11:10.000000000 +0200
@@ -1,11 +1,11 @@
 #include "rar.hpp"
 
-wchar* PointToName(const wchar *Path)
+const wchar* PointToName(const wchar *Path)
 {
   for (int I=(int)wcslen(Path)-1;I>=0;I--)
     if (IsPathDiv(Path[I]))
       return (wchar*)&Path[I+1];
-  return (wchar*)((*Path!=0 && IsDriveDiv(Path[1])) ? Path+2:Path);
+  return *Path!=0 && IsDriveDiv(Path[1]) ? Path+2:Path;
 }
 
 
@@ -126,7 +126,7 @@
 
 
 // 'Ext' is an extension with the leading dot, like L".rar".
-wchar *GetExt(const wchar *Name)
+const wchar *GetExt(const wchar *Name)
 {
   return Name==NULL ? NULL:wcsrchr(PointToName(Name),'.');
 }
@@ -281,9 +281,15 @@
 #if defined(_WIN_ALL)
 bool SHGetPathStrFromIDList(PCIDLIST_ABSOLUTE pidl,std::wstring &Path)
 {
-  std::vector<wchar> Buf(MAX_PATH);
-  bool Success=SHGetPathFromIDList(pidl,Buf.data())!=FALSE;
-  Path=Buf.data();
+  // Allocate size enough for both SHGetPathFromIDList and its *Ex version.
+  std::vector<wchar> Buf(Max(MAXPATHSIZE,MAX_PATH));
+#if _WIN32_WINNT >= _WIN32_WINNT_VISTA // Vista+.
+  bool 
Success=SHGetPathFromIDListEx(pidl,Buf.data(),(DWORD)Buf.size(),0)!=FALSE;
+#else
+  bool Success=SHGetPathFromIDList(pidl,Buf.data())!=FALSE; // XP, limited to 
260 chars.
+#endif
+  if (Success)
+    Path=Buf.data();
   return Success;
 }
 #endif
@@ -306,8 +312,8 @@
       std::vector<wchar> PathBuf(DataSize/sizeof(wchar));
       RegQueryValueEx(hKey,L"AppData",0,NULL,(BYTE *)PathBuf.data(),&DataSize);
       Path=PathBuf.data();
-      RegCloseKey(hKey);
     }
+    RegCloseKey(hKey);
   }
 
   if (Path.empty() || !FileExist(Path))
@@ -1192,7 +1198,7 @@
 {
   HMODULE hModule=nullptr;
   
-  std::vector<wchar> Path(256);
+  std::vector<wchar> Path(MAX_PATH);
   while (Path.size()<=MAXPATHSIZE)
   {
     if (GetModuleFileName(hModule,Path.data(),(DWORD)Path.size())<Path.size())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/pathfn.hpp new/unrar/pathfn.hpp
--- old/unrar/pathfn.hpp        2026-06-27 13:35:32.000000000 +0200
+++ new/unrar/pathfn.hpp        2026-09-09 15:11:10.000000000 +0200
@@ -1,7 +1,7 @@
 #ifndef _RAR_PATHFN_
 #define _RAR_PATHFN_
 
-wchar* PointToName(const wchar *Path);
+const wchar* PointToName(const wchar *Path);
 std::wstring PointToName(const std::wstring &Path);
 size_t GetNamePos(const std::wstring &Path);
 wchar* PointToLastChar(const wchar *Path);
@@ -11,7 +11,7 @@
 void SetExt(std::wstring &Name,std::wstring NewExt);
 void RemoveExt(std::wstring &Name);
 void SetSFXExt(std::wstring &SFXName);
-wchar *GetExt(const wchar *Name);
+const wchar *GetExt(const wchar *Name);
 std::wstring GetExt(const std::wstring &Name);
 std::wstring::size_type GetExtPos(const std::wstring &Name);
 bool CmpExt(const std::wstring &Name,const std::wstring &Ext);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/rar.cpp new/unrar/rar.cpp
--- old/unrar/rar.cpp   2026-06-27 13:35:32.000000000 +0200
+++ new/unrar/rar.cpp   2026-09-09 15:11:11.000000000 +0200
@@ -59,7 +59,7 @@
     }
     Cmd->AddArcName(ModuleName);
     Cmd->ParseDone();
-    Cmd->AbsoluteLinks=true; // If users runs SFX, he trusts an archive source.
+    Cmd->AbsoluteLinks=true; // If users run SFX, they trust an archive source.
 #else // !SFX_MODULE
     Cmd->ParseCommandLine(true,argc,argv);
     if (!Cmd->ConfigDisabled)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/rawread.cpp new/unrar/rawread.cpp
--- old/unrar/rawread.cpp       2026-06-27 13:35:32.000000000 +0200
+++ new/unrar/rawread.cpp       2026-09-09 15:11:11.000000000 +0200
@@ -191,11 +191,11 @@
 
 
 // Read vint from arbitrary byte array.
-uint64 RawGetV(const byte *Data,uint &ReadPos,uint DataSize,bool &Overflow)
+uint64 RawGetV(const byte *Data,uint &ReadPos,uint EndPos,bool &Overflow)
 {
   Overflow=false;
   uint64 Result=0;
-  for (uint Shift=0;ReadPos<DataSize;Shift+=7)
+  for (uint Shift=0;ReadPos<EndPos;Shift+=7)
   {
     byte CurByte=Data[ReadPos++];
     Result+=uint64(CurByte & 0x7f)<<Shift;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/recvol3.cpp new/unrar/recvol3.cpp
--- old/unrar/recvol3.cpp       2026-06-27 13:35:32.000000000 +0200
+++ new/unrar/recvol3.cpp       2026-09-09 15:11:11.000000000 +0200
@@ -122,6 +122,9 @@
   RecVolMask.replace(VolNumStart,std::wstring::npos,L"*.rev");
   size_t BaseNamePartLength=VolNumStart;
 
+  if (BaseNamePartLength==0)
+    return false;
+
   int64 RecFileSize=0;
 
   // We cannot display "Calculating CRC..." message here, because we do not
@@ -171,6 +174,13 @@
       CurFile.TOpen(CurName);
       CurFile.Seek(0,SEEK_END);
       int64 Length=CurFile.Tell();
+
+      if (Length<7) // Too small to be valid, skip to avoid seek error below.
+      {
+        uiMsg(UIERROR_NOTVOLUME,CurName);
+        continue;
+      }
+
       CurFile.Seek(Length-7,SEEK_SET);
       for (int I=0;I<3;I++)
         P[2-I]=CurFile.GetByte()+1;
@@ -221,7 +231,19 @@
     // checks above. Still we keep it here for better clarity and security.
     int SrcPos=FileNumber+P[0]-1;
     if (SrcPos<0 || SrcPos>=ASIZE(SrcFile))
+    {
+      delete NewFile;
       continue;
+    }
+
+    // Such volume number was already used. Skip to avoid memory leak.
+    // Alternatively we could 'delete SrcFile[SrcPos]' and overwrite.
+    if (SrcFile[SrcPos]!=nullptr)
+    {
+      delete NewFile;
+      continue;
+    }
+
     SrcFile[SrcPos]=NewFile;
 
     FoundRecVolumes++;
@@ -296,6 +318,8 @@
         uiMsg(UIERROR_RECVOLFOUND,FoundRecVolumes); // Intentionally not 
displayed in console mode.
         uiMsg(UIERROR_RECONSTRUCTING);
         ErrHandler.CreateErrorMsg(ArcName);
+
+        delete NewFile;
         return false;
       }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/recvol5.cpp new/unrar/recvol5.cpp
--- old/unrar/recvol5.cpp       2026-06-27 13:35:32.000000000 +0200
+++ new/unrar/recvol5.cpp       2026-09-09 15:11:11.000000000 +0200
@@ -155,7 +155,7 @@
   std::wstring FirstVolName;
   std::wstring LongestRevName;
 
-  int64 RecFileSize=0;
+  uint64 RecFileSize=0,FirstVolSize=0;
 
   FindFile VolFind;
   VolFind.SetMask(ArcName);
@@ -206,6 +206,9 @@
             VolNum+=(fd.Name[NumPos]-'0')*K;
           if (VolNum==0 || VolNum>MaxVolumes)
             continue;
+          if (FirstVolSize==0)
+            FirstVolSize=Vol->FileLength();
+
           size_t CurSize=RecItems.size();
           if (VolNum>CurSize)
           {
@@ -219,17 +222,19 @@
             VolNameToFirstName(fd.Name,FirstVolName,true);
         }
     }
-    if (ItemPos==-1)
-      delete Vol; // Skip found file, it is not RAR or REV volume.
+
+    // Skip found file if it is not RAR or REV volume. Also skip if found
+    // more REV volumes than needed.
+    if (ItemPos==-1 || (size_t)ItemPos>=RecItems.size())
+      delete Vol;
     else
-      if ((uint)ItemPos<RecItems.size()) // Check if found more REV than 
needed.
-      {
-        // Store found RAR or REV volume.
-        RecVolItem *Item=&RecItems[ItemPos];
-        Item->f=Vol;
-        Item->New=false;
-        Item->Name=fd.Name;
-      }
+    {
+      // Store found RAR or REV volume.
+      RecVolItem *Item=&RecItems[ItemPos];
+      Item->f=Vol;
+      Item->New=false;
+      Item->Name=fd.Name;
+    }
   }
 
   if (!Silent || FoundRecVolumes!=0)
@@ -328,7 +333,7 @@
           ErrHandler.CreateErrorMsg(Item->Name);
         ErrHandler.Exit(UserReject ? RARX_USERBREAK:RARX_CREATE);
       }
-      NewVol->Prealloc(Item->FileSize);
+      NewVol->Prealloc(Min(Item->FileSize,FirstVolSize));
       Item->f=NewVol;
     }
     NextVolumeName(FirstVolName,false);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/rijndael.cpp new/unrar/rijndael.cpp
--- old/unrar/rijndael.cpp      2026-06-27 13:35:32.000000000 +0200
+++ new/unrar/rijndael.cpp      2026-09-09 15:11:11.000000000 +0200
@@ -82,8 +82,12 @@
 
 Rijndael::Rijndael()
 {
-  if (S5[0]==0)
+  static bool TablesInitialized=false;
+  if (!TablesInitialized)
+  {
     GenerateTables();
+    TablesInitialized=true;
+  }
   m_uRounds = 0;
   CBCMode = true; // Always true for RAR.
 #ifdef USE_SSE
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/rs.cpp new/unrar/rs.cpp
--- old/unrar/rs.cpp    2026-06-27 13:35:32.000000000 +0200
+++ new/unrar/rs.cpp    2026-09-09 15:11:11.000000000 +0200
@@ -14,6 +14,7 @@
 // Initialize logarithms and exponents Galois field tables.
 void RSCoder::gfInit()
 {
+  gfLog[0]=0; // Just in case, likely excessive, because log(0) is undefined.
   for (int I=0,J=1;I<MAXPAR;I++)
   {
     gfLog[J]=I;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/rs16.cpp new/unrar/rs16.cpp
--- old/unrar/rs16.cpp  2026-06-27 13:35:32.000000000 +0200
+++ new/unrar/rs16.cpp  2026-09-09 15:11:11.000000000 +0200
@@ -258,11 +258,14 @@
 #endif
 
 
-// We update ECC in blocks by applying every data block to all ECC blocks.
-// This function applies one data block to one ECC block.
+// We write recovery data over former ECC blocks by applying every data block
+// to each ECC block. This function applies one data block to one ECC block.
 void RSCoder16::UpdateECC(uint DataNum, uint ECCNum, const byte *Data, byte 
*ECC, size_t BlockSize)
 {
-  if (DataNum==0) // Init ECC data.
+  // Init former ECC data before processing the first data block.
+  // We use this former ECC as output buffer and we copied its actual
+  // ECC contents over invalid data block before that.
+  if (DataNum==0)
     memset(ECC, 0, BlockSize);
 
   bool DirectAccess;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/ui.hpp new/unrar/ui.hpp
--- old/unrar/ui.hpp    2026-06-27 13:35:32.000000000 +0200
+++ new/unrar/ui.hpp    2026-09-09 15:11:12.000000000 +0200
@@ -68,8 +68,11 @@
 
 // Flags for uiAskReplace function.
 enum UIASKREP_FLAGS {
-  UIASKREP_F_NORENAME=1,UIASKREP_F_EXCHSRCDEST=2,UIASKREP_F_SHOWNAMEONLY=4,
-  UIASKREP_F_SINGLEFILE=8
+  UIASKREP_F_NORENAME     = 0x01, // Hide "Rename" button.
+  UIASKREP_F_EXCHSRCDEST  = 0x02, // Exchange source and destination file 
metadata.
+  UIASKREP_F_SHOWNAMEONLY = 0x04, // Hide source file path.
+  UIASKREP_F_SINGLEFILE   = 0x08, // Single file is processed, hide "Yes/No to 
All" buttons.
+  UIASKREP_F_SRCFOLDER    = 0x10  // Source is a folder.
 };
 
 // Codes returned by uiAskReplace. Note that uiAskReplaceEx returns only
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/uicommon.cpp new/unrar/uicommon.cpp
--- old/unrar/uicommon.cpp      2026-06-27 13:35:32.000000000 +0200
+++ new/unrar/uicommon.cpp      2026-09-09 15:11:12.000000000 +0200
@@ -29,12 +29,18 @@
     // target attributes, so we can delete the symlink below.
     PrepareToDelete(Name);
 
-    // Overwrite the link itself instead of its target.
-    // For normal files we prefer to inherit file attributes, permissions
-    // and hard links.
     FindData FD;
-    if (FindFile::FastFind(Name,&FD,true) && FD.IsLink)
-      DelFile(Name);
+    if (FindFile::FastFind(Name,&FD,true))
+    {
+      // Overwrite the link itself instead of its target.
+      // For normal files we prefer to inherit file attributes, permissions
+      // and hard links.
+      if (FD.IsLink)
+        DelFile(Name);
+      else
+        if (FD.IsDir)
+          DelDir(Name); // To let overwriting a directory with a file.
+    }
   }
 
   if (Choice==UIASKREP_R_REPLACEALL)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/uiconsole.cpp new/unrar/uiconsole.cpp
--- old/unrar/uiconsole.cpp     2026-06-27 13:35:32.000000000 +0200
+++ new/unrar/uiconsole.cpp     2026-09-09 15:11:12.000000000 +0200
@@ -154,7 +154,11 @@
       break;
 #endif
     case UIERROR_FILEATTR:
+#ifdef _UNIX
+      Log(Str[0],St(MErrChangePerm),Str[1]);
+#else
       Log(Str[0],St(MErrChangeAttr),Str[1]);
+#endif
       break;
     case UIERROR_FILECOPY:
       Log(Str[0],St(MCopyError),Str[1],Str[2]);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/ulinks.cpp new/unrar/ulinks.cpp
--- old/unrar/ulinks.cpp        2026-06-27 13:35:32.000000000 +0200
+++ new/unrar/ulinks.cpp        2026-09-09 15:11:12.000000000 +0200
@@ -78,7 +78,7 @@
     size_t DataSize=(size_t)Arc.FileHead.PackSize;
     if (DataSize>MAXPATHSIZE)
       return false;
-    std::vector<char> TargetBuf(DataSize+1);
+    std::vector<char> TargetBuf(DataSize);
     if ((size_t)DataIO.UnpRead((byte*)TargetBuf.data(),DataSize)!=DataSize)
       return false;
     std::string Target(TargetBuf.data(),TargetBuf.size());
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/version.hpp new/unrar/version.hpp
--- old/unrar/version.hpp       2026-06-27 13:35:33.000000000 +0200
+++ new/unrar/version.hpp       2026-09-09 15:11:12.000000000 +0200
@@ -1,6 +1,6 @@
 #define RARVER_MAJOR     7
-#define RARVER_MINOR    23
-#define RARVER_BETA      0
-#define RARVER_DAY      27
-#define RARVER_MONTH     6
+#define RARVER_MINOR    30
+#define RARVER_BETA      1
+#define RARVER_DAY       9
+#define RARVER_MONTH     9
 #define RARVER_YEAR   2026
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/win32acl.cpp new/unrar/win32acl.cpp
--- old/unrar/win32acl.cpp      2026-06-27 13:35:33.000000000 +0200
+++ new/unrar/win32acl.cpp      2026-09-09 15:11:12.000000000 +0200
@@ -9,7 +9,8 @@
 {
   SetACLPrivileges();
 
-  if (Arc.BrokenHeader)
+  constexpr size_t MAX_ACL_SIZE = 0x100000;
+  if (Arc.BrokenHeader || Arc.EAHead.UnpSize>MAX_ACL_SIZE)
   {
     uiMsg(UIERROR_ACLBROKEN,Arc.FileName,FileName);
     ErrHandler.SetErrorCode(RARX_CRC);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/win32lnk.cpp new/unrar/win32lnk.cpp
--- old/unrar/win32lnk.cpp      2026-06-27 13:35:33.000000000 +0200
+++ new/unrar/win32lnk.cpp      2026-09-09 15:11:12.000000000 +0200
@@ -50,7 +50,7 @@
   std::vector<byte> Buf(BufSize);
   REPARSE_DATA_BUFFER *rdb=(REPARSE_DATA_BUFFER *)Buf.data();
 
-  // Remove \??\ NTFS junction prefix of present.
+  // Remove \??\ NTFS junction prefix if present.
   bool WinPrefix=starts_with(SubstName,L"\\??\\");
   std::wstring PrintName=WinPrefix ? SubstName.substr(4):SubstName;
 
@@ -60,12 +60,20 @@
   size_t PrintLength=PrintName.size();
 
   bool AbsPath=WinPrefix;
-  // IsFullPath is not really needed here, AbsPath check is enough.
+  // IsFullPath is not really needed here for symlinks, AbsPath check is 
enough.
   // We added it just for extra safety, in case some Windows version would
   // allow to create absolute targets with SYMLINK_FLAG_RELATIVE.
+  // Junction points are either catched by \??\ or fail to follow the target
+  // once created, if \??\ was manually stripped from path.
   // Use hd->FileName instead of Name, since Name can include the destination
   // path as a prefix, which can confuse IsRelativeSymlinkSafe algorithm.
+  // 2026.08.19: We added FSREDIR_JUNCTION check, because normally junctions
+  // are always absolute, even if they pretent to not be. But this check is
+  // excessive and we keep it just in case here. If junction is absolute,
+  // it will be catched by other checks below. If junction isn't absolute,
+  // it will not follow the target path once created.
   if (!Cmd->AbsoluteLinks && (AbsPath || IsFullPath(hd->RedirName) ||
+      hd->RedirType==FSREDIR_JUNCTION ||
       !IsRelativeSymlinkSafe(Cmd,hd->FileName,Name,hd->RedirName)))
   {
     uiMsg(UIERROR_SKIPUNSAFELINK,hd->FileName,hd->RedirName);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unrar/win32stm.cpp new/unrar/win32stm.cpp
--- old/unrar/win32stm.cpp      2026-06-27 13:35:33.000000000 +0200
+++ new/unrar/win32stm.cpp      2026-09-09 15:11:12.000000000 +0200
@@ -125,7 +125,7 @@
 
 
 #ifdef _WIN_ALL
-void ExtractStreams(Archive &Arc,const std::wstring &FileName,bool TestMode)
+void ExtractStreams(CommandData *Cmd,Archive &Arc,const std::wstring &FileName)
 {
   std::wstring StreamName=GetStreamNameNTFS(Arc);
 
@@ -136,10 +136,16 @@
     return;
   }
 
-  if (TestMode)
+  if (Cmd->Test)
   {
+    if (!Cmd->DisableNames)
+      mprintf(St(MExtrTestFile),(FileName+StreamName).c_str());
     File CurFile;
-    Arc.ReadSubData(nullptr,&CurFile,true);
+    if (Arc.ReadSubData(nullptr,&CurFile,true) && !Cmd->DisableNames &&
+        !Cmd->DisablePercentage)
+    {
+      mprintf(L" %s",St(MOk));
+    }
     return;
   }
 
@@ -187,6 +193,10 @@
 
   if (CurFile.WCreate(FullName))
   {
+    CurFile.SetAllowDelete(!Cmd->KeepBroken);
+
+    if (!Cmd->DisableNames)
+      mprintf(St(MExtrFile),FullName.c_str());
 #ifdef PROPAGATE_MOTW
     if (!ParsedMotw.empty())
     {
@@ -198,10 +208,15 @@
     else
 #endif
     if (Arc.ReadSubData(nullptr,&CurFile,false))
+    {
       CurFile.Close();
+      if (!Cmd->DisableNames && !Cmd->DisablePercentage)
+        mprintf(L" %s",St(MOk));
+    }
   }
 
-  // Restoring original file timestamps.
+  // Restoring original file timestamps. Note that NTFS ADS share file
+  // attributes and times with the main file.
   File HostFile;
   if (HostFound && HostFile.Open(FileName,FMF_OPENSHARED|FMF_UPDATE))
     SetFileTime(HostFile.GetHandle(),&FD.ftCreationTime,&FD.ftLastAccessTime,

Reply via email to