Update to UnRAR v6.1.7

This commit is contained in:
Micah Snyder 2022-07-14 17:09:53 -07:00 committed by Micah Snyder
parent bb5cf49a5f
commit 83ba241087
49 changed files with 716 additions and 440 deletions

View file

@ -7,49 +7,16 @@
for samples and ideas allowed to make Reed-Solomon coding
more efficient.
* RAR text compression algorithm is based on Dmitry Shkarin PPMII
* RAR4 text compression algorithm is based on Dmitry Shkarin PPMII
and Dmitry Subbotin carryless rangecoder public domain source code.
You may find it in ftp.elf.stuba.sk/pub/pc/pack.
You can find it in ftp.elf.stuba.sk/pub/pc/pack.
* RAR encryption includes parts of code from Szymon Stefanek
and Brian Gladman AES implementations also as Steve Reid SHA-1 source.
* RAR encryption includes parts of public domain code
from Szymon Stefanek AES and Steve Reid SHA-1 implementations.
---------------------------------------------------------------------------
Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK.
All rights reserved.
LICENSE TERMS
The free distribution and use of this software in both source and binary
form is allowed (with or without changes) provided that:
1. distributions of this source code include the above copyright
notice, this list of conditions and the following disclaimer;
2. distributions in binary form include the above copyright
notice, this list of conditions and the following disclaimer
in the documentation and/or other associated materials;
3. the copyright holder's name is not used to endorse products
built using this software without specific written permission.
ALTERNATIVELY, provided that this notice is retained in full, this product
may be distributed under the terms of the GNU General Public License (GPL),
in which case the provisions of the GPL apply INSTEAD OF those given above.
DISCLAIMER
This software is provided 'as is' with no explicit or implied warranties
in respect of its properties, including, but not limited to, correctness
and/or fitness for purpose.
---------------------------------------------------------------------------
Source code of this package also as other cryptographic technology
and computing project related links are available on Brian Gladman's
web site: http://www.gladman.me.uk
* RAR uses CRC32 function based on Intel Slicing-by-8 algorithm.
Original Intel Slicing-by-8 code is available here:
* With exception of SFX modules, RAR uses CRC32 function based
on Intel Slicing-by-8 algorithm. Original Intel Slicing-by-8 code
is available here:
https://sourceforge.net/projects/slicing-by-8/

View file

