Updated UnRAR 5.6.5 to 5.7.5. Library is still not-quite-vanilla, as we still have a hack in dll.cpp:332 allowing skipping of files in solid archives. For ClamAV, it only skips if encrypted, allowing it to continue scanning metadata for each encrypted file. This results in improved malware detection.

pull/111/head
Micah Snyder 6 years ago
parent 3690b81196
commit 113fe99555
  1. 21
      libclamunrar/arccmt.cpp
  2. 5
      libclamunrar/archive.hpp
  3. 65
      libclamunrar/arcread.cpp
  4. 335
      libclamunrar/cmddata.cpp
  5. 11
      libclamunrar/cmddata.hpp
  6. 305
      libclamunrar/cmdfilter.cpp
  7. 118
      libclamunrar/cmdmix.cpp
  8. 8
      libclamunrar/crypt3.cpp
  9. 57
      libclamunrar/dll.cpp
  10. 1
      libclamunrar/dll.def
  11. 10
      libclamunrar/dll.hpp
  12. 10
      libclamunrar/dll.rc
  13. 13
      libclamunrar/dll_nocrypt.def
  14. 2
      libclamunrar/errhnd.hpp
  15. 45
      libclamunrar/extract.cpp
  16. 2
      libclamunrar/file.cpp
  17. 2
      libclamunrar/file.hpp
  18. 2
      libclamunrar/filefn.cpp
  19. 10
      libclamunrar/find.cpp
  20. 13
      libclamunrar/headers.hpp
  21. 16
      libclamunrar/list.cpp
  22. 14
      libclamunrar/loclang.hpp
  23. 10
      libclamunrar/match.cpp
  24. 4
      libclamunrar/match.hpp
  25. 27
      libclamunrar/options.hpp
  26. 5
      libclamunrar/os.hpp
  27. 102
      libclamunrar/pathfn.cpp
  28. 2
      libclamunrar/pathfn.hpp
  29. 10
      libclamunrar/qopen.cpp
  30. 20
      libclamunrar/qopen.hpp
  31. 7
      libclamunrar/rar.cpp
  32. 1
      libclamunrar/rdwrfn.cpp
  33. 12
      libclamunrar/recvol3.cpp
  34. 8
      libclamunrar/recvol5.cpp
  35. 5
      libclamunrar/rijndael.cpp
  36. 20
      libclamunrar/rs16.cpp
  37. 11
      libclamunrar/scantree.cpp
  38. 2
      libclamunrar/scantree.hpp
  39. 52
      libclamunrar/strfn.cpp
  40. 8
      libclamunrar/strfn.hpp
  41. 2
      libclamunrar/suballoc.hpp
  42. 22
      libclamunrar/system.cpp
  43. 1
      libclamunrar/system.hpp
  44. 32
      libclamunrar/threadmisc.cpp
  45. 4
      libclamunrar/timefn.cpp
  46. 23
      libclamunrar/ui.hpp
  47. 6
      libclamunrar/uicommon.cpp
  48. 20
      libclamunrar/uiconsole.cpp
  49. 6
      libclamunrar/uisilent.cpp
  50. 9
      libclamunrar/unicode.cpp
  51. 6
      libclamunrar/unpack50.cpp
  52. 2
      libclamunrar/unpack50frag.cpp
  53. 16
      libclamunrar/unpack50mt.cpp
  54. 8
      libclamunrar/version.hpp
  55. 10
      libclamunrar/volume.cpp
  56. 6
      libclamunrar/win32acl.cpp
  57. 16
      libclamunrar/win32stm.cpp
  58. 7
      libclamunrar_iface/unrar_iface.cpp

@ -34,7 +34,7 @@ bool Archive::GetComment(Array<wchar> *CmtData)
#ifndef SFX_MODULE
// Old style (RAR 2.9) comment header embedded into the main
// archive header.
if (BrokenHeader)
if (BrokenHeader || CommHead.HeadSize<SIZEOF_COMMHEAD)
{
uiMsg(UIERROR_CMTBROKEN,FileName);
return false;
@ -57,6 +57,8 @@ bool Archive::GetComment(Array<wchar> *CmtData)
#else
UnpCmtLength=GetByte();
UnpCmtLength+=(GetByte()<<8);
if (CmtLength<2)
return false;
CmtLength-=2;
DataIO.SetCmt13Encryption();
CommHead.UnpVer=15;
@ -85,15 +87,18 @@ bool Archive::GetComment(Array<wchar> *CmtData)
byte *UnpData;
size_t UnpDataSize;
DataIO.GetUnpackedData(&UnpData,&UnpDataSize);
if (UnpDataSize>0)
{
#ifdef _WIN_ALL
// If we ever decide to extend it to Android, we'll need to alloc
// 4x memory for OEM to UTF-8 output here.
OemToCharBuffA((char *)UnpData,(char *)UnpData,(DWORD)UnpDataSize);
// If we ever decide to extend it to Android, we'll need to alloc
// 4x memory for OEM to UTF-8 output here.
OemToCharBuffA((char *)UnpData,(char *)UnpData,(DWORD)UnpDataSize);
#endif
CmtData->Alloc(UnpDataSize+1);
memset(CmtData->Addr(0),0,CmtData->Size()*sizeof(wchar));
CharToWide((char *)UnpData,CmtData->Addr(0),CmtData->Size());
CmtData->Alloc(wcslen(CmtData->Addr(0)));
CmtData->Alloc(UnpDataSize+1);
memset(CmtData->Addr(0),0,CmtData->Size()*sizeof(wchar));
CharToWide((char *)UnpData,CmtData->Addr(0),CmtData->Size());
CmtData->Alloc(wcslen(CmtData->Addr(0)));
}
}
}
else

@ -37,8 +37,7 @@ class Archive:public File
void RequestArcPassword();
void UnexpEndArcMsg();
void BrokenHeaderMsg();
void UnkEncVerMsg(const wchar *Name);
void UnkEncVerMsg();
void UnkEncVerMsg(const wchar *Name,const wchar *Info);
bool ReadCommentData(Array<wchar> *CmtData);
#if !defined(RAR_NOCRYPT)
@ -85,7 +84,7 @@ class Archive:public File
void AddSubData(byte *SrcData,uint64 DataSize,File *SrcFile,
const wchar *Name,uint Flags);
bool ReadSubData(Array<byte> *UnpData,File *DestFile);
HEADER_TYPE GetHeaderType() {return CurHeaderType;};
HEADER_TYPE GetHeaderType() {return CurHeaderType;}
RAROptions* GetRAROptions() {return Cmd;}
void SetSilentOpen(bool Mode) {SilentOpen=Mode;}
#if 0

