1 #include "rar.hpp"
2 
3 #define RECVOL_BUFSIZE  0x8000
4 
RecVolumes()5 RecVolumes::RecVolumes()
6 {
7   Buf.Alloc(RECVOL_BUFSIZE*256);
8   memset(SrcFile,0,sizeof(SrcFile));
9 }
10 
11 
~RecVolumes()12 RecVolumes::~RecVolumes()
13 {
14   for (int I=0;I<sizeof(SrcFile)/sizeof(SrcFile[0]);I++)
15     delete SrcFile[I];
16 }
17 
18 
19 
20 
Restore(RAROptions * Cmd,const char * Name,const wchar * NameW,bool Silent)21 bool RecVolumes::Restore(RAROptions *Cmd,const char *Name,
22                          const wchar *NameW,bool Silent)
23 {
24   char ArcName[NM];
25   wchar ArcNameW[NM];
26   strcpy(ArcName,Name);
27   strcpyw(ArcNameW,NameW);
28   char *Ext=GetExt(ArcName);
29   bool NewStyle=false;
30   bool RevName=Ext!=NULL && stricomp(Ext,".rev")==0;
31   if (RevName)
32   {
33     for (int DigitGroup=0;Ext>ArcName && DigitGroup<3;Ext--)
34       if (!IsDigit(*Ext))
35         if (IsDigit(*(Ext-1)) && (*Ext=='_' || DigitGroup<2))
36           DigitGroup++;
37         else
38           if (DigitGroup<2)
39           {
40             NewStyle=true;
41             break;
42           }
43     while (IsDigit(*Ext) && Ext>ArcName+1)
44       Ext--;
45     strcpy(Ext,"*.*");
46     FindFile Find;
47     Find.SetMask(ArcName);
48     struct FindData FD;
49     while (Find.Next(&FD))
50     {
51       Archive Arc(Cmd);
52       if (Arc.WOpen(FD.Name,FD.NameW) && Arc.IsArchive(true))
53       {
54         strcpy(ArcName,FD.Name);
55         *ArcNameW=0;
56         break;
57       }
58     }
59   }
60 
61   Archive Arc(Cmd);
62   if (!Arc.WCheckOpen(ArcName,ArcNameW))
63     return(false);
64   if (!Arc.Volume)
65   {
66 #ifndef SILENT
67     Log(ArcName,St(MNotVolume),ArcName);
68 #endif
69     return(false);
70   }
71   bool NewNumbering=(Arc.NewMhd.Flags & MHD_NEWNUMBERING)!=0;
72   Arc.Close();
73   char *VolNumStart=VolNameToFirstName(ArcName,ArcName,NewNumbering);
74   char RecVolMask[NM];
75   strcpy(RecVolMask,ArcName);
76   size_t BaseNamePartLength=VolNumStart-ArcName;
77   strcpy(RecVolMask+BaseNamePartLength,"*.rev");
78 
79 #ifndef SILENT
80   int64 RecFileSize=0;
81 #endif
82 
83 #ifndef SILENT
84   mprintf(St(MCalcCRCAllVol));
85 #endif
86 
87   FindFile Find;
88   Find.SetMask(RecVolMask);
89   struct FindData RecData;
90   int FileNumber=0,RecVolNumber=0,FoundRecVolumes=0,MissingVolumes=0;
91   char PrevName[NM];
92   while (Find.Next(&RecData))
93   {
94     char *Name=RecData.Name;
95     int P[3];
96     if (!RevName && !NewStyle)
97     {
98       NewStyle=true;
99       char *Dot=GetExt(Name);
100       if (Dot!=NULL)
101       {
102         int LineCount=0;
103         Dot--;
104         while (Dot>Name && *Dot!='.')
105         {
106           if (*Dot=='_')
107             LineCount++;
108           Dot--;
109         }
110         if (LineCount==2)
111           NewStyle=false;
112       }
113     }
114     if (NewStyle)
115     {
116       File CurFile;
117       CurFile.TOpen(Name);
118       CurFile.Seek(0,SEEK_END);
119       int64 Length=CurFile.Tell();
120       CurFile.Seek(Length-7,SEEK_SET);
121       for (int I=0;I<3;I++)
122         P[2-I]=CurFile.GetByte()+1;
123       uint FileCRC=0;
124       for (int I=0;I<4;I++)
125         FileCRC|=CurFile.GetByte()<<(I*8);
126       if (FileCRC!=CalcFileCRC(&CurFile,Length-4))
127       {
128 #ifndef SILENT
129         mprintf(St(MCRCFailed),Name);
130 #endif
131         continue;
132       }
133     }
134     else
135     {
136       char *Dot=GetExt(Name);
137       if (Dot==NULL)
138         continue;
139       bool WrongParam=false;
140       for (int I=0;I<sizeof(P)/sizeof(P[0]);I++)
141       {
142         do
143         {
144           Dot--;
145         } while (IsDigit(*Dot) && Dot>=Name+BaseNamePartLength);
146         P[I]=atoi(Dot+1);
147         if (P[I]==0 || P[I]>255)
148           WrongParam=true;
149       }
150       if (WrongParam)
151         continue;
152     }
153     if (P[1]+P[2]>255)
154       continue;
155     if (RecVolNumber!=0 && RecVolNumber!=P[1] || FileNumber!=0 && FileNumber!=P[2])
156     {
157 #ifndef SILENT
158       Log(NULL,St(MRecVolDiffSets),Name,PrevName);
159 #endif
160       return(false);
161     }
162     RecVolNumber=P[1];
163     FileNumber=P[2];
164     strcpy(PrevName,Name);
165     File *NewFile=new File;
166     NewFile->TOpen(Name);
167     SrcFile[FileNumber+P[0]-1]=NewFile;
168     FoundRecVolumes++;
169 #ifndef SILENT
170     if (RecFileSize==0)
171       RecFileSize=NewFile->FileLength();
172 #endif
173   }
174 #ifndef SILENT
175   if (!Silent || FoundRecVolumes!=0)
176   {
177     mprintf(St(MRecVolFound),FoundRecVolumes);
178   }
179 #endif
180   if (FoundRecVolumes==0)
181     return(false);
182 
183   bool WriteFlags[256];
184   memset(WriteFlags,0,sizeof(WriteFlags));
185 
186   char LastVolName[NM];
187   *LastVolName=0;
188 
189   for (int CurArcNum=0;CurArcNum<FileNumber;CurArcNum++)
190   {
191     Archive *NewFile=new Archive;
192     bool ValidVolume=FileExist(ArcName);
193     if (ValidVolume)
194     {
195       NewFile->TOpen(ArcName);
196       ValidVolume=NewFile->IsArchive(false);
197       if (ValidVolume)
198       {
199         while (NewFile->ReadHeader()!=0)
200         {
201           if (NewFile->GetHeaderType()==ENDARC_HEAD)
202           {
203             if ((NewFile->EndArcHead.Flags&EARC_DATACRC)!=0 &&
204                 NewFile->EndArcHead.ArcDataCRC!=CalcFileCRC(NewFile,NewFile->CurBlockPos))
205             {
206               ValidVolume=false;
207 #ifndef SILENT
208               mprintf(St(MCRCFailed),ArcName);
209 #endif
210             }
211             break;
212           }
213           NewFile->SeekToNext();
214         }
215       }
216       if (!ValidVolume)
217       {
218         NewFile->Close();
219         char NewName[NM];
220         strcpy(NewName,ArcName);
221         strcat(NewName,".bad");
222 #ifndef SILENT
223         mprintf(St(MBadArc),ArcName);
224         mprintf(St(MRenaming),ArcName,NewName);
225 #endif
226         rename(ArcName,NewName);
227       }
228       NewFile->Seek(0,SEEK_SET);
229     }
230     if (!ValidVolume)
231     {
232       NewFile->TCreate(ArcName);
233       WriteFlags[CurArcNum]=true;
234       MissingVolumes++;
235 
236       if (CurArcNum==FileNumber-1)
237         strcpy(LastVolName,ArcName);
238 
239 #ifndef SILENT
240       mprintf(St(MAbsNextVol),ArcName);
241 #endif
242     }
243     SrcFile[CurArcNum]=(File*)NewFile;
244     NextVolumeName(ArcName,ArcNameW,ASIZE(ArcName),!NewNumbering);
245   }
246 
247 #ifndef SILENT
248   mprintf(St(MRecVolMissing),MissingVolumes);
249 #endif
250 
251   if (MissingVolumes==0)
252   {
253 #ifndef SILENT
254     mprintf(St(MRecVolAllExist));
255 #endif
256     return(false);
257   }
258 
259   if (MissingVolumes>FoundRecVolumes)
260   {
261 #ifndef SILENT
262     mprintf(St(MRecVolCannotFix));
263 #endif
264     return(false);
265   }
266 #ifndef SILENT
267   mprintf(St(MReconstructing));
268 #endif
269 
270   RSCoder RSC(RecVolNumber);
271 
272   int TotalFiles=FileNumber+RecVolNumber;
273   int Erasures[256],EraSize=0;
274 
275   for (int I=0;I<TotalFiles;I++)
276     if (WriteFlags[I] || SrcFile[I]==NULL)
277       Erasures[EraSize++]=I;
278 
279 #ifndef SILENT
280   int64 ProcessedSize=0;
281 #ifndef GUI
282   int LastPercent=-1;
283   mprintf("     ");
284 #endif
285 #endif
286   int RecCount=0;
287 
288   while (true)
289   {
290     if ((++RecCount & 15)==0)
291       Wait();
292     int MaxRead=0;
293     for (int I=0;I<TotalFiles;I++)
294       if (WriteFlags[I] || SrcFile[I]==NULL)
295         memset(&Buf[I*RECVOL_BUFSIZE],0,RECVOL_BUFSIZE);
296       else
297       {
298         int ReadSize=SrcFile[I]->Read(&Buf[I*RECVOL_BUFSIZE],RECVOL_BUFSIZE);
299         if (ReadSize!=RECVOL_BUFSIZE)
300           memset(&Buf[I*RECVOL_BUFSIZE+ReadSize],0,RECVOL_BUFSIZE-ReadSize);
301         if (ReadSize>MaxRead)
302           MaxRead=ReadSize;
303       }
304     if (MaxRead==0)
305       break;
306 #ifndef SILENT
307     int CurPercent=ToPercent(ProcessedSize,RecFileSize);
308     if (!Cmd->DisablePercentage && CurPercent!=LastPercent)
309     {
310       mprintf("\b\b\b\b%3d%%",CurPercent);
311       LastPercent=CurPercent;
312     }
313     ProcessedSize+=MaxRead;
314 #endif
315     for (int BufPos=0;BufPos<MaxRead;BufPos++)
316     {
317       byte Data[256];
318       for (int I=0;I<TotalFiles;I++)
319         Data[I]=Buf[I*RECVOL_BUFSIZE+BufPos];
320       RSC.Decode(Data,TotalFiles,Erasures,EraSize);
321       for (int I=0;I<EraSize;I++)
322         Buf[Erasures[I]*RECVOL_BUFSIZE+BufPos]=Data[Erasures[I]];
323 /*
324       for (int I=0;I<FileNumber;I++)
325         Buf[I*RECVOL_BUFSIZE+BufPos]=Data[I];
326 */
327     }
328     for (int I=0;I<FileNumber;I++)
329       if (WriteFlags[I])
330         SrcFile[I]->Write(&Buf[I*RECVOL_BUFSIZE],MaxRead);
331   }
332   for (int I=0;I<RecVolNumber+FileNumber;I++)
333     if (SrcFile[I]!=NULL)
334     {
335       File *CurFile=SrcFile[I];
336       if (NewStyle && WriteFlags[I])
337       {
338         int64 Length=CurFile->Tell();
339         CurFile->Seek(Length-7,SEEK_SET);
340         for (int J=0;J<7;J++)
341           CurFile->PutByte(0);
342       }
343       CurFile->Close();
344       SrcFile[I]=NULL;
345     }
346   if (*LastVolName)
347   {
348     Archive Arc(Cmd);
349     if (Arc.Open(LastVolName,NULL,false,true) && Arc.IsArchive(true) &&
350         Arc.SearchBlock(ENDARC_HEAD))
351     {
352       Arc.Seek(Arc.NextBlockPos,SEEK_SET);
353       char Buf[8192];
354       int ReadSize=Arc.Read(Buf,sizeof(Buf));
355       int ZeroCount=0;
356       while (ZeroCount<ReadSize && Buf[ZeroCount]==0)
357         ZeroCount++;
358       if (ZeroCount==ReadSize)
359       {
360         Arc.Seek(Arc.NextBlockPos,SEEK_SET);
361         Arc.Truncate();
362       }
363     }
364   }
365 #if !defined(GUI) && !defined(SILENT)
366   if (!Cmd->DisablePercentage)
367     mprintf("\b\b\b\b100%%");
368   if (!Silent && !Cmd->DisableDone)
369     mprintf(St(MDone));
370 #endif
371   return(true);
372 }
373