@ -231,7 +231,7 @@ bool Archive::IsArchive(bool EnableBroken)
// first file header to set "comment" flag when reading service header.
// Unless we are in silent mode, we need to know about presence of comment
// immediately after IsArchive call.
if (HeadersLeft && (!SilentOpen || !Encrypted))
if (HeadersLeft && (!SilentOpen || !Encrypted) && IsSeekable())
{
int64 SavePos=Tell();
int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos;

View file

@ -558,6 +558,13 @@ size_t Archive::ReadHeader50()
return 0;
#else
if (Cmd->SkipEncrypted)
{
uiMsg(UIMSG_SKIPENCARC,FileName);
FailedHeaderDecryption=true; // Suppress error messages and quit quietly.
return 0;
}
byte HeadersInitV[SIZE_INITV];
if (Read(HeadersInitV,SIZE_INITV)!=SIZE_INITV)
{
@ -876,7 +883,12 @@ size_t Archive::ReadHeader50()
// code to shell extension, which is not done now.
if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_RR) && hd->SubData.Size()>0)
{
RecoveryPercent=hd->SubData[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;

View file

@ -108,6 +108,11 @@ void CommandData::ParseArg(wchar *Arg)
// 'S' can contain SFX name, which case is important in Unix.
if (*Command!='I' && *Command!='S')
wcsupper(Command);
if (*Command=='P') // Enforce -idq for print command.
{
MsgStream=MSG_ERRONLY;
SetConsoleMsgStream(MSG_ERRONLY);
}
}
else
if (*ArcName==0)
@ -373,6 +378,9 @@ void CommandData::ProcessSwitch(const wchar *Switch)
case '3':
ExclPath=EXCL_ABSPATH;
break;
case '4':
wcsncpyz(ExclArcPath,Switch+3,ASIZE(ExclArcPath));
break;
}
break;
default:
@ -399,6 +407,8 @@ void CommandData::ProcessSwitch(const wchar *Switch)
EncryptHeaders=true;
if (Switch[2]!=0)
{
if (wcslen(Switch+2)>=MAXPASSWORD)
uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1);
Password.Set(Switch+2);
cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0]));
}
@ -561,6 +571,10 @@ void CommandData::ProcessSwitch(const wchar *Switch)
break;
case 'D':
break;
case 'E':
if (toupperw(Switch[2])=='S' && Switch[3]==0)
SkipEncrypted=true;
break;
case 'S':
{
wchar StoreNames[1024];
@ -648,6 +662,10 @@ void CommandData::ProcessSwitch(const wchar *Switch)
AllowIncompatNames=true;
break;
#endif
case 'P':
wcsncpyz(ExtrPath,Switch+2,ASIZE(ExtrPath));
AddEndSlash(ExtrPath,ASIZE(ExtrPath));
break;
case 'R':
Overwrite=OVERWRITE_AUTORENAME;
break;
@ -672,6 +690,8 @@ void CommandData::ProcessSwitch(const wchar *Switch)
}
else
{
if (wcslen(Switch+1)>=MAXPASSWORD)
uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1);
Password.Set(Switch+1);
cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0]));
}
@ -752,6 +772,10 @@ void CommandData::ProcessSwitch(const wchar *Switch)
case 'D':
Solid|=SOLID_VOLUME_DEPENDENT;
break;
case 'I':
ProhibitConsoleInput();
wcsncpyz(UseStdin,Switch[2] ? Switch+2:L"stdin",ASIZE(UseStdin));
break;
case 'L':
if (IsDigit(Switch[2]))
FileSizeLess=atoilw(Switch+2);
@ -935,7 +959,7 @@ void CommandData::ProcessCommand()
wcsncpyz(ArcName,Name,ASIZE(ArcName));
}
if (wcschr(L"AFUMD",*Command)==NULL)
if (wcschr(L"AFUMD",*Command)==NULL && *UseStdin==0)
{
if (GenerateArcName)
{

View file

@ -50,7 +50,7 @@ class CommandData:public RAROptions
bool GetArcName(wchar *Name,int MaxSize);
bool CheckWinSize();
int GetRecoverySize(const wchar *Str,int DefSize);
int GetRecoverySize(const wchar *CmdStr,const wchar *Value,int DefSize);
#ifndef SFX_MODULE
void ReportWrongSwitches(RARFORMAT Format);

View file

@ -262,6 +262,8 @@ bool CommandData::TimeCheck(RarTime &ftm,RarTime &ftc,RarTime &fta)
// Return 'true' if we need to exclude the file from processing.
bool CommandData::SizeCheck(int64 Size)
{
if (Size==INT64NDF) // If called from archive formats like bzip2, not storing the file size.
return false;
if (FileSizeLess!=INT64NDF && Size>=FileSizeLess)
return true;
if (FileSizeMore!=INT64NDF && Size<=FileSizeMore)

View file

@ -61,14 +61,14 @@ void CommandData::OutHelp(RAR_EXIT ExitCode)
MUNRARTitle1,MRARTitle2,MCHelpCmd,MCHelpCmdE,MCHelpCmdL,
MCHelpCmdP,MCHelpCmdT,MCHelpCmdV,MCHelpCmdX,MCHelpSw,MCHelpSwm,
MCHelpSwAT,MCHelpSwAC,MCHelpSwAD,MCHelpSwAG,MCHelpSwAI,MCHelpSwAP,
MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU,
MCHelpSwDH,MCHelpSwEP,MCHelpSwEP3,MCHelpSwF,MCHelpSwIDP,MCHelpSwIERR,
MCHelpSwINUL,MCHelpSwIOFF,MCHelpSwKB,MCHelpSwN,MCHelpSwNa,MCHelpSwNal,
MCHelpSwO,MCHelpSwOC,MCHelpSwOL,MCHelpSwOR,MCHelpSwOW,MCHelpSwP,
MCHelpSwPm,MCHelpSwR,MCHelpSwRI,MCHelpSwSC,MCHelpSwSL,MCHelpSwSM,
MCHelpSwTA,MCHelpSwTB,MCHelpSwTN,MCHelpSwTO,MCHelpSwTS,MCHelpSwU,
MCHelpSwVUnr,MCHelpSwVER,MCHelpSwVP,MCHelpSwX,MCHelpSwXa,MCHelpSwXal,
MCHelpSwY
MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU,MCHelpSwDH,MCHelpSwEP,
MCHelpSwEP3,MCHelpSwEP4,MCHelpSwF,MCHelpSwIDP,MCHelpSwIERR,
MCHelpSwINUL,MCHelpSwIOFF,MCHelpSwKB,MCHelpSwME,MCHelpSwN,MCHelpSwNa,
MCHelpSwNal,MCHelpSwO,MCHelpSwOC,MCHelpSwOL,MCHelpSwOP,MCHelpSwOR,
MCHelpSwOW,MCHelpSwP,MCHelpSwR,MCHelpSwRI,MCHelpSwSC,MCHelpSwSI,
MCHelpSwSL,MCHelpSwSM,MCHelpSwTA,MCHelpSwTB,MCHelpSwTN,MCHelpSwTO,
MCHelpSwTS,MCHelpSwU,MCHelpSwVUnr,MCHelpSwVER,MCHelpSwVP,MCHelpSwX,
MCHelpSwXa,MCHelpSwXal,MCHelpSwY
#endif
};

View file

@ -3,6 +3,7 @@
static MESSAGE_TYPE MsgStream=MSG_STDOUT;
static RAR_CHARSET RedirectCharset=RCH_DEFAULT;
static bool ProhibitInput=false;
const int MaxMsgSize=2*NM+2048;
@ -61,6 +62,12 @@ void SetConsoleRedirectCharset(RAR_CHARSET RedirectCharset)
}
void ProhibitConsoleInput()
{
ProhibitInput=true;
}
#ifndef SILENT
static void cvt_wprintf(FILE *dest,const wchar *fmt,va_list arglist)
{
@ -141,28 +148,56 @@ void eprintf(const wchar *fmt,...)
#ifndef SILENT
static void QuitIfInputProhibited()
{
// We cannot handle user prompts if -si is used to read file or archive data
// from stdin.
if (ProhibitInput)
{
mprintf(St(MStdinNoInput));
ErrHandler.Exit(RARX_FATAL);
}
}
static void GetPasswordText(wchar *Str,uint MaxLength)
{
if (MaxLength==0)
return;
QuitIfInputProhibited();
if (StdinRedirected)
getwstr(Str,MaxLength); // Read from pipe or redirected file.
else
{
#ifdef _WIN_ALL
HANDLE hConIn=GetStdHandle(STD_INPUT_HANDLE);
HANDLE hConOut=GetStdHandle(STD_OUTPUT_HANDLE);
DWORD ConInMode,ConOutMode;
DWORD Read=0;
DWORD ConInMode;
GetConsoleMode(hConIn,&ConInMode);
GetConsoleMode(hConOut,&ConOutMode);
SetConsoleMode(hConIn,ENABLE_LINE_INPUT);
SetConsoleMode(hConOut,ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT);
SetConsoleMode(hConIn,ENABLE_LINE_INPUT); // Remove ENABLE_ECHO_INPUT.
// We prefer ReadConsole to ReadFile, so we can read Unicode input.
DWORD Read=0;
ReadConsole(hConIn,Str,MaxLength-1,&Read,NULL);
Str[Read]=0;
SetConsoleMode(hConIn,ConInMode);
SetConsoleMode(hConOut,ConOutMode);
// If entered password is longer than MAXPASSWORD and truncated,
// read its unread part anyway, so it isn't read later as the second
// password for -p switch. Low level FlushConsoleInputBuffer doesn't help
// for high level ReadConsole, which in line input mode seems to store
// the rest of string in its own internal buffer.
if (wcschr(Str,'\r')==NULL) // If '\r' is missing, the password was truncated.
while (true)
{
wchar Trail[64];
DWORD TrailRead=0;
// Use ASIZE(Trail)-1 to reserve the space for trailing 0.
ReadConsole(hConIn,Trail,ASIZE(Trail)-1,&TrailRead,NULL);
Trail[TrailRead]=0;
if (TrailRead==0 || wcschr(Trail,'\r')!=NULL)
break;
}
#else
char StrA[MAXPASSWORD*4]; // "*4" for multibyte UTF-8 characters.
#if defined(_EMX) || defined (__VMS)
@ -190,16 +225,21 @@ bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *
while (true)
{
if (!StdinRedirected)
// if (!StdinRedirected)
if (Type==UIPASSWORD_GLOBAL)
eprintf(L"\n%s: ",St(MAskPsw));
else
eprintf(St(MAskPswFor),FileName);
wchar PlainPsw[MAXPASSWORD];
wchar PlainPsw[MAXPASSWORD+1];
GetPasswordText(PlainPsw,ASIZE(PlainPsw));
if (*PlainPsw==0 && Type==UIPASSWORD_GLOBAL)
return false;
if (wcslen(PlainPsw)>=MAXPASSWORD)
{
PlainPsw[MAXPASSWORD-1]=0;
uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1);
}
if (!StdinRedirected && Type==UIPASSWORD_GLOBAL)
{
eprintf(St(MReAskPsw));
@ -229,6 +269,8 @@ bool getwstr(wchar *str,size_t n)
// Print buffered prompt title function before waiting for input.
fflush(stderr);
QuitIfInputProhibited();
*str=0;
#if defined(_WIN_ALL)
// fgetws does not work well with non-English text in Windows,
@ -240,6 +282,7 @@ bool getwstr(wchar *str,size_t n)
Array<char> StrA(n*4); // Up to 4 UTF-8 characters per wchar_t.
File SrcFile;
SrcFile.SetHandleType(FILE_HANDLESTD);
SrcFile.SetLineInputMode(true);
int ReadSize=SrcFile.Read(&StrA[0],StrA.Size()-1);
if (ReadSize<=0)
{

View file

@ -4,6 +4,7 @@
void InitConsole();
void SetConsoleMsgStream(MESSAGE_TYPE MsgStream);
void SetConsoleRedirectCharset(RAR_CHARSET RedirectCharset);
void ProhibitConsoleInput();
void OutComment(const wchar *Comment,size_t Size);
#ifndef SILENT

View file

@ -14,6 +14,12 @@
#include "rar.hpp"
#ifndef SFX_MODULE
// User suggested to avoid BSD license in SFX module, so they do not need
// to include the license to SFX archive.
#define USE_SLICING
#endif
static uint crc_tables[8][256]; // Tables for Slicing-by-8.
@ -37,6 +43,7 @@ static void InitTables()
{
InitCRC32(crc_tables[0]);
#ifdef USE_SLICING
for (uint I=0;I<256;I++) // Build additional lookup tables.
{
uint C=crc_tables[0][I];
@ -46,6 +53,7 @@ static void InitTables()
crc_tables[J][I]=C;
}
}
#endif
}
@ -55,6 +63,7 @@ uint CRC32(uint StartCRC,const void *Addr,size_t Size)
{
byte *Data=(byte *)Addr;
#ifdef USE_SLICING
// Align Data to 8 for better performance.
for (;Size>0 && ((size_t)Data & 7);Size--,Data++)
StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);
@ -77,6 +86,7 @@ uint CRC32(uint StartCRC,const void *Addr,size_t Size)
crc_tables[1][(byte)(NextData >> 16)] ^
crc_tables[0][(byte)(NextData >> 24)];
}
#endif
for (;Size>0;Size--,Data++) // Process left data.
StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);

View file

@ -329,7 +329,7 @@ int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestNa
{
Data->Cmd.DllError=0;
if (Data->OpenMode==RAR_OM_LIST || Data->OpenMode==RAR_OM_LIST_INCSPLIT ||
Operation==RAR_SKIP) // && !Data->Arc.Solid)
Operation==RAR_SKIP && !Data->Arc.Solid)
{
if (Data->Arc.Volume && Data->Arc.GetHeaderType()==HEAD_FILE &&
Data->Arc.FileHead.SplitAfter)

View file

@ -2,8 +2,8 @@
#include <commctrl.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION 6, 2, 100, 3821
PRODUCTVERSION 6, 2, 100, 3821
FILEVERSION 6, 12, 100, 489
PRODUCTVERSION 6, 12, 100, 489
FILEOS VOS__WINDOWS32
FILETYPE VFT_APP
{
@ -14,9 +14,9 @@ FILETYPE VFT_APP
VALUE "CompanyName", "Alexander Roshal\0"
VALUE "ProductName", "RAR decompression library\0"
VALUE "FileDescription", "RAR decompression library\0"
VALUE "FileVersion", "6.2.0\0"
VALUE "ProductVersion", "6.2.0\0"
VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2021\0"
VALUE "FileVersion", "6.12.0\0"
VALUE "ProductVersion", "6.12.0\0"
VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2022\0"
VALUE "OriginalFilename", "Unrar.dll\0"
}
}

View file

@ -20,8 +20,6 @@ void EncodeFileName::Decode(char *Name,size_t NameSize,byte *EncName,size_t EncS
{
if (FlagBits==0)
{
if (EncPos>=EncSize)
break;
Flags=EncName[EncPos++];
FlagBits=8;
}

View file

@ -4,9 +4,8 @@
class EncodeFileName
{
private:
void AddFlags(int Value);
void AddFlags(byte Value,byte *EncName);
byte *EncName;
byte Flags;
uint FlagBits;
size_t FlagsPos;

View file

@ -49,8 +49,7 @@ void CmdExtract::DoExtract()
if (Code!=EXTRACT_ARC_REPEAT)
break;
}
if (FindFile::FastFind(ArcName,&FD))
DataIO.ProcessedArcSize+=FD.Size;
DataIO.ProcessedArcSize+=DataIO.LastArcSize;
}
// Clean user entered password. Not really required, just for extra safety.
@ -82,7 +81,7 @@ void CmdExtract::DoExtract()
void CmdExtract::ExtractArchiveInit(Archive &Arc)
{
DataIO.UnpArcSize=Arc.FileLength();
DataIO.AdjustTotalArcSize(&Arc);
FileCount=0;
MatchedArgs=0;
@ -105,8 +104,22 @@ void CmdExtract::ExtractArchiveInit(Archive &Arc)
EXTRACT_ARC_CODE CmdExtract::ExtractArchive()
{
Archive Arc(Cmd);
if (!Arc.WOpen(ArcName))
return EXTRACT_ARC_NEXT;
if (*Cmd->UseStdin!=0)
{
Arc.SetHandleType(FILE_HANDLESTD);
#ifdef USE_QOPEN
Arc.SetProhibitQOpen(true);
#endif
}
else
{
#if defined(_WIN_ALL) && !defined(SFX_MODULE) // WinRAR GUI code also resets the cache.
if (*Cmd->Command=='T' || Cmd->Test)
ResetFileCache(ArcName); // Reset the file cache when testing an archive.
#endif
if (!Arc.WOpen(ArcName))
return EXTRACT_ARC_NEXT;
}
if (!Arc.IsArchive(true))
{
@ -216,14 +229,11 @@ EXTRACT_ARC_CODE CmdExtract::ExtractArchive()
if (Repeat)
{
// If we started extraction from not first volume and need to
// restart it from first, we must correct DataIO.TotalArcSize
// for correct total progress display. We subtract the size
// of current volume and all volumes after it and add the size
// of new (first) volume.
FindData OldArc,NewArc;
if (FindFile::FastFind(Arc.FileName,&OldArc) &&
FindFile::FastFind(ArcName,&NewArc))
DataIO.TotalArcSize-=VolumeSetSize+OldArc.Size-NewArc.Size;
// restart it from first, we must set DataIO.TotalArcSize to size
// of new first volume to display the total progress correctly.
FindData NewArc;
if (FindFile::FastFind(ArcName,&NewArc))
DataIO.TotalArcSize=NewArc.Size;
return EXTRACT_ARC_REPEAT;
}
else
@ -403,6 +413,12 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
FirstFile=false;
#endif
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)
{
// First common call of uiStartFileExtract. It is done before overwrite
@ -632,7 +648,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
uint64 Preallocated=0;
if (!TestMode && !Arc.BrokenHeader && Arc.FileHead.UnpSize>1000000 &&
Arc.FileHead.PackSize*1024>Arc.FileHead.UnpSize &&
Arc.FileHead.PackSize*1024>Arc.FileHead.UnpSize && Arc.IsSeekable() &&
(Arc.FileHead.UnpSize<100000000 || Arc.FileLength()>Arc.FileHead.PackSize))
{
CurFile.Prealloc(Arc.FileHead.UnpSize);
@ -650,8 +666,11 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
if (Type==FSREDIR_HARDLINK || Type==FSREDIR_FILECOPY)
{
wchar RedirName[NM];
ConvertPath(Arc.FileHead.RedirName,RedirName,ASIZE(RedirName));
wchar NameExisting[NM];
ExtrPrepareName(Arc,Arc.FileHead.RedirName,NameExisting,ASIZE(NameExisting));
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));
@ -921,19 +940,13 @@ void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *De
#endif
#ifndef SFX_MODULE
size_t ArcPathLength=wcslen(Cmd->ArcPath);
wchar *ArcPath=*Cmd->ExclArcPath!=0 ? Cmd->ExclArcPath:Cmd->ArcPath;
size_t ArcPathLength=wcslen(ArcPath);
if (ArcPathLength>0)
{
size_t NameLength=wcslen(ArcFileName);
// Earlier we compared lengths only here, but then noticed a cosmetic bug
// in WinRAR. When extracting a file reference from subfolder with
// "Extract relative paths", so WinRAR sets ArcPath, if reference target
// is missing, error message removed ArcPath both from reference and target
// names. If target was stored in another folder, its name looked wrong.
if (NameLength>=ArcPathLength &&
wcsnicompc(Cmd->ArcPath,ArcFileName,ArcPathLength)==0 &&
(IsPathDiv(Cmd->ArcPath[ArcPathLength-1]) ||
if (NameLength>=ArcPathLength && wcsnicompc(ArcPath,ArcFileName,ArcPathLength)==0 &&
(IsPathDiv(ArcPath[ArcPathLength-1]) ||
IsPathDiv(ArcFileName[ArcPathLength]) || ArcFileName[ArcPathLength]==0))
{
ArcFileName+=Min(ArcPathLength,NameLength);
@ -966,7 +979,7 @@ void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *De
// Must do after Cmd->ArcPath processing above, so file name and arc path
// trailing spaces are in sync.
if (!Cmd->AllowIncompatNames)
MakeNameCompatible(DestName);
MakeNameCompatible(DestName,DestSize);
#endif
wchar DiskLetter=toupperw(DestName[0]);
@ -1027,11 +1040,7 @@ bool CmdExtract::ExtrGetPassword(Archive &Arc,const wchar *ArcFileName)
if (!uiGetPassword(UIPASSWORD_FILE,ArcFileName,&Cmd->Password)/* || !Cmd->Password.IsSet()*/)
{
// Suppress "test is ok" message if user cancelled the password prompt.
// 2019.03.23: If some archives are tested ok and prompt is cancelled for others,
// do we really need to suppress "test is ok"? Also if we set an empty password
// and "Use for all archives" in WinRAR Ctrl+P and skip some encrypted archives.
// We commented out this UIERROR_INCERRCOUNT for now.
// uiMsg(UIERROR_INCERRCOUNT);
uiMsg(UIERROR_INCERRCOUNT);
return false;
}
Cmd->ManualPassword=true;

View file

@ -7,6 +7,7 @@ File::File()
NewFile=false;
LastWrite=false;
HandleType=FILE_HANDLENORMAL;
LineInput=false;
SkipClose=false;
ErrorType=FILE_SUCCESS;
OpenShared=false;
@ -14,11 +15,11 @@ File::File()
AllowExceptions=true;
PreserveAtime=false;
#ifdef _WIN_ALL
NoSequentialRead=false;
CreateMode=FMF_UNDEFINED;
#endif
ReadErrorMode=FREM_ASK;
TruncatedAfterReadError=false;
CurFilePos=0;
}
@ -58,7 +59,7 @@ bool File::Open(const wchar *Name,uint Mode)
uint ShareMode=(Mode & FMF_OPENEXCLUSIVE) ? 0 : FILE_SHARE_READ;
if (OpenShared)
ShareMode|=FILE_SHARE_WRITE;
uint Flags=NoSequentialRead ? 0:FILE_FLAG_SEQUENTIAL_SCAN;
uint Flags=FILE_FLAG_SEQUENTIAL_SCAN;
FindData FD;
if (PreserveAtime)
Access|=FILE_WRITE_ATTRIBUTES; // Needed to preserve atime.
@ -379,10 +380,11 @@ int File::Read(void *Data,size_t Size)
if (ReadErrorMode==FREM_IGNORE)
FilePos=Tell();
int ReadSize;
int TotalRead=0;
while (true)
{
ReadSize=DirectRead(Data,Size);
int ReadSize=DirectRead(Data,Size);
if (ReadSize==-1)
{
ErrorType=FILE_READERROR;
@ -396,6 +398,8 @@ int File::Read(void *Data,size_t Size)
size_t SizeToRead=Min(Size-I,512);
int ReadCode=DirectRead(Data,SizeToRead);
ReadSize+=(ReadCode==-1) ? 512:ReadCode;
if (ReadSize!=-1)
TotalRead+=ReadSize;
}
}
else
@ -415,9 +419,28 @@ int File::Read(void *Data,size_t Size)
ErrHandler.ReadError(FileName);
}
}
TotalRead+=ReadSize; // If ReadSize is -1, TotalRead is also set to -1 here.
if (HandleType==FILE_HANDLESTD && !LineInput && ReadSize>0 && (uint)ReadSize<Size)
{
// Unlike regular files, for pipe we can read only as much as was
// written at the other end of pipe. We had seen data coming in small
// ~80 byte chunks when piping from 'type arc.rar'. Extraction code
// would fail if we read an incomplete archive header from stdin.
// So here we ensure that requested size is completely read.
// But we return the available data immediately in "line input" mode,
// when processing user's input in console prompts. Otherwise apps
// piping user responses to multiple Ask() prompts can hang if no more
// data is available yet and pipe isn't closed.
Data=(byte*)Data+ReadSize;
Size-=ReadSize;
continue;
}
break;
}
return ReadSize; // It can return -1 only if AllowExceptions is disabled.
if (TotalRead>0) // Can be -1 for error and AllowExceptions disabled.
CurFilePos+=TotalRead;
return TotalRead; // It can return -1 only if AllowExceptions is disabled.
}
@ -499,6 +522,30 @@ bool File::RawSeek(int64 Offset,int Method)
{
if (hFile==FILE_BAD_HANDLE)
return true;
if (!IsSeekable())
{
if (Method==SEEK_CUR)
{
Offset+=CurFilePos;
Method=SEEK_SET;
}
if (Method==SEEK_SET && Offset>=CurFilePos) // Reading for seek forward.
{
uint64 SkipSize=Offset-CurFilePos;
while (SkipSize>0)
{
byte Buf[4096];
int ReadSize=Read(Buf,(size_t)Min(SkipSize,ASIZE(Buf)));
if (ReadSize<=0)
return false;
SkipSize-=ReadSize;
}
CurFilePos=Offset;
return true;
}
return false; // Backward or end of file seek on unseekable file.
}
if (Offset<0 && Method!=SEEK_SET)
{
Offset=(Method==SEEK_CUR ? Tell():FileLength())+Offset;
@ -533,6 +580,8 @@ int64 File::Tell()
ErrHandler.SeekError(FileName);
else
return -1;
if (!IsSeekable())
return CurFilePos;
#ifdef _WIN_ALL
LONG HighDist=0;
uint LowDist=SetFilePointer(hFile,0,&HighDist,FILE_CURRENT);

View file

@ -59,6 +59,16 @@ class File
FileHandle hFile;
bool LastWrite;
FILE_HANDLETYPE HandleType;
// If we read the user input in console prompts from stdin, we shall
// process the available line immediately, not waiting for rest of data.
// Otherwise apps piping user responses to multiple Ask() prompts can
// hang if no more data is available yet and pipe isn't closed.
// If we read RAR archive or other file data from stdin, we shall collect
// the entire requested block as long as pipe isn't closed, so we get
// complete archive headers, not split between different reads.
bool LineInput;
bool SkipClose;
FILE_READ_ERROR_MODE ReadErrorMode;
bool NewFile;
@ -70,6 +80,8 @@ class File
#endif
bool PreserveAtime;
bool TruncatedAfterReadError;
int64 CurFilePos; // Used for forward seeks in stdin files.
protected:
bool OpenShared; // Set by 'Archive' class.
public:
@ -110,7 +122,9 @@ class File
virtual bool IsOpened() {return hFile!=FILE_BAD_HANDLE;} // 'virtual' for MultiFile class.
int64 FileLength();
void SetHandleType(FILE_HANDLETYPE Type) {HandleType=Type;}
void SetLineInputMode(bool Mode) {LineInput=Mode;}
FILE_HANDLETYPE GetHandleType() {return HandleType;}
bool IsSeekable() {return HandleType!=FILE_HANDLESTD;}
bool IsDevice();
static bool RemoveCreated();
FileHandle GetHandle() {return hFile;}
@ -119,9 +133,6 @@ class File
int64 Copy(File &Dest,int64 Length=INT64NDF);
void SetAllowDelete(bool Allow) {AllowDelete=Allow;}
void SetExceptions(bool Allow) {AllowExceptions=Allow;}
#ifdef _WIN_ALL
void RemoveSequentialFlag() {NoSequentialRead=true;}
#endif
void SetPreserveAtime(bool Preserve) {PreserveAtime=Preserve;}
bool IsTruncatedAfterReadError() {return TruncatedAfterReadError;}
#ifdef _UNIX

View file

@ -397,7 +397,11 @@ void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,
{
#ifndef SILENT
if ((Flags & CALCFSUM_SHOWPROGRESS)!=0)
uiExtractProgress(TotalRead,FileLength,TotalRead,FileLength);
{
// Update only the current file progress in WinRAR, set the total to 0
// to keep it as is. It looks better for WinRAR,
uiExtractProgress(TotalRead,FileLength,0,0);
}
else
{
if ((Flags & CALCFSUM_SHOWPERCENT)!=0)
@ -517,6 +521,18 @@ bool SetFileCompression(const wchar *Name,bool State)
CloseHandle(hFile);
return RetCode!=0;
}
void ResetFileCache(const wchar *Name)
{
// To reset file cache in Windows it is enough to open it with
// FILE_FLAG_NO_BUFFERING and then close it.
HANDLE hSrc=CreateFile(Name,GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,OPEN_EXISTING,FILE_FLAG_NO_BUFFERING,NULL);
if (hSrc!=INVALID_HANDLE_VALUE)
CloseHandle(hSrc);
}
#endif

View file

@ -41,6 +41,7 @@ bool DelDir(const wchar *Name);
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
bool SetFileCompression(const wchar *Name,bool State);
void ResetFileCache(const wchar *Name);
#endif

View file

@ -144,9 +144,15 @@ bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink)
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);

View file

@ -1,6 +1,6 @@
#define INCLUDEGLOBAL
#if defined(__BORLANDC__) || defined(_MSC_VER)
#ifdef _MSC_VER
#pragma hdrstop
#endif

View file

@ -1,6 +1,5 @@
#include "rar.hpp"
#ifdef _WIN_ALL
DWORD WinNT()
{
static int dwPlatformId=-1;
@ -13,6 +12,7 @@ DWORD WinNT()
dwPlatformId=WinVer.dwPlatformId;
dwMajorVersion=WinVer.dwMajorVersion;
dwMinorVersion=WinVer.dwMinorVersion;
}
DWORD Result=0;
if (dwPlatformId==VER_PLATFORM_WIN32_NT)
@ -21,4 +21,94 @@ DWORD WinNT()
return Result;
}
#endif
// Replace it with documented Windows 11 check when available.
#include <comdef.h>
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
static bool WMI_IsWindows10()
{
IWbemLocator *pLoc = NULL;
HRESULT hres = CoCreateInstance(CLSID_WbemLocator,0,CLSCTX_INPROC_SERVER,
IID_IWbemLocator,(LPVOID *)&pLoc);
if (FAILED(hres))
return false;
IWbemServices *pSvc = NULL;
hres = pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"),NULL,NULL,0,NULL,0,0,&pSvc);
if (FAILED(hres))
{
pLoc->Release();
return false;
}
hres = CoSetProxyBlanket(pSvc,RPC_C_AUTHN_WINNT,RPC_C_AUTHZ_NONE,NULL,
RPC_C_AUTHN_LEVEL_CALL,RPC_C_IMP_LEVEL_IMPERSONATE,NULL,EOAC_NONE);
if (FAILED(hres))
{
pSvc->Release();
pLoc->Release();
return false;
}
IEnumWbemClassObject *pEnumerator = NULL;
hres = pSvc->ExecQuery(bstr_t("WQL"), bstr_t("SELECT * FROM Win32_OperatingSystem"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
if (FAILED(hres))
{
pSvc->Release();
pLoc->Release();
return false;
}
IWbemClassObject *pclsObj = NULL;
ULONG uReturn = 0;
bool Win10=false;
while (pEnumerator!=NULL)
{
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
if (uReturn==0)
break;
VARIANT vtProp;
hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);
Win10|=wcsstr(vtProp.bstrVal,L"Windows 10")!=NULL;
VariantClear(&vtProp);
pclsObj->Release();
}
pSvc->Release();
pLoc->Release();
pEnumerator->Release();
return Win10;
}
// Replace it with actual check when available.
bool IsWindows11OrGreater()
{
static bool IsSet=false,IsWin11=false;
if (!IsSet)
{
OSVERSIONINFO WinVer;
WinVer.dwOSVersionInfoSize=sizeof(WinVer);
GetVersionEx(&WinVer);
IsWin11=WinVer.dwMajorVersion>10 ||
WinVer.dwMajorVersion==10 && WinVer.dwBuildNumber >= 22000 && !WMI_IsWindows10();
IsSet=true;
}
return IsWin11;
}

View file

@ -10,4 +10,7 @@ enum WINNT_VERSION {
DWORD WinNT();
// Replace it with actual check when available.
bool IsWindows11OrGreater();
#endif

View file

@ -22,9 +22,6 @@ void ListArchive(CommandData *Cmd)
Cmd->Password.Clean(); // Clean user entered password before processing next archive.
Archive Arc(Cmd);
#ifdef _WIN_ALL
Arc.RemoveSequentialFlag();
#endif
if (!Arc.WOpen(ArcName))
continue;
bool FileMatched=true;
@ -310,17 +307,21 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
mprintf(L"\n%12ls: %ls",St(MListPacked),PackSizeText);
mprintf(L"\n%12ls: %ls",St(MListRatio),RatioStr);
}
bool WinTitles=false;
#ifdef _WIN_ALL
WinTitles=true;
#endif
if (hd.mtime.IsSet())
mprintf(L"\n%12ls: %ls",St(MListMtime),DateStr);
mprintf(L"\n%12ls: %ls",St(WinTitles ? MListModified:MListMtime),DateStr);
if (hd.ctime.IsSet())
{
hd.ctime.GetText(DateStr,ASIZE(DateStr),true);
mprintf(L"\n%12ls: %ls",St(MListCtime),DateStr);
mprintf(L"\n%12ls: %ls",St(WinTitles ? MListCreated:MListCtime),DateStr);
}
if (hd.atime.IsSet())
{
hd.atime.GetText(DateStr,ASIZE(DateStr),true);
mprintf(L"\n%12ls: %ls",St(MListAtime),DateStr);
mprintf(L"\n%12ls: %ls",St(WinTitles ? MListAccessed:MListAtime),DateStr);
}
mprintf(L"\n%12ls: %ls",St(MListAttr),AttrStr);
if (hd.FileHash.Type==HASH_CRC32)
@ -376,15 +377,16 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
{
mprintf(L"\n%12ls: ",L"Unix owner");
if (*hd.UnixOwnerName!=0)
mprintf(L"%ls:",GetWide(hd.UnixOwnerName));
mprintf(L"%ls",GetWide(hd.UnixOwnerName));
else
if (hd.UnixOwnerNumeric)
mprintf(L"#%d",hd.UnixOwnerID);
mprintf(L":");
if (*hd.UnixGroupName!=0)
mprintf(L"%ls",GetWide(hd.UnixGroupName));
if ((*hd.UnixOwnerName!=0 || *hd.UnixGroupName!=0) && (hd.UnixOwnerNumeric || hd.UnixGroupNumeric))
mprintf(L" ");
if (hd.UnixOwnerNumeric)
mprintf(L"#%d:",hd.UnixOwnerID);
if (hd.UnixGroupNumeric)
mprintf(L"#%d:",hd.UnixGroupID);
else
if (hd.UnixGroupNumeric)
mprintf(L"#%d",hd.UnixGroupID);
}
mprintf(L"\n");

View file

@ -72,11 +72,11 @@
#define MCHelpSwDW L"\n dw Wipe files after archiving"
#define MCHelpSwEa L"\n e[+]<attr> Set file exclude and include attributes"
#define MCHelpSwED L"\n ed Do not add empty directories"
#define MCHelpSwEN L"\n en Do not put 'end of archive' block"
#define MCHelpSwEP L"\n ep Exclude paths from names"
#define MCHelpSwEP1 L"\n ep1 Exclude base directory from names"
#define MCHelpSwEP2 L"\n ep2 Expand paths to full"
#define MCHelpSwEP3 L"\n ep3 Expand paths to full including the drive letter"
#define MCHelpSwEP4 L"\n ep4<path> Exclude the path prefix from names"
#define MCHelpSwF L"\n f Freshen files"
#define MCHelpSwHP L"\n hp[password] Encrypt both file data and headers"
#define MCHelpSwHT L"\n ht[b|c] Select hash type [BLAKE2,CRC32] for file checksum"
@ -95,6 +95,7 @@
#define MCHelpSwMA L"\n ma[4|5] Specify a version of archiving format"
#define MCHelpSwMC L"\n mc<par> Set advanced compression parameters"
#define MCHelpSwMD L"\n md<n>[k,m,g] Dictionary size in KB, MB or GB"
#define MCHelpSwME L"\n me[par] Set encryption parameters"
#define MCHelpSwMS L"\n ms[ext;ext] Specify file types to store"
#define MCHelpSwMT L"\n mt<threads> Set the number of threads"
#define MCHelpSwN L"\n n<file> Additionally filter included files"
@ -106,11 +107,11 @@
#define MCHelpSwOI L"\n oi[0-4][:min] Save identical files as references"
#define MCHelpSwOL L"\n ol[a] Process symbolic links as the link [absolute paths]"
#define MCHelpSwONI L"\n oni Allow potentially incompatible names"
#define MCHelpSwOP L"\n op<path> Set the output path for extracted files"
#define MCHelpSwOR L"\n or Rename files automatically"
#define MCHelpSwOS L"\n os Save NTFS streams"
#define MCHelpSwOW L"\n ow Save or restore file owner and group"
#define MCHelpSwP L"\n p[password] Set password"
#define MCHelpSwPm L"\n p- Do not query password"
#define MCHelpSwQO L"\n qo[-|+] Add quick open information [none|force]"
#define MCHelpSwR L"\n r Recurse subdirectories"
#define MCHelpSwRm L"\n r- Disable recursion"
@ -272,6 +273,9 @@
#define MListMtime L"mtime"
#define MListCtime L"ctime"
#define MListAtime L"atime"
#define MListModified L"Modified"
#define MListCreated L"Created"
#define MListAccessed L"Accessed"
#define MListAttr L"Attributes"
#define MListFlags L"Flags"
#define MListCompInfo L"Compression"
@ -385,3 +389,8 @@
#define MErrReadTrunc L"\n%s is archived incompletely because of read error.\n"
#define MErrReadCount L"\n%u files are archived incompletely because of read errors."
#define MDirNameExists L"\nDirectory with such name already exists"
#define MStdinNoInput L"\nKeyboard input is not allowed when reading data from stdin"
#define MTruncPsw L"\nPassword exceeds the maximum allowed length of %u characters and will be truncated."
#define MAdjustValue L"\nAdjusting %s value to %s."
#define MOpFailed L"\nOperation failed"
#define MSkipEncArc L"\nSkipping the encrypted archive %s"

View file

@ -123,7 +123,7 @@ UNRAR_OBJ=filestr.o recvol.o rs.o scantree.o qopen.o
LIB_OBJ=filestr.o scantree.o dll.o qopen.o
OBJECTS=rar.o strlist.o strfn.o pathfn.o smallfn.o global.o file.o filefn.o filcreat.o \
archive.o arcread.o unicode.o system.o isnt.o crypt.o crc.o rawread.o encname.o \
archive.o arcread.o unicode.o system.o crypt.o crc.o rawread.o encname.o \
resource.o match.o timefn.o rdwrfn.o consio.o options.o errhnd.o rarvm.o secpassword.o \
rijndael.o getbits.o sha1.o sha256.o blake2s.o hash.o extinfo.o extract.o volume.o \
list.o find.o unpack.o headers.o threadpool.o rs16.o cmddata.o ui.o

View file

@ -116,9 +116,11 @@ class RAROptions
RAR_CHARSET ErrlogCharset;
RAR_CHARSET RedirectCharset;
wchar ArcPath[NM];
wchar ArcPath[NM]; // For -ap<path>.
wchar ExclArcPath[NM]; // For -ep4<path> switch.
SecPassword Password;
bool EncryptHeaders;
bool SkipEncrypted;
bool ManualPassword; // Password entered manually during operation, might need to clean for next archive.
@ -195,7 +197,11 @@ class RAROptions
EXTTIME_MODE xctime;
EXTTIME_MODE xatime;
bool PreserveAtime;
wchar CompressStdin[NM];
// Read data from stdin and store in archive under a name specified here
// when archiving. Read an archive from stdin if any non-empty string
// is specified here when extracting.
wchar UseStdin[NM];
uint Threads; // We use it to init hash even if RAR_SMP is not defined.

View file

@ -36,12 +36,11 @@
// re-definition warnings in third party projects.
#ifndef UNICODE
#define UNICODE
#define _UNICODE // Set _T() macro to convert from narrow to wide strings.
#endif
#undef WINVER
#undef _WIN32_WINNT
#define WINVER 0x0501
#define _WIN32_WINNT 0x0501
#define WINVER _WIN32_WINNT_WINXP
#define _WIN32_WINNT _WIN32_WINNT_WINXP
#if !defined(ZIPSFX)
#define RAR_SMP
@ -79,8 +78,11 @@
#include <direct.h>
#include <intrin.h>
#define USE_SSE
#define SSE_ALIGNMENT 16
// Use SSE only for x86/x64, not ARM Windows.
#if defined(_M_IX86) || defined(_M_X64)
#define USE_SSE
#define SSE_ALIGNMENT 16
#endif
#else
#include <dirent.h>
#endif // _MSC_VER
@ -212,7 +214,8 @@
#endif
#endif
#if _POSIX_C_SOURCE >= 200809L
// Unlike Apple x64, utimensat shall be available in all Apple M1 systems.
#if _POSIX_C_SOURCE >= 200809L || defined(__APPLE__) && defined(__arm64__)
#define UNIX_TIME_NS // Nanosecond time precision in Unix.
#endif

View file

@ -5,7 +5,7 @@ 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 && IsDriveDiv(Path[1])) ? Path+2:Path);
return (wchar*)((*Path!=0 && IsDriveDiv(Path[1])) ? Path+2:Path);
}
@ -319,6 +319,9 @@ void GetConfigName(const wchar *Name,wchar *FullName,size_t MaxSize,bool CheckEx
// of file name if numeric part is missing.
wchar* GetVolNumPart(const wchar *ArcName)
{
// We do not want to increment any characters in path component.
ArcName=PointToName(ArcName);
if (*ArcName==0)
return (wchar *)ArcName;
@ -342,7 +345,7 @@ wchar* GetVolNumPart(const wchar *ArcName)
{
// Validate the first numeric part only if it has a dot somewhere
// before it.
wchar *Dot=wcschr(PointToName(ArcName),'.');
const wchar *Dot=wcschr(ArcName,'.');
if (Dot!=NULL && Dot<NumPtr)
ChPtr=NumPtr;
break;
@ -694,7 +697,8 @@ static void GenArcName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,u
wchar Mask[MAX_GENERATE_MASK];
wcsncpyz(Mask,*GenerateMask!=0 ? GenerateMask:L"yyyymmddhhmmss",ASIZE(Mask));
bool QuoteMode=false,Hours=false;
bool QuoteMode=false;
uint MAsMinutes=0; // By default we treat 'M' as months.
for (uint I=0;Mask[I]!=0;I++)
{
if (Mask[I]=='{' || Mask[I]=='}')
@ -706,13 +710,16 @@ static void GenArcName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,u
continue;
int CurChar=toupperw(Mask[I]);
if (CurChar=='H')
Hours=true;
MAsMinutes=2; // Treat next two 'M' after 'H' as minutes.
if (CurChar=='D' || CurChar=='Y')
MAsMinutes=0; // Treat 'M' in HHDDMMYY and HHYYMMDD as month.
if (Hours && CurChar=='M')
if (MAsMinutes>0 && CurChar=='M')
{
// Replace minutes with 'I'. We use 'M' both for months and minutes,
// so we treat as minutes only those 'M' which are found after hours.
// so we treat as minutes only those 'M', which are found after hours.
Mask[I]='I';
MAsMinutes--;
}
if (CurChar=='N')
{
@ -776,7 +783,9 @@ static void GenArcName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,u
const wchar *MaskChars=L"YMDHISWAEN";
// How many times every modifier character was encountered in the mask.
int CField[sizeof(Field)/sizeof(Field[0])];
memset(CField,0,sizeof(CField));
QuoteMode=false;
for (uint I=0;Mask[I]!=0;I++)
@ -818,13 +827,22 @@ static void GenArcName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,u
{
size_t FieldPos=ChPtr-MaskChars;
int CharPos=(int)strlen(Field[FieldPos])-CField[FieldPos]--;
if (FieldPos==1 && toupperw(Mask[I+1])=='M' && toupperw(Mask[I+2])=='M')
// CField[FieldPos] shall have exactly 3 "MMM" symbols, so we do not
// repeat the month name in case "MMMMMMMM" mask. But since we
// decremented CField[FieldPos] above, we compared it with 2.
if (FieldPos==1 && CField[FieldPos]==2 &&
toupperw(Mask[I+1])=='M' && toupperw(Mask[I+2])=='M')
{
wcsncpyz(DateText+J,GetMonthName(rlt.Month-1),ASIZE(DateText)-J);
J=wcslen(DateText);
I+=2;
continue;
}
// If CharPos is negative, we have more modifier characters than
// matching time data. We prefer to issue a modifier character
// instead of repeating time data from beginning, so user can notice
// excessive modifiers added by mistake.
if (CharPos<0)
DateText[J]=Mask[I];
else
@ -987,9 +1005,9 @@ void ConvertToPrecomposed(wchar *Name,size_t NameSize)
}
// Remove trailing spaces and dots in file name and in dir names in path.
void MakeNameCompatible(wchar *Name)
void MakeNameCompatible(wchar *Name,size_t MaxSize)
{
// Remove trailing spaces and dots in file name and in dir names in path.
int Src=0,Dest=0;
while (true)
{
@ -1007,5 +1025,47 @@ void MakeNameCompatible(wchar *Name)
Src++;
Dest++;
}
// Rename reserved device names, such as aux.txt to _aux.txt.
// We check them in path components too, where they are also prohibited.
for (uint I=0;Name[I]!=0;I++)
if (I==0 || I>0 && IsPathDiv(Name[I-1]))
{
static const wchar *Devices[]={L"CON",L"PRN",L"AUX",L"NUL",L"COM#",L"LPT#"};
wchar *s=Name+I;
bool MatchFound=false;
for (uint J=0;J<ASIZE(Devices);J++)
for (uint K=0;;K++)
if (Devices[J][K]=='#')
{
if (!IsDigit(s[K]))
break;
}
else
if (Devices[J][K]==0)
{
// Names like aux.txt are accessible without \\?\ prefix
// since Windows 11. Pure aux is still prohibited.
MatchFound=s[K]==0 || s[K]=='.' && !IsWindows11OrGreater() || IsPathDiv(s[K]);
break;
}
else
if (Devices[J][K]!=toupperw(s[K]))
break;
if (MatchFound)
{
wchar OrigName[NM];
wcsncpyz(OrigName,Name,ASIZE(OrigName));
if (MaxSize>I+1) // I+1, because we do not move the trailing 0.
memmove(s+1,s,(MaxSize-I-1)*sizeof(*s));
*s='_';
#ifndef SFX_MODULE
uiMsg(UIMSG_CORRECTINGNAME,nullptr);
uiMsg(UIERROR_RENAMING,nullptr,OrigName,Name);
#endif
}
}
}
#endif

View file

@ -70,7 +70,8 @@ void GenerateArchiveName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask
#ifdef _WIN_ALL
bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize);
void ConvertToPrecomposed(wchar *Name,size_t NameSize);
void MakeNameCompatible(wchar *Name);
void MakeNameCompatible(wchar *Name,size_t MaxSize);
#endif
#endif

View file

@ -16,6 +16,7 @@
#include "errhnd.hpp"
#include "secpassword.hpp"
#include "array.hpp"
#include "strlist.hpp"
#include "timefn.hpp"
#include "sha1.hpp"
#include "sha256.hpp"
@ -28,7 +29,6 @@
#include "headers.hpp"
#include "pathfn.hpp"
#include "strfn.hpp"
#include "strlist.hpp"
#ifdef _WIN_ALL
#include "isnt.hpp"
#endif

View file

@ -16,6 +16,7 @@ void ComprDataIO::Init()
UnpackFromMemory=false;
UnpackToMemory=false;
UnpPackedSize=0;
UnpPackedLeft=0;
ShowProgress=true;
TestMode=false;
SkipUnpCRC=false;
@ -35,7 +36,9 @@ void ComprDataIO::Init()
SubHead=NULL;
SubHeadPos=NULL;
CurrentCommand=0;
ProcessedArcSize=TotalArcSize=0;
ProcessedArcSize=0;
LastArcSize=0;
TotalArcSize=0;
}
@ -75,10 +78,10 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count)
}
else
{
size_t SizeToRead=((int64)Count>UnpPackedSize) ? (size_t)UnpPackedSize:Count;
size_t SizeToRead=((int64)Count>UnpPackedLeft) ? (size_t)UnpPackedLeft:Count;
if (SizeToRead > 0)
{
if (UnpVolume && Decryption && (int64)Count>UnpPackedSize)
if (UnpVolume && Decryption && (int64)Count>UnpPackedLeft)
{
// We need aligned blocks for decryption and we want "Keep broken
// files" to work efficiently with missing encrypted volumes.
@ -109,7 +112,7 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count)
ReadAddr+=ReadSize;
Count-=ReadSize;
#endif
UnpPackedSize-=ReadSize;
UnpPackedLeft-=ReadSize;
// Do not ask for next volume if we read something from current volume.
// If next volume is missing, we need to process all data from current
@ -118,7 +121,7 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count)
// we ask for next volume also if we have non-aligned encryption block.
// Since we adjust data size for decryption earlier above,
// it does not hurt "Keep broken files" mode efficiency.
if (UnpVolume && UnpPackedSize == 0 &&
if (UnpVolume && UnpPackedLeft == 0 &&
(ReadSize==0 || Decryption && (TotalRead & CRYPT_BLOCK_MASK) != 0) )
{
#ifndef NOVOLUME
@ -134,7 +137,7 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count)
}
Archive *SrcArc=(Archive *)SrcFile;
if (SrcArc!=NULL)
ShowUnpRead(SrcArc->CurBlockPos+CurUnpRead,UnpArcSize);
ShowUnpRead(SrcArc->NextBlockPos-UnpPackedSize+CurUnpRead,TotalArcSize);
if (ReadSize!=-1)
{
ReadSize=TotalRead;
@ -148,13 +151,6 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count)
}
#if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
// Disable the run time stack check for unrar.dll, so we can manipulate
// with ProcessDataProc call type below. Run time check would intercept
// a wrong ESP before we restore it.
#pragma runtime_checks( "s", off )
#endif
void ComprDataIO::UnpWrite(byte *Addr,size_t Count)
{
@ -167,28 +163,7 @@ void ComprDataIO::UnpWrite(byte *Addr,size_t Count)
ErrHandler.Exit(RARX_USERBREAK);
if (Cmd->ProcessDataProc!=NULL)
{
// Here we preserve ESP value. It is necessary for those developers,
// who still define ProcessDataProc callback as "C" type function,
// even though in year 2001 we announced in unrar.dll whatsnew.txt
// that it will be PASCAL type (for compatibility with Visual Basic).
#if defined(_MSC_VER)
#ifndef _WIN_64
__asm mov ebx,esp
#endif
#elif defined(_WIN_ALL) && defined(__BORLANDC__)
_EBX=_ESP;
#endif
int RetCode=Cmd->ProcessDataProc(Addr,(int)Count);
// Restore ESP after ProcessDataProc with wrongly defined calling
// convention broken it.
#if defined(_MSC_VER)
#ifndef _WIN_64
__asm mov esp,ebx
#endif
#elif defined(_WIN_ALL) && defined(__BORLANDC__)
_ESP=_EBX;
#endif
if (RetCode==0)
ErrHandler.Exit(RARX_USERBREAK);
}
@ -216,11 +191,6 @@ void ComprDataIO::UnpWrite(byte *Addr,size_t Count)
Wait();
}
#if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
// Restore the run time stack check for unrar.dll.
#pragma runtime_checks( "s", restore )
#endif
@ -230,12 +200,8 @@ void ComprDataIO::ShowUnpRead(int64 ArcPos,int64 ArcSize)
{
if (ShowProgress && SrcFile!=NULL)
{
if (TotalArcSize!=0)
{
// important when processing several archives or multivolume archive
ArcSize=TotalArcSize;
ArcPos+=ProcessedArcSize;
}
// Important when processing several archives or multivolume archive.
ArcPos+=ProcessedArcSize;
Archive *SrcArc=(Archive *)SrcFile;
RAROptions *Cmd=SrcArc->GetRAROptions();
@ -319,3 +285,38 @@ void ComprDataIO::SetUnpackToMemory(byte *Addr,uint Size)
UnpackToMemoryAddr=Addr;
UnpackToMemorySize=Size;
}
// Extraction progress is based on the position in archive and we adjust
// the total archives size here, so trailing blocks do not prevent progress
// reaching 100% at the end of extraction. Alternatively we could print "100%"
// after completing the entire archive extraction, but then we would need
// to take into account possible messages like the checksum error after
// last file percent progress.
void ComprDataIO::AdjustTotalArcSize(Archive *Arc)
{
// If we know a position of QO or RR blocks, use them to adjust the total
// packed size to beginning of these blocks. Earlier we already calculated
// the total size based on entire archive sizes. We also set LastArcSize
// to start of first trailing block, to add it later to ProcessedArcSize.
int64 ArcLength=Arc->IsSeekable() ? Arc->FileLength() : 0;
if (Arc->MainHead.QOpenOffset!=0) // QO is always preceding RR record.
LastArcSize=Arc->MainHead.QOpenOffset;
else
if (Arc->MainHead.RROffset!=0)
LastArcSize=Arc->MainHead.RROffset;
else
{
// If neither QO nor RR are found, exclude the approximate size of
// end of archive block.
// We select EndBlock to be larger than typical 8 bytes HEAD_ENDARC,
// but to not exceed the smallest 22 bytes HEAD_FILE with 1 byte file
// name, so we do not have two files with 100% at the end of archive.
const uint EndBlock=23;
if (ArcLength>EndBlock)
LastArcSize=ArcLength-EndBlock;
}
TotalArcSize-=ArcLength-LastArcSize;
}

View file

@ -1,6 +1,7 @@
#ifndef _RAR_DATAIO_
#define _RAR_DATAIO_
class Archive;
class CmdAdd;
class Unpack;
class ArcFileSearch;
@ -29,6 +30,7 @@ class ComprDataIO
byte *UnpWrAddr;
int64 UnpPackedSize;
int64 UnpPackedLeft;
bool ShowProgress;
bool TestMode;
@ -61,7 +63,7 @@ class ComprDataIO
void UnpWrite(byte *Addr,size_t Count);
void EnableShowProgress(bool Show) {ShowProgress=Show;}
void GetUnpackedData(byte **Data,size_t *Size);
void SetPackedSizeToRead(int64 Size) {UnpPackedSize=Size;}
void SetPackedSizeToRead(int64 Size) {UnpPackedSize=UnpPackedLeft=Size;}
void SetTestMode(bool Mode) {TestMode=Mode;}
void SetSkipUnpCRC(bool Skip) {SkipUnpCRC=Skip;}
void SetNoFileHeader(bool Mode) {NoFileHeader=Mode;}
@ -74,12 +76,12 @@ class ComprDataIO
void SetCmt13Encryption();
void SetUnpackToMemory(byte *Addr,uint Size);
void SetCurrentCommand(wchar Cmd) {CurrentCommand=Cmd;}
void AdjustTotalArcSize(Archive *Arc);
bool PackVolume;
bool UnpVolume;
bool NextVolumeMissing;
int64 UnpArcSize;
int64 CurPackRead,CurPackWrite,CurUnpRead,CurUnpWrite;
@ -87,6 +89,9 @@ class ComprDataIO
// Used to calculate the total operation progress.
int64 ProcessedArcSize;
// Last extracted archive size up to QO or RR block.
int64 LastArcSize;
int64 TotalArcSize;
DataHash PackedDataHash; // Packed write and unpack read hash.

View file

@ -1,5 +1,9 @@
static const uint MaxVolumes=65535;
// We select this limit arbitrarily, to prevent user creating too many
// rev files by mistake.
#define MAX_REV_TO_DATA_RATIO 10 // 1000% of rev files.
RecVolumes5::RecVolumes5(RAROptions *Cmd,bool TestOnly)
{
RealBuf=NULL;
@ -145,13 +149,16 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
wchar *Num=GetVolNumPart(ArcName);
while (Num>ArcName && IsDigit(*(Num-1)))
Num--;
if (Num==ArcName)
if (Num<=PointToName(ArcName))
return false; // Numeric part is missing or entire volume name is numeric, not possible for RAR or REV volume.
wcsncpyz(Num,L"*.*",ASIZE(ArcName)-(Num-ArcName));
wchar FirstVolName[NM];
*FirstVolName=0;
wchar LongestRevName[NM];
*LongestRevName=0;
int64 RecFileSize=0;
FindFile VolFind;
@ -164,7 +171,7 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
Archive *Vol=new Archive(Cmd);
int ItemPos=-1;
if (Vol->WOpen(fd.Name))
if (!fd.IsDir && Vol->WOpen(fd.Name))
{
if (CmpExt(fd.Name,L"rev"))
{
@ -176,6 +183,9 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
ItemPos=RecNum;
FoundRecVolumes++;
if (wcslen(fd.Name)>wcslen(LongestRevName))
wcsncpyz(LongestRevName,fd.Name,ASIZE(LongestRevName));
}
}
else
@ -231,6 +241,15 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
if (FoundRecVolumes==0)
return false;
// If we did not find even a single .rar volume, create .rar volume name
// based on the longest .rev file name. Use longest .rev, so we have
// enough space for volume number.
if (*FirstVolName==0)
{
SetExt(LongestRevName,L"rar",ASIZE(LongestRevName));
VolNameToFirstName(LongestRevName,FirstVolName,ASIZE(FirstVolName),true);
}
uiMsg(UIMSG_RECVOLCALCCHECKSUM);
MissingVolumes=0;
@ -301,7 +320,7 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
Item->f=NULL;
}
if ((Item->New=(Item->f==NULL))) // Additional parentheses to avoid GCC warning.
if ((Item->New=(Item->f==NULL))==true)
{
wcsncpyz(Item->Name,FirstVolName,ASIZE(Item->Name));
uiMsg(UIMSG_CREATING,Item->Name);
@ -316,7 +335,6 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
}
NewVol->Prealloc(Item->FileSize);
Item->f=NewVol;
Item->New=true;
}
NextVolumeName(FirstVolName,ASIZE(FirstVolName),false);
}
@ -346,13 +364,11 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
RecBufferSize&=~(SSE_ALIGNMENT-1); // Align for SSE.
#endif
uint *Data=new uint[TotalCount];
RSCoder16 RS;
if (!RS.Init(DataCount,RecCount,ValidFlags))
{
uiMsg(UIERROR_OPFAILED);
delete[] ValidFlags;
delete[] Data;
return false; // Should not happen, we check parameter validity above.
}
@ -415,7 +431,6 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
RecItems[I].f->Close();
delete[] ValidFlags;
delete[] Data;
#if !defined(SILENT)
if (!Cmd->DisablePercentage)
mprintf(L"\b\b\b\b100%%");

View file

@ -1,22 +1,41 @@
/***************************************************************************
* This code is based on public domain Szymon Stefanek AES implementation: *
* http://www.pragmaware.net/software/rijndael/index.php *
* *
* Dynamic tables generation is based on the Brian Gladman work: *
* http://fp.gladman.plus.com/cryptography_technology/rijndael *
***************************************************************************/
/**************************************************************************
* This code is based on Szymon Stefanek public domain AES implementation *
**************************************************************************/
#include "rar.hpp"
#ifdef USE_SSE
#include <wmmintrin.h>
#endif
static byte S[256],S5[256],rcon[30];
static byte S[256]=
{
99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118,
202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192,
183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21,
4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117,
9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132,
83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207,
208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168,
81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210,
205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115,
96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219,
224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121,
231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8,
186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138,
112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158,
225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223,
140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22
};
static byte S5[256];
// Round constants. 10 items are used by AES-128, 8 by AES-192, 7 by AES-256.
static byte rcon[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36};
static byte T1[256][4],T2[256][4],T3[256][4],T4[256][4];
static byte T5[256][4],T6[256][4],T7[256][4],T8[256][4];
static byte U1[256][4],U2[256][4],U3[256][4],U4[256][4];
inline void Xor128(void *dest,const void *arg1,const void *arg2)
{
#ifdef ALLOW_MISALIGNED
@ -63,7 +82,7 @@ inline void Copy128(byte *dest,const byte *src)
Rijndael::Rijndael()
{
if (S[0]==0)
if (S5[0]==0)
GenerateTables();
CBCMode = true; // Always true for RAR.
}
@ -82,7 +101,7 @@ void Rijndael::Init(bool Encrypt,const byte *key,uint keyLen,const byte * initVe
AES_NI=(CPUInfo[2] & 0x2000000)!=0;
}
else
AES_NI=0;
AES_NI=false;
#endif
// Other developers asked us to initialize it to suppress "may be used
@ -416,51 +435,40 @@ void Rijndael::keyEncToDec()
}
#define ff_poly 0x011b
#define ff_hi 0x80
static byte gmul(byte a, byte b) // Galois field "peasant's algorithm" multiplication.
{
const byte poly=0x1b; // Lower byte of AES 0x11b irreducible polynomial.
byte result = 0;
while (b>0)
{
if ((b & 1) != 0)
result ^= a;
a = (a & 0x80) ? (a<<1)^poly : a<<1;
b >>= 1;
}
return result;
}
#define FFinv(x) ((x) ? pow[255 - log[x]]: 0)
#define FFmul02(x) (x ? pow[log[x] + 0x19] : 0)
#define FFmul03(x) (x ? pow[log[x] + 0x01] : 0)
#define FFmul09(x) (x ? pow[log[x] + 0xc7] : 0)
#define FFmul0b(x) (x ? pow[log[x] + 0x68] : 0)
#define FFmul0d(x) (x ? pow[log[x] + 0xee] : 0)
#define FFmul0e(x) (x ? pow[log[x] + 0xdf] : 0)
#define fwd_affine(x) \
(w = (uint)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), (byte)(0x63^(w^(w>>8))))
#define inv_affine(x) \
(w = (uint)x, w = (w<<1)^(w<<3)^(w<<6), (byte)(0x05^(w^(w>>8))))
// 2021-09-24: changed to slower and simpler code without interim tables.
// It is still fast enough for our purpose.
void Rijndael::GenerateTables()
{
unsigned char pow[512],log[256];
int i = 0, w = 1;
do
{
pow[i] = (byte)w;
pow[i + 255] = (byte)w;
log[w] = (byte)i++;
w ^= (w << 1) ^ (w & ff_hi ? ff_poly : 0);
} while (w != 1);
for (int I=0;I<256;I++)
S5[S[I]]=I;
for (int i = 0,w = 1; i < sizeof(rcon)/sizeof(rcon[0]); i++)
for (int I=0;I<256;I++)
{
rcon[i] = w;
w = (w << 1) ^ (w & ff_hi ? ff_poly : 0);
}
for(int i = 0; i < 256; ++i)
{
unsigned char b=S[i]=fwd_affine(FFinv((byte)i));
T1[i][1]=T1[i][2]=T2[i][2]=T2[i][3]=T3[i][0]=T3[i][3]=T4[i][0]=T4[i][1]=b;
T1[i][0]=T2[i][1]=T3[i][2]=T4[i][3]=FFmul02(b);
T1[i][3]=T2[i][0]=T3[i][1]=T4[i][2]=FFmul03(b);
S5[i] = b = FFinv(inv_affine((byte)i));
U1[b][3]=U2[b][0]=U3[b][1]=U4[b][2]=T5[i][3]=T6[i][0]=T7[i][1]=T8[i][2]=FFmul0b(b);
U1[b][1]=U2[b][2]=U3[b][3]=U4[b][0]=T5[i][1]=T6[i][2]=T7[i][3]=T8[i][0]=FFmul09(b);
U1[b][2]=U2[b][3]=U3[b][0]=U4[b][1]=T5[i][2]=T6[i][3]=T7[i][0]=T8[i][1]=FFmul0d(b);
U1[b][0]=U2[b][1]=U3[b][2]=U4[b][3]=T5[i][0]=T6[i][1]=T7[i][2]=T8[i][3]=FFmul0e(b);
byte s=S[I];
T1[I][1]=T1[I][2]=T2[I][2]=T2[I][3]=T3[I][0]=T3[I][3]=T4[I][0]=T4[I][1]=s;
T1[I][0]=T2[I][1]=T3[I][2]=T4[I][3]=gmul(s,2);
T1[I][3]=T2[I][0]=T3[I][1]=T4[I][2]=gmul(s,3);
byte b=S5[I];
U1[b][3]=U2[b][0]=U3[b][1]=U4[b][2]=T5[I][3]=T6[I][0]=T7[I][1]=T8[I][2]=gmul(b,0xb);
U1[b][1]=U2[b][2]=U3[b][3]=U4[b][0]=T5[I][1]=T6[I][2]=T7[I][3]=T8[I][0]=gmul(b,0x9);
U1[b][2]=U2[b][3]=U3[b][0]=U4[b][1]=T5[I][2]=T6[I][3]=T7[I][0]=T8[I][1]=gmul(b,0xd);
U1[b][0]=U2[b][1]=U3[b][2]=U4[b][3]=T5[I][0]=T6[I][1]=T7[I][2]=T8[I][3]=gmul(b,0xe);
}
}

View file

@ -2,11 +2,7 @@
#define _RIJNDAEL_H_
/**************************************************************************
* This code is based on Szymon Stefanek AES implementation: *
* http://www.esat.kuleuven.ac.be/~rijmen/rijndael/rijndael-cpplib.tar.gz *
* *
* Dynamic tables generation is based on the Brian Gladman's work: *
* http://fp.gladman.plus.com/cryptography_technology/rijndael *
* This code is based on Szymon Stefanek public domain AES implementation *
**************************************************************************/
#define _MAX_KEY_COLUMNS (256/32)

View file

@ -95,7 +95,9 @@ bool RSCoder16::Init(uint DataCount, uint RecCount, bool *ValidityFlags)
if (NE > ValidECC || NE == 0 || ValidECC == 0)
return false;
}
if (ND + NR > gfSize || NR > ND || ND == 0 || NR == 0)
// 2021.09.01 - we allowed RR and REV >100%, so no more NR > ND check.
if (ND + NR > gfSize || /*NR > ND ||*/ ND == 0 || NR == 0)
return false;
delete[] MX;

View file

@ -121,48 +121,26 @@ wchar* RemoveLF(wchar *Str)
}
unsigned char loctolower(unsigned char ch)
{
#if defined(_WIN_ALL)
// Convert to LPARAM first to avoid a warning in 64 bit mode.
// Convert to uintptr_t to avoid Clang/win error: cast to 'char *' from smaller integer type 'unsigned char' [-Werror,-Wint-to-pointer-cast]
return (int)(LPARAM)CharLowerA((LPSTR)(uintptr_t)ch);
#else
return tolower(ch);
#endif
}
unsigned char loctoupper(unsigned char ch)
{
#if defined(_WIN_ALL)
// Convert to LPARAM first to avoid a warning in 64 bit mode.
// Convert to uintptr_t to avoid Clang/win error: cast to 'char *' from smaller integer type 'unsigned char' [-Werror,-Wint-to-pointer-cast]
return (int)(LPARAM)CharUpperA((LPSTR)(uintptr_t)ch);
#else
return toupper(ch);
#endif
}
// toupper with English only results if English input is provided.
// It avoids Turkish (small i) -> (big I with dot) conversion problem.
// We do not define 'ch' as 'int' to avoid necessity to cast all
#if defined(SFX_MODULE)
// char version of etoupperw. Used in console SFX module only.
// Fast toupper for English only input and output. Additionally to speed,
// it also avoids Turkish small i to big I with dot conversion problem.
// We do not define 'c' as 'int' to avoid necessity to cast all
// signed chars passed to this function to unsigned char.
unsigned char etoupper(unsigned char ch)
unsigned char etoupper(unsigned char c)
{
if (ch=='i')
return 'I';
return toupper(ch);
return c>='a' && c<='z' ? c-'a'+'A' : c;
}
#endif
// Unicode version of etoupper.
wchar etoupperw(wchar ch)
// Fast toupper for English only input and output. Additionally to speed,
// it also avoids Turkish small i to big I with dot conversion problem.
// We do not define 'c' as 'int' to avoid necessity to cast all
// signed wchars passed to this function to unsigned char.
wchar etoupperw(wchar c)
{
if (ch=='i')
return 'I';
return toupperw(ch);
return c>='a' && c<='z' ? c-'a'+'A' : c;
}

View file

@ -13,16 +13,16 @@ int stricomp(const char *s1,const char *s2);
int strnicomp(const char *s1,const char *s2,size_t n);
wchar* RemoveEOL(wchar *Str);
wchar* RemoveLF(wchar *Str);
unsigned char loctolower(unsigned char ch);
unsigned char loctoupper(unsigned char ch);
void strncpyz(char *dest, const char *src, size_t maxlen);
void wcsncpyz(wchar *dest, const wchar *src, size_t maxlen);
void strncatz(char* dest, const char* src, size_t maxlen);
void wcsncatz(wchar* dest, const wchar* src, size_t maxlen);
unsigned char etoupper(unsigned char ch);
wchar etoupperw(wchar ch);
#if defined(SFX_MODULE)
unsigned char etoupper(unsigned char c);
#endif
wchar etoupperw(wchar c);
bool IsDigit(int ch);
bool IsSpace(int ch);

View file

@ -273,12 +273,12 @@ void RarTime::SetAgeText(const wchar *TimeText)
uint Seconds=0,Value=0;
for (uint I=0;TimeText[I]!=0;I++)
{
int Ch=TimeText[I];
wchar Ch=TimeText[I];
if (IsDigit(Ch))
Value=Value*10+Ch-'0';
else
{
switch(etoupper(Ch))
switch(etoupperw(Ch))
{
case 'D':
Seconds+=Value*24*3600;

View file

@ -39,7 +39,7 @@ enum UIMESSAGE_CODE {
UIERROR_UOWNERBROKEN, UIERROR_UOWNERGETOWNERID, UIERROR_UOWNERGETGROUPID,
UIERROR_UOWNERSET, UIERROR_ULINKREAD, UIERROR_ULINKEXIST,
UIERROR_OPENPRESERVEATIME, UIERROR_READERRTRUNCATED, UIERROR_READERRCOUNT,
UIERROR_DIRNAMEEXISTS,
UIERROR_DIRNAMEEXISTS,UIERROR_TRUNCPSW,UIERROR_ADJUSTVALUE,
UIMSG_FIRST,
UIMSG_STRING, UIMSG_BUILD, UIMSG_RRSEARCH, UIMSG_ANALYZEFILEDATA,
@ -49,6 +49,7 @@ enum UIMESSAGE_CODE {
UIMSG_CORRECTINGNAME, UIMSG_BADARCHIVE, UIMSG_CREATING, UIMSG_RENAMING,
UIMSG_RECVOLCALCCHECKSUM, UIMSG_RECVOLFOUND, UIMSG_RECVOLMISSING,
UIMSG_MISSINGVOL, UIMSG_RECONSTRUCTING, UIMSG_CHECKSUM, UIMSG_FAT32SIZE,
UIMSG_SKIPENCARC,
UIWAIT_FIRST,
UIWAIT_DISKFULLNEXT, UIWAIT_FCREATEERROR, UIWAIT_BADPSW,

View file

@ -71,7 +71,10 @@ bool uiStartFileExtract(const wchar *FileName,bool Extract,bool Test,bool Skip)
void uiExtractProgress(int64 CurFileSize,int64 TotalFileSize,int64 CurSize,int64 TotalSize)
{
int CurPercent=ToPercent(CurSize,TotalSize);
// We set the total size to 0 to update only the current progress and keep
// the total progress intact in WinRAR. Unlike WinRAR, console RAR has only
// the total progress and updates it with current values in such case.
int CurPercent=TotalSize!=0 ? ToPercent(CurSize,TotalSize) : ToPercent(CurFileSize,TotalFileSize);
mprintf(L"\b\b\b\b%3d%%",CurPercent);
}
@ -247,6 +250,9 @@ void uiMsgStore::Msg()
mprintf(L"\n"); // Needed when called from CmdExtract::ExtractCurrentFile.
break;
#ifndef SFX_MODULE
case UIERROR_OPFAILED:
Log(NULL,St(MOpFailed));
break;
case UIERROR_NEWRARFORMAT:
Log(Str[0],St(MNewRarFormat));
break;
@ -329,6 +335,13 @@ void uiMsgStore::Msg()
case UIERROR_DIRNAMEEXISTS:
Log(NULL,St(MDirNameExists));
break;
case UIERROR_TRUNCPSW:
eprintf(St(MTruncPsw),Num[0]);
eprintf(L"\n");
break;
case UIERROR_ADJUSTVALUE:
Log(NULL,St(MAdjustValue),Str[0],Str[1]);
break;
#ifndef SFX_MODULE
case UIMSG_STRING:
@ -369,6 +382,9 @@ void uiMsgStore::Msg()
mprintf(St(MFAT32Size));
mprintf(L" "); // For progress percent.
break;
case UIMSG_SKIPENCARC:
Log(NULL,St(MSkipEncArc),Str[0]);
break;

View file

@ -50,6 +50,26 @@ static bool IsFullPath(const char *PathA) // Unix ASCII version.
}
// For security purpose we prefer to be sure that CharToWide completed
// successfully and even if it truncated a string for some reason,
// it didn't affect the number of path related characters we analyze
// in IsRelativeSymlinkSafe later.
// This check is likely to be excessive, but let's keep it anyway.
static bool SafeCharToWide(const char *Src,wchar *Dest,size_t DestSize)
{
if (!CharToWide(Src,Dest,DestSize) || *Dest==0)
return false;
uint SrcChars=0,DestChars=0;
for (uint I=0;Src[I]!=0;I++)
if (Src[I]=='/' || Src[I]=='.')
SrcChars++;
for (uint I=0;Dest[I]!=0;I++)
if (Dest[I]=='/' || Dest[I]=='.')
DestChars++;
return SrcChars==DestChars;
}
bool ExtractUnixLink30(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName)
{
char Target[NM];
@ -72,12 +92,12 @@ bool ExtractUnixLink30(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const w
return true;
wchar TargetW[NM];
CharToWide(Target,TargetW,ASIZE(TargetW));
// Check for *TargetW==0 to catch CharToWide failure.
if (!SafeCharToWide(Target,TargetW,ASIZE(TargetW)))
return false;
// Use Arc.FileHead.FileName instead of LinkName, since LinkName
// can include the destination path as a prefix, which can
// confuse IsRelativeSymlinkSafe algorithm.
if (!Cmd->AbsoluteLinks && (*TargetW==0 || IsFullPath(TargetW) ||
if (!Cmd->AbsoluteLinks && (IsFullPath(TargetW) ||
!IsRelativeSymlinkSafe(Cmd,Arc.FileHead.FileName,LinkName,TargetW)))
return false;
return UnixSymlink(Cmd,Target,LinkName,&Arc.FileHead.mtime,&Arc.FileHead.atime);
@ -100,11 +120,17 @@ bool ExtractUnixLink50(CommandData *Cmd,const wchar *Name,FileHeader *hd)
return false;
DosSlashToUnix(Target,Target,ASIZE(Target));
}
wchar TargetW[NM];
if (!SafeCharToWide(Target,TargetW,ASIZE(TargetW)))
return false;
// Use hd->FileName instead of LinkName, since LinkName can include
// the destination path as a prefix, which can confuse
// IsRelativeSymlinkSafe algorithm.
if (!Cmd->AbsoluteLinks && (IsFullPath(Target) ||
!IsRelativeSymlinkSafe(Cmd,hd->FileName,Name,hd->RedirName)))
// 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;
return UnixSymlink(Cmd,Target,Name,&hd->mtime,&hd->atime);
}

View file

@ -601,59 +601,6 @@ char* SupportDBCS::charnext(const char *s)
// to break string processing loops.
return (char *)(IsLeadByte[(byte)*s] && s[1]!=0 ? s+2:s+1);
}
size_t SupportDBCS::strlend(const char *s)
{
size_t Length=0;
while (*s!=0)
{
if (IsLeadByte[(byte)*s])
s+=2;
else
s++;
Length++;
}
return(Length);
}
char* SupportDBCS::strchrd(const char *s, int c)
{
while (*s!=0)
if (IsLeadByte[(byte)*s])
s+=2;
else
if (*s==c)
return((char *)s);
else
s++;
return(NULL);
}
void SupportDBCS::copychrd(char *dest,const char *src)
{
dest[0]=src[0];
if (IsLeadByte[(byte)src[0]])
dest[1]=src[1];
}
char* SupportDBCS::strrchrd(const char *s, int c)
{
const char *found=NULL;
while (*s!=0)
if (IsLeadByte[(byte)*s])
s+=2;
else
{
if (*s==c)
found=s;
s++;
}
return((char *)found);
}
#endif

View file

@ -33,34 +33,19 @@ class SupportDBCS
public:
SupportDBCS();
void Init();
char* charnext(const char *s);
size_t strlend(const char *s);
char *strchrd(const char *s, int c);
char *strrchrd(const char *s, int c);
void copychrd(char *dest,const char *src);
bool IsLeadByte[256];
bool DBCSMode;
};
extern SupportDBCS gdbcs;
inline char* charnext(const char *s) {return (char *)(gdbcs.DBCSMode ? gdbcs.charnext(s):s+1);}
inline size_t strlend(const char *s) {return (uint)(gdbcs.DBCSMode ? gdbcs.strlend(s):strlen(s));}
inline char* strchrd(const char *s, int c) {return (char *)(gdbcs.DBCSMode ? gdbcs.strchrd(s,c):strchr(s,c));}
inline char* strrchrd(const char *s, int c) {return (char *)(gdbcs.DBCSMode ? gdbcs.strrchrd(s,c):strrchr(s,c));}
inline void copychrd(char *dest,const char *src) {if (gdbcs.DBCSMode) gdbcs.copychrd(dest,src); else *dest=*src;}
inline bool IsDBCSMode() {return(gdbcs.DBCSMode);}
inline void InitDBCS() {gdbcs.Init();}
inline bool IsDBCSMode() {return gdbcs.DBCSMode;}
#else
#define charnext(s) ((s)+1)
#define strlend strlen
#define strchrd strchr
#define strrchrd strrchr
#define IsDBCSMode() (true)
inline void copychrd(char *dest,const char *src) {*dest=*src;}
#define IsDBCSMode() (false)
#endif

View file

@ -91,12 +91,6 @@ void Unpack::Init(size_t WinSize,bool Solid)
if ((WinSize>>16)>0x10000) // Window size must not exceed 4 GB.
return;
// Unrar does not support window size greather than 1GB at this time.
// Any request for a window larger than 1GB should be ignored.
const size_t MaxAllocSize=0x40000000;
if (WinSize>MaxAllocSize)
WinSize=MaxAllocSize;
// Archiving code guarantees that window size does not grow in the same
// solid stream. So if we are here, we are either creating a new window
// or increasing the size of non-solid window. So we could safely reject

View file

@ -23,8 +23,8 @@
// allocation. Must be equal or larger than MAX_ANALYZE_SIZE.
#define MAX_FILTER_BLOCK_SIZE 0x400000
// Write data in 4 MB or smaller blocks. Must not exceed PACK_MAX_WRITE,
// so we keep a number of buffered filters in unpacker reasonable.
// Write data in 4 MB or smaller blocks. Must not exceed PACK_MAX_READ,
// so we keep the number of buffered filters in unpacker reasonable.
#define UNPACK_MAX_WRITE 0x400000
// Decode compressed bit fields to alphabet numbers.

View file

@ -1,6 +1,6 @@
#define RARVER_MAJOR 6
#define RARVER_MINOR 2
#define RARVER_MINOR 12
#define RARVER_BETA 0
#define RARVER_DAY 11
#define RARVER_MONTH 6
#define RARVER_YEAR 2021
#define RARVER_DAY 4
#define RARVER_MONTH 5
#define RARVER_YEAR 2022

View file

@ -25,10 +25,12 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma
uiMsg(UIERROR_CHECKSUMPACKED, Arc.FileName, hd->FileName);
}
bool PrevVolEncrypted=Arc.Encrypted;
int64 PosBeforeClose=Arc.Tell();
if (DataIO!=NULL)
DataIO->ProcessedArcSize+=Arc.FileLength();
DataIO->ProcessedArcSize+=DataIO->LastArcSize;
Arc.Close();
@ -40,12 +42,20 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma
#if !defined(SFX_MODULE) && !defined(RARDLL)
bool RecoveryDone=false;
#endif
bool FailedOpen=false,OldSchemeTested=false;
bool OldSchemeTested=false;
bool FailedOpen=false; // No more next volume open attempts if true.
#if !defined(SILENT)
// In -vp mode we force the pause before next volume even if it is present
// and even if we are on the hard disk. It is important when user does not
// want to process partially downloaded volumes preliminary.
// 2022.01.11: In WinRAR 6.10 beta versions we tried to ignore VolumePause
// if we could open the next volume with FMF_OPENEXCLUSIVE. But another
// developer asked us to return the previous behavior and always prompt
// for confirmation. They want to control when unrar continues, because
// the next file might not be fully decoded yet. They write chunks of data
// and then close the file again until the next chunk comes in.
if (Cmd->VolumePause && !uiAskNextVolume(NextName,ASIZE(NextName)))
FailedOpen=true;
#endif
@ -127,6 +137,16 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma
return false;
#endif
if (Arc.Encrypted!=PrevVolEncrypted)
{
// There is no legitimate reason for encrypted header state to be
// changed in the middle of volume sequence. So we abort here to prevent
// replacing an encrypted header volume to unencrypted and adding
// unexpected files by third party to encrypted extraction.
uiMsg(UIERROR_BADARCHIVE,Arc.FileName);
ErrHandler.Exit(RARX_FATAL);
}
if (SplitHeader)
Arc.SearchBlock(HeaderType);
else
@ -151,9 +171,8 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma
DataIO->UnpVolume=hd->SplitAfter;
DataIO->SetPackedSizeToRead(hd->PackSize);
}
#ifdef SFX_MODULE
DataIO->UnpArcSize=Arc.FileLength();
#endif
DataIO->AdjustTotalArcSize(&Arc);
// Reset the size of packed data read from current volume. It is used
// to display the total progress and preceding volumes are already
@ -171,13 +190,6 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma
#ifdef RARDLL
#if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
// Disable the run time stack check for unrar.dll, so we can manipulate
// with ChangeVolProc call type below. Run time check would intercept
// a wrong ESP before we restore it.
#pragma runtime_checks( "s", off )
#endif
bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize)
{
bool DllVolChanged=false,DllVolAborted=false;
@ -212,28 +224,7 @@ bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize)
{
char NextNameA[NM];
WideToChar(NextName,NextNameA,ASIZE(NextNameA));
// Here we preserve ESP value. It is necessary for those developers,
// who still define ChangeVolProc callback as "C" type function,
// even though in year 2001 we announced in unrar.dll whatsnew.txt
// that it will be PASCAL type (for compatibility with Visual Basic).
#if defined(_MSC_VER)
#ifndef _WIN_64
__asm mov ebx,esp
#endif
#elif defined(_WIN_ALL) && defined(__BORLANDC__)
_EBX=_ESP;
#endif
int RetCode=Cmd->ChangeVolProc(NextNameA,RAR_VOL_ASK);
// Restore ESP after ChangeVolProc with wrongly defined calling
// convention broken it.
#if defined(_MSC_VER)
#ifndef _WIN_64
__asm mov esp,ebx
#endif
#elif defined(_WIN_ALL) && defined(__BORLANDC__)
_ESP=_EBX;
#endif
if (RetCode==0)
DllVolAborted=true;
else
@ -268,21 +259,10 @@ bool DllVolNotify(RAROptions *Cmd,wchar *NextName)
}
if (Cmd->ChangeVolProc!=NULL)
{
#if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__)
_EBX=_ESP;
#endif
int RetCode=Cmd->ChangeVolProc(NextNameA,RAR_VOL_NOTIFY);
#if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__)
_ESP=_EBX;
#endif
if (RetCode==0)
return false;
}
return true;
}
#if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
// Restore the run time stack check for unrar.dll.
#pragma runtime_checks( "s", restore )
#endif
#endif