@ -10,7 +10,10 @@ size_t Archive::ReadHeader()
CurBlockPos=Tell();
size_t ReadSize;
// Other developers asked us to initialize it to suppress "may be used
// uninitialized" warning in code below in some compilers.
size_t ReadSize=0;
switch(Format)
{
#ifndef SFX_MODULE
@ -113,9 +116,9 @@ void Archive::BrokenHeaderMsg()
}
void Archive::UnkEncVerMsg(const wchar *Name)
void Archive::UnkEncVerMsg(const wchar *Name,const wchar *Info)
{
uiMsg(UIERROR_UNKNOWNENCMETHOD,FileName,Name);
uiMsg(UIERROR_UNKNOWNENCMETHOD,FileName,Name,Info);
ErrHandler.SetErrorCode(RARX_WARNING);
}
@ -201,7 +204,7 @@ size_t Archive::ReadHeader15()
if (ShortBlock.HeaderType==HEAD_MAIN && (ShortBlock.Flags & MHD_COMMENT)!=0)
{
// Old style (up to RAR 2.9) main archive comment embedded into
// the main archive header found. While we can read the entire
// the main archive header found. While we can read the entire
// ShortBlock.HeadSize here and remove this part of "if", it would be
// waste of memory, because we'll read and process this comment data
// in other function anyway and we do not need them here now.
@ -227,7 +230,7 @@ size_t Archive::ReadHeader15()
Encrypted=(MainHead.Flags & MHD_PASSWORD)!=0;
Signed=MainHead.PosAV!=0 || MainHead.HighPosAV!=0;
MainHead.CommentInHeader=(MainHead.Flags & MHD_COMMENT)!=0;
// Only for encrypted 3.0+ archives. 2.x archives did not have this
// flag, so for non-encrypted archives, we'll set it later based on
// file attributes.
@ -254,7 +257,7 @@ size_t Archive::ReadHeader15()
hd->WinSize=hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5);
hd->CommentInHeader=(hd->Flags & LHD_COMMENT)!=0;
hd->Version=(hd->Flags & LHD_VERSION)!=0;
hd->DataSize=Raw.Get4();
uint LowUnpSize=Raw.Get4();
hd->HostOS=Raw.Get1();
@ -279,7 +282,7 @@ size_t Archive::ReadHeader15()
{
case 13: hd->CryptMethod=CRYPT_RAR13; break;
case 15: hd->CryptMethod=CRYPT_RAR15; break;
case 20:
case 20:
case 26: hd->CryptMethod=CRYPT_RAR20; break;
default: hd->CryptMethod=CRYPT_RAR30; break;
}
@ -301,7 +304,7 @@ size_t Archive::ReadHeader15()
}
hd->Inherited=!FileBlock && (hd->SubFlags & SUBHEAD_FLAGS_INHERITED)!=0;
hd->LargeFile=(hd->Flags & LHD_LARGE)!=0;
uint HighPackSize,HighUnpSize;
@ -311,7 +314,7 @@ size_t Archive::ReadHeader15()
HighUnpSize=Raw.Get4();
hd->UnknownUnpSize=(LowUnpSize==0xffffffff && HighUnpSize==0xffffffff);
}
else
else
{
HighPackSize=HighUnpSize=0;
// UnpSize equal to 0xffffffff without LHD_LARGE flag indicates
@ -506,7 +509,7 @@ size_t Archive::ReadHeader15()
NextBlockPos+=Raw.Get4();
break;
}
ushort HeaderCRC=Raw.GetCRC15(false);
// Old AV header does not have header CRC properly set.
@ -566,7 +569,7 @@ size_t Archive::ReadHeader50()
// We repeat the password request only for manually entered passwords
// and not for -p<pwd>. Wrong password can be intentionally provided
// in -p<pwd> to not stop batch processing for encrypted archives.
bool GlobalPassword=Cmd->Password.IsSet();
bool GlobalPassword=Cmd->Password.IsSet() || uiIsGlobalPasswordSet();
while (true) // Repeat the password prompt for wrong passwords.
{
@ -641,7 +644,7 @@ size_t Archive::ReadHeader50()
BrokenHeaderMsg();
return 0;
}
Raw.Read(SizeToRead);
if (Raw.Size()<HeaderSize)
@ -674,7 +677,7 @@ size_t Archive::ReadHeader50()
return 0;
}
}
uint64 ExtraSize=0;
if ((ShortBlock.Flags & HFL_EXTRA)!=0)
{
@ -702,7 +705,9 @@ size_t Archive::ReadHeader50()
uint CryptVersion=(uint)Raw.GetV();
if (CryptVersion>CRYPT_VERSION)
{
UnkEncVerMsg(FileName);
wchar Info[20];
swprintf(Info,ASIZE(Info),L"h%u",CryptVersion);
UnkEncVerMsg(FileName,Info);
return 0;
}
uint EncFlags=(uint)Raw.GetV();
@ -710,7 +715,9 @@ size_t Archive::ReadHeader50()
CryptHead.Lg2Count=Raw.Get1();
if (CryptHead.Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
{
UnkEncVerMsg(FileName);
wchar Info[20];
swprintf(Info,ASIZE(Info),L"hc%u",CryptHead.Lg2Count);
UnkEncVerMsg(FileName,Info);
return 0;
}
Raw.GetB(CryptHead.Salt,SIZE_SALT50);
@ -763,7 +770,7 @@ size_t Archive::ReadHeader50()
// to not break normal archive processing by calling function.
int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos;
HEADER_TYPE SaveCurHeaderType=CurHeaderType;
QOpen.Init(this,false);
QOpen.Load(MainHead.QOpenOffset);
@ -788,7 +795,7 @@ size_t Archive::ReadHeader50()
hd->PackSize=DataSize;
hd->FileFlags=(uint)Raw.GetV();
hd->UnpSize=Raw.GetV();
hd->UnknownUnpSize=(hd->FileFlags & FHFL_UNPUNKNOWN)!=0;
if (hd->UnknownUnpSize)
hd->UnpSize=INT64NDF;
@ -815,6 +822,8 @@ size_t Archive::ReadHeader50()
// but it was already used in RAR 1.5 and Unpack needs to distinguish
// them.
hd->UnpVer=(CompInfo & 0x3f) + 50;
if (hd->UnpVer!=50) // Only 5.0 compression is known now.
hd->UnpVer=VER_UNKNOWN;
hd->HostOS=(byte)Raw.GetV();
size_t NameSize=(size_t)Raw.GetV();
@ -873,7 +882,7 @@ size_t Archive::ReadHeader50()
RecoverySize=Header.RecSectionSize*Header.RecCount;
}
#endif
if (BadCRC) // Add the file name to broken header message displayed above.
uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName);
}
@ -989,8 +998,12 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
{
FileHeader *hd=(FileHeader *)bb;
uint EncVersion=(uint)Raw->GetV();
if (EncVersion > CRYPT_VERSION)
UnkEncVerMsg(hd->FileName);
if (EncVersion>CRYPT_VERSION)
{
wchar Info[20];
swprintf(Info,ASIZE(Info),L"x%u",EncVersion);
UnkEncVerMsg(hd->FileName,Info);
}
else
{
uint Flags=(uint)Raw->GetV();
@ -998,7 +1011,11 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
hd->UseHashKey=(Flags & FHEXTRA_CRYPT_HASHMAC)!=0;
hd->Lg2Count=Raw->Get1();
if (hd->Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
UnkEncVerMsg(hd->FileName);
{
wchar Info[20];
swprintf(Info,ASIZE(Info),L"xc%u",hd->Lg2Count);
UnkEncVerMsg(hd->FileName,Info);
}
Raw->GetB(hd->Salt,SIZE_SALT50);
Raw->GetB(hd->InitV,SIZE_INITV);
if (hd->UsePswCheck)
@ -1290,7 +1307,7 @@ void Archive::ConvertAttributes()
if (mask == (mode_t) -1)
{
// umask call returns the current umask value. Argument (022) is not
// umask call returns the current umask value. Argument (022) is not
// really important here.
mask = umask(022);
@ -1367,8 +1384,8 @@ void Archive::ConvertFileHeader(FileHeader *hd)
// ':' in file names is allowed in Unix, but not in Windows.
// Even worse, file data will be written to NTFS stream on NTFS,
// so automatic name correction on file create error in extraction
// routine does not work. In Windows and DOS versions we better
// so automatic name correction on file create error in extraction
// routine does not work. In Windows and DOS versions we better
// replace ':' now.
if (*s==':')
*s='_';

@ -1,5 +1,8 @@
#include "rar.hpp"
#include "cmdfilter.cpp"
#include "cmdmix.cpp"
CommandData::CommandData()
{
Init();
@ -120,6 +123,7 @@ void CommandData::ParseArg(wchar *Arg)
wchar CmdChar=toupperw(*Command);
bool Add=wcschr(L"AFUM",CmdChar)!=NULL;
bool Extract=CmdChar=='X' || CmdChar=='E';
bool Repair=CmdChar=='R' && Command[1]==0;
if (EndSeparator && !Add)
wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath));
else
@ -130,15 +134,15 @@ void CommandData::ParseArg(wchar *Arg)
FindData FileData;
bool Found=FindFile::FastFind(Arg,&FileData);
if ((!Found || ListMode==RCLM_ACCEPT_LISTS) &&
ListMode!=RCLM_REJECT_LISTS && *Arg=='@' && !IsWildcard(Arg))
ListMode!=RCLM_REJECT_LISTS && *Arg=='@' && !IsWildcard(Arg+1))
{
FileLists=true;
ReadTextFile(Arg+1,&FileArgs,false,true,FilelistCharset,true,true,true);
}
else
if (Found && FileData.IsDir && Extract && *ExtrPath==0)
else // We use 'destpath\' when extracting and reparing.
if (Found && FileData.IsDir && (Extract || Repair) && *ExtrPath==0)
{
wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath));
AddEndSlash(ExtrPath,ASIZE(ExtrPath));
@ -280,7 +284,11 @@ void CommandData::ProcessSwitch(const wchar *Switch)
ClearArc=true;
break;
case 'D':
AppendArcNameToPath=true;
if (Switch[2]==0)
AppendArcNameToPath=APPENDARCNAME_DESTPATH;
else
if (Switch[2]=='1')
AppendArcNameToPath=APPENDARCNAME_OWNDIR;
break;
#ifndef SFX_MODULE
case 'G':
@ -302,7 +310,7 @@ void CommandData::ProcessSwitch(const wchar *Switch)
AddArcOnly=true;
break;
case 'P':
wcscpy(ArcPath,Switch+2);
wcsncpyz(ArcPath,Switch+2,ASIZE(ArcPath));
break;
case 'S':
SyncFiles=true;
@ -407,9 +415,9 @@ void CommandData::ProcessSwitch(const wchar *Switch)
wcsncpyz(LogName,Switch[4]!=0 ? Switch+4:DefLogName,ASIZE(LogName));
break;
}
if (wcsicomp(Switch+1,L"SND")==0)
if (wcsnicomp(Switch+1,L"SND",3)==0)
{
Sound=true;
Sound=Switch[4]=='-' ? SOUND_NOTIFY_OFF : SOUND_NOTIFY_ON;
break;
}
if (wcsicomp(Switch+1,L"ERR")==0)
@ -805,16 +813,16 @@ void CommandData::ProcessSwitch(const wchar *Switch)
ArcTime=ARCTIME_LATEST;
break;
case 'O':
FileTimeBefore.SetAgeText(Switch+2);
SetTimeFilters(Switch+2,true,true);
break;
case 'N':
FileTimeAfter.SetAgeText(Switch+2);
SetTimeFilters(Switch+2,false,true);
break;
case 'B':
FileTimeBefore.SetIsoText(Switch+2);
SetTimeFilters(Switch+2,true,false);
break;
case 'A':
FileTimeAfter.SetIsoText(Switch+2);
SetTimeFilters(Switch+2,false,false);
break;
case 'S':
{
@ -897,7 +905,7 @@ void CommandData::ProcessSwitch(const wchar *Switch)
if (Switch[1]==0)
{
// If comment file is not specified, we read data from stdin.
wcscpy(CommentFile,L"stdin");
wcsncpyz(CommentFile,L"stdin",ASIZE(CommentFile));
}
else
wcsncpyz(CommentFile,Switch+1,ASIZE(CommentFile));
@ -922,309 +930,6 @@ void CommandData::BadSwitch(const wchar *Switch)
#endif
void CommandData::OutTitle()
{
if (BareOutput || DisableCopyright)
return;
#if defined(__GNUC__) && defined(SFX_MODULE)
mprintf(St(MCopyrightS));
#else
#ifndef SILENT
static bool TitleShown=false;
if (TitleShown)
return;
TitleShown=true;
wchar Version[80];
if (RARVER_BETA!=0)
swprintf(Version,ASIZE(Version),L"%d.%02d %ls %d",RARVER_MAJOR,RARVER_MINOR,St(MBeta),RARVER_BETA);
else
swprintf(Version,ASIZE(Version),L"%d.%02d",RARVER_MAJOR,RARVER_MINOR);
#if defined(_WIN_32) || defined(_WIN_64)
wcsncatz(Version,L" ",ASIZE(Version));
#endif
#ifdef _WIN_32
wcsncatz(Version,St(Mx86),ASIZE(Version));
#endif
#ifdef _WIN_64
wcsncatz(Version,St(Mx64),ASIZE(Version));
#endif
if (PrintVersion)
{
mprintf(L"%s",Version);
exit(0);
}
mprintf(St(MUCopyright),Version,RARVER_YEAR);
#endif
#endif
}
inline bool CmpMSGID(MSGID i1,MSGID i2)
{
#ifdef MSGID_INT
return i1==i2;
#else
// If MSGID is const char*, we cannot compare pointers only.
// Pointers to different instances of same string can differ,
// so we need to compare complete strings.
return wcscmp(i1,i2)==0;
#endif
}
void CommandData::OutHelp(RAR_EXIT ExitCode)
{
#if !defined(SILENT)
OutTitle();
static MSGID Help[]={
#ifdef SFX_MODULE
// Console SFX switches definition.
MCHelpCmd,MSHelpCmdE,MSHelpCmdT,MSHelpCmdV
#else
// UnRAR switches definition.
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
#endif
};
for (uint I=0;I<ASIZE(Help);I++)
{
#ifndef SFX_MODULE
if (CmpMSGID(Help[I],MCHelpSwV))
continue;
#ifndef _WIN_ALL
static MSGID Win32Only[]={
MCHelpSwIEML,MCHelpSwVD,MCHelpSwAO,MCHelpSwOS,MCHelpSwIOFF,
MCHelpSwEP2,MCHelpSwOC,MCHelpSwONI,MCHelpSwDR,MCHelpSwRI
};
bool Found=false;
for (int J=0;J<sizeof(Win32Only)/sizeof(Win32Only[0]);J++)
if (CmpMSGID(Help[I],Win32Only[J]))
{
Found=true;
break;
}
if (Found)
continue;
#endif
#if !defined(_UNIX) && !defined(_WIN_ALL)
if (CmpMSGID(Help[I],MCHelpSwOW))
continue;
#endif
#if !defined(_WIN_ALL) && !defined(_EMX)
if (CmpMSGID(Help[I],MCHelpSwAC))
continue;
#endif
#ifndef SAVE_LINKS
if (CmpMSGID(Help[I],MCHelpSwOL))
continue;
#endif
#ifndef RAR_SMP
if (CmpMSGID(Help[I],MCHelpSwMT))
continue;
#endif
#endif
mprintf(St(Help[I]));
}
mprintf(L"\n");
ErrHandler.Exit(ExitCode);
#endif
}
// Return 'true' if we need to exclude the file from processing as result
// of -x switch. If CheckInclList is true, we also check the file against
// the include list created with -n switch.
bool CommandData::ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList)
{
if (CheckArgs(&ExclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
return true;
if (!CheckInclList || InclArgs.ItemsCount()==0)
return false;
if (CheckArgs(&InclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
return false;
return true;
}
bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode)
{
wchar *Name=ConvertPath(CheckName,NULL);
wchar FullName[NM];
wchar CurMask[NM];
*FullName=0;
Args->Rewind();
while (Args->GetString(CurMask,ASIZE(CurMask)))
{
wchar *LastMaskChar=PointToLastChar(CurMask);
bool DirMask=IsPathDiv(*LastMaskChar); // Mask for directories only.
if (Dir)
{
// CheckName is a directory.
if (DirMask)
{
// We process the directory and have the directory exclusion mask.
// So let's convert "mask\" to "mask" and process it normally.
*LastMaskChar=0;
}
else
{
// REMOVED, we want -npath\* to match empty folders too.
// If mask has wildcards in name part and does not have the trailing
// '\' character, we cannot use it for directories.
// if (IsWildcard(PointToName(CurMask)))
// continue;
}
}
else
{
// If we process a file inside of directory excluded by "dirmask\".
// we want to exclude such file too. So we convert "dirmask\" to
// "dirmask\*". It is important for operations other than archiving
// with -x. When archiving with -x, directory matched by "dirmask\"
// is excluded from further scanning.
if (DirMask)
wcsncatz(CurMask,L"*",ASIZE(CurMask));
}
#ifndef SFX_MODULE
if (CheckFullPath && IsFullPath(CurMask))
{
// We do not need to do the special "*\" processing here, because
// unlike the "else" part of this "if", now we convert names to full
// format, so they all include the path, which is matched by "*\"
// correctly. Moreover, removing "*\" from mask would break
// the comparison, because now all names have the path.
if (*FullName==0)
ConvertNameToFull(CheckName,FullName,ASIZE(FullName));
if (CmpName(CurMask,FullName,MatchMode))
return true;
}
else
#endif
{
wchar NewName[NM+2],*CurName=Name;
// Important to convert before "*\" check below, so masks like
// d:*\something are processed properly.
wchar *CmpMask=ConvertPath(CurMask,NULL);
if (CmpMask[0]=='*' && IsPathDiv(CmpMask[1]))
{
// We want "*\name" to match 'name' not only in subdirectories,
// but also in the current directory. We convert the name
// from 'name' to '.\name' to be matched by "*\" part even if it is
// in current directory.
NewName[0]='.';
NewName[1]=CPATHDIVIDER;
wcsncpyz(NewName+2,Name,ASIZE(NewName)-2);
CurName=NewName;
}
if (CmpName(CmpMask,CurName,MatchMode))
return true;
}
}
return false;
}
#ifndef SFX_MODULE
// Now this function performs only one task and only in Windows version:
// it skips symlinks to directories if -e1024 switch is specified.
// Symlinks are skipped in ScanTree class, so their entire contents
// is skipped too. Without this function we would check the attribute
// only directly before archiving, so we would skip the symlink record,
// but not the contents of symlinked directory.
bool CommandData::ExclDirByAttr(uint FileAttr)
{
#ifdef _WIN_ALL
if ((FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0 &&
(ExclFileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0)
return true;
#endif
return false;
}
#endif
#ifndef SFX_MODULE
// Return 'true' if we need to exclude the file from processing.
bool CommandData::TimeCheck(RarTime &ft)
{
if (FileTimeBefore.IsSet() && ft>=FileTimeBefore)
return true;
if (FileTimeAfter.IsSet() && ft<=FileTimeAfter)
return true;
return false;
}
#endif
#ifndef SFX_MODULE
// Return 'true' if we need to exclude the file from processing.
bool CommandData::SizeCheck(int64 Size)
{
if (FileSizeLess!=INT64NDF && Size>=FileSizeLess)
return(true);
if (FileSizeMore!=INT64NDF && Size<=FileSizeMore)
return(true);
return(false);
}
#endif
int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType,
wchar *MatchedArg,uint MatchedArgSize)
{
if (MatchedArg!=NULL && MatchedArgSize>0)
*MatchedArg=0;
// if (wcslen(FileHead.FileName)>=NM)
// return 0;
bool Dir=FileHead.Dir;
if (ExclCheck(FileHead.FileName,Dir,false,true))
return 0;
#ifndef SFX_MODULE
if (TimeCheck(FileHead.mtime))
return 0;
if ((FileHead.FileAttr & ExclFileAttr)!=0 || InclAttrSet && (FileHead.FileAttr & InclFileAttr)==0)
return 0;
if (!Dir && SizeCheck(FileHead.UnpSize))
return 0;
#endif
wchar *ArgName;
FileArgs.Rewind();
for (int StringCount=1;(ArgName=FileArgs.GetString())!=NULL;StringCount++)
if (CmpName(ArgName,FileHead.FileName,MatchType))
{
if (ExactMatch!=NULL)
*ExactMatch=wcsicompc(ArgName,FileHead.FileName)==0;
if (MatchedArg!=NULL)
wcsncpyz(MatchedArg,ArgName,MatchedArgSize);
return StringCount;
}
return 0;
}
void CommandData::ProcessCommand()
{
#ifndef SFX_MODULE

@ -6,6 +6,8 @@
enum RAR_CMD_LIST_MODE {RCLM_AUTO,RCLM_REJECT_LISTS,RCLM_ACCEPT_LISTS};
enum IS_PROCESS_FILE_FLAGS {IPFF_EXCLUDE_PARENT=1};
class CommandData:public RAROptions
{
private:
@ -13,6 +15,9 @@ class CommandData:public RAROptions
void ProcessSwitch(const wchar *Switch);
void BadSwitch(const wchar *Switch);
uint GetExclAttr(const wchar *Str);
#if !defined(SFX_MODULE)
void SetTimeFilters(const wchar *Mod,bool Before,bool Age);
#endif
bool FileLists;
bool NoMoreSwitches;
@ -34,11 +39,11 @@ class CommandData:public RAROptions
bool ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList);
static bool CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode);
bool ExclDirByAttr(uint FileAttr);
bool TimeCheck(RarTime &ft);
bool TimeCheck(RarTime &ftm,RarTime &ftc,RarTime &fta);
bool SizeCheck(int64 Size);
bool AnyFiltersActive();
int IsProcessFile(FileHeader &FileHead,bool *ExactMatch=NULL,int MatchType=MATCH_WILDSUBPATH,
wchar *MatchedArg=NULL,uint MatchedArgSize=0);
int IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType,
bool Flags,wchar *MatchedArg,uint MatchedArgSize);
void ProcessCommand();
void AddArcName(const wchar *Name);
bool GetArcName(wchar *Name,int MaxSize);

@ -0,0 +1,305 @@
// Return 'true' if we need to exclude the file from processing as result
// of -x switch. If CheckInclList is true, we also check the file against
// the include list created with -n switch.
bool CommandData::ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList)
{
if (CheckArgs(&ExclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
return true;
if (!CheckInclList || InclArgs.ItemsCount()==0)
return false;
if (CheckArgs(&InclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
return false;
return true;
}
bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode)
{
wchar *Name=ConvertPath(CheckName,NULL,0);
wchar FullName[NM];
wchar CurMask[NM];
*FullName=0;
Args->Rewind();
while (Args->GetString(CurMask,ASIZE(CurMask)))
{
wchar *LastMaskChar=PointToLastChar(CurMask);
bool DirMask=IsPathDiv(*LastMaskChar); // Mask for directories only.
if (Dir)
{
// CheckName is a directory.
if (DirMask)
{
// We process the directory and have the directory exclusion mask.
// So let's convert "mask\" to "mask" and process it normally.
*LastMaskChar=0;
}
else
{
// REMOVED, we want -npath\* to match empty folders too.
// If mask has wildcards in name part and does not have the trailing
// '\' character, we cannot use it for directories.
// if (IsWildcard(PointToName(CurMask)))
// continue;
}
}
else
{
// If we process a file inside of directory excluded by "dirmask\".
// we want to exclude such file too. So we convert "dirmask\" to
// "dirmask\*". It is important for operations other than archiving
// with -x. When archiving with -x, directory matched by "dirmask\"
// is excluded from further scanning.
if (DirMask)
wcsncatz(CurMask,L"*",ASIZE(CurMask));
}
#ifndef SFX_MODULE
if (CheckFullPath && IsFullPath(CurMask))
{
// We do not need to do the special "*\" processing here, because
// unlike the "else" part of this "if", now we convert names to full
// format, so they all include the path, which is matched by "*\"
// correctly. Moreover, removing "*\" from mask would break
// the comparison, because now all names have the path.
if (*FullName==0)
ConvertNameToFull(CheckName,FullName,ASIZE(FullName));
if (CmpName(CurMask,FullName,MatchMode))
return true;
}
else
#endif
{
wchar NewName[NM+2],*CurName=Name;
// Important to convert before "*\" check below, so masks like
// d:*\something are processed properly.
wchar *CmpMask=ConvertPath(CurMask,NULL,0);
if (CmpMask[0]=='*' && IsPathDiv(CmpMask[1]))
{
// We want "*\name" to match 'name' not only in subdirectories,
// but also in the current directory. We convert the name
// from 'name' to '.\name' to be matched by "*\" part even if it is
// in current directory.
NewName[0]='.';
NewName[1]=CPATHDIVIDER;
wcsncpyz(NewName+2,Name,ASIZE(NewName)-2);
CurName=NewName;
}
if (CmpName(CmpMask,CurName,MatchMode))
return true;
}
}
return false;
}
#ifndef SFX_MODULE
// Now this function performs only one task and only in Windows version:
// it skips symlinks to directories if -e1024 switch is specified.
// Symlinks are skipped in ScanTree class, so their entire contents
// is skipped too. Without this function we would check the attribute
// only directly before archiving, so we would skip the symlink record,
// but not the contents of symlinked directory.
bool CommandData::ExclDirByAttr(uint FileAttr)
{
#ifdef _WIN_ALL
if ((FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0 &&
(ExclFileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0)
return true;
#endif
return false;
}
#endif
#if !defined(SFX_MODULE)
void CommandData::SetTimeFilters(const wchar *Mod,bool Before,bool Age)
{
bool ModeOR=false,TimeMods=false;
const wchar *S=Mod;
// Check if any 'mca' modifiers are present, set OR mode if 'o' is present,
// skip modifiers and set S to beginning of time string. Be sure to check
// *S!=0, because termination 0 is a part of string for wcschr.
for (;*S!=0 && wcschr(L"MCAOmcao",*S)!=NULL;S++)
if (*S=='o' || *S=='O')
ModeOR=true;
else
TimeMods=true;
if (!TimeMods) // Assume 'm' if no modifiers are specified.
Mod=L"m";
// Set the specified time for every modifier. Be sure to check *Mod!=0,
// because termination 0 is a part of string for wcschr. This check is
// important when we set Mod to "m" above.
for (;*Mod!=0 && wcschr(L"MCAOmcao",*Mod)!=NULL;Mod++)
switch(toupperw(*Mod))
{
case 'M':
if (Before)
{
Age ? FileMtimeBefore.SetAgeText(S):FileMtimeBefore.SetIsoText(S);
FileMtimeBeforeOR=ModeOR;
}
else
{
Age ? FileMtimeAfter.SetAgeText(S):FileMtimeAfter.SetIsoText(S);
FileMtimeAfterOR=ModeOR;
}
break;
case 'C':
if (Before)
{
Age ? FileCtimeBefore.SetAgeText(S):FileCtimeBefore.SetIsoText(S);
FileCtimeBeforeOR=ModeOR;
}
else
{
Age ? FileCtimeAfter.SetAgeText(S):FileCtimeAfter.SetIsoText(S);
FileCtimeAfterOR=ModeOR;
}
break;
case 'A':
if (Before)
{
Age ? FileAtimeBefore.SetAgeText(S):FileAtimeBefore.SetIsoText(S);
FileAtimeBeforeOR=ModeOR;
}
else
{
Age ? FileAtimeAfter.SetAgeText(S):FileAtimeAfter.SetIsoText(S);
FileAtimeAfterOR=ModeOR;
}
break;
}
}
#endif
#ifndef SFX_MODULE
// Return 'true' if we need to exclude the file from processing.
bool CommandData::TimeCheck(RarTime &ftm,RarTime &ftc,RarTime &fta)
{
bool FilterOR=false;
if (FileMtimeBefore.IsSet()) // Filter present.
if (ftm>=FileMtimeBefore) // Condition not matched.
if (FileMtimeBeforeOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileMtimeBeforeOR)
return false; // Include file in OR mode.
if (FileMtimeAfter.IsSet()) // Filter present.
if (ftm<FileMtimeAfter) // Condition not matched.
if (FileMtimeAfterOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileMtimeAfterOR)
return false; // Include file in OR mode.
if (FileCtimeBefore.IsSet()) // Filter present.
if (ftc>=FileCtimeBefore) // Condition not matched.
if (FileCtimeBeforeOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileCtimeBeforeOR)
return false; // Include file in OR mode.
if (FileCtimeAfter.IsSet()) // Filter present.
if (ftc<FileCtimeAfter) // Condition not matched.
if (FileCtimeAfterOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileCtimeAfterOR)
return false; // Include file in OR mode.
if (FileAtimeBefore.IsSet()) // Filter present.
if (fta>=FileAtimeBefore) // Condition not matched.
if (FileAtimeBeforeOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileAtimeBeforeOR)
return false; // Include file in OR mode.
if (FileAtimeAfter.IsSet()) // Filter present.
if (fta<FileAtimeAfter) // Condition not matched.
if (FileAtimeAfterOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileAtimeAfterOR)
return false; // Include file in OR mode.
return FilterOR; // Exclude if all OR filters are not matched.
}
#endif
#ifndef SFX_MODULE
// Return 'true' if we need to exclude the file from processing.
bool CommandData::SizeCheck(int64 Size)
{
if (FileSizeLess!=INT64NDF && Size>=FileSizeLess)
return true;
if (FileSizeMore!=INT64NDF && Size<=FileSizeMore)
return true;
return false;
}
#endif
// Return 0 if file must not be processed or a number of matched parameter otherwise.
int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType,
bool Flags,wchar *MatchedArg,uint MatchedArgSize)
{
if (MatchedArg!=NULL && MatchedArgSize>0)
*MatchedArg=0;
bool Dir=FileHead.Dir;
if (ExclCheck(FileHead.FileName,Dir,false,true))
return 0;
#ifndef SFX_MODULE
if (TimeCheck(FileHead.mtime,FileHead.ctime,FileHead.atime))
return 0;
if ((FileHead.FileAttr & ExclFileAttr)!=0 || InclAttrSet && (FileHead.FileAttr & InclFileAttr)==0)
return 0;
if (!Dir && SizeCheck(FileHead.UnpSize))
return 0;
#endif
wchar *ArgName;
FileArgs.Rewind();
for (int StringCount=1;(ArgName=FileArgs.GetString())!=NULL;StringCount++)
if (CmpName(ArgName,FileHead.FileName,MatchType))
{
if (ExactMatch!=NULL)
*ExactMatch=wcsicompc(ArgName,FileHead.FileName)==0;
if (MatchedArg!=NULL)
wcsncpyz(MatchedArg,ArgName,MatchedArgSize);
return StringCount;
}
return 0;
}

@ -0,0 +1,118 @@
void CommandData::OutTitle()
{
if (BareOutput || DisableCopyright)
return;
#if defined(__GNUC__) && defined(SFX_MODULE)
mprintf(St(MCopyrightS));
#else
#ifndef SILENT
static bool TitleShown=false;
if (TitleShown)
return;
TitleShown=true;
wchar Version[80];
if (RARVER_BETA!=0)
swprintf(Version,ASIZE(Version),L"%d.%02d %ls %d",RARVER_MAJOR,RARVER_MINOR,St(MBeta),RARVER_BETA);
else
swprintf(Version,ASIZE(Version),L"%d.%02d",RARVER_MAJOR,RARVER_MINOR);
#if defined(_WIN_32) || defined(_WIN_64)
wcsncatz(Version,L" ",ASIZE(Version));
#endif
#ifdef _WIN_32
wcsncatz(Version,St(Mx86),ASIZE(Version));
#endif
#ifdef _WIN_64
wcsncatz(Version,St(Mx64),ASIZE(Version));
#endif
if (PrintVersion)
{
mprintf(L"%s",Version);
exit(0);
}
mprintf(St(MUCopyright),Version,RARVER_YEAR);
#endif
#endif
}
inline bool CmpMSGID(MSGID i1,MSGID i2)
{
#ifdef MSGID_INT
return i1==i2;
#else
// If MSGID is const char*, we cannot compare pointers only.
// Pointers to different instances of same string can differ,
// so we need to compare complete strings.
return wcscmp(i1,i2)==0;
#endif
}
void CommandData::OutHelp(RAR_EXIT ExitCode)
{
#if !defined(SILENT)
OutTitle();
static MSGID Help[]={
#ifdef SFX_MODULE
// Console SFX switches definition.
MCHelpCmd,MSHelpCmdE,MSHelpCmdT,MSHelpCmdV
#else
// UnRAR switches definition.
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
#endif
};
for (uint I=0;I<ASIZE(Help);I++)
{
#ifndef SFX_MODULE
if (CmpMSGID(Help[I],MCHelpSwV))
continue;
#ifndef _WIN_ALL
static MSGID Win32Only[]={
MCHelpSwIEML,MCHelpSwVD,MCHelpSwAO,MCHelpSwOS,MCHelpSwIOFF,
MCHelpSwEP2,MCHelpSwOC,MCHelpSwONI,MCHelpSwDR,MCHelpSwRI
};
bool Found=false;
for (uint J=0;J<ASIZE(Win32Only);J++)
if (CmpMSGID(Help[I],Win32Only[J]))
{
Found=true;
break;
}
if (Found)
continue;
#endif
#if !defined(_UNIX) && !defined(_WIN_ALL)
if (CmpMSGID(Help[I],MCHelpSwOW))
continue;
#endif
#if !defined(_WIN_ALL) && !defined(_EMX)
if (CmpMSGID(Help[I],MCHelpSwAC))
continue;
#endif
#ifndef SAVE_LINKS
if (CmpMSGID(Help[I],MCHelpSwOL))
continue;
#endif
#ifndef RAR_SMP
if (CmpMSGID(Help[I],MCHelpSwMT))
continue;
#endif
#endif
mprintf(St(Help[I]));
}
mprintf(L"\n");
ErrHandler.Exit(ExitCode);
#endif
}

@ -28,8 +28,8 @@ void CryptData::SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,co
sha1_context c;
sha1_init(&c);
const int HashRounds=0x40000;
for (int I=0;I<HashRounds;I++)
const uint HashRounds=0x40000;
for (uint I=0;I<HashRounds;I++)
{
sha1_process_rar29( &c, RawPsw, RawLength );
byte PswNum[3];
@ -47,8 +47,8 @@ void CryptData::SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,co
}
uint32 digest[5];
sha1_done( &c, digest );
for (int I=0;I<4;I++)
for (int J=0;J<4;J++)
for (uint I=0;I<4;I++)
for (uint J=0;J<4;J++)
AESKey[I*4+J]=(byte)(digest[I]>>(J*8));
KDF3Cache[KDF3CachePos].Pwd=*Password;

@ -42,7 +42,7 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
Data->Cmd.DllError=0;
Data->OpenMode=r->OpenMode;
Data->Cmd.FileArgs.AddString(L"*");
Data->Cmd.KeepBroken = true;
Data->Cmd.KeepBroken=(r->OpFlags&ROADOF_KEEPBROKEN)!=0;
char AnsiArcName[NM];
*AnsiArcName=0;
@ -93,9 +93,11 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
return NULL;
}
r->Flags=0;
if (Data->Arc.Volume)
r->Flags|=0x01;
if (Data->Arc.MainComment)
r->Flags|=0x02;
if (Data->Arc.Locked)
r->Flags|=0x04;
if (Data->Arc.Solid)
@ -114,17 +116,29 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
Array<wchar> CmtDataW;
if (r->CmtBufSize!=0 && Data->Arc.GetComment(&CmtDataW))
{
Array<char> CmtData(CmtDataW.Size()*4+1);
memset(&CmtData[0],0,CmtData.Size());
WideToChar(&CmtDataW[0],&CmtData[0],CmtData.Size()-1);
size_t Size=strlen(&CmtData[0])+1;
r->Flags|=2;
r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1;
r->CmtSize=(uint)Min(Size,r->CmtBufSize);
memcpy(r->CmtBuf,&CmtData[0],r->CmtSize-1);
if (Size<=r->CmtBufSize)
r->CmtBuf[r->CmtSize-1]=0;
if (r->CmtBufW!=NULL)
{
CmtDataW.Push(0);
size_t Size=wcslen(&CmtDataW[0])+1;
r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1;
r->CmtSize=(uint)Min(Size,r->CmtBufSize);
memcpy(r->CmtBufW,&CmtDataW[0],(r->CmtSize-1)*sizeof(*r->CmtBufW));
r->CmtBufW[r->CmtSize-1]=0;
}
else
if (r->CmtBuf!=NULL)
{
Array<char> CmtData(CmtDataW.Size()*4+1);
memset(&CmtData[0],0,CmtData.Size());
WideToChar(&CmtDataW[0],&CmtData[0],CmtData.Size()-1);
size_t Size=strlen(&CmtData[0])+1;
r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1;
r->CmtSize=(uint)Min(Size,r->CmtBufSize);
memcpy(r->CmtBuf,&CmtData[0],r->CmtSize-1);
r->CmtBuf[r->CmtSize-1]=0;
}
}
else
r->CmtState=r->CmtSize=0;
@ -216,7 +230,7 @@ int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D)
// open callback for RAR5 archives and if password is invalid.
if (Data->Arc.FailedHeaderDecryption)
return ERAR_BAD_PASSWORD;
return ERAR_END_ARCHIVE;
}
FileHeader *hd=&Data->Arc.FileHead;
@ -254,13 +268,10 @@ int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D)
D->UnpSize=uint(hd->UnpSize & 0xffffffff);
D->UnpSizeHigh=uint(hd->UnpSize>>32);
D->HostOS=hd->HSType==HSYS_WINDOWS ? HOST_WIN32:HOST_UNIX;
if (Data->Arc.Format==RARFMT50)
D->UnpVer=Data->Arc.FileHead.UnpVer==0 ? 50 : 200; // If it is not 0, just set it to something big.
else
D->UnpVer=Data->Arc.FileHead.UnpVer;
D->UnpVer=Data->Arc.FileHead.UnpVer;
D->FileCRC=hd->FileHash.CRC32;
D->FileTime=hd->mtime.GetDos();
uint64 MRaw=hd->mtime.GetWin();
D->MtimeLow=(uint)MRaw;
D->MtimeHigh=(uint)(MRaw>>32);
@ -373,7 +384,7 @@ int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestNa
if (DestNameW!=NULL)
wcsncpyz(Data->Cmd.DllDestName,DestNameW,ASIZE(Data->Cmd.DllDestName));
wcscpy(Data->Cmd.Command,Operation==RAR_EXTRACT ? L"X":L"T");
wcsncpyz(Data->Cmd.Command,Operation==RAR_EXTRACT ? L"X":L"T",ASIZE(Data->Cmd.Command));
Data->Cmd.Test=Operation!=RAR_EXTRACT;
bool Repeat=false;
Data->Extract.ExtractCurrentFile(Data->Arc,Data->HeaderSize,Repeat);
@ -385,7 +396,7 @@ int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestNa
// if archive is still open to avoid calling file operations on
// the invalid file handle. Some of our file operations like Seek()
// process such invalid handle correctly, some not.
while (Data->Arc.IsOpened() && Data->Arc.ReadHeader()!=0 &&
while (Data->Arc.IsOpened() && Data->Arc.ReadHeader()!=0 &&
Data->Arc.GetHeaderType()==HEAD_SERVICE)
{
Data->Extract.ExtractCurrentFile(Data->Arc,Data->HeaderSize,Repeat);
@ -440,16 +451,16 @@ void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataPro
}
#ifndef RAR_NOCRYPT
void PASCAL RARSetPassword(HANDLE hArcData,char *Password)
{
#ifndef RAR_NOCRYPT
DataSet *Data=(DataSet *)hArcData;
wchar PasswordW[MAXPASSWORD];
GetWideName(Password,NULL,PasswordW,ASIZE(PasswordW));
Data->Cmd.Password.Set(PasswordW);
cleandata(PasswordW,sizeof(PasswordW));
}
#endif
}
int PASCAL RARGetDllVersion()

@ -5,6 +5,7 @@ EXPORTS
RARReadHeader
RARReadHeaderEx
RARProcessFile
RARProcessFileW
RARSetCallback
RARSetChangeVolProc
RARSetProcessDataProc

@ -1,7 +1,7 @@
#ifndef _UNRAR_DLL_
#define _UNRAR_DLL_
#pragma pack(1)
#pragma pack(push, 1)
#define ERAR_SUCCESS 0
#define ERAR_END_ARCHIVE 10
@ -135,6 +135,8 @@ typedef int (CALLBACK *UNRARCALLBACK)(UINT msg,LPARAM UserData,LPARAM P1,LPARAM
#define ROADF_ENCHEADERS 0x0080
#define ROADF_FIRSTVOLUME 0x0100
#define ROADOF_KEEPBROKEN 0x0001
struct RAROpenArchiveDataEx
{
char *ArcName;
@ -148,7 +150,9 @@ struct RAROpenArchiveDataEx
unsigned int Flags;
UNRARCALLBACK Callback;
LPARAM UserData;
unsigned int Reserved[28];
unsigned int OpFlags;
wchar_t *CmtBufW;
unsigned int Reserved[25];
};
enum UNRARCALLBACK_MESSAGES {
@ -180,6 +184,6 @@ int PASCAL RARGetDllVersion();
}
#endif
#pragma pack()
#pragma pack(pop)
#endif

@ -2,8 +2,8 @@
#include <commctrl.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION 5, 60, 100, 2736
PRODUCTVERSION 5, 60, 100, 2736
FILEVERSION 5, 71, 100, 3045
PRODUCTVERSION 5, 71, 100, 3045
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", "5.60.0\0"
VALUE "ProductVersion", "5.60.0\0"
VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2018\0"
VALUE "FileVersion", "5.71.0\0"
VALUE "ProductVersion", "5.71.0\0"
VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2019\0"
VALUE "OriginalFilename", "Unrar.dll\0"
}
}

@ -0,0 +1,13 @@
EXPORTS
RAROpenArchive
RAROpenArchiveEx
RARCloseArchive
RARReadHeader
RARReadHeaderEx
RARProcessFile
RARProcessFileW
RARSetCallback
RARSetChangeVolProc
RARSetProcessDataProc
; RARSetPassword
RARGetDllVersion

@ -56,7 +56,7 @@ class ErrorHandler
uint GetErrorCount() {return ErrCount;}
void SetSignalHandlers(bool Enable);
void Throw(RAR_EXIT Code);
void SetSilent(bool Mode) {Silent=Mode;};
void SetSilent(bool Mode) {Silent=Mode;}
bool GetSysErrMsg(wchar *Msg,size_t Size);
void SysErrMsg();
int GetSystemErrorCode();

@ -87,7 +87,7 @@ void CmdExtract::ExtractArchiveInit(Archive &Arc)
FirstFile=true;
#endif
GlobalPassword=Cmd->Password.IsSet();
GlobalPassword=Cmd->Password.IsSet() || uiIsGlobalPasswordSet();
DataIO.UnpVolume=false;
@ -161,7 +161,7 @@ EXTRACT_ARC_CODE CmdExtract::ExtractArchive()
// This size is necessary to display the correct total progress indicator.
wchar NextName[NM];
wcscpy(NextName,Arc.FileName);
wcsncpyz(NextName,Arc.FileName,ASIZE(NextName));
while (true)
{
@ -261,15 +261,17 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
if (HeaderType==HEAD_ENDARC)
if (Arc.EndArcHead.NextVolume)
{
#ifndef NOVOLUME
#ifdef NOVOLUME
return false;
#else
if (!MergeArchive(Arc,&DataIO,false,Command))
{
ErrHandler.SetErrorCode(RARX_WARNING);
return false;
}
#endif
Arc.Seek(Arc.CurBlockPos,SEEK_SET);
return true;
#endif
}
else
return false;
@ -298,7 +300,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
bool EqualNames=false;
wchar MatchedArg[NM];
int MatchNumber=Cmd->IsProcessFile(Arc.FileHead,&EqualNames,MatchType,MatchedArg,ASIZE(MatchedArg));
int MatchNumber=Cmd->IsProcessFile(Arc.FileHead,&EqualNames,MatchType,0,MatchedArg,ASIZE(MatchedArg));
bool MatchFound=MatchNumber!=0;
#ifndef SFX_MODULE
if (Cmd->ExclPath==EXCL_BASEPATH)
@ -323,6 +325,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
if (wcsicomp(ArcName,CurVolName)!=0 && FileExist(ArcName))
{
wcsncpyz(Cmd->ArcName,ArcName,ASIZE(ArcName)); // For GUI "Delete archive after extraction".
// If first volume name does not match the current name and if such
// volume name really exists, let's unpack from this first volume.
Repeat=true;
@ -344,7 +347,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
#endif
wchar ArcFileName[NM];
ConvertPath(Arc.FileHead.FileName,ArcFileName);
ConvertPath(Arc.FileHead.FileName,ArcFileName,ASIZE(ArcFileName));
if (Arc.FileHead.Version)
{
@ -472,7 +475,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0 &&
!Arc.BrokenHeader)
{
if (GlobalPassword) // For -p<pwd> or Ctrl+P.
if (GlobalPassword) // For -p<pwd> or Ctrl+P to avoid the infinite loop.
{
// This message is used by Android GUI to reset cached passwords.
// Update appropriate code if changed.
@ -613,10 +616,14 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
}
#endif
if (!TestMode && !Arc.BrokenHeader &&
(Arc.FileHead.PackSize<<11)>Arc.FileHead.UnpSize &&
uint64 Preallocated=0;
if (!TestMode && !Arc.BrokenHeader && Arc.FileHead.UnpSize>1000000 &&
Arc.FileHead.PackSize*1024>Arc.FileHead.UnpSize &&
(Arc.FileHead.UnpSize<100000000 || Arc.FileLength()>Arc.FileHead.PackSize))
{
CurFile.Prealloc(Arc.FileHead.UnpSize);
Preallocated=Arc.FileHead.UnpSize;
}
CurFile.SetAllowDelete(!Cmd->KeepBroken);
@ -733,8 +740,9 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
(!LinkEntry || Arc.FileHead.RedirType==FSREDIR_FILECOPY && LinkSuccess) &&
(!BrokenFile || Cmd->KeepBroken))
{
// We could preallocate more space that really written to broken file.
if (BrokenFile)
// We could preallocate more space that really written to broken file
// or file with crafted header.
if (Preallocated>0 && (BrokenFile || DataIO.CurUnpWrite!=Preallocated))
CurFile.Truncate();
#if defined(_WIN_ALL) || defined(_EMX)
@ -850,9 +858,12 @@ void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *De
}
#ifndef SFX_MODULE
if (Cmd->AppendArcNameToPath)
if (Cmd->AppendArcNameToPath!=APPENDARCNAME_NONE)
{
wcsncatz(DestName,PointToName(Arc.FirstVolumeName),DestSize);
if (Cmd->AppendArcNameToPath==APPENDARCNAME_DESTPATH)
wcsncatz(DestName,PointToName(Arc.FirstVolumeName),DestSize);
else
wcsncpyz(DestName,Arc.FirstVolumeName,DestSize); // To archive own dir.
SetExt(DestName,NULL,DestSize);
AddEndSlash(DestName,DestSize);
}
@ -965,7 +976,11 @@ 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.
uiMsg(UIERROR_INCERRCOUNT);
// 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);
return false;
}
Cmd->ManualPassword=true;
@ -1081,7 +1096,7 @@ void CmdExtract::ExtrCreateDir(Archive &Arc,const wchar *ArcFileName)
{
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
if (Cmd->SetCompressedAttr &&
(Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT())
(Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT()!=WNT_NONE)
SetFileCompression(DestFileName,true);
#endif
SetFileHeaderExtra(Cmd,Arc,DestFileName);

@ -271,7 +271,7 @@ bool File::Rename(const wchar *NewName)
Success=RenameFile(FileName,NewName);
if (Success)
wcscpy(FileName,NewName);
wcsncpyz(FileName,NewName,ASIZE(FileName));
return Success;
}

@ -99,7 +99,7 @@ class File
void SetCloseFileTime(RarTime *ftm,RarTime *fta=NULL);
static void SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta);
void GetOpenFileTime(RarTime *ft);
virtual bool IsOpened() {return hFile!=FILE_BAD_HANDLE;}; // 'virtual' for MultiFile class.
virtual bool IsOpened() {return hFile!=FILE_BAD_HANDLE;} // 'virtual' for MultiFile class.
int64 FileLength();
void SetHandleType(FILE_HANDLETYPE Type) {HandleType=Type;}
FILE_HANDLETYPE GetHandleType() {return HandleType;}

@ -348,7 +348,7 @@ wchar *MkTemp(wchar *Name,size_t MaxSize)
swprintf(RndText,ASIZE(RndText),L"%u.%03u",PID,Ext);
if (Length+wcslen(RndText)>=MaxSize || Attempt==1000)
return NULL;
wcscpy(Name+Length,RndText);
wcsncpyz(Name+Length,RndText,MaxSize-Length);
if (!FileExist(Name))
break;
}

@ -26,7 +26,7 @@ FindFile::~FindFile()
void FindFile::SetMask(const wchar *Mask)
{
wcscpy(FindMask,Mask);
wcsncpyz(FindMask,Mask,ASIZE(FindMask));
FirstCall=true;
}
@ -52,7 +52,7 @@ bool FindFile::Next(FindData *fd,bool GetSymLink)
wcsncpyz(DirName,FindMask,ASIZE(DirName));
RemoveNameFromPath(DirName);
if (*DirName==0)
wcscpy(DirName,L".");
wcsncpyz(DirName,L".",ASIZE(DirName));
char DirNameA[NM];
WideToChar(DirName,DirNameA,ASIZE(DirNameA));
if ((dirp=opendir(DirNameA))==NULL)
@ -75,20 +75,20 @@ bool FindFile::Next(FindData *fd,bool GetSymLink)
if (CmpName(FindMask,Name,MATCH_NAMES))
{
wchar FullName[NM];
wcscpy(FullName,FindMask);
wcsncpyz(FullName,FindMask,ASIZE(FullName));
*PointToName(FullName)=0;
if (wcslen(FullName)+wcslen(Name)>=ASIZE(FullName)-1)
{
uiMsg(UIERROR_PATHTOOLONG,FullName,L"",Name);
return false;
}
wcscat(FullName,Name);
wcsncatz(FullName,Name,ASIZE(FullName));
if (!FastFind(FullName,fd,GetSymLink))
{
ErrHandler.OpenErrorMsg(FullName);
continue;
}
wcscpy(fd->Name,FullName);
wcsncpyz(fd->Name,FullName,ASIZE(fd->Name));
break;
}
}

@ -14,10 +14,11 @@
#define SIZEOF_UOHEAD 18
#define SIZEOF_STREAMHEAD 26
#define VER_PACK 29
#define VER_PACK5 50 // It is stored as 0, but we subtract 50 when saving an archive.
#define VER_UNPACK 29
#define VER_UNPACK5 50 // It is stored as 0, but we add 50 when reading an archive.
#define VER_PACK 29U
#define VER_PACK5 50U // It is stored as 0, but we subtract 50 when saving an archive.
#define VER_UNPACK 29U
#define VER_UNPACK5 50U // It is stored as 0, but we add 50 when reading an archive.
#define VER_UNKNOWN 9999U // Just some large value.
#define MHD_VOLUME 0x0001U
@ -174,7 +175,7 @@ struct MainHeader:BaseBlock
struct FileHeader:BlockHeader
{
byte HostOS;
byte UnpVer;
uint UnpVer; // It is 1 byte in RAR29 and bit field in RAR5.
byte Method;
union {
uint FileAttr;
@ -190,7 +191,7 @@ struct FileHeader:BlockHeader
int64 PackSize;
int64 UnpSize;
int64 MaxSize; // Reserve size bytes for vint of this size.
int64 MaxSize; // Reserve packed and unpacked size bytes for vint of this size.
HashValue FileHash;

@ -71,6 +71,7 @@ void ListArchive(CommandData *Cmd)
*VolNumText=0;
while(Arc.ReadHeader()>0)
{
Wait(); // Allow quit listing with Ctrl+C.
HEADER_TYPE HeaderType=Arc.GetHeaderType();
if (HeaderType==HEAD_ENDARC)
{
@ -91,7 +92,7 @@ void ListArchive(CommandData *Cmd)
switch(HeaderType)
{
case HEAD_FILE:
FileMatched=Cmd->IsProcessFile(Arc.FileHead)!=0;
FileMatched=Cmd->IsProcessFile(Arc.FileHead,NULL,MATCH_WILDSUBPATH,0,NULL,0)!=0;
if (FileMatched)
{
ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare);
@ -215,7 +216,7 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
wchar UnpSizeText[30],PackSizeText[30];
if (hd.UnpSize==INT64NDF)
wcscpy(UnpSizeText,L"?");
wcsncpyz(UnpSizeText,L"?",ASIZE(UnpSizeText));
else
itoa(hd.UnpSize,UnpSizeText,ASIZE(UnpSizeText));
itoa(hd.PackSize,PackSizeText,ASIZE(PackSizeText));
@ -229,13 +230,13 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
wchar RatioStr[10];
if (hd.SplitBefore && hd.SplitAfter)
wcscpy(RatioStr,L"<->");
wcsncpyz(RatioStr,L"<->",ASIZE(RatioStr));
else
if (hd.SplitBefore)
wcscpy(RatioStr,L"<--");
wcsncpyz(RatioStr,L"<--",ASIZE(RatioStr));
else
if (hd.SplitAfter)
wcscpy(RatioStr,L"-->");
wcsncpyz(RatioStr,L"-->",ASIZE(RatioStr));
else
swprintf(RatioStr,ASIZE(RatioStr),L"%d%%",ToPercentUnlim(hd.PackSize,hd.UnpSize));
@ -344,7 +345,8 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
mprintf(L"\n%12ls: %ls",St(MListHostOS),HostOS);
mprintf(L"\n%12ls: RAR %ls(v%d) -m%d -md=%d%s",St(MListCompInfo),
Format==RARFMT15 ? L"3.0":L"5.0",hd.UnpVer,hd.Method,
Format==RARFMT15 ? L"3.0":L"5.0",
hd.UnpVer==VER_UNKNOWN ? 0 : hd.UnpVer,hd.Method,
hd.WinSize>=0x100000 ? hd.WinSize/0x100000:hd.WinSize/0x400,
hd.WinSize>=0x100000 ? L"M":L"K");
@ -466,7 +468,7 @@ void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSiz
(A & 0x0001) ? ((A & 0x200)!=0 ? 't' : 'x') : '-');
break;
case HSYS_UNKNOWN:
wcscpy(AttrStr,L"?");
wcsncpyz(AttrStr,L"?",AttrSize);
break;
}
}

@ -85,7 +85,7 @@
#define MCHelpSwILOG L"\n ilog[name] Log errors to file"
#define MCHelpSwINUL L"\n inul Disable all messages"
#define MCHelpSwIOFF L"\n ioff[n] Turn PC off after completing an operation"
#define MCHelpSwISND L"\n isnd Enable sound"
#define MCHelpSwISND L"\n isnd[-] Control notification sounds"
#define MCHelpSwIVER L"\n iver Display the version number"
#define MCHelpSwK L"\n k Lock archive"
#define MCHelpSwKB L"\n kb Keep broken extracted files"
@ -127,11 +127,11 @@
#define MCHelpSwT L"\n t Test files after archiving"
#define MCHelpSwTK L"\n tk Keep original archive time"
#define MCHelpSwTL L"\n tl Set archive time to latest file"
#define MCHelpSwTN L"\n tn<time> Process files newer than <time>"
#define MCHelpSwTO L"\n to<time> Process files older than <time>"
#define MCHelpSwTA L"\n ta<date> Process files modified after <date> in YYYYMMDDHHMMSS format"
#define MCHelpSwTB L"\n tb<date> Process files modified before <date> in YYYYMMDDHHMMSS format"
#define MCHelpSwTS L"\n ts[m|c|a] Save or restore file time (modification, creation, access)"
#define MCHelpSwTN L"\n tn[mcao]<t> Process files newer than <t> time"
#define MCHelpSwTO L"\n to[mcao]<t> Process files older than <t> time"
#define MCHelpSwTA L"\n ta[mcao]<d> Process files modified after <d> YYYYMMDDHHMMSS date"
#define MCHelpSwTB L"\n tb[mcao]<d> Process files modified before <d> YYYYMMDDHHMMSS date"
#define MCHelpSwTS L"\n ts[m,c,a] Save or restore file time (modification, creation, access)"
#define MCHelpSwU L"\n u Update files"
#define MCHelpSwV L"\n v Create volumes with size autodetection or list all volumes"
#define MCHelpSwVUnr L"\n v List all volumes"
@ -354,7 +354,7 @@
#define MCannotDelete L"\nCannot delete %s"
#define MRecycleFailed L"\nCannot move some files and folders to Recycle Bin"
#define MCalcCRC L"\nCalculating the checksum"
#define MTooLargeSFXArc L"\nWARNING: Too large SFX archive. Windows cannot run the executable file exceeding 4 GB."
#define MTooLargeSFXArc L"\nToo large SFX archive. Windows cannot run the executable file exceeding 4 GB."
#define MCalcCRCAllVol L"\nCalculating checksums of all volumes."
#define MNotEnoughDisk L"\nERROR: Not enough disk space for %s."
#define MNewerRAR L"\nYou may need a newer version of RAR."

@ -25,10 +25,10 @@ bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode)
if (CmpMode!=MATCH_NAMES)
{
size_t WildLength=wcslen(Wildcard);
if (CmpMode!=MATCH_EXACT && CmpMode!=MATCH_EXACTPATH &&
if (CmpMode!=MATCH_EXACT && CmpMode!=MATCH_EXACTPATH && CmpMode!=MATCH_ALLWILD &&
mwcsnicompc(Wildcard,Name,WildLength,ForceCase)==0)
{
// For all modes except MATCH_NAMES, MATCH_EXACT and MATCH_EXACTPATH
// For all modes except MATCH_NAMES, MATCH_EXACT, MATCH_EXACTPATH, MATCH_ALLWILD,
// "path1" mask must match "path1\path2\filename.ext" and "path1" names.
wchar NextCh=Name[WildLength];
if (NextCh==L'\\' || NextCh==L'/' || NextCh==0)
@ -46,6 +46,8 @@ bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode)
if ((CmpMode==MATCH_EXACT || CmpMode==MATCH_EXACTPATH) &&
mwcsicompc(Path1,Path2,ForceCase)!=0)
return(false);
if (CmpMode==MATCH_ALLWILD)
return match(Wildcard,Name,ForceCase);
if (CmpMode==MATCH_SUBPATH || CmpMode==MATCH_WILDSUBPATH)
if (IsWildcard(Path1))
return(match(Wildcard,Name,ForceCase));
@ -64,8 +66,8 @@ bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode)
// Always return false for RAR temporary files to exclude them
// from archiving operations.
if (mwcsnicompc(L"__rar_",Name2,6,false)==0)
return(false);
// if (mwcsnicompc(L"__rar_",Name2,6,false)==0)
// return(false);
if (CmpMode==MATCH_EXACT)
return(mwcsicompc(Name1,Name2,ForceCase)==0);

@ -14,6 +14,10 @@ enum {
MATCH_EXACT, // Paths must match exactly.
// Names must match exactly.
MATCH_ALLWILD, // Paths and names are compared using wildcards.
// Unlike MATCH_SUBPATH, paths do not match subdirs
// unless a wildcard tells so.
MATCH_EXACTPATH, // Paths must match exactly.
// Names are compared using wildcards.

@ -12,11 +12,7 @@ enum PATH_EXCL_MODE {
EXCL_SKIPWHOLEPATH, // -ep (exclude the path completely)
EXCL_BASEPATH, // -ep1 (exclude the base part of path)
EXCL_SAVEFULLPATH, // -ep2 (the full path without the disk letter)
EXCL_ABSPATH, // -ep3 (the full path with the disk letter)
EXCL_SKIPABSPATH // Works as EXCL_BASEPATH for fully qualified paths
// and as EXCL_UNCHANGED for relative paths.
// Used by WinRAR GUI only.
EXCL_ABSPATH // -ep3 (the full path with the disk letter)
};
enum {SOLID_NONE=0,SOLID_NORMAL=1,SOLID_COUNT=2,SOLID_FILEEXT=4,
@ -63,11 +59,20 @@ enum SAVECOPY_MODE {
SAVECOPY_DUPLISTEXIT
};
enum APPENDARCNAME_MODE
{
APPENDARCNAME_NONE=0,APPENDARCNAME_DESTPATH,APPENDARCNAME_OWNDIR
};
enum POWER_MODE {
POWERMODE_KEEP=0,POWERMODE_OFF,POWERMODE_HIBERNATE,POWERMODE_SLEEP,
POWERMODE_RESTART
};
// Need "forced off" state to turn off sound in GUI command line.
enum SOUND_NOTIFY_MODE {SOUND_NOTIFY_DEFAULT=0,SOUND_NOTIFY_ON,SOUND_NOTIFY_OFF};
struct FilterMode
{
FilterState State;
@ -112,7 +117,7 @@ class RAROptions
wchar LogName[NM];
MESSAGE_TYPE MsgStream;
bool Sound;
SOUND_NOTIFY_MODE Sound;
OVERWRITE_MODE Overwrite;
int Method;
HASH_TYPE HashType;
@ -163,8 +168,10 @@ class RAROptions
bool SaveStreams;
bool SetCompressedAttr;
bool IgnoreGeneralAttr;
RarTime FileTimeBefore;
RarTime FileTimeAfter;
RarTime FileMtimeBefore,FileCtimeBefore,FileAtimeBefore;
bool FileMtimeBeforeOR,FileCtimeBeforeOR,FileAtimeBeforeOR;
RarTime FileMtimeAfter,FileCtimeAfter,FileAtimeAfter;
bool FileMtimeAfterOR,FileCtimeAfterOR,FileAtimeAfterOR;
int64 FileSizeLess;
int64 FileSizeMore;
bool Lock;
@ -173,9 +180,9 @@ class RAROptions
FilterMode FilterModes[MAX_FILTER_TYPES];
wchar EmailTo[NM];
uint VersionControl;
bool AppendArcNameToPath;
APPENDARCNAME_MODE AppendArcNameToPath;
POWER_MODE Shutdown;
EXTTIME_MODE xmtime;
EXTTIME_MODE xmtime; // Extended time modes (time precision to store).
EXTTIME_MODE xctime;
EXTTIME_MODE xatime;
wchar CompressStdin[NM];

@ -32,7 +32,12 @@
#define STRICT 1
#endif
// 'ifndef' check here is needed for unrar.dll header to avoid macro
// re-definition warnings in third party projects.
#ifndef UNICODE
#define UNICODE
#endif
#undef WINVER
#undef _WIN32_WINNT
#define WINVER 0x0501

@ -16,7 +16,7 @@ wchar* PointToLastChar(const wchar *Path)
}
wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath)
wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath,size_t DestSize)
{
const wchar *DestPtr=SrcPath;
@ -25,7 +25,7 @@ wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath)
if (IsPathDiv(s[0]) && s[1]=='.' && s[2]=='.' && IsPathDiv(s[3]))
DestPtr=s+4;
// Remove <d>:\ and any sequence of . and \ in the beginning of path string.
// Remove any amount of <d>:\ and any sequence of . and \ in the beginning of path string.
while (*DestPtr!=0)
{
const wchar *s=DestPtr;
@ -58,7 +58,7 @@ wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath)
// so we use the temporary buffer for copying.
wchar TmpStr[NM];
wcsncpyz(TmpStr,DestPtr,ASIZE(TmpStr));
wcscpy(DestPath,TmpStr);
wcsncpyz(DestPath,TmpStr,DestSize);
}
return (wchar *)DestPtr;
}
@ -120,7 +120,14 @@ bool CmpExt(const wchar *Name,const wchar *Ext)
bool IsWildcard(const wchar *Str)
{
return Str==NULL ? false:wcspbrk(Str,L"*?")!=NULL;
if (Str==NULL)
return false;
#ifdef _WIN_ALL
// Not treat the special NTFS \\?\d: path prefix as a wildcard.
if (Str[0]=='\\' && Str[1]=='\\' && Str[2]=='?' && Str[3]=='\\')
Str+=4;
#endif
return wcspbrk(Str,L"*?")!=NULL;
}
@ -163,8 +170,8 @@ int GetPathDisk(const wchar *Path)
void AddEndSlash(wchar *Path,size_t MaxLength)
{
size_t Length=wcslen(Path);
if (Length>0 && Path[Length-1]!=CPATHDIVIDER && Length+1<MaxLength)
wcscat(Path,SPATHDIVIDER);
if (Length>0 && Path[Length-1]!=CPATHDIVIDER)
wcsncatz(Path,SPATHDIVIDER,MaxLength);
}
@ -303,9 +310,13 @@ void GetConfigName(const wchar *Name,wchar *FullName,size_t MaxSize,bool CheckEx
#endif
// Returns a pointer to rightmost digit of volume number.
// Returns a pointer to rightmost digit of volume number or to beginning
// of file name if numeric part is missing.
wchar* GetVolNumPart(const wchar *ArcName)
{
if (*ArcName==0)
return (wchar *)ArcName;
// Pointing to last name character.
const wchar *ChPtr=ArcName+wcslen(ArcName)-1;
@ -346,18 +357,33 @@ void NextVolumeName(wchar *ArcName,uint MaxLength,bool OldNumbering)
ChPtr=GetExt(ArcName);
}
else
if (ChPtr[1]==0 && wcslen(ArcName)<MaxLength-3 || wcsicomp(ChPtr+1,L"exe")==0 || wcsicomp(ChPtr+1,L"sfx")==0)
wcscpy(ChPtr+1,L"rar");
if (ChPtr[1]==0 || wcsicomp(ChPtr,L".exe")==0 || wcsicomp(ChPtr,L".sfx")==0)
wcsncpyz(ChPtr,L".rar",MaxLength-(ChPtr-ArcName));
if (ChPtr==NULL || *ChPtr!='.' || ChPtr[1]==0)
{
// Normally we shall have some extension here. If we don't, it means
// the name has no extension and buffer has no free space to append one.
// Let's clear the name to prevent a new call with same name and return.
*ArcName=0;
return;
}
if (!OldNumbering)
{
ChPtr=GetVolNumPart(ArcName);
// We should not check for IsDigit(*ChPtr) here and should increment
// even non-digits. If we got a corrupt archive with volume flag,
// but without numeric part, we still need to modify its name somehow,
// so while (exist(name)) {NextVolumeName()} loops do not run infinitely.
while ((++(*ChPtr))=='9'+1)
{
*ChPtr='0';
ChPtr--;
if (ChPtr<ArcName || !IsDigit(*ChPtr))
{
// Convert .part:.rar (.part9.rar after increment) to part10.rar.
for (wchar *EndPtr=ArcName+wcslen(ArcName);EndPtr!=ChPtr;EndPtr--)
*(EndPtr+1)=*EndPtr;
*(ChPtr+1)='1';
@ -366,15 +392,15 @@ void NextVolumeName(wchar *ArcName,uint MaxLength,bool OldNumbering)
}
}
else
if (!IsDigit(*(ChPtr+2)) || !IsDigit(*(ChPtr+3)))
wcscpy(ChPtr+2,L"00");
if (!IsDigit(ChPtr[2]) || !IsDigit(ChPtr[3]))
wcsncpyz(ChPtr+2,L"00",MaxLength-(ChPtr-ArcName)-2); // From .rar to .r00.
else
{
ChPtr+=3;
while ((++(*ChPtr))=='9'+1)
if (*(ChPtr-1)=='.')
ChPtr+=wcslen(ChPtr)-1; // Set to last character.
while (++(*ChPtr)=='9'+1)
if (ChPtr<=ArcName || *(ChPtr-1)=='.')
{
*ChPtr='A';
*ChPtr='a'; // From .999 to .a00 if started from .001 or for too short names.
break;
}
else
@ -585,8 +611,7 @@ int ParseVersionFileName(wchar *Name,bool Truncate)
wchar *VerText=wcsrchr(Name,';');
if (VerText!=NULL)
{
if (Version==0)
Version=atoiw(VerText+1);
Version=atoiw(VerText+1);
if (Truncate)
*VerText=0;
}
@ -652,7 +677,7 @@ wchar* VolNameToFirstName(const wchar *VolName,wchar *FirstName,size_t MaxSize,b
#ifndef SFX_MODULE
static void GenArcName(wchar *ArcName,const wchar *GenerateMask,uint ArcNumber,bool &ArcNumPresent)
static void GenArcName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,uint ArcNumber,bool &ArcNumPresent)
{
bool Prefix=false;
if (*GenerateMask=='+')
@ -713,7 +738,7 @@ static void GenArcName(wchar *ArcName,const wchar *GenerateMask,uint ArcNumber,b
wchar Ext[NM],*Dot=GetExt(ArcName);
*Ext=0;
if (Dot==NULL)
wcscpy(Ext,*PointToName(ArcName)==0 ? L".rar":L"");
wcsncpyz(Ext,*PointToName(ArcName)==0 ? L".rar":L"",ASIZE(Ext));
else
{
wcsncpyz(Ext,Dot,ASIZE(Ext));
@ -749,7 +774,7 @@ static void GenArcName(wchar *ArcName,const wchar *GenerateMask,uint ArcNumber,b
int CField[sizeof(Field)/sizeof(Field[0])];
memset(CField,0,sizeof(CField));
QuoteMode=false;
for (int I=0;Mask[I]!=0;I++)
for (uint I=0;Mask[I]!=0;I++)
{
if (Mask[I]=='{' || Mask[I]=='}')
{
@ -810,21 +835,17 @@ static void GenArcName(wchar *ArcName,const wchar *GenerateMask,uint ArcNumber,b
AddEndSlash(NewName,ASIZE(NewName));
wcsncatz(NewName,DateText,ASIZE(NewName));
wcsncatz(NewName,PointToName(ArcName),ASIZE(NewName));
wcscpy(ArcName,NewName);
wcsncpyz(ArcName,NewName,MaxSize);
}
else
wcscat(ArcName,DateText);
wcscat(ArcName,Ext);
wcsncatz(ArcName,DateText,MaxSize);
wcsncatz(ArcName,Ext,MaxSize);
}
void GenerateArchiveName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,bool Archiving)
{
// Must be enough space for archive name plus all stuff in mask plus
// extra overhead produced by mask 'N' (archive number) characters.
// One 'N' character can result in several numbers if we process more
// than 9 archives.
wchar NewName[NM+MAX_GENERATE_MASK+20];
wchar NewName[NM];
uint ArcNumber=1;
while (true) // Loop for 'N' (archive number) processing.
@ -833,7 +854,7 @@ void GenerateArchiveName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask
bool ArcNumPresent=false;
GenArcName(NewName,GenerateMask,ArcNumber,ArcNumPresent);
GenArcName(NewName,ASIZE(NewName),GenerateMask,ArcNumber,ArcNumPresent);
if (!ArcNumPresent)
break;
@ -845,7 +866,7 @@ void GenerateArchiveName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask
// existing archive before the first unused name. So we generate
// the name for (ArcNumber-1) below.
wcsncpyz(NewName,NullToEmpty(ArcName),ASIZE(NewName));
GenArcName(NewName,GenerateMask,ArcNumber-1,ArcNumPresent);
GenArcName(NewName,ASIZE(NewName),GenerateMask,ArcNumber-1,ArcNumPresent);
}
break;
}
@ -895,8 +916,8 @@ bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize)
{
if (MaxSize<=PrefixLength+SrcLength)
return false;
wcsncpy(Dest,Prefix,PrefixLength);
wcscpy(Dest+PrefixLength,Src);
wcsncpyz(Dest,Prefix,MaxSize);
wcsncatz(Dest,Src,MaxSize); // "\\?\D:\very long path".
return true;
}
else
@ -904,9 +925,9 @@ bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize)
{
if (MaxSize<=PrefixLength+SrcLength+2)
return false;
wcsncpy(Dest,Prefix,PrefixLength);
wcscpy(Dest+PrefixLength,L"UNC");
wcscpy(Dest+PrefixLength+3,Src+1);
wcsncpyz(Dest,Prefix,MaxSize);
wcsncatz(Dest,L"UNC",MaxSize);
wcsncatz(Dest,Src+1,MaxSize); // "\\?\UNC\server\share".
return true;
}
// We may be here only if we modify IsFullPath in the future.
@ -923,9 +944,10 @@ bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize)
{
if (MaxSize<=PrefixLength+SrcLength+2)
return false;
wcsncpy(Dest,Prefix,PrefixLength);
wcsncpy(Dest+PrefixLength,CurDir,2); // Copy drive letter 'd:'.
wcscpy(Dest+PrefixLength+2,Src);
wcsncpyz(Dest,Prefix,MaxSize);
CurDir[2]=0;
wcsncatz(Dest,CurDir,MaxSize); // Copy drive letter 'd:'.
wcsncatz(Dest,Src,MaxSize);
return true;
}
else // Paths in path\name format.
@ -933,8 +955,8 @@ bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize)
AddEndSlash(CurDir,ASIZE(CurDir));
if (MaxSize<=PrefixLength+wcslen(CurDir)+SrcLength)
return false;
wcsncpy(Dest,Prefix,PrefixLength);
wcscpy(Dest+PrefixLength,CurDir);
wcsncpyz(Dest,Prefix,MaxSize);
wcsncatz(Dest,CurDir,MaxSize);
if (Src[0]=='.' && IsPathDiv(Src[1])) // Remove leading .\ in pathname.
Src+=2;

@ -3,7 +3,7 @@
wchar* PointToName(const wchar *Path);
wchar* PointToLastChar(const wchar *Path);
wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath);
wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath,size_t DestSize);
void SetName(wchar *FullName,const wchar *Name,size_t MaxSize);
void SetExt(wchar *Name,const wchar *NewExt,size_t MaxSize);
void SetSFXExt(wchar *SFXName,size_t MaxSize);

@ -84,7 +84,7 @@ void QuickOpen::Load(uint64 BlockPos)
if (ReadSize==0 || Arc->GetHeaderType()!=HEAD_SERVICE ||
!Arc->SubHead.CmpName(SUBHEAD_TYPE_QOPEN))
return;
QLHeaderPos=Arc->CurBlockPos;
QOHeaderPos=Arc->CurBlockPos;
RawDataStart=Arc->Tell();
RawDataSize=Arc->SubHead.UnpSize;
@ -172,7 +172,7 @@ bool QuickOpen::Seek(int64 Offset,int Method)
// archive updating involve several passes. So if we detect that file
// pointer is moved back, we reload quick open data from beginning.
if (Method==SEEK_SET && (uint64)Offset<SeekPos && (uint64)Offset<LastReadHeaderPos)
Load(QLHeaderPos);
Load(QOHeaderPos);
if (Method==SEEK_SET)
SeekPos=Offset;
@ -250,10 +250,10 @@ bool QuickOpen::ReadRaw(RawRead &Raw)
return false;
}
// If rest of block data crosses buffer boundary, read it in loop.
size_t DataLeft=ReadBufSize-ReadBufPos;
// If rest of block data crosses Buf boundary, read it in loop.
while (SizeToRead>0)
{
size_t DataLeft=ReadBufSize-ReadBufPos;
size_t CurSizeToRead=Min(DataLeft,(size_t)SizeToRead);
Raw.Read(Buf+ReadBufPos,CurSizeToRead);
ReadBufPos+=CurSizeToRead;
@ -285,6 +285,6 @@ bool QuickOpen::ReadNext()
LastReadHeader.Alloc(HeaderSize);
Raw.GetB(&LastReadHeader[0],HeaderSize);
// Calculate the absolute position as offset from quick open service header.
LastReadHeaderPos=QLHeaderPos-Offset;
LastReadHeaderPos=QOHeaderPos-Offset;
return true;
}

