Browse code

Updated UnRAR 5.7.5 to 5.9.2.

As with the previous libclamunrar commit, this update maintains the hack
in dll.cpp:332 that allows skipping of files in solid archives.

Micah Snyder authored on 2020/04/22 03:22:33
Showing 53 changed files
... ...
@@ -7,7 +7,7 @@ Note: This file refers to the source tarball. Things described here may differ
7 7
 
8 8
 ClamAV 0.102.3 is a bug patch release to address the following issues.
9 9
 
10
--
10
+- Updated libclamunrar to UnRAR 5.9.2.
11 11
 
12 12
 Special thanks to the following for code contributions and bug reports:
13 13
 
14 14
deleted file mode 100644
... ...
@@ -1,22 +0,0 @@
1
-PROJECT_NAME     = ClamAV - Libclamunrar
2
-OUTPUT_DIRECTORY = ../docs/libclamunrar
3
-WARNINGS         = YES
4
-FILE_PATTERNS    = *.c *.h
5
-PERL_PATH        = /usr/bin/perl
6
-SEARCHENGINE     = YES
7
-
8
-GENERATE_LATEX=NO
9
-OPTIMIZE_OUTPUT_FOR_C=YES
10
-HAVE_DOT=YES
11
-CALL_GRAPH=YES
12
-CALLER_GRAPH=YES
13
-JAVADOC_AUTOBRIEF=YES
14
-GENERATE_MAN=NO
15
-EXAMPLE_PATH=examples
16
-
17
-DOT_CLEANUP=NO
18
-MAX_DOT_GRAPH_DEPTH=3
19
-
20
-EXTRACT_ALL=YES
21
-INPUT = . \
22
-        ../shared
... ...
@@ -4,8 +4,15 @@ bool Archive::GetComment(Array<wchar> *CmtData)
4 4
 {
5 5
   if (!MainComment)
6 6
     return false;
7
-  SaveFilePos SavePos(*this);
7
+  int64 SavePos=Tell();
8
+  bool Success=DoGetComment(CmtData);
9
+  Seek(SavePos,SEEK_SET);
10
+  return Success;
11
+}
12
+
8 13
 
14
+bool Archive::DoGetComment(Array<wchar> *CmtData)
15
+{
9 16
 #ifndef SFX_MODULE
10 17
   uint CmtLength;
11 18
   if (Format==RARFMT14)
... ...
@@ -136,7 +143,7 @@ bool Archive::GetComment(Array<wchar> *CmtData)
136 136
 bool Archive::ReadCommentData(Array<wchar> *CmtData)
137 137
 {
138 138
   Array<byte> CmtRaw;
139
-  if (!ReadSubData(&CmtRaw,NULL))
139
+  if (!ReadSubData(&CmtRaw,NULL,false))
140 140
     return false;
141 141
   size_t CmtSize=CmtRaw.Size();
142 142
   CmtRaw.Push(0);
... ...
@@ -208,8 +208,8 @@ bool Archive::IsArchive(bool EnableBroken)
208 208
       break;
209 209
   }
210 210
 
211
-  // This check allows to make RS based recovery even if password is incorrect.
212
-  // But we should not do it for EnableBroken or we'll get 'not RAR archive'
211
+  
212
+  // We should not do it for EnableBroken or we'll get 'not RAR archive'
213 213
   // messages when extracting encrypted archives with wrong password.
214 214
   if (FailedHeaderDecryption && !EnableBroken)
215 215
     return false;
... ...
@@ -233,7 +233,7 @@ bool Archive::IsArchive(bool EnableBroken)
233 233
   // immediately after IsArchive call.
234 234
   if (HeadersLeft && (!SilentOpen || !Encrypted))
235 235
   {
236
-    SaveFilePos SavePos(*this);
236
+    int64 SavePos=Tell();
237 237
     int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos;
238 238
     HEADER_TYPE SaveCurHeaderType=CurHeaderType;
239 239
 
... ...
@@ -262,6 +262,7 @@ bool Archive::IsArchive(bool EnableBroken)
262 262
     CurBlockPos=SaveCurBlockPos;
263 263
     NextBlockPos=SaveNextBlockPos;
264 264
     CurHeaderType=SaveCurHeaderType;
265
+    Seek(SavePos,SEEK_SET);
265 266
   }
266 267
   if (!Volume || FirstVolume)
267 268
     wcsncpyz(FirstVolumeName,FileName,ASIZE(FirstVolumeName));
... ...
@@ -29,7 +29,6 @@ class Archive:public File
29 29
     void UpdateLatestTime(FileHeader *CurBlock);
30 30
     void ConvertNameCase(wchar *Name);
31 31
     void ConvertFileHeader(FileHeader *hd);
32
-    void WriteBlock50(HEADER_TYPE HeaderType,BaseBlock *wb,bool OnlySetSize,bool NonFinalWrite);
33 32
     size_t ReadHeader14();
34 33
     size_t ReadHeader15();
35 34
     size_t ReadHeader50();
... ...
@@ -38,6 +37,7 @@ class Archive:public File
38 38
     void UnexpEndArcMsg();
39 39
     void BrokenHeaderMsg();
40 40
     void UnkEncVerMsg(const wchar *Name,const wchar *Info);
41
+    bool DoGetComment(Array<wchar> *CmtData);
41 42
     bool ReadCommentData(Array<wchar> *CmtData);
42 43
 
43 44
 #if !defined(RAR_NOCRYPT)
... ...
@@ -65,8 +65,6 @@ class Archive:public File
65 65
     size_t SearchBlock(HEADER_TYPE HeaderType);
66 66
     size_t SearchSubBlock(const wchar *Type);
67 67
     size_t SearchRR();
68
-    void WriteBlock(HEADER_TYPE HeaderType,BaseBlock *wb=NULL,bool OnlySetSize=false,bool NonFinalWrite=false);
69
-    void SetBlockSize(HEADER_TYPE HeaderType,BaseBlock *wb=NULL) {WriteBlock(HeaderType,wb,true);}
70 68
     size_t ReadHeader();
71 69
     void CheckArc(bool EnableBroken);
72 70
     void CheckOpen(const wchar *Name);
... ...
@@ -83,7 +81,7 @@ class Archive:public File
83 83
     int64 GetStartPos();
84 84
     void AddSubData(byte *SrcData,uint64 DataSize,File *SrcFile,
85 85
          const wchar *Name,uint Flags);
86
-    bool ReadSubData(Array<byte> *UnpData,File *DestFile);
86
+    bool ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode);
87 87
     HEADER_TYPE GetHeaderType() {return CurHeaderType;}
88 88
     RAROptions* GetRAROptions() {return Cmd;}
89 89
     void SetSilentOpen(bool Mode) {SilentOpen=Mode;}
90 90
deleted file mode 100644
... ...
@@ -1,67 +0,0 @@
1
-ArcMemory::ArcMemory()
2
-{
3
-  Loaded=false;
4
-  SeekPos=0;
5
-}
6
-
7
-
8
-void ArcMemory::Load(const byte *Data,size_t Size)
9
-{
10
-  ArcData.Alloc(Size);
11
-  memcpy(&ArcData[0],Data,Size);
12
-  Loaded=true;
13
-  SeekPos=0;
14
-}
15
-
16
-
17
-bool ArcMemory::Unload()
18
-{
19
-  if (!Loaded)
20
-    return false;
21
-  Loaded=false;
22
-  return true;
23
-}
24
-
25
-
26
-bool ArcMemory::Read(void *Data,size_t Size,size_t &Result)
27
-{
28
-  if (!Loaded)
29
-    return false;
30
-  Result=(size_t)Min(Size,ArcData.Size()-SeekPos);
31
-  memcpy(Data,&ArcData[(size_t)SeekPos],Result);
32
-  SeekPos+=Result;
33
-  return true;
34
-}
35
-
36
-
37
-bool ArcMemory::Seek(int64 Offset,int Method)
38
-{
39
-  if (!Loaded)
40
-    return false;
41
-  if (Method==SEEK_SET)
42
-  {
43
-    if (Offset<0)
44
-      SeekPos=0;
45
-    else
46
-      SeekPos=Min((uint64)Offset,ArcData.Size());
47
-  }
48
-  else
49
-    if (Method==SEEK_CUR || Method==SEEK_END)
50
-    {
51
-      if (Method==SEEK_END)
52
-        SeekPos=ArcData.Size();
53
-      SeekPos+=(uint64)Offset;
54
-      if (SeekPos>ArcData.Size())
55
-        SeekPos=Offset<0 ? 0 : ArcData.Size();
56
-    }
57
-  return true;
58
-}
59
-
60
-
61
-bool ArcMemory::Tell(int64 *Pos)
62
-{
63
-  if (!Loaded)
64
-    return false;
65
-  *Pos=SeekPos;
66
-  return true;
67
-}
68 1
deleted file mode 100644
... ...
@@ -1,22 +0,0 @@
1
-#ifndef _RAR_ARCMEM_
2
-#define _RAR_ARCMEM_
3
-
4
-// Memory interface for software fuzzers.
5
-
6
-class ArcMemory
7
-{
8
-  private:
9
-    bool Loaded;
10
-    Array<byte> ArcData;
11
-    uint64 SeekPos;
12
-  public:
13
-    ArcMemory();
14
-    void Load(const byte *Data,size_t Size);
15
-    bool Unload();
16
-    bool IsLoaded() {return Loaded;}
17
-    bool Read(void *Data,size_t Size,size_t &Result);
18
-    bool Seek(int64 Offset,int Method);
19
-    bool Tell(int64 *Pos);
20
-};
21
-
22
-#endif
... ...
@@ -268,14 +268,14 @@ size_t Archive::ReadHeader15()
268 268
         uint FileTime=Raw.Get4();
269 269
         hd->UnpVer=Raw.Get1();
270 270
 
271
-        // RAR15 did not use the special dictionary size to mark dirs.
272
-        if (hd->UnpVer<20 && (hd->FileAttr & 0x10)!=0)
273
-          hd->Dir=true;
274
-
275 271
         hd->Method=Raw.Get1()-0x30;
276 272
         size_t NameSize=Raw.Get2();
277 273
         hd->FileAttr=Raw.Get4();
278 274
 
