... | ... |
@@ -34,7 +34,7 @@ bool Archive::GetComment(Array<wchar> *CmtData) |
34 | 34 |
#ifndef SFX_MODULE |
35 | 35 |
// Old style (RAR 2.9) comment header embedded into the main |
36 | 36 |
// archive header. |
37 |
- if (BrokenHeader) |
|
37 |
+ if (BrokenHeader || CommHead.HeadSize<SIZEOF_COMMHEAD) |
|
38 | 38 |
{ |
39 | 39 |
uiMsg(UIERROR_CMTBROKEN,FileName); |
40 | 40 |
return false; |
... | ... |
@@ -57,6 +57,8 @@ bool Archive::GetComment(Array<wchar> *CmtData) |
57 | 57 |
#else |
58 | 58 |
UnpCmtLength=GetByte(); |
59 | 59 |
UnpCmtLength+=(GetByte()<<8); |
60 |
+ if (CmtLength<2) |
|
61 |
+ return false; |
|
60 | 62 |
CmtLength-=2; |
61 | 63 |
DataIO.SetCmt13Encryption(); |
62 | 64 |
CommHead.UnpVer=15; |
... | ... |
@@ -85,15 +87,18 @@ bool Archive::GetComment(Array<wchar> *CmtData) |
85 | 85 |
byte *UnpData; |
86 | 86 |
size_t UnpDataSize; |
87 | 87 |
DataIO.GetUnpackedData(&UnpData,&UnpDataSize); |
88 |
+ if (UnpDataSize>0) |
|
89 |
+ { |
|
88 | 90 |
#ifdef _WIN_ALL |
89 |
- // If we ever decide to extend it to Android, we'll need to alloc |
|
90 |
- // 4x memory for OEM to UTF-8 output here. |
|
91 |
- OemToCharBuffA((char *)UnpData,(char *)UnpData,(DWORD)UnpDataSize); |
|
91 |
+ // If we ever decide to extend it to Android, we'll need to alloc |
|
92 |
+ // 4x memory for OEM to UTF-8 output here. |
|
93 |
+ OemToCharBuffA((char *)UnpData,(char *)UnpData,(DWORD)UnpDataSize); |
|
92 | 94 |
#endif |
93 |
- CmtData->Alloc(UnpDataSize+1); |
|
94 |
- memset(CmtData->Addr(0),0,CmtData->Size()*sizeof(wchar)); |
|
95 |
- CharToWide((char *)UnpData,CmtData->Addr(0),CmtData->Size()); |
|
96 |
- CmtData->Alloc(wcslen(CmtData->Addr(0))); |
|
95 |
+ CmtData->Alloc(UnpDataSize+1); |
|
96 |
+ memset(CmtData->Addr(0),0,CmtData->Size()*sizeof(wchar)); |
|
97 |
+ CharToWide((char *)UnpData,CmtData->Addr(0),CmtData->Size()); |
|
98 |
+ CmtData->Alloc(wcslen(CmtData->Addr(0))); |
|
99 |
+ } |
|
97 | 100 |
} |
98 | 101 |
} |
99 | 102 |
else |
... | ... |
@@ -37,8 +37,7 @@ class Archive:public File |
37 | 37 |
void RequestArcPassword(); |
38 | 38 |
void UnexpEndArcMsg(); |
39 | 39 |
void BrokenHeaderMsg(); |
40 |
- void UnkEncVerMsg(const wchar *Name); |
|
41 |
- void UnkEncVerMsg(); |
|
40 |
+ void UnkEncVerMsg(const wchar *Name,const wchar *Info); |
|
42 | 41 |
bool ReadCommentData(Array<wchar> *CmtData); |
43 | 42 |
|
44 | 43 |
#if !defined(RAR_NOCRYPT) |
... | ... |
@@ -85,7 +84,7 @@ class Archive:public File |
85 | 85 |
void AddSubData(byte *SrcData,uint64 DataSize,File *SrcFile, |
86 | 86 |
const wchar *Name,uint Flags); |
87 | 87 |
bool ReadSubData(Array<byte> *UnpData,File *DestFile); |
88 |
- HEADER_TYPE GetHeaderType() {return CurHeaderType;}; |
|
88 |
+ HEADER_TYPE GetHeaderType() {return CurHeaderType;} |
|
89 | 89 |
RAROptions* GetRAROptions() {return Cmd;} |
90 | 90 |
void SetSilentOpen(bool Mode) {SilentOpen=Mode;} |
91 | 91 |
#if 0 |
... | ... |
@@ -10,7 +10,10 @@ size_t Archive::ReadHeader() |
10 | 10 |
|
11 | 11 |
CurBlockPos=Tell(); |
12 | 12 |
|
13 |
- size_t ReadSize; |
|
13 |
+ // Other developers asked us to initialize it to suppress "may be used |
|
14 |
+ // uninitialized" warning in code below in some compilers. |
|
15 |
+ size_t ReadSize=0; |
|
16 |
+ |
|
14 | 17 |
switch(Format) |
15 | 18 |
{ |
16 | 19 |
#ifndef SFX_MODULE |
... | ... |
@@ -113,9 +116,9 @@ void Archive::BrokenHeaderMsg() |
113 | 113 |
} |
114 | 114 |
|
115 | 115 |
|
116 |
-void Archive::UnkEncVerMsg(const wchar *Name) |
|
116 |
+void Archive::UnkEncVerMsg(const wchar *Name,const wchar *Info) |
|
117 | 117 |
{ |
118 |
- uiMsg(UIERROR_UNKNOWNENCMETHOD,FileName,Name); |
|
118 |
+ uiMsg(UIERROR_UNKNOWNENCMETHOD,FileName,Name,Info); |
|
119 | 119 |
ErrHandler.SetErrorCode(RARX_WARNING); |
120 | 120 |
} |
121 | 121 |
|
... | ... |
@@ -201,7 +204,7 @@ size_t Archive::ReadHeader15() |
201 | 201 |
if (ShortBlock.HeaderType==HEAD_MAIN && (ShortBlock.Flags & MHD_COMMENT)!=0) |
202 | 202 |
{ |
203 | 203 |
// Old style (up to RAR 2.9) main archive comment embedded into |
204 |
- // the main archive header found. While we can read the entire |
|
204 |
+ // the main archive header found. While we can read the entire |
|
205 | 205 |
// ShortBlock.HeadSize here and remove this part of "if", it would be |
206 | 206 |
// waste of memory, because we'll read and process this comment data |
207 | 207 |
// in other function anyway and we do not need them here now. |
... | ... |
@@ -227,7 +230,7 @@ size_t Archive::ReadHeader15() |
227 | 227 |
Encrypted=(MainHead.Flags & MHD_PASSWORD)!=0; |
228 | 228 |
Signed=MainHead.PosAV!=0 || MainHead.HighPosAV!=0; |
229 | 229 |
MainHead.CommentInHeader=(MainHead.Flags & MHD_COMMENT)!=0; |
230 |
- |
|
230 |
+ |
|
231 | 231 |
// Only for encrypted 3.0+ archives. 2.x archives did not have this |
232 | 232 |
// flag, so for non-encrypted archives, we'll set it later based on |
233 | 233 |
// file attributes. |
... | ... |
@@ -254,7 +257,7 @@ size_t Archive::ReadHeader15() |
254 | 254 |
hd->WinSize=hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5); |
255 | 255 |
hd->CommentInHeader=(hd->Flags & LHD_COMMENT)!=0; |
256 | 256 |
hd->Version=(hd->Flags & LHD_VERSION)!=0; |
257 |
- |
|
257 |
+ |
|
258 | 258 |
hd->DataSize=Raw.Get4(); |
259 | 259 |
uint LowUnpSize=Raw.Get4(); |
260 | 260 |
hd->HostOS=Raw.Get1(); |
... | ... |
@@ -279,7 +282,7 @@ size_t Archive::ReadHeader15() |
279 | 279 |
{ |
280 | 280 |
case 13: hd->CryptMethod=CRYPT_RAR13; break; |
281 | 281 |
case 15: hd->CryptMethod=CRYPT_RAR15; break; |
282 |
- case 20: |
|
282 |
+ case 20: |
|
283 | 283 |
case 26: hd->CryptMethod=CRYPT_RAR20; break; |
284 | 284 |
default: hd->CryptMethod=CRYPT_RAR30; break; |
285 | 285 |
} |
... | ... |
@@ -301,7 +304,7 @@ size_t Archive::ReadHeader15() |
301 | 301 |
} |
302 | 302 |
|
303 | 303 |
hd->Inherited=!FileBlock && (hd->SubFlags & SUBHEAD_FLAGS_INHERITED)!=0; |
304 |
- |
|
304 |
+ |
|
305 | 305 |
hd->LargeFile=(hd->Flags & LHD_LARGE)!=0; |
306 | 306 |
|
307 | 307 |
uint HighPackSize,HighUnpSize; |
... | ... |
@@ -311,7 +314,7 @@ size_t Archive::ReadHeader15() |
311 | 311 |
HighUnpSize=Raw.Get4(); |
312 | 312 |
hd->UnknownUnpSize=(LowUnpSize==0xffffffff && HighUnpSize==0xffffffff); |
313 | 313 |
} |
314 |
- else |
|
314 |
+ else |
|
315 | 315 |
{ |
316 | 316 |
HighPackSize=HighUnpSize=0; |
317 | 317 |
// UnpSize equal to 0xffffffff without LHD_LARGE flag indicates |
... | ... |
@@ -506,7 +509,7 @@ size_t Archive::ReadHeader15() |
506 | 506 |
NextBlockPos+=Raw.Get4(); |
507 | 507 |
break; |
508 | 508 |
} |
509 |
- |
|
509 |
+ |
|
510 | 510 |
ushort HeaderCRC=Raw.GetCRC15(false); |
511 | 511 |
|
512 | 512 |
// Old AV header does not have header CRC properly set. |
... | ... |
@@ -566,7 +569,7 @@ size_t Archive::ReadHeader50() |
566 | 566 |
// We repeat the password request only for manually entered passwords |
567 | 567 |
// and not for -p<pwd>. Wrong password can be intentionally provided |
568 | 568 |
// in -p<pwd> to not stop batch processing for encrypted archives. |
569 |
- bool GlobalPassword=Cmd->Password.IsSet(); |
|
569 |
+ bool GlobalPassword=Cmd->Password.IsSet() || uiIsGlobalPasswordSet(); |
|
570 | 570 |
|
571 | 571 |
while (true) // Repeat the password prompt for wrong passwords. |
572 | 572 |
{ |
... | ... |
@@ -641,7 +644,7 @@ size_t Archive::ReadHeader50() |
641 | 641 |
BrokenHeaderMsg(); |
642 | 642 |
return 0; |
643 | 643 |
} |
644 |
- |
|
644 |
+ |
|
645 | 645 |
Raw.Read(SizeToRead); |
646 | 646 |
|
647 | 647 |
if (Raw.Size()<HeaderSize) |
... | ... |
@@ -674,7 +677,7 @@ size_t Archive::ReadHeader50() |
674 | 674 |
return 0; |
675 | 675 |
} |
676 | 676 |
} |
677 |
- |
|
677 |
+ |
|
678 | 678 |
uint64 ExtraSize=0; |
679 | 679 |
if ((ShortBlock.Flags & HFL_EXTRA)!=0) |
680 | 680 |
{ |
... | ... |
@@ -702,7 +705,9 @@ size_t Archive::ReadHeader50() |
702 | 702 |
uint CryptVersion=(uint)Raw.GetV(); |
703 | 703 |
if (CryptVersion>CRYPT_VERSION) |
704 | 704 |
{ |
705 |
- UnkEncVerMsg(FileName); |
|
705 |
+ wchar Info[20]; |
|
706 |
+ swprintf(Info,ASIZE(Info),L"h%u",CryptVersion); |
|
707 |
+ UnkEncVerMsg(FileName,Info); |
|
706 | 708 |
return 0; |
707 | 709 |
} |
708 | 710 |
uint EncFlags=(uint)Raw.GetV(); |
... | ... |
@@ -710,7 +715,9 @@ size_t Archive::ReadHeader50() |
710 | 710 |
CryptHead.Lg2Count=Raw.Get1(); |
711 | 711 |
if (CryptHead.Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX) |
712 | 712 |
{ |
713 |
- UnkEncVerMsg(FileName); |
|
713 |
+ wchar Info[20]; |
|
714 |
+ swprintf(Info,ASIZE(Info),L"hc%u",CryptHead.Lg2Count); |
|
715 |
+ UnkEncVerMsg(FileName,Info); |
|
714 | 716 |
return 0; |
715 | 717 |
} |
716 | 718 |
Raw.GetB(CryptHead.Salt,SIZE_SALT50); |
... | ... |
@@ -763,7 +770,7 @@ size_t Archive::ReadHeader50() |
763 | 763 |
// to not break normal archive processing by calling function. |
764 | 764 |
int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos; |
765 | 765 |
HEADER_TYPE SaveCurHeaderType=CurHeaderType; |
766 |
- |
|
766 |
+ |
|
767 | 767 |
QOpen.Init(this,false); |
768 | 768 |
QOpen.Load(MainHead.QOpenOffset); |
769 | 769 |
|
... | ... |
@@ -788,7 +795,7 @@ size_t Archive::ReadHeader50() |
788 | 788 |
hd->PackSize=DataSize; |
789 | 789 |
hd->FileFlags=(uint)Raw.GetV(); |
790 | 790 |
hd->UnpSize=Raw.GetV(); |
791 |
- |
|
791 |
+ |
|
792 | 792 |
hd->UnknownUnpSize=(hd->FileFlags & FHFL_UNPUNKNOWN)!=0; |
793 | 793 |
if (hd->UnknownUnpSize) |
794 | 794 |
hd->UnpSize=INT64NDF; |
... | ... |
@@ -815,6 +822,8 @@ size_t Archive::ReadHeader50() |
815 | 815 |
// but it was already used in RAR 1.5 and Unpack needs to distinguish |
816 | 816 |
// them. |
817 | 817 |
hd->UnpVer=(CompInfo & 0x3f) + 50; |
818 |
+ if (hd->UnpVer!=50) // Only 5.0 compression is known now. |
|
819 |
+ hd->UnpVer=VER_UNKNOWN; |
|
818 | 820 |
|
819 | 821 |
hd->HostOS=(byte)Raw.GetV(); |
820 | 822 |
size_t NameSize=(size_t)Raw.GetV(); |
... | ... |
@@ -873,7 +882,7 @@ size_t Archive::ReadHeader50() |
873 | 873 |
RecoverySize=Header.RecSectionSize*Header.RecCount; |
874 | 874 |
} |
875 | 875 |
#endif |
876 |
- |
|
876 |
+ |
|
877 | 877 |
if (BadCRC) // Add the file name to broken header message displayed above. |
878 | 878 |
uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName); |
879 | 879 |
} |
... | ... |
@@ -989,8 +998,12 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb) |
989 | 989 |
{ |
990 | 990 |
FileHeader *hd=(FileHeader *)bb; |
991 | 991 |
uint EncVersion=(uint)Raw->GetV(); |
992 |
- if (EncVersion > CRYPT_VERSION) |
|
993 |
- UnkEncVerMsg(hd->FileName); |
|
992 |
+ if (EncVersion>CRYPT_VERSION) |
|
993 |
+ { |
|
994 |
+ wchar Info[20]; |
|
995 |
+ swprintf(Info,ASIZE(Info),L"x%u",EncVersion); |
|
996 |
+ UnkEncVerMsg(hd->FileName,Info); |
|
997 |
+ } |
|
994 | 998 |
else |
995 | 999 |
{ |
996 | 1000 |
uint Flags=(uint)Raw->GetV(); |
... | ... |
@@ -998,7 +1011,11 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb) |
998 | 998 |
hd->UseHashKey=(Flags & FHEXTRA_CRYPT_HASHMAC)!=0; |
999 | 999 |
hd->Lg2Count=Raw->Get1(); |
1000 | 1000 |
if (hd->Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX) |
1001 |
- UnkEncVerMsg(hd->FileName); |
|
1001 |
+ { |
|
1002 |
+ wchar Info[20]; |
|
1003 |
+ swprintf(Info,ASIZE(Info),L"xc%u",hd->Lg2Count); |
|
1004 |
+ UnkEncVerMsg(hd->FileName,Info); |
|
1005 |
+ } |
|
1002 | 1006 |
Raw->GetB(hd->Salt,SIZE_SALT50); |
1003 | 1007 |
Raw->GetB(hd->InitV,SIZE_INITV); |
1004 | 1008 |
if (hd->UsePswCheck) |
... | ... |
@@ -1290,7 +1307,7 @@ void Archive::ConvertAttributes() |
1290 | 1290 |
|
1291 | 1291 |
if (mask == (mode_t) -1) |
1292 | 1292 |
{ |
1293 |
- // umask call returns the current umask value. Argument (022) is not |
|
1293 |
+ // umask call returns the current umask value. Argument (022) is not |
|
1294 | 1294 |
// really important here. |
1295 | 1295 |
mask = umask(022); |
1296 | 1296 |
|
... | ... |
@@ -1367,8 +1384,8 @@ void Archive::ConvertFileHeader(FileHeader *hd) |
1367 | 1367 |
|
1368 | 1368 |
// ':' in file names is allowed in Unix, but not in Windows. |
1369 | 1369 |
// Even worse, file data will be written to NTFS stream on NTFS, |
1370 |
- // so automatic name correction on file create error in extraction |
|
1371 |
- // routine does not work. In Windows and DOS versions we better |
|
1370 |
+ // so automatic name correction on file create error in extraction |
|
1371 |
+ // routine does not work. In Windows and DOS versions we better |
|
1372 | 1372 |
// replace ':' now. |
1373 | 1373 |
if (*s==':') |
1374 | 1374 |
*s='_'; |
... | ... |
@@ -1,5 +1,8 @@ |
1 | 1 |
#include "rar.hpp" |
2 | 2 |
|
3 |
+#include "cmdfilter.cpp" |
|
4 |
+#include "cmdmix.cpp" |
|
5 |
+ |
|
3 | 6 |
CommandData::CommandData() |
4 | 7 |
{ |
5 | 8 |
Init(); |
... | ... |
@@ -120,6 +123,7 @@ void CommandData::ParseArg(wchar *Arg) |
120 | 120 |
wchar CmdChar=toupperw(*Command); |
121 | 121 |
bool Add=wcschr(L"AFUM",CmdChar)!=NULL; |
122 | 122 |
bool Extract=CmdChar=='X' || CmdChar=='E'; |
123 |
+ bool Repair=CmdChar=='R' && Command[1]==0; |
|
123 | 124 |
if (EndSeparator && !Add) |
124 | 125 |
wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath)); |
125 | 126 |
else |
... | ... |
@@ -130,15 +134,15 @@ void CommandData::ParseArg(wchar *Arg) |
130 | 130 |
FindData FileData; |
131 | 131 |
bool Found=FindFile::FastFind(Arg,&FileData); |
132 | 132 |
if ((!Found || ListMode==RCLM_ACCEPT_LISTS) && |
133 |
- ListMode!=RCLM_REJECT_LISTS && *Arg=='@' && !IsWildcard(Arg)) |
|
133 |
+ ListMode!=RCLM_REJECT_LISTS && *Arg=='@' && !IsWildcard(Arg+1)) |
|
134 | 134 |
{ |
135 | 135 |
FileLists=true; |
136 | 136 |
|
137 | 137 |
ReadTextFile(Arg+1,&FileArgs,false,true,FilelistCharset,true,true,true); |
138 | 138 |
|
139 | 139 |
} |
140 |
- else |
|
141 |
- if (Found && FileData.IsDir && Extract && *ExtrPath==0) |
|
140 |
+ else // We use 'destpath\' when extracting and reparing. |
|
141 |
+ if (Found && FileData.IsDir && (Extract || Repair) && *ExtrPath==0) |
|
142 | 142 |
{ |
143 | 143 |
wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath)); |
144 | 144 |
AddEndSlash(ExtrPath,ASIZE(ExtrPath)); |
... | ... |
@@ -280,7 +284,11 @@ void CommandData::ProcessSwitch(const wchar *Switch) |
280 | 280 |
ClearArc=true; |
281 | 281 |
break; |
282 | 282 |
case 'D': |
283 |
- AppendArcNameToPath=true; |
|
283 |
+ if (Switch[2]==0) |
|
284 |
+ AppendArcNameToPath=APPENDARCNAME_DESTPATH; |
|
285 |
+ else |
|
286 |
+ if (Switch[2]=='1') |
|
287 |
+ AppendArcNameToPath=APPENDARCNAME_OWNDIR; |
|
284 | 288 |
break; |
285 | 289 |
#ifndef SFX_MODULE |
286 | 290 |
case 'G': |
... | ... |
@@ -302,7 +310,7 @@ void CommandData::ProcessSwitch(const wchar *Switch) |
302 | 302 |
AddArcOnly=true; |
303 | 303 |
break; |
304 | 304 |
case 'P': |
305 |
- wcscpy(ArcPath,Switch+2); |
|
305 |
+ wcsncpyz(ArcPath,Switch+2,ASIZE(ArcPath)); |
|
306 | 306 |
break; |
307 | 307 |
case 'S': |
308 | 308 |
SyncFiles=true; |
... | ... |
@@ -407,9 +415,9 @@ void CommandData::ProcessSwitch(const wchar *Switch) |
407 | 407 |
wcsncpyz(LogName,Switch[4]!=0 ? Switch+4:DefLogName,ASIZE(LogName)); |
408 | 408 |
break; |
409 | 409 |
} |
410 |
- if (wcsicomp(Switch+1,L"SND")==0) |
|
410 |
+ if (wcsnicomp(Switch+1,L"SND",3)==0) |
|
411 | 411 |
{ |
412 |
- Sound=true; |
|
412 |
+ Sound=Switch[4]=='-' ? SOUND_NOTIFY_OFF : SOUND_NOTIFY_ON; |
|
413 | 413 |
break; |
414 | 414 |
} |
415 | 415 |
if (wcsicomp(Switch+1,L"ERR")==0) |
... | ... |
@@ -805,16 +813,16 @@ void CommandData::ProcessSwitch(const wchar *Switch) |
805 | 805 |
ArcTime=ARCTIME_LATEST; |
806 | 806 |
break; |
807 | 807 |
case 'O': |
808 |
- FileTimeBefore.SetAgeText(Switch+2); |
|
808 |
+ SetTimeFilters(Switch+2,true,true); |
|
809 | 809 |
break; |
810 | 810 |
case 'N': |
811 |
- FileTimeAfter.SetAgeText(Switch+2); |
|
811 |
+ SetTimeFilters(Switch+2,false,true); |
|
812 | 812 |
break; |
813 | 813 |
case 'B': |
814 |
- FileTimeBefore.SetIsoText(Switch+2); |
|
814 |
+ SetTimeFilters(Switch+2,true,false); |
|
815 | 815 |
break; |
816 | 816 |
case 'A': |
817 |
- FileTimeAfter.SetIsoText(Switch+2); |
|
817 |
+ SetTimeFilters(Switch+2,false,false); |
|
818 | 818 |
break; |
819 | 819 |
case 'S': |
820 | 820 |
{ |
... | ... |
@@ -897,7 +905,7 @@ void CommandData::ProcessSwitch(const wchar *Switch) |
897 | 897 |
if (Switch[1]==0) |
898 | 898 |
{ |
899 | 899 |
// If comment file is not specified, we read data from stdin. |
900 |
- wcscpy(CommentFile,L"stdin"); |
|
900 |
+ wcsncpyz(CommentFile,L"stdin",ASIZE(CommentFile)); |
|
901 | 901 |
} |
902 | 902 |
else |
903 | 903 |
wcsncpyz(CommentFile,Switch+1,ASIZE(CommentFile)); |
... | ... |
@@ -922,309 +930,6 @@ void CommandData::BadSwitch(const wchar *Switch) |
922 | 922 |
#endif |
923 | 923 |
|
924 | 924 |
|
925 |
-void CommandData::OutTitle() |
|
926 |
-{ |
|
927 |
- if (BareOutput || DisableCopyright) |
|
928 |
- return; |
|
929 |
-#if defined(__GNUC__) && defined(SFX_MODULE) |
|
930 |
- mprintf(St(MCopyrightS)); |
|
931 |
-#else |
|
932 |
-#ifndef SILENT |
|
933 |
- static bool TitleShown=false; |
|
934 |
- if (TitleShown) |
|
935 |
- return; |
|
936 |
- TitleShown=true; |
|
937 |
- |
|
938 |
- wchar Version[80]; |
|
939 |
- if (RARVER_BETA!=0) |
|
940 |
- swprintf(Version,ASIZE(Version),L"%d.%02d %ls %d",RARVER_MAJOR,RARVER_MINOR,St(MBeta),RARVER_BETA); |
|
941 |
- else |
|
942 |
- swprintf(Version,ASIZE(Version),L"%d.%02d",RARVER_MAJOR,RARVER_MINOR); |
|
943 |
-#if defined(_WIN_32) || defined(_WIN_64) |
|
944 |
- wcsncatz(Version,L" ",ASIZE(Version)); |
|
945 |
-#endif |
|
946 |
-#ifdef _WIN_32 |
|
947 |
- wcsncatz(Version,St(Mx86),ASIZE(Version)); |
|
948 |
-#endif |
|
949 |
-#ifdef _WIN_64 |
|
950 |
- wcsncatz(Version,St(Mx64),ASIZE(Version)); |
|
951 |
-#endif |
|
952 |
- if (PrintVersion) |
|
953 |
- { |
|
954 |
- mprintf(L"%s",Version); |
|
955 |
- exit(0); |
|
956 |
- } |
|
957 |
- mprintf(St(MUCopyright),Version,RARVER_YEAR); |
|
958 |
-#endif |
|
959 |
-#endif |
|
960 |
-} |
|
961 |
- |
|
962 |
- |
|
963 |
-inline bool CmpMSGID(MSGID i1,MSGID i2) |
|
964 |
-{ |
|
965 |
-#ifdef MSGID_INT |
|
966 |
- return i1==i2; |
|
967 |
-#else |
|
968 |
- // If MSGID is const char*, we cannot compare pointers only. |
|
969 |
- // Pointers to different instances of same string can differ, |
|
970 |
- // so we need to compare complete strings. |
|
971 |
- return wcscmp(i1,i2)==0; |
|
972 |
-#endif |
|
973 |
-} |
|
974 |
- |
|
975 |
-void CommandData::OutHelp(RAR_EXIT ExitCode) |
|
976 |
-{ |
|
977 |
-#if !defined(SILENT) |
|
978 |
- OutTitle(); |
|
979 |
- static MSGID Help[]={ |
|
980 |
-#ifdef SFX_MODULE |
|
981 |
- // Console SFX switches definition. |
|
982 |
- MCHelpCmd,MSHelpCmdE,MSHelpCmdT,MSHelpCmdV |
|
983 |
-#else |
|
984 |
- // UnRAR switches definition. |
|
985 |
- MUNRARTitle1,MRARTitle2,MCHelpCmd,MCHelpCmdE,MCHelpCmdL, |
|
986 |
- MCHelpCmdP,MCHelpCmdT,MCHelpCmdV,MCHelpCmdX,MCHelpSw,MCHelpSwm, |
|
987 |
- MCHelpSwAT,MCHelpSwAC,MCHelpSwAD,MCHelpSwAG,MCHelpSwAI,MCHelpSwAP, |
|
988 |
- MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU, |
|
989 |
- MCHelpSwDH,MCHelpSwEP,MCHelpSwEP3,MCHelpSwF,MCHelpSwIDP,MCHelpSwIERR, |
|
990 |
- MCHelpSwINUL,MCHelpSwIOFF,MCHelpSwKB,MCHelpSwN,MCHelpSwNa,MCHelpSwNal, |
|
991 |
- MCHelpSwO,MCHelpSwOC,MCHelpSwOL,MCHelpSwOR,MCHelpSwOW,MCHelpSwP, |
|
992 |
- MCHelpSwPm,MCHelpSwR,MCHelpSwRI,MCHelpSwSC,MCHelpSwSL,MCHelpSwSM, |
|
993 |
- MCHelpSwTA,MCHelpSwTB,MCHelpSwTN,MCHelpSwTO,MCHelpSwTS,MCHelpSwU, |
|
994 |
- MCHelpSwVUnr,MCHelpSwVER,MCHelpSwVP,MCHelpSwX,MCHelpSwXa,MCHelpSwXal, |
|
995 |
- MCHelpSwY |
|
996 |
-#endif |
|
997 |
- }; |
|
998 |
- |
|
999 |
- for (uint I=0;I<ASIZE(Help);I++) |
|
1000 |
- { |
|
1001 |
-#ifndef SFX_MODULE |
|
1002 |
- if (CmpMSGID(Help[I],MCHelpSwV)) |
|
1003 |
- continue; |
|
1004 |
-#ifndef _WIN_ALL |
|
1005 |
- static MSGID Win32Only[]={ |
|
1006 |
- MCHelpSwIEML,MCHelpSwVD,MCHelpSwAO,MCHelpSwOS,MCHelpSwIOFF, |
|
1007 |
- MCHelpSwEP2,MCHelpSwOC,MCHelpSwONI,MCHelpSwDR,MCHelpSwRI |
|
1008 |
- }; |
|
1009 |
- bool Found=false; |
|
1010 |
- for (int J=0;J<sizeof(Win32Only)/sizeof(Win32Only[0]);J++) |
|
1011 |
- if (CmpMSGID(Help[I],Win32Only[J])) |
|
1012 |
- { |
|
1013 |
- Found=true; |
|
1014 |
- break; |
|
1015 |
- } |
|
1016 |
- if (Found) |
|
1017 |
- continue; |
|
1018 |
-#endif |
|
1019 |
-#if !defined(_UNIX) && !defined(_WIN_ALL) |
|
1020 |
- if (CmpMSGID(Help[I],MCHelpSwOW)) |
|
1021 |
- continue; |
|
1022 |
-#endif |
|
1023 |
-#if !defined(_WIN_ALL) && !defined(_EMX) |
|
1024 |
- if (CmpMSGID(Help[I],MCHelpSwAC)) |
|
1025 |
- continue; |
|
1026 |
-#endif |
|
1027 |
-#ifndef SAVE_LINKS |
|
1028 |
- if (CmpMSGID(Help[I],MCHelpSwOL)) |
|
1029 |
- continue; |
|
1030 |
-#endif |
|
1031 |
-#ifndef RAR_SMP |
|
1032 |
- if (CmpMSGID(Help[I],MCHelpSwMT)) |
|
1033 |
- continue; |
|
1034 |
-#endif |
|
1035 |
-#endif |
|
1036 |
- mprintf(St(Help[I])); |
|
1037 |
- } |
|
1038 |
- mprintf(L"\n"); |
|
1039 |
- ErrHandler.Exit(ExitCode); |
|
1040 |
-#endif |
|
1041 |
-} |
|
1042 |
- |
|
1043 |
- |
|
1044 |
-// Return 'true' if we need to exclude the file from processing as result |
|
1045 |
-// of -x switch. If CheckInclList is true, we also check the file against |
|
1046 |
-// the include list created with -n switch. |
|
1047 |
-bool CommandData::ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList) |
|
1048 |
-{ |
|
1049 |
- if (CheckArgs(&ExclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH)) |
|
1050 |
- return true; |
|
1051 |
- if (!CheckInclList || InclArgs.ItemsCount()==0) |
|
1052 |
- return false; |
|
1053 |
- if (CheckArgs(&InclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH)) |
|
1054 |
- return false; |
|
1055 |
- return true; |
|
1056 |
-} |
|
1057 |
- |
|
1058 |
- |
|
1059 |
-bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode) |
|
1060 |
-{ |
|
1061 |
- wchar *Name=ConvertPath(CheckName,NULL); |
|
1062 |
- wchar FullName[NM]; |
|
1063 |
- wchar CurMask[NM]; |
|
1064 |
- *FullName=0; |
|
1065 |
- Args->Rewind(); |
|
1066 |
- while (Args->GetString(CurMask,ASIZE(CurMask))) |
|
1067 |
- { |
|
1068 |
- wchar *LastMaskChar=PointToLastChar(CurMask); |
|
1069 |
- bool DirMask=IsPathDiv(*LastMaskChar); // Mask for directories only. |
|
1070 |
- |
|
1071 |
- if (Dir) |
|
1072 |
- { |
|
1073 |
- // CheckName is a directory. |
|
1074 |
- if (DirMask) |
|
1075 |
- { |
|
1076 |
- // We process the directory and have the directory exclusion mask. |
|
1077 |
- // So let's convert "mask\" to "mask" and process it normally. |
|
1078 |
- |
|
1079 |
- *LastMaskChar=0; |
|
1080 |
- } |
|
1081 |
- else |
|
1082 |
- { |
|
1083 |
- // REMOVED, we want -npath\* to match empty folders too. |
|
1084 |
- // If mask has wildcards in name part and does not have the trailing |
|
1085 |
- // '\' character, we cannot use it for directories. |
|
1086 |
- |
|
1087 |
- // if (IsWildcard(PointToName(CurMask))) |
|
1088 |
- // continue; |
|
1089 |
- } |
|
1090 |
- } |
|
1091 |
- else |
|
1092 |
- { |
|
1093 |
- // If we process a file inside of directory excluded by "dirmask\". |
|
1094 |
- // we want to exclude such file too. So we convert "dirmask\" to |
|
1095 |
- // "dirmask\*". It is important for operations other than archiving |
|
1096 |
- // with -x. When archiving with -x, directory matched by "dirmask\" |
|
1097 |
- // is excluded from further scanning. |
|
1098 |
- |
|
1099 |
- if (DirMask) |
|
1100 |
- wcsncatz(CurMask,L"*",ASIZE(CurMask)); |
|
1101 |
- } |
|
1102 |
- |
|
1103 |
-#ifndef SFX_MODULE |
|
1104 |
- if (CheckFullPath && IsFullPath(CurMask)) |
|
1105 |
- { |
|
1106 |
- // We do not need to do the special "*\" processing here, because |
|
1107 |
- // unlike the "else" part of this "if", now we convert names to full |
|
1108 |
- // format, so they all include the path, which is matched by "*\" |
|
1109 |
- // correctly. Moreover, removing "*\" from mask would break |
|
1110 |
- // the comparison, because now all names have the path. |
|
1111 |
- |
|
1112 |
- if (*FullName==0) |
|
1113 |
- ConvertNameToFull(CheckName,FullName,ASIZE(FullName)); |
|
1114 |
- if (CmpName(CurMask,FullName,MatchMode)) |
|
1115 |
- return true; |
|
1116 |
- } |
|
1117 |
- else |
|
1118 |
-#endif |
|
1119 |
- { |
|
1120 |
- wchar NewName[NM+2],*CurName=Name; |
|
1121 |
- |
|
1122 |
- // Important to convert before "*\" check below, so masks like |
|
1123 |
- // d:*\something are processed properly. |
|
1124 |
- wchar *CmpMask=ConvertPath(CurMask,NULL); |
|
1125 |
- |
|
1126 |
- if (CmpMask[0]=='*' && IsPathDiv(CmpMask[1])) |
|
1127 |
- { |
|
1128 |
- // We want "*\name" to match 'name' not only in subdirectories, |
|
1129 |
- // but also in the current directory. We convert the name |
|
1130 |
- // from 'name' to '.\name' to be matched by "*\" part even if it is |
|
1131 |
- // in current directory. |
|
1132 |
- NewName[0]='.'; |
|
1133 |
- NewName[1]=CPATHDIVIDER; |
|
1134 |
- wcsncpyz(NewName+2,Name,ASIZE(NewName)-2); |
|
1135 |
- CurName=NewName; |
|
1136 |
- } |
|
1137 |
- |
|
1138 |
- if (CmpName(CmpMask,CurName,MatchMode)) |
|
1139 |
- return true; |
|
1140 |
- } |
|
1141 |
- } |
|
1142 |
- return false; |
|
1143 |
-} |
|
1144 |
- |
|
1145 |
- |
|
1146 |
-#ifndef SFX_MODULE |
|
1147 |
-// Now this function performs only one task and only in Windows version: |
|
1148 |
-// it skips symlinks to directories if -e1024 switch is specified. |
|
1149 |
-// Symlinks are skipped in ScanTree class, so their entire contents |
|
1150 |
-// is skipped too. Without this function we would check the attribute |
|
1151 |
-// only directly before archiving, so we would skip the symlink record, |
|
1152 |
-// but not the contents of symlinked directory. |
|
1153 |
-bool CommandData::ExclDirByAttr(uint FileAttr) |
|
1154 |
-{ |
|
1155 |
-#ifdef _WIN_ALL |
|
1156 |
- if ((FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0 && |
|
1157 |
- (ExclFileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0) |
|
1158 |
- return true; |
|
1159 |
-#endif |
|
1160 |
- return false; |
|
1161 |
-} |
|
1162 |
-#endif |
|
1163 |
- |
|
1164 |
- |
|
1165 |
- |
|
1166 |
- |
|
1167 |
-#ifndef SFX_MODULE |
|
1168 |
-// Return 'true' if we need to exclude the file from processing. |
|
1169 |
-bool CommandData::TimeCheck(RarTime &ft) |
|
1170 |
-{ |
|
1171 |
- if (FileTimeBefore.IsSet() && ft>=FileTimeBefore) |
|
1172 |
- return true; |
|
1173 |
- if (FileTimeAfter.IsSet() && ft<=FileTimeAfter) |
|
1174 |
- return true; |
|
1175 |
- return false; |
|
1176 |
-} |
|
1177 |
-#endif |
|
1178 |
- |
|
1179 |
- |
|
1180 |
-#ifndef SFX_MODULE |
|
1181 |
-// Return 'true' if we need to exclude the file from processing. |
|
1182 |
-bool CommandData::SizeCheck(int64 Size) |
|
1183 |
-{ |
|
1184 |
- if (FileSizeLess!=INT64NDF && Size>=FileSizeLess) |
|
1185 |
- return(true); |
|
1186 |
- if (FileSizeMore!=INT64NDF && Size<=FileSizeMore) |
|
1187 |
- return(true); |
|
1188 |
- return(false); |
|
1189 |
-} |
|
1190 |
-#endif |
|
1191 |
- |
|
1192 |
- |
|
1193 |
- |
|
1194 |
- |
|
1195 |
-int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType, |
|
1196 |
- wchar *MatchedArg,uint MatchedArgSize) |
|
1197 |
-{ |
|
1198 |
- if (MatchedArg!=NULL && MatchedArgSize>0) |
|
1199 |
- *MatchedArg=0; |
|
1200 |
-// if (wcslen(FileHead.FileName)>=NM) |
|
1201 |
-// return 0; |
|
1202 |
- bool Dir=FileHead.Dir; |
|
1203 |
- if (ExclCheck(FileHead.FileName,Dir,false,true)) |
|
1204 |
- return 0; |
|
1205 |
-#ifndef SFX_MODULE |
|
1206 |
- if (TimeCheck(FileHead.mtime)) |
|
1207 |
- return 0; |
|
1208 |
- if ((FileHead.FileAttr & ExclFileAttr)!=0 || InclAttrSet && (FileHead.FileAttr & InclFileAttr)==0) |
|
1209 |
- return 0; |
|
1210 |
- if (!Dir && SizeCheck(FileHead.UnpSize)) |
|
1211 |
- return 0; |
|
1212 |
-#endif |
|
1213 |
- wchar *ArgName; |
|
1214 |
- FileArgs.Rewind(); |
|
1215 |
- for (int StringCount=1;(ArgName=FileArgs.GetString())!=NULL;StringCount++) |
|
1216 |
- if (CmpName(ArgName,FileHead.FileName,MatchType)) |
|
1217 |
- { |
|
1218 |
- if (ExactMatch!=NULL) |
|
1219 |
- *ExactMatch=wcsicompc(ArgName,FileHead.FileName)==0; |
|
1220 |
- if (MatchedArg!=NULL) |
|
1221 |
- wcsncpyz(MatchedArg,ArgName,MatchedArgSize); |
|
1222 |
- return StringCount; |
|
1223 |
- } |
|
1224 |
- return 0; |
|
1225 |
-} |
|
1226 |
- |
|
1227 |
- |
|
1228 | 925 |
void CommandData::ProcessCommand() |
1229 | 926 |
{ |
1230 | 927 |
#ifndef SFX_MODULE |
... | ... |
@@ -6,6 +6,8 @@ |
6 | 6 |
|
7 | 7 |
enum RAR_CMD_LIST_MODE {RCLM_AUTO,RCLM_REJECT_LISTS,RCLM_ACCEPT_LISTS}; |
8 | 8 |
|
9 |
+enum IS_PROCESS_FILE_FLAGS {IPFF_EXCLUDE_PARENT=1}; |
|
10 |
+ |
|
9 | 11 |
class CommandData:public RAROptions |
10 | 12 |
{ |
11 | 13 |
private: |
... | ... |
@@ -13,6 +15,9 @@ class CommandData:public RAROptions |
13 | 13 |
void ProcessSwitch(const wchar *Switch); |
14 | 14 |
void BadSwitch(const wchar *Switch); |
15 | 15 |
uint GetExclAttr(const wchar *Str); |
16 |
+#if !defined(SFX_MODULE) |
|
17 |
+ void SetTimeFilters(const wchar *Mod,bool Before,bool Age); |
|
18 |
+#endif |
|
16 | 19 |
|
17 | 20 |
bool FileLists; |
18 | 21 |
bool NoMoreSwitches; |
... | ... |
@@ -34,11 +39,11 @@ class CommandData:public RAROptions |
34 | 34 |
bool ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList); |
35 | 35 |
static bool CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode); |
36 | 36 |
bool ExclDirByAttr(uint FileAttr); |
37 |
- bool TimeCheck(RarTime &ft); |
|
37 |
+ bool TimeCheck(RarTime &ftm,RarTime &ftc,RarTime &fta); |
|
38 | 38 |
bool SizeCheck(int64 Size); |
39 | 39 |
bool AnyFiltersActive(); |
40 |
- int IsProcessFile(FileHeader &FileHead,bool *ExactMatch=NULL,int MatchType=MATCH_WILDSUBPATH, |
|
41 |
- wchar *MatchedArg=NULL,uint MatchedArgSize=0); |
|
40 |
+ int IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType, |
|
41 |
+ bool Flags,wchar *MatchedArg,uint MatchedArgSize); |
|
42 | 42 |
void ProcessCommand(); |
43 | 43 |
void AddArcName(const wchar *Name); |
44 | 44 |
bool GetArcName(wchar *Name,int MaxSize); |
45 | 45 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,305 @@ |
0 |
+// Return 'true' if we need to exclude the file from processing as result |
|
1 |
+// of -x switch. If CheckInclList is true, we also check the file against |
|
2 |
+// the include list created with -n switch. |
|
3 |
+bool CommandData::ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList) |
|
4 |
+{ |
|
5 |
+ if (CheckArgs(&ExclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH)) |
|
6 |
+ return true; |
|
7 |
+ if (!CheckInclList || InclArgs.ItemsCount()==0) |
|
8 |
+ return false; |
|
9 |
+ if (CheckArgs(&InclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH)) |
|
10 |
+ return false; |
|
11 |
+ return true; |
|
12 |
+} |
|
13 |
+ |
|
14 |
+ |
|
15 |
+bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode) |
|
16 |
+{ |
|
17 |
+ wchar *Name=ConvertPath(CheckName,NULL,0); |
|
18 |
+ wchar FullName[NM]; |
|
19 |
+ wchar CurMask[NM]; |
|
20 |
+ *FullName=0; |
|
21 |
+ Args->Rewind(); |
|
22 |
+ while (Args->GetString(CurMask,ASIZE(CurMask))) |
|
23 |
+ { |
|
24 |
+ wchar *LastMaskChar=PointToLastChar(CurMask); |
|
25 |
+ bool DirMask=IsPathDiv(*LastMaskChar); // Mask for directories only. |
|
26 |
+ |
|
27 |
+ if (Dir) |
|
28 |
+ { |
|
29 |
+ // CheckName is a directory. |
|
30 |
+ if (DirMask) |
|
31 |
+ { |
|
32 |
+ // We process the directory and have the directory exclusion mask. |
|
33 |
+ // So let's convert "mask\" to "mask" and process it normally. |
|
34 |
+ |
|
35 |
+ *LastMaskChar=0; |
|
36 |
+ } |
|
37 |
+ else |
|
38 |
+ { |
|
39 |
+ // REMOVED, we want -npath\* to match empty folders too. |
|
40 |
+ // If mask has wildcards in name part and does not have the trailing |
|
41 |
+ // '\' character, we cannot use it for directories. |
|
42 |
+ |
|
43 |
+ // if (IsWildcard(PointToName(CurMask))) |
|
44 |
+ // continue; |
|
45 |
+ } |
|
46 |
+ } |
|
47 |
+ else |
|
48 |
+ { |
|
49 |
+ // If we process a file inside of directory excluded by "dirmask\". |
|
50 |
+ // we want to exclude such file too. So we convert "dirmask\" to |
|
51 |
+ // "dirmask\*". It is important for operations other than archiving |
|
52 |
+ // with -x. When archiving with -x, directory matched by "dirmask\" |
|
53 |
+ // is excluded from further scanning. |
|
54 |
+ |
|
55 |
+ if (DirMask) |
|
56 |
+ wcsncatz(CurMask,L"*",ASIZE(CurMask)); |
|
57 |
+ } |
|
58 |
+ |
|
59 |
+#ifndef SFX_MODULE |
|
60 |
+ if (CheckFullPath && IsFullPath(CurMask)) |
|
61 |
+ { |
|
62 |
+ // We do not need to do the special "*\" processing here, because |
|
63 |
+ // unlike the "else" part of this "if", now we convert names to full |
|
64 |
+ // format, so they all include the path, which is matched by "*\" |
|
65 |
+ // correctly. Moreover, removing "*\" from mask would break |
|
66 |
+ // the comparison, because now all names have the path. |
|
67 |
+ |
|
68 |
+ if (*FullName==0) |
|
69 |
+ ConvertNameToFull(CheckName,FullName,ASIZE(FullName)); |
|
70 |
+ if (CmpName(CurMask,FullName,MatchMode)) |
|
71 |
+ return true; |
|
72 |
+ } |
|
73 |
+ else |
|
74 |
+#endif |
|
75 |
+ { |
|
76 |
+ wchar NewName[NM+2],*CurName=Name; |
|
77 |
+ |
|
78 |
+ // Important to convert before "*\" check below, so masks like |
|
79 |
+ // d:*\something are processed properly. |
|
80 |
+ wchar *CmpMask=ConvertPath(CurMask,NULL,0); |
|
81 |
+ |
|
82 |
+ if (CmpMask[0]=='*' && IsPathDiv(CmpMask[1])) |
|
83 |
+ { |
|
84 |
+ // We want "*\name" to match 'name' not only in subdirectories, |
|
85 |
+ // but also in the current directory. We convert the name |
|
86 |
+ // from 'name' to '.\name' to be matched by "*\" part even if it is |
|
87 |
+ // in current directory. |
|
88 |
+ NewName[0]='.'; |
|
89 |
+ NewName[1]=CPATHDIVIDER; |
|
90 |
+ wcsncpyz(NewName+2,Name,ASIZE(NewName)-2); |
|
91 |
+ CurName=NewName; |
|
92 |
+ } |
|
93 |
+ |
|
94 |
+ if (CmpName(CmpMask,CurName,MatchMode)) |
|
95 |
+ return true; |
|
96 |
+ } |
|
97 |
+ } |
|
98 |
+ return false; |
|
99 |
+} |
|
100 |
+ |
|
101 |
+ |
|
102 |
+ |
|
103 |
+ |
|
104 |
+#ifndef SFX_MODULE |
|
105 |
+// Now this function performs only one task and only in Windows version: |
|
106 |
+// it skips symlinks to directories if -e1024 switch is specified. |
|
107 |
+// Symlinks are skipped in ScanTree class, so their entire contents |
|
108 |
+// is skipped too. Without this function we would check the attribute |
|
109 |
+// only directly before archiving, so we would skip the symlink record, |
|
110 |
+// but not the contents of symlinked directory. |
|
111 |
+bool CommandData::ExclDirByAttr(uint FileAttr) |
|
112 |
+{ |
|
113 |
+#ifdef _WIN_ALL |
|
114 |
+ if ((FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0 && |
|
115 |
+ (ExclFileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0) |
|
116 |
+ return true; |
|
117 |
+#endif |
|
118 |
+ return false; |
|
119 |
+} |
|
120 |
+#endif |
|
121 |
+ |
|
122 |
+ |
|
123 |
+ |
|
124 |
+ |
|
125 |
+#if !defined(SFX_MODULE) |
|
126 |
+void CommandData::SetTimeFilters(const wchar *Mod,bool Before,bool Age) |
|
127 |
+{ |
|
128 |
+ bool ModeOR=false,TimeMods=false; |
|
129 |
+ const wchar *S=Mod; |
|
130 |
+ // Check if any 'mca' modifiers are present, set OR mode if 'o' is present, |
|
131 |
+ // skip modifiers and set S to beginning of time string. Be sure to check |
|
132 |
+ // *S!=0, because termination 0 is a part of string for wcschr. |
|
133 |
+ for (;*S!=0 && wcschr(L"MCAOmcao",*S)!=NULL;S++) |
|
134 |
+ if (*S=='o' || *S=='O') |
|
135 |
+ ModeOR=true; |
|
136 |
+ else |
|
137 |
+ TimeMods=true; |
|
138 |
+ |
|
139 |
+ if (!TimeMods) // Assume 'm' if no modifiers are specified. |
|
140 |
+ Mod=L"m"; |
|
141 |
+ |
|
142 |
+ // Set the specified time for every modifier. Be sure to check *Mod!=0, |
|
143 |
+ // because termination 0 is a part of string for wcschr. This check is |
|
144 |
+ // important when we set Mod to "m" above. |
|
145 |
+ for (;*Mod!=0 && wcschr(L"MCAOmcao",*Mod)!=NULL;Mod++) |
|
146 |
+ switch(toupperw(*Mod)) |
|
147 |
+ { |
|
148 |
+ case 'M': |
|
149 |
+ if (Before) |
|
150 |
+ { |
|
151 |
+ Age ? FileMtimeBefore.SetAgeText(S):FileMtimeBefore.SetIsoText(S); |
|
152 |
+ FileMtimeBeforeOR=ModeOR; |
|
153 |
+ } |
|
154 |
+ else |
|
155 |
+ { |
|
156 |
+ Age ? FileMtimeAfter.SetAgeText(S):FileMtimeAfter.SetIsoText(S); |
|
157 |
+ FileMtimeAfterOR=ModeOR; |
|
158 |
+ } |
|
159 |
+ break; |
|
160 |
+ case 'C': |
|
161 |
+ if (Before) |
|
162 |
+ { |
|
163 |
+ Age ? FileCtimeBefore.SetAgeText(S):FileCtimeBefore.SetIsoText(S); |
|
164 |
+ FileCtimeBeforeOR=ModeOR; |
|
165 |
+ } |
|
166 |
+ else |
|
167 |
+ { |
|
168 |
+ Age ? FileCtimeAfter.SetAgeText(S):FileCtimeAfter.SetIsoText(S); |
|
169 |
+ FileCtimeAfterOR=ModeOR; |
|
170 |
+ } |
|
171 |
+ break; |
|
172 |
+ case 'A': |
|
173 |
+ if (Before) |
|
174 |
+ { |
|
175 |
+ Age ? FileAtimeBefore.SetAgeText(S):FileAtimeBefore.SetIsoText(S); |
|
176 |
+ FileAtimeBeforeOR=ModeOR; |
|
177 |
+ } |
|
178 |
+ else |
|
179 |
+ { |
|
180 |
+ Age ? FileAtimeAfter.SetAgeText(S):FileAtimeAfter.SetIsoText(S); |
|
181 |
+ FileAtimeAfterOR=ModeOR; |
|
182 |
+ } |
|
183 |
+ break; |
|
184 |
+ } |
|
185 |
+} |
|
186 |
+#endif |
|
187 |
+ |
|
188 |
+ |
|
189 |
+#ifndef SFX_MODULE |
|
190 |
+// Return 'true' if we need to exclude the file from processing. |
|
191 |
+bool CommandData::TimeCheck(RarTime &ftm,RarTime &ftc,RarTime &fta) |
|
192 |
+{ |
|
193 |
+ bool FilterOR=false; |
|
194 |
+ |
|
195 |
+ if (FileMtimeBefore.IsSet()) // Filter present. |
|
196 |
+ if (ftm>=FileMtimeBefore) // Condition not matched. |
|
197 |
+ if (FileMtimeBeforeOR) |
|
198 |
+ FilterOR=true; // Not matched OR filter is present. |
|
199 |
+ else |
|
200 |
+ return true; // Exclude file in AND mode. |
|
201 |
+ else // Condition matched. |
|
202 |
+ if (FileMtimeBeforeOR) |
|
203 |
+ return false; // Include file in OR mode. |
|
204 |
+ |
|
205 |
+ if (FileMtimeAfter.IsSet()) // Filter present. |
|
206 |
+ if (ftm<FileMtimeAfter) // Condition not matched. |
|
207 |
+ if (FileMtimeAfterOR) |
|
208 |
+ FilterOR=true; // Not matched OR filter is present. |
|
209 |
+ else |
|
210 |
+ return true; // Exclude file in AND mode. |
|
211 |
+ else // Condition matched. |
|
212 |
+ if (FileMtimeAfterOR) |
|
213 |
+ return false; // Include file in OR mode. |
|
214 |
+ |
|
215 |
+ if (FileCtimeBefore.IsSet()) // Filter present. |
|
216 |
+ if (ftc>=FileCtimeBefore) // Condition not matched. |
|
217 |
+ if (FileCtimeBeforeOR) |
|
218 |
+ FilterOR=true; // Not matched OR filter is present. |
|
219 |
+ else |
|
220 |
+ return true; // Exclude file in AND mode. |
|
221 |
+ else // Condition matched. |
|
222 |
+ if (FileCtimeBeforeOR) |
|
223 |
+ return false; // Include file in OR mode. |
|
224 |
+ |
|
225 |
+ if (FileCtimeAfter.IsSet()) // Filter present. |
|
226 |
+ if (ftc<FileCtimeAfter) // Condition not matched. |
|
227 |
+ if (FileCtimeAfterOR) |
|
228 |
+ FilterOR=true; // Not matched OR filter is present. |
|
229 |
+ else |
|
230 |
+ return true; // Exclude file in AND mode. |
|
231 |
+ else // Condition matched. |
|
232 |
+ if (FileCtimeAfterOR) |
|
233 |
+ return false; // Include file in OR mode. |
|
234 |
+ |
|
235 |
+ if (FileAtimeBefore.IsSet()) // Filter present. |
|
236 |
+ if (fta>=FileAtimeBefore) // Condition not matched. |
|
237 |
+ if (FileAtimeBeforeOR) |
|
238 |
+ FilterOR=true; // Not matched OR filter is present. |
|
239 |
+ else |
|
240 |
+ return true; // Exclude file in AND mode. |
|
241 |
+ else // Condition matched. |
|
242 |
+ if (FileAtimeBeforeOR) |
|
243 |
+ return false; // Include file in OR mode. |
|
244 |
+ |
|
245 |
+ if (FileAtimeAfter.IsSet()) // Filter present. |
|
246 |
+ if (fta<FileAtimeAfter) // Condition not matched. |
|
247 |
+ if (FileAtimeAfterOR) |
|
248 |
+ FilterOR=true; // Not matched OR filter is present. |
|
249 |
+ else |
|
250 |
+ return true; // Exclude file in AND mode. |
|
251 |
+ else // Condition matched. |
|
252 |
+ if (FileAtimeAfterOR) |
|
253 |
+ return false; // Include file in OR mode. |
|
254 |
+ |
|
255 |
+ return FilterOR; // Exclude if all OR filters are not matched. |
|
256 |
+} |
|
257 |
+#endif |
|
258 |
+ |
|
259 |
+ |
|
260 |
+#ifndef SFX_MODULE |
|
261 |
+// Return 'true' if we need to exclude the file from processing. |
|
262 |
+bool CommandData::SizeCheck(int64 Size) |
|
263 |
+{ |
|
264 |
+ if (FileSizeLess!=INT64NDF && Size>=FileSizeLess) |
|
265 |
+ return true; |
|
266 |
+ if (FileSizeMore!=INT64NDF && Size<=FileSizeMore) |
|
267 |
+ return true; |
|
268 |
+ return false; |
|
269 |
+} |
|
270 |
+#endif |
|
271 |
+ |
|
272 |
+ |
|
273 |
+ |
|
274 |
+ |
|
275 |
+// Return 0 if file must not be processed or a number of matched parameter otherwise. |
|
276 |
+int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType, |
|
277 |
+ bool Flags,wchar *MatchedArg,uint MatchedArgSize) |
|
278 |
+{ |
|
279 |
+ if (MatchedArg!=NULL && MatchedArgSize>0) |
|
280 |
+ *MatchedArg=0; |
|
281 |
+ bool Dir=FileHead.Dir; |
|
282 |
+ if (ExclCheck(FileHead.FileName,Dir,false,true)) |
|
283 |
+ return 0; |
|
284 |
+#ifndef SFX_MODULE |
|
285 |
+ if (TimeCheck(FileHead.mtime,FileHead.ctime,FileHead.atime)) |
|
286 |
+ return 0; |
|
287 |
+ if ((FileHead.FileAttr & ExclFileAttr)!=0 || InclAttrSet && (FileHead.FileAttr & InclFileAttr)==0) |
|
288 |
+ return 0; |
|
289 |
+ if (!Dir && SizeCheck(FileHead.UnpSize)) |
|
290 |
+ return 0; |
|
291 |
+#endif |
|
292 |
+ wchar *ArgName; |
|
293 |
+ FileArgs.Rewind(); |
|
294 |
+ for (int StringCount=1;(ArgName=FileArgs.GetString())!=NULL;StringCount++) |
|
295 |
+ if (CmpName(ArgName,FileHead.FileName,MatchType)) |
|
296 |
+ { |
|
297 |
+ if (ExactMatch!=NULL) |
|
298 |
+ *ExactMatch=wcsicompc(ArgName,FileHead.FileName)==0; |
|
299 |
+ if (MatchedArg!=NULL) |
|
300 |
+ wcsncpyz(MatchedArg,ArgName,MatchedArgSize); |
|
301 |
+ return StringCount; |
|
302 |
+ } |
|
303 |
+ return 0; |
|
304 |
+} |
0 | 305 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,118 @@ |
0 |
+void CommandData::OutTitle() |
|
1 |
+{ |
|
2 |
+ if (BareOutput || DisableCopyright) |
|
3 |
+ return; |
|
4 |
+#if defined(__GNUC__) && defined(SFX_MODULE) |
|
5 |
+ mprintf(St(MCopyrightS)); |
|
6 |
+#else |
|
7 |
+#ifndef SILENT |
|
8 |
+ static bool TitleShown=false; |
|
9 |
+ if (TitleShown) |
|
10 |
+ return; |
|
11 |
+ TitleShown=true; |
|
12 |
+ |
|
13 |
+ wchar Version[80]; |
|
14 |
+ if (RARVER_BETA!=0) |
|
15 |
+ swprintf(Version,ASIZE(Version),L"%d.%02d %ls %d",RARVER_MAJOR,RARVER_MINOR,St(MBeta),RARVER_BETA); |
|
16 |
+ else |
|
17 |
+ swprintf(Version,ASIZE(Version),L"%d.%02d",RARVER_MAJOR,RARVER_MINOR); |
|
18 |
+#if defined(_WIN_32) || defined(_WIN_64) |
|
19 |
+ wcsncatz(Version,L" ",ASIZE(Version)); |
|
20 |
+#endif |
|
21 |
+#ifdef _WIN_32 |
|
22 |
+ wcsncatz(Version,St(Mx86),ASIZE(Version)); |
|
23 |
+#endif |
|
24 |
+#ifdef _WIN_64 |
|
25 |
+ wcsncatz(Version,St(Mx64),ASIZE(Version)); |
|
26 |
+#endif |
|
27 |
+ if (PrintVersion) |
|
28 |
+ { |
|
29 |
+ mprintf(L"%s",Version); |
|
30 |
+ exit(0); |
|
31 |
+ } |
|
32 |
+ mprintf(St(MUCopyright),Version,RARVER_YEAR); |
|
33 |
+#endif |
|
34 |
+#endif |
|
35 |
+} |
|
36 |
+ |
|
37 |
+ |
|
38 |
+inline bool CmpMSGID(MSGID i1,MSGID i2) |
|
39 |
+{ |
|
40 |
+#ifdef MSGID_INT |
|
41 |
+ return i1==i2; |
|
42 |
+#else |
|
43 |
+ // If MSGID is const char*, we cannot compare pointers only. |
|
44 |
+ // Pointers to different instances of same string can differ, |
|
45 |
+ // so we need to compare complete strings. |
|
46 |
+ return wcscmp(i1,i2)==0; |
|
47 |
+#endif |
|
48 |
+} |
|
49 |
+ |
|
50 |
+void CommandData::OutHelp(RAR_EXIT ExitCode) |
|
51 |
+{ |
|
52 |
+#if !defined(SILENT) |
|
53 |
+ OutTitle(); |
|
54 |
+ static MSGID Help[]={ |
|
55 |
+#ifdef SFX_MODULE |
|
56 |
+ // Console SFX switches definition. |
|
57 |
+ MCHelpCmd,MSHelpCmdE,MSHelpCmdT,MSHelpCmdV |
|
58 |
+#else |
|
59 |
+ // UnRAR switches definition. |
|
60 |
+ MUNRARTitle1,MRARTitle2,MCHelpCmd,MCHelpCmdE,MCHelpCmdL, |
|
61 |
+ MCHelpCmdP,MCHelpCmdT,MCHelpCmdV,MCHelpCmdX,MCHelpSw,MCHelpSwm, |
|
62 |
+ MCHelpSwAT,MCHelpSwAC,MCHelpSwAD,MCHelpSwAG,MCHelpSwAI,MCHelpSwAP, |
|
63 |
+ MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU, |
|
64 |
+ MCHelpSwDH,MCHelpSwEP,MCHelpSwEP3,MCHelpSwF,MCHelpSwIDP,MCHelpSwIERR, |
|
65 |
+ MCHelpSwINUL,MCHelpSwIOFF,MCHelpSwKB,MCHelpSwN,MCHelpSwNa,MCHelpSwNal, |
|
66 |
+ MCHelpSwO,MCHelpSwOC,MCHelpSwOL,MCHelpSwOR,MCHelpSwOW,MCHelpSwP, |
|
67 |
+ MCHelpSwPm,MCHelpSwR,MCHelpSwRI,MCHelpSwSC,MCHelpSwSL,MCHelpSwSM, |
|
68 |
+ MCHelpSwTA,MCHelpSwTB,MCHelpSwTN,MCHelpSwTO,MCHelpSwTS,MCHelpSwU, |
|
69 |
+ MCHelpSwVUnr,MCHelpSwVER,MCHelpSwVP,MCHelpSwX,MCHelpSwXa,MCHelpSwXal, |
|
70 |
+ MCHelpSwY |
|
71 |
+#endif |
|
72 |
+ }; |
|
73 |
+ |
|
74 |
+ for (uint I=0;I<ASIZE(Help);I++) |
|
75 |
+ { |
|
76 |
+#ifndef SFX_MODULE |
|
77 |
+ if (CmpMSGID(Help[I],MCHelpSwV)) |
|
78 |
+ continue; |
|
79 |
+#ifndef _WIN_ALL |
|
80 |
+ static MSGID Win32Only[]={ |
|
81 |
+ MCHelpSwIEML,MCHelpSwVD,MCHelpSwAO,MCHelpSwOS,MCHelpSwIOFF, |
|
82 |
+ MCHelpSwEP2,MCHelpSwOC,MCHelpSwONI,MCHelpSwDR,MCHelpSwRI |
|
83 |
+ }; |
|
84 |
+ bool Found=false; |
|
85 |
+ for (uint J=0;J<ASIZE(Win32Only);J++) |
|
86 |
+ if (CmpMSGID(Help[I],Win32Only[J])) |
|
87 |
+ { |
|
88 |
+ Found=true; |
|
89 |
+ break; |
|
90 |
+ } |
|
91 |
+ if (Found) |
|
92 |
+ continue; |
|
93 |
+#endif |
|
94 |
+#if !defined(_UNIX) && !defined(_WIN_ALL) |
|
95 |
+ if (CmpMSGID(Help[I],MCHelpSwOW)) |
|
96 |
+ continue; |
|
97 |
+#endif |
|
98 |
+#if !defined(_WIN_ALL) && !defined(_EMX) |
|
99 |
+ if (CmpMSGID(Help[I],MCHelpSwAC)) |
|
100 |
+ continue; |
|
101 |
+#endif |
|
102 |
+#ifndef SAVE_LINKS |
|
103 |
+ if (CmpMSGID(Help[I],MCHelpSwOL)) |
|
104 |
+ continue; |
|
105 |
+#endif |
|
106 |
+#ifndef RAR_SMP |
|
107 |
+ if (CmpMSGID(Help[I],MCHelpSwMT)) |
|
108 |
+ continue; |
|
109 |
+#endif |
|
110 |
+#endif |
|
111 |
+ mprintf(St(Help[I])); |
|
112 |
+ } |
|
113 |
+ mprintf(L"\n"); |
|
114 |
+ ErrHandler.Exit(ExitCode); |
|
115 |
+#endif |
|
116 |
+} |
|
117 |
+ |
... | ... |
@@ -28,8 +28,8 @@ void CryptData::SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,co |
28 | 28 |
sha1_context c; |
29 | 29 |
sha1_init(&c); |
30 | 30 |
|
31 |
- const int HashRounds=0x40000; |
|
32 |
- for (int I=0;I<HashRounds;I++) |
|
31 |
+ const uint HashRounds=0x40000; |
|
32 |
+ for (uint I=0;I<HashRounds;I++) |
|
33 | 33 |
{ |
34 | 34 |
sha1_process_rar29( &c, RawPsw, RawLength ); |
35 | 35 |
byte PswNum[3]; |
... | ... |
@@ -47,8 +47,8 @@ void CryptData::SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,co |
47 | 47 |
} |
48 | 48 |
uint32 digest[5]; |
49 | 49 |
sha1_done( &c, digest ); |
50 |
- for (int I=0;I<4;I++) |
|
51 |
- for (int J=0;J<4;J++) |
|
50 |
+ for (uint I=0;I<4;I++) |
|
51 |
+ for (uint J=0;J<4;J++) |
|
52 | 52 |
AESKey[I*4+J]=(byte)(digest[I]>>(J*8)); |
53 | 53 |
|
54 | 54 |
KDF3Cache[KDF3CachePos].Pwd=*Password; |
... | ... |
@@ -42,7 +42,7 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r) |
42 | 42 |
Data->Cmd.DllError=0; |
43 | 43 |
Data->OpenMode=r->OpenMode; |
44 | 44 |
Data->Cmd.FileArgs.AddString(L"*"); |
45 |
- Data->Cmd.KeepBroken = true; |
|
45 |
+ Data->Cmd.KeepBroken=(r->OpFlags&ROADOF_KEEPBROKEN)!=0; |
|
46 | 46 |
|
47 | 47 |
char AnsiArcName[NM]; |
48 | 48 |
*AnsiArcName=0; |
... | ... |
@@ -93,9 +93,11 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r) |
93 | 93 |
return NULL; |
94 | 94 |
} |
95 | 95 |
r->Flags=0; |
96 |
- |
|
96 |
+ |
|
97 | 97 |
if (Data->Arc.Volume) |
98 | 98 |
r->Flags|=0x01; |
99 |
+ if (Data->Arc.MainComment) |
|
100 |
+ r->Flags|=0x02; |
|
99 | 101 |
if (Data->Arc.Locked) |
100 | 102 |
r->Flags|=0x04; |
101 | 103 |
if (Data->Arc.Solid) |
... | ... |
@@ -114,17 +116,29 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r) |
114 | 114 |
Array<wchar> CmtDataW; |
115 | 115 |
if (r->CmtBufSize!=0 && Data->Arc.GetComment(&CmtDataW)) |
116 | 116 |
{ |
117 |
- Array<char> CmtData(CmtDataW.Size()*4+1); |
|
118 |
- memset(&CmtData[0],0,CmtData.Size()); |
|
119 |
- WideToChar(&CmtDataW[0],&CmtData[0],CmtData.Size()-1); |
|
120 |
- size_t Size=strlen(&CmtData[0])+1; |
|
121 |
- |
|
122 |
- r->Flags|=2; |
|
123 |
- r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1; |
|
124 |
- r->CmtSize=(uint)Min(Size,r->CmtBufSize); |
|
125 |
- memcpy(r->CmtBuf,&CmtData[0],r->CmtSize-1); |
|
126 |
- if (Size<=r->CmtBufSize) |
|
127 |
- r->CmtBuf[r->CmtSize-1]=0; |
|
117 |
+ if (r->CmtBufW!=NULL) |
|
118 |
+ { |
|
119 |
+ CmtDataW.Push(0); |
|
120 |
+ size_t Size=wcslen(&CmtDataW[0])+1; |
|
121 |
+ |
|
122 |
+ r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1; |
|
123 |
+ r->CmtSize=(uint)Min(Size,r->CmtBufSize); |
|
124 |
+ memcpy(r->CmtBufW,&CmtDataW[0],(r->CmtSize-1)*sizeof(*r->CmtBufW)); |
|
125 |
+ r->CmtBufW[r->CmtSize-1]=0; |
|
126 |
+ } |
|
127 |
+ else |
|
128 |
+ if (r->CmtBuf!=NULL) |
|
129 |
+ { |
|
130 |
+ Array<char> CmtData(CmtDataW.Size()*4+1); |
|
131 |
+ memset(&CmtData[0],0,CmtData.Size()); |
|
132 |
+ WideToChar(&CmtDataW[0],&CmtData[0],CmtData.Size()-1); |
|
133 |
+ size_t Size=strlen(&CmtData[0])+1; |
|
134 |
+ |
|
135 |
+ r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1; |
|
136 |
+ r->CmtSize=(uint)Min(Size,r->CmtBufSize); |
|
137 |
+ memcpy(r->CmtBuf,&CmtData[0],r->CmtSize-1); |
|
138 |
+ r->CmtBuf[r->CmtSize-1]=0; |
|
139 |
+ } |
|
128 | 140 |
} |
129 | 141 |
else |
130 | 142 |
r->CmtState=r->CmtSize=0; |
... | ... |
@@ -216,7 +230,7 @@ int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D) |
216 | 216 |
// open callback for RAR5 archives and if password is invalid. |
217 | 217 |
if (Data->Arc.FailedHeaderDecryption) |
218 | 218 |
return ERAR_BAD_PASSWORD; |
219 |
- |
|
219 |
+ |
|
220 | 220 |
return ERAR_END_ARCHIVE; |
221 | 221 |
} |
222 | 222 |
FileHeader *hd=&Data->Arc.FileHead; |
... | ... |
@@ -254,13 +268,10 @@ int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D) |
254 | 254 |
D->UnpSize=uint(hd->UnpSize & 0xffffffff); |
255 | 255 |
D->UnpSizeHigh=uint(hd->UnpSize>>32); |
256 | 256 |
D->HostOS=hd->HSType==HSYS_WINDOWS ? HOST_WIN32:HOST_UNIX; |
257 |
- if (Data->Arc.Format==RARFMT50) |
|
258 |
- D->UnpVer=Data->Arc.FileHead.UnpVer==0 ? 50 : 200; // If it is not 0, just set it to something big. |
|
259 |
- else |
|
260 |
- D->UnpVer=Data->Arc.FileHead.UnpVer; |
|
257 |
+ D->UnpVer=Data->Arc.FileHead.UnpVer; |
|
261 | 258 |
D->FileCRC=hd->FileHash.CRC32; |
262 | 259 |
D->FileTime=hd->mtime.GetDos(); |
263 |
- |
|
260 |
+ |
|
264 | 261 |
uint64 MRaw=hd->mtime.GetWin(); |
265 | 262 |
D->MtimeLow=(uint)MRaw; |
266 | 263 |
D->MtimeHigh=(uint)(MRaw>>32); |
... | ... |
@@ -373,7 +384,7 @@ int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestNa |
373 | 373 |
if (DestNameW!=NULL) |
374 | 374 |
wcsncpyz(Data->Cmd.DllDestName,DestNameW,ASIZE(Data->Cmd.DllDestName)); |
375 | 375 |
|
376 |
- wcscpy(Data->Cmd.Command,Operation==RAR_EXTRACT ? L"X":L"T"); |
|
376 |
+ wcsncpyz(Data->Cmd.Command,Operation==RAR_EXTRACT ? L"X":L"T",ASIZE(Data->Cmd.Command)); |
|
377 | 377 |
Data->Cmd.Test=Operation!=RAR_EXTRACT; |
378 | 378 |
bool Repeat=false; |
379 | 379 |
Data->Extract.ExtractCurrentFile(Data->Arc,Data->HeaderSize,Repeat); |
... | ... |
@@ -385,7 +396,7 @@ int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestNa |
385 | 385 |
// if archive is still open to avoid calling file operations on |
386 | 386 |
// the invalid file handle. Some of our file operations like Seek() |
387 | 387 |
// process such invalid handle correctly, some not. |
388 |
- while (Data->Arc.IsOpened() && Data->Arc.ReadHeader()!=0 && |
|
388 |
+ while (Data->Arc.IsOpened() && Data->Arc.ReadHeader()!=0 && |
|
389 | 389 |
Data->Arc.GetHeaderType()==HEAD_SERVICE) |
390 | 390 |
{ |
391 | 391 |
Data->Extract.ExtractCurrentFile(Data->Arc,Data->HeaderSize,Repeat); |
... | ... |
@@ -440,16 +451,16 @@ void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataPro |
440 | 440 |
} |
441 | 441 |
|
442 | 442 |
|
443 |
-#ifndef RAR_NOCRYPT |
|
444 | 443 |
void PASCAL RARSetPassword(HANDLE hArcData,char *Password) |
445 | 444 |
{ |
445 |
+#ifndef RAR_NOCRYPT |
|
446 | 446 |
DataSet *Data=(DataSet *)hArcData; |
447 | 447 |
wchar PasswordW[MAXPASSWORD]; |
448 | 448 |
GetWideName(Password,NULL,PasswordW,ASIZE(PasswordW)); |
449 | 449 |
Data->Cmd.Password.Set(PasswordW); |
450 | 450 |
cleandata(PasswordW,sizeof(PasswordW)); |
451 |
-} |
|
452 | 451 |
#endif |
452 |
+} |
|
453 | 453 |
|
454 | 454 |
|
455 | 455 |
int PASCAL RARGetDllVersion() |
... | ... |
@@ -1,7 +1,7 @@ |
1 | 1 |
#ifndef _UNRAR_DLL_ |
2 | 2 |
#define _UNRAR_DLL_ |
3 | 3 |
|
4 |
-#pragma pack(1) |
|
4 |
+#pragma pack(push, 1) |
|
5 | 5 |
|
6 | 6 |
#define ERAR_SUCCESS 0 |
7 | 7 |
#define ERAR_END_ARCHIVE 10 |
... | ... |
@@ -135,6 +135,8 @@ typedef int (CALLBACK *UNRARCALLBACK)(UINT msg,LPARAM UserData,LPARAM P1,LPARAM |
135 | 135 |
#define ROADF_ENCHEADERS 0x0080 |
136 | 136 |
#define ROADF_FIRSTVOLUME 0x0100 |
137 | 137 |
|
138 |
+#define ROADOF_KEEPBROKEN 0x0001 |
|
139 |
+ |
|
138 | 140 |
struct RAROpenArchiveDataEx |
139 | 141 |
{ |
140 | 142 |
char *ArcName; |
... | ... |
@@ -148,7 +150,9 @@ struct RAROpenArchiveDataEx |
148 | 148 |
unsigned int Flags; |
149 | 149 |
UNRARCALLBACK Callback; |
150 | 150 |
LPARAM UserData; |
151 |
- unsigned int Reserved[28]; |
|
151 |
+ unsigned int OpFlags; |
|
152 |
+ wchar_t *CmtBufW; |
|
153 |
+ unsigned int Reserved[25]; |
|
152 | 154 |
}; |
153 | 155 |
|
154 | 156 |
enum UNRARCALLBACK_MESSAGES { |
... | ... |
@@ -180,6 +184,6 @@ int PASCAL RARGetDllVersion(); |
180 | 180 |
} |
181 | 181 |
#endif |
182 | 182 |
|
183 |
-#pragma pack() |
|
183 |
+#pragma pack(pop) |
|
184 | 184 |
|
185 | 185 |
#endif |
... | ... |
@@ -2,8 +2,8 @@ |
2 | 2 |
#include <commctrl.h> |
3 | 3 |
|
4 | 4 |
VS_VERSION_INFO VERSIONINFO |
5 |
-FILEVERSION 5, 60, 100, 2736 |
|
6 |
-PRODUCTVERSION 5, 60, 100, 2736 |
|
5 |
+FILEVERSION 5, 71, 100, 3045 |
|
6 |
+PRODUCTVERSION 5, 71, 100, 3045 |
|
7 | 7 |
FILEOS VOS__WINDOWS32 |
8 | 8 |
FILETYPE VFT_APP |
9 | 9 |
{ |
... | ... |
@@ -14,9 +14,9 @@ FILETYPE VFT_APP |
14 | 14 |
VALUE "CompanyName", "Alexander Roshal\0" |
15 | 15 |
VALUE "ProductName", "RAR decompression library\0" |
16 | 16 |
VALUE "FileDescription", "RAR decompression library\0" |
17 |
- VALUE "FileVersion", "5.60.0\0" |
|
18 |
- VALUE "ProductVersion", "5.60.0\0" |
|
19 | ||
17 |
+ VALUE "FileVersion", "5.71.0\0" |
|
18 |
+ VALUE "ProductVersion", "5.71.0\0" |
|
19 | ||
20 | 20 |
VALUE "OriginalFilename", "Unrar.dll\0" |
21 | 21 |
} |
22 | 22 |
} |
23 | 23 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,13 @@ |
0 |
+EXPORTS |
|
1 |
+ RAROpenArchive |
|
2 |
+ RAROpenArchiveEx |
|
3 |
+ RARCloseArchive |
|
4 |
+ RARReadHeader |
|
5 |
+ RARReadHeaderEx |
|
6 |
+ RARProcessFile |
|
7 |
+ RARProcessFileW |
|
8 |
+ RARSetCallback |
|
9 |
+ RARSetChangeVolProc |
|
10 |
+ RARSetProcessDataProc |
|
11 |
+; RARSetPassword |
|
12 |
+ RARGetDllVersion |
... | ... |
@@ -56,7 +56,7 @@ class ErrorHandler |
56 | 56 |
uint GetErrorCount() {return ErrCount;} |
57 | 57 |
void SetSignalHandlers(bool Enable); |
58 | 58 |
void Throw(RAR_EXIT Code); |
59 |
- void SetSilent(bool Mode) {Silent=Mode;}; |
|
59 |
+ void SetSilent(bool Mode) {Silent=Mode;} |
|
60 | 60 |
bool GetSysErrMsg(wchar *Msg,size_t Size); |
61 | 61 |
void SysErrMsg(); |
62 | 62 |
int GetSystemErrorCode(); |
... | ... |
@@ -87,7 +87,7 @@ void CmdExtract::ExtractArchiveInit(Archive &Arc) |
87 | 87 |
FirstFile=true; |
88 | 88 |
#endif |
89 | 89 |
|
90 |
- GlobalPassword=Cmd->Password.IsSet(); |
|
90 |
+ GlobalPassword=Cmd->Password.IsSet() || uiIsGlobalPasswordSet(); |
|
91 | 91 |
|
92 | 92 |
DataIO.UnpVolume=false; |
93 | 93 |
|
... | ... |
@@ -161,7 +161,7 @@ EXTRACT_ARC_CODE CmdExtract::ExtractArchive() |
161 | 161 |
// This size is necessary to display the correct total progress indicator. |
162 | 162 |
|
163 | 163 |
wchar NextName[NM]; |
164 |
- wcscpy(NextName,Arc.FileName); |
|
164 |
+ wcsncpyz(NextName,Arc.FileName,ASIZE(NextName)); |
|
165 | 165 |
|
166 | 166 |
while (true) |
167 | 167 |
{ |
... | ... |
@@ -261,15 +261,17 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) |
261 | 261 |
if (HeaderType==HEAD_ENDARC) |
262 | 262 |
if (Arc.EndArcHead.NextVolume) |
263 | 263 |
{ |
264 |
-#ifndef NOVOLUME |
|
264 |
+#ifdef NOVOLUME |
|
265 |
+ return false; |
|
266 |
+#else |
|
265 | 267 |
if (!MergeArchive(Arc,&DataIO,false,Command)) |
266 | 268 |
{ |
267 | 269 |
ErrHandler.SetErrorCode(RARX_WARNING); |
268 | 270 |
return false; |
269 | 271 |
} |
270 |
-#endif |
|
271 | 272 |
Arc.Seek(Arc.CurBlockPos,SEEK_SET); |
272 | 273 |
return true; |
274 |
+#endif |
|
273 | 275 |
} |
274 | 276 |
else |
275 | 277 |
return false; |
... | ... |
@@ -298,7 +300,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) |
298 | 298 |
|
299 | 299 |
bool EqualNames=false; |
300 | 300 |
wchar MatchedArg[NM]; |
301 |
- int MatchNumber=Cmd->IsProcessFile(Arc.FileHead,&EqualNames,MatchType,MatchedArg,ASIZE(MatchedArg)); |
|
301 |
+ int MatchNumber=Cmd->IsProcessFile(Arc.FileHead,&EqualNames,MatchType,0,MatchedArg,ASIZE(MatchedArg)); |
|
302 | 302 |
bool MatchFound=MatchNumber!=0; |
303 | 303 |
#ifndef SFX_MODULE |
304 | 304 |
if (Cmd->ExclPath==EXCL_BASEPATH) |
... | ... |
@@ -323,6 +325,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) |
323 | 323 |
|
324 | 324 |
if (wcsicomp(ArcName,CurVolName)!=0 && FileExist(ArcName)) |
325 | 325 |
{ |
326 |
+ wcsncpyz(Cmd->ArcName,ArcName,ASIZE(ArcName)); // For GUI "Delete archive after extraction". |
|
326 | 327 |
// If first volume name does not match the current name and if such |
327 | 328 |
// volume name really exists, let's unpack from this first volume. |
328 | 329 |
Repeat=true; |
... | ... |
@@ -344,7 +347,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) |
344 | 344 |
#endif |
345 | 345 |
|
346 | 346 |
wchar ArcFileName[NM]; |
347 |
- ConvertPath(Arc.FileHead.FileName,ArcFileName); |
|
347 |
+ ConvertPath(Arc.FileHead.FileName,ArcFileName,ASIZE(ArcFileName)); |
|
348 | 348 |
|
349 | 349 |
if (Arc.FileHead.Version) |
350 | 350 |
{ |
... | ... |
@@ -472,7 +475,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) |
472 | 472 |
memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0 && |
473 | 473 |
!Arc.BrokenHeader) |
474 | 474 |
{ |
475 |
- if (GlobalPassword) // For -p<pwd> or Ctrl+P. |
|
475 |
+ if (GlobalPassword) // For -p<pwd> or Ctrl+P to avoid the infinite loop. |
|
476 | 476 |
{ |
477 | 477 |
// This message is used by Android GUI to reset cached passwords. |
478 | 478 |
// Update appropriate code if changed. |
... | ... |
@@ -613,10 +616,14 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) |
613 | 613 |
} |
614 | 614 |
#endif |
615 | 615 |
|
616 |
- if (!TestMode && !Arc.BrokenHeader && |
|
617 |
- (Arc.FileHead.PackSize<<11)>Arc.FileHead.UnpSize && |
|
616 |
+ uint64 Preallocated=0; |
|
617 |
+ if (!TestMode && !Arc.BrokenHeader && Arc.FileHead.UnpSize>1000000 && |
|
618 |
+ Arc.FileHead.PackSize*1024>Arc.FileHead.UnpSize && |
|
618 | 619 |
(Arc.FileHead.UnpSize<100000000 || Arc.FileLength()>Arc.FileHead.PackSize)) |
620 |
+ { |
|
619 | 621 |
CurFile.Prealloc(Arc.FileHead.UnpSize); |
622 |
+ Preallocated=Arc.FileHead.UnpSize; |
|
623 |
+ } |
|
620 | 624 |
|
621 | 625 |
CurFile.SetAllowDelete(!Cmd->KeepBroken); |
622 | 626 |
|
... | ... |
@@ -733,8 +740,9 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) |
733 | 733 |
(!LinkEntry || Arc.FileHead.RedirType==FSREDIR_FILECOPY && LinkSuccess) && |
734 | 734 |
(!BrokenFile || Cmd->KeepBroken)) |
735 | 735 |
{ |
736 |
- // We could preallocate more space that really written to broken file. |
|
737 |
- if (BrokenFile) |
|
736 |
+ // We could preallocate more space that really written to broken file |
|
737 |
+ // or file with crafted header. |
|
738 |
+ if (Preallocated>0 && (BrokenFile || DataIO.CurUnpWrite!=Preallocated)) |
|
738 | 739 |
CurFile.Truncate(); |
739 | 740 |
|
740 | 741 |
#if defined(_WIN_ALL) || defined(_EMX) |
... | ... |
@@ -850,9 +858,12 @@ void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *De |
850 | 850 |
} |
851 | 851 |
|
852 | 852 |
#ifndef SFX_MODULE |
853 |
- if (Cmd->AppendArcNameToPath) |
|
853 |
+ if (Cmd->AppendArcNameToPath!=APPENDARCNAME_NONE) |
|
854 | 854 |
{ |
855 |
- wcsncatz(DestName,PointToName(Arc.FirstVolumeName),DestSize); |
|
855 |
+ if (Cmd->AppendArcNameToPath==APPENDARCNAME_DESTPATH) |
|
856 |
+ wcsncatz(DestName,PointToName(Arc.FirstVolumeName),DestSize); |
|
857 |
+ else |
|
858 |
+ wcsncpyz(DestName,Arc.FirstVolumeName,DestSize); // To archive own dir. |
|
856 | 859 |
SetExt(DestName,NULL,DestSize); |
857 | 860 |
AddEndSlash(DestName,DestSize); |
858 | 861 |
} |
... | ... |
@@ -965,7 +976,11 @@ bool CmdExtract::ExtrGetPassword(Archive &Arc,const wchar *ArcFileName) |
965 | 965 |
if (!uiGetPassword(UIPASSWORD_FILE,ArcFileName,&Cmd->Password)/* || !Cmd->Password.IsSet()*/) |
966 | 966 |
{ |
967 | 967 |
// Suppress "test is ok" message if user cancelled the password prompt. |
968 |
- uiMsg(UIERROR_INCERRCOUNT); |
|
968 |
+// 2019.03.23: If some archives are tested ok and prompt is cancelled for others, |
|
969 |
+// do we really need to suppress "test is ok"? Also if we set an empty password |
|
970 |
+// and "Use for all archives" in WinRAR Ctrl+P and skip some encrypted archives. |
|
971 |
+// We commented out this UIERROR_INCERRCOUNT for now. |
|
972 |
+// uiMsg(UIERROR_INCERRCOUNT); |
|
969 | 973 |
return false; |
970 | 974 |
} |
971 | 975 |
Cmd->ManualPassword=true; |
... | ... |
@@ -1081,7 +1096,7 @@ void CmdExtract::ExtrCreateDir(Archive &Arc,const wchar *ArcFileName) |
1081 | 1081 |
{ |
1082 | 1082 |
#if defined(_WIN_ALL) && !defined(SFX_MODULE) |
1083 | 1083 |
if (Cmd->SetCompressedAttr && |
1084 |
- (Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT()) |
|
1084 |
+ (Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT()!=WNT_NONE) |
|
1085 | 1085 |
SetFileCompression(DestFileName,true); |
1086 | 1086 |
#endif |
1087 | 1087 |
SetFileHeaderExtra(Cmd,Arc,DestFileName); |
... | ... |
@@ -99,7 +99,7 @@ class File |
99 | 99 |
void SetCloseFileTime(RarTime *ftm,RarTime *fta=NULL); |
100 | 100 |
static void SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta); |
101 | 101 |
void GetOpenFileTime(RarTime *ft); |
102 |
- virtual bool IsOpened() {return hFile!=FILE_BAD_HANDLE;}; // 'virtual' for MultiFile class. |
|
102 |
+ virtual bool IsOpened() {return hFile!=FILE_BAD_HANDLE;} // 'virtual' for MultiFile class. |
|
103 | 103 |
int64 FileLength(); |
104 | 104 |
void SetHandleType(FILE_HANDLETYPE Type) {HandleType=Type;} |
105 | 105 |
FILE_HANDLETYPE GetHandleType() {return HandleType;} |
... | ... |
@@ -348,7 +348,7 @@ wchar *MkTemp(wchar *Name,size_t MaxSize) |
348 | 348 |
swprintf(RndText,ASIZE(RndText),L"%u.%03u",PID,Ext); |
349 | 349 |
if (Length+wcslen(RndText)>=MaxSize || Attempt==1000) |
350 | 350 |
return NULL; |
351 |
- wcscpy(Name+Length,RndText); |
|
351 |
+ wcsncpyz(Name+Length,RndText,MaxSize-Length); |
|
352 | 352 |
if (!FileExist(Name)) |
353 | 353 |
break; |
354 | 354 |
} |
... | ... |
@@ -26,7 +26,7 @@ FindFile::~FindFile() |
26 | 26 |
|
27 | 27 |
void FindFile::SetMask(const wchar *Mask) |
28 | 28 |
{ |
29 |
- wcscpy(FindMask,Mask); |
|
29 |
+ wcsncpyz(FindMask,Mask,ASIZE(FindMask)); |
|
30 | 30 |
FirstCall=true; |
31 | 31 |
} |
32 | 32 |
|
... | ... |
@@ -52,7 +52,7 @@ bool FindFile::Next(FindData *fd,bool GetSymLink) |
52 | 52 |
wcsncpyz(DirName,FindMask,ASIZE(DirName)); |
53 | 53 |
RemoveNameFromPath(DirName); |
54 | 54 |
if (*DirName==0) |
55 |
- wcscpy(DirName,L"."); |
|
55 |
+ wcsncpyz(DirName,L".",ASIZE(DirName)); |
|
56 | 56 |
char DirNameA[NM]; |
57 | 57 |
WideToChar(DirName,DirNameA,ASIZE(DirNameA)); |
58 | 58 |
if ((dirp=opendir(DirNameA))==NULL) |
... | ... |
@@ -75,20 +75,20 @@ bool FindFile::Next(FindData *fd,bool GetSymLink) |
75 | 75 |
if (CmpName(FindMask,Name,MATCH_NAMES)) |
76 | 76 |
{ |
77 | 77 |
wchar FullName[NM]; |
78 |
- wcscpy(FullName,FindMask); |
|
78 |
+ wcsncpyz(FullName,FindMask,ASIZE(FullName)); |
|
79 | 79 |
*PointToName(FullName)=0; |
80 | 80 |
if (wcslen(FullName)+wcslen(Name)>=ASIZE(FullName)-1) |
81 | 81 |
{ |
82 | 82 |
uiMsg(UIERROR_PATHTOOLONG,FullName,L"",Name); |
83 | 83 |
return false; |
84 | 84 |
} |
85 |
- wcscat(FullName,Name); |
|
85 |
+ wcsncatz(FullName,Name,ASIZE(FullName)); |
|
86 | 86 |
if (!FastFind(FullName,fd,GetSymLink)) |
87 | 87 |
{ |
88 | 88 |
ErrHandler.OpenErrorMsg(FullName); |
89 | 89 |
continue; |
90 | 90 |
} |
91 |
- wcscpy(fd->Name,FullName); |
|
91 |
+ wcsncpyz(fd->Name,FullName,ASIZE(fd->Name)); |
|
92 | 92 |
break; |
93 | 93 |
} |
94 | 94 |
} |
... | ... |
@@ -14,10 +14,11 @@ |
14 | 14 |
#define SIZEOF_UOHEAD 18 |
15 | 15 |
#define SIZEOF_STREAMHEAD 26 |
16 | 16 |
|
17 |
-#define VER_PACK 29 |
|
18 |
-#define VER_PACK5 50 // It is stored as 0, but we subtract 50 when saving an archive. |
|
19 |
-#define VER_UNPACK 29 |
|
20 |
-#define VER_UNPACK5 50 // It is stored as 0, but we add 50 when reading an archive. |
|
17 |
+#define VER_PACK 29U |
|
18 |
+#define VER_PACK5 50U // It is stored as 0, but we subtract 50 when saving an archive. |
|
19 |
+#define VER_UNPACK 29U |
|
20 |
+#define VER_UNPACK5 50U // It is stored as 0, but we add 50 when reading an archive. |
|
21 |
+#define VER_UNKNOWN 9999U // Just some large value. |
|
21 | 22 |
|
22 | 23 |
#define MHD_VOLUME 0x0001U |
23 | 24 |
|
... | ... |
@@ -174,7 +175,7 @@ struct MainHeader:BaseBlock |
174 | 174 |
struct FileHeader:BlockHeader |
175 | 175 |
{ |
176 | 176 |
byte HostOS; |
177 |
- byte UnpVer; |
|
177 |
+ uint UnpVer; // It is 1 byte in RAR29 and bit field in RAR5. |
|
178 | 178 |
byte Method; |
179 | 179 |
union { |
180 | 180 |
uint FileAttr; |
... | ... |
@@ -190,7 +191,7 @@ struct FileHeader:BlockHeader |
190 | 190 |
|
191 | 191 |
int64 PackSize; |
192 | 192 |
int64 UnpSize; |
193 |
- int64 MaxSize; // Reserve size bytes for vint of this size. |
|
193 |
+ int64 MaxSize; // Reserve packed and unpacked size bytes for vint of this size. |
|
194 | 194 |
|
195 | 195 |
HashValue FileHash; |
196 | 196 |
|
... | ... |
@@ -71,6 +71,7 @@ void ListArchive(CommandData *Cmd) |
71 | 71 |
*VolNumText=0; |
72 | 72 |
while(Arc.ReadHeader()>0) |
73 | 73 |
{ |
74 |
+ Wait(); // Allow quit listing with Ctrl+C. |
|
74 | 75 |
HEADER_TYPE HeaderType=Arc.GetHeaderType(); |
75 | 76 |
if (HeaderType==HEAD_ENDARC) |
76 | 77 |
{ |
... | ... |
@@ -91,7 +92,7 @@ void ListArchive(CommandData *Cmd) |
91 | 91 |
switch(HeaderType) |
92 | 92 |
{ |
93 | 93 |
case HEAD_FILE: |
94 |
- FileMatched=Cmd->IsProcessFile(Arc.FileHead)!=0; |
|
94 |
+ FileMatched=Cmd->IsProcessFile(Arc.FileHead,NULL,MATCH_WILDSUBPATH,0,NULL,0)!=0; |
|
95 | 95 |
if (FileMatched) |
96 | 96 |
{ |
97 | 97 |
ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare); |
... | ... |
@@ -215,7 +216,7 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo |
215 | 215 |
|
216 | 216 |
wchar UnpSizeText[30],PackSizeText[30]; |
217 | 217 |
if (hd.UnpSize==INT64NDF) |
218 |
- wcscpy(UnpSizeText,L"?"); |
|
218 |
+ wcsncpyz(UnpSizeText,L"?",ASIZE(UnpSizeText)); |
|
219 | 219 |
else |
220 | 220 |
itoa(hd.UnpSize,UnpSizeText,ASIZE(UnpSizeText)); |
221 | 221 |
itoa(hd.PackSize,PackSizeText,ASIZE(PackSizeText)); |
... | ... |
@@ -229,13 +230,13 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo |
229 | 229 |
wchar RatioStr[10]; |
230 | 230 |
|
231 | 231 |
if (hd.SplitBefore && hd.SplitAfter) |
232 |
- wcscpy(RatioStr,L"<->"); |
|
232 |
+ wcsncpyz(RatioStr,L"<->",ASIZE(RatioStr)); |
|
233 | 233 |
else |
234 | 234 |
if (hd.SplitBefore) |
235 |
- wcscpy(RatioStr,L"<--"); |
|
235 |
+ wcsncpyz(RatioStr,L"<--",ASIZE(RatioStr)); |
|
236 | 236 |
else |
237 | 237 |
if (hd.SplitAfter) |
238 |
- wcscpy(RatioStr,L"-->"); |
|
238 |
+ wcsncpyz(RatioStr,L"-->",ASIZE(RatioStr)); |
|
239 | 239 |
else |
240 | 240 |
swprintf(RatioStr,ASIZE(RatioStr),L"%d%%",ToPercentUnlim(hd.PackSize,hd.UnpSize)); |
241 | 241 |
|
... | ... |
@@ -344,7 +345,8 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo |
344 | 344 |
mprintf(L"\n%12ls: %ls",St(MListHostOS),HostOS); |
345 | 345 |
|
346 | 346 |
mprintf(L"\n%12ls: RAR %ls(v%d) -m%d -md=%d%s",St(MListCompInfo), |
347 |
- Format==RARFMT15 ? L"3.0":L"5.0",hd.UnpVer,hd.Method, |
|
347 |
+ Format==RARFMT15 ? L"3.0":L"5.0", |
|
348 |
+ hd.UnpVer==VER_UNKNOWN ? 0 : hd.UnpVer,hd.Method, |
|
348 | 349 |
hd.WinSize>=0x100000 ? hd.WinSize/0x100000:hd.WinSize/0x400, |
349 | 350 |
hd.WinSize>=0x100000 ? L"M":L"K"); |
350 | 351 |
|
... | ... |
@@ -466,7 +468,7 @@ void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSiz |
466 | 466 |
(A & 0x0001) ? ((A & 0x200)!=0 ? 't' : 'x') : '-'); |
467 | 467 |
break; |
468 | 468 |
case HSYS_UNKNOWN: |
469 |
- wcscpy(AttrStr,L"?"); |
|
469 |
+ wcsncpyz(AttrStr,L"?",AttrSize); |
|
470 | 470 |
break; |
471 | 471 |
} |
472 | 472 |
} |
... | ... |
@@ -85,7 +85,7 @@ |
85 | 85 |
#define MCHelpSwILOG L"\n ilog[name] Log errors to file" |
86 | 86 |
#define MCHelpSwINUL L"\n inul Disable all messages" |
87 | 87 |
#define MCHelpSwIOFF L"\n ioff[n] Turn PC off after completing an operation" |
88 |
-#define MCHelpSwISND L"\n isnd Enable sound" |
|
88 |
+#define MCHelpSwISND L"\n isnd[-] Control notification sounds" |
|
89 | 89 |
#define MCHelpSwIVER L"\n iver Display the version number" |
90 | 90 |
#define MCHelpSwK L"\n k Lock archive" |
91 | 91 |
#define MCHelpSwKB L"\n kb Keep broken extracted files" |
... | ... |
@@ -127,11 +127,11 @@ |
127 | 127 |
#define MCHelpSwT L"\n t Test files after archiving" |
128 | 128 |
#define MCHelpSwTK L"\n tk Keep original archive time" |
129 | 129 |
#define MCHelpSwTL L"\n tl Set archive time to latest file" |
130 |
-#define MCHelpSwTN L"\n tn<time> Process files newer than <time>" |
|
131 |
-#define MCHelpSwTO L"\n to<time> Process files older than <time>" |
|
132 |
-#define MCHelpSwTA L"\n ta<date> Process files modified after <date> in YYYYMMDDHHMMSS format" |
|
133 |
-#define MCHelpSwTB L"\n tb<date> Process files modified before <date> in YYYYMMDDHHMMSS format" |
|
134 |
-#define MCHelpSwTS L"\n ts[m|c|a] Save or restore file time (modification, creation, access)" |
|
130 |
+#define MCHelpSwTN L"\n tn[mcao]<t> Process files newer than <t> time" |
|
131 |
+#define MCHelpSwTO L"\n to[mcao]<t> Process files older than <t> time" |
|
132 |
+#define MCHelpSwTA L"\n ta[mcao]<d> Process files modified after <d> YYYYMMDDHHMMSS date" |
|
133 |
+#define MCHelpSwTB L"\n tb[mcao]<d> Process files modified before <d> YYYYMMDDHHMMSS date" |
|
134 |
+#define MCHelpSwTS L"\n ts[m,c,a] Save or restore file time (modification, creation, access)" |
|
135 | 135 |
#define MCHelpSwU L"\n u Update files" |
136 | 136 |
#define MCHelpSwV L"\n v Create volumes with size autodetection or list all volumes" |
137 | 137 |
#define MCHelpSwVUnr L"\n v List all volumes" |
... | ... |
@@ -354,7 +354,7 @@ |
354 | 354 |
#define MCannotDelete L"\nCannot delete %s" |
355 | 355 |
#define MRecycleFailed L"\nCannot move some files and folders to Recycle Bin" |
356 | 356 |
#define MCalcCRC L"\nCalculating the checksum" |
357 |
-#define MTooLargeSFXArc L"\nWARNING: Too large SFX archive. Windows cannot run the executable file exceeding 4 GB." |
|
357 |
+#define MTooLargeSFXArc L"\nToo large SFX archive. Windows cannot run the executable file exceeding 4 GB." |
|
358 | 358 |
#define MCalcCRCAllVol L"\nCalculating checksums of all volumes." |
359 | 359 |
#define MNotEnoughDisk L"\nERROR: Not enough disk space for %s." |
360 | 360 |
#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) |
25 | 25 |
if (CmpMode!=MATCH_NAMES) |
26 | 26 |
{ |
27 | 27 |
size_t WildLength=wcslen(Wildcard); |
28 |
- if (CmpMode!=MATCH_EXACT && CmpMode!=MATCH_EXACTPATH && |
|
28 |
+ if (CmpMode!=MATCH_EXACT && CmpMode!=MATCH_EXACTPATH && CmpMode!=MATCH_ALLWILD && |
|
29 | 29 |
mwcsnicompc(Wildcard,Name,WildLength,ForceCase)==0) |
30 | 30 |
{ |
31 |
- // For all modes except MATCH_NAMES, MATCH_EXACT and MATCH_EXACTPATH |
|
31 |
+ // For all modes except MATCH_NAMES, MATCH_EXACT, MATCH_EXACTPATH, MATCH_ALLWILD, |
|
32 | 32 |
// "path1" mask must match "path1\path2\filename.ext" and "path1" names. |
33 | 33 |
wchar NextCh=Name[WildLength]; |
34 | 34 |
if (NextCh==L'\\' || NextCh==L'/' || NextCh==0) |
... | ... |
@@ -46,6 +46,8 @@ bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode) |
46 | 46 |
if ((CmpMode==MATCH_EXACT || CmpMode==MATCH_EXACTPATH) && |
47 | 47 |
mwcsicompc(Path1,Path2,ForceCase)!=0) |
48 | 48 |
return(false); |
49 |
+ if (CmpMode==MATCH_ALLWILD) |
|
50 |
+ return match(Wildcard,Name,ForceCase); |
|
49 | 51 |
if (CmpMode==MATCH_SUBPATH || CmpMode==MATCH_WILDSUBPATH) |
50 | 52 |
if (IsWildcard(Path1)) |
51 | 53 |
return(match(Wildcard,Name,ForceCase)); |
... | ... |
@@ -64,8 +66,8 @@ bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode) |
64 | 64 |
|
65 | 65 |
// Always return false for RAR temporary files to exclude them |
66 | 66 |
// from archiving operations. |
67 |
- if (mwcsnicompc(L"__rar_",Name2,6,false)==0) |
|
68 |
- return(false); |
|
67 |
+// if (mwcsnicompc(L"__rar_",Name2,6,false)==0) |
|
68 |
+// return(false); |
|
69 | 69 |
|
70 | 70 |
if (CmpMode==MATCH_EXACT) |
71 | 71 |
return(mwcsicompc(Name1,Name2,ForceCase)==0); |
... | ... |
@@ -14,6 +14,10 @@ enum { |
14 | 14 |
MATCH_EXACT, // Paths must match exactly. |
15 | 15 |
// Names must match exactly. |
16 | 16 |
|
17 |
+ MATCH_ALLWILD, // Paths and names are compared using wildcards. |
|
18 |
+ // Unlike MATCH_SUBPATH, paths do not match subdirs |
|
19 |
+ // unless a wildcard tells so. |
|
20 |
+ |
|
17 | 21 |
MATCH_EXACTPATH, // Paths must match exactly. |
18 | 22 |
// Names are compared using wildcards. |
19 | 23 |
|
... | ... |
@@ -12,11 +12,7 @@ enum PATH_EXCL_MODE { |
12 | 12 |
EXCL_SKIPWHOLEPATH, // -ep (exclude the path completely) |
13 | 13 |
EXCL_BASEPATH, // -ep1 (exclude the base part of path) |
14 | 14 |
EXCL_SAVEFULLPATH, // -ep2 (the full path without the disk letter) |
15 |
- EXCL_ABSPATH, // -ep3 (the full path with the disk letter) |
|
16 |
- |
|
17 |
- EXCL_SKIPABSPATH // Works as EXCL_BASEPATH for fully qualified paths |
|
18 |
- // and as EXCL_UNCHANGED for relative paths. |
|
19 |
- // Used by WinRAR GUI only. |
|
15 |
+ EXCL_ABSPATH // -ep3 (the full path with the disk letter) |
|
20 | 16 |
}; |
21 | 17 |
|
22 | 18 |
enum {SOLID_NONE=0,SOLID_NORMAL=1,SOLID_COUNT=2,SOLID_FILEEXT=4, |
... | ... |
@@ -63,11 +59,20 @@ enum SAVECOPY_MODE { |
63 | 63 |
SAVECOPY_DUPLISTEXIT |
64 | 64 |
}; |
65 | 65 |
|
66 |
+enum APPENDARCNAME_MODE |
|
67 |
+{ |
|
68 |
+ APPENDARCNAME_NONE=0,APPENDARCNAME_DESTPATH,APPENDARCNAME_OWNDIR |
|
69 |
+}; |
|
70 |
+ |
|
66 | 71 |
enum POWER_MODE { |
67 | 72 |
POWERMODE_KEEP=0,POWERMODE_OFF,POWERMODE_HIBERNATE,POWERMODE_SLEEP, |
68 | 73 |
POWERMODE_RESTART |
69 | 74 |
}; |
70 | 75 |
|
76 |
+ |
|
77 |
+// Need "forced off" state to turn off sound in GUI command line. |
|
78 |
+enum SOUND_NOTIFY_MODE {SOUND_NOTIFY_DEFAULT=0,SOUND_NOTIFY_ON,SOUND_NOTIFY_OFF}; |
|
79 |
+ |
|
71 | 80 |
struct FilterMode |
72 | 81 |
{ |
73 | 82 |
FilterState State; |
... | ... |
@@ -112,7 +117,7 @@ class RAROptions |
112 | 112 |
|
113 | 113 |
wchar LogName[NM]; |
114 | 114 |
MESSAGE_TYPE MsgStream; |
115 |
- bool Sound; |
|
115 |
+ SOUND_NOTIFY_MODE Sound; |
|
116 | 116 |
OVERWRITE_MODE Overwrite; |
117 | 117 |
int Method; |
118 | 118 |
HASH_TYPE HashType; |
... | ... |
@@ -163,8 +168,10 @@ class RAROptions |
163 | 163 |
bool SaveStreams; |
164 | 164 |
bool SetCompressedAttr; |
165 | 165 |
bool IgnoreGeneralAttr; |
166 |
- RarTime FileTimeBefore; |
|
167 |
- RarTime FileTimeAfter; |
|
166 |
+ RarTime FileMtimeBefore,FileCtimeBefore,FileAtimeBefore; |
|
167 |
+ bool FileMtimeBeforeOR,FileCtimeBeforeOR,FileAtimeBeforeOR; |
|
168 |
+ RarTime FileMtimeAfter,FileCtimeAfter,FileAtimeAfter; |
|
169 |
+ bool FileMtimeAfterOR,FileCtimeAfterOR,FileAtimeAfterOR; |
|
168 | 170 |
int64 FileSizeLess; |
169 | 171 |
int64 FileSizeMore; |
170 | 172 |
bool Lock; |
... | ... |
@@ -173,9 +180,9 @@ class RAROptions |
173 | 173 |
FilterMode FilterModes[MAX_FILTER_TYPES]; |
174 | 174 |
wchar EmailTo[NM]; |
175 | 175 |
uint VersionControl; |
176 |
- bool AppendArcNameToPath; |
|
176 |
+ APPENDARCNAME_MODE AppendArcNameToPath; |
|
177 | 177 |
POWER_MODE Shutdown; |
178 |
- EXTTIME_MODE xmtime; |
|
178 |
+ EXTTIME_MODE xmtime; // Extended time modes (time precision to store). |
|
179 | 179 |
EXTTIME_MODE xctime; |
180 | 180 |
EXTTIME_MODE xatime; |
181 | 181 |
wchar CompressStdin[NM]; |
... | ... |
@@ -32,7 +32,12 @@ |
32 | 32 |
#define STRICT 1 |
33 | 33 |
#endif |
34 | 34 |
|
35 |
+// 'ifndef' check here is needed for unrar.dll header to avoid macro |
|
36 |
+// re-definition warnings in third party projects. |
|
37 |
+#ifndef UNICODE |
|
35 | 38 |
#define UNICODE |
39 |
+#endif |
|
40 |
+ |
|
36 | 41 |
#undef WINVER |
37 | 42 |
#undef _WIN32_WINNT |
38 | 43 |
#define WINVER 0x0501 |
... | ... |
@@ -16,7 +16,7 @@ wchar* PointToLastChar(const wchar *Path) |
16 | 16 |
} |
17 | 17 |
|
18 | 18 |
|
19 |
-wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath) |
|
19 |
+wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath,size_t DestSize) |
|
20 | 20 |
{ |
21 | 21 |
const wchar *DestPtr=SrcPath; |
22 | 22 |
|
... | ... |
@@ -25,7 +25,7 @@ wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath) |
25 | 25 |
if (IsPathDiv(s[0]) && s[1]=='.' && s[2]=='.' && IsPathDiv(s[3])) |
26 | 26 |
DestPtr=s+4; |
27 | 27 |
|
28 |
- // Remove <d>:\ and any sequence of . and \ in the beginning of path string. |
|
28 |
+ // Remove any amount of <d>:\ and any sequence of . and \ in the beginning of path string. |
|
29 | 29 |
while (*DestPtr!=0) |
30 | 30 |
{ |
31 | 31 |
const wchar *s=DestPtr; |
... | ... |
@@ -58,7 +58,7 @@ wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath) |
58 | 58 |
// so we use the temporary buffer for copying. |
59 | 59 |
wchar TmpStr[NM]; |
60 | 60 |
wcsncpyz(TmpStr,DestPtr,ASIZE(TmpStr)); |
61 |
- wcscpy(DestPath,TmpStr); |
|
61 |
+ wcsncpyz(DestPath,TmpStr,DestSize); |
|
62 | 62 |
} |
63 | 63 |
return (wchar *)DestPtr; |
64 | 64 |
} |
... | ... |
@@ -120,7 +120,14 @@ bool CmpExt(const wchar *Name,const wchar *Ext) |
120 | 120 |
|
121 | 121 |
bool IsWildcard(const wchar *Str) |
122 | 122 |
{ |
123 |
- return Str==NULL ? false:wcspbrk(Str,L"*?")!=NULL; |
|
123 |
+ if (Str==NULL) |
|
124 |
+ return false; |
|
125 |
+#ifdef _WIN_ALL |
|
126 |
+ // Not treat the special NTFS \\?\d: path prefix as a wildcard. |
|
127 |
+ if (Str[0]=='\\' && Str[1]=='\\' && Str[2]=='?' && Str[3]=='\\') |
|
128 |
+ Str+=4; |
|
129 |
+#endif |
|
130 |
+ return wcspbrk(Str,L"*?")!=NULL; |
|
124 | 131 |
} |
125 | 132 |
|
126 | 133 |
|
... | ... |
@@ -163,8 +170,8 @@ int GetPathDisk(const wchar *Path) |
163 | 163 |
void AddEndSlash(wchar *Path,size_t MaxLength) |
164 | 164 |
{ |
165 | 165 |
size_t Length=wcslen(Path); |
166 |
- if (Length>0 && Path[Length-1]!=CPATHDIVIDER && Length+1<MaxLength) |
|
167 |
- wcscat(Path,SPATHDIVIDER); |
|
166 |
+ if (Length>0 && Path[Length-1]!=CPATHDIVIDER) |
|
167 |
+ wcsncatz(Path,SPATHDIVIDER,MaxLength); |
|
168 | 168 |
} |
169 | 169 |
|
170 | 170 |
|
... | ... |
@@ -303,9 +310,13 @@ void GetConfigName(const wchar *Name,wchar *FullName,size_t MaxSize,bool CheckEx |
303 | 303 |
#endif |
304 | 304 |
|
305 | 305 |
|
306 |
-// Returns a pointer to rightmost digit of volume number. |
|
306 |
+// Returns a pointer to rightmost digit of volume number or to beginning |
|
307 |
+// of file name if numeric part is missing. |
|
307 | 308 |
wchar* GetVolNumPart(const wchar *ArcName) |
308 | 309 |
{ |
310 |
+ if (*ArcName==0) |
|
311 |
+ return (wchar *)ArcName; |
|
312 |
+ |
|
309 | 313 |
// Pointing to last name character. |
310 | 314 |
const wchar *ChPtr=ArcName+wcslen(ArcName)-1; |
311 | 315 |
|
... | ... |
@@ -346,18 +357,33 @@ void NextVolumeName(wchar *ArcName,uint MaxLength,bool OldNumbering) |
346 | 346 |
ChPtr=GetExt(ArcName); |
347 | 347 |
} |
348 | 348 |
else |
349 |
- if (ChPtr[1]==0 && wcslen(ArcName)<MaxLength-3 || wcsicomp(ChPtr+1,L"exe")==0 || wcsicomp(ChPtr+1,L"sfx")==0) |
|
350 |
- wcscpy(ChPtr+1,L"rar"); |
|
349 |
+ if (ChPtr[1]==0 || wcsicomp(ChPtr,L".exe")==0 || wcsicomp(ChPtr,L".sfx")==0) |
|
350 |
+ wcsncpyz(ChPtr,L".rar",MaxLength-(ChPtr-ArcName)); |
|
351 |
+ |
|
352 |
+ if (ChPtr==NULL || *ChPtr!='.' || ChPtr[1]==0) |
|
353 |
+ { |
|
354 |
+ // Normally we shall have some extension here. If we don't, it means |
|
355 |
+ // the name has no extension and buffer has no free space to append one. |
|
356 |
+ // Let's clear the name to prevent a new call with same name and return. |
|
357 |
+ *ArcName=0; |
|
358 |
+ return; |
|
359 |
+ } |
|
360 |
+ |
|
351 | 361 |
if (!OldNumbering) |
352 | 362 |
{ |
353 | 363 |
ChPtr=GetVolNumPart(ArcName); |
354 | 364 |
|
365 |
+ // We should not check for IsDigit(*ChPtr) here and should increment |
|
366 |
+ // even non-digits. If we got a corrupt archive with volume flag, |
|
367 |
+ // but without numeric part, we still need to modify its name somehow, |
|
368 |
+ // so while (exist(name)) {NextVolumeName()} loops do not run infinitely. |
|
355 | 369 |
while ((++(*ChPtr))=='9'+1) |
356 | 370 |
{ |
357 | 371 |
*ChPtr='0'; |
358 | 372 |
ChPtr--; |
359 | 373 |
if (ChPtr<ArcName || !IsDigit(*ChPtr)) |
360 | 374 |
{ |
375 |
+ // Convert .part:.rar (.part9.rar after increment) to part10.rar. |
|
361 | 376 |
for (wchar *EndPtr=ArcName+wcslen(ArcName);EndPtr!=ChPtr;EndPtr--) |
362 | 377 |
*(EndPtr+1)=*EndPtr; |
363 | 378 |
*(ChPtr+1)='1'; |
... | ... |
@@ -366,15 +392,15 @@ void NextVolumeName(wchar *ArcName,uint MaxLength,bool OldNumbering) |
366 | 366 |
} |
367 | 367 |
} |
368 | 368 |
else |
369 |
- if (!IsDigit(*(ChPtr+2)) || !IsDigit(*(ChPtr+3))) |
|
370 |
- wcscpy(ChPtr+2,L"00"); |
|
369 |
+ if (!IsDigit(ChPtr[2]) || !IsDigit(ChPtr[3])) |
|
370 |
+ wcsncpyz(ChPtr+2,L"00",MaxLength-(ChPtr-ArcName)-2); // From .rar to .r00. |
|
371 | 371 |
else |
372 | 372 |
{ |
373 |
- ChPtr+=3; |
|
374 |
- while ((++(*ChPtr))=='9'+1) |
|
375 |
- if (*(ChPtr-1)=='.') |
|
373 |
+ ChPtr+=wcslen(ChPtr)-1; // Set to last character. |
|
374 |
+ while (++(*ChPtr)=='9'+1) |
|
375 |
+ if (ChPtr<=ArcName || *(ChPtr-1)=='.') |
|
376 | 376 |
{ |
377 |
- *ChPtr='A'; |
|
377 |
+ *ChPtr='a'; // From .999 to .a00 if started from .001 or for too short names. |
|
378 | 378 |
break; |
379 | 379 |
} |
380 | 380 |
else |
... | ... |
@@ -585,8 +611,7 @@ int ParseVersionFileName(wchar *Name,bool Truncate) |
585 | 585 |
wchar *VerText=wcsrchr(Name,';'); |
586 | 586 |
if (VerText!=NULL) |
587 | 587 |
{ |
588 |
- if (Version==0) |
|
589 |
- Version=atoiw(VerText+1); |
|
588 |
+ Version=atoiw(VerText+1); |
|
590 | 589 |
if (Truncate) |
591 | 590 |
*VerText=0; |
592 | 591 |
} |
... | ... |
@@ -652,7 +677,7 @@ wchar* VolNameToFirstName(const wchar *VolName,wchar *FirstName,size_t MaxSize,b |
652 | 652 |
|
653 | 653 |
|
654 | 654 |
#ifndef SFX_MODULE |
655 |
-static void GenArcName(wchar *ArcName,const wchar *GenerateMask,uint ArcNumber,bool &ArcNumPresent) |
|
655 |
+static void GenArcName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,uint ArcNumber,bool &ArcNumPresent) |
|
656 | 656 |
{ |
657 | 657 |
bool Prefix=false; |
658 | 658 |
if (*GenerateMask=='+') |
... | ... |
@@ -713,7 +738,7 @@ static void GenArcName(wchar *ArcName,const wchar *GenerateMask,uint ArcNumber,b |
713 | 713 |
wchar Ext[NM],*Dot=GetExt(ArcName); |
714 | 714 |
*Ext=0; |
715 | 715 |
if (Dot==NULL) |
716 |
- wcscpy(Ext,*PointToName(ArcName)==0 ? L".rar":L""); |
|
716 |
+ wcsncpyz(Ext,*PointToName(ArcName)==0 ? L".rar":L"",ASIZE(Ext)); |
|
717 | 717 |
else |
718 | 718 |
{ |
719 | 719 |
wcsncpyz(Ext,Dot,ASIZE(Ext)); |
... | ... |
@@ -749,7 +774,7 @@ static void GenArcName(wchar *ArcName,const wchar *GenerateMask,uint ArcNumber,b |
749 | 749 |
int CField[sizeof(Field)/sizeof(Field[0])]; |
750 | 750 |
memset(CField,0,sizeof(CField)); |
751 | 751 |
QuoteMode=false; |
752 |
- for (int I=0;Mask[I]!=0;I++) |
|
752 |
+ for (uint I=0;Mask[I]!=0;I++) |
|
753 | 753 |
{ |
754 | 754 |
if (Mask[I]=='{' || Mask[I]=='}') |
755 | 755 |
{ |
... | ... |
@@ -810,21 +835,17 @@ static void GenArcName(wchar *ArcName,const wchar *GenerateMask,uint ArcNumber,b |
810 | 810 |
AddEndSlash(NewName,ASIZE(NewName)); |
811 | 811 |
wcsncatz(NewName,DateText,ASIZE(NewName)); |
812 | 812 |
wcsncatz(NewName,PointToName(ArcName),ASIZE(NewName)); |
813 |
- wcscpy(ArcName,NewName); |
|
813 |
+ wcsncpyz(ArcName,NewName,MaxSize); |
|
814 | 814 |
} |
815 | 815 |
else |
816 |
- wcscat(ArcName,DateText); |
|
817 |
- wcscat(ArcName,Ext); |
|
816 |
+ wcsncatz(ArcName,DateText,MaxSize); |
|
817 |
+ wcsncatz(ArcName,Ext,MaxSize); |
|
818 | 818 |
} |
819 | 819 |
|
820 | 820 |
|
821 | 821 |
void GenerateArchiveName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,bool Archiving) |
822 | 822 |
{ |
823 |
- // Must be enough space for archive name plus all stuff in mask plus |
|
824 |
- // extra overhead produced by mask 'N' (archive number) characters. |
|
825 |
- // One 'N' character can result in several numbers if we process more |
|
826 |
- // than 9 archives. |
|
827 |
- wchar NewName[NM+MAX_GENERATE_MASK+20]; |
|
823 |
+ wchar NewName[NM]; |
|
828 | 824 |
|
829 | 825 |
uint ArcNumber=1; |
830 | 826 |
while (true) // Loop for 'N' (archive number) processing. |
... | ... |
@@ -833,7 +854,7 @@ void GenerateArchiveName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask |
833 | 833 |
|
834 | 834 |
bool ArcNumPresent=false; |
835 | 835 |
|
836 |
- GenArcName(NewName,GenerateMask,ArcNumber,ArcNumPresent); |
|
836 |
+ GenArcName(NewName,ASIZE(NewName),GenerateMask,ArcNumber,ArcNumPresent); |
|
837 | 837 |
|
838 | 838 |
if (!ArcNumPresent) |
839 | 839 |
break; |
... | ... |
@@ -845,7 +866,7 @@ void GenerateArchiveName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask |
845 | 845 |
// existing archive before the first unused name. So we generate |
846 | 846 |
// the name for (ArcNumber-1) below. |
847 | 847 |
wcsncpyz(NewName,NullToEmpty(ArcName),ASIZE(NewName)); |
848 |
- GenArcName(NewName,GenerateMask,ArcNumber-1,ArcNumPresent); |
|
848 |
+ GenArcName(NewName,ASIZE(NewName),GenerateMask,ArcNumber-1,ArcNumPresent); |
|
849 | 849 |
} |
850 | 850 |
break; |
851 | 851 |
} |
... | ... |
@@ -895,8 +916,8 @@ bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize) |
895 | 895 |
{ |
896 | 896 |
if (MaxSize<=PrefixLength+SrcLength) |
897 | 897 |
return false; |
898 |
- wcsncpy(Dest,Prefix,PrefixLength); |
|
899 |
- wcscpy(Dest+PrefixLength,Src); |
|
898 |
+ wcsncpyz(Dest,Prefix,MaxSize); |
|
899 |
+ wcsncatz(Dest,Src,MaxSize); // "\\?\D:\very long path". |
|
900 | 900 |
return true; |
901 | 901 |
} |
902 | 902 |
else |
... | ... |
@@ -904,9 +925,9 @@ bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize) |
904 | 904 |
{ |
905 | 905 |
if (MaxSize<=PrefixLength+SrcLength+2) |
906 | 906 |
return false; |
907 |
- wcsncpy(Dest,Prefix,PrefixLength); |
|
908 |
- wcscpy(Dest+PrefixLength,L"UNC"); |
|
909 |
- wcscpy(Dest+PrefixLength+3,Src+1); |
|
907 |
+ wcsncpyz(Dest,Prefix,MaxSize); |
|
908 |
+ wcsncatz(Dest,L"UNC",MaxSize); |
|
909 |
+ wcsncatz(Dest,Src+1,MaxSize); // "\\?\UNC\server\share". |
|
910 | 910 |
return true; |
911 | 911 |
} |
912 | 912 |
// 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) |
923 | 923 |
{ |
924 | 924 |
if (MaxSize<=PrefixLength+SrcLength+2) |
925 | 925 |
return false; |
926 |
- wcsncpy(Dest,Prefix,PrefixLength); |
|
927 |
- wcsncpy(Dest+PrefixLength,CurDir,2); // Copy drive letter 'd:'. |
|
928 |
- wcscpy(Dest+PrefixLength+2,Src); |
|
926 |
+ wcsncpyz(Dest,Prefix,MaxSize); |
|
927 |
+ CurDir[2]=0; |
|
928 |
+ wcsncatz(Dest,CurDir,MaxSize); // Copy drive letter 'd:'. |
|
929 |
+ wcsncatz(Dest,Src,MaxSize); |
|
929 | 930 |
return true; |
930 | 931 |
} |
931 | 932 |
else // Paths in path\name format. |
... | ... |
@@ -933,8 +955,8 @@ bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize) |
933 | 933 |
AddEndSlash(CurDir,ASIZE(CurDir)); |
934 | 934 |
if (MaxSize<=PrefixLength+wcslen(CurDir)+SrcLength) |
935 | 935 |
return false; |
936 |
- wcsncpy(Dest,Prefix,PrefixLength); |
|
937 |
- wcscpy(Dest+PrefixLength,CurDir); |
|
936 |
+ wcsncpyz(Dest,Prefix,MaxSize); |
|
937 |
+ wcsncatz(Dest,CurDir,MaxSize); |
|
938 | 938 |
|
939 | 939 |
if (Src[0]=='.' && IsPathDiv(Src[1])) // Remove leading .\ in pathname. |
940 | 940 |
Src+=2; |
... | ... |
@@ -3,7 +3,7 @@ |
3 | 3 |
|
4 | 4 |
wchar* PointToName(const wchar *Path); |
5 | 5 |
wchar* PointToLastChar(const wchar *Path); |
6 |
-wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath); |
|
6 |
+wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath,size_t DestSize); |
|
7 | 7 |
void SetName(wchar *FullName,const wchar *Name,size_t MaxSize); |
8 | 8 |
void SetExt(wchar *Name,const wchar *NewExt,size_t MaxSize); |
9 | 9 |
void SetSFXExt(wchar *SFXName,size_t MaxSize); |
... | ... |
@@ -84,7 +84,7 @@ void QuickOpen::Load(uint64 BlockPos) |
84 | 84 |
if (ReadSize==0 || Arc->GetHeaderType()!=HEAD_SERVICE || |
85 | 85 |
!Arc->SubHead.CmpName(SUBHEAD_TYPE_QOPEN)) |
86 | 86 |
return; |
87 |
- QLHeaderPos=Arc->CurBlockPos; |
|
87 |
+ QOHeaderPos=Arc->CurBlockPos; |
|
88 | 88 |
RawDataStart=Arc->Tell(); |
89 | 89 |
RawDataSize=Arc->SubHead.UnpSize; |
90 | 90 |
|
... | ... |
@@ -172,7 +172,7 @@ bool QuickOpen::Seek(int64 Offset,int Method) |
172 | 172 |
// archive updating involve several passes. So if we detect that file |
173 | 173 |
// pointer is moved back, we reload quick open data from beginning. |
174 | 174 |
if (Method==SEEK_SET && (uint64)Offset<SeekPos && (uint64)Offset<LastReadHeaderPos) |
175 |
- Load(QLHeaderPos); |
|
175 |
+ Load(QOHeaderPos); |
|
176 | 176 |
|
177 | 177 |
if (Method==SEEK_SET) |
178 | 178 |
SeekPos=Offset; |
... | ... |
@@ -250,10 +250,10 @@ bool QuickOpen::ReadRaw(RawRead &Raw) |
250 | 250 |
return false; |
251 | 251 |
} |
252 | 252 |
|
253 |
- // If rest of block data crosses buffer boundary, read it in loop. |
|
254 |
- size_t DataLeft=ReadBufSize-ReadBufPos; |
|
253 |
+ // If rest of block data crosses Buf boundary, read it in loop. |
|
255 | 254 |
while (SizeToRead>0) |
256 | 255 |
{ |
256 |
+ size_t DataLeft=ReadBufSize-ReadBufPos; |
|
257 | 257 |
size_t CurSizeToRead=Min(DataLeft,(size_t)SizeToRead); |
258 | 258 |
Raw.Read(Buf+ReadBufPos,CurSizeToRead); |
259 | 259 |
ReadBufPos+=CurSizeToRead; |
... | ... |
@@ -285,6 +285,6 @@ bool QuickOpen::ReadNext() |
285 | 285 |
LastReadHeader.Alloc(HeaderSize); |
286 | 286 |
Raw.GetB(&LastReadHeader[0],HeaderSize); |
287 | 287 |
// Calculate the absolute position as offset from quick open service header. |
288 |
- LastReadHeaderPos=QLHeaderPos-Offset; |
|
288 |
+ LastReadHeaderPos=QOHeaderPos-Offset; |
|
289 | 289 |
return true; |
290 | 290 |
} |
... | ... |
@@ -29,24 +29,24 @@ class QuickOpen |
29 | 29 |
QuickOpenItem *ListStart; |
30 | 30 |
QuickOpenItem *ListEnd; |
31 | 31 |
|
32 |
- byte *Buf; |
|
33 |
- static const size_t MaxBufSize=0x10000; // Must be multiple of CRYPT_BLOCK_SIZE. |
|
34 |
- size_t CurBufSize; |
|
32 |
+ byte *Buf; // Read quick open data here. |
|
33 |
+ static const size_t MaxBufSize=0x10000; // Buf size, must be multiple of CRYPT_BLOCK_SIZE. |
|
34 |
+ size_t CurBufSize; // Current size of buffered data in write mode. |
|
35 | 35 |
#ifndef RAR_NOCRYPT // For shell extension. |
36 | 36 |
CryptData Crypt; |
37 | 37 |
#endif |
38 | 38 |
|
39 | 39 |
bool Loaded; |
40 |
- uint64 QLHeaderPos; |
|
41 |
- uint64 RawDataStart; |
|
42 |
- uint64 RawDataSize; |
|
43 |
- uint64 RawDataPos; |
|
44 |
- size_t ReadBufSize; |
|
45 |
- size_t ReadBufPos; |
|
40 |
+ uint64 QOHeaderPos; // Main QO header position. |
|
41 |
+ uint64 RawDataStart; // Start of QO data, just after the main header. |
|
42 |
+ uint64 RawDataSize; // Size of entire QO data. |
|
43 |
+ uint64 RawDataPos; // Current read position in QO data. |
|
44 |
+ size_t ReadBufSize; // Size of Buf data currently read from QO. |
|
45 |
+ size_t ReadBufPos; // Current read position in Buf data. |
|
46 | 46 |
Array<byte> LastReadHeader; |
47 | 47 |
uint64 LastReadHeaderPos; |
48 | 48 |
uint64 SeekPos; |
49 |
- bool UnsyncSeekPos; // QOpen SeekPos does not match an actual file pointer. |
|
49 |
+ bool UnsyncSeekPos; // QOpen SeekPos does not match an actual file pointer. |
|
50 | 50 |
public: |
51 | 51 |
QuickOpen(); |
52 | 52 |
~QuickOpen(); |
... | ... |
@@ -37,7 +37,7 @@ int main(int argc, char *argv[]) |
37 | 37 |
|
38 | 38 |
CommandData *Cmd=new CommandData; |
39 | 39 |
#ifdef SFX_MODULE |
40 |
- wcscpy(Cmd->Command,L"X"); |
|
40 |
+ wcsncpyz(Cmd->Command,L"X",ASIZE(Cmd->Command)); |
|
41 | 41 |
char *Switch=argc>1 ? argv[1]:NULL; |
42 | 42 |
if (Switch!=NULL && Cmd->IsSwitch(Switch[0])) |
43 | 43 |
{ |
... | ... |
@@ -68,6 +68,8 @@ int main(int argc, char *argv[]) |
68 | 68 |
|
69 | 69 |
#if defined(_WIN_ALL) && !defined(SFX_MODULE) |
70 | 70 |
ShutdownOnClose=Cmd->Shutdown; |
71 |
+ if (ShutdownOnClose) |
|
72 |
+ ShutdownCheckAnother(true); |
|
71 | 73 |
#endif |
72 | 74 |
|
73 | 75 |
uiInit(Cmd->Sound); |
... | ... |
@@ -93,7 +95,8 @@ int main(int argc, char *argv[]) |
93 | 93 |
} |
94 | 94 |
|
95 | 95 |
#if defined(_WIN_ALL) && !defined(SFX_MODULE) |
96 |
- if (ShutdownOnClose!=POWERMODE_KEEP && ErrHandler.IsShutdownEnabled()) |
|
96 |
+ if (ShutdownOnClose!=POWERMODE_KEEP && ErrHandler.IsShutdownEnabled() && |
|
97 |
+ !ShutdownCheckAnother(false)) |
|
97 | 98 |
Shutdown(ShutdownOnClose); |
98 | 99 |
#endif |
99 | 100 |
ErrHandler.MainExit=true; |
... | ... |
@@ -111,7 +111,7 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) |
111 | 111 |
NewStyle=IsNewStyleRev(ArcName); |
112 | 112 |
while (Ext>ArcName+1 && (IsDigit(*(Ext-1)) || *(Ext-1)=='_')) |
113 | 113 |
Ext--; |
114 |
- wcscpy(Ext,L"*.*"); |
|
114 |
+ wcsncpyz(Ext,L"*.*",ASIZE(ArcName)-(Ext-ArcName)); |
|
115 | 115 |
|
116 | 116 |
FindFile Find; |
117 | 117 |
Find.SetMask(ArcName); |
... | ... |
@@ -235,7 +235,7 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) |
235 | 235 |
} |
236 | 236 |
RecVolNumber=P[1]; |
237 | 237 |
FileNumber=P[2]; |
238 |
- wcscpy(PrevName,CurName); |
|
238 |
+ wcsncpyz(PrevName,CurName,ASIZE(PrevName)); |
|
239 | 239 |
File *NewFile=new File; |
240 | 240 |
NewFile->TOpen(CurName); |
241 | 241 |
SrcFile[FileNumber+P[0]-1]=NewFile; |
... | ... |
@@ -247,7 +247,7 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) |
247 | 247 |
if (!Silent || FoundRecVolumes!=0) |
248 | 248 |
uiMsg(UIMSG_RECVOLFOUND,FoundRecVolumes); |
249 | 249 |
if (FoundRecVolumes==0) |
250 |
- return(false); |
|
250 |
+ return false; |
|
251 | 251 |
|
252 | 252 |
bool WriteFlags[256]; |
253 | 253 |
memset(WriteFlags,0,sizeof(WriteFlags)); |
... | ... |
@@ -290,8 +290,8 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) |
290 | 290 |
{ |
291 | 291 |
NewFile->Close(); |
292 | 292 |
wchar NewName[NM]; |
293 |
- wcscpy(NewName,ArcName); |
|
294 |
- wcscat(NewName,L".bad"); |
|
293 |
+ wcsncpyz(NewName,ArcName,ASIZE(NewName)); |
|
294 |
+ wcsncatz(NewName,L".bad",ASIZE(NewName)); |
|
295 | 295 |
|
296 | 296 |
uiMsg(UIMSG_BADARCHIVE,ArcName); |
297 | 297 |
uiMsg(UIMSG_RENAMING,ArcName,NewName); |
... | ... |
@@ -322,7 +322,7 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) |
322 | 322 |
MissingVolumes++; |
323 | 323 |
|
324 | 324 |
if (CurArcNum==FileNumber-1) |
325 |
- wcscpy(LastVolName,ArcName); |
|
325 |
+ wcsncpyz(LastVolName,ArcName,ASIZE(LastVolName)); |
|
326 | 326 |
|
327 | 327 |
uiMsg(UIMSG_MISSINGVOL,ArcName); |
328 | 328 |
uiMsg(UIEVENT_NEWARCHIVE,ArcName); |
... | ... |
@@ -139,12 +139,10 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) |
139 | 139 |
wcsncpyz(ArcName,Name,ASIZE(ArcName)); |
140 | 140 |
|
141 | 141 |
wchar *Num=GetVolNumPart(ArcName); |
142 |
- if (Num==ArcName) |
|
143 |
- return false; // Number part is missing in the name. |
|
144 | 142 |
while (Num>ArcName && IsDigit(*(Num-1))) |
145 | 143 |
Num--; |
146 | 144 |
if (Num==ArcName) |
147 |
- return false; // Entire volume name is numeric, not possible for REV file. |
|
145 |
+ return false; // Numeric part is missing or entire volume name is numeric, not possible for RAR or REV volume. |
|
148 | 146 |
wcsncpyz(Num,L"*.*",ASIZE(ArcName)-(Num-ArcName)); |
149 | 147 |
|
150 | 148 |
wchar FirstVolName[NM]; |
... | ... |
@@ -289,8 +287,8 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) |
289 | 289 |
Item->f->Close(); |
290 | 290 |
|
291 | 291 |
wchar NewName[NM]; |
292 |
- wcscpy(NewName,Item->Name); |
|
293 |
- wcscat(NewName,L".bad"); |
|
292 |
+ wcsncpyz(NewName,Item->Name,ASIZE(NewName)); |
|
293 |
+ wcsncatz(NewName,L".bad",ASIZE(NewName)); |
|
294 | 294 |
|
295 | 295 |
uiMsg(UIMSG_BADARCHIVE,Item->Name); |
296 | 296 |
uiMsg(UIMSG_RENAMING,Item->Name,NewName); |
... | ... |
@@ -79,7 +79,10 @@ void Rijndael::Init(bool Encrypt,const byte *key,uint keyLen,const byte * initVe |
79 | 79 |
AES_NI=(CPUInfo[2] & 0x2000000)!=0; |
80 | 80 |
#endif |
81 | 81 |
|
82 |
- uint uKeyLenInBytes; |
|
82 |
+ // Other developers asked us to initialize it to suppress "may be used |
|
83 |
+ // uninitialized" warning in code below in some compilers. |
|
84 |
+ uint uKeyLenInBytes=0; |
|
85 |
+ |
|
83 | 86 |
switch(keyLen) |
84 | 87 |
{ |
85 | 88 |
case 128: |
... | ... |
@@ -27,7 +27,7 @@ RSCoder16::~RSCoder16() |
27 | 27 |
delete[] MX; |
28 | 28 |
delete[] ValidFlags; |
29 | 29 |
} |
30 |
- |
|
30 |
+ |
|
31 | 31 |
|
32 | 32 |
// Initialize logarithms and exponents Galois field tables. |
33 | 33 |
void RSCoder16::gfInit() |
... | ... |
@@ -41,7 +41,7 @@ void RSCoder16::gfInit() |
41 | 41 |
gfExp[L]=E; |
42 | 42 |
gfExp[L+gfSize]=E; // Duplicate the table to avoid gfExp overflow check. |
43 | 43 |
E<<=1; |
44 |
- if (E>gfSize) |
|
44 |
+ if (E>gfSize) |
|
45 | 45 |
E^=0x1100B; // Irreducible field-generator polynomial. |
46 | 46 |
} |
47 | 47 |
|
... | ... |
@@ -59,7 +59,7 @@ uint RSCoder16::gfAdd(uint a,uint b) // Addition in Galois field. |
59 | 59 |
} |
60 | 60 |
|
61 | 61 |
|
62 |
-uint RSCoder16::gfMul(uint a,uint b) // Multiplication in Galois field. |
|
62 |
+uint RSCoder16::gfMul(uint a,uint b) // Multiplication in Galois field. |
|
63 | 63 |
{ |
64 | 64 |
return gfExp[gfLog[a]+gfLog[b]]; |
65 | 65 |
} |
... | ... |
@@ -156,7 +156,7 @@ void RSCoder16::InvertDecoderMatrix() |
156 | 156 |
for (uint Kr = 0, Kf = 0; Kr < NE; Kr++, Kf++) |
157 | 157 |
{ |
158 | 158 |
while (ValidFlags[Kf]) // Skip trivial rows. |
159 |
- Kf++; |
|
159 |
+ Kf++; |
|
160 | 160 |
MI[Kr * ND + Kf] = 1; // Set diagonal 1. |
161 | 161 |
} |
162 | 162 |
|
... | ... |
@@ -174,7 +174,7 @@ void RSCoder16::InvertDecoderMatrix() |
174 | 174 |
// after MI[..]^=, but we do not need it for matrix inversion. |
175 | 175 |
for (uint I = 0; I < NE; I++) |
176 | 176 |
MI[I * ND + Kf] ^= MX[I * ND + Kf]; |
177 |
- Kf++; |
|
177 |
+ Kf++; |
|
178 | 178 |
} |
179 | 179 |
|
180 | 180 |
if (Kf == ND) |
... | ... |
@@ -186,14 +186,14 @@ void RSCoder16::InvertDecoderMatrix() |
186 | 186 |
uint PInv = gfInv( MXk[Kf] ); // Pivot inverse. |
187 | 187 |
// Divide the pivot row by pivot, so pivot cell contains 1. |
188 | 188 |
for (uint I = 0; I < ND; I++) |
189 |
- { |
|
189 |
+ { |
|
190 | 190 |
MXk[I] = gfMul( MXk[I], PInv ); |
191 | 191 |
MIk[I] = gfMul( MIk[I], PInv ); |
192 | 192 |
} |
193 | 193 |
|
194 | 194 |
for (uint I = 0; I < NE; I++) |
195 | 195 |
if (I != Kr) // For all rows except containing the pivot cell. |
196 |
- { |
|
196 |
+ { |
|
197 | 197 |
// Apply Gaussian elimination Mij -= Mkj * Mik / pivot. |
198 | 198 |
// Since pivot is already 1, it is reduced to Mij -= Mkj * Mik. |
199 | 199 |
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 |
361 | 361 |
__m128i LowBytes1=_mm_and_si128(D[1],LowByteMask); |
362 | 362 |
__m128i HighBytes=_mm_packus_epi16(HighBytes0,HighBytes1); |
363 | 363 |
__m128i LowBytes=_mm_packus_epi16(LowBytes0,LowBytes1); |
364 |
- |
|
364 |
+ |
|
365 | 365 |
// Multiply bits 0..3 of low bytes. Store low and high product bytes |
366 | 366 |
// separately in cumulative sum variables. |
367 | 367 |
__m128i LowBytesLow4=_mm_and_si128(LowBytes,Low4Mask); |
... | ... |
@@ -377,7 +377,7 @@ bool RSCoder16::SSE_UpdateECC(uint DataNum, uint ECCNum, const byte *Data, byte |
377 | 377 |
// Add new product to existing sum, low and high bytes separately. |
378 | 378 |
LowBytesMultSum=_mm_xor_si128(LowBytesMultSum,LowBytesHigh4MultLow); |
379 | 379 |
HighBytesMultSum=_mm_xor_si128(HighBytesMultSum,LowBytesHigh4MultHigh); |
380 |
- |
|
380 |
+ |
|
381 | 381 |
// Multiply bits 0..3 of high bytes. Store low and high product bytes separately. |
382 | 382 |
__m128i HighBytesLow4=_mm_and_si128(HighBytes,Low4Mask); |
383 | 383 |
__m128i HighBytesLow4MultLow=_mm_shuffle_epi8(T2L,HighBytesLow4); |
... | ... |
@@ -413,7 +413,7 @@ bool RSCoder16::SSE_UpdateECC(uint DataNum, uint ECCNum, const byte *Data, byte |
413 | 413 |
// because Data and ECC can have different alignment offsets. |
414 | 414 |
for (; Pos<BlockSize; Pos+=2) |
415 | 415 |
*(ushort*)(ECC+Pos) ^= gfMul( M, *(ushort*)(Data+Pos) ); |
416 |
- |
|
416 |
+ |
|
417 | 417 |
return true; |
418 | 418 |
} |
419 | 419 |
#endif |
... | ... |
@@ -142,7 +142,12 @@ bool ScanTree::GetFilteredMask() |
142 | 142 |
bool WildcardFound=false; |
143 | 143 |
uint FolderWildcardCount=0; |
144 | 144 |
uint SlashPos=0; |
145 |
- for (int I=0;CurMask[I]!=0;I++) |
|
145 |
+ uint StartPos=0; |
|
146 |
+#ifdef _WIN_ALL // Not treat the special NTFS \\?\d: path prefix as a wildcard. |
|
147 |
+ if (CurMask[0]=='\\' && CurMask[1]=='\\' && CurMask[2]=='?' && CurMask[3]=='\\') |
|
148 |
+ StartPos=4; |
|
149 |
+#endif |
|
150 |
+ for (uint I=StartPos;CurMask[I]!=0;I++) |
|
146 | 151 |
{ |
147 | 152 |
if (CurMask[I]=='?' || CurMask[I]=='*') |
148 | 153 |
WildcardFound=true; |
... | ... |
@@ -171,7 +176,7 @@ bool ScanTree::GetFilteredMask() |
171 | 171 |
|
172 | 172 |
wchar Filter[NM]; |
173 | 173 |
// Convert path\dir*\ to *\dir filter to search for 'dir' in all 'path' subfolders. |
174 |
- wcscpy(Filter,L"*"); |
|
174 |
+ wcsncpyz(Filter,L"*",ASIZE(Filter)); |
|
175 | 175 |
AddEndSlash(Filter,ASIZE(Filter)); |
176 | 176 |
// SlashPos might point or not point to path separator for masks like 'dir*', '\dir*' or 'd:dir*' |
177 | 177 |
wchar *WildName=IsPathDiv(CurMask[SlashPos]) || IsDriveDiv(CurMask[SlashPos]) ? CurMask+SlashPos+1 : CurMask+SlashPos; |
... | ... |
@@ -360,7 +365,7 @@ SCAN_CODE ScanTree::FindProc(FindData *FD) |
360 | 360 |
wcsncpyz(CurMask,Mask+1,ASIZE(CurMask)); |
361 | 361 |
else |
362 | 362 |
{ |
363 |
- *(PrevSlash+1)=0; |
|
363 |
+ *PrevSlash=0; |
|
364 | 364 |
wcsncatz(CurMask,Mask,ASIZE(CurMask)); |
365 | 365 |
} |
366 | 366 |
} |
... | ... |
@@ -64,7 +64,7 @@ class ScanTree |
64 | 64 |
ScanTree(StringList *FileMasks,RECURSE_MODE Recurse,bool GetLinks,SCAN_DIRS GetDirs); |
65 | 65 |
~ScanTree(); |
66 | 66 |
SCAN_CODE GetNext(FindData *FindData); |
67 |
- size_t GetSpecPathLength() {return SpecPathLength;}; |
|
67 |
+ size_t GetSpecPathLength() {return SpecPathLength;} |
|
68 | 68 |
int GetErrors() {return Errors;}; |
69 | 69 |
void SetErrArcName(const wchar *Name) {wcsncpyz(ErrArcName,Name,ASIZE(ErrArcName));} |
70 | 70 |
void SetCommandData(CommandData *Cmd) {ScanTree::Cmd=Cmd;} |
... | ... |
@@ -281,53 +281,49 @@ int wcsnicompc(const wchar *s1,const wchar *s2,size_t n) |
281 | 281 |
} |
282 | 282 |
|
283 | 283 |
|
284 |
-// Safe strncpy: copies maxlen-1 max and always returns zero terminated dest. |
|
285 |
-char* strncpyz(char *dest, const char *src, size_t maxlen) |
|
284 |
+// Safe copy: copies maxlen-1 max and for maxlen>0 returns zero terminated dest. |
|
285 |
+void strncpyz(char *dest, const char *src, size_t maxlen) |
|
286 | 286 |
{ |
287 | 287 |
if (maxlen>0) |
288 | 288 |
{ |
289 |
- strncpy(dest,src,maxlen-1); |
|
290 |
- dest[maxlen-1]=0; |
|
289 |
+ while (--maxlen>0 && *src!=0) |
|
290 |
+ *dest++=*src++; |
|
291 |
+ *dest=0; |
|
291 | 292 |
} |
292 |
- return dest; |
|
293 | 293 |
} |
294 | 294 |
|
295 | 295 |
|
296 |
-// Safe wcsncpy: copies maxlen-1 max and always returns zero terminated dest. |
|
297 |
-wchar* wcsncpyz(wchar *dest, const wchar *src, size_t maxlen) |
|
296 |
+// Safe copy: copies maxlen-1 max and for maxlen>0 returns zero terminated dest. |
|
297 |
+void wcsncpyz(wchar *dest, const wchar *src, size_t maxlen) |
|
298 | 298 |
{ |
299 | 299 |
if (maxlen>0) |
300 | 300 |
{ |
301 |
- wcsncpy(dest,src,maxlen-1); |
|
302 |
- dest[maxlen-1]=0; |
|
301 |
+ while (--maxlen>0 && *src!=0) |
|
302 |
+ *dest++=*src++; |
|
303 |
+ *dest=0; |
|
303 | 304 |
} |
304 |
- return dest; |
|
305 | 305 |
} |
306 | 306 |
|
307 | 307 |
|
308 |
-// Safe strncat: resulting dest length cannot exceed maxlen and dest |
|
309 |
-// is always zero terminated. Note that 'maxlen' parameter defines the entire |
|
310 |
-// dest buffer size and is not compatible with standard strncat. |
|
311 |
-char* strncatz(char* dest, const char* src, size_t maxlen) |
|
308 |
+// Safe append: resulting dest length cannot exceed maxlen and dest |
|
309 |
+// is always zero terminated. 'maxlen' parameter defines the entire |
|
310 |
+// dest buffer size and is not compatible with wcsncat. |
|
311 |
+void strncatz(char* dest, const char* src, size_t maxlen) |
|
312 | 312 |
{ |
313 |
- size_t Length = strlen(dest); |
|
314 |
- int avail=int(maxlen - Length - 1); |
|
315 |
- if (avail > 0) |
|
316 |
- strncat(dest, src, avail); |
|
317 |
- return dest; |
|
313 |
+ size_t length = strlen(dest); |
|
314 |
+ if (maxlen > length) |
|
315 |
+ strncpyz(dest + length, src, maxlen - length); |
|
318 | 316 |
} |
319 | 317 |
|
320 | 318 |
|
321 |
-// Safe wcsncat: resulting dest length cannot exceed maxlen and dest |
|
322 |
-// is always zero terminated. Note that 'maxlen' parameter defines the entire |
|
323 |
-// dest buffer size and is not compatible with standard wcsncat. |
|
324 |
-wchar* wcsncatz(wchar* dest, const wchar* src, size_t maxlen) |
|
319 |
+// Safe append: resulting dest length cannot exceed maxlen and dest |
|
320 |
+// is always zero terminated. 'maxlen' parameter defines the entire |
|
321 |
+// dest buffer size and is not compatible with wcsncat. |
|
322 |
+void wcsncatz(wchar* dest, const wchar* src, size_t maxlen) |
|
325 | 323 |
{ |
326 |
- size_t Length = wcslen(dest); |
|
327 |
- int avail=int(maxlen - Length - 1); |
|
328 |
- if (avail > 0) |
|
329 |
- wcsncat(dest, src, avail); |
|
330 |
- return dest; |
|
324 |
+ size_t length = wcslen(dest); |
|
325 |
+ if (maxlen > length) |
|
326 |
+ wcsncpyz(dest + length, src, maxlen - length); |
|
331 | 327 |
} |
332 | 328 |
|
333 | 329 |
|
... | ... |
@@ -16,10 +16,10 @@ wchar* RemoveLF(wchar *Str); |
16 | 16 |
unsigned char loctolower(unsigned char ch); |
17 | 17 |
unsigned char loctoupper(unsigned char ch); |
18 | 18 |
|
19 |
-char* strncpyz(char *dest, const char *src, size_t maxlen); |
|
20 |
-wchar* wcsncpyz(wchar *dest, const wchar *src, size_t maxlen); |
|
21 |
-char* strncatz(char* dest, const char* src, size_t maxlen); |
|
22 |
-wchar* wcsncatz(wchar* dest, const wchar* src, size_t maxlen); |
|
19 |
+void strncpyz(char *dest, const char *src, size_t maxlen); |
|
20 |
+void wcsncpyz(wchar *dest, const wchar *src, size_t maxlen); |
|
21 |
+void strncatz(char* dest, const char* src, size_t maxlen); |
|
22 |
+void wcsncatz(wchar* dest, const wchar* src, size_t maxlen); |
|
23 | 23 |
|
24 | 24 |
unsigned char etoupper(unsigned char ch); |
25 | 25 |
wchar etoupperw(wchar ch); |
... | ... |
@@ -77,7 +77,7 @@ class SubAllocator |
77 | 77 |
inline void* ExpandUnits(void* ptr,int OldNU); |
78 | 78 |
inline void* ShrinkUnits(void* ptr,int OldNU,int NewNU); |
79 | 79 |
inline void FreeUnits(void* ptr,int OldNU); |
80 |
- long GetAllocatedMemory() {return(SubAllocatorSize);}; |
|
80 |
+ long GetAllocatedMemory() {return(SubAllocatorSize);} |
|
81 | 81 |
|
82 | 82 |
byte *pText, *UnitsStart,*HeapEnd,*FakeUnitsStart; |
83 | 83 |
}; |
... | ... |
@@ -123,6 +123,28 @@ void Shutdown(POWER_MODE Mode) |
123 | 123 |
if (Mode==POWERMODE_RESTART) |
124 | 124 |
ExitWindowsEx(EWX_REBOOT|EWX_FORCE,SHTDN_REASON_FLAG_PLANNED); |
125 | 125 |
} |
126 |
+ |
|
127 |
+ |
|
128 |
+bool ShutdownCheckAnother(bool Open) |
|
129 |
+{ |
|
130 |
+ const wchar *EventName=L"rar -ioff"; |
|
131 |
+ static HANDLE hEvent=NULL; |
|
132 |
+ bool Result=false; // Return false if no other RAR -ioff are running. |
|
133 |
+ if (Open) // Create or open the event. |
|
134 |
+ hEvent=CreateEvent(NULL,FALSE,FALSE,EventName); |
|
135 |
+ else |
|
136 |
+ { |
|
137 |
+ if (hEvent!=NULL) |
|
138 |
+ CloseHandle(hEvent); // Close our event. |
|
139 |
+ // Check if other copies still own the event. While race conditions |
|
140 |
+ // are possible, they are improbable and their harm is minimal. |
|
141 |
+ hEvent=CreateEvent(NULL,FALSE,FALSE,EventName); |
|
142 |
+ Result=GetLastError()==ERROR_ALREADY_EXISTS; |
|
143 |
+ if (hEvent!=NULL) |
|
144 |
+ CloseHandle(hEvent); |
|
145 |
+ } |
|
146 |
+ return Result; |
|
147 |
+} |
|
126 | 148 |
#endif |
127 | 149 |
|
128 | 150 |
|
... | ... |
@@ -53,25 +53,22 @@ static struct GlobalPoolCreateSync |
53 | 53 |
|
54 | 54 |
ThreadPool* CreateThreadPool() |
55 | 55 |
{ |
56 |
+#ifdef RARDLL |
|
57 |
+ // We use a simple thread pool, which does not allow to add tasks from |
|
58 |
+ // different functions and threads in the same time. It is ok for RAR, |
|
59 |
+ // but UnRAR.dll can be used in multithreaded environment. So we return |
|
60 |
+ // a new pool for UnRAR.dll every time. |
|
61 |
+ return new ThreadPool(MaxPoolThreads); |
|
62 |
+#else |
|
63 |
+ // Reuse the existing pool for RAR. |
|
56 | 64 |
CriticalSectionStart(&PoolCreateSync.CritSection); |
57 |
- |
|
65 |
+ |
|
58 | 66 |
if (GlobalPoolUseCount++ == 0) |
59 | 67 |
GlobalPool=new ThreadPool(MaxPoolThreads); |
60 | 68 |
|
61 |
- // We use a simple thread pool, which does not allow to add tasks from |
|
62 |
- // different functions and threads in the same time. It is ok for RAR, |
|
63 |
- // but UnRAR.dll can be used in multithreaded environment. So if one of |
|
64 |
- // threads requests a copy of global pool and another copy is already |
|
65 |
- // in use, we create and return a new pool instead of existing global. |
|
66 |
- if (GlobalPoolUseCount > 1) |
|
67 |
- { |
|
68 |
- ThreadPool *Pool = new ThreadPool(MaxPoolThreads); |
|
69 |
- CriticalSectionEnd(&PoolCreateSync.CritSection); |
|
70 |
- return Pool; |
|
71 |
- } |
|
72 |
- |
|
73 | 69 |
CriticalSectionEnd(&PoolCreateSync.CritSection); |
74 | 70 |
return GlobalPool; |
71 |
+#endif |
|
75 | 72 |
} |
76 | 73 |
|
77 | 74 |
|
... | ... |
@@ -79,17 +76,16 @@ void DestroyThreadPool(ThreadPool *Pool) |
79 | 79 |
{ |
80 | 80 |
if (Pool!=NULL) |
81 | 81 |
{ |
82 |
+#ifdef RARDLL |
|
83 |
+ delete Pool; |
|
84 |
+#else |
|
82 | 85 |
CriticalSectionStart(&PoolCreateSync.CritSection); |
83 | 86 |
|
84 | 87 |
if (Pool==GlobalPool && GlobalPoolUseCount > 0 && --GlobalPoolUseCount == 0) |
85 | 88 |
delete GlobalPool; |
86 | 89 |
|
87 |
- // To correctly work in multithreaded environment UnRAR.dll creates |
|
88 |
- // new pools if global pool is already in use. We delete such pools here. |
|
89 |
- if (Pool!=GlobalPool) |
|
90 |
- delete Pool; |
|
91 |
- |
|
92 | 90 |
CriticalSectionEnd(&PoolCreateSync.CritSection); |
91 |
+#endif |
|
93 | 92 |
} |
94 | 93 |
} |
95 | 94 |
|
... | ... |
@@ -236,7 +236,7 @@ void RarTime::GetText(wchar *DateStr,size_t MaxSize,bool FullMS) |
236 | 236 |
else |
237 | 237 |
{ |
238 | 238 |
// We use escape before '?' to avoid weird C trigraph characters. |
239 |
- wcscpy(DateStr,L"\?\?\?\?-\?\?-\?\? \?\?:\?\?"); |
|
239 |
+ wcsncpyz(DateStr,L"\?\?\?\?-\?\?-\?\? \?\?:\?\?",MaxSize); |
|
240 | 240 |
} |
241 | 241 |
} |
242 | 242 |
|
... | ... |
@@ -271,7 +271,7 @@ void RarTime::SetIsoText(const wchar *TimeText) |
271 | 271 |
void RarTime::SetAgeText(const wchar *TimeText) |
272 | 272 |
{ |
273 | 273 |
uint Seconds=0,Value=0; |
274 |
- for (int I=0;TimeText[I]!=0;I++) |
|
274 |
+ for (uint I=0;TimeText[I]!=0;I++) |
|
275 | 275 |
{ |
276 | 276 |
int Ch=TimeText[I]; |
277 | 277 |
if (IsDigit(Ch)) |
... | ... |
@@ -18,7 +18,8 @@ enum UIMESSAGE_CODE { |
18 | 18 |
UIERROR_HEADERBROKEN, UIERROR_MHEADERBROKEN, UIERROR_FHEADERBROKEN, |
19 | 19 |
UIERROR_SUBHEADERBROKEN, UIERROR_SUBHEADERUNKNOWN, |
20 | 20 |
UIERROR_SUBHEADERDATABROKEN, UIERROR_RRDAMAGED, UIERROR_UNKNOWNMETHOD, |
21 |
- UIERROR_UNKNOWNENCMETHOD, UIERROR_RENAMING, UIERROR_NEWERRAR, UIERROR_NOTSFX, UIERROR_OLDTOSFX, |
|
21 |
+ UIERROR_UNKNOWNENCMETHOD, UIERROR_RENAMING, UIERROR_NEWERRAR, |
|
22 |
+ UIERROR_NOTSFX, UIERROR_OLDTOSFX, |
|
22 | 23 |
UIERROR_WRONGSFXVER, UIERROR_ALREADYENC, UIERROR_DICTOUTMEM, |
23 | 24 |
UIERROR_USESMALLERDICT, UIERROR_MODIFYUNKNOWN, UIERROR_MODIFYOLD, |
24 | 25 |
UIERROR_MODIFYLOCKED, UIERROR_MODIFYVOLUME, UIERROR_NOTVOLUME, |
... | ... |
@@ -31,12 +32,12 @@ enum UIMESSAGE_CODE { |
31 | 31 |
UIERROR_NOFILESTOADD, UIERROR_NOFILESTODELETE, UIERROR_NOFILESTOEXTRACT, |
32 | 32 |
UIERROR_MISSINGVOL, UIERROR_NEEDPREVVOL, UIERROR_UNKNOWNEXTRA, |
33 | 33 |
UIERROR_CORRUPTEXTRA, UIERROR_NTFSREQUIRED, UIERROR_ZIPVOLSFX, |
34 |
- UIERROR_FILERO, UIERROR_TOOLARGESFX, UIERROR_EMAIL, UIERROR_ACLGET, |
|
35 |
- UIERROR_ACLBROKEN, UIERROR_ACLUNKNOWN, UIERROR_ACLSET, UIERROR_STREAMBROKEN, |
|
36 |
- UIERROR_STREAMUNKNOWN, UIERROR_INCOMPATSWITCH, UIERROR_PATHTOOLONG, |
|
37 |
- UIERROR_DIRSCAN, UIERROR_UOWNERGET, UIERROR_UOWNERBROKEN, |
|
38 |
- UIERROR_UOWNERGETOWNERID, UIERROR_UOWNERGETGROUPID, UIERROR_UOWNERSET, |
|
39 |
- UIERROR_ULINKREAD, UIERROR_ULINKEXIST, |
|
34 |
+ UIERROR_FILERO, UIERROR_TOOLARGESFX, UIERROR_NOZIPSFX, UIERROR_EMAIL, |
|
35 |
+ UIERROR_ACLGET, UIERROR_ACLBROKEN, UIERROR_ACLUNKNOWN, UIERROR_ACLSET, |
|
36 |
+ UIERROR_STREAMBROKEN, UIERROR_STREAMUNKNOWN, UIERROR_INCOMPATSWITCH, |
|
37 |
+ UIERROR_PATHTOOLONG, UIERROR_DIRSCAN, UIERROR_UOWNERGET, |
|
38 |
+ UIERROR_UOWNERBROKEN, UIERROR_UOWNERGETOWNERID, UIERROR_UOWNERGETGROUPID, |
|
39 |
+ UIERROR_UOWNERSET, UIERROR_ULINKREAD, UIERROR_ULINKEXIST, |
|
40 | 40 |
|
41 | 41 |
UIMSG_FIRST, |
42 | 42 |
UIMSG_STRING, UIMSG_BUILD, UIMSG_RRSEARCH, UIMSG_ANALYZEFILEDATA, |
... | ... |
@@ -75,7 +76,7 @@ enum UIASKREP_RESULT { |
75 | 75 |
UIASKREP_RESULT uiAskReplace(wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags); |
76 | 76 |
UIASKREP_RESULT uiAskReplaceEx(RAROptions *Cmd,wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags); |
77 | 77 |
|
78 |
-void uiInit(bool Sound); |
|
78 |
+void uiInit(SOUND_NOTIFY_MODE Sound); |
|
79 | 79 |
|
80 | 80 |
|
81 | 81 |
void uiStartArchiveExtract(bool Extract,const wchar *ArcName); |
... | ... |
@@ -85,6 +86,7 @@ void uiProcessProgress(const char *Command,int64 CurSize,int64 TotalSize); |
85 | 85 |
|
86 | 86 |
enum UIPASSWORD_TYPE {UIPASSWORD_GLOBAL,UIPASSWORD_FILE,UIPASSWORD_ARCHIVE}; |
87 | 87 |
bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password); |
88 |
+bool uiIsGlobalPasswordSet(); |
|
88 | 89 |
|
89 | 90 |
enum UIALARM_TYPE {UIALARM_ERROR, UIALARM_INFO, UIALARM_QUESTION}; |
90 | 91 |
void uiAlarm(UIALARM_TYPE Type); |
... | ... |
@@ -110,6 +112,11 @@ class uiMsgStore |
110 | 110 |
public: |
111 | 111 |
uiMsgStore(UIMESSAGE_CODE Code) |
112 | 112 |
{ |
113 |
+ // Init arrays in case a caller passes fewer parameters than expected. |
|
114 |
+ for (uint I=0;I<ASIZE(Str);I++) |
|
115 |
+ Str[I]=L""; |
|
116 |
+ memset(Num,0,sizeof(Num)); |
|
117 |
+ |
|
113 | 118 |
NumSize=StrSize=0; |
114 | 119 |
this->Code=Code; |
115 | 120 |
} |
... | ... |
@@ -18,7 +18,10 @@ UIASKREP_RESULT uiAskReplace(wchar *Name,size_t MaxNameSize,int64 FileSize,RarTi |
18 | 18 |
{ |
19 | 19 |
itoa(FileSize,SizeText2,ASIZE(SizeText2)); |
20 | 20 |
FileTime->GetText(DateStr2,ASIZE(DateStr2),false); |
21 |
- eprintf(St(MAskReplace),Name,SizeText1,DateStr1,SizeText2,DateStr2); |
|
21 |
+ if ((Flags & UIASKREP_F_EXCHSRCDEST)==0) |
|
22 |
+ eprintf(St(MAskReplace),Name,SizeText1,DateStr1,SizeText2,DateStr2); |
|
23 |
+ else |
|
24 |
+ eprintf(St(MAskReplace),Name,SizeText2,DateStr2,SizeText1,DateStr1); |
|
22 | 25 |
} |
23 | 26 |
|
24 | 27 |
bool AllowRename=(Flags & UIASKREP_F_NORENAME)==0; |
... | ... |
@@ -186,7 +189,11 @@ void uiMsgStore::Msg() |
186 | 186 |
Log(Str[0],St(MUnknownMeth),Str[1]); |
187 | 187 |
break; |
188 | 188 |
case UIERROR_UNKNOWNENCMETHOD: |
189 |
- Log(Str[0],St(MUnkEncMethod),Str[1]); |
|
189 |
+ { |
|
190 |
+ wchar Msg[256]; |
|
191 |
+ swprintf(Msg,ASIZE(Msg),St(MUnkEncMethod),Str[1]); |
|
192 |
+ Log(Str[0],L"%s: %s",Msg,Str[2]); |
|
193 |
+ } |
|
190 | 194 |
break; |
191 | 195 |
#ifndef SFX_MODULE |
192 | 196 |
case UIERROR_RENAMING: |
... | ... |
@@ -219,6 +226,7 @@ void uiMsgStore::Msg() |
219 | 219 |
break; |
220 | 220 |
case UIERROR_INVALIDNAME: |
221 | 221 |
Log(Str[0],St(MInvalidName),Str[1]); |
222 |
+ mprintf(L"\n"); // Needed when called from CmdExtract::ExtractCurrentFile. |
|
222 | 223 |
break; |
223 | 224 |
#ifndef SFX_MODULE |
224 | 225 |
case UIERROR_NEWRARFORMAT: |
... | ... |
@@ -354,9 +362,15 @@ bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Passw |
354 | 354 |
} |
355 | 355 |
|
356 | 356 |
|
357 |
+bool uiIsGlobalPasswordSet() |
|
358 |
+{ |
|
359 |
+ return false; |
|
360 |
+} |
|
361 |
+ |
|
362 |
+ |
|
357 | 363 |
void uiAlarm(UIALARM_TYPE Type) |
358 | 364 |
{ |
359 |
- if (uiSoundEnabled) |
|
365 |
+ if (uiSoundNotify==SOUND_NOTIFY_ON) |
|
360 | 366 |
{ |
361 | 367 |
static clock_t LastTime=-10; // Negative to always beep first time. |
362 | 368 |
if ((MonoClock()-LastTime)/CLOCKS_PER_SEC>5) |
... | ... |
@@ -70,7 +70,7 @@ bool WideToChar(const wchar *Src,char *Dest,size_t DestSize) |
70 | 70 |
#endif |
71 | 71 |
if (DestSize>0) |
72 | 72 |
Dest[DestSize-1]=0; |
73 |
- |
|
73 |
+ |
|
74 | 74 |
// We tried to return the empty string if conversion is failed, |
75 | 75 |
// but it does not work well. WideCharToMultiByte returns 'failed' code |
76 | 76 |
// 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) |
138 | 138 |
if (wcschr(Src,(wchar)MappedStringMark)==NULL) |
139 | 139 |
return false; |
140 | 140 |
|
141 |
+ // Seems to be that wcrtomb in some memory analyzing libraries |
|
142 |
+ // can produce uninitilized output while reporting success on garbage input. |
|
143 |
+ // So we clean the destination to calm analyzers. |
|
144 |
+ memset(Dest,0,DestSize); |
|
145 |
+ |
|
141 | 146 |
Success=true; |
142 | 147 |
uint SrcPos=0,DestPos=0; |
143 | 148 |
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) |
173 | 173 |
|
174 | 174 |
|
175 | 175 |
#if defined(_UNIX) && defined(MBFUNCTIONS) |
176 |
-// Convert and map inconvertible Unicode characters. |
|
176 |
+// Convert and map inconvertible Unicode characters. |
|
177 | 177 |
// We use it for extended ASCII names in Unix. |
178 | 178 |
void CharToWideMap(const char *Src,wchar *Dest,size_t DestSize,bool &Success) |
179 | 179 |
{ |
... | ... |
@@ -11,7 +11,7 @@ void Unpack::Unpack5(bool Solid) |
11 | 11 |
// Check TablesRead5 to be sure that we read tables at least once |
12 | 12 |
// regardless of current block header TablePresent flag. |
13 | 13 |
// So we can safefly use these tables below. |
14 |
- if (!ReadBlockHeader(Inp,BlockHeader) || |
|
14 |
+ if (!ReadBlockHeader(Inp,BlockHeader) || |
|
15 | 15 |
!ReadTables(Inp,BlockHeader,BlockTables) || !TablesRead5) |
16 | 16 |
return; |
17 | 17 |
} |
... | ... |
@@ -536,11 +536,11 @@ bool Unpack::ReadBlockHeader(BitInput &Inp,UnpackBlockHeader &Header) |
536 | 536 |
if (!UnpReadBuf()) |
537 | 537 |
return false; |
538 | 538 |
Inp.faddbits((8-Inp.InBit)&7); |
539 |
- |
|
539 |
+ |
|
540 | 540 |
byte BlockFlags=Inp.fgetbits()>>8; |
541 | 541 |
Inp.faddbits(8); |
542 | 542 |
uint ByteCount=((BlockFlags>>3)&3)+1; // Block size byte count. |
543 |
- |
|
543 |
+ |
|
544 | 544 |
if (ByteCount==4) |
545 | 545 |
return false; |
546 | 546 |
|
... | ... |
@@ -48,7 +48,7 @@ void FragmentedWindow::Init(size_t WinSize) |
48 | 48 |
} |
49 | 49 |
if (NewMem==NULL) |
50 | 50 |
throw std::bad_alloc(); |
51 |
- |
|
51 |
+ |
|
52 | 52 |
// Clean the window to generate the same output when unpacking corrupt |
53 | 53 |
// RAR files, which may access to unused areas of sliding dictionary. |
54 | 54 |
memset(NewMem,0,Size); |
... | ... |
@@ -165,7 +165,7 @@ void Unpack::Unpack5MT(bool Solid) |
165 | 165 |
if (DataLeft<TooSmallToProcess) |
166 | 166 |
break; |
167 | 167 |
} |
168 |
- |
|
168 |
+ |
|
169 | 169 |
//#undef USE_THREADS |
170 | 170 |
UnpackThreadDataList UTDArray[MaxPoolThreads]; |
171 | 171 |
uint UTDArrayPos=0; |
... | ... |
@@ -180,7 +180,7 @@ void Unpack::Unpack5MT(bool Solid) |
180 | 180 |
UnpackThreadDataList *UTD=UTDArray+UTDArrayPos++; |
181 | 181 |
UTD->D=UnpThreadData+CurBlock; |
182 | 182 |
UTD->BlockCount=Min(MaxBlockPerThread,BlockNumberMT-CurBlock); |
183 |
- |
|
183 |
+ |
|
184 | 184 |
#ifdef USE_THREADS |
185 | 185 |
if (BlockNumber==1) |
186 | 186 |
UnpackDecode(*UTD->D); |
... | ... |
@@ -200,7 +200,7 @@ void Unpack::Unpack5MT(bool Solid) |
200 | 200 |
#endif |
201 | 201 |
|
202 | 202 |
bool IncompleteThread=false; |
203 |
- |
|
203 |
+ |
|
204 | 204 |
for (uint Block=0;Block<BlockNumber;Block++) |
205 | 205 |
{ |
206 | 206 |
UnpackThreadData *CurData=UnpThreadData+Block; |
... | ... |
@@ -251,7 +251,7 @@ void Unpack::Unpack5MT(bool Solid) |
251 | 251 |
break; |
252 | 252 |
} |
253 | 253 |
} |
254 |
- |
|
254 |
+ |
|
255 | 255 |
if (IncompleteThread || Done) |
256 | 256 |
break; // Current buffer is done, read more data or quit. |
257 | 257 |
else |
... | ... |
@@ -303,7 +303,7 @@ void Unpack::UnpackDecode(UnpackThreadData &D) |
303 | 303 |
D.DamagedData=true; |
304 | 304 |
return; |
305 | 305 |
} |
306 |
- |
|
306 |
+ |
|
307 | 307 |
D.DecodedSize=0; |
308 | 308 |
int BlockBorder=D.BlockHeader.BlockStart+D.BlockHeader.BlockSize-1; |
309 | 309 |
|
... | ... |
@@ -413,7 +413,7 @@ void Unpack::UnpackDecode(UnpackThreadData &D) |
413 | 413 |
{ |
414 | 414 |
UnpackFilter Filter; |
415 | 415 |
ReadFilter(D.Inp,Filter); |
416 |
- |
|
416 |
+ |
|
417 | 417 |
CurItem->Type=UNPDT_FILTER; |
418 | 418 |
CurItem->Length=Filter.Type; |
419 | 419 |
CurItem->Distance=Filter.BlockStart; |
... | ... |
@@ -498,7 +498,7 @@ bool Unpack::ProcessDecoded(UnpackThreadData &D) |
498 | 498 |
if (Item->Type==UNPDT_FILTER) |
499 | 499 |
{ |
500 | 500 |
UnpackFilter Filter; |
501 |
- |
|
501 |
+ |
|
502 | 502 |
Filter.Type=(byte)Item->Length; |
503 | 503 |
Filter.BlockStart=Item->Distance; |
504 | 504 |
|
... | ... |
@@ -534,7 +534,7 @@ bool Unpack::UnpackLargeBlock(UnpackThreadData &D) |
534 | 534 |
D.DamagedData=true; |
535 | 535 |
return false; |
536 | 536 |
} |
537 |
- |
|
537 |
+ |
|
538 | 538 |
int BlockBorder=D.BlockHeader.BlockStart+D.BlockHeader.BlockSize-1; |
539 | 539 |
|
540 | 540 |
// Reserve enough space even for filter entry. |
... | ... |
@@ -34,7 +34,7 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma |
34 | 34 |
Arc.Close(); |
35 | 35 |
|
36 | 36 |
wchar NextName[NM]; |
37 |
- wcscpy(NextName,Arc.FileName); |
|
37 |
+ wcsncpyz(NextName,Arc.FileName,ASIZE(NextName)); |
|
38 | 38 |
NextVolumeName(NextName,ASIZE(NextName),!Arc.NewNumbering); |
39 | 39 |
|
40 | 40 |
#if !defined(SFX_MODULE) && !defined(RARDLL) |
... | ... |
@@ -67,12 +67,12 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma |
67 | 67 |
// Checking for new style volumes renamed by user to old style |
68 | 68 |
// name format. Some users did it for unknown reason. |
69 | 69 |
wchar AltNextName[NM]; |
70 |
- wcscpy(AltNextName,Arc.FileName); |
|
70 |
+ wcsncpyz(AltNextName,Arc.FileName,ASIZE(AltNextName)); |
|
71 | 71 |
NextVolumeName(AltNextName,ASIZE(AltNextName),true); |
72 | 72 |
OldSchemeTested=true; |
73 | 73 |
if (Arc.Open(AltNextName,OpenMode)) |
74 | 74 |
{ |
75 |
- wcscpy(NextName,AltNextName); |
|
75 |
+ wcsncpyz(NextName,AltNextName,ASIZE(NextName)); |
|
76 | 76 |
break; |
77 | 77 |
} |
78 | 78 |
} |
... | ... |
@@ -185,7 +185,7 @@ bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize) |
185 | 185 |
if (Cmd->Callback!=NULL) |
186 | 186 |
{ |
187 | 187 |
wchar OrgNextName[NM]; |
188 |
- wcscpy(OrgNextName,NextName); |
|
188 |
+ wcsncpyz(OrgNextName,NextName,ASIZE(OrgNextName)); |
|
189 | 189 |
if (Cmd->Callback(UCM_CHANGEVOLUMEW,Cmd->UserData,(LPARAM)NextName,RAR_VOL_ASK)==-1) |
190 | 190 |
DllVolAborted=true; |
191 | 191 |
else |
... | ... |
@@ -195,7 +195,7 @@ bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize) |
195 | 195 |
{ |
196 | 196 |
char NextNameA[NM],OrgNextNameA[NM]; |
197 | 197 |
WideToChar(NextName,NextNameA,ASIZE(NextNameA)); |
198 |
- strcpy(OrgNextNameA,NextNameA); |
|
198 |
+ strncpyz(OrgNextNameA,NextNameA,ASIZE(OrgNextNameA)); |
|
199 | 199 |
if (Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextNameA,RAR_VOL_ASK)==-1) |
200 | 200 |
DllVolAborted=true; |
201 | 201 |
else |
... | ... |
@@ -54,7 +54,10 @@ void ExtractACL20(Archive &Arc,const wchar *FileName) |
54 | 54 |
if (!SetCode) |
55 | 55 |
{ |
56 | 56 |
uiMsg(UIERROR_ACLSET,Arc.FileName,FileName); |
57 |
+ DWORD LastError=GetLastError(); |
|
57 | 58 |
ErrHandler.SysErrMsg(); |
59 |
+ if (LastError==ERROR_ACCESS_DENIED && !IsUserAdmin()) |
|
60 |
+ uiMsg(UIERROR_NEEDADMIN); |
|
58 | 61 |
ErrHandler.SetErrorCode(RARX_WARNING); |
59 | 62 |
} |
60 | 63 |
} |
... | ... |
@@ -86,7 +89,10 @@ void ExtractACL(Archive &Arc,const wchar *FileName) |
86 | 86 |
if (!SetCode) |
87 | 87 |
{ |
88 | 88 |
uiMsg(UIERROR_ACLSET,Arc.FileName,FileName); |
89 |
+ DWORD LastError=GetLastError(); |
|
89 | 90 |
ErrHandler.SysErrMsg(); |
91 |
+ if (LastError==ERROR_ACCESS_DENIED && !IsUserAdmin()) |
|
92 |
+ uiMsg(UIERROR_NEEDADMIN); |
|
90 | 93 |
ErrHandler.SetErrorCode(RARX_WARNING); |
91 | 94 |
} |
92 | 95 |
} |
... | ... |
@@ -20,11 +20,13 @@ void ExtractStreams20(Archive &Arc,const wchar *FileName) |
20 | 20 |
wchar StreamName[NM+2]; |
21 | 21 |
if (FileName[0]!=0 && FileName[1]==0) |
22 | 22 |
{ |
23 |
- wcscpy(StreamName,L".\\"); |
|
24 |
- wcscpy(StreamName+2,FileName); |
|
23 |
+ // Convert single character names like f:stream to .\f:stream to |
|
24 |
+ // resolve the ambiguity with drive letters. |
|
25 |
+ wcsncpyz(StreamName,L".\\",ASIZE(StreamName)); |
|
26 |
+ wcsncatz(StreamName,FileName,ASIZE(StreamName)); |
|
25 | 27 |
} |
26 | 28 |
else |
27 |
- wcscpy(StreamName,FileName); |
|
29 |
+ wcsncpyz(StreamName,FileName,ASIZE(StreamName)); |
|
28 | 30 |
if (wcslen(StreamName)+strlen(Arc.StreamHead.StreamName)>=ASIZE(StreamName) || |
29 | 31 |
Arc.StreamHead.StreamName[0]!=':') |
30 | 32 |
{ |
... | ... |
@@ -35,7 +37,7 @@ void ExtractStreams20(Archive &Arc,const wchar *FileName) |
35 | 35 |
|
36 | 36 |
wchar StoredName[NM]; |
37 | 37 |
CharToWide(Arc.StreamHead.StreamName,StoredName,ASIZE(StoredName)); |
38 |
- ConvertPath(StoredName+1,StoredName+1); |
|
38 |
+ ConvertPath(StoredName+1,StoredName+1,ASIZE(StoredName)-1); |
|
39 | 39 |
|
40 | 40 |
wcsncatz(StreamName,StoredName,ASIZE(StreamName)); |
41 | 41 |
|
... | ... |
@@ -83,8 +85,10 @@ void ExtractStreams(Archive &Arc,const wchar *FileName,bool TestMode) |
83 | 83 |
wchar FullName[NM+2]; |
84 | 84 |
if (FileName[0]!=0 && FileName[1]==0) |
85 | 85 |
{ |
86 |
- wcscpy(FullName,L".\\"); |
|
87 |
- wcsncpyz(FullName+2,FileName,ASIZE(FullName)-2); |
|
86 |
+ // Convert single character names like f:stream to .\f:stream to |
|
87 |
+ // resolve the ambiguity with drive letters. |
|
88 |
+ wcsncpyz(FullName,L".\\",ASIZE(FullName)); |
|
89 |
+ wcsncatz(FullName,FileName,ASIZE(FullName)); |
|
88 | 90 |
} |
89 | 91 |
else |
90 | 92 |
wcsncpyz(FullName,FileName,ASIZE(FullName)); |
... | ... |
@@ -91,7 +91,7 @@ uint8_t unrar_debug = 0; |
91 | 91 |
|
92 | 92 |
/** |
93 | 93 |
* @brief Translate an ERAR_<code> to the appropriate UNRAR_<code> |
94 |
- * |
|
94 |
+ * |
|
95 | 95 |
* @param errorCode ERAR_<code> |
96 | 96 |
* @return cl_unrar_error_t UNRAR_OK, UNRAR_ENCRYPTED, or UNRAR_ERR. |
97 | 97 |
*/ |
... | ... |
@@ -213,6 +213,7 @@ cl_unrar_error_t unrar_open(const char* filename, void** hArchive, char** commen |
213 | 213 |
} |
214 | 214 |
archiveData->ArcName = (char *)filename; |
215 | 215 |
archiveData->OpenMode = RAR_OM_EXTRACT; |
216 |
+ archiveData->OpFlags |= ROADOF_KEEPBROKEN; |
|
216 | 217 |
archiveData->CmtBuf = (char*)calloc(1, CMTBUFSIZE); |
217 | 218 |
if (archiveData->CmtBuf == NULL) { |
218 | 219 |
unrar_dbgmsg("unrar_open: Not enough memory to allocate main archive header comment buffer.\n"); |
... | ... |
@@ -291,7 +292,7 @@ done: |
291 | 291 |
|
292 | 292 |
/** |
293 | 293 |
* @brief Get file metadata from the next file header. |
294 |
- * |
|
294 |
+ * |
|
295 | 295 |
* @param hArchive Handle to the archive we're extracting. |
296 | 296 |
* @param[in/out] file_metadata Pointer to a pre-allocated metadata structure. |
297 | 297 |
* @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 |
320 | 320 |
*/ |
321 | 321 |
headerData.CmtBuf = NULL; |
322 | 322 |
headerData.CmtBufSize = 0; |
323 |
- |
|
323 |
+ |
|
324 | 324 |
headerData.RedirNameSize = 1024 * sizeof(wchar_t); |
325 | 325 |
headerData.RedirName = (wchar_t*)&RedirName; |
326 | 326 |
memset(headerData.RedirName, 0, headerData.RedirNameSize); |