@ -29,24 +29,24 @@ class QuickOpen
QuickOpenItem *ListStart;
QuickOpenItem *ListEnd;
byte *Buf;
static const size_t MaxBufSize=0x10000; // Must be multiple of CRYPT_BLOCK_SIZE.
size_t CurBufSize;
byte *Buf; // Read quick open data here.
static const size_t MaxBufSize=0x10000; // Buf size, must be multiple of CRYPT_BLOCK_SIZE.
size_t CurBufSize; // Current size of buffered data in write mode.
#ifndef RAR_NOCRYPT // For shell extension.
CryptData Crypt;
#endif
bool Loaded;
uint64 QLHeaderPos;
uint64 RawDataStart;
uint64 RawDataSize;
uint64 RawDataPos;
size_t ReadBufSize;
size_t ReadBufPos;
uint64 QOHeaderPos; // Main QO header position.
uint64 RawDataStart; // Start of QO data, just after the main header.
uint64 RawDataSize; // Size of entire QO data.
uint64 RawDataPos; // Current read position in QO data.
size_t ReadBufSize; // Size of Buf data currently read from QO.
size_t ReadBufPos; // Current read position in Buf data.
Array<byte> LastReadHeader;
uint64 LastReadHeaderPos;
uint64 SeekPos;
bool UnsyncSeekPos; // QOpen SeekPos does not match an actual file pointer.
bool UnsyncSeekPos; // QOpen SeekPos does not match an actual file pointer.
public:
QuickOpen();
~QuickOpen();

