mirror of
https://github.com/Cisco-Talos/clamav.git
synced 2025-10-19 10:23:17 +00:00
Update to UnRAR v6.1.7
This commit is contained in:
parent
bb5cf49a5f
commit
83ba241087
49 changed files with 716 additions and 440 deletions
|
@ -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/
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -329,7 +329,7 @@ int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestNa
|
|||
{
|
||||
Data->Cmd.DllError=0;
|
||||
if (Data->OpenMode==RAR_OM_LIST || Data->OpenMode==RAR_OM_LIST_INCSPLIT ||
|
||||
Operation==RAR_SKIP) // && !Data->Arc.Solid)
|
||||
Operation==RAR_SKIP && !Data->Arc.Solid)
|
||||
{
|
||||
if (Data->Arc.Volume && Data->Arc.GetHeaderType()==HEAD_FILE &&
|
||||
Data->Arc.FileHead.SplitAfter)
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
#include <commctrl.h>
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 6, 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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 (*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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#define INCLUDEGLOBAL
|
||||
|
||||
#if defined(__BORLANDC__) || defined(_MSC_VER)
|
||||
#ifdef _MSC_VER
|
||||
#pragma hdrstop
|
||||
#endif
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -10,4 +10,7 @@ enum WINNT_VERSION {
|
|||
DWORD WinNT();
|
||||
|
||||
|
||||
// Replace it with actual check when available.
|
||||
bool IsWindows11OrGreater();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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);
|
||||
else
|
||||
if (hd.UnixGroupNumeric)
|
||||
mprintf(L"#%d:",hd.UnixGroupID);
|
||||
mprintf(L"#%d",hd.UnixGroupID);
|
||||
}
|
||||
|
||||
mprintf(L"\n");
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
// 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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
// 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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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%%");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue