"Fossies" - the Fresh Open Source Software Archive 
Member "unrar/recvol5.cpp" (4 May 2022, 13977 Bytes) of package /linux/misc/unrarsrc-6.1.7.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "recvol5.cpp" see the
Fossies "Dox" file reference documentation.
1 static const uint MaxVolumes=65535;
2
3 // We select this limit arbitrarily, to prevent user creating too many
4 // rev files by mistake.
5 #define MAX_REV_TO_DATA_RATIO 10 // 1000% of rev files.
6
7 RecVolumes5::RecVolumes5(RAROptions *Cmd,bool TestOnly)
8 {
9 RealBuf=NULL;
10 RealReadBuffer=NULL;
11
12 DataCount=0;
13 RecCount=0;
14 TotalCount=0;
15 RecBufferSize=0;
16
17 #ifdef RAR_SMP
18 MaxUserThreads=Cmd->Threads;
19 #else
20 MaxUserThreads=1;
21 #endif
22
23 ThreadData=new RecRSThreadData[MaxUserThreads];
24 for (uint I=0;I<MaxUserThreads;I++)
25 {
26 ThreadData[I].RecRSPtr=this;
27 ThreadData[I].RS=NULL;
28 }
29
30 if (TestOnly)
31 {
32 #ifdef RAR_SMP
33 RecThreadPool=NULL;
34 #endif
35 }
36 else
37 {
38 #ifdef RAR_SMP
39 RecThreadPool=new ThreadPool(MaxUserThreads);
40 #endif
41 RealBuf=new byte[TotalBufferSize+SSE_ALIGNMENT];
42 Buf=(byte *)ALIGN_VALUE(RealBuf,SSE_ALIGNMENT);
43 }
44 }
45
46
47 RecVolumes5::~RecVolumes5()
48 {
49 delete[] RealBuf;
50 delete[] RealReadBuffer;
51 for (uint I=0;I<RecItems.Size();I++)
52 delete RecItems[I].f;
53 for (uint I=0;I<MaxUserThreads;I++)
54 delete ThreadData[I].RS;
55 delete[] ThreadData;
56 #ifdef RAR_SMP
57 delete RecThreadPool;
58 #endif
59 }
60
61
62
63
64 #ifdef RAR_SMP
65 THREAD_PROC(RecThreadRS)
66 {
67 RecRSThreadData *td=(RecRSThreadData *)Data;
68 td->RecRSPtr->ProcessAreaRS(td);
69 }
70 #endif
71
72
73 void RecVolumes5::ProcessRS(RAROptions *Cmd,uint DataNum,const byte *Data,uint MaxRead,bool Encode)
74 {
75 /*
76 RSCoder16 RS;
77 RS.Init(DataCount,RecCount,Encode ? NULL:ValidFlags);
78 uint Count=Encode ? RecCount : MissingVolumes;
79 for (uint I=0;I<Count;I++)
80 RS.UpdateECC(DataNum, I, Data, Buf+I*RecBufferSize, MaxRead);
81 */
82
83 uint ThreadNumber=MaxUserThreads;
84
85 const uint MinThreadBlock=0x1000;
86 ThreadNumber=Min(ThreadNumber,MaxRead/MinThreadBlock);
87
88 if (ThreadNumber<1)
89 ThreadNumber=1;
90 uint ThreadDataSize=MaxRead/ThreadNumber;
91 ThreadDataSize+=(ThreadDataSize&1); // Must be even for 16-bit RS coder.
92 #ifdef USE_SSE
93 ThreadDataSize=ALIGN_VALUE(ThreadDataSize,SSE_ALIGNMENT); // Alignment for SSE operations.
94 #endif
95 if (ThreadDataSize<MinThreadBlock)
96 ThreadDataSize=MinThreadBlock;
97
98 for (size_t I=0,CurPos=0;I<ThreadNumber && CurPos<MaxRead;I++)
99 {
100 RecRSThreadData *td=ThreadData+I;
101 if (td->RS==NULL)
102 {
103 td->RS=new RSCoder16;
104 td->RS->Init(DataCount,RecCount,Encode ? NULL:ValidFlags);
105 }
106 td->DataNum=DataNum;
107 td->Data=Data;
108 td->Encode=Encode;
109 td->StartPos=CurPos;
110
111 size_t EndPos=CurPos+ThreadDataSize;
112 if (EndPos>MaxRead || I==ThreadNumber-1)
113 EndPos=MaxRead;
114
115 td->Size=EndPos-CurPos;
116
117 CurPos=EndPos;
118
119 #ifdef RAR_SMP
120 if (ThreadNumber>1)
121 RecThreadPool->AddTask(RecThreadRS,(void*)td);
122 else
123 ProcessAreaRS(td);
124 #else
125 ProcessAreaRS(td);
126 #endif
127 }
128 #ifdef RAR_SMP
129 RecThreadPool->WaitDone();
130 #endif // RAR_SMP
131 }
132
133
134 void RecVolumes5::ProcessAreaRS(RecRSThreadData *td)
135 {
136 uint Count=td->Encode ? RecCount : MissingVolumes;
137 for (uint I=0;I<Count;I++)
138 td->RS->UpdateECC(td->DataNum, I, td->Data+td->StartPos, Buf+I*RecBufferSize+td->StartPos, td->Size);
139 }
140
141
142
143
144 bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
145 {
146 wchar ArcName[NM];
147 wcsncpyz(ArcName,Name,ASIZE(ArcName));
148
149 wchar *Num=GetVolNumPart(ArcName);
150 while (Num>ArcName && IsDigit(*(Num-1)))
151 Num--;
152 if (Num<=PointToName(ArcName))
153 return false; // Numeric part is missing or entire volume name is numeric, not possible for RAR or REV volume.
154 wcsncpyz(Num,L"*.*",ASIZE(ArcName)-(Num-ArcName));
155
156 wchar FirstVolName[NM];
157 *FirstVolName=0;
158
159 wchar LongestRevName[NM];
160 *LongestRevName=0;
161
162 int64 RecFileSize=0;
163
164 FindFile VolFind;
165 VolFind.SetMask(ArcName);
166 FindData fd;
167 uint FoundRecVolumes=0;
168 while (VolFind.Next(&fd))
169 {
170 Wait();
171
172 Archive *Vol=new Archive(Cmd);
173 int ItemPos=-1;
174 if (!fd.IsDir && Vol->WOpen(fd.Name))
175 {
176 if (CmpExt(fd.Name,L"rev"))
177 {
178 uint RecNum=ReadHeader(Vol,FoundRecVolumes==0);
179 if (RecNum!=0)
180 {
181 if (FoundRecVolumes==0)
182 RecFileSize=Vol->FileLength();
183
184 ItemPos=RecNum;
185 FoundRecVolumes++;
186
187 if (wcslen(fd.Name)>wcslen(LongestRevName))
188 wcsncpyz(LongestRevName,fd.Name,ASIZE(LongestRevName));
189 }
190 }
191 else
192 if (Vol->IsArchive(true) && (Vol->SFXSize>0 || CmpExt(fd.Name,L"rar")))
193 {
194 if (!Vol->Volume && !Vol->BrokenHeader)
195 {
196 uiMsg(UIERROR_NOTVOLUME,ArcName);
197 return false;
198 }
199 // We work with archive as with raw data file, so we do not want
200 // to spend time to QOpen I/O redirection.
201 Vol->QOpenUnload();
202
203 Vol->Seek(0,SEEK_SET);
204
205 // RAR volume found. Get its number, store the handle in appropriate
206 // array slot, clean slots in between if we had to grow the array.
207 wchar *Num=GetVolNumPart(fd.Name);
208 uint VolNum=0;
209 for (uint K=1;Num>=fd.Name && IsDigit(*Num);K*=10,Num--)
210 VolNum+=(*Num-'0')*K;
211 if (VolNum==0 || VolNum>MaxVolumes)
212 continue;
213 size_t CurSize=RecItems.Size();
214 if (VolNum>CurSize)
215 {
216 RecItems.Alloc(VolNum);
217 for (size_t I=CurSize;I<VolNum;I++)
218 RecItems[I].f=NULL;
219 }
220 ItemPos=VolNum-1;
221
222 if (*FirstVolName==0)
223 VolNameToFirstName(fd.Name,FirstVolName,ASIZE(FirstVolName),true);
224 }
225 }
226 if (ItemPos==-1)
227 delete Vol; // Skip found file, it is not RAR or REV volume.
228 else
229 if ((uint)ItemPos<RecItems.Size()) // Check if found more REV than needed.
230 {
231 // Store found RAR or REV volume.
232 RecVolItem *Item=RecItems+ItemPos;
233 Item->f=Vol;
234 Item->New=false;
235 wcsncpyz(Item->Name,fd.Name,ASIZE(Item->Name));
236 }
237 }
238
239 if (!Silent || FoundRecVolumes!=0)
240 uiMsg(UIMSG_RECVOLFOUND,FoundRecVolumes);
241 if (FoundRecVolumes==0)
242 return false;
243
244 // If we did not find even a single .rar volume, create .rar volume name
245 // based on the longest .rev file name. Use longest .rev, so we have
246 // enough space for volume number.
247 if (*FirstVolName==0)
248 {
249 SetExt(LongestRevName,L"rar",ASIZE(LongestRevName));
250 VolNameToFirstName(LongestRevName,FirstVolName,ASIZE(FirstVolName),true);
251 }
252
253 uiMsg(UIMSG_RECVOLCALCCHECKSUM);
254
255 MissingVolumes=0;
256 for (uint I=0;I<TotalCount;I++)
257 {
258 RecVolItem *Item=&RecItems[I];
259 if (Item->f!=NULL)
260 {
261 uiMsg(UIMSG_STRING,Item->Name);
262
263 uint RevCRC;
264 CalcFileSum(Item->f,&RevCRC,NULL,MaxUserThreads,INT64NDF,CALCFSUM_CURPOS);
265 Item->Valid=RevCRC==Item->CRC;
266 if (!Item->Valid)
267 {
268 uiMsg(UIMSG_CHECKSUM,Item->Name);
269
270 // Close only corrupt REV volumes here. We'll close and rename corrupt
271 // RAR volumes later, if we'll know that recovery is possible.
272 if (I>=DataCount)
273 {
274 Item->f->Close();
275 Item->f=NULL;
276 FoundRecVolumes--;
277 }
278 }
279 }
280 if (I<DataCount && (Item->f==NULL || !Item->Valid))
281 MissingVolumes++;
282 }
283
284 uiMsg(UIMSG_RECVOLMISSING,MissingVolumes);
285
286 if (MissingVolumes==0)
287 {
288 uiMsg(UIERROR_RECVOLALLEXIST);
289 return false;
290 }
291
292 if (MissingVolumes>FoundRecVolumes)
293 {
294 uiMsg(UIERROR_RECVOLFOUND,FoundRecVolumes); // Intentionally not displayed in console mode.
295 uiMsg(UIERROR_RECVOLCANNOTFIX);
296 return false;
297 }
298
299 uiMsg(UIMSG_RECONSTRUCTING);
300
301 // Create missing and rename bad volumes.
302 uint64 MaxVolSize=0;
303 for (uint I=0;I<DataCount;I++)
304 {
305 RecVolItem *Item=&RecItems[I];
306 if (Item->FileSize>MaxVolSize)
307 MaxVolSize=Item->FileSize;
308 if (Item->f!=NULL && !Item->Valid)
309 {
310 Item->f->Close();
311
312 wchar NewName[NM];
313 wcsncpyz(NewName,Item->Name,ASIZE(NewName));
314 wcsncatz(NewName,L".bad",ASIZE(NewName));
315
316 uiMsg(UIMSG_BADARCHIVE,Item->Name);
317 uiMsg(UIMSG_RENAMING,Item->Name,NewName);
318 RenameFile(Item->Name,NewName);
319 delete Item->f;
320 Item->f=NULL;
321 }
322
323 if ((Item->New=(Item->f==NULL))==true)
324 {
325 wcsncpyz(Item->Name,FirstVolName,ASIZE(Item->Name));
326 uiMsg(UIMSG_CREATING,Item->Name);
327 uiMsg(UIEVENT_NEWARCHIVE,Item->Name);
328 File *NewVol=new File;
329 bool UserReject;
330 if (!FileCreate(Cmd,NewVol,Item->Name,ASIZE(Item->Name),&UserReject))
331 {
332 if (!UserReject)
333 ErrHandler.CreateErrorMsg(Item->Name);
334 ErrHandler.Exit(UserReject ? RARX_USERBREAK:RARX_CREATE);
335 }
336 NewVol->Prealloc(Item->FileSize);
337 Item->f=NewVol;
338 }
339 NextVolumeName(FirstVolName,ASIZE(FirstVolName),false);
340 }
341
342
343 int64 ProcessedSize=0;
344 int LastPercent=-1;
345 mprintf(L" ");
346
347 // Even though we already preliminary calculated missing volume number,
348 // let's do it again now, when we have the final and exact information.
349 MissingVolumes=0;
350
351 ValidFlags=new bool[TotalCount];
352 for (uint I=0;I<TotalCount;I++)
353 {
354 ValidFlags[I]=RecItems[I].f!=NULL && !RecItems[I].New;
355 if (I<DataCount && !ValidFlags[I])
356 MissingVolumes++;
357 }
358
359 // Size of per file buffer.
360 RecBufferSize=TotalBufferSize/MissingVolumes;
361 if ((RecBufferSize&1)==1) // Must be even for our RS16 codec.
362 RecBufferSize--;
363 #ifdef USE_SSE
364 RecBufferSize&=~(SSE_ALIGNMENT-1); // Align for SSE.
365 #endif
366
367 RSCoder16 RS;
368 if (!RS.Init(DataCount,RecCount,ValidFlags))
369 {
370 uiMsg(UIERROR_OPFAILED);
371 delete[] ValidFlags;
372 return false; // Should not happen, we check parameter validity above.
373 }
374
375 RealReadBuffer=new byte[RecBufferSize+SSE_ALIGNMENT];
376 byte *ReadBuf=(byte *)ALIGN_VALUE(RealReadBuffer,SSE_ALIGNMENT);
377
378 while (true)
379 {
380 Wait();
381
382 int MaxRead=0;
383 for (uint I=0,J=DataCount;I<DataCount;I++)
384 {
385 uint VolNum=I;
386 if (!ValidFlags[I]) // If next RAR volume is missing or invalid.
387 {
388 while (!ValidFlags[J]) // Find next valid REV volume.
389 J++;
390 VolNum=J++; // Use next valid REV volume data instead of RAR.
391 }
392 RecVolItem *Item=RecItems+VolNum;
393
394 byte *B=&ReadBuf[0];
395 int ReadSize=0;
396 if (Item->f!=NULL && !Item->New)
397 ReadSize=Item->f->Read(B,RecBufferSize);
398 if (ReadSize!=RecBufferSize)
399 memset(B+ReadSize,0,RecBufferSize-ReadSize);
400 if (ReadSize>MaxRead)
401 MaxRead=ReadSize;
402
403 // We can have volumes of different size. Let's use data chunk
404 // for largest volume size.
405 uint DataToProcess=(uint)Min(RecBufferSize,MaxVolSize-ProcessedSize);
406 ProcessRS(Cmd,I,B,DataToProcess,false);
407 }
408 if (MaxRead==0)
409 break;
410
411 for (uint I=0,J=0;I<DataCount;I++)
412 if (!ValidFlags[I])
413 {
414 RecVolItem *Item=RecItems+I;
415 size_t WriteSize=(size_t)Min(MaxRead,Item->FileSize);
416 Item->f->Write(Buf+(J++)*RecBufferSize,WriteSize);
417 Item->FileSize-=WriteSize;
418 }
419
420 int CurPercent=ToPercent(ProcessedSize,RecFileSize);
421 if (!Cmd->DisablePercentage && CurPercent!=LastPercent)
422 {
423 uiProcessProgress("RV",ProcessedSize,RecFileSize);
424 LastPercent=CurPercent;
425 }
426 ProcessedSize+=MaxRead;
427 }
428
429 for (uint I=0;I<TotalCount;I++)
430 if (RecItems[I].f!=NULL)
431 RecItems[I].f->Close();
432
433 delete[] ValidFlags;
434 #if !defined(SILENT)
435 if (!Cmd->DisablePercentage)
436 mprintf(L"\b\b\b\b100%%");
437 if (!Silent && !Cmd->DisableDone)
438 mprintf(St(MDone));
439 #endif
440 return true;
441 }
442
443
444 uint RecVolumes5::ReadHeader(File *RecFile,bool FirstRev)
445 {
446 const size_t FirstReadSize=REV5_SIGN_SIZE+8;
447 byte ShortBuf[FirstReadSize];
448 if (RecFile->Read(ShortBuf,FirstReadSize)!=FirstReadSize)
449 return 0;
450 if (memcmp(ShortBuf,REV5_SIGN,REV5_SIGN_SIZE)!=0)
451 return 0;
452 uint HeaderSize=RawGet4(ShortBuf+REV5_SIGN_SIZE+4);
453 if (HeaderSize>0x100000 || HeaderSize<=5)
454 return 0;
455 uint BlockCRC=RawGet4(ShortBuf+REV5_SIGN_SIZE);
456
457 RawRead Raw(RecFile);
458 if (Raw.Read(HeaderSize)!=HeaderSize)
459 return 0;
460
461 // Calculate CRC32 of entire header including 4 byte size field.
462 uint CalcCRC=CRC32(0xffffffff,ShortBuf+REV5_SIGN_SIZE+4,4);
463 if ((CRC32(CalcCRC,Raw.GetDataPtr(),HeaderSize)^0xffffffff)!=BlockCRC)
464 return 0;
465
466 if (Raw.Get1()!=1) // Version check.
467 return 0;
468 DataCount=Raw.Get2();
469 RecCount=Raw.Get2();
470 TotalCount=DataCount+RecCount;
471 uint RecNum=Raw.Get2(); // Number of recovery volume.
472 if (RecNum>=TotalCount || TotalCount>MaxVolumes)
473 return 0;
474 uint RevCRC=Raw.Get4(); // CRC of current REV volume.
475
476 if (FirstRev)
477 {
478 // If we have read the first valid REV file, init data structures
479 // using information from REV header.
480 size_t CurSize=RecItems.Size();
481 RecItems.Alloc(TotalCount);
482 for (size_t I=CurSize;I<TotalCount;I++)
483 RecItems[I].f=NULL;
484 for (uint I=0;I<DataCount;I++)
485 {
486 RecItems[I].FileSize=Raw.Get8();
487 RecItems[I].CRC=Raw.Get4();
488 }
489 }
490
491 RecItems[RecNum].CRC=RevCRC; // Assign it here, after allocating RecItems.
492
493 return RecNum;
494 }
495
496
497 void RecVolumes5::Test(RAROptions *Cmd,const wchar *Name)
498 {
499 wchar VolName[NM];
500 wcsncpyz(VolName,Name,ASIZE(VolName));
501
502 uint FoundRecVolumes=0;
503 while (FileExist(VolName))
504 {
505 File CurFile;
506 if (!CurFile.Open(VolName))
507 {
508 ErrHandler.OpenErrorMsg(VolName); // It also sets RARX_OPEN.
509 continue;
510 }
511 if (!uiStartFileExtract(VolName,false,true,false))
512 return;
513 mprintf(St(MExtrTestFile),VolName);
514 mprintf(L" ");
515 bool Valid=false;
516 uint RecNum=ReadHeader(&CurFile,FoundRecVolumes==0);
517 if (RecNum!=0)
518 {
519 FoundRecVolumes++;
520
521 uint RevCRC;
522 CalcFileSum(&CurFile,&RevCRC,NULL,1,INT64NDF,CALCFSUM_CURPOS|(Cmd->DisablePercentage ? 0 : CALCFSUM_SHOWPROGRESS));
523 Valid=RevCRC==RecItems[RecNum].CRC;
524 }
525
526 if (Valid)
527 {
528 mprintf(L"%s%s ",L"\b\b\b\b\b ",St(MOk));
529 }
530 else
531 {
532 uiMsg(UIERROR_CHECKSUM,VolName,VolName);
533 ErrHandler.SetErrorCode(RARX_CRC);
534 }
535
536 NextVolumeName(VolName,ASIZE(VolName),false);
537 }
538 }