@ -37,7 +37,7 @@ int main(int argc, char *argv[])
CommandData *Cmd=new CommandData;
#ifdef SFX_MODULE
wcscpy(Cmd->Command,L"X");
wcsncpyz(Cmd->Command,L"X",ASIZE(Cmd->Command));
char *Switch=argc>1 ? argv[1]:NULL;
if (Switch!=NULL && Cmd->IsSwitch(Switch[0]))
{
@ -68,6 +68,8 @@ int main(int argc, char *argv[])
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
ShutdownOnClose=Cmd->Shutdown;
if (ShutdownOnClose)
ShutdownCheckAnother(true);
#endif
uiInit(Cmd->Sound);
@ -93,7 +95,8 @@ int main(int argc, char *argv[])
}
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
if (ShutdownOnClose!=POWERMODE_KEEP && ErrHandler.IsShutdownEnabled())
if (ShutdownOnClose!=POWERMODE_KEEP && ErrHandler.IsShutdownEnabled() &&
!ShutdownCheckAnother(false))
Shutdown(ShutdownOnClose);
#endif
ErrHandler.MainExit=true;

@ -25,6 +25,7 @@ void ComprDataIO::Init()
NextVolumeMissing=false;
SrcFile=NULL;
DestFile=NULL;
UnpWrAddr=NULL;
UnpWrSize=0;
Command=NULL;
Encryption=false;

