Coverage Report

Created: 2023-12-08 06:48

/src/clamav/libclamunrar/rdwrfn.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "rar.hpp"
2
3
ComprDataIO::ComprDataIO()
4
1.95M
{
5
1.95M
#ifndef RAR_NOCRYPT
6
1.95M
  Crypt=new CryptData;
7
1.95M
  Decrypt=new CryptData;
8
1.95M
#endif
9
10
1.95M
  Init();
11
1.95M
}
12
13
14
void ComprDataIO::Init()
15
1.95M
{
16
1.95M
  UnpackFromMemory=false;
17
1.95M
  UnpackToMemory=false;
18
1.95M
  UnpPackedSize=0;
19
1.95M
  UnpPackedLeft=0;
20
1.95M
  ShowProgress=true;
21
1.95M
  TestMode=false;
22
1.95M
  SkipUnpCRC=false;
23
1.95M
  NoFileHeader=false;
24
1.95M
  PackVolume=false;
25
1.95M
  UnpVolume=false;
26
1.95M
  NextVolumeMissing=false;
27
1.95M
  SrcFile=NULL;
28
1.95M
  DestFile=NULL;
29
1.95M
  UnpWrAddr=NULL;
30
1.95M
  UnpWrSize=0;
31
1.95M
  Command=NULL;
32
1.95M
  Encryption=false;
33
1.95M
  Decryption=false;
34
1.95M
  CurPackRead=CurPackWrite=CurUnpRead=CurUnpWrite=0;
35
1.95M
  LastPercent=-1;
36
1.95M
  SubHead=NULL;
37
1.95M
  SubHeadPos=NULL;
38
1.95M
  CurrentCommand=0;
39
1.95M
  ProcessedArcSize=0;
40
1.95M
  LastArcSize=0;
41
1.95M
  TotalArcSize=0;
42
1.95M
}
43
44
45
ComprDataIO::~ComprDataIO()
46
1.95M
{
47
1.95M
#ifndef RAR_NOCRYPT
48
1.95M
  delete Crypt;
49
1.95M
  delete Decrypt;
50
1.95M
#endif
51
1.95M
}
52
53
54
55
56
int ComprDataIO::UnpRead(byte *Addr,size_t Count)
57
8.28M
{
58
8.28M
#ifndef RAR_NOCRYPT
59
  // In case of encryption we need to align read size to encryption 
60
  // block size. We can do it by simple masking, because unpack read code
61
  // always reads more than CRYPT_BLOCK_SIZE, so we do not risk to make it 0.
62
8.28M
  if (Decryption)
63
112k
    Count &= ~CRYPT_BLOCK_MASK;
64
8.28M
#endif
65
  
66
8.28M
  int ReadSize=0,TotalRead=0;
67
8.28M
  byte *ReadAddr;
68
8.28M
  ReadAddr=Addr;
69
8.28M
  while (Count > 0)
70
8.28M
  {
71
8.28M
    Archive *SrcArc=(Archive *)SrcFile;
72
73
8.28M
    if (UnpackFromMemory)
74
0
    {
75
0
      memcpy(Addr,UnpackFromMemoryAddr,UnpackFromMemorySize);
76
0
      ReadSize=(int)UnpackFromMemorySize;
77
0
      UnpackFromMemorySize=0;
78
0
    }
79
8.28M
    else
80
8.28M
    {
81
8.28M
      size_t SizeToRead=((int64)Count>UnpPackedLeft) ? (size_t)UnpPackedLeft:Count;
82
8.28M
      if (SizeToRead > 0)
83
7.98M
      {
84
7.98M
        if (UnpVolume && Decryption && (int64)Count>UnpPackedLeft)
85
0
        {
86
          // We need aligned blocks for decryption and we want "Keep broken
87
          // files" to work efficiently with missing encrypted volumes.
88
          // So for last data block in volume we adjust the size to read to
89
          // next equal or smaller block producing aligned total block size.
90
          // So we'll ask for next volume only when processing few unaligned
91
          // bytes left in the end, when most of data is already extracted.
92
0
          size_t NewTotalRead = TotalRead + SizeToRead;
93
0
          size_t Adjust = NewTotalRead - (NewTotalRead  & ~CRYPT_BLOCK_MASK);
94
0
          size_t NewSizeToRead = SizeToRead - Adjust;
95
0
          if ((int)NewSizeToRead > 0)
96
0
            SizeToRead = NewSizeToRead;
97
0
        }
98
99
7.98M
        if (!SrcFile->IsOpened())
100
0
          return -1;
101
7.98M
        ReadSize=SrcFile->Read(ReadAddr,SizeToRead);
102
7.98M
        FileHeader *hd=SubHead!=NULL ? SubHead:&SrcArc->FileHead;
103
7.98M
        if (!NoFileHeader && hd->SplitAfter)
104
1.86M
          PackedDataHash.Update(ReadAddr,ReadSize);
105
7.98M
      }
106
8.28M
    }
107
8.28M
    CurUnpRead+=ReadSize;
108
8.28M
    TotalRead+=ReadSize;
109
8.28M
#ifndef NOVOLUME
110
    // These variable are not used in NOVOLUME mode, so it is better
111
    // to exclude commands below to avoid compiler warnings.
112
8.28M
    ReadAddr+=ReadSize;
113
8.28M
    Count-=ReadSize;
114
8.28M
#endif
115
8.28M
    UnpPackedLeft-=ReadSize;
116
117
    // Do not ask for next volume if we read something from current volume.
118
    // If next volume is missing, we need to process all data from current
119
    // volume before aborting. It helps to recover all possible data
120
    // in "Keep broken files" mode. But if we process encrypted data,
121
    // we ask for next volume also if we have non-aligned encryption block.
122
    // Since we adjust data size for decryption earlier above,
123
    // it does not hurt "Keep broken files" mode efficiency.
124
8.28M
    if (UnpVolume && UnpPackedLeft == 0 && 
125
8.28M
        (ReadSize==0 || Decryption && (TotalRead & CRYPT_BLOCK_MASK) != 0) )
126
8.50k
    {
127
8.50k
#ifndef NOVOLUME
128
8.50k
      if (!MergeArchive(*SrcArc,this,true,CurrentCommand))
129
8.50k
#endif
130
8.50k
      {
131
8.50k
        NextVolumeMissing=true;
132
8.50k
        return -1;
133
8.50k
      }
134
8.50k
    }
135
8.27M
    else
136
8.27M
      break;
137
8.28M
  }
138
8.27M
  Archive *SrcArc=(Archive *)SrcFile;
139
8.27M
  if (SrcArc!=NULL)
140
8.27M
    ShowUnpRead(SrcArc->NextBlockPos-UnpPackedSize+CurUnpRead,TotalArcSize);
141
8.27M
  if (ReadSize!=-1)
142
8.27M
  {
143
8.27M
    ReadSize=TotalRead;
144
8.27M
#ifndef RAR_NOCRYPT
145
8.27M
    if (Decryption)
146
112k
      Decrypt->DecryptBlock(Addr,ReadSize);
147
8.27M
#endif
148
8.27M
  }
149
8.27M
  Wait();
150
8.27M
  return ReadSize;
151
8.28M
}
152
153
154
void ComprDataIO::UnpWrite(byte *Addr,size_t Count)
155
401k
{
156
157
401k
#ifdef RARDLL
158
401k
  CommandData *Cmd=((Archive *)SrcFile)->GetCommandData();
159
401k
  if (Cmd->DllOpMode!=RAR_SKIP)
160
395k
  {
161
395k
    if (Cmd->Callback!=NULL &&
162
395k
        Cmd->Callback(UCM_PROCESSDATA,Cmd->UserData,(LPARAM)Addr,Count)==-1)
163
0
      ErrHandler.Exit(RARX_USERBREAK);
164
395k
    if (Cmd->ProcessDataProc!=NULL)
165
0
    {
166
0
      int RetCode=Cmd->ProcessDataProc(Addr,(int)Count);
167
0
      if (RetCode==0)
168
0
        ErrHandler.Exit(RARX_USERBREAK);
169
0
    }
170
395k
  }
171
401k
#endif // RARDLL
172
173
401k
  UnpWrAddr=Addr;
174
401k
  UnpWrSize=Count;
175
401k
  if (UnpackToMemory)
176
0
  {
177
0
    if (Count <= UnpackToMemorySize)
178
0
    {
179
0
      memcpy(UnpackToMemoryAddr,Addr,Count);
180
0
      UnpackToMemoryAddr+=Count;
181
0
      UnpackToMemorySize-=Count;
182
0
    }
183
0
  }
184
401k
  else
185
401k
    if (!TestMode)
186
385k
      DestFile->Write(Addr,Count);
187
401k
  CurUnpWrite+=Count;
188
401k
  if (!SkipUnpCRC)
189
391k
    UnpHash.Update(Addr,Count);
190
401k
  ShowUnpWrite();
191
401k
  Wait();
192
401k
}
193
194
195
196
197
198
199
void ComprDataIO::ShowUnpRead(int64 ArcPos,int64 ArcSize)
200
8.27M
{
201
8.27M
  if (ShowProgress && SrcFile!=NULL)
202
8.16M
  {
203
    // Important when processing several archives or multivolume archive.
204
8.16M
    ArcPos+=ProcessedArcSize;
205
206
8.16M
    Archive *SrcArc=(Archive *)SrcFile;
207
8.16M
    CommandData *Cmd=SrcArc->GetCommandData();
208
209
8.16M
    int CurPercent=ToPercent(ArcPos,ArcSize);
210
8.16M
    if (!Cmd->DisablePercentage && CurPercent!=LastPercent)
211
423k
    {
212
423k
      uiExtractProgress(CurUnpWrite,SrcArc->FileHead.UnpSize,ArcPos,ArcSize);
213
423k
      LastPercent=CurPercent;
214
423k
    }
215
8.16M
  }
216
8.27M
}
217
218
219
void ComprDataIO::ShowUnpWrite()
220
401k
{
221
401k
}
222
223
224
225
226
227
228
229
230
231
232
void ComprDataIO::SetFiles(File *SrcFile,File *DestFile)
233
442k
{
234
442k
  if (SrcFile!=NULL)
235
442k
    ComprDataIO::SrcFile=SrcFile;
236
442k
  if (DestFile!=NULL)
237
435k
    ComprDataIO::DestFile=DestFile;
238
442k
  LastPercent=-1;
239
442k
}
240
241
242
void ComprDataIO::GetUnpackedData(byte **Data,size_t *Size)
243
6.57k
{
244
6.57k
  *Data=UnpWrAddr;
245
6.57k
  *Size=UnpWrSize;
246
6.57k
}
247
248
249
void ComprDataIO::SetEncryption(bool Encrypt,CRYPT_METHOD Method,
250
     SecPassword *Password,const byte *Salt,const byte *InitV,
251
     uint Lg2Cnt,byte *HashKey,byte *PswCheck)
