"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 }