@ -111,7 +111,7 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
NewStyle=IsNewStyleRev(ArcName);
while (Ext>ArcName+1 && (IsDigit(*(Ext-1)) || *(Ext-1)=='_'))
Ext--;
wcscpy(Ext,L"*.*");
wcsncpyz(Ext,L"*.*",ASIZE(ArcName)-(Ext-ArcName));
FindFile Find;
Find.SetMask(ArcName);
@ -235,7 +235,7 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
}
RecVolNumber=P[1];
FileNumber=P[2];
wcscpy(PrevName,CurName);
wcsncpyz(PrevName,CurName,ASIZE(PrevName));
File *NewFile=new File;
NewFile->TOpen(CurName);
SrcFile[FileNumber+P[0]-1]=NewFile;
@ -247,7 +247,7 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
if (!Silent || FoundRecVolumes!=0)
uiMsg(UIMSG_RECVOLFOUND,FoundRecVolumes);
if (FoundRecVolumes==0)
return(false);
return false;
bool WriteFlags[256];
memset(WriteFlags,0,sizeof(WriteFlags));
@ -290,8 +290,8 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
{
NewFile->Close();
wchar NewName[NM];
wcscpy(NewName,ArcName);
wcscat(NewName,L".bad");
wcsncpyz(NewName,ArcName,ASIZE(NewName));
wcsncatz(NewName,L".bad",ASIZE(NewName));
uiMsg(UIMSG_BADARCHIVE,ArcName);
uiMsg(UIMSG_RENAMING,ArcName,NewName);
@ -322,7 +322,7 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
MissingVolumes++;
if (CurArcNum==FileNumber-1)
wcscpy(LastVolName,ArcName);
wcsncpyz(LastVolName,ArcName,ASIZE(LastVolName));
uiMsg(UIMSG_MISSINGVOL,ArcName);
uiMsg(UIEVENT_NEWARCHIVE,ArcName);

@ -139,12 +139,10 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
wcsncpyz(ArcName,Name,ASIZE(ArcName));
wchar *Num=GetVolNumPart(ArcName);
if (Num==ArcName)
return false; // Number part is missing in the name.
while (Num>ArcName && IsDigit(*(Num-1)))
Num--;
if (Num==ArcName)
return false; // Entire volume name is numeric, not possible for REV file.
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];
@ -289,8 +287,8 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
Item->f->Close();
wchar NewName[NM];
wcscpy(NewName,Item->Name);
wcscat(NewName,L".bad");
wcsncpyz(NewName,Item->Name,ASIZE(NewName));
wcsncatz(NewName,L".bad",ASIZE(NewName));
uiMsg(UIMSG_BADARCHIVE,Item->Name);
uiMsg(UIMSG_RENAMING,Item->Name,NewName);

