diff -Nru unrar-nonfree-5.2.7/archive.cpp unrar-nonfree-5.3.2/archive.cpp --- unrar-nonfree-5.2.7/archive.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/archive.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -240,13 +240,22 @@ { HEADER_TYPE HeaderType=GetHeaderType(); if (HeaderType==HEAD_SERVICE) + { + // If we have a split service headers, it surely indicates non-first + // volume. But not split service header does not guarantee the first + // volume, because we can have split file after non-split archive + // comment. So we do not quit from loop here. FirstVolume=Volume && !SubHead.SplitBefore; + } else if (HeaderType==HEAD_FILE) { FirstVolume=Volume && !FileHead.SplitBefore; break; } + else + if (HeaderType==HEAD_ENDARC) // Might happen if archive contains only a split service header. + break; SeekToNext(); } CurBlockPos=SaveCurBlockPos; diff -Nru unrar-nonfree-5.2.7/archive.hpp unrar-nonfree-5.3.2/archive.hpp --- unrar-nonfree-5.2.7/archive.hpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/archive.hpp 2015-08-04 10:22:40.000000000 +0000 @@ -61,7 +61,7 @@ public: Archive(RAROptions *InitCmd=NULL); ~Archive(); - RARFORMAT IsSignature(const byte *D,size_t Size); + static RARFORMAT IsSignature(const byte *D,size_t Size); bool IsArchive(bool EnableBroken); size_t SearchBlock(HEADER_TYPE HeaderType); size_t SearchSubBlock(const wchar *Type); diff -Nru unrar-nonfree-5.2.7/arcread.cpp unrar-nonfree-5.3.2/arcread.cpp --- unrar-nonfree-5.2.7/arcread.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/arcread.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -915,7 +915,7 @@ size_t NextPos=size_t(Raw->GetPos()+FieldSize); uint64 FieldType=Raw->GetV(); - FieldSize=Raw->DataLeft(); // Field size without size and type fields. + FieldSize=int64(NextPos-Raw->GetPos()); // Field size without size and type fields. if (bb->HeaderType==HEAD_MAIN) { @@ -982,6 +982,11 @@ sha256_done(&ctx, Digest); hd->UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0; + + // RAR 5.21 and earlier set PswCheck field in service records to 0 + // even if UsePswCheck was present. + if (bb->HeaderType==HEAD_SERVICE && memcmp(hd->PswCheck,"\0\0\0\0\0\0\0\0",SIZE_PSWCHECK)==0) + hd->UsePswCheck=0; } hd->SaltSet=true; hd->CryptMethod=CRYPT_RAR50; @@ -1095,6 +1100,19 @@ break; case FHEXTRA_SUBDATA: { + // RAR 5.21 and earlier set FHEXTRA_SUBDATA size to 1 less than + // required. It did not hurt extraction, because UnRAR 5.21 + // and earlier ignored this field and set FieldSize as data left + // in entire extra area. But now we set the correct field size + // and set FieldSize based on actual extra record size, + // so we need to adjust it for those older archives here. + // FHEXTRA_SUBDATA in those archives always belongs to HEAD_SERVICE + // and always is last in extra area. So since its size is by 1 + // less than needed, we always have 1 byte left in extra area, + // which fact we use here to detect such archives. + if (bb->HeaderType==HEAD_SERVICE && Raw->Size()-NextPos==1) + FieldSize++; + hd->SubData.Alloc((size_t)FieldSize); Raw->GetB(hd->SubData.Addr(0),(size_t)FieldSize); } @@ -1266,6 +1284,11 @@ else hd->FileAttr=0x20; +#ifdef _WIN_ALL + if (hd->HSType==HSYS_UNIX) // Convert Unix, OS X and Android decomposed chracters to Windows precomposed. + ConvertToPrecomposed(hd->FileName,ASIZE(hd->FileName)); +#endif + for (wchar *s=hd->FileName;*s!=0;s++) { #ifdef _UNIX @@ -1344,14 +1367,19 @@ uiMsg(UIERROR_SUBHEADERUNKNOWN,FileName); return false; } - UnpData->Alloc((size_t)SubHead.UnpSize); - SubDataIO.SetUnpackToMemory(&(*UnpData)[0],(uint)SubHead.UnpSize); + if (UnpData==NULL) + SubDataIO.SetTestMode(true); + else + { + UnpData->Alloc((size_t)SubHead.UnpSize); + SubDataIO.SetUnpackToMemory(&(*UnpData)[0],(uint)SubHead.UnpSize); + } } if (SubHead.Encrypted) if (Cmd->Password.IsSet()) SubDataIO.SetEncryption(false,SubHead.CryptMethod,&Cmd->Password, SubHead.SaltSet ? SubHead.Salt:NULL,SubHead.InitV, - SubHead.Lg2Count,SubHead.PswCheck,SubHead.HashKey); + SubHead.Lg2Count,SubHead.HashKey,SubHead.PswCheck); else return false; SubDataIO.UnpHash.Init(SubHead.FileHash.Type,1); diff -Nru unrar-nonfree-5.2.7/cmddata.cpp unrar-nonfree-5.3.2/cmddata.cpp --- unrar-nonfree-5.2.7/cmddata.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/cmddata.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -52,6 +52,7 @@ // In Windows we may prefer to implement our own command line parser // to avoid replacing \" by " in standard parser. Such replacing corrupts // destination paths like "dest path\" in extraction commands. + // Also our own parser is Unicode compatible. const wchar *CmdLine=GetCommandLine(); wchar *Par; @@ -766,6 +767,9 @@ case 'L': FilelistCharset=rch; break; + case 'R': + RedirectCharset=rch; + break; default: BadSwitch(Switch); AlreadyBad=true; @@ -1019,17 +1023,17 @@ // the include list created with -n switch. bool CommandData::ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList) { - if (ExclCheckArgs(&ExclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH)) + if (CheckArgs(&ExclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH)) return true; if (!CheckInclList || InclArgs.ItemsCount()==0) return false; - if (ExclCheckArgs(&InclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH)) + if (CheckArgs(&InclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH)) return false; return true; } -bool CommandData::ExclCheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode) +bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode) { wchar *Name=ConvertPath(CheckName,NULL); wchar FullName[NM]; @@ -1064,9 +1068,9 @@ { // 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. - // When archiving, directory matched by "dirmask\" is excluded - // from further scanning. + // "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) wcscat(CurMask,L"*"); @@ -1090,7 +1094,12 @@ #endif { wchar NewName[NM+2],*CurName=Name; - if (CurMask[0]=='*' && IsPathDiv(CurMask[1])) + + // 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 @@ -1102,7 +1111,7 @@ CurName=NewName; } - if (CmpName(ConvertPath(CurMask,NULL),CurName,MatchMode)) + if (CmpName(CmpMask,CurName,MatchMode)) return true; } } diff -Nru unrar-nonfree-5.2.7/cmddata.hpp unrar-nonfree-5.3.2/cmddata.hpp --- unrar-nonfree-5.2.7/cmddata.hpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/cmddata.hpp 2015-08-04 10:22:40.000000000 +0000 @@ -12,7 +12,6 @@ void ProcessSwitchesString(const wchar *Str); void ProcessSwitch(const wchar *Switch); void BadSwitch(const wchar *Switch); - bool ExclCheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode); uint GetExclAttr(const wchar *Str); bool FileLists; @@ -33,6 +32,7 @@ void OutHelp(RAR_EXIT ExitCode); bool IsSwitch(int Ch); 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 SizeCheck(int64 Size); diff -Nru unrar-nonfree-5.2.7/consio.cpp unrar-nonfree-5.3.2/consio.cpp --- unrar-nonfree-5.2.7/consio.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/consio.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -2,6 +2,8 @@ #include "log.cpp" static MESSAGE_TYPE MsgStream=MSG_STDOUT; +static RAR_CHARSET RedirectCharset=RCH_DEFAULT; + const int MaxMsgSize=2*NM+2048; #ifdef _WIN_ALL @@ -46,9 +48,10 @@ } -void InitConsoleOptions(MESSAGE_TYPE MsgStream) +void InitConsoleOptions(MESSAGE_TYPE MsgStream,RAR_CHARSET RedirectCharset) { ::MsgStream=MsgStream; + ::RedirectCharset=RedirectCharset; } @@ -63,17 +66,23 @@ safebuf wchar Msg[MaxMsgSize]; if (dest==stdout && StdoutRedirected || dest==stderr && StderrRedirected) { - // Avoid Unicode for redirect in Windows, it does not work with pipes. - vswprintf(Msg,ASIZE(Msg),fmtw,arglist); - safebuf char MsgA[MaxMsgSize]; - WideToChar(Msg,MsgA,ASIZE(MsgA)); - CharToOemA(MsgA,MsgA); // Console tools like 'more' expect OEM encoding. - - // We already converted \n to \r\n above, so we use WriteFile instead - // of C library to avoid unnecessary additional conversion. HANDLE hOut=GetStdHandle(dest==stdout ? STD_OUTPUT_HANDLE:STD_ERROR_HANDLE); + vswprintf(Msg,ASIZE(Msg),fmtw,arglist); DWORD Written; - WriteFile(hOut,MsgA,(DWORD)strlen(MsgA),&Written,NULL); + if (RedirectCharset==RCH_UNICODE) + WriteFile(hOut,Msg,(DWORD)wcslen(Msg)*sizeof(*Msg),&Written,NULL); + else + { + // Avoid Unicode for redirect in Windows, it does not work with pipes. + safebuf char MsgA[MaxMsgSize]; + WideToChar(Msg,MsgA,ASIZE(MsgA)); + if (RedirectCharset!=RCH_ANSI) + CharToOemA(MsgA,MsgA); // Console tools like 'more' expect OEM encoding. + + // We already converted \n to \r\n above, so we use WriteFile instead + // of C library to avoid unnecessary additional conversion. + WriteFile(hOut,MsgA,(DWORD)strlen(MsgA),&Written,NULL); + } return; } // MSVC2008 vfwprintf writes every character to console separately diff -Nru unrar-nonfree-5.2.7/consio.hpp unrar-nonfree-5.3.2/consio.hpp --- unrar-nonfree-5.2.7/consio.hpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/consio.hpp 2015-08-04 10:22:40.000000000 +0000 @@ -2,7 +2,7 @@ #define _RAR_CONSIO_ void InitConsole(); -void InitConsoleOptions(MESSAGE_TYPE MsgStream); +void InitConsoleOptions(MESSAGE_TYPE MsgStream,RAR_CHARSET RedirectCharset); void OutComment(const wchar *Comment,size_t Size); #ifndef SILENT diff -Nru unrar-nonfree-5.2.7/debian/changelog unrar-nonfree-5.3.2/debian/changelog --- unrar-nonfree-5.2.7/debian/changelog 2015-03-27 21:54:31.000000000 +0000 +++ unrar-nonfree-5.3.2/debian/changelog 2015-08-10 12:58:20.000000000 +0000 @@ -1,10 +1,8 @@ -unrar-nonfree (1:5.2.7-0.1) unstable; urgency=high +unrar-nonfree (1:5.3.2-1) unstable; urgency=medium - * Non-maintainer upload. - * New upstream release - - Fixes a symlink directory traversal vulnerability (Closes: #774171) + * New upstream release (Closes: #759586) - -- Felix Geyer Fri, 27 Mar 2015 22:44:26 +0100 + -- Martin Meredith Mon, 10 Aug 2015 13:49:14 +0100 unrar-nonfree (1:5.2.5-1) unstable; urgency=medium diff -Nru unrar-nonfree-5.2.7/debian/control unrar-nonfree-5.3.2/debian/control --- unrar-nonfree-5.2.7/debian/control 2015-02-03 13:00:46.000000000 +0000 +++ unrar-nonfree-5.3.2/debian/control 2015-08-10 13:00:10.000000000 +0000 @@ -4,7 +4,7 @@ Maintainer: Martin Meredith Homepage: http://www.rarlabs.com/ Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.16.1~) -Standards-Version: 3.9.5 +Standards-Version: 3.9.6.1 XS-Autobuild: yes Package: unrar diff -Nru unrar-nonfree-5.2.7/dll.cpp unrar-nonfree-5.3.2/dll.cpp --- unrar-nonfree-5.2.7/dll.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/dll.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -74,7 +74,7 @@ delete Data; return NULL; } - if (!Data->Arc.IsArchive(false)) + if (!Data->Arc.IsArchive(true)) { if (Data->Cmd.DllError!=0) r->OpenResult=Data->Cmd.DllError; @@ -271,7 +271,16 @@ D->HashType=RAR_HASH_NONE; break; } - + + D->RedirType=hd->RedirType; + // RedirNameSize sanity check is useful in case some developer + // did not initialize Reserved area with 0 as required in docs. + // We have taken 'Redir*' fields from Reserved area. We may remove + // this RedirNameSize check sometimes later. + if (hd->RedirType!=FSREDIR_NONE && D->RedirName!=NULL && + D->RedirNameSize>0 && D->RedirNameSize<100000) + wcsncpyz(D->RedirName,hd->RedirName,D->RedirNameSize); + D->DirTarget=hd->DirTarget; } catch (RAR_EXIT ErrCode) { diff -Nru unrar-nonfree-5.2.7/dll.hpp unrar-nonfree-5.3.2/dll.hpp --- unrar-nonfree-5.2.7/dll.hpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/dll.hpp 2015-08-04 10:22:40.000000000 +0000 @@ -31,7 +31,7 @@ #define RAR_VOL_ASK 0 #define RAR_VOL_NOTIFY 1 -#define RAR_DLL_VERSION 6 +#define RAR_DLL_VERSION 7 #define RAR_HASH_NONE 0 #define RAR_HASH_CRC32 1 @@ -98,7 +98,11 @@ unsigned int DictSize; unsigned int HashType; char Hash[32]; - unsigned int Reserved[1014]; + unsigned int RedirType; + wchar_t *RedirName; + unsigned int RedirNameSize; + unsigned int DirTarget; + unsigned int Reserved[994]; }; diff -Nru unrar-nonfree-5.2.7/dll.rc unrar-nonfree-5.3.2/dll.rc --- unrar-nonfree-5.2.7/dll.rc 2015-03-04 11:45:30.000000000 +0000 +++ unrar-nonfree-5.3.2/dll.rc 2015-08-04 09:51:02.000000000 +0000 @@ -2,8 +2,8 @@ #include VS_VERSION_INFO VERSIONINFO -FILEVERSION 5, 21, 100, 1510 -PRODUCTVERSION 5, 21, 100, 1510 +FILEVERSION 5, 30, 2, 1679 +PRODUCTVERSION 5, 30, 2, 1679 FILEOS VOS__WINDOWS32 FILETYPE VFT_APP { @@ -14,15 +14,15 @@ VALUE "CompanyName", "Alexander Roshal\0" VALUE "ProductName", "RAR decompression library\0" VALUE "FileDescription", "RAR decompression library\0" - VALUE "FileVersion", "5.21.0\0" - VALUE "ProductVersion", "5.21.0\0" + VALUE "FileVersion", "5.30.2\0" + VALUE "ProductVersion", "5.30.2\0" VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2015\0" VALUE "OriginalFilename", "Unrar.dll\0" } } BLOCK "VarFileInfo" { - VALUE "Translation", 0, 0 + VALUE "Translation", 0x0409, 0x04E4 } } diff -Nru unrar-nonfree-5.2.7/extinfo.cpp unrar-nonfree-5.3.2/extinfo.cpp --- unrar-nonfree-5.2.7/extinfo.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/extinfo.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -20,6 +20,8 @@ #ifndef SFX_MODULE void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *Name) { + if (Cmd->Test) + return; switch(Arc.SubBlockHead.SubType) { #ifdef _UNIX @@ -45,15 +47,15 @@ void SetExtraInfo(CommandData *Cmd,Archive &Arc,wchar *Name) { #ifdef _UNIX - if (Cmd->ProcessOwners && Arc.Format==RARFMT15 && + if (!Cmd->Test && Cmd->ProcessOwners && Arc.Format==RARFMT15 && Arc.SubHead.CmpName(SUBHEAD_TYPE_UOWNER)) ExtractUnixOwner30(Arc,Name); #endif #ifdef _WIN_ALL - if (Cmd->ProcessOwners && Arc.SubHead.CmpName(SUBHEAD_TYPE_ACL)) + if (!Cmd->Test && Cmd->ProcessOwners && Arc.SubHead.CmpName(SUBHEAD_TYPE_ACL)) ExtractACL(Arc,Name); if (Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM)) - ExtractStreams(Arc,Name); + ExtractStreams(Arc,Name,Cmd->Test); #endif } diff -Nru unrar-nonfree-5.2.7/extract.cpp unrar-nonfree-5.3.2/extract.cpp --- unrar-nonfree-5.2.7/extract.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/extract.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -89,7 +89,7 @@ DataIO.UnpVolume=false; - PrevExtracted=false; + PrevProcessed=false; AllMatchesExact=true; ReconstructDone=false; AnySolidDataUnpackedWell=false; @@ -228,10 +228,10 @@ if (HeaderType!=HEAD_FILE) { #ifndef SFX_MODULE - if (HeaderType==HEAD3_OLDSERVICE && PrevExtracted) + if (HeaderType==HEAD3_OLDSERVICE && PrevProcessed) SetExtraInfo20(Cmd,Arc,DestFileName); #endif - if (HeaderType==HEAD_SERVICE && PrevExtracted) + if (HeaderType==HEAD_SERVICE && PrevProcessed) SetExtraInfo(Cmd,Arc,DestFileName); if (HeaderType==HEAD_ENDARC) if (Arc.EndArcHead.NextVolume) @@ -251,7 +251,7 @@ Arc.SeekToNext(); return true; } - PrevExtracted=false; + PrevProcessed=false; if (!Cmd->Recurse && MatchedArgs>=Cmd->FileArgs.ItemsCount() && AllMatchesExact) return false; @@ -472,6 +472,11 @@ } if (ExtrFile) { + // Set it in test mode, so we also test subheaders such as NTFS streams + // after tested file. + if (Cmd->Test) + PrevProcessed=true; + bool TestMode=Cmd->Test || SkipSolid; // Unpack to memory, not to disk. if (!SkipSolid) @@ -517,7 +522,7 @@ DataIO.SetEncryption(false,Arc.FileHead.CryptMethod,&FilePassword, Arc.FileHead.SaltSet ? Arc.FileHead.Salt:NULL, Arc.FileHead.InitV,Arc.FileHead.Lg2Count, - PswCheck,Arc.FileHead.HashKey); + Arc.FileHead.HashKey,PswCheck); bool WrongPassword=false; // If header is damaged, we cannot rely on password check value, @@ -596,7 +601,7 @@ // but not when testing an archive. ShowChecksum=false; } - PrevExtracted=FileCreateMode && LinkSuccess; + PrevProcessed=FileCreateMode && LinkSuccess; } else if (!Arc.FileHead.SplitBefore && !WrongPassword) @@ -712,7 +717,7 @@ if (!Cmd->IgnoreGeneralAttr && !SetFileAttr(CurFile.FileName,Arc.FileHead.FileAttr)) uiMsg(UIERROR_FILEATTR,Arc.FileName,CurFile.FileName); - PrevExtracted=true; + PrevProcessed=true; } } } @@ -785,12 +790,17 @@ { wcsncpyz(DestName,Cmd->ExtrPath,DestSize); - // We need IsPathDiv check here to correctly handle Unix forward slash - // in the end of destination path in Windows: rar x arc dest/ - if (*Cmd->ExtrPath!=0 && !IsPathDiv(*PointToLastChar(Cmd->ExtrPath))) + if (*Cmd->ExtrPath!=0) { - // Destination path can be without trailing slash if it come from GUI shell. - AddEndSlash(DestName,DestSize); + wchar LastChar=*PointToLastChar(Cmd->ExtrPath); + // We need IsPathDiv check here to correctly handle Unix forward slash + // in the end of destination path in Windows: rar x arc dest/ + // IsDriveDiv is needed for current drive dir: rar x arc d: + if (!IsPathDiv(LastChar) && !IsDriveDiv(LastChar)) + { + // Destination path can be without trailing slash if it come from GUI shell. + AddEndSlash(DestName,DestSize); + } } #ifndef SFX_MODULE @@ -990,14 +1000,14 @@ mprintf(St(MCreatDir),DestFileName); mprintf(L" %s",St(MOk)); #endif - PrevExtracted=true; + PrevProcessed=true; } else if (DirExist) { if (!Cmd->IgnoreGeneralAttr) SetFileAttr(DestFileName,Arc.FileHead.FileAttr); - PrevExtracted=true; + PrevProcessed=true; } else { @@ -1008,7 +1018,7 @@ #endif ErrHandler.SetErrorCode(RARX_CREATE); } - if (PrevExtracted) + if (PrevProcessed) { #if defined(_WIN_ALL) && !defined(SFX_MODULE) if (Cmd->SetCompressedAttr && diff -Nru unrar-nonfree-5.2.7/extract.hpp unrar-nonfree-5.3.2/extract.hpp --- unrar-nonfree-5.2.7/extract.hpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/extract.hpp 2015-08-04 10:22:40.000000000 +0000 @@ -44,7 +44,7 @@ wchar ArcName[NM]; bool PasswordAll; - bool PrevExtracted; + bool PrevProcessed; // If previous file was successfully extracted or tested. wchar DestFileName[NM]; bool PasswordCancelled; #if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT) diff -Nru unrar-nonfree-5.2.7/filcreat.cpp unrar-nonfree-5.3.2/filcreat.cpp --- unrar-nonfree-5.2.7/filcreat.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/filcreat.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -67,9 +67,9 @@ uint NamePrefixLength=Ext-Name; wcsncpy(NewName,Name,NamePrefixLength); wcscpy(NewName+NamePrefixLength,L"("); - itoa(FileVer,NewName+NamePrefixLength+1); - wcscat(NewName,L")"); - wcscat(NewName,Ext); + itoa(FileVer,NewName+NamePrefixLength+1,ASIZE(NewName)-NamePrefixLength-1); + wcsncatz(NewName,L")",ASIZE(NewName)); + wcsncatz(NewName,Ext,ASIZE(NewName)); #else swprintf(NewName,ASIZE(NewName),L"%.*ls(%u)%ls",uint(Ext-Name),Name,FileVer,Ext); #endif diff -Nru unrar-nonfree-5.2.7/file.cpp unrar-nonfree-5.3.2/file.cpp --- unrar-nonfree-5.2.7/file.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/file.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -121,6 +121,12 @@ hNewFile=fdopen(handle,UpdateMode ? UPDATEBINARY:READBINARY); #endif } +#ifdef _ANDROID + // If we open an existing file in r&w mode and external card is read-only + // for usual file API. + if (hNewFile==FILE_BAD_HANDLE && UpdateMode && errno!=ENOENT) + hNewFile=JniOpenFile(Name); +#endif if (hNewFile==FILE_BAD_HANDLE && errno==ENOENT) ErrorType=FILE_NOTFOUND; #endif @@ -193,6 +199,8 @@ #ifdef _ANDROID if (hFile==FILE_BAD_HANDLE) hFile=JniCreateFile(Name); // If external card is read-only for usual file API. + if (hFile!=FILE_BAD_HANDLE) + JniFileNotify(Name,false); #endif #else hFile=fopen(NameA,WriteMode ? WRITEBINARY:CREATEBINARY); diff -Nru unrar-nonfree-5.2.7/filefn.cpp unrar-nonfree-5.3.2/filefn.cpp --- unrar-nonfree-5.2.7/filefn.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/filefn.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -32,6 +32,8 @@ #ifdef _ANDROID if (ErrCode==-1 && errno!=ENOENT) ErrCode=JniMkdir(Name) ? 0 : -1; // If external card is read-only for usual file API. + if (ErrCode!=-1) + JniFileNotify(Name,false); #endif if (ErrCode==-1) return errno==ENOENT ? MKDIR_BADPATH:MKDIR_ERROR; @@ -420,6 +422,11 @@ #ifdef _ANDROID if (!Success) Success=JniRename(SrcName,DestName); // If external card is read-only for usual file API. + if (Success) + { + JniFileNotify(SrcName,true); + JniFileNotify(DestName,false); + } #endif return Success; #endif @@ -444,6 +451,8 @@ #ifdef _ANDROID if (!Success) Success=JniDelete(Name); + if (Success) + JniFileNotify(Name,true); #endif return Success; #endif diff -Nru unrar-nonfree-5.2.7/isnt.cpp unrar-nonfree-5.3.2/isnt.cpp --- unrar-nonfree-5.2.7/isnt.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/isnt.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -19,6 +19,6 @@ Result=dwMajorVersion*0x100+dwMinorVersion; - return(Result); + return Result; } #endif diff -Nru unrar-nonfree-5.2.7/list.cpp unrar-nonfree-5.3.2/list.cpp --- unrar-nonfree-5.2.7/list.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/list.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -117,22 +117,22 @@ if (TitleShown) { wchar UnpSizeText[20]; - itoa(TotalUnpSize,UnpSizeText); + itoa(TotalUnpSize,UnpSizeText,ASIZE(UnpSizeText)); wchar PackSizeText[20]; - itoa(TotalPackSize,PackSizeText); + itoa(TotalPackSize,PackSizeText,ASIZE(PackSizeText)); if (Verbose) { - mprintf(L"\n----------- --------- -------- ----- -------- ----- -------- ----"); - mprintf(L"\n%21ls %9ls %3d%% %-25ls %u",UnpSizeText, + mprintf(L"\n----------- --------- -------- ----- ---------- ----- -------- ----"); + mprintf(L"\n%21ls %9ls %3d%% %-27ls %u",UnpSizeText, PackSizeText,ToPercentUnlim(TotalPackSize,TotalUnpSize), VolNumText,FileCount); } else { - mprintf(L"\n----------- --------- -------- ----- ----"); - mprintf(L"\n%21ls %-14ls %u",UnpSizeText,VolNumText,FileCount); + mprintf(L"\n----------- --------- ---------- ----- ----"); + mprintf(L"\n%21ls %-16ls %u",UnpSizeText,VolNumText,FileCount); } SumFileCount+=FileCount; @@ -172,14 +172,14 @@ if (ArcCount>1 && !Bare && !Technical) { wchar UnpSizeText[20],PackSizeText[20]; - itoa(SumUnpSize,UnpSizeText); - itoa(SumPackSize,PackSizeText); + itoa(SumUnpSize,UnpSizeText,ASIZE(UnpSizeText)); + itoa(SumPackSize,PackSizeText,ASIZE(PackSizeText)); if (Verbose) - mprintf(L"%21ls %9ls %3d%% %26ls %u",UnpSizeText,PackSizeText, + mprintf(L"%21ls %9ls %3d%% %28ls %u",UnpSizeText,PackSizeText, ToPercentUnlim(SumPackSize,SumUnpSize),L"",SumFileCount); else - mprintf(L"%21ls %16s %lu",UnpSizeText,L"",SumFileCount); + mprintf(L"%21ls %18s %lu",UnpSizeText,L"",SumFileCount); } } @@ -205,12 +205,12 @@ if (Verbose) { mprintf(L"\n%ls",St(MListTitleV)); - mprintf(L"\n----------- --------- -------- ----- -------- ----- -------- ----"); + mprintf(L"\n----------- --------- -------- ----- ---------- ----- -------- ----"); } else { mprintf(L"\n%ls",St(MListTitleL)); - mprintf(L"\n----------- --------- -------- ----- ----"); + mprintf(L"\n----------- --------- ---------- ----- ----"); } TitleShown=true; } @@ -219,8 +219,8 @@ if (hd.UnpSize==INT64NDF) wcscpy(UnpSizeText,L"?"); else - itoa(hd.UnpSize,UnpSizeText); - itoa(hd.PackSize,PackSizeText); + itoa(hd.UnpSize,UnpSizeText,ASIZE(UnpSizeText)); + itoa(hd.PackSize,PackSizeText,ASIZE(PackSizeText)); wchar AttrStr[30]; if (hd.HeaderType==HEAD_SERVICE) @@ -242,7 +242,7 @@ swprintf(RatioStr,ASIZE(RatioStr),L"%d%%",ToPercentUnlim(hd.PackSize,hd.UnpSize)); wchar DateStr[50]; - hd.mtime.GetText(DateStr,ASIZE(DateStr),Technical,Technical); + hd.mtime.GetText(DateStr,ASIZE(DateStr),Technical); if (Technical) { @@ -309,12 +309,12 @@ mprintf(L"\n%12ls: %ls",St(MListMtime),DateStr); if (hd.ctime.IsSet()) { - hd.ctime.GetText(DateStr,ASIZE(DateStr),true,true); + hd.ctime.GetText(DateStr,ASIZE(DateStr),true); mprintf(L"\n%12ls: %ls",St(MListCtime),DateStr); } if (hd.atime.IsSet()) { - hd.atime.GetText(DateStr,ASIZE(DateStr),true,true); + hd.atime.GetText(DateStr,ASIZE(DateStr),true); mprintf(L"\n%12ls: %ls",St(MListAtime),DateStr); } mprintf(L"\n%12ls: %ls",St(MListAttr),AttrStr); @@ -435,13 +435,13 @@ { case HSYS_WINDOWS: swprintf(AttrStr,AttrSize,L"%c%c%c%c%c%c%c", - (A & 0x2000) ? 'I' : '.', // Not content indexed. - (A & 0x0800) ? 'C' : '.', // Compressed. - (A & 0x0020) ? 'A' : '.', // Archive. - (A & 0x0010) ? 'D' : '.', // Directory. - (A & 0x0004) ? 'S' : '.', // System. - (A & 0x0002) ? 'H' : '.', // Hidden. - (A & 0x0001) ? 'R' : '.'); // Read-only. + (A & 0x2000)!=0 ? 'I' : '.', // Not content indexed. + (A & 0x0800)!=0 ? 'C' : '.', // Compressed. + (A & 0x0020)!=0 ? 'A' : '.', // Archive. + (A & 0x0010)!=0 ? 'D' : '.', // Directory. + (A & 0x0004)!=0 ? 'S' : '.', // System. + (A & 0x0002)!=0 ? 'H' : '.', // Hidden. + (A & 0x0001)!=0 ? 'R' : '.'); // Read-only. break; case HSYS_UNIX: switch (A & 0xF000) @@ -459,13 +459,13 @@ swprintf(AttrStr+1,AttrSize-1,L"%c%c%c%c%c%c%c%c%c", (A & 0x0100) ? 'r' : '-', (A & 0x0080) ? 'w' : '-', - (A & 0x0040) ? ((A & 0x0800) ? 's':'x'):((A & 0x0800) ? 'S':'-'), + (A & 0x0040) ? ((A & 0x0800)!=0 ? 's':'x'):((A & 0x0800)!=0 ? 'S':'-'), (A & 0x0020) ? 'r' : '-', (A & 0x0010) ? 'w' : '-', - (A & 0x0008) ? ((A & 0x0400) ? 's':'x'):((A & 0x0400) ? 'S':'-'), + (A & 0x0008) ? ((A & 0x0400)!=0 ? 's':'x'):((A & 0x0400)!=0 ? 'S':'-'), (A & 0x0004) ? 'r' : '-', (A & 0x0002) ? 'w' : '-', - (A & 0x0001) ? 'x' : '-'); + (A & 0x0001) ? ((A & 0x200)!=0 ? 't' : 'x') : '-'); break; case HSYS_UNKNOWN: wcscpy(AttrStr,L"?"); diff -Nru unrar-nonfree-5.2.7/loclang.hpp unrar-nonfree-5.3.2/loclang.hpp --- unrar-nonfree-5.2.7/loclang.hpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/loclang.hpp 2015-08-04 10:22:40.000000000 +0000 @@ -237,7 +237,7 @@ #define MDeleting L"\nDeleting %s" #define MEraseArc L"\nErasing empty archive %s" #define MNoDelFiles L"\nNo files to delete" -#define MLogTitle L"\n\n-------- %2d %s %d, archive %s\n" +#define MLogTitle L"-------- %2d %s %d, archive %s" #define MPathTooLong L"\nERROR: Path too long\n" #define MListArchive L"Archive" #define MListDetails L"Details" @@ -248,8 +248,8 @@ #define MListLock L"lock" #define MListEnc L"encrypted" #define MListEncHead L"encrypted headers" -#define MListTitleL L" Attributes Size Date Time Name" -#define MListTitleV L" Attributes Size Packed Ratio Date Time Checksum Name" +#define MListTitleL L" Attributes Size Date Time Name" +#define MListTitleV L" Attributes Size Packed Ratio Date Time Checksum Name" #define MListName L"Name" #define MListType L"Type" #define MListFile L"File" @@ -258,7 +258,7 @@ #define MListWSymlink L"Windows symbolic link" #define MListJunction L"NTFS junction point" #define MListHardlink L"Hard link" -#define MListCopy L"File copy" +#define MListCopy L"File reference" #define MListStream L"NTFS alternate data stream" #define MListTarget L"Target" #define MListSize L"Size" @@ -375,7 +375,7 @@ #define MNumFound L"%d found." #define MUnknownExtra L"\nUnknown extra field in %s." #define MCopyError L"\nCannot copy %s to %s." -#define MCopyErrorHint L"\nYou need to unpack the entire archive to create file copy entries." +#define MCopyErrorHint L"\nYou need to unpack the entire archive to create file reference entries." #define MCopyingData L"\nCopying data" #define MErrCreateLnkS L"\nCannot create symbolic link %s" #define MErrCreateLnkH L"\nCannot create hard link %s" diff -Nru unrar-nonfree-5.2.7/options.hpp unrar-nonfree-5.3.2/options.hpp --- unrar-nonfree-5.2.7/options.hpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/options.hpp 2015-08-04 10:22:40.000000000 +0000 @@ -95,6 +95,7 @@ RAR_CHARSET CommentCharset; RAR_CHARSET FilelistCharset; RAR_CHARSET ErrlogCharset; + RAR_CHARSET RedirectCharset; wchar ArcPath[NM]; SecPassword Password; diff -Nru unrar-nonfree-5.2.7/pathfn.cpp unrar-nonfree-5.3.2/pathfn.cpp --- unrar-nonfree-5.2.7/pathfn.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/pathfn.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -144,9 +144,16 @@ } +bool IsDriveLetter(const wchar *Path) +{ + wchar Letter=etoupperw(Path[0]); + return Letter>='A' && Letter<='Z' && IsDriveDiv(Path[1]); +} + + int GetPathDisk(const wchar *Path) { - if (IsDiskLetter(Path)) + if (IsDriveLetter(Path)) return etoupperw(*Path)-'A'; else return -1; @@ -534,7 +541,7 @@ return true; */ #if defined(_WIN_ALL) || defined(_EMX) - return Path[0]=='\\' && Path[1]=='\\' || IsDiskLetter(Path) && IsPathDiv(Path[2]); + return Path[0]=='\\' && Path[1]=='\\' || IsDriveLetter(Path) && IsPathDiv(Path[2]); #else return IsPathDiv(Path[0]); #endif @@ -547,17 +554,10 @@ } -bool IsDiskLetter(const wchar *Path) -{ - wchar Letter=etoupperw(Path[0]); - return Letter>='A' && Letter<='Z' && IsDriveDiv(Path[1]); -} - - void GetPathRoot(const wchar *Path,wchar *Root,size_t MaxSize) { *Root=0; - if (IsDiskLetter(Path)) + if (IsDriveLetter(Path)) swprintf(Root,MaxSize,L"%c:\\",*Path); else if (Path[0]=='\\' && Path[1]=='\\') @@ -887,11 +887,11 @@ return false; const wchar *Prefix=L"\\\\?\\"; const size_t PrefixLength=4; - bool FullPath=IsDiskLetter(Src) && IsPathDiv(Src[2]); + bool FullPath=IsDriveLetter(Src) && IsPathDiv(Src[2]); size_t SrcLength=wcslen(Src); if (IsFullPath(Src)) // Paths in d:\path\name format. { - if (IsDiskLetter(Src)) + if (IsDriveLetter(Src)) { if (MaxSize<=PrefixLength+SrcLength) return false; @@ -945,4 +945,17 @@ } return false; } + + +// Convert Unix, OS X and Android decomposed chracters to Windows precomposed. +void ConvertToPrecomposed(wchar *Name,size_t NameSize) +{ + wchar FileName[NM]; + if (WinNT()>=WNT_VISTA && // MAP_PRECOMPOSED is not supported in XP. + FoldString(MAP_PRECOMPOSED,Name,-1,FileName,ASIZE(FileName))!=0) + { + FileName[ASIZE(FileName)-1]=0; + wcsncpyz(Name,FileName,NameSize); + } +} #endif diff -Nru unrar-nonfree-5.2.7/pathfn.hpp unrar-nonfree-5.3.2/pathfn.hpp --- unrar-nonfree-5.2.7/pathfn.hpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/pathfn.hpp 2015-08-04 10:22:40.000000000 +0000 @@ -12,6 +12,7 @@ bool IsWildcard(const wchar *Str); bool IsPathDiv(int Ch); bool IsDriveDiv(int Ch); +bool IsDriveLetter(const wchar *Path); int GetPathDisk(const wchar *Path); void AddEndSlash(wchar *Path,size_t MaxLength); void MakeName(const wchar *Path,const wchar *Name,wchar *Pathname,size_t MaxSize); @@ -57,7 +58,6 @@ void ConvertNameToFull(const wchar *Src,wchar *Dest,size_t MaxSize); bool IsFullPath(const wchar *Path); bool IsFullRootPath(const wchar *Path); -bool IsDiskLetter(const wchar *Path); void GetPathRoot(const wchar *Path,wchar *Root,size_t MaxSize); int ParseVersionFileName(wchar *Name,bool Truncate); wchar* VolNameToFirstName(const wchar *VolName,wchar *FirstName,size_t MaxSize,bool NewNumbering); @@ -69,6 +69,7 @@ #ifdef _WIN_ALL bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize); +void ConvertToPrecomposed(wchar *Name,size_t NameSize); #endif #endif diff -Nru unrar-nonfree-5.2.7/rar.cpp unrar-nonfree-5.3.2/rar.cpp --- unrar-nonfree-5.2.7/rar.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/rar.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -55,6 +55,7 @@ } Cmd->AddArcName(ModuleName); Cmd->ParseDone(); + Cmd->AbsoluteLinks=true; // If users runs SFX, he trusts an archive source. #else // !SFX_MODULE Cmd->ParseCommandLine(true,argc,argv); if (!Cmd->ConfigDisabled) @@ -70,7 +71,7 @@ #endif uiInit(Cmd->Sound); - InitConsoleOptions(Cmd->MsgStream); + InitConsoleOptions(Cmd->MsgStream,Cmd->RedirectCharset); InitLogOptions(Cmd->LogName,Cmd->ErrlogCharset); ErrHandler.SetSilent(Cmd->AllYes || Cmd->MsgStream==MSG_NULL); ErrHandler.SetShutdown(Cmd->Shutdown); diff -Nru unrar-nonfree-5.2.7/rdwrfn.cpp unrar-nonfree-5.3.2/rdwrfn.cpp --- unrar-nonfree-5.2.7/rdwrfn.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/rdwrfn.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -269,7 +269,7 @@ void ComprDataIO::SetEncryption(bool Encrypt,CRYPT_METHOD Method, SecPassword *Password,const byte *Salt,const byte *InitV, - uint Lg2Cnt,byte *PswCheck,byte *HashKey) + uint Lg2Cnt,byte *HashKey,byte *PswCheck) { #ifndef RAR_NOCRYPT if (Encrypt) diff -Nru unrar-nonfree-5.2.7/rdwrfn.hpp unrar-nonfree-5.3.2/rdwrfn.hpp --- unrar-nonfree-5.2.7/rdwrfn.hpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/rdwrfn.hpp 2015-08-04 10:22:40.000000000 +0000 @@ -61,7 +61,7 @@ void SetCommand(CmdAdd *Cmd) {Command=Cmd;} void SetSubHeader(FileHeader *hd,int64 *Pos) {SubHead=hd;SubHeadPos=Pos;} void SetEncryption(bool Encrypt,CRYPT_METHOD Method,SecPassword *Password, - const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *PswCheck,byte *HashKey); + const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck); void SetAV15Encryption(); void SetCmt13Encryption(); void SetUnpackToMemory(byte *Addr,uint Size); diff -Nru unrar-nonfree-5.2.7/scantree.cpp unrar-nonfree-5.3.2/scantree.cpp --- unrar-nonfree-5.2.7/scantree.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/scantree.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -27,11 +27,14 @@ } -SCAN_CODE ScanTree::GetNext(FindData *FindData) +SCAN_CODE ScanTree::GetNext(FindData *FD) { if (Depth<0) return SCAN_DONE; +#ifndef SILENT + uint LoopCount=0; +#endif SCAN_CODE FindCode; while (1) @@ -39,8 +42,15 @@ if (*CurMask==0 && !GetNextMask()) return SCAN_DONE; +#ifndef SILENT + // Let's return some ticks to system or WinRAR can become irresponsible + // while scanning files in command like "winrar a -r arc c:\file.ext". + // Also we reset system sleep timer here. + if ((++LoopCount & 0x3ff)==0) + Wait(); +#endif - FindCode=FindProc(FindData); + FindCode=FindProc(FD); if (FindCode==SCAN_ERROR) { Errors++; @@ -48,21 +58,85 @@ } if (FindCode==SCAN_NEXT) continue; - if (FindCode==SCAN_SUCCESS && FindData->IsDir && GetDirs==SCAN_SKIPDIRS) + if (FindCode==SCAN_SUCCESS && FD->IsDir && GetDirs==SCAN_SKIPDIRS) continue; if (FindCode==SCAN_DONE && GetNextMask()) continue; + if (FilterList.ItemsCount()>0 && FindCode==SCAN_SUCCESS) + if (!CommandData::CheckArgs(&FilterList,FD->IsDir,FD->Name,false,MATCH_WILDSUBPATH)) + continue; break; } - return(FindCode); + return FindCode; } -bool ScanTree::GetNextMask() +// For masks like dir1\dir2*\file.ext this function sets 'dir1' recursive mask +// and '*\dir2*\file.ext' filter. Masks without folder wildcards are +// returned as is. +bool ScanTree::GetFilteredMask() { + FilterList.Reset(); if (!FileMasks->GetString(CurMask,ASIZE(CurMask))) return false; - CurMask[ASIZE(CurMask)-1]=0; + + // Check if folder wildcards present. + bool WildcardFound=false,FolderWildcardFound=false; + uint SlashPos=0; + for (int I=0;CurMask[I]!=0;I++) + { + if (CurMask[I]=='?' || CurMask[I]=='*') + WildcardFound=true; + if (IsPathDiv(CurMask[I]) || IsDriveDiv(CurMask[I])) + { + if (WildcardFound) + { + FolderWildcardFound=true; + break; + } + SlashPos=I; + } + } + if (!FolderWildcardFound) + return true; + + wchar Filter[NM]; + // Convert path\dir*\ to *\dir filter to search for 'dir' in all 'path' subfolders. + wcscpy(Filter,L"*"); + 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; + wcsncatz(Filter,WildName,ASIZE(Filter)); + + // Treat dir*\* or dir*\*.* as dir\, so empty 'dir' is also matched + // by such mask. Skipping empty dir with dir*\*.* confused some users. + wchar *LastMask=PointToName(Filter); + if (wcscmp(LastMask,L"*")==0 || wcscmp(LastMask,L"*.*")==0) + *LastMask=0; + + FilterList.AddString(Filter); + + bool RelativeDrive=IsDriveDiv(CurMask[SlashPos]); + if (RelativeDrive) + SlashPos++; // Use "d:" instead of "d" for d:* mask. + + CurMask[SlashPos]=0; + + if (!RelativeDrive) // Keep d: mask as is, not convert to d:\* + { + // We need to append "\*" both for -ep1 to work correctly and to + // convert d:\* masks previously truncated to d: back to original form. + AddEndSlash(CurMask,ASIZE(CurMask)); + wcsncatz(CurMask,MASKALL,ASIZE(CurMask)); + } + return true; +} + + +bool ScanTree::GetNextMask() +{ + if (!GetFilteredMask()) + return false; #ifdef _WIN_ALL UnixSlashToDos(CurMask,CurMask,ASIZE(CurMask)); #endif @@ -70,7 +144,7 @@ // We wish to scan entire disk if mask like c:\ is specified // regardless of recursion mode. Use c:\*.* mask when need to scan only // the root directory. - ScanEntireDisk=IsDiskLetter(CurMask) && IsPathDiv(CurMask[2]) && CurMask[3]==0; + ScanEntireDisk=IsDriveLetter(CurMask) && IsPathDiv(CurMask[2]) && CurMask[3]==0; wchar *Name=PointToName(CurMask); if (*Name==0) @@ -113,6 +187,7 @@ // We do not use "*" for directories at any level or for files // at top level in recursion mode. bool SearchAll=!IsDir && (Depth>0 || Recurse==RECURSE_ALWAYS || + FilterList.ItemsCount()>0 || Wildcards && Recurse==RECURSE_WILDCARDS || ScanEntireDisk && Recurse!=RECURSE_DISABLE); if (Depth==0) diff -Nru unrar-nonfree-5.2.7/scantree.hpp unrar-nonfree-5.3.2/scantree.hpp --- unrar-nonfree-5.2.7/scantree.hpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/scantree.hpp 2015-08-04 10:22:40.000000000 +0000 @@ -18,6 +18,7 @@ class ScanTree { private: + bool GetFilteredMask(); bool GetNextMask(); SCAN_CODE FindProc(FindData *FD); void ScanError(bool &Error); @@ -38,6 +39,7 @@ wchar CurMask[NM]; wchar OrigCurMask[NM]; + StringList FilterList; bool SearchAllInRoot; size_t SpecPathLength; diff -Nru unrar-nonfree-5.2.7/strfn.cpp unrar-nonfree-5.3.2/strfn.cpp --- unrar-nonfree-5.2.7/strfn.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/strfn.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -285,13 +285,15 @@ } -void itoa(int64 n,char *Str) +void itoa(int64 n,char *Str,size_t MaxSize) { char NumStr[50]; size_t Pos=0; do { + if (Pos+1>=MaxSize) + break; NumStr[Pos++]=char(n%10)+'0'; n=n/10; } while (n!=0); @@ -302,13 +304,15 @@ } -void itoa(int64 n,wchar *Str) +void itoa(int64 n,wchar *Str,size_t MaxSize) { wchar NumStr[50]; size_t Pos=0; do { + if (Pos+1>=MaxSize) + break; NumStr[Pos++]=wchar(n%10)+'0'; n=n/10; } while (n!=0); diff -Nru unrar-nonfree-5.2.7/strfn.hpp unrar-nonfree-5.3.2/strfn.hpp --- unrar-nonfree-5.2.7/strfn.hpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/strfn.hpp 2015-08-04 10:22:40.000000000 +0000 @@ -34,8 +34,8 @@ int wcsicompc(const wchar *Str1,const wchar *Str2); -void itoa(int64 n,char *Str); -void itoa(int64 n,wchar *Str); +void itoa(int64 n,char *Str,size_t MaxSize); +void itoa(int64 n,wchar *Str,size_t MaxSize); const wchar* GetWide(const char *Src); const wchar* GetCmdParam(const wchar *CmdLine,wchar *Param,size_t MaxSize); #ifndef SILENT diff -Nru unrar-nonfree-5.2.7/system.cpp unrar-nonfree-5.3.2/system.cpp --- unrar-nonfree-5.2.7/system.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/system.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -21,6 +21,10 @@ { PriorityClass=IDLE_PRIORITY_CLASS; PriorityLevel=THREAD_PRIORITY_IDLE; + +// Background mode for Vista, can be slow for many small files. +// if (WinNT()>=WNT_VISTA) +// SetPriorityClass(GetCurrentProcess(),PROCESS_MODE_BACKGROUND_BEGIN); } else if (Priority<7) @@ -58,15 +62,29 @@ ThreadPool::SetPriority(PriorityLevel); #endif -// Background mode for Vista, too slow for real life use. -// if (WinNT()>=WNT_VISTA && Priority==1) -// SetPriorityClass(GetCurrentProcess(),PROCESS_MODE_BACKGROUND_BEGIN); - #endif } #endif +// Monotonic clock. Like clock(), returns time passed in CLOCKS_PER_SEC items. +// In Android 5+ and Unix usual clock() returns time spent by all threads +// together, so we cannot use it to measure time intervals anymore. +clock_t MonoClock() +{ +#if defined(_ANDROID) && defined(_UNIX) && defined(CLOCK_MONOTONIC) + struct timespec CurTime; + clock_gettime(CLOCK_MONOTONIC, &CurTime); + int64 nsec = int64(CurTime.tv_sec)*1000000000 + CurTime.tv_nsec; + nsec /= 1000000000 / CLOCKS_PER_SEC; + return (clock_t)nsec; +#else + return clock(); +#endif +} + + + #ifndef SETUP void Wait() { @@ -74,7 +92,18 @@ ErrHandler.Exit(RARX_USERBREAK); #if defined(_WIN_ALL) && !defined(SFX_MODULE) if (SleepTime!=0) - Sleep(SleepTime); + { + static clock_t LastTime=MonoClock(); + if (MonoClock()-LastTime>10*CLOCKS_PER_SEC/1000) + { + Sleep(SleepTime); + LastTime=MonoClock(); + } + } +#endif +#ifdef _WIN_ALL + // Reset system sleep timer to prevent system going sleep. + SetThreadExecutionState(ES_SYSTEM_REQUIRED); #endif } #endif diff -Nru unrar-nonfree-5.2.7/system.hpp unrar-nonfree-5.3.2/system.hpp --- unrar-nonfree-5.2.7/system.hpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/system.hpp 2015-08-04 10:22:40.000000000 +0000 @@ -19,6 +19,7 @@ void InitSystemOptions(int SleepTime); void SetPriority(int Priority); +clock_t MonoClock(); void Wait(); bool EmailFile(const wchar *FileName,const wchar *MailToW); void Shutdown(); diff -Nru unrar-nonfree-5.2.7/threadmisc.cpp unrar-nonfree-5.3.2/threadmisc.cpp --- unrar-nonfree-5.2.7/threadmisc.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/threadmisc.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -58,7 +58,6 @@ if (GlobalPoolUseCount++ == 0) GlobalPool=new ThreadPool(MaxPoolThreads); -#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 if one of @@ -70,7 +69,6 @@ CriticalSectionEnd(&PoolCreateSync.CritSection); return Pool; } -#endif CriticalSectionEnd(&PoolCreateSync.CritSection); return GlobalPool; @@ -83,12 +81,11 @@ if (Pool!=NULL && Pool==GlobalPool && GlobalPoolUseCount > 0 && --GlobalPoolUseCount == 0) delete GlobalPool; -#ifdef RARDLL + // 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!=NULL && Pool!=GlobalPool) delete Pool; -#endif CriticalSectionEnd(&PoolCreateSync.CritSection); } diff -Nru unrar-nonfree-5.2.7/timefn.cpp unrar-nonfree-5.3.2/timefn.cpp --- unrar-nonfree-5.2.7/timefn.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/timefn.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -216,7 +216,7 @@ #if !defined(GUI) || !defined(SFX_MODULE) -void RarTime::GetText(wchar *DateStr,size_t MaxSize,bool FullYear,bool FullMS) +void RarTime::GetText(wchar *DateStr,size_t MaxSize,bool FullMS) { if (IsSet()) { @@ -225,15 +225,12 @@ if (FullMS) swprintf(DateStr,MaxSize,L"%u-%02u-%02u %02u:%02u:%02u,%03u",lt.Year,lt.Month,lt.Day,lt.Hour,lt.Minute,lt.Second,lt.Reminder/10000); else - if (FullYear) - swprintf(DateStr,MaxSize,L"%02u-%02u-%u %02u:%02u",lt.Day,lt.Month,lt.Year,lt.Hour,lt.Minute); - else - swprintf(DateStr,MaxSize,L"%02u-%02u-%02u %02u:%02u",lt.Day,lt.Month,lt.Year%100,lt.Hour,lt.Minute); + swprintf(DateStr,MaxSize,L"%u-%02u-%02u %02u:%02u",lt.Year,lt.Month,lt.Day,lt.Hour,lt.Minute); } else { // We use escape before '?' to avoid weird C trigraph characters. - wcscpy(DateStr,FullYear ? L"\?\?-\?\?-\?\?\?\? \?\?:\?\?":L"\?\?-\?\?-\?\? \?\?:\?\?"); + wcscpy(DateStr,L"\?\?\?\?-\?\?-\?\? \?\?:\?\?"); } } #endif diff -Nru unrar-nonfree-5.2.7/timefn.hpp unrar-nonfree-5.3.2/timefn.hpp --- unrar-nonfree-5.2.7/timefn.hpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/timefn.hpp 2015-08-04 10:22:40.000000000 +0000 @@ -43,7 +43,7 @@ void SetRaw(uint64 RawTime); uint GetDos(); void SetDos(uint DosTime); - void GetText(wchar *DateStr,size_t MaxSize,bool FullYear,bool FullMS); + void GetText(wchar *DateStr,size_t MaxSize,bool FullMS); void SetIsoText(const wchar *TimeText); void SetAgeText(const wchar *TimeText); void SetCurrentTime(); diff -Nru unrar-nonfree-5.2.7/uiconsole.cpp unrar-nonfree-5.3.2/uiconsole.cpp --- unrar-nonfree-5.2.7/uiconsole.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/uiconsole.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -6,8 +6,8 @@ FindData ExistingFD; memset(&ExistingFD,0,sizeof(ExistingFD)); // In case find fails. FindFile::FastFind(Name,&ExistingFD); - itoa(ExistingFD.Size,SizeText1); - ExistingFD.mtime.GetText(DateStr1,ASIZE(DateStr1),true,false); + itoa(ExistingFD.Size,SizeText1,ASIZE(SizeText1)); + ExistingFD.mtime.GetText(DateStr1,ASIZE(DateStr1),false); if (FileSize==INT64NDF || FileTime==NULL) { @@ -16,8 +16,8 @@ } else { - itoa(FileSize,SizeText2); - FileTime->GetText(DateStr2,ASIZE(DateStr2),true,false); + itoa(FileSize,SizeText2,ASIZE(SizeText2)); + FileTime->GetText(DateStr2,ASIZE(DateStr2),false); eprintf(St(MAskReplace),Name,SizeText1,DateStr1,SizeText2,DateStr2); } @@ -135,6 +135,7 @@ break; case UIERROR_FILECOPYHINT: Log(Str[0],St(MCopyErrorHint)); + mprintf(L" "); // For progress percent. break; case UIERROR_DIRCREATE: Log(Str[0],St(MExtrErrMkDir),Str[1]); @@ -342,14 +343,15 @@ { if (uiSoundEnabled) { - static clock_t LastTime=clock(); - if ((clock()-LastTime)/CLOCKS_PER_SEC>5) + static clock_t LastTime=-10; // Negative to always beep first time. + if ((MonoClock()-LastTime)/CLOCKS_PER_SEC>5) { #ifdef _WIN_ALL MessageBeep(-1); #else putwchar('\007'); #endif + LastTime=MonoClock(); } } } diff -Nru unrar-nonfree-5.2.7/unpack30.cpp unrar-nonfree-5.3.2/unpack30.cpp --- unrar-nonfree-5.2.7/unpack30.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/unpack30.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -310,11 +310,11 @@ // Try to read the new buffer if only one byte is left. // But if we read all bytes except the last, one byte is enough. if (Inp.InAddr>=ReadTop-1 && !UnpReadBuf30() && I>8; Inp.addbits(8); } - return(AddVMCode(FirstByte,&VMCode[0],Length)); + return AddVMCode(FirstByte,&VMCode[0],Length); } @@ -322,7 +322,7 @@ { unsigned int FirstByte=SafePPMDecodeChar(); if ((int)FirstByte==-1) - return(false); + return false; int Length=(FirstByte & 7)+1; if (Length==7) { @@ -336,10 +336,10 @@ { int B1=SafePPMDecodeChar(); if (B1==-1) - return(false); + return false; int B2=SafePPMDecodeChar(); if (B2==-1) - return(false); + return false; Length=B1*256+B2; } Array VMCode(Length); @@ -350,7 +350,7 @@ return(false); VMCode[I]=Ch; } - return(AddVMCode(FirstByte,&VMCode[0],Length)); + return AddVMCode(FirstByte,&VMCode[0],Length); } @@ -361,11 +361,11 @@ VM.Init(); uint FiltPos; - if (FirstByte & 0x80) + if ((FirstByte & 0x80)!=0) { FiltPos=RarVM::ReadData(VMCodeInp); if (FiltPos==0) - InitFilters30(); + InitFilters30(false); else FiltPos--; } @@ -373,7 +373,7 @@ FiltPos=LastFilter; // Use the same filter as last time. if (FiltPos>Filters30.Size() || FiltPos>OldFilterLengths.Size()) - return(false); + return false; LastFilter=FiltPos; bool NewFilter=(FiltPos==Filters30.Size()); @@ -382,7 +382,7 @@ UnpackFilter30 *Filter; if (NewFilter) // New filter code, never used before since VM reset. { - if (FiltPos>MAX3_FILTERS) + if (FiltPos>MAX3_UNPACK_FILTERS) { // Too many different filters, corrupt archive. delete StackFilter; @@ -418,6 +418,8 @@ } if (EmptyCount==0) { + if (PrgStack.Size()>MAX3_UNPACK_FILTERS) + return false; PrgStack.Add(1); EmptyCount=1; } @@ -426,10 +428,10 @@ StackFilter->ExecCount=Filter->ExecCount; uint BlockStart=RarVM::ReadData(VMCodeInp); - if (FirstByte & 0x40) + if ((FirstByte & 0x40)!=0) BlockStart+=258; StackFilter->BlockStart=(uint)((BlockStart+UnpPtr)&MaxWinMask); - if (FirstByte & 0x20) + if ((FirstByte & 0x20)!=0) { StackFilter->BlockLength=RarVM::ReadData(VMCodeInp); @@ -454,9 +456,9 @@ StackFilter->Prg.InitR[4]=StackFilter->BlockLength; StackFilter->Prg.InitR[5]=StackFilter->ExecCount; - if (FirstByte & 0x10) // set registers to optional parameters if any + if ((FirstByte & 0x10)!=0) // Set registers to optional parameters if any. { - unsigned int InitMask=VMCodeInp.fgetbits()>>9; + uint InitMask=VMCodeInp.fgetbits()>>9; VMCodeInp.faddbits(7); for (int I=0;I<7;I++) if (InitMask & (1<=0x10000 || VMCodeSize==0) - return(false); + return false; Array VMCode(VMCodeSize); for (uint I=0;I>8; VMCodeInp.faddbits(8); } @@ -502,13 +504,13 @@ VM.SetLowEndianValue((uint *)&GlobalData[0x2c],StackFilter->ExecCount); memset(&GlobalData[0x30],0,16); - if (FirstByte & 8) // Put the data block passed as parameter if any. + if ((FirstByte & 8)!=0) // Put the data block passed as parameter if any. { if (VMCodeInp.Overflow(3)) - return(false); + return false; uint DataSize=RarVM::ReadData(VMCodeInp); if (DataSize>VM_GLOBALMEMSIZE-VM_FIXEDGLOBALSIZE) - return(false); + return false; size_t CurSize=StackFilter->Prg.GlobalData.Size(); if (CurSizePrg.GlobalData.Add(DataSize+VM_FIXEDGLOBALSIZE-CurSize); @@ -516,12 +518,12 @@ for (uint I=0;I>8; VMCodeInp.faddbits(8); } } - return(true); + return true; } @@ -529,7 +531,7 @@ { int DataSize=ReadTop-Inp.InAddr; // Data left to process. if (DataSize<0) - return(false); + return false; if (Inp.InAddr>BitInput::MAX_SIZE/2) { // If we already processed more than half of buffer, let's move @@ -549,7 +551,7 @@ if (ReadCode>0) ReadTop+=ReadCode; ReadBorder=ReadTop-30; - return(ReadCode!=-1); + return ReadCode!=-1; } @@ -816,21 +818,23 @@ memset(UnpOldTable,0,sizeof(UnpOldTable)); PPMEscChar=2; UnpBlockType=BLOCK_LZ; - - InitFilters30(); } + InitFilters30(Solid); } -void Unpack::InitFilters30() +void Unpack::InitFilters30(bool Solid) { - OldFilterLengths.Reset(); - LastFilter=0; + if (!Solid) + { + OldFilterLengths.SoftReset(); + LastFilter=0; - for (size_t I=0;I=MAX_UNPACK_FILTERS-1) + if (Filters.Size()>=MAX_UNPACK_FILTERS) + { UnpWriteBuf(); // Write data, apply and flush filters. + if (Filters.Size()>=MAX_UNPACK_FILTERS) + InitFilters(); // Still too many filters, prevent excessive memory use. + } // If distance to filter start is that large that due to circular dictionary - // mode it points to old not written yet data, then we set 'NextWindow' + // mode now it points to old not written yet data, then we set 'NextWindow' // flag and process this filter only after processing that older data. Filter.NextWindow=WrPtr!=UnpPtr && ((WrPtr-UnpPtr)&MaxWinMask)<=Filter.BlockStart; @@ -250,7 +254,7 @@ for (size_t I=0;INextWindow) { // Here we skip filters which have block start in current data range - // due to address warp around in circular dictionary, but actually + // due to address wrap around in circular dictionary, but actually // belong to next dictionary block. If such filter start position // is included to current write range, then we reset 'NextWindow' flag. // In fact we can reset it even without such check, because current @@ -372,7 +376,8 @@ } // We prefer to write data in blocks not exceeding UNPACK_MAX_WRITE - // instead of potentially huge MaxWinSize blocks. + // instead of potentially huge MaxWinSize blocks. It also allows us + // to keep the size of Filters array reasonable. WriteBorder=(UnpPtr+Min(MaxWinSize,UNPACK_MAX_WRITE))&MaxWinMask; // Choose the nearest among WriteBorder and WrPtr actual written border. @@ -644,5 +649,5 @@ void Unpack::InitFilters() { - Filters.Reset(); + Filters.SoftReset(); } diff -Nru unrar-nonfree-5.2.7/unpack.cpp unrar-nonfree-5.3.2/unpack.cpp --- unrar-nonfree-5.2.7/unpack.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/unpack.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -47,7 +47,7 @@ Unpack::~Unpack() { - InitFilters30(); + InitFilters30(false); if (Window!=NULL) free(Window); @@ -114,7 +114,7 @@ if (!Fragmented) { // Clean the window to generate the same output when unpacking corrupt - // RAR files, which may access to unused areas of sliding dictionary. + // RAR files, which may access unused areas of sliding dictionary. memset(NewWindow,0,WinSize); // If Window is not NULL, it means that window size has grown. @@ -122,7 +122,7 @@ // RAR archiving code does not allow it in solid streams now, // but let's implement it anyway just in case we'll change it sometimes. if (Grow) - for (size_t I=1;I=8) { + // In theory we still could overlap here. + // Supposing Distance == MaxWinSize - 1 we have memcpy(Src, Src + 1, 8). + // But for real RAR archives Distance <= MaxWinSize - MAX_LZ_MATCH + // always, so overlap here is impossible. + // This memcpy expanded inline by MSVC. We could also use uint64 // assignment, which seems to provide about the same speed. memcpy(Dest,Src,8); diff -Nru unrar-nonfree-5.2.7/version.hpp unrar-nonfree-5.3.2/version.hpp --- unrar-nonfree-5.2.7/version.hpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/version.hpp 2015-08-04 10:22:40.000000000 +0000 @@ -1,6 +1,6 @@ #define RARVER_MAJOR 5 -#define RARVER_MINOR 21 -#define RARVER_BETA 0 -#define RARVER_DAY 15 -#define RARVER_MONTH 2 +#define RARVER_MINOR 30 +#define RARVER_BETA 2 +#define RARVER_DAY 4 +#define RARVER_MONTH 8 #define RARVER_YEAR 2015 diff -Nru unrar-nonfree-5.2.7/win32lnk.cpp unrar-nonfree-5.3.2/win32lnk.cpp --- unrar-nonfree-5.2.7/win32lnk.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/win32lnk.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -62,7 +62,11 @@ size_t PrintLength=wcslen(PrintName); bool AbsPath=WinPrefix; - if (!Cmd->AbsoluteLinks && (AbsPath || !IsRelativeSymlinkSafe(hd->FileName,hd->RedirName))) + // IsFullPath is not really needed here, AbsPath check is enough. + // We added it just for extra safety, in case some Windows version would + // allow to create absolute targets with SYMLINK_FLAG_RELATIVE. + if (!Cmd->AbsoluteLinks && (AbsPath || IsFullPath(hd->RedirName) || + !IsRelativeSymlinkSafe(hd->FileName,hd->RedirName))) return false; CreatePath(Name,true); diff -Nru unrar-nonfree-5.2.7/win32stm.cpp unrar-nonfree-5.3.2/win32stm.cpp --- unrar-nonfree-5.2.7/win32stm.cpp 2015-03-25 17:35:42.000000000 +0000 +++ unrar-nonfree-5.3.2/win32stm.cpp 2015-08-04 10:22:40.000000000 +0000 @@ -78,7 +78,7 @@ #ifdef _WIN_ALL -void ExtractStreams(Archive &Arc,const wchar *FileName) +void ExtractStreams(Archive &Arc,const wchar *FileName,bool TestMode) { wchar FullName[NM+2]; if (FileName[0]!=0 && FileName[1]==0) @@ -101,6 +101,12 @@ return; } + if (TestMode) + { + Arc.ReadSubData(NULL,NULL); + return; + } + wcsncatz(FullName,StreamName,ASIZE(FullName)); FindData fd;