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