@ -79,7 +79,10 @@ void Rijndael::Init(bool Encrypt,const byte *key,uint keyLen,const byte * initVe
AES_NI=(CPUInfo[2] & 0x2000000)!=0;
#endif
uint uKeyLenInBytes;
// Other developers asked us to initialize it to suppress "may be used
// uninitialized" warning in code below in some compilers.
uint uKeyLenInBytes=0;
switch(keyLen)
{
case 128:

@ -27,7 +27,7 @@ RSCoder16::~RSCoder16()
delete[] MX;
delete[] ValidFlags;
}
// Initialize logarithms and exponents Galois field tables.
void RSCoder16::gfInit()
@ -41,7 +41,7 @@ void RSCoder16::gfInit()
gfExp[L]=E;
gfExp[L+gfSize]=E; // Duplicate the table to avoid gfExp overflow check.
E<<=1;
if (E>gfSize)
if (E>gfSize)
E^=0x1100B; // Irreducible field-generator polynomial.
}
@ -59,7 +59,7 @@ uint RSCoder16::gfAdd(uint a,uint b) // Addition in Galois field.
}
uint RSCoder16::gfMul(uint a,uint b) // Multiplication in Galois field.
uint RSCoder16::gfMul(uint a,uint b) // Multiplication in Galois field.
{
return gfExp[gfLog[a]+gfLog[b]];
}
@ -156,7 +156,7 @@ void RSCoder16::InvertDecoderMatrix()
for (uint Kr = 0, Kf = 0; Kr < NE; Kr++, Kf++)
{
while (ValidFlags[Kf]) // Skip trivial rows.
Kf++;
Kf++;
MI[Kr * ND + Kf] = 1; // Set diagonal 1.
}
@ -174,7 +174,7 @@ void RSCoder16::InvertDecoderMatrix()
// after MI[..]^=, but we do not need it for matrix inversion.
for (uint I = 0; I < NE; I++)
MI[I * ND + Kf] ^= MX[I * ND + Kf];
Kf++;
Kf++;
}
if (Kf == ND)
@ -186,14 +186,14 @@ void RSCoder16::InvertDecoderMatrix()
uint PInv = gfInv( MXk[Kf] ); // Pivot inverse.
// Divide the pivot row by pivot, so pivot cell contains 1.
for (uint I = 0; I < ND; I++)
{
{
MXk[I] = gfMul( MXk[I], PInv );
MIk[I] = gfMul( MIk[I], PInv );
}
for (uint I = 0; I < NE; I++)
if (I != Kr) // For all rows except containing the pivot cell.
{
{
// Apply Gaussian elimination Mij -= Mkj * Mik / pivot.
// Since pivot is already 1, it is reduced to Mij -= Mkj * Mik.
uint *MXi = MX + I * ND; // i-th row of main matrix.
@ -361,7 +361,7 @@ bool RSCoder16::SSE_UpdateECC(uint DataNum, uint ECCNum, const byte *Data, byte
__m128i LowBytes1=_mm_and_si128(D[1],LowByteMask);
__m128i HighBytes=_mm_packus_epi16(HighBytes0,HighBytes1);
__m128i LowBytes=_mm_packus_epi16(LowBytes0,LowBytes1);
// Multiply bits 0..3 of low bytes. Store low and high product bytes
// separately in cumulative sum variables.
__m128i LowBytesLow4=_mm_and_si128(LowBytes,Low4Mask);
@ -377,7 +377,7 @@ bool RSCoder16::SSE_UpdateECC(uint DataNum, uint ECCNum, const byte *Data, byte
// Add new product to existing sum, low and high bytes separately.
LowBytesMultSum=_mm_xor_si128(LowBytesMultSum,LowBytesHigh4MultLow);
HighBytesMultSum=_mm_xor_si128(HighBytesMultSum,LowBytesHigh4MultHigh);
// Multiply bits 0..3 of high bytes. Store low and high product bytes separately.
__m128i HighBytesLow4=_mm_and_si128(HighBytes,Low4Mask);
__m128i HighBytesLow4MultLow=_mm_shuffle_epi8(T2L,HighBytesLow4);
@ -413,7 +413,7 @@ bool RSCoder16::SSE_UpdateECC(uint DataNum, uint ECCNum, const byte *Data, byte
// because Data and ECC can have different alignment offsets.
for (; Pos<BlockSize; Pos+=2)
*(ushort*)(ECC+Pos) ^= gfMul( M, *(ushort*)(Data+Pos) );
return true;
}
#endif

@ -142,7 +142,12 @@ bool ScanTree::GetFilteredMask()
bool WildcardFound=false;
uint FolderWildcardCount=0;
uint SlashPos=0;
for (int I=0;CurMask[I]!=0;I++)
uint StartPos=0;
#ifdef _WIN_ALL // Not treat the special NTFS \\?\d: path prefix as a wildcard.
if (CurMask[0]=='\\' && CurMask[1]=='\\' && CurMask[2]=='?' && CurMask[3]=='\\')
StartPos=4;
#endif
for (uint I=StartPos;CurMask[I]!=0;I++)
{
if (CurMask[I]=='?' || CurMask[I]=='*')
WildcardFound=true;
@ -171,7 +176,7 @@ bool ScanTree::GetFilteredMask()
wchar Filter[NM];
// Convert path\dir*\ to *\dir filter to search for 'dir' in all 'path' subfolders.
wcscpy(Filter,L"*");
wcsncpyz(Filter,L"*",ASIZE(Filter));
AddEndSlash(Filter,ASIZE(Filter));
// SlashPos might point or not point to path separator for masks like 'dir*', '\dir*' or 'd:dir*'
wchar *WildName=IsPathDiv(CurMask[SlashPos]) || IsDriveDiv(CurMask[SlashPos]) ? CurMask+SlashPos+1 : CurMask+SlashPos;
@ -360,7 +365,7 @@ SCAN_CODE ScanTree::FindProc(FindData *FD)
wcsncpyz(CurMask,Mask+1,ASIZE(CurMask));
else
{
*(PrevSlash+1)=0;
*PrevSlash=0;
wcsncatz(CurMask,Mask,ASIZE(CurMask));
}
}

@ -64,7 +64,7 @@ class ScanTree
ScanTree(StringList *FileMasks,RECURSE_MODE Recurse,bool GetLinks,SCAN_DIRS GetDirs);
~ScanTree();
SCAN_CODE GetNext(FindData *FindData);
size_t GetSpecPathLength() {return SpecPathLength;};
size_t GetSpecPathLength() {return SpecPathLength;}
int GetErrors() {return Errors;};
void SetErrArcName(const wchar *Name) {wcsncpyz(ErrArcName,Name,ASIZE(ErrArcName));}
void SetCommandData(CommandData *Cmd) {ScanTree::Cmd=Cmd;}

@ -281,53 +281,49 @@ int wcsnicompc(const wchar *s1,const wchar *s2,size_t n)
}
// Safe strncpy: copies maxlen-1 max and always returns zero terminated dest.
char* strncpyz(char *dest, const char *src, size_t maxlen)
// Safe copy: copies maxlen-1 max and for maxlen>0 returns zero terminated dest.
void strncpyz(char *dest, const char *src, size_t maxlen)
{
if (maxlen>0)
{
strncpy(dest,src,maxlen-1);
dest[maxlen-1]=0;
while (--maxlen>0 && *src!=0)
*dest++=*src++;
*dest=0;
}
return dest;
}
// Safe wcsncpy: copies maxlen-1 max and always returns zero terminated dest.
wchar* wcsncpyz(wchar *dest, const wchar *src, size_t maxlen)
// Safe copy: copies maxlen-1 max and for maxlen>0 returns zero terminated dest.
void wcsncpyz(wchar *dest, const wchar *src, size_t maxlen)
{
if (maxlen>0)
{
wcsncpy(dest,src,maxlen-1);
dest[maxlen-1]=0;
while (--maxlen>0 && *src!=0)
*dest++=*src++;
*dest=0;
}
return dest;
}
// Safe strncat: resulting dest length cannot exceed maxlen and dest
// is always zero terminated. Note that 'maxlen' parameter defines the entire
// dest buffer size and is not compatible with standard strncat.
char* strncatz(char* dest, const char* src, size_t maxlen)
// Safe append: resulting dest length cannot exceed maxlen and dest
// is always zero terminated. 'maxlen' parameter defines the entire
// dest buffer size and is not compatible with wcsncat.
void strncatz(char* dest, const char* src, size_t maxlen)
{
size_t Length = strlen(dest);
int avail=int(maxlen - Length - 1);
if (avail > 0)
strncat(dest, src, avail);
return dest;
size_t length = strlen(dest);
if (maxlen > length)
strncpyz(dest + length, src, maxlen - length);
}
// Safe wcsncat: resulting dest length cannot exceed maxlen and dest
// is always zero terminated. Note that 'maxlen' parameter defines the entire
// dest buffer size and is not compatible with standard wcsncat.
wchar* wcsncatz(wchar* dest, const wchar* src, size_t maxlen)
// Safe append: resulting dest length cannot exceed maxlen and dest
// is always zero terminated. 'maxlen' parameter defines the entire
// dest buffer size and is not compatible with wcsncat.
void wcsncatz(wchar* dest, const wchar* src, size_t maxlen)
{
size_t Length = wcslen(dest);
int avail=int(maxlen - Length - 1);
if (avail > 0)
wcsncat(dest, src, avail);
return dest;
size_t length = wcslen(dest);
if (maxlen > length)
wcsncpyz(dest + length, src, maxlen - length);
}

@ -16,10 +16,10 @@ wchar* RemoveLF(wchar *Str);
unsigned char loctolower(unsigned char ch);
unsigned char loctoupper(unsigned char ch);
char* strncpyz(char *dest, const char *src, size_t maxlen);
wchar* wcsncpyz(wchar *dest, const wchar *src, size_t maxlen);
char* strncatz(char* dest, const char* src, size_t maxlen);
wchar* wcsncatz(wchar* dest, const wchar* src, size_t maxlen);
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);

@ -77,7 +77,7 @@ class SubAllocator
inline void* ExpandUnits(void* ptr,int OldNU);
inline void* ShrinkUnits(void* ptr,int OldNU,int NewNU);
inline void FreeUnits(void* ptr,int OldNU);
long GetAllocatedMemory() {return(SubAllocatorSize);};
long GetAllocatedMemory() {return(SubAllocatorSize);}
byte *pText, *UnitsStart,*HeapEnd,*FakeUnitsStart;
};

@ -123,6 +123,28 @@ void Shutdown(POWER_MODE Mode)
if (Mode==POWERMODE_RESTART)
ExitWindowsEx(EWX_REBOOT|EWX_FORCE,SHTDN_REASON_FLAG_PLANNED);
}
bool ShutdownCheckAnother(bool Open)
{
const wchar *EventName=L"rar -ioff";
static HANDLE hEvent=NULL;
bool Result=false; // Return false if no other RAR -ioff are running.
if (Open) // Create or open the event.
hEvent=CreateEvent(NULL,FALSE,FALSE,EventName);
else
{
if (hEvent!=NULL)
CloseHandle(hEvent); // Close our event.
// Check if other copies still own the event. While race conditions
// are possible, they are improbable and their harm is minimal.
hEvent=CreateEvent(NULL,FALSE,FALSE,EventName);
Result=GetLastError()==ERROR_ALREADY_EXISTS;
if (hEvent!=NULL)
CloseHandle(hEvent);
}
return Result;
}
#endif

@ -23,6 +23,7 @@ clock_t MonoClock();
void Wait();
bool EmailFile(const wchar *FileName,const wchar *MailToW);
void Shutdown(POWER_MODE Mode);
bool ShutdownCheckAnother(bool Open);
#ifdef _WIN_ALL
HMODULE WINAPI LoadSysLibrary(const wchar *Name);

@ -53,25 +53,22 @@ static struct GlobalPoolCreateSync
ThreadPool* CreateThreadPool()
{
#ifdef RARDLL
// We use a simple thread pool, which does not allow to add tasks from
// different functions and threads in the same time. It is ok for RAR,
// but UnRAR.dll can be used in multithreaded environment. So we return
// a new pool for UnRAR.dll every time.
return new ThreadPool(MaxPoolThreads);
#else
// Reuse the existing pool for RAR.
CriticalSectionStart(&PoolCreateSync.CritSection);
if (GlobalPoolUseCount++ == 0)
GlobalPool=new ThreadPool(MaxPoolThreads);
// We use a simple thread pool, which does not allow to add tasks from
// different functions and threads in the same time. It is ok for RAR,
// but UnRAR.dll can be used in multithreaded environment. So if one of
// threads requests a copy of global pool and another copy is already
// in use, we create and return a new pool instead of existing global.
if (GlobalPoolUseCount > 1)
{
ThreadPool *Pool = new ThreadPool(MaxPoolThreads);
CriticalSectionEnd(&PoolCreateSync.CritSection);
return Pool;
}
CriticalSectionEnd(&PoolCreateSync.CritSection);
return GlobalPool;
#endif
}
@ -79,17 +76,16 @@ void DestroyThreadPool(ThreadPool *Pool)
{
if (Pool!=NULL)
{
#ifdef RARDLL
delete Pool;
#else
CriticalSectionStart(&PoolCreateSync.CritSection);
if (Pool==GlobalPool && GlobalPoolUseCount > 0 && --GlobalPoolUseCount == 0)
delete GlobalPool;
// To correctly work in multithreaded environment UnRAR.dll creates
// new pools if global pool is already in use. We delete such pools here.
if (Pool!=GlobalPool)
delete Pool;
CriticalSectionEnd(&PoolCreateSync.CritSection);
#endif
}
}

@ -236,7 +236,7 @@ void RarTime::GetText(wchar *DateStr,size_t MaxSize,bool FullMS)
else
{
// We use escape before '?' to avoid weird C trigraph characters.
wcscpy(DateStr,L"\?\?\?\?-\?\?-\?\? \?\?:\?\?");
wcsncpyz(DateStr,L"\?\?\?\?-\?\?-\?\? \?\?:\?\?",MaxSize);
}
}
@ -271,7 +271,7 @@ void RarTime::SetIsoText(const wchar *TimeText)
void RarTime::SetAgeText(const wchar *TimeText)
{
uint Seconds=0,Value=0;
for (int I=0;TimeText[I]!=0;I++)
for (uint I=0;TimeText[I]!=0;I++)
{
int Ch=TimeText[I];
if (IsDigit(Ch))

@ -18,7 +18,8 @@ enum UIMESSAGE_CODE {
UIERROR_HEADERBROKEN, UIERROR_MHEADERBROKEN, UIERROR_FHEADERBROKEN,
UIERROR_SUBHEADERBROKEN, UIERROR_SUBHEADERUNKNOWN,
UIERROR_SUBHEADERDATABROKEN, UIERROR_RRDAMAGED, UIERROR_UNKNOWNMETHOD,
UIERROR_UNKNOWNENCMETHOD, UIERROR_RENAMING, UIERROR_NEWERRAR, UIERROR_NOTSFX, UIERROR_OLDTOSFX,
UIERROR_UNKNOWNENCMETHOD, UIERROR_RENAMING, UIERROR_NEWERRAR,
UIERROR_NOTSFX, UIERROR_OLDTOSFX,
UIERROR_WRONGSFXVER, UIERROR_ALREADYENC, UIERROR_DICTOUTMEM,
UIERROR_USESMALLERDICT, UIERROR_MODIFYUNKNOWN, UIERROR_MODIFYOLD,
UIERROR_MODIFYLOCKED, UIERROR_MODIFYVOLUME, UIERROR_NOTVOLUME,
@ -31,12 +32,12 @@ enum UIMESSAGE_CODE {
UIERROR_NOFILESTOADD, UIERROR_NOFILESTODELETE, UIERROR_NOFILESTOEXTRACT,
UIERROR_MISSINGVOL, UIERROR_NEEDPREVVOL, UIERROR_UNKNOWNEXTRA,
UIERROR_CORRUPTEXTRA, UIERROR_NTFSREQUIRED, UIERROR_ZIPVOLSFX,
UIERROR_FILERO, UIERROR_TOOLARGESFX, UIERROR_EMAIL, UIERROR_ACLGET,
UIERROR_ACLBROKEN, UIERROR_ACLUNKNOWN, UIERROR_ACLSET, UIERROR_STREAMBROKEN,
UIERROR_STREAMUNKNOWN, UIERROR_INCOMPATSWITCH, UIERROR_PATHTOOLONG,
UIERROR_DIRSCAN, UIERROR_UOWNERGET, UIERROR_UOWNERBROKEN,
UIERROR_UOWNERGETOWNERID, UIERROR_UOWNERGETGROUPID, UIERROR_UOWNERSET,
UIERROR_ULINKREAD, UIERROR_ULINKEXIST,
UIERROR_FILERO, UIERROR_TOOLARGESFX, UIERROR_NOZIPSFX, UIERROR_EMAIL,
UIERROR_ACLGET, UIERROR_ACLBROKEN, UIERROR_ACLUNKNOWN, UIERROR_ACLSET,
UIERROR_STREAMBROKEN, UIERROR_STREAMUNKNOWN, UIERROR_INCOMPATSWITCH,
UIERROR_PATHTOOLONG, UIERROR_DIRSCAN, UIERROR_UOWNERGET,
UIERROR_UOWNERBROKEN, UIERROR_UOWNERGETOWNERID, UIERROR_UOWNERGETGROUPID,
UIERROR_UOWNERSET, UIERROR_ULINKREAD, UIERROR_ULINKEXIST,
UIMSG_FIRST,
UIMSG_STRING, UIMSG_BUILD, UIMSG_RRSEARCH, UIMSG_ANALYZEFILEDATA,
@ -75,7 +76,7 @@ enum UIASKREP_RESULT {
UIASKREP_RESULT uiAskReplace(wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags);
UIASKREP_RESULT uiAskReplaceEx(RAROptions *Cmd,wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags);
void uiInit(bool Sound);
void uiInit(SOUND_NOTIFY_MODE Sound);
void uiStartArchiveExtract(bool Extract,const wchar *ArcName);
@ -85,6 +86,7 @@ void uiProcessProgress(const char *Command,int64 CurSize,int64 TotalSize);
enum UIPASSWORD_TYPE {UIPASSWORD_GLOBAL,UIPASSWORD_FILE,UIPASSWORD_ARCHIVE};
bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password);
bool uiIsGlobalPasswordSet();
enum UIALARM_TYPE {UIALARM_ERROR, UIALARM_INFO, UIALARM_QUESTION};
void uiAlarm(UIALARM_TYPE Type);
@ -110,6 +112,11 @@ class uiMsgStore
public:
uiMsgStore(UIMESSAGE_CODE Code)
{
// Init arrays in case a caller passes fewer parameters than expected.
for (uint I=0;I<ASIZE(Str);I++)
Str[I]=L"";
memset(Num,0,sizeof(Num));
NumSize=StrSize=0;
this->Code=Code;
}

@ -1,8 +1,8 @@
static bool uiSoundEnabled;
static SOUND_NOTIFY_MODE uiSoundNotify;
void uiInit(bool Sound)
void uiInit(SOUND_NOTIFY_MODE Sound)
{
uiSoundEnabled = Sound;
uiSoundNotify = Sound;
}

@ -18,7 +18,10 @@ UIASKREP_RESULT uiAskReplace(wchar *Name,size_t MaxNameSize,int64 FileSize,RarTi
{
itoa(FileSize,SizeText2,ASIZE(SizeText2));
FileTime->GetText(DateStr2,ASIZE(DateStr2),false);
eprintf(St(MAskReplace),Name,SizeText1,DateStr1,SizeText2,DateStr2);
if ((Flags & UIASKREP_F_EXCHSRCDEST)==0)
eprintf(St(MAskReplace),Name,SizeText1,DateStr1,SizeText2,DateStr2);
else
eprintf(St(MAskReplace),Name,SizeText2,DateStr2,SizeText1,DateStr1);
}
bool AllowRename=(Flags & UIASKREP_F_NORENAME)==0;
@ -186,7 +189,11 @@ void uiMsgStore::Msg()
Log(Str[0],St(MUnknownMeth),Str[1]);
break;
case UIERROR_UNKNOWNENCMETHOD:
Log(Str[0],St(MUnkEncMethod),Str[1]);
{
wchar Msg[256];
swprintf(Msg,ASIZE(Msg),St(MUnkEncMethod),Str[1]);
Log(Str[0],L"%s: %s",Msg,Str[2]);
}
break;
#ifndef SFX_MODULE
case UIERROR_RENAMING:
@ -219,6 +226,7 @@ void uiMsgStore::Msg()
break;
case UIERROR_INVALIDNAME:
Log(Str[0],St(MInvalidName),Str[1]);
mprintf(L"\n"); // Needed when called from CmdExtract::ExtractCurrentFile.
break;
#ifndef SFX_MODULE
case UIERROR_NEWRARFORMAT:
@ -354,9 +362,15 @@ bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Passw
}
bool uiIsGlobalPasswordSet()
{
return false;
}
void uiAlarm(UIALARM_TYPE Type)
{
if (uiSoundEnabled)
if (uiSoundNotify==SOUND_NOTIFY_ON)
{
static clock_t LastTime=-10; // Negative to always beep first time.
if ((MonoClock()-LastTime)/CLOCKS_PER_SEC>5)

@ -39,6 +39,12 @@ bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Passw
}
bool uiIsGlobalPasswordSet()
{
return false;
}
void uiAlarm(UIALARM_TYPE Type)
{
}

@ -70,7 +70,7 @@ bool WideToChar(const wchar *Src,char *Dest,size_t DestSize)
#endif
if (DestSize>0)
Dest[DestSize-1]=0;
// We tried to return the empty string if conversion is failed,
// but it does not work well. WideCharToMultiByte returns 'failed' code
// and partially converted string even if we wanted to convert only a part
@ -138,6 +138,11 @@ bool WideToCharMap(const wchar *Src,char *Dest,size_t DestSize,bool &Success)
if (wcschr(Src,(wchar)MappedStringMark)==NULL)
return false;
// Seems to be that wcrtomb in some memory analyzing libraries
// can produce uninitilized output while reporting success on garbage input.
// So we clean the destination to calm analyzers.
memset(Dest,0,DestSize);
Success=true;
uint SrcPos=0,DestPos=0;
while (Src[SrcPos]!=0 && DestPos<DestSize-MB_CUR_MAX)
@ -173,7 +178,7 @@ bool WideToCharMap(const wchar *Src,char *Dest,size_t DestSize,bool &Success)
#if defined(_UNIX) && defined(MBFUNCTIONS)
// Convert and map inconvertible Unicode characters.
// Convert and map inconvertible Unicode characters.
// We use it for extended ASCII names in Unix.
void CharToWideMap(const char *Src,wchar *Dest,size_t DestSize,bool &Success)
{

@ -11,7 +11,7 @@ void Unpack::Unpack5(bool Solid)
// Check TablesRead5 to be sure that we read tables at least once
// regardless of current block header TablePresent flag.
// So we can safefly use these tables below.
if (!ReadBlockHeader(Inp,BlockHeader) ||
if (!ReadBlockHeader(Inp,BlockHeader) ||
!ReadTables(Inp,BlockHeader,BlockTables) || !TablesRead5)
return;
}
@ -536,11 +536,11 @@ bool Unpack::ReadBlockHeader(BitInput &Inp,UnpackBlockHeader &Header)
if (!UnpReadBuf())
return false;
Inp.faddbits((8-Inp.InBit)&7);
byte BlockFlags=Inp.fgetbits()>>8;
Inp.faddbits(8);
uint ByteCount=((BlockFlags>>3)&3)+1; // Block size byte count.
if (ByteCount==4)
return false;

@ -48,7 +48,7 @@ void FragmentedWindow::Init(size_t WinSize)
}
if (NewMem==NULL)
throw std::bad_alloc();
// Clean the window to generate the same output when unpacking corrupt
// RAR files, which may access to unused areas of sliding dictionary.
memset(NewMem,0,Size);

@ -165,7 +165,7 @@ void Unpack::Unpack5MT(bool Solid)
if (DataLeft<TooSmallToProcess)
break;
}
//#undef USE_THREADS
UnpackThreadDataList UTDArray[MaxPoolThreads];
uint UTDArrayPos=0;
@ -180,7 +180,7 @@ void Unpack::Unpack5MT(bool Solid)
UnpackThreadDataList *UTD=UTDArray+UTDArrayPos++;
UTD->D=UnpThreadData+CurBlock;
UTD->BlockCount=Min(MaxBlockPerThread,BlockNumberMT-CurBlock);
#ifdef USE_THREADS
if (BlockNumber==1)
UnpackDecode(*UTD->D);
@ -200,7 +200,7 @@ void Unpack::Unpack5MT(bool Solid)
#endif
bool IncompleteThread=false;
for (uint Block=0;Block<BlockNumber;Block++)
{
UnpackThreadData *CurData=UnpThreadData+Block;
@ -251,7 +251,7 @@ void Unpack::Unpack5MT(bool Solid)
break;
}
}
if (IncompleteThread || Done)
break; // Current buffer is done, read more data or quit.
else
@ -303,7 +303,7 @@ void Unpack::UnpackDecode(UnpackThreadData &D)
D.DamagedData=true;
return;
}
D.DecodedSize=0;
int BlockBorder=D.BlockHeader.BlockStart+D.BlockHeader.BlockSize-1;
@ -413,7 +413,7 @@ void Unpack::UnpackDecode(UnpackThreadData &D)
{
UnpackFilter Filter;
ReadFilter(D.Inp,Filter);
CurItem->Type=UNPDT_FILTER;
CurItem->Length=Filter.Type;
CurItem->Distance=Filter.BlockStart;
@ -498,7 +498,7 @@ bool Unpack::ProcessDecoded(UnpackThreadData &D)
if (Item->Type==UNPDT_FILTER)
{
UnpackFilter Filter;
Filter.Type=(byte)Item->Length;
Filter.BlockStart=Item->Distance;
@ -534,7 +534,7 @@ bool Unpack::UnpackLargeBlock(UnpackThreadData &D)
D.DamagedData=true;
return false;
}
int BlockBorder=D.BlockHeader.BlockStart+D.BlockHeader.BlockSize-1;
// Reserve enough space even for filter entry.

@ -1,6 +1,6 @@
#define RARVER_MAJOR 5
#define RARVER_MINOR 60
#define RARVER_MINOR 71
#define RARVER_BETA 0
#define RARVER_DAY 24
#define RARVER_MONTH 6
#define RARVER_YEAR 2018
#define RARVER_DAY 28
#define RARVER_MONTH 4
#define RARVER_YEAR 2019

@ -34,7 +34,7 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma
Arc.Close();
wchar NextName[NM];
wcscpy(NextName,Arc.FileName);
wcsncpyz(NextName,Arc.FileName,ASIZE(NextName));
NextVolumeName(NextName,ASIZE(NextName),!Arc.NewNumbering);
#if !defined(SFX_MODULE) && !defined(RARDLL)
@ -67,12 +67,12 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma
// Checking for new style volumes renamed by user to old style
// name format. Some users did it for unknown reason.
wchar AltNextName[NM];
wcscpy(AltNextName,Arc.FileName);
wcsncpyz(AltNextName,Arc.FileName,ASIZE(AltNextName));
NextVolumeName(AltNextName,ASIZE(AltNextName),true);
OldSchemeTested=true;
if (Arc.Open(AltNextName,OpenMode))
{
wcscpy(NextName,AltNextName);
wcsncpyz(NextName,AltNextName,ASIZE(NextName));
break;
}
}
@ -185,7 +185,7 @@ bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize)
if (Cmd->Callback!=NULL)
{
wchar OrgNextName[NM];
wcscpy(OrgNextName,NextName);
wcsncpyz(OrgNextName,NextName,ASIZE(OrgNextName));
if (Cmd->Callback(UCM_CHANGEVOLUMEW,Cmd->UserData,(LPARAM)NextName,RAR_VOL_ASK)==-1)
DllVolAborted=true;
else
@ -195,7 +195,7 @@ bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize)
{
char NextNameA[NM],OrgNextNameA[NM];
WideToChar(NextName,NextNameA,ASIZE(NextNameA));
strcpy(OrgNextNameA,NextNameA);
strncpyz(OrgNextNameA,NextNameA,ASIZE(OrgNextNameA));
if (Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextNameA,RAR_VOL_ASK)==-1)
DllVolAborted=true;
else

@ -54,7 +54,10 @@ void ExtractACL20(Archive &Arc,const wchar *FileName)
if (!SetCode)
{
uiMsg(UIERROR_ACLSET,Arc.FileName,FileName);
DWORD LastError=GetLastError();
ErrHandler.SysErrMsg();
if (LastError==ERROR_ACCESS_DENIED && !IsUserAdmin())
uiMsg(UIERROR_NEEDADMIN);
ErrHandler.SetErrorCode(RARX_WARNING);
}
}
@ -86,7 +89,10 @@ void ExtractACL(Archive &Arc,const wchar *FileName)
if (!SetCode)
{
uiMsg(UIERROR_ACLSET,Arc.FileName,FileName);
DWORD LastError=GetLastError();
ErrHandler.SysErrMsg();
if (LastError==ERROR_ACCESS_DENIED && !IsUserAdmin())
uiMsg(UIERROR_NEEDADMIN);
ErrHandler.SetErrorCode(RARX_WARNING);
}
}