275
+        // RAR15 did not use the special dictionary size to mark dirs.
276
+        if (hd->UnpVer<20 && (hd->FileAttr & 0x10)!=0)
277
+          hd->Dir=true;
278
+
279 279
         hd->CryptMethod=CRYPT_NONE;
280 280
         if (hd->Encrypted)
281 281
           switch(hd->UnpVer)
... ...
@@ -402,8 +402,8 @@ size_t Archive::ReadHeader15()
402 402
             if (rmode & 4)
403 403
               rlt.Second++;
404 404
             rlt.Reminder=0;
405
-            int count=rmode&3;
406
-            for (int J=0;J<count;J++)
405
+            uint count=rmode&3;
406
+            for (uint J=0;J<count;J++)
407 407
             {
408 408
               byte CurByte=Raw.Get1();
409 409
               rlt.Reminder|=(((uint)CurByte)<<((J+3-count)*8));
... ...
@@ -521,7 +521,6 @@ size_t Archive::ReadHeader15()
521 521
     {
522 522
       // Last 7 bytes of recovered volume can contain zeroes, because
523 523
       // REV files store its own information (volume number, etc.) here.
524
-      SaveFilePos SavePos(*this);
525 524
       int64 Length=Tell();
526 525
       Seek(Length-7,SEEK_SET);
527 526
       Recovered=true;
... ...
@@ -584,7 +583,7 @@ size_t Archive::ReadHeader50()
584 584
         {
585 585
           // This message is used by Android GUI to reset cached passwords.
586 586
           // Update appropriate code if changed.
587
-          uiMsg(UIERROR_BADPSW,FileName);
587
+          uiMsg(UIERROR_BADPSW,FileName,FileName);
588 588
           FailedHeaderDecryption=true;
589 589
           ErrHandler.SetErrorCode(RARX_BADPWD);
590 590
           return 0;
... ...
@@ -593,7 +592,7 @@ size_t Archive::ReadHeader50()
593 593
         {
594 594
           // This message is used by Android GUI and Windows GUI and SFX to
595 595
           // reset cached passwords. Update appropriate code if changed.
596
-          uiMsg(UIWAIT_BADPSW,FileName);
596
+          uiMsg(UIWAIT_BADPSW,FileName,FileName);
597 597
           Cmd->Password.Clean();
598 598
         }
599 599
 
... ...
@@ -720,6 +719,7 @@ size_t Archive::ReadHeader50()
720 720
           UnkEncVerMsg(FileName,Info);
721 721
           return 0;
722 722
         }
723
+
723 724
         Raw.GetB(CryptHead.Salt,SIZE_SALT50);
724 725
         if (CryptHead.UsePswCheck)
725 726
         {
... ...
@@ -1256,8 +1256,9 @@ size_t Archive::ReadHeader14()
1256 1256
     Raw.Read(NameSize);
1257 1257
 
1258 1258
     char FileName[NM];
1259
-    Raw.GetB((byte *)FileName,Min(NameSize,ASIZE(FileName)));
1260
-    FileName[NameSize]=0;
1259
+    size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
1260
+    Raw.GetB((byte *)FileName,ReadNameSize);
1261
+    FileName[ReadNameSize]=0;
1261 1262
     IntToExt(FileName,FileName,ASIZE(FileName));
1262 1263
     CharToWide(FileName,FileHead.FileName,ASIZE(FileHead.FileName));
1263 1264
     ConvertNameCase(FileHead.FileName);
... ...
@@ -1414,7 +1415,7 @@ int64 Archive::GetStartPos()
1414 1414
 }
1415 1415
 
1416 1416
 
1417
-bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile)
1417
+bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode)
1418 1418
 {
1419 1419
   if (BrokenHeader)
1420 1420
   {
... ...
@@ -1462,6 +1463,7 @@ bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile)
1462 1462
   SubDataIO.SetPackedSizeToRead(SubHead.PackSize);
1463 1463
   SubDataIO.EnableShowProgress(false);
1464 1464
   SubDataIO.SetFiles(this,DestFile);
1465
+  SubDataIO.SetTestMode(TestMode);
1465 1466
   SubDataIO.UnpVolume=SubHead.SplitAfter;
1466 1467
   SubDataIO.SetSubHeader(&SubHead,NULL);
1467 1468
   Unpack.SetDestSize(SubHead.UnpSize);
... ...
@@ -3,6 +3,7 @@
3 3
 #define _RAR_BLAKE2_
4 4
 
5 5
 #define BLAKE2_DIGEST_SIZE 32
6
+#define BLAKE2_THREADS_NUMBER 8
6 7
 
7 8
 enum blake2s_constant
8 9
 {
... ...
@@ -295,10 +295,13 @@ void CommandData::ProcessSwitch(const wchar *Switch)
295 295
           if (Switch[2]=='-' && Switch[3]==0)
296 296
             GenerateArcName=0;
297 297
           else
298
-          {
299
-            GenerateArcName=true;
300
-            wcsncpyz(GenerateMask,Switch+2,ASIZE(GenerateMask));
301
-          }
298
+            if (toupperw(Switch[2])=='F')
299
+              wcsncpyz(DefGenerateMask,Switch+3,ASIZE(DefGenerateMask));
300
+            else
301
+            {
302
+              GenerateArcName=true;
303
+              wcsncpyz(GenerateMask,Switch+2,ASIZE(GenerateMask));
304
+            }
302 305
           break;
303 306
 #endif
304 307
         case 'I':
... ...
@@ -373,11 +376,11 @@ void CommandData::ProcessSwitch(const wchar *Switch)
373 373
         default:
374 374
           if (Switch[1]=='+')
375 375
           {
376
-            InclFileAttr|=GetExclAttr(Switch+2);
376
+            InclFileAttr|=GetExclAttr(Switch+2,InclDir);
377 377
             InclAttrSet=true;
378 378
           }
379 379
           else
380
-            ExclFileAttr|=GetExclAttr(Switch+1);
380
+            ExclFileAttr|=GetExclAttr(Switch+1,ExclDir);
381 381
           break;
382 382
       }
383 383
       break;
... ...
@@ -825,39 +828,7 @@ void CommandData::ProcessSwitch(const wchar *Switch)
825 825
           SetTimeFilters(Switch+2,false,false);
826 826
           break;
827 827
         case 'S':
828
-          {
829
-            EXTTIME_MODE Mode=EXTTIME_HIGH3;
830
-            bool CommonMode=Switch[2]>='0' && Switch[2]<='4';
831
-            if (CommonMode)
832
-              Mode=(EXTTIME_MODE)(Switch[2]-'0');
833
-            if (Mode==EXTTIME_HIGH1 || Mode==EXTTIME_HIGH2) // '2' and '3' not supported anymore.
834
-              Mode=EXTTIME_HIGH3;
835
-            if (Switch[2]=='-')
836
-              Mode=EXTTIME_NONE;
837
-            if (CommonMode || Switch[2]=='-' || Switch[2]=='+' || Switch[2]==0)
838
-              xmtime=xctime=xatime=Mode;
839
-            else
840
-            {
841
-              if (Switch[3]>='0' && Switch[3]<='4')
842
-                Mode=(EXTTIME_MODE)(Switch[3]-'0');
843
-              if (Mode==EXTTIME_HIGH1 || Mode==EXTTIME_HIGH2) // '2' and '3' not supported anymore.
844
-                Mode=EXTTIME_HIGH3;
845
-              if (Switch[3]=='-')
846
-                Mode=EXTTIME_NONE;
847
-              switch(toupperw(Switch[2]))
848
-              {
849
-                case 'M':
850
-                  xmtime=Mode;
851
-                  break;
852
-                case 'C':
853
-                  xctime=Mode;
854
-                  break;
855
-                case 'A':
856
-                  xatime=Mode;
857
-                  break;
858
-              }
859
-            }
860
-          }
828
+          SetStoreTimeMode(Switch+2);
861 829
           break;
862 830
         case '-':
863 831
           Test=false;
... ...
@@ -960,7 +931,10 @@ void CommandData::ProcessCommand()
960 960
   if (wcschr(L"AFUMD",*Command)==NULL)
961 961
   {
962 962
     if (GenerateArcName)
963
-      GenerateArchiveName(ArcName,ASIZE(ArcName),GenerateMask,false);
963
+    {
964
+      const wchar *Mask=*GenerateMask!=0 ? GenerateMask:DefGenerateMask;
965
+      GenerateArchiveName(ArcName,ASIZE(ArcName),Mask,false);
966
+    }
964 967
 
965 968
     StringList ArcMasks;
966 969
     ArcMasks.AddString(ArcName);
... ...
@@ -979,7 +953,6 @@ void CommandData::ProcessCommand()
979 979
     case 'X':
980 980
     case 'E':
981 981
     case 'T':
982
-    case 'I':
983 982
       {
984 983
         CmdExtract Extract(this);
985 984
         Extract.DoExtract();
... ...
@@ -1022,7 +995,7 @@ bool CommandData::IsSwitch(int Ch)
1022 1022
 
1023 1023
 
1024 1024
 #ifndef SFX_MODULE
1025
-uint CommandData::GetExclAttr(const wchar *Str)
1025
+uint CommandData::GetExclAttr(const wchar *Str,bool &Dir)
1026 1026
 {
1027 1027
   if (IsDigit(*Str))
1028 1028
     return wcstol(Str,NULL,0);
... ...
@@ -1032,10 +1005,10 @@ uint CommandData::GetExclAttr(const wchar *Str)
1032 1032
   {
1033 1033
     switch(toupperw(*Str))
1034 1034
     {
1035
-#ifdef _UNIX
1036 1035
       case 'D':
1037
-        Attr|=S_IFDIR;
1036
+        Dir=true;
1038 1037
         break;
1038
+#ifdef _UNIX
1039 1039
       case 'V':
1040 1040
         Attr|=S_IFCHR;
1041 1041
         break;
... ...
@@ -1049,9 +1022,6 @@ uint CommandData::GetExclAttr(const wchar *Str)
1049 1049
       case 'S':
1050 1050
         Attr|=0x4;
1051 1051
         break;
1052
-      case 'D':
1053
-        Attr|=0x10;
1054
-        break;
1055 1052
       case 'A':
1056 1053
         Attr|=0x20;
1057 1054
         break;
... ...
@@ -14,9 +14,10 @@ class CommandData:public RAROptions
14 14
     void ProcessSwitchesString(const wchar *Str);
15 15
     void ProcessSwitch(const wchar *Switch);
16 16
     void BadSwitch(const wchar *Switch);
17
-    uint GetExclAttr(const wchar *Str);
17
+    uint GetExclAttr(const wchar *Str,bool &Dir);
18 18
 #if !defined(SFX_MODULE)
19 19
     void SetTimeFilters(const wchar *Mod,bool Before,bool Age);
20
+    void SetStoreTimeMode(const wchar *S);
20 21
 #endif
21 22
 
22 23
     bool FileLists;
... ...
@@ -285,7 +285,10 @@ int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchTy
285 285
 #ifndef SFX_MODULE
286 286
   if (TimeCheck(FileHead.mtime,FileHead.ctime,FileHead.atime))
287 287
     return 0;
288
-  if ((FileHead.FileAttr & ExclFileAttr)!=0 || InclAttrSet && (FileHead.FileAttr & InclFileAttr)==0)
288
+  if ((FileHead.FileAttr & ExclFileAttr)!=0 || FileHead.Dir && ExclDir)
289
+    return 0;
290
+  if (InclAttrSet && (!FileHead.Dir && (FileHead.FileAttr & InclFileAttr)==0 ||
291
+      FileHead.Dir && !InclDir))
289 292
     return 0;
290 293
   if (!Dir && SizeCheck(FileHead.UnpSize))
291 294
     return 0;
... ...
@@ -303,3 +306,47 @@ int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchTy
303 303
     }
304 304
   return 0;
305 305
 }
306
+
307
+
308
+#if !defined(SFX_MODULE)
309
+void CommandData::SetStoreTimeMode(const wchar *S)
310
+{
311
+  if (*S==0 || IsDigit(*S) || *S=='-' || *S=='+')
312
+  {
313
+    // Apply -ts, -ts1, -ts-, -ts+ to all 3 times.
314
+    // Handle obsolete -ts[2,3,4] as ts+.
315
+    EXTTIME_MODE Mode=EXTTIME_MAX;
316
+    if (*S=='-')
317
+      Mode=EXTTIME_NONE;
318
+    if (*S=='1')
319
+      Mode=EXTTIME_1S;
320
+    xmtime=xctime=xatime=Mode;
321
+    S++;
322
+  }
323
+
324
+  while (*S!=0)
325
+  {
326
+    EXTTIME_MODE Mode=EXTTIME_MAX;
327
+    if (S[1]=='-')
328
+      Mode=EXTTIME_NONE;
329
+    if (S[1]=='1')
330
+      Mode=EXTTIME_1S;
331
+    switch(toupperw(*S))
332
+    {
333
+      case 'M':
334
+        xmtime=Mode;
335
+        break;
336
+      case 'C':
337
+        xctime=Mode;
338
+        break;
339
+      case 'A':
340
+        xatime=Mode;
341
+        break;
342
+      case 'P':
343
+        PreserveAtime=true;
344
+        break;
345
+    }
346
+    S++;
347
+  }
348
+}
349
+#endif
... ...
@@ -95,23 +95,23 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
95 95
     r->Flags=0;
96 96
 
97 97
     if (Data->Arc.Volume)
98
-      r->Flags|=0x01;
98
+      r->Flags|=ROADF_VOLUME;
99 99
     if (Data->Arc.MainComment)
100
-      r->Flags|=0x02;
100
+      r->Flags|=ROADF_COMMENT;
101 101
     if (Data->Arc.Locked)
102
-      r->Flags|=0x04;
102
+      r->Flags|=ROADF_LOCK;
103 103
     if (Data->Arc.Solid)
104
-      r->Flags|=0x08;
104
+      r->Flags|=ROADF_SOLID;
105 105
     if (Data->Arc.NewNumbering)
106
-      r->Flags|=0x10;
106
+      r->Flags|=ROADF_NEWNUMBERING;
107 107
     if (Data->Arc.Signed)
108
-      r->Flags|=0x20;
108
+      r->Flags|=ROADF_SIGNED;
109 109
     if (Data->Arc.Protected)
110
-      r->Flags|=0x40;
110
+      r->Flags|=ROADF_RECOVERY;
111 111
     if (Data->Arc.Encrypted)
112
-      r->Flags|=0x80;
112
+      r->Flags|=ROADF_ENCHEADERS;
113 113
     if (Data->Arc.FirstVolume)
114
-      r->Flags|=0x100;
114
+      r->Flags|=ROADF_FIRSTVOLUME;
115 115
 
116 116
     Array<wchar> CmtDataW;
117 117
     if (r->CmtBufSize!=0 && Data->Arc.GetComment(&CmtDataW))
... ...
@@ -2,8 +2,8 @@
2 2
 #include <commctrl.h>
3 3
 
4 4
 VS_VERSION_INFO VERSIONINFO
5
-FILEVERSION 5, 71, 100, 3045
6
-PRODUCTVERSION 5, 71, 100, 3045
5
+FILEVERSION 5, 90, 100, 3379
6
+PRODUCTVERSION 5, 90, 100, 3379
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.71.0\0"
18
-      VALUE "ProductVersion", "5.71.0\0"
19

                
17
+      VALUE "FileVersion", "5.90.0\0"
18
+      VALUE "ProductVersion", "5.90.0\0"
19

                
20 20
       VALUE "OriginalFilename", "Unrar.dll\0"
21 21
     }
22 22
   }
... ...
@@ -158,6 +158,7 @@ void ErrorHandler::OpenErrorMsg(const wchar *FileName)
158 158
 
159 159
 void ErrorHandler::OpenErrorMsg(const wchar *ArcName,const wchar *FileName)
160 160
 {
161
+  Wait(); // Keep GUI responsive if many files cannot be opened when archiving.
161 162
   uiMsg(UIERROR_FILEOPEN,ArcName,FileName);
162 163
   SysErrMsg();
163 164
   SetErrorCode(RARX_OPEN);
... ...
@@ -328,7 +329,7 @@ void ErrorHandler::Throw(RAR_EXIT Code)
328 328
 
329 329
 bool ErrorHandler::GetSysErrMsg(wchar *Msg,size_t Size)
330 330
 {
331
-#if !defined(SFX_MODULE) && !defined(SILENT)
331
+#ifndef SILENT
332 332
 #ifdef _WIN_ALL
333 333
   int ErrType=GetLastError();
334 334
   if (ErrType!=0)
... ...
@@ -361,7 +362,7 @@ void ErrorHandler::SysErrMsg()
361 361
     return;
362 362
 #ifdef _WIN_ALL
363 363
   wchar *CurMsg=Msg;
364
-  while (CurMsg!=NULL)
364
+  while (CurMsg!=NULL) // Print string with \r\n as several strings to multiple lines.
365 365
   {
366 366
     while (*CurMsg=='\r' || *CurMsg=='\n')
367 367
       CurMsg++;
... ...
@@ -40,6 +40,8 @@ void CmdExtract::DoExtract()
40 40
   {
41 41
     if (Cmd->ManualPassword)
42 42
       Cmd->Password.Clean(); // Clean user entered password before processing next archive.
43
+  
44
+    ReconstructDone=false; // Must be reset here, not in ExtractArchiveInit().
43 45
     while (true)
44 46
     {
45 47
       EXTRACT_ARC_CODE Code=ExtractArchive();
... ...
@@ -93,7 +95,6 @@ void CmdExtract::ExtractArchiveInit(Archive &Arc)
93 93
 
94 94
   PrevProcessed=false;
95 95
   AllMatchesExact=true;
96
-  ReconstructDone=false;
97 96
   AnySolidDataUnpackedWell=false;
98 97
 
99 98
   StartTime.SetCurrentTime();
... ...
@@ -479,13 +480,13 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
479 479
         {
480 480
           // This message is used by Android GUI to reset cached passwords.
481 481
           // Update appropriate code if changed.
482
-          uiMsg(UIERROR_BADPSW,ArcFileName);
482
+          uiMsg(UIERROR_BADPSW,Arc.FileName,ArcFileName);
483 483
         }
484 484
         else // For passwords entered manually.
485 485
         {
486 486
           // This message is used by Android GUI and Windows GUI and SFX to
487 487
           // reset cached passwords. Update appropriate code if changed.
488
-          uiMsg(UIWAIT_BADPSW,ArcFileName);
488
+          uiMsg(UIWAIT_BADPSW,Arc.FileName,ArcFileName);
489 489
           Cmd->Password.Clean();
490 490
 
491 491
           // Avoid new requests for unrar.dll to prevent the infinite loop
... ...
@@ -624,7 +625,6 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
624 624
         CurFile.Prealloc(Arc.FileHead.UnpSize);
625 625
         Preallocated=Arc.FileHead.UnpSize;
626 626
       }
627
-
628 627
       CurFile.SetAllowDelete(!Cmd->KeepBroken);
629 628
 
630 629
       bool FileCreateMode=!TestMode && !SkipSolid && Command!='P';
... ...
@@ -736,38 +736,52 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
736 736
       else
737 737
         mprintf(L"\b\b\b\b\b     ");
738 738
 
739
+      // If we successfully unpacked a hard link, we wish to set its file
740
+      // attributes. Hard link shares file metadata with link target,
741
+      // so we do not need to set link time or owner. But when we overwrite
742
+      // an existing link, we can call PrepareToDelete(), which affects
743
+      // link target attributes as well. So we set link attributes to restore
744
+      // both target and link attributes if PrepareToDelete() changed them.
745
+      bool SetAttrOnly=LinkEntry && Arc.FileHead.RedirType==FSREDIR_HARDLINK && LinkSuccess;
746
+
739 747
       if (!TestMode && (Command=='X' || Command=='E') &&
740
-          (!LinkEntry || Arc.FileHead.RedirType==FSREDIR_FILECOPY && LinkSuccess) && 
748
+          (!LinkEntry || SetAttrOnly || Arc.FileHead.RedirType==FSREDIR_FILECOPY && LinkSuccess) && 
741 749
           (!BrokenFile || Cmd->KeepBroken))
742 750
       {
743
-        // We could preallocate more space that really written to broken file
744
-        // or file with crafted header.
745
-        if (Preallocated>0 && (BrokenFile || DataIO.CurUnpWrite!=Preallocated))
746
-          CurFile.Truncate();
751
+        // Below we use DestFileName instead of CurFile.FileName,
752
+        // so we can set file attributes also for hard links, which do not
753
+        // have the open CurFile. These strings are the same for other items.
747 754
 
748
-#if defined(_WIN_ALL) || defined(_EMX)
749
-        if (Cmd->ClearArc)
750
-          Arc.FileHead.FileAttr&=~FILE_ATTRIBUTE_ARCHIVE;
751
-#endif
755
+        if (!SetAttrOnly)
756
+        {
757
+          // We could preallocate more space that really written to broken file
758
+          // or file with crafted header.
759
+          if (Preallocated>0 && (BrokenFile || DataIO.CurUnpWrite!=Preallocated))
760
+            CurFile.Truncate();
752 761
 
753 762
 
754
-        CurFile.SetOpenFileTime(
755
-          Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime,
756
-          Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.FileHead.ctime,
757
-          Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime);
758
-        CurFile.Close();
763
+          CurFile.SetOpenFileTime(
764
+            Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime,
765
+            Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.FileHead.ctime,
766
+            Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime);
767
+          CurFile.Close();
768
+
769
+          SetFileHeaderExtra(Cmd,Arc,DestFileName);
770
+
771
+          CurFile.SetCloseFileTime(
772
+            Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime,
773
+            Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime);
774
+        }
775
+        
759 776
 #if defined(_WIN_ALL) && !defined(SFX_MODULE)
760 777
         if (Cmd->SetCompressedAttr &&
761 778
             (Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0)
762
-          SetFileCompression(CurFile.FileName,true);
779
+          SetFileCompression(DestFileName,true);
780
+        if (Cmd->ClearArc)
781
+          Arc.FileHead.FileAttr&=~FILE_ATTRIBUTE_ARCHIVE;
763 782
 #endif
764
-        SetFileHeaderExtra(Cmd,Arc,CurFile.FileName);
765
-
766
-        CurFile.SetCloseFileTime(
767
-          Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime,
768
-          Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime);
769
-        if (!Cmd->IgnoreGeneralAttr && !SetFileAttr(CurFile.FileName,Arc.FileHead.FileAttr))
770
-          uiMsg(UIERROR_FILEATTR,Arc.FileName,CurFile.FileName);
783
+        if (!Cmd->IgnoreGeneralAttr && !SetFileAttr(DestFileName,Arc.FileHead.FileAttr))
784
+          uiMsg(UIERROR_FILEATTR,Arc.FileName,DestFileName);
771 785
 
772 786
         PrevProcessed=true;
773 787
       }
... ...
@@ -13,6 +13,7 @@ File::File()
13 13
   OpenShared=false;
14 14
   AllowDelete=true;
15 15
   AllowExceptions=true;
16
+  PreserveAtime=false;
16 17
 #ifdef _WIN_ALL
17 18
   NoSequentialRead=false;
18 19
   CreateMode=FMF_UNDEFINED;
... ...
@@ -56,6 +57,9 @@ bool File::Open(const wchar *Name,uint Mode)
56 56
   if (OpenShared)
57 57
     ShareMode|=FILE_SHARE_WRITE;
58 58
   uint Flags=NoSequentialRead ? 0:FILE_FLAG_SEQUENTIAL_SCAN;
59
+  FindData FD;
60
+  if (PreserveAtime)
61
+    Access|=FILE_WRITE_ATTRIBUTES; // Needed to preserve atime.
59 62
   hNewFile=CreateFile(Name,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
60 63
 
61 64
   DWORD LastError;
... ...
@@ -86,6 +90,11 @@ bool File::Open(const wchar *Name,uint Mode)
86 86
   }
87 87
   if (hNewFile==FILE_BAD_HANDLE && LastError==ERROR_FILE_NOT_FOUND)
88 88
     ErrorType=FILE_NOTFOUND;
89
+  if (PreserveAtime && hNewFile!=FILE_BAD_HANDLE)
90
+  {
91
+    FILETIME ft={0xffffffff,0xffffffff}; // This value prevents atime modification.
92
+    SetFileTime(hNewFile,NULL,&ft,NULL);
93
+  }
89 94
 
90 95
 #else
91 96
   int flags=UpdateMode ? O_RDWR:(WriteMode ? O_WRONLY:O_RDONLY);
... ...
@@ -95,6 +104,11 @@ bool File::Open(const wchar *Name,uint Mode)
95 95
   flags|=O_LARGEFILE;
96 96
 #endif
97 97
 #endif
98
+  // NDK r20 has O_NOATIME, but fails to create files with it in Android 7+.
99
+#if defined(O_NOATIME)
100
+  if (PreserveAtime)
101
+    flags|=O_NOATIME;
102
+#endif
98 103
   char NameA[NM];
99 104
   WideToChar(Name,NameA,ASIZE(NameA));
100 105
 
... ...
@@ -230,7 +244,7 @@ bool File::Close()
230 230
     {
231 231
 #ifdef _WIN_ALL
232 232
       // We use the standard system handle for stdout in Windows
233
-      // and it must not  be closed here.
233
+      // and it must not be closed here.
234 234
       if (HandleType==FILE_HANDLENORMAL)
235 235
         Success=CloseHandle(hFile)==TRUE;
236 236
 #else
... ...
@@ -387,7 +401,7 @@ int File::Read(void *Data,size_t Size)
387 387
     }
388 388
     break;
389 389
   }
390
-  return ReadSize;
390
+  return ReadSize; // It can return -1 only if AllowExceptions is disabled.
391 391
 }
392 392
 
393 393
 
... ...
@@ -670,9 +684,11 @@ void File::GetOpenFileTime(RarTime *ft)
670 670
 
671 671
 int64 File::FileLength()
672 672
 {
673
-  SaveFilePos SavePos(*this);
673
+  int64 SavePos=Tell();
674 674
   Seek(0,SEEK_END);
675
-  return Tell();
675
+  int64 Length=Tell();
676
+  Seek(SavePos,SEEK_SET);
677
+  return Length;
676 678
 }
677 679
 
678 680
 
... ...
@@ -62,6 +62,7 @@ class File
62 62
     bool NoSequentialRead;
63 63
     uint CreateMode;
64 64
 #endif
65
+    bool PreserveAtime;
65 66
   protected:
66 67
     bool OpenShared; // Set by 'Archive' class.
67 68
   public:
... ...
@@ -114,6 +115,7 @@ class File
114 114
 #ifdef _WIN_ALL
115 115
     void RemoveSequentialFlag() {NoSequentialRead=true;}
116 116
 #endif
117
+    void SetPreserveAtime(bool Preserve) {PreserveAtime=Preserve;}
117 118
 #ifdef _UNIX
118 119
     int GetFD()
119 120
     {
... ...
@@ -360,7 +360,7 @@ wchar *MkTemp(wchar *Name,size_t MaxSize)
360 360
 #if !defined(SFX_MODULE)
361 361
 void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,uint Flags)
362 362
 {
363
-  SaveFilePos SavePos(*SrcFile);
363
+  int64 SavePos=SrcFile->Tell();
364 364
 #ifndef SILENT
365 365
   int64 FileLength=Size==INT64NDF ? SrcFile->FileLength() : Size;
366 366
 #endif
... ...
@@ -415,6 +415,8 @@ void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,
415 415
     if (Size!=INT64NDF)
416 416
       Size-=ReadSize;
417 417
   }
418
+  SrcFile->Seek(SavePos,SEEK_SET);
419
+
418 420
   if ((Flags & CALCFSUM_SHOWPERCENT)!=0)
419 421
     uiMsg(UIEVENT_FILESUMEND);
420 422
 
... ...
@@ -63,12 +63,12 @@ bool FindFile::Next(FindData *fd,bool GetSymLink)
63 63
   }
64 64
   while (1)
65 65
   {
66
+    wchar Name[NM];
66 67
     struct dirent *ent=readdir(dirp);
67 68
     if (ent==NULL)
68 69
       return false;
69 70
     if (strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0)
70 71
       continue;
71
-    wchar Name[NM];
72 72
     if (!CharToWide(ent->d_name,Name,ASIZE(Name)))
73 73
       uiMsg(UIERROR_INVALIDNAME,UINULL,Name);
74 74
 
... ...
@@ -53,7 +53,7 @@ DataHash::DataHash()
53 53
 DataHash::~DataHash()
54 54
 {
55 55
 #ifdef RAR_SMP
56
-  DestroyThreadPool(ThPool);
56
+  delete ThPool;
57 57
 #endif
58 58
   cleandata(&CurCRC32, sizeof(CurCRC32));
59 59
   if (blake2ctx!=NULL)
... ...
@@ -94,7 +94,7 @@ void DataHash::Update(const void *Data,size_t DataSize)
94 94
   {
95 95
 #ifdef RAR_SMP
96 96
     if (MaxThreads>1 && ThPool==NULL)
97
-      ThPool=CreateThreadPool();
97
+      ThPool=new ThreadPool(BLAKE2_THREADS_NUMBER);
98 98
     blake2ctx->ThPool=ThPool;
99 99
     blake2ctx->MaxThreads=MaxThreads;
100 100
 #endif
... ...
@@ -345,7 +345,7 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
345 345
       mprintf(L"\n%12ls: %ls",St(MListHostOS),HostOS);
346 346
 
347 347
     mprintf(L"\n%12ls: RAR %ls(v%d) -m%d -md=%d%s",St(MListCompInfo),
348
-            Format==RARFMT15 ? L"3.0":L"5.0",
348
+            Format==RARFMT15 ? L"1.5":L"5.0",
349 349
             hd.UnpVer==VER_UNKNOWN ? 0 : hd.UnpVer,hd.Method,
350 350
             hd.WinSize>=0x100000 ? hd.WinSize/0x100000:hd.WinSize/0x400,
351 351
             hd.WinSize>=0x100000 ? L"M":L"K");
... ...
@@ -131,7 +131,7 @@
131 131
 #define   MCHelpSwTO         L"\n  to[mcao]<t>   Process files older than <t> time"
132 132
 #define   MCHelpSwTA         L"\n  ta[mcao]<d>   Process files modified after <d> YYYYMMDDHHMMSS date"
133 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)"
134
+#define   MCHelpSwTS         L"\n  ts[m,c,a,p]   Save or restore time (modification, creation, access, preserve)"
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"
... ...
@@ -203,7 +203,6 @@
203 203
 #define   MErrOpenFile       L"file"
204 204
 #define   MAddNoFiles        L"\nWARNING: No files"
205 205
 #define   MMdfEncrSol        L"\n%s: encrypted"
206
-#define   MCannotMdfEncrSol  L"\nCannot modify solid archive containing encrypted files"
207 206
 #define   MAddAnalyze        L"\nAnalyzing archived files: "
208 207
 #define   MRepacking         L"\nRepacking archived files: "
209 208
 #define   MCRCFailed         L"\n%-20s - checksum error"
... ...
@@ -342,7 +341,7 @@
342 342
 #define   MFAT32Size         L"\nWARNING: FAT32 file system does not support 4 GB or larger files"
343 343
 #define   MErrChangeAttr     L"\nWARNING: Cannot change attributes of %s"
344 344
 #define   MWrongSFXVer       L"\nERROR: default SFX module does not support RAR %d.%d archives"
345
-#define   MCannotEncName     L"\nCannot encrypt archive already containing encrypted files"
345
+#define   MHeadEncMismatch   L"\nCannot change the header encryption mode in already encrypted archive"
346 346
 #define   MCannotEmail       L"\nCannot email the file %s"
347 347
 #define   MCopyrightS        L"\nRAR SFX archive" 
348 348
 #define   MSHelpCmd          L"\n\n<Commands>" 
... ...
@@ -360,6 +359,7 @@
360 360
 #define   MNewerRAR          L"\nYou may need a newer version of RAR."
361 361
 #define   MUnkEncMethod      L"\nUnknown encryption method in %s"
362 362
 #define   MWrongPassword     L"\nThe specified password is incorrect."
363
+#define   MWrongFilePassword L"\nIncorrect password for %s"
363 364
 #define   MAreaDamaged       L"\nCorrupt %d bytes at %08x %08x"
364 365
 #define   MBlocksRecovered   L"\n%u blocks are recovered, %u blocks are relocated"
365 366
 #define   MRRDamaged         L"\nRecovery record is corrupt."
... ...
@@ -379,3 +379,4 @@
379 379
 #define   MNeedAdmin         L"\nYou may need to run RAR as administrator"
380 380
 #define   MDictOutMem        L"\nNot enough memory for %d MB compression dictionary, changed to %d MB."
381 381
 #define   MUseSmalllerDict   L"\nPlease use a smaller compression dictionary."
382
+#define   MOpenErrAtime      L"\nYou may need to remove -tsp switch to open this file."
... ...
@@ -22,7 +22,7 @@ void RAROptions::Init()
22 22
   Method=3;
23 23
   MsgStream=MSG_STDOUT;
24 24
   ConvertNames=NAMES_ORIGINALCASE;
25
-  xmtime=EXTTIME_HIGH3;
25
+  xmtime=EXTTIME_MAX;
26 26
   FileSizeLess=INT64NDF;
27 27
   FileSizeMore=INT64NDF;
28 28
   HashType=HASH_CRC32;
... ...
@@ -21,7 +21,7 @@ enum {SOLID_NONE=0,SOLID_NORMAL=1,SOLID_COUNT=2,SOLID_FILEEXT=4,
21 21
 enum {ARCTIME_NONE=0,ARCTIME_KEEP,ARCTIME_LATEST};
22 22
 
23 23
 enum EXTTIME_MODE {
24
-  EXTTIME_NONE=0,EXTTIME_1S,EXTTIME_HIGH1,EXTTIME_HIGH2,EXTTIME_HIGH3
24
+  EXTTIME_NONE=0,EXTTIME_1S,EXTTIME_MAX
25 25
 };
26 26
 
27 27
 enum {NAMES_ORIGINALCASE=0,NAMES_UPPERCASE,NAMES_LOWERCASE};
... ...
@@ -92,6 +92,12 @@ class RAROptions
92 92
 
93 93
     uint ExclFileAttr;
94 94
     uint InclFileAttr;
95
+
96
+    // We handle -ed and -e+d with special flags instead of attribute mask,
97
+    // so it works with both Windows and Unix archives.
98
+    bool ExclDir;
99
+    bool InclDir;
100
+
95 101
     bool InclAttrSet;
96 102
     size_t WinSize;
97 103
     wchar TempPath[NM];
... ...
@@ -162,6 +168,7 @@ class RAROptions
162 162
 #ifndef SFX_MODULE
163 163
     bool GenerateArcName;
164 164
     wchar GenerateMask[MAX_GENERATE_MASK];
165
+    wchar DefGenerateMask[MAX_GENERATE_MASK];
165 166
 #endif
166 167
     bool SyncFiles;
167 168
     bool ProcessEA;
... ...
@@ -185,6 +192,7 @@ class RAROptions
185 185
     EXTTIME_MODE xmtime; // Extended time modes (time precision to store).
186 186
     EXTTIME_MODE xctime;
187 187
     EXTTIME_MODE xatime;
188
+    bool PreserveAtime;
188 189
     wchar CompressStdin[NM];
189 190
 
190 191
     uint Threads; // We use it to init hash even if RAR_SMP is not defined.
... ...
@@ -133,7 +133,7 @@
133 133
 
134 134
 #ifdef _UNIX
135 135
 
136
-#define  NM  2048
136
+#define NM  2048
137 137
 
138 138
 #include <unistd.h>
139 139
 #include <sys/types.h>
... ...
@@ -170,14 +170,17 @@ int GetPathDisk(const wchar *Path)
170 170
 void AddEndSlash(wchar *Path,size_t MaxLength)
171 171
 {
172 172
   size_t Length=wcslen(Path);
173
-  if (Length>0 && Path[Length-1]!=CPATHDIVIDER)
174
-    wcsncatz(Path,SPATHDIVIDER,MaxLength);
173
+  if (Length>0 && Path[Length-1]!=CPATHDIVIDER && Length+1<MaxLength)
174
+  {
175
+    Path[Length]=CPATHDIVIDER;
176
+    Path[Length+1]=0;
177
+  }
175 178
 }
176 179
 
177 180
 
178 181
 void MakeName(const wchar *Path,const wchar *Name,wchar *Pathname,size_t MaxSize)
179 182
 {
180
-  // 'Name' and 'Pathname' can point to same memory area. This is why we use
183
+  // 'Path', 'Name' and 'Pathname' can point to same memory area. So we use
181 184
   // the temporary buffer instead of constructing the name in 'Pathname'.
182 185
   wchar OutName[NM];
183 186
   wcsncpyz(OutName,Path,ASIZE(OutName));
... ...
@@ -67,7 +67,7 @@ void QuickOpen::Load(uint64 BlockPos)
67 67
     SeekPos=Arc->Tell();
68 68
     UnsyncSeekPos=false;
69 69
 
70
-    SaveFilePos SavePos(*Arc);
70
+    int64 SavePos=SeekPos;
71 71
     Arc->Seek(BlockPos,SEEK_SET);
72 72
 
73 73
     // If BlockPos points to original main header, we'll have the infinite
... ...
@@ -83,10 +83,14 @@ void QuickOpen::Load(uint64 BlockPos)
83 83
 
84 84
     if (ReadSize==0 || Arc->GetHeaderType()!=HEAD_SERVICE ||
85 85
         !Arc->SubHead.CmpName(SUBHEAD_TYPE_QOPEN))
86
+    {
87
+      Arc->Seek(SavePos,SEEK_SET);
86 88
       return;
89
+    }
87 90
     QOHeaderPos=Arc->CurBlockPos;
88 91
     RawDataStart=Arc->Tell();
89 92
     RawDataSize=Arc->SubHead.UnpSize;
93
+    Arc->Seek(SavePos,SEEK_SET);
90 94
 
91 95
     Loaded=true; // Set only after all file processing calls like Tell, Seek, ReadHeader.
92 96
   }
... ...
@@ -201,22 +205,28 @@ bool QuickOpen::Tell(int64 *Pos)
201 201
 
202 202
 uint QuickOpen::ReadBuffer()
203 203
 {
204
-  SaveFilePos SavePos(*Arc);
204
+  int64 SavePos=Arc->Tell();
205 205
   Arc->File::Seek(RawDataStart+RawDataPos,SEEK_SET);
206 206
   size_t SizeToRead=(size_t)Min(RawDataSize-RawDataPos,MaxBufSize-ReadBufSize);
207 207
   if (Arc->SubHead.Encrypted)
208 208
     SizeToRead &= ~CRYPT_BLOCK_MASK;
209
-  if (SizeToRead==0)
210
-    return 0;
211
-  int ReadSize=Arc->File::Read(Buf+ReadBufSize,SizeToRead);
212
-  if (ReadSize<=0)
213
-    return 0;
209
+  int ReadSize=0;
210
+  if (SizeToRead!=0)
211
+  {
212
+    ReadSize=Arc->File::Read(Buf+ReadBufSize,SizeToRead);
213
+    if (ReadSize<=0)
214
+      ReadSize=0;
215
+    else
216
+    {
214 217
 #ifndef RAR_NOCRYPT
215
-  if (Arc->SubHead.Encrypted)
216
-    Crypt.DecryptBlock(Buf+ReadBufSize,ReadSize & ~CRYPT_BLOCK_MASK);
218
+      if (Arc->SubHead.Encrypted)
219
+        Crypt.DecryptBlock(Buf+ReadBufSize,ReadSize & ~CRYPT_BLOCK_MASK);
217 220
 #endif
218
-  RawDataPos+=ReadSize;
219
-  ReadBufSize+=ReadSize;
221
+      RawDataPos+=ReadSize;
222
+      ReadBufSize+=ReadSize;
223
+    }
224
+  }
225
+  Arc->Seek(SavePos,SEEK_SET);
220 226
   return ReadSize;
221 227
 }
222 228
 
... ...
@@ -39,7 +39,6 @@
39 39
 #include "filestr.hpp"
40 40
 #include "find.hpp"
41 41
 #include "scantree.hpp"
42
-#include "savepos.hpp"
43 42
 #include "getbits.hpp"
44 43
 #include "rdwrfn.hpp"
45 44
 #ifdef USE_QOPEN
... ...
@@ -77,6 +76,9 @@
77 77
 
78 78
 #include "rs.hpp"
79 79
 #include "rs16.hpp"
80
+
81
+
82
+
80 83
 #include "recvol.hpp"
81 84
 #include "volume.hpp"
82 85
 #include "smallfn.hpp"
... ...
@@ -21,15 +21,12 @@ typedef wchar_t          wchar;  // Unicode character
21 21
 // Maximum int64 value.
22 22
 #define MAX_INT64 int64(INT32TO64(0x7fffffff,0xffffffff))
23 23
 
24
-// Special int64 value, large enough to never be found in real life.
24
+// Special int64 value, large enough to never be found in real life
25
+// and small enough to fit to both signed and unsigned 64-bit ints.
25 26
 // We use it in situations, when we need to indicate that parameter 
26 27
 // is not defined and probably should be calculated inside of function.
27 28
 // Lower part is intentionally 0x7fffffff, not 0xffffffff, to make it 
28
-// compatible with 32 bit int64.
29
+// compatible with 32 bit int64 if 64 bit type is not supported.
29 30
 #define INT64NDF INT32TO64(0x7fffffff,0x7fffffff)
30 31
 
31
-// Maximum uint64 value.
32
-#define MAX_UINT64 INT32TO64(0xffffffff,0xffffffff)
33
-#define UINT64NDF MAX_UINT64
34
-
35 32
 #endif
... ...
@@ -3,6 +3,7 @@
3 3
 
4 4
 class CmdAdd;
5 5
 class Unpack;
6
+class ArcFileSearch;
6 7
 
7 8
 #if 0
8 9
 // We use external i/o calls for Benchmark command.
... ...
@@ -31,12 +31,12 @@ bool RecVolumesRestore(RAROptions *Cmd,const wchar *Name,bool Silent)
31 31
   // handling exceptions. So it can close and delete files on Cancel.
32 32
   if (Fmt==RARFMT15)
33 33
   {
34
-    RecVolumes3 RecVol(false);
34
+    RecVolumes3 RecVol(Cmd,false);
35 35
     return RecVol.Restore(Cmd,Name,Silent);
36 36
   }
37 37
   else
38 38
   {
39
-    RecVolumes5 RecVol(false);
39
+    RecVolumes5 RecVol(Cmd,false);
40 40
     return RecVol.Restore(Cmd,Name,Silent);
41 41
   }
42 42
 }
... ...
@@ -100,12 +100,12 @@ void RecVolumesTest(RAROptions *Cmd,Archive *Arc,const wchar *Name)
100 100
   RevFile.Close();
101 101
   if (Rev5)
102 102
   {
103
-    RecVolumes5 RecVol(true);
103
+    RecVolumes5 RecVol(Cmd,true);
104 104
     RecVol.Test(Cmd,Name);
105 105
   }
106 106
   else
107 107
   {
108
-    RecVolumes3 RecVol(true);
108
+    RecVolumes3 RecVol(Cmd,true);
109 109
     RecVol.Test(Cmd,Name);
110 110
   }
111 111
 }
... ...
@@ -14,7 +14,7 @@ class RecVolumes3
14 14
     ThreadPool *RSThreadPool;
15 15
 #endif
16 16
   public:
17
-    RecVolumes3(bool TestOnly);
17
+    RecVolumes3(RAROptions *Cmd,bool TestOnly);
18 18
     ~RecVolumes3();
19 19
     void Make(RAROptions *Cmd,wchar *ArcName);
20 20
     bool Restore(RAROptions *Cmd,const wchar *Name,bool Silent);
... ...
@@ -71,11 +71,12 @@ class RecVolumes5
71 71
 #ifdef RAR_SMP
72 72
     ThreadPool *RecThreadPool;
73 73
 #endif
74
-    RecRSThreadData ThreadData[MaxPoolThreads]; // Store thread parameters.
74
+    uint MaxUserThreads; // Maximum number of threads defined by user.
75
+    RecRSThreadData *ThreadData; // Array to store thread parameters.
75 76
   public: // 'public' only because called from thread functions.
76 77
     void ProcessAreaRS(RecRSThreadData *td);
77 78
   public:
78
-    RecVolumes5(bool TestOnly);
79
+    RecVolumes5(RAROptions *Cmd,bool TestOnly);
79 80
     ~RecVolumes5();
80 81
     bool Restore(RAROptions *Cmd,const wchar *Name,bool Silent);
81 82
     void Test(RAROptions *Cmd,const wchar *Name);
... ...
@@ -36,7 +36,7 @@ THREAD_PROC(RSDecodeThread)
36 36
 }
37 37
 #endif
38 38
 
39
-RecVolumes3::RecVolumes3(bool TestOnly)
39
+RecVolumes3::RecVolumes3(RAROptions *Cmd,bool TestOnly)
40 40
 {
41 41
   memset(SrcFile,0,sizeof(SrcFile));
42 42
   if (TestOnly)
... ...
@@ -50,7 +50,7 @@ RecVolumes3::RecVolumes3(bool TestOnly)
50 50
     Buf.Alloc(TotalBufferSize);
51 51
     memset(SrcFile,0,sizeof(SrcFile));
52 52
 #ifdef RAR_SMP
53
-    RSThreadPool=CreateThreadPool();
53
+    RSThreadPool=new ThreadPool(Cmd->Threads);
54 54
 #endif
55 55
   }
56 56
 }
... ...
@@ -61,7 +61,7 @@ RecVolumes3::~RecVolumes3()
61 61
   for (size_t I=0;I<ASIZE(SrcFile);I++)
62 62
     delete SrcFile[I];
63 63
 #ifdef RAR_SMP
64
-  DestroyThreadPool(RSThreadPool);
64
+  delete RSThreadPool;
65 65
 #endif
66 66
 }
67 67
 
... ...
@@ -363,11 +363,10 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
363 363
 
364 364
 #ifdef RAR_SMP
365 365
   uint ThreadNumber=Cmd->Threads;
366
-  RSEncode rse[MaxPoolThreads];
367 366
 #else
368 367
   uint ThreadNumber=1;
369
-  RSEncode rse[1];
370 368
 #endif
369
+  RSEncode *rse=new RSEncode[ThreadNumber];
371 370
   for (uint I=0;I<ThreadNumber;I++)
372 371
     rse[I].Init(RecVolNumber);
373 372
 
... ...
@@ -438,6 +437,8 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
438 438
       if (WriteFlags[I])
439 439
         SrcFile[I]->Write(&Buf[I*RecBufferSize],MaxRead);
440 440
   }
441
+  delete[] rse;
442
+
441 443
   for (int I=0;I<RecVolNumber+FileNumber;I++)
442 444
     if (SrcFile[I]!=NULL)
443 445
     {
... ...
@@ -1,6 +1,6 @@
1 1
 static const uint MaxVolumes=65535;
2 2
 
3
-RecVolumes5::RecVolumes5(bool TestOnly)
3
+RecVolumes5::RecVolumes5(RAROptions *Cmd,bool TestOnly)
4 4
 {
5 5
   RealBuf=NULL;
6 6
   RealReadBuffer=NULL;
... ...
@@ -10,7 +10,14 @@ RecVolumes5::RecVolumes5(bool TestOnly)
10 10
   TotalCount=0;
11 11
   RecBufferSize=0;
12 12
 
13
-  for (uint I=0;I<ASIZE(ThreadData);I++)
13
+#ifdef RAR_SMP
14
+  MaxUserThreads=Cmd->Threads;
15
+#else
16
+  MaxUserThreads=1;
17
+#endif
18
+
19
+  ThreadData=new RecRSThreadData[MaxUserThreads];
20
+  for (uint I=0;I<MaxUserThreads;I++)
14 21
   {
15 22
     ThreadData[I].RecRSPtr=this;
16 23
     ThreadData[I].RS=NULL;
... ...
@@ -25,7 +32,7 @@ RecVolumes5::RecVolumes5(bool TestOnly)
25 25
   else
26 26
   {
27 27
 #ifdef RAR_SMP
28
-    RecThreadPool=CreateThreadPool();
28
+    RecThreadPool=new ThreadPool(MaxUserThreads);
29 29
 #endif
30 30
     RealBuf=new byte[TotalBufferSize+SSE_ALIGNMENT];
31 31
     Buf=(byte *)ALIGN_VALUE(RealBuf,SSE_ALIGNMENT);
... ...
@@ -39,10 +46,11 @@ RecVolumes5::~RecVolumes5()
39 39
   delete[] RealReadBuffer;
40 40
   for (uint I=0;I<RecItems.Size();I++)
41 41
     delete RecItems[I].f;
42
-  for (uint I=0;I<ASIZE(ThreadData);I++)
42
+  for (uint I=0;I<MaxUserThreads;I++)
43 43
     delete ThreadData[I].RS;
44
+  delete[] ThreadData;
44 45
 #ifdef RAR_SMP
45
-  DestroyThreadPool(RecThreadPool);
46
+  delete RecThreadPool;
46 47
 #endif
47 48
 }
48 49
 
... ...
@@ -68,11 +76,7 @@ void RecVolumes5::ProcessRS(RAROptions *Cmd,uint DataNum,const byte *Data,uint M
68 68
     RS.UpdateECC(DataNum, I, Data, Buf+I*RecBufferSize, MaxRead);
69 69
 */
70 70
 
71
-#ifdef RAR_SMP
72
-  uint ThreadNumber=Cmd->Threads;
73
-#else
74
-  uint ThreadNumber=1;
75
-#endif
71
+  uint ThreadNumber=MaxUserThreads;
76 72
 
77 73
   const uint MinThreadBlock=0x1000;
78 74
   ThreadNumber=Min(ThreadNumber,MaxRead/MinThreadBlock);
... ...
@@ -238,7 +242,7 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
238 238
       uiMsg(UIMSG_STRING,Item->Name);
239 239
 
240 240
       uint RevCRC;
241
-      CalcFileSum(Item->f,&RevCRC,NULL,Cmd->Threads,INT64NDF,CALCFSUM_CURPOS);
241
+      CalcFileSum(Item->f,&RevCRC,NULL,MaxUserThreads,INT64NDF,CALCFSUM_CURPOS);
242 242
       Item->Valid=RevCRC==Item->CRC;
243 243
       if (!Item->Valid)
244 244
       {
... ...
@@ -2,8 +2,10 @@
2 2
 
3 3
 
4 4
 
5
+
6
+
5 7
 #ifndef RARDLL
6
-const wchar *St(MSGID StringId)
8
+const wchar* St(MSGID StringId)
7 9
 {
8 10
   return StringId;
9 11
 }
... ...
@@ -75,8 +75,14 @@ void Rijndael::Init(bool Encrypt,const byte *key,uint keyLen,const byte * initVe
75 75
   // Check SSE here instead of constructor, so if object is a part of some
76 76
   // structure memset'ed before use, this variable is not lost.
77 77
   int CPUInfo[4];
78
-  __cpuid(CPUInfo, 1);
79
-  AES_NI=(CPUInfo[2] & 0x2000000)!=0;
78
+  __cpuid(CPUInfo, 0x80000000); // Get the maximum supported cpuid function.
79
+  if ((CPUInfo[0] & 0x7fffffff)>=1)
80
+  {
81
+    __cpuid(CPUInfo, 1);
82
+    AES_NI=(CPUInfo[2] & 0x2000000)!=0;
83
+  }
84
+  else
85
+    AES_NI=0;
80 86
 #endif
81 87
 
82 88
   // Other developers asked us to initialize it to suppress "may be used
... ...
@@ -14,13 +14,26 @@ class SaveFilePos
14 14
     }
15 15
     ~SaveFilePos()
16 16
     {
17
-      // If file is already closed by current exception processing,
18
-      // we would get uneeded error messages and an exception inside of
19
-      // exception and terminate if we try to seek without checking
20
-      // if file is still opened. We should not also restore the position
21
-      // if external code closed the file on purpose.
17
+      // Unless the file is already closed either by current exception
18
+      // processing or intentionally by external code.
22 19
       if (SaveFile->IsOpened())
23
-        SaveFile->Seek(SavePos,SEEK_SET);
20
+      {
21
+        try
22
+        {
23
+          SaveFile->Seek(SavePos,SEEK_SET);
24
+        }
25
+        catch(RAR_EXIT)
26
+        {
27
+          // Seek() can throw an exception and it terminates process
28
+          // if we are already processing another exception. Also in C++ 11
29
+          // an exception in destructor always terminates process unless
30
+          // we mark destructor with noexcept(false). So we do not want to
31
+          // throw here. To prevent data loss we do not want to continue
32
+          // execution after seek error, so we close the file.
33
+          // Any next access to this file will return an error.
34
+          SaveFile->Close();
35
+        }
36
+      }
24 37
     }
25 38
 };
26 39
 
... ...
@@ -241,8 +241,8 @@ uint GetDigits(uint Number)
241 241
 
242 242
 bool LowAscii(const char *Str)
243 243
 {
244
-  for (int I=0;Str[I]!=0;I++)
245
-    if ((byte)Str[I]<32 || (byte)Str[I]>127)
244
+  for (size_t I=0;Str[I]!=0;I++)
245
+    if (/*(byte)Str[I]<32 || */(byte)Str[I]>127)
246 246
       return false;
247 247
   return true;
248 248
 }
... ...
@@ -250,11 +250,11 @@ bool LowAscii(const char *Str)
250 250
 
251 251
 bool LowAscii(const wchar *Str)
252 252
 {
253
-  for (int I=0;Str[I]!=0;I++)
253
+  for (size_t I=0;Str[I]!=0;I++)
254 254
   {
255 255
     // We convert wchar_t to uint just in case if some compiler
256 256
     // uses signed wchar_t.
257
-    if ((uint)Str[I]<32 || (uint)Str[I]>127)
257
+    if (/*(uint)Str[I]<32 || */(uint)Str[I]>127)
258 258
       return false;
259 259
   }
260 260
   return true;
... ...
@@ -187,18 +187,29 @@ SSE_VERSION _SSE_Version=GetSSEVersion();
187 187
 SSE_VERSION GetSSEVersion()
188 188
 {
189 189
   int CPUInfo[4];
190
-  __cpuid(CPUInfo, 7);
191
-  if ((CPUInfo[1] & 0x20)!=0)
192
-    return SSE_AVX2;
193
-  __cpuid(CPUInfo, 1);
194
-  if ((CPUInfo[2] & 0x80000)!=0)
195
-    return SSE_SSE41;
196
-  if ((CPUInfo[2] & 0x200)!=0)
197
-    return SSE_SSSE3;
198
-  if ((CPUInfo[3] & 0x4000000)!=0)
199
-    return SSE_SSE2;
200
-  if ((CPUInfo[3] & 0x2000000)!=0)
201
-    return SSE_SSE;
190
+  __cpuid(CPUInfo, 0x80000000);
191
+
192
+  // Maximum supported cpuid function. For example, Pentium M 755 returns 4 here.
193
+  uint MaxSupported=CPUInfo[0] & 0x7fffffff;
194
+
195
+  if (MaxSupported>=7)
196
+  {
197
+    __cpuid(CPUInfo, 7);
198
+    if ((CPUInfo[1] & 0x20)!=0)
199
+      return SSE_AVX2;
200
+  }
201
+  if (MaxSupported>=1)
202
+  {
203
+    __cpuid(CPUInfo, 1);
204
+    if ((CPUInfo[2] & 0x80000)!=0)
205
+      return SSE_SSE41;
206
+    if ((CPUInfo[2] & 0x200)!=0)
207
+      return SSE_SSSE3;
208
+    if ((CPUInfo[3] & 0x4000000)!=0)
209
+      return SSE_SSE2;
210
+    if ((CPUInfo[3] & 0x2000000)!=0)
211
+      return SSE_SSE;
212
+  }
202 213
   return SSE_NONE;
203 214
 }
204 215
 #endif
... ...
@@ -1,7 +1,3 @@
1
-// Typically we use the same global thread pool for all RAR modules.
2
-static ThreadPool *GlobalPool=NULL;
3
-static uint GlobalPoolUseCount=0;
4
-
5 1
 static inline bool CriticalSectionCreate(CRITSECT_HANDLE *CritSection)
6 2
 {
7 3
 #ifdef _WIN_ALL
... ...
@@ -43,53 +39,6 @@ static inline void CriticalSectionEnd(CRITSECT_HANDLE *CritSection)
43 43
 }
44 44
 
45 45
 
46
-static struct GlobalPoolCreateSync
47
-{
48
-  CRITSECT_HANDLE CritSection;
49
-  GlobalPoolCreateSync()  { CriticalSectionCreate(&CritSection); }
50
-  ~GlobalPoolCreateSync() { CriticalSectionDelete(&CritSection); }
51
-} PoolCreateSync;
52
-
53
-
54
-ThreadPool* CreateThreadPool()
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.
64
-  CriticalSectionStart(&PoolCreateSync.CritSection); 
65
-  
66
-  if (GlobalPoolUseCount++ == 0)
67
-    GlobalPool=new ThreadPool(MaxPoolThreads);
68
-
69
-  CriticalSectionEnd(&PoolCreateSync.CritSection); 
70
-  return GlobalPool;
71
-#endif
72
-}
73
-
74
-
75
-void DestroyThreadPool(ThreadPool *Pool)
76
-{
77
-  if (Pool!=NULL)
78
-  {
79
-#ifdef RARDLL
80
-    delete Pool;
81
-#else
82
-    CriticalSectionStart(&PoolCreateSync.CritSection); 
83
-
84
-    if (Pool==GlobalPool && GlobalPoolUseCount > 0 && --GlobalPoolUseCount == 0)
85
-      delete GlobalPool;
86
-
87
-    CriticalSectionEnd(&PoolCreateSync.CritSection); 
88
-#endif
89
-  }
90
-}
91
-
92
-
93 46
 static THREAD_HANDLE ThreadCreate(NATIVE_THREAD_PTR Proc,void *Data)
94 47
 {
95 48
 #ifdef _UNIX
... ...
@@ -170,12 +170,13 @@ void ThreadPool::AddTask(PTHREAD_PROC Proc,void *Data)
170 170
     CreateThreads();
171 171
   
172 172
   // If queue is full, wait until it is empty.
173
-  if ((QueueTop + 1) % ASIZE(TaskQueue) == QueueBottom)
173
+  if (ActiveThreads>=ASIZE(TaskQueue))
174 174
     WaitDone();
175 175
 
176 176
   TaskQueue[QueueTop].Proc = Proc;
177 177
   TaskQueue[QueueTop].Param = Data;
178 178
   QueueTop = (QueueTop + 1) % ASIZE(TaskQueue);
179
+  ActiveThreads++;
179 180
 }
180 181
 
181 182
 
... ...
@@ -184,9 +185,6 @@ void ThreadPool::AddTask(PTHREAD_PROC Proc,void *Data)
184 184
 // are sleeping yet.
185 185
 void ThreadPool::WaitDone()
186 186
 {
187
-  // We add ASIZE(TaskQueue) for case if TaskQueue array size is not
188
-  // a power of two. Negative numbers would not suit our purpose here.
189
-  ActiveThreads=(QueueTop+ASIZE(TaskQueue)-QueueBottom) % ASIZE(TaskQueue);
190 187
   if (ActiveThreads==0)
191 188
     return;
192 189
 #ifdef _WIN_ALL
... ...
@@ -4,7 +4,10 @@
4 4
 #ifndef RAR_SMP
5 5
 const uint MaxPoolThreads=1; // For single threaded version.
6 6
 #else
7
-const uint MaxPoolThreads=32;
7
+// We need to use the processor groups API to increase it beyond 64.
8
+// Also be sure to check and adjust if needed per thread and total block size
9
+// when compressing if going above 64.
10
+const uint MaxPoolThreads=64;
8 11
 
9 12
 
10 13
 #ifdef _UNIX
... ...
@@ -98,9 +101,6 @@ class ThreadPool
98 98
 #endif
99 99
 };
100 100
 
101
-ThreadPool* CreateThreadPool();
102
-void DestroyThreadPool(ThreadPool *Pool);
103
-
104 101
 #endif // RAR_SMP
105 102
 
106 103
 #endif // _RAR_THREADPOOL_
... ...
@@ -20,7 +20,7 @@ enum UIMESSAGE_CODE {
20 20
   UIERROR_SUBHEADERDATABROKEN, UIERROR_RRDAMAGED, UIERROR_UNKNOWNMETHOD,
21 21
   UIERROR_UNKNOWNENCMETHOD, UIERROR_RENAMING, UIERROR_NEWERRAR,
22 22
   UIERROR_NOTSFX, UIERROR_OLDTOSFX,
23
-  UIERROR_WRONGSFXVER, UIERROR_ALREADYENC, UIERROR_DICTOUTMEM,
23
+  UIERROR_WRONGSFXVER, UIERROR_HEADENCMISMATCH, UIERROR_DICTOUTMEM,
24 24
   UIERROR_USESMALLERDICT, UIERROR_MODIFYUNKNOWN, UIERROR_MODIFYOLD,
25 25
   UIERROR_MODIFYLOCKED, UIERROR_MODIFYVOLUME, UIERROR_NOTVOLUME,
26 26
   UIERROR_NOTFIRSTVOLUME, UIERROR_RECVOLLIMIT, UIERROR_RECVOLDIFFSETS,
... ...
@@ -38,6 +38,7 @@ enum UIMESSAGE_CODE {
38 38
   UIERROR_PATHTOOLONG, UIERROR_DIRSCAN, UIERROR_UOWNERGET,
39 39
   UIERROR_UOWNERBROKEN, UIERROR_UOWNERGETOWNERID, UIERROR_UOWNERGETGROUPID,
40 40
   UIERROR_UOWNERSET, UIERROR_ULINKREAD, UIERROR_ULINKEXIST,
41
+  UIERROR_OPENPRESERVEATIME,
41 42
 
42 43
   UIMSG_FIRST,
43 44
   UIMSG_STRING, UIMSG_BUILD, UIMSG_RRSEARCH, UIMSG_ANALYZEFILEDATA,
... ...
@@ -99,6 +99,8 @@ void uiMsgStore::Msg()
99 99
       Log(Str[0],St(MDataBadCRC),Str[1],Str[0]);
100 100
       break;
101 101
     case UIERROR_BADPSW:
102
+      Log(Str[0],St(MWrongFilePassword),Str[1]);
103
+      break;
102 104
     case UIWAIT_BADPSW:
103 105
       Log(Str[0],St(MWrongPassword));
104 106
       break;
... ...
@@ -489,6 +489,8 @@ const wchar_t* wcscasestr(const wchar_t *str, const wchar_t *search)
489 489
 wchar* wcslower(wchar *s)
490 490
 {
491 491
 #ifdef _WIN_ALL
492
+  // _wcslwr requires setlocale and we do not want to depend on setlocale
493
+  // in Windows. Also CharLower involves less overhead.
492 494
   CharLower(s);
493 495
 #else
494 496
   for (wchar *c=s;*c!=0;c++)
... ...
@@ -503,6 +505,8 @@ wchar* wcslower(wchar *s)
503 503
 wchar* wcsupper(wchar *s)
504 504
 {
505 505
 #ifdef _WIN_ALL
506
+  // _wcsupr requires setlocale and we do not want to depend on setlocale
507
+  // in Windows. Also CharUpper involves less overhead.
506 508
   CharUpper(s);
507 509
 #else
508 510
   for (wchar *c=s;*c!=0;c++)
... ...
@@ -520,8 +524,9 @@ int toupperw(int ch)
520 520
 #if defined(_WIN_ALL)
521 521
   // CharUpper is more reliable than towupper in Windows, which seems to be
522 522
   // C locale dependent even in Unicode version. For example, towupper failed
523
-  // to convert lowercase Russian characters.
524
-  return (int)(INT_PTR)CharUpper((wchar *)(INT_PTR)ch);
523
+  // to convert lowercase Russian characters. Use 0xffff mask to prevent crash
524
+  // if value larger than 0xffff is passed to this function.
525
+  return (int)(INT_PTR)CharUpper((wchar *)(INT_PTR)(ch&0xffff));
525 526
 #else
526 527
   return towupper(ch);
527 528
 #endif
... ...
@@ -532,8 +537,9 @@ int tolowerw(int ch)
532 532
 {
533 533
 #if defined(_WIN_ALL)
534 534
   // CharLower is more reliable than towlower in Windows.
535
-  // See comment for towupper above.
536
-  return (int)(INT_PTR)CharLower((wchar *)(INT_PTR)ch);
535
+  // See comment for towupper above. Use 0xffff mask to prevent crash
536
+  // if value larger than 0xffff is passed to this function.
537
+  return (int)(INT_PTR)CharLower((wchar *)(INT_PTR)(ch&0xffff));
537 538
 #else
538 539
   return towlower(ch);
539 540
 #endif
... ...
@@ -648,3 +654,5 @@ char* SupportDBCS::strrchrd(const char *s, int c)
648 648
   return((char *)found);
649 649
 }
650 650
 #endif
651
+
652
+
... ...
@@ -63,4 +63,5 @@ inline void InitDBCS() {gdbcs.Init();}
63 63
 inline void copychrd(char *dest,const char *src) {*dest=*src;}
64 64
 #endif
65 65
 
66
+
66 67
 #endif
... ...
@@ -26,7 +26,7 @@ Unpack::Unpack(ComprDataIO *DataIO)
26 26
   UnpSomeRead=false;
27 27
 #ifdef RAR_SMP
28 28
   MaxUserThreads=1;
29
-  UnpThreadPool=CreateThreadPool();
29
+  UnpThreadPool=NULL;
30 30
   ReadBufMT=NULL;
31 31
   UnpThreadData=NULL;
32 32
 #endif
... ...
@@ -52,13 +52,24 @@ Unpack::~Unpack()
52 52
   if (Window!=NULL)
53 53
     free(Window);
54 54
 #ifdef RAR_SMP
55
-  DestroyThreadPool(UnpThreadPool);
55
+  delete UnpThreadPool;
56 56
   delete[] ReadBufMT;
57 57
   delete[] UnpThreadData;
58 58
 #endif
59 59
 }
60 60
 
61 61
 
62
+#ifdef RAR_SMP
63
+void Unpack::SetThreads(uint Threads)
64
+{
65
+  // More than 8 threads are unlikely to provide noticeable gain
66
+  // for unpacking, but would use the additional memory.
67
+  MaxUserThreads=Min(Threads,8);
68
+  UnpThreadPool=new ThreadPool(MaxUserThreads);
69
+}
70
+#endif
71
+
72
+
62 73
 void Unpack::Init(size_t WinSize,bool Solid)
63 74
 {
64 75
   // If 32-bit RAR unpacks an archive with 4 GB dictionary, the window size
... ...
@@ -24,7 +24,7 @@
24 24
 #define MAX_FILTER_BLOCK_SIZE 0x400000
25 25
 
26 26
 // Write data in 4 MB or smaller blocks. Must not exceed PACK_MAX_WRITE,
27
-// so we keep number of buffered filter in unpacker reasonable.
27
+// so we keep a number of buffered filters in unpacker reasonable.
28 28
 #define UNPACK_MAX_WRITE      0x400000
29 29
 
30 30
 // Decode compressed bit fields to alphabet numbers.
... ...
@@ -382,10 +382,7 @@ class Unpack:PackDef
382 382
     void SetSuspended(bool Suspended) {Unpack::Suspended=Suspended;}
383 383
 
384 384
 #ifdef RAR_SMP
385
-    // More than 8 threads are unlikely to provide a noticeable gain
386
-    // for unpacking, but would use the additional memory.
387
-    void SetThreads(uint Threads) {MaxUserThreads=Min(Threads,8);}
388
-
385
+    void SetThreads(uint Threads);
389 386
     void UnpackDecode(UnpackThreadData &D);
390 387
 #endif
391 388
 
... ...
@@ -436,6 +436,10 @@ byte* Unpack::ApplyFilter(byte *Data,uint DataSize,UnpackFilter *Flt)
436 436
       }
437 437
       return SrcData;
438 438
     case FILTER_ARM:
439
+      // 2019-11-15: we turned off ARM filter by default when compressing,
440
+      // mostly because it is inefficient for modern 64 bit ARM binaries.
441
+      // It was turned on by default in 5.0 - 5.80b3 , so we still need it
442
+      // here for compatibility with some of previously created archives.
439 443
       {
440 444
         uint FileOffset=(uint)WrittenFileSize;
441 445
         // DataSize is unsigned, so we use "CurPos+3" and not "DataSize-3"
... ...
@@ -1,6 +1,6 @@
1 1
 #define RARVER_MAJOR     5
2
-#define RARVER_MINOR    71
2
+#define RARVER_MINOR    90
3 3
 #define RARVER_BETA      0
4
-#define RARVER_DAY      28
5
-#define RARVER_MONTH     4
6
-#define RARVER_YEAR   2019
4
+#define RARVER_DAY      26
5
+#define RARVER_MONTH     3
6
+#define RARVER_YEAR   2020
... ...
@@ -67,7 +67,7 @@ void ExtractACL20(Archive &Arc,const wchar *FileName)
67 67
 void ExtractACL(Archive &Arc,const wchar *FileName)
68 68
 {
69 69
   Array<byte> SubData;
70
-  if (!Arc.ReadSubData(&SubData,NULL))
70
+  if (!Arc.ReadSubData(&SubData,NULL,false))
71 71
     return;
72 72
 
73 73
   SetACLPrivileges();
... ...
@@ -104,7 +104,8 @@ void ExtractStreams(Archive &Arc,const wchar *FileName,bool TestMode)
104 104
 
105 105
   if (TestMode)
106 106
   {
107
-    Arc.ReadSubData(NULL,NULL);
107
+    File CurFile;
108
+    Arc.ReadSubData(NULL,&CurFile,true);
108 109
     return;
109 110
   }
110 111
 
... ...
@@ -116,7 +117,7 @@ void ExtractStreams(Archive &Arc,const wchar *FileName,bool TestMode)
116 116
   if ((fd.FileAttr & FILE_ATTRIBUTE_READONLY)!=0)
117 117
     SetFileAttr(FileName,fd.FileAttr & ~FILE_ATTRIBUTE_READONLY);
118 118
   File CurFile;
119
-  if (CurFile.WCreate(FullName) && Arc.ReadSubData(NULL,&CurFile))
119
+  if (CurFile.WCreate(FullName) && Arc.ReadSubData(NULL,&CurFile,false))
120 120
     CurFile.Close();
121 121
   File HostFile;
122 122
   if (Found && HostFile.Open(FileName,FMF_OPENSHARED|FMF_UPDATE))