252
450k
{
253
450k
#ifndef RAR_NOCRYPT
254
450k
  if (Encrypt)
255
0
    Encryption=Crypt->SetCryptKeys(true,Method,Password,Salt,InitV,Lg2Cnt,HashKey,PswCheck);
256
450k
  else
257
450k
    Decryption=Decrypt->SetCryptKeys(false,Method,Password,Salt,InitV,Lg2Cnt,HashKey,PswCheck);
258
450k
#endif
259
450k
}
260
261
262
#if !defined(SFX_MODULE) && !defined(RAR_NOCRYPT)
263
void ComprDataIO::SetAV15Encryption()
264
0
{
265
0
  Decryption=true;
266
0
  Decrypt->SetAV15Encryption();
267
0
}
268
#endif
269
270
271
#if !defined(SFX_MODULE) && !defined(RAR_NOCRYPT)
272
void ComprDataIO::SetCmt13Encryption()
273
6.57k
{
274
6.57k
  Decryption=true;
275
6.57k
  Decrypt->SetCmt13Encryption();
276
6.57k
}
277
#endif
278
279
280
281
282
void ComprDataIO::SetUnpackToMemory(byte *Addr,uint Size)
283
0
{
284
0
  UnpackToMemory=true;
285
0
  UnpackToMemoryAddr=Addr;
286
0
  UnpackToMemorySize=Size;
287
0
}
288
289
290
// Extraction progress is based on the position in archive and we adjust 
291
// the total archives size here, so trailing blocks do not prevent progress
292
// reaching 100% at the end of extraction. Alternatively we could print "100%"
293
// after completing the entire archive extraction, but then we would need
294
// to take into account possible messages like the checksum error after
295
// last file percent progress.
296
void ComprDataIO::AdjustTotalArcSize(Archive *Arc)
297
944k
{
298
  // If we know a position of QO or RR blocks, use them to adjust the total
299
  // packed size to beginning of these blocks. Earlier we already calculated
300
  // the total size based on entire archive sizes. We also set LastArcSize
301
  // to start of first trailing block, to add it later to ProcessedArcSize.
302
944k
  int64 ArcLength=Arc->IsSeekable() ? Arc->FileLength() : 0;
303
944k
  if (Arc->MainHead.QOpenOffset!=0) // QO is always preceding RR record.
304
285
    LastArcSize=Arc->MainHead.QOpenOffset;
305
944k
  else
306
944k
    if (Arc->MainHead.RROffset!=0)
307
599
      LastArcSize=Arc->MainHead.RROffset;
308
943k
    else
309
943k
    {
310
      // If neither QO nor RR are found, exclude the approximate size of
311
      // end of archive block.
312
      // We select EndBlock to be larger than typical 8 bytes HEAD_ENDARC,
313
      // but to not exceed the smallest 22 bytes HEAD_FILE with 1 byte file
314
      // name, so we do not have two files with 100% at the end of archive.
315
943k
      const uint EndBlock=23;
316
317
943k
      if (ArcLength>EndBlock)
318
939k
        LastArcSize=ArcLength-EndBlock;
319
943k
    }
320
321
944k
  TotalArcSize-=ArcLength-LastArcSize;
322
944k
}