@ -20,11 +20,13 @@ void ExtractStreams20(Archive &Arc,const wchar *FileName)
wchar StreamName[NM+2];
if (FileName[0]!=0 && FileName[1]==0)
{
wcscpy(StreamName,L".\\");
wcscpy(StreamName+2,FileName);
// Convert single character names like f:stream to .\f:stream to
// resolve the ambiguity with drive letters.
wcsncpyz(StreamName,L".\\",ASIZE(StreamName));
wcsncatz(StreamName,FileName,ASIZE(StreamName));
}
else
wcscpy(StreamName,FileName);
wcsncpyz(StreamName,FileName,ASIZE(StreamName));
if (wcslen(StreamName)+strlen(Arc.StreamHead.StreamName)>=ASIZE(StreamName) ||
Arc.StreamHead.StreamName[0]!=':')
{
@ -35,7 +37,7 @@ void ExtractStreams20(Archive &Arc,const wchar *FileName)
wchar StoredName[NM];
CharToWide(Arc.StreamHead.StreamName,StoredName,ASIZE(StoredName));
ConvertPath(StoredName+1,StoredName+1);
ConvertPath(StoredName+1,StoredName+1,ASIZE(StoredName)-1);
wcsncatz(StreamName,StoredName,ASIZE(StreamName));
@ -83,8 +85,10 @@ void ExtractStreams(Archive &Arc,const wchar *FileName,bool TestMode)
wchar FullName[NM+2];
if (FileName[0]!=0 && FileName[1]==0)
{
wcscpy(FullName,L".\\");
wcsncpyz(FullName+2,FileName,ASIZE(FullName)-2);
// Convert single character names like f:stream to .\f:stream to
// resolve the ambiguity with drive letters.
wcsncpyz(FullName,L".\\",ASIZE(FullName));
wcsncatz(FullName,FileName,ASIZE(FullName));
}
else
wcsncpyz(FullName,FileName,ASIZE(FullName));

@ -91,7 +91,7 @@ uint8_t unrar_debug = 0;
/**
* @brief Translate an ERAR_<code> to the appropriate UNRAR_<code>
*
*
* @param errorCode ERAR_<code>
* @return cl_unrar_error_t UNRAR_OK, UNRAR_ENCRYPTED, or UNRAR_ERR.
*/
@ -213,6 +213,7 @@ cl_unrar_error_t unrar_open(const char* filename, void** hArchive, char** commen
}
archiveData->ArcName = (char *)filename;
archiveData->OpenMode = RAR_OM_EXTRACT;
archiveData->OpFlags |= ROADOF_KEEPBROKEN;
archiveData->CmtBuf = (char*)calloc(1, CMTBUFSIZE);
if (archiveData->CmtBuf == NULL) {
unrar_dbgmsg("unrar_open: Not enough memory to allocate main archive header comment buffer.\n");
@ -291,7 +292,7 @@ done:
/**
* @brief Get file metadata from the next file header.
*
*
* @param hArchive Handle to the archive we're extracting.
* @param[in/out] file_metadata Pointer to a pre-allocated metadata structure.
* @return cl_unrar_error_t UNRAR_OK if metadata retrieved, UNRAR_BREAK if no more files, UNRAR_ENCRYPTED if header was encrypted, else maybe UNRAR_EMEM or UNRAR_ERR.
@ -320,7 +321,7 @@ cl_unrar_error_t unrar_peek_file_header(void* hArchive, unrar_metadata_t* file_m
*/
headerData.CmtBuf = NULL;
headerData.CmtBufSize = 0;
headerData.RedirNameSize = 1024 * sizeof(wchar_t);
headerData.RedirName = (wchar_t*)&RedirName;
memset(headerData.RedirName, 0, headerData.RedirNameSize);

Loading…
Cancel
Save