bool WildFileExist(const wchar *Name) { if (IsWildcard(Name)) { FindFile Find; Find.SetMask(Name); FindData fd; return Find.Next(&fd); } return FileExist(Name); }
bool WildFileExist(const char *Name,const wchar *NameW) { if (IsWildcard(Name,NameW)) { FindFile Find; Find.SetMask(Name); Find.SetMaskW(NameW); FindData fd; return(Find.Next(&fd)); } return(FileExist(Name,NameW)); }
bool WildFileExist(const char *FileName,const wchar *FileNameW) { if (IsWildcard(FileName,FileNameW)) { FindFile Find; Find.SetMask(FileName); Find.SetMaskW(FileNameW); struct FindData fd; return(Find.Next(&fd)); } return(FileExist(FileName,FileNameW)); }
// Get the name of first volume. Return the leftmost digit of volume number. wchar* VolNameToFirstName(const wchar *VolName,wchar *FirstName,size_t MaxSize,bool NewNumbering) { if (FirstName!=VolName) wcsncpyz(FirstName,VolName,MaxSize); wchar *VolNumStart=FirstName; if (NewNumbering) { wchar N='1'; // From the rightmost digit of volume number to the left. for (wchar *ChPtr=GetVolNumPart(FirstName);ChPtr>FirstName;ChPtr--) if (IsDigit(*ChPtr)) { *ChPtr=N; // Set the rightmost digit to '1' and others to '0'. N='0'; } else if (N=='0') { VolNumStart=ChPtr+1; // Store the position of leftmost digit in volume number. break; } } else { // Old volume numbering scheme. Just set the extension to ".rar". SetExt(FirstName,L"rar",MaxSize); VolNumStart=GetExt(FirstName); } if (!FileExist(FirstName)) { // If the first volume, which name we just generated, is not exist, // check if volume with same name and any other extension is available. // It can help in case of *.exe or *.sfx first volume. wchar Mask[NM]; wcsncpyz(Mask,FirstName,ASIZE(Mask)); SetExt(Mask,L"*",ASIZE(Mask)); FindFile Find; Find.SetMask(Mask); FindData FD; while (Find.Next(&FD)) { Archive Arc; if (Arc.Open(FD.Name,0) && Arc.IsArchive(true) && Arc.FirstVolume) { wcsncpyz(FirstName,FD.Name,MaxSize); break; } } } return VolNumStart; }
// For masks like dir1\dir2*\*.ext in non-recursive mode. bool ScanTree::ExpandFolderMask() { bool WildcardFound=false; uint SlashPos=0; for (int I=0;CurMask[I]!=0;I++) { if (CurMask[I]=='?' || CurMask[I]=='*') WildcardFound=true; if (WildcardFound && IsPathDiv(CurMask[I])) { // First path separator position after folder wildcard mask. // In case of dir1\dir2*\dir3\name.ext mask it may point not to file // name, so we cannot use PointToName() here. SlashPos=I; break; } } wchar Mask[NM]; wcsncpyz(Mask,CurMask,ASIZE(Mask)); Mask[SlashPos]=0; // Prepare the list of all folders matching the wildcard mask. ExpandedFolderList.Reset(); FindFile Find; Find.SetMask(Mask); FindData FD; while (Find.Next(&FD)) if (FD.IsDir) { wcsncatz(FD.Name,CurMask+SlashPos,ASIZE(FD.Name)); // Treat dir*\* or dir*\*.* as dir, so empty 'dir' is also matched // by such mask. Skipping empty dir with dir*\*.* confused some users. wchar *LastMask=PointToName(FD.Name); if (wcscmp(LastMask,L"*")==0 || wcscmp(LastMask,L"*.*")==0) RemoveNameFromPath(FD.Name); ExpandedFolderList.AddString(FD.Name); } if (ExpandedFolderList.ItemsCount()==0) return false; // Return the first matching folder name now. ExpandedFolderList.GetString(CurMask,ASIZE(CurMask)); return true; }
char* VolNameToFirstName(const char *VolName,char *FirstName,bool NewNumbering) { if (FirstName!=VolName) strcpy(FirstName,VolName); char *VolNumStart=FirstName; if (NewNumbering) { int N='1'; for (char *ChPtr=GetVolNumPart(FirstName);ChPtr>FirstName;ChPtr--) if (isdigit(*ChPtr)) { *ChPtr=N; N='0'; } else if (N=='0') { VolNumStart=ChPtr+1; break; } } else { SetExt(FirstName,"rar"); VolNumStart=GetExt(FirstName); } if (!FileExist(FirstName)) { char Mask[NM]; strcpy(Mask,FirstName); SetExt(Mask,"*"); FindFile Find; Find.SetMask(Mask); struct FindData FD; while (Find.Next(&FD)) { Archive Arc; if (Arc.Open(FD.Name,FD.NameW) && Arc.IsArchive(true) && !Arc.NotFirstVolume) { strcpy(FirstName,FD.Name); break; } } } return(VolNumStart); }
void RecVolumesTest(RAROptions *Cmd,Archive *Arc,const wchar *Name) { wchar RevName[NM]; *RevName=0; if (Arc!=NULL) { // We received .rar or .exe volume as a parameter, trying to find // the matching .rev file number 1. bool NewNumbering=Arc->NewNumbering; wchar ArcName[NM]; wcsncpyz(ArcName,Name,ASIZE(ArcName)); wchar *VolNumStart=VolNameToFirstName(ArcName,ArcName,ASIZE(ArcName),NewNumbering); wchar RecVolMask[NM]; wcsncpyz(RecVolMask,ArcName,ASIZE(RecVolMask)); size_t BaseNamePartLength=VolNumStart-ArcName; wcsncpyz(RecVolMask+BaseNamePartLength,L"*.rev",ASIZE(RecVolMask)-BaseNamePartLength); FindFile Find; Find.SetMask(RecVolMask); FindData RecData; while (Find.Next(&RecData)) { wchar *Num=GetVolNumPart(RecData.Name); if (*Num!='1') // Name must have "0...01" numeric part. continue; bool FirstVol=true; while (--Num>=RecData.Name && IsDigit(*Num)) if (*Num!='0') { FirstVol=false; break; } if (FirstVol) { wcsncpyz(RevName,RecData.Name,ASIZE(RevName)); Name=RevName; break; } } if (*RevName==0) // First .rev file not found. return; } File RevFile; if (!RevFile.Open(Name)) { ErrHandler.OpenErrorMsg(Name); // It also sets RARX_OPEN. return; } #ifndef GUI mprintf(L"\n"); #endif byte Sign[REV5_SIGN_SIZE]; bool Rev5=RevFile.Read(Sign,REV5_SIGN_SIZE)==REV5_SIGN_SIZE && memcmp(Sign,REV5_SIGN,REV5_SIGN_SIZE)==0; RevFile.Close(); if (Rev5) { RecVolumes5 RecVol(true); RecVol.Test(Cmd,Name); } else { RecVolumes3 RecVol(true); RecVol.Test(Cmd,Name); } }
bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) { wchar ArcName[NM]; wcscpy(ArcName,Name); wchar *Num=GetVolNumPart(ArcName); while (Num>ArcName && IsDigit(*(Num-1))) Num--; wcsncpyz(Num,L"*.*",ASIZE(ArcName)-(Num-ArcName)); wchar FirstVolName[NM]; *FirstVolName=0; int64 RecFileSize=0; FindFile VolFind; VolFind.SetMask(ArcName); FindData fd; uint FoundRecVolumes=0; while (VolFind.Next(&fd)) { Wait(); Archive *Vol=new Archive(Cmd); int ItemPos=-1; if (Vol->WOpen(fd.Name)) { if (CmpExt(fd.Name,L"rev")) { uint RecNum=ReadHeader(Vol,FoundRecVolumes==0); if (RecNum!=0) { if (FoundRecVolumes==0) RecFileSize=Vol->FileLength(); ItemPos=RecNum; FoundRecVolumes++; } } else if (Vol->IsArchive(true) && (Vol->SFXSize>0 || CmpExt(fd.Name,L"rar"))) { if (!Vol->Volume && !Vol->BrokenHeader) { uiMsg(UIERROR_NOTVOLUME,ArcName); return false; } // We work with archive as with raw data file, so we do not want // to spend time to QOpen I/O redirection. Vol->QOpenUnload(); Vol->Seek(0,SEEK_SET); // RAR volume found. Get its number, store the handle in appropriate // array slot, clean slots in between if we had to grow the array. wchar *Num=GetVolNumPart(fd.Name); uint VolNum=0; for (uint K=1;Num>=fd.Name && IsDigit(*Num);K*=10,Num--) VolNum+=(*Num-'0')*K; if (VolNum==0 || VolNum>MaxVolumes) continue; size_t CurSize=RecItems.Size(); if (VolNum>CurSize) { RecItems.Alloc(VolNum); for (size_t I=CurSize;I<VolNum;I++) RecItems[I].f=NULL; } ItemPos=VolNum-1; if (*FirstVolName==0) VolNameToFirstName(fd.Name,FirstVolName,ASIZE(FirstVolName),true); } } if (ItemPos==-1) delete Vol; // Skip found file, it is not RAR or REV volume. else if ((uint)ItemPos<RecItems.Size()) // Check if found more REV than needed. { // Store found RAR or REV volume. RecVolItem *Item=RecItems+ItemPos; Item->f=Vol; Item->New=false; wcsncpyz(Item->Name,fd.Name,ASIZE(Item->Name)); } } if (!Silent || FoundRecVolumes!=0) uiMsg(UIMSG_RECVOLFOUND,FoundRecVolumes); if (FoundRecVolumes==0) return false; uiMsg(UIMSG_RECVOLCALCCHECKSUM); MissingVolumes=0; for (uint I=0;I<TotalCount;I++) { RecVolItem *Item=&RecItems[I]; if (Item->f!=NULL) { uiMsg(UIMSG_STRING,Item->Name); uint RevCRC; CalcFileSum(Item->f,&RevCRC,NULL,Cmd->Threads,INT64NDF,CALCFSUM_CURPOS); Item->Valid=RevCRC==Item->CRC; if (!Item->Valid) { uiMsg(UIMSG_CHECKSUM,Item->Name); // Close only corrupt REV volumes here. We'll close and rename corrupt // RAR volumes later, if we'll know that recovery is possible. if (I>=DataCount) { Item->f->Close(); Item->f=NULL; FoundRecVolumes--; } } } if (I<DataCount && (Item->f==NULL || !Item->Valid)) MissingVolumes++; } uiMsg(UIMSG_RECVOLMISSING,MissingVolumes); if (MissingVolumes==0) { uiMsg(UIERROR_RECVOLALLEXIST); return false; } if (MissingVolumes>FoundRecVolumes) { uiMsg(UIERROR_RECVOLFOUND,FoundRecVolumes); // Intentionally not displayed in console mode. uiMsg(UIERROR_RECVOLCANNOTFIX); return false; } uiMsg(UIMSG_RECONSTRUCTING); // Create missing and rename bad volumes. uint64 MaxVolSize=0; for (uint I=0;I<DataCount;I++) { RecVolItem *Item=&RecItems[I]; if (Item->FileSize>MaxVolSize) MaxVolSize=Item->FileSize; if (Item->f!=NULL && !Item->Valid) { Item->f->Close(); wchar NewName[NM]; wcscpy(NewName,Item->Name); wcscat(NewName,L".bad"); uiMsg(UIMSG_BADARCHIVE,Item->Name); uiMsg(UIMSG_RENAMING,Item->Name,NewName); RenameFile(Item->Name,NewName); delete Item->f; Item->f=NULL; } if (Item->New=(Item->f==NULL)) { wcsncpyz(Item->Name,FirstVolName,ASIZE(Item->Name)); uiMsg(UIMSG_CREATING,Item->Name); uiMsg(UIEVENT_NEWARCHIVE,Item->Name); File *NewVol=new File; bool UserReject; if (!FileCreate(Cmd,NewVol,Item->Name,ASIZE(Item->Name),&UserReject)) { if (!UserReject) ErrHandler.CreateErrorMsg(Item->Name); ErrHandler.Exit(UserReject ? RARX_USERBREAK:RARX_CREATE); } NewVol->Prealloc(Item->FileSize); Item->f=NewVol; Item->New=true; } NextVolumeName(FirstVolName,ASIZE(FirstVolName),false); } int64 ProcessedSize=0; #ifndef GUI int LastPercent=-1; mprintf(L" "); #endif // Even though we already preliminary calculated missing volume number, // let's do it again now, when we have the final and exact information. MissingVolumes=0; ValidFlags=new bool[TotalCount]; for (uint I=0;I<TotalCount;I++) { ValidFlags[I]=RecItems[I].f!=NULL && !RecItems[I].New; if (I<DataCount && !ValidFlags[I]) MissingVolumes++; } // Size of per file buffer. RecBufferSize=TotalBufferSize/MissingVolumes; if ((RecBufferSize&1)==1) // Must be even for our RS16 codec. RecBufferSize--; #ifdef USE_SSE RecBufferSize&=~(SSE_ALIGNMENT-1); // Align for SSE. #endif uint *Data=new uint[TotalCount]; RSCoder16 RS; if (!RS.Init(DataCount,RecCount,ValidFlags)) return false; // Should not happen, we check parameter validity above. RealReadBuffer=new byte[RecBufferSize+SSE_ALIGNMENT]; byte *ReadBuf=(byte *)ALIGN_VALUE(RealReadBuffer,SSE_ALIGNMENT); while (true) { Wait(); int MaxRead=0; for (uint I=0,J=DataCount;I<DataCount;I++) { uint VolNum=I; if (!ValidFlags[I]) // If next RAR volume is missing or invalid. { while (!ValidFlags[J]) // Find next valid REV volume. J++; VolNum=J++; // Use next valid REV volume data instead of RAR. } RecVolItem *Item=RecItems+VolNum; byte *B=&ReadBuf[0]; int ReadSize=0; if (Item->f!=NULL && !Item->New) ReadSize=Item->f->Read(B,RecBufferSize); if (ReadSize!=RecBufferSize) memset(B+ReadSize,0,RecBufferSize-ReadSize); if (ReadSize>MaxRead) MaxRead=ReadSize; // We can have volumes of different size. Let's use data chunk // for largest volume size. uint DataToProcess=(uint)Min(RecBufferSize,MaxVolSize-ProcessedSize); ProcessRS(Cmd,I,B,DataToProcess,false); } if (MaxRead==0) break; for (uint I=0,J=0;I<DataCount;I++) if (!ValidFlags[I]) { RecVolItem *Item=RecItems+I; size_t WriteSize=(size_t)Min(MaxRead,Item->FileSize); Item->f->Write(Buf+(J++)*RecBufferSize,WriteSize); Item->FileSize-=WriteSize; } int CurPercent=ToPercent(ProcessedSize,RecFileSize); if (!Cmd->DisablePercentage && CurPercent!=LastPercent) { uiProcessProgress("RV",ProcessedSize,RecFileSize); LastPercent=CurPercent; } ProcessedSize+=MaxRead; } for (uint I=0;I<TotalCount;I++) if (RecItems[I].f!=NULL) RecItems[I].f->Close(); delete[] ValidFlags; delete[] Data; #if !defined(GUI) && !defined(SILENT) if (!Cmd->DisablePercentage) mprintf(L"\b\b\b\b100%%"); if (!Silent && !Cmd->DisableDone) mprintf(St(MDone)); #endif return true; }
bool RecVolumes::Restore(RAROptions *Cmd,const char *Name,const wchar *NameW,bool Silent) { char ArcName[NM]; wchar ArcNameW[NM]; strcpy(ArcName,Name); wcscpy(ArcNameW,NameW); char *Ext=GetExt(ArcName); bool NewStyle=false; bool RevName=Ext!=NULL && stricomp(Ext,".rev")==0; if (RevName) { for (int DigitGroup=0;Ext>ArcName && DigitGroup<3;Ext--) if (!IsDigit(*Ext)) if (IsDigit(*(Ext-1)) && (*Ext=='_' || DigitGroup<2)) DigitGroup++; else if (DigitGroup<2) { NewStyle=true; break; } while (IsDigit(*Ext) && Ext>ArcName+1) Ext--; strcpy(Ext,"*.*"); if (*ArcNameW!=0) { wchar *ExtW=GetExt(ArcNameW); for (int DigitGroup=0;ExtW>ArcNameW && DigitGroup<3;ExtW--) if (!IsDigit(*ExtW)) if (IsDigit(*(ExtW-1)) && (*ExtW=='_' || DigitGroup<2)) DigitGroup++; else if (DigitGroup<2) { NewStyle=true; break; } while (IsDigit(*ExtW) && ExtW>ArcNameW+1) ExtW--; wcscpy(ExtW,L"*.*"); } FindFile Find; Find.SetMask(ArcName); Find.SetMaskW(ArcNameW); FindData fd; while (Find.Next(&fd)) { Archive Arc(Cmd); if (Arc.WOpen(fd.Name,fd.NameW) && Arc.IsArchive(true)) { strcpy(ArcName,fd.Name); wcscpy(ArcNameW,fd.NameW); break; } } } Archive Arc(Cmd); if (!Arc.WCheckOpen(ArcName,ArcNameW)) return(false); if (!Arc.Volume) { #ifndef SILENT Log(ArcName,St(MNotVolume),ArcName); #endif return(false); } bool NewNumbering=(Arc.NewMhd.Flags & MHD_NEWNUMBERING)!=0; Arc.Close(); char *VolNumStart=VolNameToFirstName(ArcName,ArcName,NewNumbering); char RecVolMask[NM]; strcpy(RecVolMask,ArcName); size_t BaseNamePartLength=VolNumStart-ArcName; strcpy(RecVolMask+BaseNamePartLength,"*.rev"); wchar RecVolMaskW[NM]; size_t BaseNamePartLengthW=0; *RecVolMaskW=0; if (*ArcNameW!=0) { wchar *VolNumStartW=VolNameToFirstName(ArcNameW,ArcNameW,NewNumbering); wcscpy(RecVolMaskW,ArcNameW); BaseNamePartLengthW=VolNumStartW-ArcNameW; wcscpy(RecVolMaskW+BaseNamePartLengthW,L"*.rev"); } #ifndef SILENT int64 RecFileSize=0; #endif // We cannot display "Calculating CRC..." message here, because we do not // know if we'll find any recovery volumes. We'll display it after finding // the first recovery volume. bool CalcCRCMessageDone=false; FindFile Find; Find.SetMask(RecVolMask); Find.SetMaskW(RecVolMaskW); FindData RecData; int FileNumber=0,RecVolNumber=0,FoundRecVolumes=0,MissingVolumes=0; char PrevName[NM]; wchar PrevNameW[NM]; while (Find.Next(&RecData)) { char *CurName=RecData.Name; wchar *CurNameW=RecData.NameW; int P[3]; if (!RevName && !NewStyle) { NewStyle=true; char *Dot=GetExt(CurName); if (Dot!=NULL) { int LineCount=0; Dot--; while (Dot>CurName && *Dot!='.') { if (*Dot=='_') LineCount++; Dot--; } if (LineCount==2) NewStyle=false; } wchar *DotW=GetExt(CurNameW); if (DotW!=NULL) { int LineCount=0; DotW--; while (DotW>CurNameW && *DotW!='.') { if (*DotW=='_') LineCount++; DotW--; } if (LineCount==2) NewStyle=false; } } if (NewStyle) { if (!CalcCRCMessageDone) { #ifndef SILENT mprintf(St(MCalcCRCAllVol)); #endif CalcCRCMessageDone=true; } #ifndef SILENT mprintf("\r\n%s",CurName); #endif File CurFile; CurFile.TOpen(CurName,CurNameW); CurFile.Seek(0,SEEK_END); int64 Length=CurFile.Tell(); CurFile.Seek(Length-7,SEEK_SET); for (int I=0;I<3;I++) P[2-I]=CurFile.GetByte()+1; uint FileCRC=0; for (int I=0;I<4;I++) FileCRC|=CurFile.GetByte()<<(I*8); if (FileCRC!=CalcFileCRC(&CurFile,Length-4)) { #ifndef SILENT mprintf(St(MCRCFailed),CurName); #endif continue; } } else { char *Dot=GetExt(CurName); if (Dot==NULL) continue; bool WrongParam=false; for (int I=0;I<ASIZE(P);I++) { do { Dot--; } while (IsDigit(*Dot) && Dot>=CurName+BaseNamePartLength); P[I]=atoi(Dot+1); if (P[I]==0 || P[I]>255) WrongParam=true; } if (WrongParam) continue; } if (P[1]+P[2]>255) continue; if (RecVolNumber!=0 && RecVolNumber!=P[1] || FileNumber!=0 && FileNumber!=P[2]) { #ifndef SILENT Log(NULL,St(MRecVolDiffSets),CurName,PrevName); #endif return(false); } RecVolNumber=P[1]; FileNumber=P[2]; strcpy(PrevName,CurName); wcscpy(PrevNameW,CurNameW); File *NewFile=new File; NewFile->TOpen(CurName,CurNameW); SrcFile[FileNumber+P[0]-1]=NewFile; FoundRecVolumes++; #ifndef SILENT if (RecFileSize==0) RecFileSize=NewFile->FileLength(); #endif } #ifndef SILENT if (!Silent || FoundRecVolumes!=0) { mprintf(St(MRecVolFound),FoundRecVolumes); } #endif if (FoundRecVolumes==0) return(false); bool WriteFlags[256]; memset(WriteFlags,0,sizeof(WriteFlags)); char LastVolName[NM]; *LastVolName=0; wchar LastVolNameW[NM]; *LastVolNameW=0; for (int CurArcNum=0;CurArcNum<FileNumber;CurArcNum++) { Archive *NewFile=new Archive; bool ValidVolume=FileExist(ArcName,ArcNameW); if (ValidVolume) { NewFile->TOpen(ArcName,ArcNameW); ValidVolume=NewFile->IsArchive(false); if (ValidVolume) { while (NewFile->ReadHeader()!=0) { if (NewFile->GetHeaderType()==ENDARC_HEAD) { #ifndef SILENT mprintf("\r\n%s",ArcName); #endif if ((NewFile->EndArcHead.Flags&EARC_DATACRC)!=0 && NewFile->EndArcHead.ArcDataCRC!=CalcFileCRC(NewFile,NewFile->CurBlockPos)) { ValidVolume=false; #ifndef SILENT mprintf(St(MCRCFailed),ArcName); #endif } break; } NewFile->SeekToNext(); } } if (!ValidVolume) { NewFile->Close(); char NewName[NM]; strcpy(NewName,ArcName); strcat(NewName,".bad"); wchar NewNameW[NM]; wcscpy(NewNameW,ArcNameW); if (*NewNameW!=0) wcscat(NewNameW,L".bad"); #ifndef SILENT mprintf(St(MBadArc),ArcName); mprintf(St(MRenaming),ArcName,NewName); #endif RenameFile(ArcName,ArcNameW,NewName,NewNameW); } NewFile->Seek(0,SEEK_SET); } if (!ValidVolume) { // It is important to return 'false' instead of aborting here, // so if we are called from extraction, we will be able to continue extracting. // It may happen if .rar and .rev are on read-only disks like CDs. if (!NewFile->Create(ArcName,ArcNameW)) { // We need to display the title of operation before the error message, // to make clear for user that create error is related to recovery // volumes. This is why we cannot use WCreate call here. Title must be // before create error, not after that. #ifndef SILENT mprintf(St(MReconstructing)); #endif ErrHandler.CreateErrorMsg(ArcName,ArcNameW); return false; } WriteFlags[CurArcNum]=true; MissingVolumes++; if (CurArcNum==FileNumber-1) { strcpy(LastVolName,ArcName); wcscpy(LastVolNameW,ArcNameW); } #ifndef SILENT mprintf(St(MAbsNextVol),ArcName); #endif } SrcFile[CurArcNum]=(File*)NewFile; NextVolumeName(ArcName,ArcNameW,ASIZE(ArcName),!NewNumbering); } #ifndef SILENT mprintf(St(MRecVolMissing),MissingVolumes); #endif if (MissingVolumes==0) { #ifndef SILENT mprintf(St(MRecVolAllExist)); #endif return(false); } if (MissingVolumes>FoundRecVolumes) { #ifndef SILENT mprintf(St(MRecVolCannotFix)); #endif return(false); } #ifndef SILENT mprintf(St(MReconstructing)); #endif int TotalFiles=FileNumber+RecVolNumber; int Erasures[256],EraSize=0; for (int I=0;I<TotalFiles;I++) if (WriteFlags[I] || SrcFile[I]==NULL) Erasures[EraSize++]=I; #ifndef SILENT int64 ProcessedSize=0; #ifndef GUI int LastPercent=-1; mprintf(" "); #endif #endif // Size of per file buffer. size_t RecBufferSize=TotalBufferSize/TotalFiles; #ifdef RAR_SMP uint ThreadNumber=Cmd->Threads; RSEncode rse[MaxPoolThreads]; uint WaitHandles[MaxPoolThreads]; #else uint ThreadNumber=1; RSEncode rse[1]; #endif for (uint I=0;I<ThreadNumber;I++) rse[I].Init(RecVolNumber); while (true) { Wait(); int MaxRead=0; for (int I=0;I<TotalFiles;I++) if (WriteFlags[I] || SrcFile[I]==NULL) memset(&Buf[I*RecBufferSize],0,RecBufferSize); else { int ReadSize=SrcFile[I]->Read(&Buf[I*RecBufferSize],RecBufferSize); if (ReadSize!=RecBufferSize) memset(&Buf[I*RecBufferSize+ReadSize],0,RecBufferSize-ReadSize); if (ReadSize>MaxRead) MaxRead=ReadSize; } if (MaxRead==0) break; #ifndef SILENT int CurPercent=ToPercent(ProcessedSize,RecFileSize); if (!Cmd->DisablePercentage && CurPercent!=LastPercent) { mprintf("\b\b\b\b%3d%%",CurPercent); LastPercent=CurPercent; } ProcessedSize+=MaxRead; #endif int BlockStart=0; int BlockSize=MaxRead/ThreadNumber; if (BlockSize<0x100) BlockSize=MaxRead; uint CurThread=0; while (BlockStart<MaxRead) { // Last thread processes all left data including increasement from rounding error. if (CurThread==ThreadNumber-1) BlockSize=MaxRead-BlockStart; RSEncode *curenc=rse+CurThread; curenc->Buf=&Buf[0]; curenc->BufStart=BlockStart; curenc->BufEnd=BlockStart+BlockSize; curenc->FileNumber=TotalFiles; curenc->RecBufferSize=RecBufferSize; curenc->Erasures=Erasures; curenc->EraSize=EraSize; #ifdef RAR_SMP if (ThreadNumber>1) { uint Handle=RSThreadPool.Start(RSDecodeThread,(void*)curenc); WaitHandles[CurThread++]=Handle; } else curenc->DecodeBuf(); #else curenc->DecodeBuf(); #endif BlockStart+=BlockSize; } #ifdef RAR_SMP if (CurThread>0) RSThreadPool.Wait(WaitHandles,CurThread); #endif // RAR_SMP for (int I=0;I<FileNumber;I++) if (WriteFlags[I]) SrcFile[I]->Write(&Buf[I*RecBufferSize],MaxRead); } for (int I=0;I<RecVolNumber+FileNumber;I++) if (SrcFile[I]!=NULL) { File *CurFile=SrcFile[I]; if (NewStyle && WriteFlags[I]) { int64 Length=CurFile->Tell(); CurFile->Seek(Length-7,SEEK_SET); for (int J=0;J<7;J++) CurFile->PutByte(0); } CurFile->Close(); SrcFile[I]=NULL; } if (*LastVolName!=0 || *LastVolNameW!=0) { // Truncate the last volume to its real size. Archive Arc(Cmd); if (Arc.Open(LastVolName,LastVolNameW,FMF_UPDATE) && Arc.IsArchive(true) && Arc.SearchBlock(ENDARC_HEAD)) { Arc.Seek(Arc.NextBlockPos,SEEK_SET); char Buf[8192]; int ReadSize=Arc.Read(Buf,sizeof(Buf)); int ZeroCount=0; while (ZeroCount<ReadSize && Buf[ZeroCount]==0) ZeroCount++; if (ZeroCount==ReadSize) { Arc.Seek(Arc.NextBlockPos,SEEK_SET); Arc.Truncate(); } } } #if !defined(GUI) && !defined(SILENT) if (!Cmd->DisablePercentage) mprintf("\b\b\b\b100%%"); if (!Silent && !Cmd->DisableDone) mprintf(St(MDone)); #endif return(true); }
bool RecVolumes::Restore(RAROptions *Cmd,const char *Name, const wchar *NameW,bool Silent) { char ArcName[NM]; wchar ArcNameW[NM]; strcpy(ArcName,Name); strcpyw(ArcNameW,NameW); char *Ext=GetExt(ArcName); bool NewStyle=false; bool RevName=Ext!=NULL && stricomp(Ext,".rev")==0; if (RevName) { for (int DigitGroup=0;Ext>ArcName && DigitGroup<3;Ext--) if (!isdigit(*Ext)) { if (isdigit(*(Ext-1)) && (*Ext=='_' || DigitGroup<2)) DigitGroup++; else if (DigitGroup<2) { NewStyle=true; break; } } while (isdigit(*Ext) && Ext>ArcName+1) Ext--; strcpy(Ext,"*.*"); FindFile Find; Find.SetMask(ArcName); struct FindData FD; while (Find.Next(&FD)) { Archive Arc(Cmd); if (Arc.WOpen(FD.Name,FD.NameW) && Arc.IsArchive(true)) { strcpy(ArcName,FD.Name); *ArcNameW=0; break; } } } Archive Arc(Cmd); if (!Arc.WCheckOpen(ArcName,ArcNameW)) return(false); if (!Arc.Volume) { #ifndef SILENT Log(ArcName,St(MNotVolume),ArcName); #endif return(false); } bool NewNumbering=(Arc.NewMhd.Flags & MHD_NEWNUMBERING); Arc.Close(); char *VolNumStart=VolNameToFirstName(ArcName,ArcName,NewNumbering); char RecVolMask[NM]; strcpy(RecVolMask,ArcName); int BaseNamePartLength=VolNumStart-ArcName; strcpy(RecVolMask+BaseNamePartLength,"*.rev"); #ifndef SILENT Int64 RecFileSize=0; #endif FindFile Find; Find.SetMask(RecVolMask); struct FindData RecData; int FileNumber=0,RecVolNumber=0,FoundRecVolumes=0,MissingVolumes=0; char PrevName[NM]; while (Find.Next(&RecData)) { char *Name=RecData.Name; int P[3]; if (!RevName && !NewStyle) { NewStyle=true; char *Dot=GetExt(Name); if (Dot!=NULL) { int LineCount=0; Dot--; while (Dot>Name && *Dot!='.') { if (*Dot=='_') LineCount++; Dot--; } if (LineCount==2) NewStyle=false; } } if (NewStyle) { File CurFile; CurFile.TOpen(Name); CurFile.Seek(0,SEEK_END); Int64 Length=CurFile.Tell(); CurFile.Seek(Length-7,SEEK_SET); for (int I=0;I<3;I++) P[2-I]=CurFile.GetByte()+1; uint FileCRC=0; for (int I=0;I<4;I++) FileCRC|=CurFile.GetByte()<<(I*8); if (FileCRC!=CalcFileCRC(&CurFile,Length-4)) { #ifndef SILENT mprintf(St(MCRCFailed),Name); #endif continue; } } else { char *Dot=GetExt(Name); if (Dot==NULL) continue; bool WrongParam=false; for (unsigned int I=0;I<sizeof(P)/sizeof(P[0]);I++) { do { Dot--; } while (isdigit(*Dot) && Dot>=Name+BaseNamePartLength); P[I]=atoi(Dot+1); if (P[I]==0 || P[I]>255) WrongParam=true; } if (WrongParam) continue; } if (P[1]+P[2]>255) continue; if ((RecVolNumber!=0 && RecVolNumber!=P[1]) || (FileNumber!=0 && FileNumber!=P[2])) { #ifndef SILENT Log(NULL,St(MRecVolDiffSets),Name,PrevName); #endif return(false); } RecVolNumber=P[1]; FileNumber=P[2]; strcpy(PrevName,Name); File *NewFile=new File; NewFile->TOpen(Name); SrcFile[FileNumber+P[0]-1]=NewFile; FoundRecVolumes++; #ifndef SILENT if (RecFileSize==0) RecFileSize=NewFile->FileLength(); #endif } #ifndef SILENT if (!Silent || FoundRecVolumes!=0) { mprintf(St(MRecVolFound),FoundRecVolumes); } #endif if (FoundRecVolumes==0) return(false); bool WriteFlags[256]; memset(WriteFlags,0,sizeof(WriteFlags)); char LastVolName[NM]; *LastVolName=0; for (int CurArcNum=0;CurArcNum<FileNumber;CurArcNum++) { Archive *NewFile=new Archive; bool ValidVolume=FileExist(ArcName); if (ValidVolume) { NewFile->TOpen(ArcName); ValidVolume=NewFile->IsArchive(false); if (ValidVolume) { bool EndFound=false,EndBlockRequired=false; while (!EndFound && NewFile->ReadHeader()!=0) { if (NewFile->GetHeaderType()==FILE_HEAD) { if (NewFile->NewLhd.UnpVer>=29) EndBlockRequired=true; if (!EndBlockRequired && (NewFile->NewLhd.Flags & LHD_SPLIT_AFTER)) EndFound=true; } if (NewFile->GetHeaderType()==ENDARC_HEAD) { if ((NewFile->EndArcHead.Flags&EARC_DATACRC)!=0 && NewFile->EndArcHead.ArcDataCRC!=CalcFileCRC(NewFile,NewFile->CurBlockPos)) { ValidVolume=false; #ifndef SILENT mprintf(St(MCRCFailed),ArcName); #endif } EndFound=true; } NewFile->SeekToNext(); } if (!EndFound) ValidVolume=false; } if (!ValidVolume) { NewFile->Close(); char NewName[NM]; strcpy(NewName,ArcName); strcat(NewName,".bad"); #ifndef SILENT mprintf(St(MBadArc),ArcName); mprintf(St(MRenaming),ArcName,NewName); #endif rename(ArcName,NewName); } NewFile->Seek(0,SEEK_SET); } if (!ValidVolume) { NewFile->TCreate(ArcName); WriteFlags[CurArcNum]=true; MissingVolumes++; if (CurArcNum==FileNumber-1) strcpy(LastVolName,ArcName); #ifndef SILENT mprintf(St(MAbsNextVol),ArcName); #endif } SrcFile[CurArcNum]=(File*)NewFile; NextVolumeName(ArcName,!NewNumbering); } #ifndef SILENT mprintf(St(MRecVolMissing),MissingVolumes); #endif if (MissingVolumes==0) { #ifndef SILENT mprintf(St(MRecVolAllExist)); #endif return(false); } if (MissingVolumes>FoundRecVolumes) { #ifndef SILENT mprintf(St(MRecVolCannotFix)); #endif return(false); } #ifndef SILENT mprintf(St(MReconstructing)); #endif RSCoder RSC(RecVolNumber); int TotalFiles=FileNumber+RecVolNumber; int Erasures[256],EraSize=0; for (int I=0;I<TotalFiles;I++) if (WriteFlags[I] || SrcFile[I]==NULL) Erasures[EraSize++]=I; #ifndef SILENT Int64 ProcessedSize=0; #ifndef GUI int LastPercent=-1; mprintf(" "); #endif #endif int RecCount=0; while (true) { if ((++RecCount & 15)==0) Wait(); int MaxRead=0; for (int I=0;I<TotalFiles;I++) if (WriteFlags[I] || SrcFile[I]==NULL) memset(&Buf[I*RECVOL_BUFSIZE],0,RECVOL_BUFSIZE); else { int ReadSize=SrcFile[I]->Read(&Buf[I*RECVOL_BUFSIZE],RECVOL_BUFSIZE); if (ReadSize!=RECVOL_BUFSIZE) memset(&Buf[I*RECVOL_BUFSIZE+ReadSize],0,RECVOL_BUFSIZE-ReadSize); if (ReadSize>MaxRead) MaxRead=ReadSize; } if (MaxRead==0) break; #ifndef SILENT int CurPercent=ToPercent(ProcessedSize,RecFileSize); if (!Cmd->DisablePercentage && CurPercent!=LastPercent) { mprintf("\b\b\b\b%3d%%",CurPercent); LastPercent=CurPercent; } ProcessedSize+=MaxRead; #endif for (int BufPos=0;BufPos<MaxRead;BufPos++) { byte Data[256]; for (int I=0;I<TotalFiles;I++) Data[I]=Buf[I*RECVOL_BUFSIZE+BufPos]; RSC.Decode(Data,TotalFiles,Erasures,EraSize); for (int I=0;I<EraSize;I++) Buf[Erasures[I]*RECVOL_BUFSIZE+BufPos]=Data[Erasures[I]]; /* for (int I=0;I<FileNumber;I++) Buf[I*RECVOL_BUFSIZE+BufPos]=Data[I]; */ } for (int I=0;I<FileNumber;I++) if (WriteFlags[I]) SrcFile[I]->Write(&Buf[I*RECVOL_BUFSIZE],MaxRead); } for (int I=0;I<RecVolNumber+FileNumber;I++) if (SrcFile[I]!=NULL) { File *CurFile=SrcFile[I]; if (NewStyle && WriteFlags[I]) { Int64 Length=CurFile->Tell(); CurFile->Seek(Length-7,SEEK_SET); for (int J=0;J<7;J++) CurFile->PutByte(0); } CurFile->Close(); SrcFile[I]=NULL; } if (*LastVolName) { Archive Arc(Cmd); if (Arc.Open(LastVolName,NULL,false,true) && Arc.IsArchive(true) && Arc.SearchBlock(ENDARC_HEAD)) { Arc.Seek(Arc.NextBlockPos,SEEK_SET); char Buf[8192]; int ReadSize=Arc.Read(Buf,sizeof(Buf)); int ZeroCount=0; while (ZeroCount<ReadSize && Buf[ZeroCount]==0) ZeroCount++; if (ZeroCount==ReadSize) { Arc.Seek(Arc.NextBlockPos,SEEK_SET); Arc.Truncate(); } } } #if !defined(GUI) && !defined(SILENT) if (!Cmd->DisablePercentage) mprintf("\b\b\b\b100%%"); if (!Silent && !Cmd->DisableDone) mprintf(St(MDone)); #endif return(true); }