"Fossies" - the Fresh Open Source Software Archive

Member "unrar/recvol3.cpp" (4 May 2022, 13399 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 "recvol3.cpp" see the Fossies "Dox" file reference documentation.

    1 // Buffer size for all volumes involved.
    2 static const size_t TotalBufferSize=0x4000000;
    3 
    4 class RSEncode // Encode or decode data area, one object per one thread.
    5 {
    6   private:
    7     RSCoder RSC;
    8   public:
    9     void EncodeBuf();
   10     void DecodeBuf();
   11 
   12     void Init(int RecVolNumber) {RSC.Init(RecVolNumber);}
   13     byte *Buf;
   14     byte *OutBuf;
   15     int BufStart;
   16     int BufEnd;
   17     int FileNumber;
   18     int RecVolNumber;
   19     size_t RecBufferSize;
   20     int *Erasures;
   21     int EraSize;
   22 };
   23 
   24 
   25 #ifdef RAR_SMP
   26 THREAD_PROC(RSEncodeThread)
   27 {
   28   RSEncode *rs=(RSEncode *)Data;
   29   rs->EncodeBuf();
   30 }
   31 
   32 THREAD_PROC(RSDecodeThread)
   33 {
   34   RSEncode *rs=(RSEncode *)Data;
   35   rs->DecodeBuf();
   36 }
   37 #endif
   38 
   39 RecVolumes3::RecVolumes3(RAROptions *Cmd,bool TestOnly)
   40 {
   41   memset(SrcFile,0,sizeof(SrcFile));
   42   if (TestOnly)
   43   {
   44 #ifdef RAR_SMP
   45     RSThreadPool=NULL;
   46 #endif
   47   }
   48   else
   49   {
   50     Buf.Alloc(TotalBufferSize);
   51     memset(SrcFile,0,sizeof(SrcFile));
   52 #ifdef RAR_SMP
   53     RSThreadPool=new ThreadPool(Cmd->Threads);
   54 #endif
   55   }
   56 }
   57 
   58 
   59 RecVolumes3::~RecVolumes3()
   60 {
   61   for (size_t I=0;I<ASIZE(SrcFile);I++)
   62     delete SrcFile[I];
   63 #ifdef RAR_SMP
   64   delete RSThreadPool;
   65 #endif
   66 }
   67 
   68 
   69 
   70 
   71 void RSEncode::EncodeBuf()
   72 {
   73   for (int BufPos=BufStart;BufPos<BufEnd;BufPos++)
   74   {
   75     byte Data[256],Code[256];
   76     for (int I=0;I<FileNumber;I++)
   77       Data[I]=Buf[I*RecBufferSize+BufPos];
   78     RSC.Encode(Data,FileNumber,Code);
   79     for (int I=0;I<RecVolNumber;I++)
   80       OutBuf[I*RecBufferSize+BufPos]=Code[I];
   81   }
   82 }
   83 
   84 
   85 // Check for names like arc5_3_1.rev created by RAR 3.0.
   86 static bool IsNewStyleRev(const wchar *Name)
   87 {
   88   wchar *Ext=GetExt(Name);
   89   if (Ext==NULL)
   90     return true;
   91   int DigitGroup=0;
   92   for (Ext--;Ext>Name;Ext--)
   93     if (!IsDigit(*Ext))
   94       if (*Ext=='_' && IsDigit(*(Ext-1)))
   95         DigitGroup++;
   96       else
   97         break;
   98   return DigitGroup<2;
   99 }
  100 
  101 
  102 bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
  103 {
  104   wchar ArcName[NM];
  105   wcsncpyz(ArcName,Name,ASIZE(ArcName));
  106   wchar *Ext=GetExt(ArcName);
  107   bool NewStyle=false; // New style .rev volumes are supported since RAR 3.10.
  108   bool RevName=Ext!=NULL && wcsicomp(Ext,L".rev")==0;
  109   if (RevName)
  110   {
  111     NewStyle=IsNewStyleRev(ArcName);
  112     while (Ext>ArcName+1 && (IsDigit(*(Ext-1)) || *(Ext-1)=='_'))
  113       Ext--;
  114     wcsncpyz(Ext,L"*.*",ASIZE(ArcName)-(Ext-ArcName));
  115     
  116     FindFile Find;
  117     Find.SetMask(ArcName);
  118     FindData fd;
  119     while (Find.Next(&fd))
  120     {
  121       Archive Arc(Cmd);
  122       if (Arc.WOpen(fd.Name) && Arc.IsArchive(true))
  123       {
  124         wcsncpyz(ArcName,fd.Name,ASIZE(ArcName));
  125         break;
  126       }
  127     }
  128   }
  129 
  130   Archive Arc(Cmd);
  131   if (!Arc.WCheckOpen(ArcName))
  132     return false;
  133   if (!Arc.Volume)
  134   {
  135     uiMsg(UIERROR_NOTVOLUME,ArcName);
  136     return false;
  137   }
  138   bool NewNumbering=Arc.NewNumbering;
  139   Arc.Close();
  140 
  141   wchar *VolNumStart=VolNameToFirstName(ArcName,ArcName,ASIZE(ArcName),NewNumbering);
  142   wchar RecVolMask[NM];
  143   wcsncpyz(RecVolMask,ArcName,ASIZE(RecVolMask));
  144   size_t BaseNamePartLength=VolNumStart-ArcName;
  145   wcsncpyz(RecVolMask+BaseNamePartLength,L"*.rev",ASIZE(RecVolMask)-BaseNamePartLength);
  146 
  147   int64 RecFileSize=0;
  148 
  149   // We cannot display "Calculating CRC..." message here, because we do not
  150   // know if we'll find any recovery volumes. We'll display it after finding
  151   // the first recovery volume.
  152   bool CalcCRCMessageDone=false;
  153 
  154   FindFile Find;
  155   Find.SetMask(RecVolMask);
  156   FindData RecData;
  157   int FileNumber=0,RecVolNumber=0,FoundRecVolumes=0,MissingVolumes=0;
  158   wchar PrevName[NM];
  159   while (Find.Next(&RecData))
  160   {
  161     wchar *CurName=RecData.Name;
  162     int P[3];
  163     if (!RevName && !NewStyle)
  164     {
  165       NewStyle=true;
  166 
  167       wchar *Dot=GetExt(CurName);
  168       if (Dot!=NULL)
  169       {
  170         int LineCount=0;
  171         Dot--;
  172         while (Dot>CurName && *Dot!='.')
  173         {
  174           if (*Dot=='_')
  175             LineCount++;
  176           Dot--;
  177         }
  178         if (LineCount==2)
  179           NewStyle=false;
  180       }
  181     }
  182     if (NewStyle)
  183     {
  184       if (!CalcCRCMessageDone)
  185       {
  186         uiMsg(UIMSG_RECVOLCALCCHECKSUM);
  187         CalcCRCMessageDone=true;
  188       }
  189       
  190       uiMsg(UIMSG_STRING,CurName);
  191 
  192       File CurFile;
  193       CurFile.TOpen(CurName);
  194       CurFile.Seek(0,SEEK_END);
  195       int64 Length=CurFile.Tell();
  196       CurFile.Seek(Length-7,SEEK_SET);
  197       for (int I=0;I<3;I++)
  198         P[2-I]=CurFile.GetByte()+1;
  199       uint FileCRC=0;
  200       for (int I=0;I<4;I++)
  201         FileCRC|=CurFile.GetByte()<<(I*8);
  202       uint CalcCRC;
  203       CalcFileSum(&CurFile,&CalcCRC,NULL,Cmd->Threads,Length-4);
  204       if (FileCRC!=CalcCRC)
  205       {
  206         uiMsg(UIMSG_CHECKSUM,CurName);
  207         continue;
  208       }
  209     }
  210     else
  211     {
  212       wchar *Dot=GetExt(CurName);
  213       if (Dot==NULL)
  214         continue;
  215       bool WrongParam=false;
  216       for (size_t I=0;I<ASIZE(P);I++)
  217       {
  218         do
  219         {
  220           Dot--;
  221         } while (IsDigit(*Dot) && Dot>=CurName+BaseNamePartLength);
  222         P[I]=atoiw(Dot+1);
  223         if (P[I]==0 || P[I]>255)
  224           WrongParam=true;
  225       }
  226       if (WrongParam)
  227         continue;
  228     }
  229     if (P[1]+P[2]>255)
  230       continue;
  231     if (RecVolNumber!=0 && RecVolNumber!=P[1] || FileNumber!=0 && FileNumber!=P[2])
  232     {
  233       uiMsg(UIERROR_RECVOLDIFFSETS,CurName,PrevName);
  234       return false;
  235     }
  236     RecVolNumber=P[1];
  237     FileNumber=P[2];
  238     wcsncpyz(PrevName,CurName,ASIZE(PrevName));
  239     File *NewFile=new File;
  240     NewFile->TOpen(CurName);
  241     SrcFile[FileNumber+P[0]-1]=NewFile;
  242     FoundRecVolumes++;
  243 
  244     if (RecFileSize==0)
  245       RecFileSize=NewFile->FileLength();
  246   }
  247   if (!Silent || FoundRecVolumes!=0)
  248     uiMsg(UIMSG_RECVOLFOUND,FoundRecVolumes);
  249   if (FoundRecVolumes==0)
  250     return false;
  251 
  252   bool WriteFlags[256];
  253   memset(WriteFlags,0,sizeof(WriteFlags));
  254 
  255   wchar LastVolName[NM];
  256   *LastVolName=0;
  257 
  258   for (int CurArcNum=0;CurArcNum<FileNumber;CurArcNum++)
  259   {
  260     Archive *NewFile=new Archive(Cmd);
  261     bool ValidVolume=FileExist(ArcName);
  262     if (ValidVolume)
  263     {
  264       NewFile->TOpen(ArcName);
  265       ValidVolume=NewFile->IsArchive(false);
  266       if (ValidVolume)
  267       {
  268         while (NewFile->ReadHeader()!=0)
  269         {
  270           if (NewFile->GetHeaderType()==HEAD_ENDARC)
  271           {
  272             uiMsg(UIMSG_STRING,ArcName);
  273 
  274             if (NewFile->EndArcHead.DataCRC)
  275             {
  276               uint CalcCRC;
  277               CalcFileSum(NewFile,&CalcCRC,NULL,Cmd->Threads,NewFile->CurBlockPos);
  278               if (NewFile->EndArcHead.ArcDataCRC!=CalcCRC)
  279               {
  280                 ValidVolume=false;
  281                 uiMsg(UIMSG_CHECKSUM,ArcName);
  282               }
  283             }
  284             break;
  285           }
  286           NewFile->SeekToNext();
  287         }
  288       }
  289       if (!ValidVolume)
  290       {
  291         NewFile->Close();
  292         wchar NewName[NM];
  293         wcsncpyz(NewName,ArcName,ASIZE(NewName));
  294         wcsncatz(NewName,L".bad",ASIZE(NewName));
  295 
  296         uiMsg(UIMSG_BADARCHIVE,ArcName);
  297         uiMsg(UIMSG_RENAMING,ArcName,NewName);
  298         RenameFile(ArcName,NewName);
  299       }
  300       NewFile->Seek(0,SEEK_SET);
  301     }
  302     if (!ValidVolume)
  303     {
  304       // It is important to return 'false' instead of aborting here,
  305       // so if we are called from extraction, we will be able to continue
  306       // extracting. It may happen if .rar and .rev are on read-only disks
  307       // like CDs.
  308       if (!NewFile->Create(ArcName,FMF_WRITE|FMF_SHAREREAD))
  309       {
  310         // We need to display the title of operation before the error message,
  311         // to make clear for user that create error is related to recovery 
  312         // volumes. This is why we cannot use WCreate call here. Title must be
  313         // before create error, not after that.
  314 
  315         uiMsg(UIERROR_RECVOLFOUND,FoundRecVolumes); // Intentionally not displayed in console mode.
  316         uiMsg(UIERROR_RECONSTRUCTING);
  317         ErrHandler.CreateErrorMsg(ArcName);
  318         return false;
  319       }
  320 
  321       WriteFlags[CurArcNum]=true;
  322       MissingVolumes++;
  323 
  324       if (CurArcNum==FileNumber-1)
  325         wcsncpyz(LastVolName,ArcName,ASIZE(LastVolName));
  326 
  327       uiMsg(UIMSG_MISSINGVOL,ArcName);
  328       uiMsg(UIEVENT_NEWARCHIVE,ArcName);
  329     }
  330     SrcFile[CurArcNum]=(File*)NewFile;
  331     NextVolumeName(ArcName,ASIZE(ArcName),!NewNumbering);
  332   }
  333 
  334   uiMsg(UIMSG_RECVOLMISSING,MissingVolumes);
  335 
  336   if (MissingVolumes==0)
  337   {
  338     uiMsg(UIERROR_RECVOLALLEXIST);
  339     return false;
  340   }
  341 
  342   if (MissingVolumes>FoundRecVolumes)
  343   {
  344     uiMsg(UIERROR_RECVOLFOUND,FoundRecVolumes); // Intentionally not displayed in console mode.
  345     uiMsg(UIERROR_RECVOLCANNOTFIX);
  346     return false;
  347   }
  348 
  349   uiMsg(UIMSG_RECONSTRUCTING);
  350 
  351   int TotalFiles=FileNumber+RecVolNumber;
  352   int Erasures[256],EraSize=0;
  353 
  354   for (int I=0;I<TotalFiles;I++)
  355     if (WriteFlags[I] || SrcFile[I]==NULL)
  356       Erasures[EraSize++]=I;
  357 
  358   int64 ProcessedSize=0;
  359   int LastPercent=-1;
  360   mprintf(L"     ");
  361   // Size of per file buffer.
  362   size_t RecBufferSize=TotalBufferSize/TotalFiles;
  363 
  364 #ifdef RAR_SMP
  365   uint ThreadNumber=Cmd->Threads;
  366 #else
  367   uint ThreadNumber=1;
  368 #endif
  369   RSEncode *rse=new RSEncode[ThreadNumber];
  370   for (uint I=0;I<ThreadNumber;I++)
  371     rse[I].Init(RecVolNumber);
  372 
  373   while (true)
  374   {
  375     Wait();
  376     int MaxRead=0;
  377     for (int I=0;I<TotalFiles;I++)
  378       if (WriteFlags[I] || SrcFile[I]==NULL)
  379         memset(&Buf[I*RecBufferSize],0,RecBufferSize);
  380       else
  381       {
  382         int ReadSize=SrcFile[I]->Read(&Buf[I*RecBufferSize],RecBufferSize);
  383         if ((size_t)ReadSize!=RecBufferSize)
  384           memset(&Buf[I*RecBufferSize+ReadSize],0,RecBufferSize-ReadSize);
  385         if (ReadSize>MaxRead)
  386           MaxRead=ReadSize;
  387       }
  388     if (MaxRead==0)
  389       break;
  390 
  391     int CurPercent=ToPercent(ProcessedSize,RecFileSize);
  392     if (!Cmd->DisablePercentage && CurPercent!=LastPercent)
  393     {
  394       uiProcessProgress("RC",ProcessedSize,RecFileSize);
  395       LastPercent=CurPercent;
  396     }
  397     ProcessedSize+=MaxRead;
  398 
  399     int BlockStart=0;
  400     int BlockSize=MaxRead/ThreadNumber;
  401     if (BlockSize<0x100)
  402       BlockSize=MaxRead;
  403     
  404     for (uint CurThread=0;BlockStart<MaxRead;CurThread++)
  405     {
  406       // Last thread processes all left data including increasement
  407       // from rounding error.
  408       if (CurThread==ThreadNumber-1)
  409         BlockSize=MaxRead-BlockStart;
  410 
  411       RSEncode *curenc=rse+CurThread;
  412       curenc->Buf=&Buf[0];
  413       curenc->BufStart=BlockStart;
  414       curenc->BufEnd=BlockStart+BlockSize;
  415       curenc->FileNumber=TotalFiles;
  416       curenc->RecBufferSize=RecBufferSize;
  417       curenc->Erasures=Erasures;
  418       curenc->EraSize=EraSize;
  419 
  420 #ifdef RAR_SMP
  421       if (ThreadNumber>1)
  422         RSThreadPool->AddTask(RSDecodeThread,(void*)curenc);
  423       else
  424         curenc->DecodeBuf();
  425 #else
  426       curenc->DecodeBuf();
  427 #endif
  428 
  429       BlockStart+=BlockSize;
  430     }
  431 
  432 #ifdef RAR_SMP
  433     RSThreadPool->WaitDone();
  434 #endif // RAR_SMP
  435     
  436     for (int I=0;I<FileNumber;I++)
  437       if (WriteFlags[I])
  438         SrcFile[I]->Write(&Buf[I*RecBufferSize],MaxRead);
  439   }
  440   delete[] rse;
  441 
  442   for (int I=0;I<RecVolNumber+FileNumber;I++)
  443     if (SrcFile[I]!=NULL)
  444     {
  445       File *CurFile=SrcFile[I];
  446       if (NewStyle && WriteFlags[I])
  447       {
  448         int64 Length=CurFile->Tell();
  449         CurFile->Seek(Length-7,SEEK_SET);
  450         for (int J=0;J<7;J++)
  451           CurFile->PutByte(0);
  452       }
  453       CurFile->Close();
  454       SrcFile[I]=NULL;
  455     }
  456   if (*LastVolName!=0)
  457   {
  458     // Truncate the last volume to its real size.
  459     Archive Arc(Cmd);
  460     if (Arc.Open(LastVolName,FMF_UPDATE) && Arc.IsArchive(true) &&
  461         Arc.SearchBlock(HEAD_ENDARC))
  462     {
  463       Arc.Seek(Arc.NextBlockPos,SEEK_SET);
  464       char Buf[8192];
  465       int ReadSize=Arc.Read(Buf,sizeof(Buf));
  466       int ZeroCount=0;
  467       while (ZeroCount<ReadSize && Buf[ZeroCount]==0)
  468         ZeroCount++;
  469       if (ZeroCount==ReadSize)
  470       {
  471         Arc.Seek(Arc.NextBlockPos,SEEK_SET);
  472         Arc.Truncate();
  473       }
  474     }
  475   }
  476 #if !defined(SILENT)
  477   if (!Cmd->DisablePercentage)
  478     mprintf(L"\b\b\b\b100%%");
  479   if (!Silent && !Cmd->DisableDone)
  480     mprintf(St(MDone));
  481 #endif
  482   return true;
  483 }
  484 
  485 
  486 void RSEncode::DecodeBuf()
  487 {
  488   for (int BufPos=BufStart;BufPos<BufEnd;BufPos++)
  489   {
  490     byte Data[256];
  491     for (int I=0;I<FileNumber;I++)
  492       Data[I]=Buf[I*RecBufferSize+BufPos];
  493     RSC.Decode(Data,FileNumber,Erasures,EraSize);
  494     for (int I=0;I<EraSize;I++)
  495       Buf[Erasures[I]*RecBufferSize+BufPos]=Data[Erasures[I]];
  496   }
  497 }
  498 
  499 
  500 void RecVolumes3::Test(RAROptions *Cmd,const wchar *Name)
  501 {
  502   if (!IsNewStyleRev(Name)) // RAR 3.0 name#_#_#.rev do not include CRC32.
  503   {
  504     ErrHandler.UnknownMethodMsg(Name,Name);
  505     return;
  506   }
  507 
  508   wchar VolName[NM];
  509   wcsncpyz(VolName,Name,ASIZE(VolName));
  510 
  511   while (FileExist(VolName))
  512   {
  513     File CurFile;
  514     if (!CurFile.Open(VolName))
  515     {
  516       ErrHandler.OpenErrorMsg(VolName); // It also sets RARX_OPEN.
  517       continue;
  518     }
  519     if (!uiStartFileExtract(VolName,false,true,false))
  520       return;
  521     mprintf(St(MExtrTestFile),VolName);
  522     mprintf(L"     ");
  523     CurFile.Seek(0,SEEK_END);
  524     int64 Length=CurFile.Tell();
  525     CurFile.Seek(Length-4,SEEK_SET);
  526     uint FileCRC=0;
  527     for (int I=0;I<4;I++)
  528       FileCRC|=CurFile.GetByte()<<(I*8);
  529 
  530     uint CalcCRC;
  531     CalcFileSum(&CurFile,&CalcCRC,NULL,1,Length-4,Cmd->DisablePercentage ? 0 : CALCFSUM_SHOWPROGRESS);
  532     if (FileCRC==CalcCRC)
  533     {
  534       mprintf(L"%s%s ",L"\b\b\b\b\b ",St(MOk));
  535     }
  536     else
  537     {
  538       uiMsg(UIERROR_CHECKSUM,VolName,VolName);
  539       ErrHandler.SetErrorCode(RARX_CRC);
  540     }
  541 
  542     NextVolumeName(VolName,ASIZE(VolName),false);
  543   }
  544 }