Ejemplo n.º 1
0
bool WildFileExist(const wchar *Name)
{
  if (IsWildcard(Name))
  {
    FindFile Find;
    Find.SetMask(Name);
    FindData fd;
    return Find.Next(&fd);
  }
  return FileExist(Name);
}
Ejemplo n.º 2
0
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));
}
Ejemplo n.º 3
0
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));
}
Ejemplo n.º 4
0
// 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;
}
Ejemplo n.º 5
0
// 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;
}
Ejemplo n.º 6
0
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);
}
Ejemplo n.º 7
0
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);
  }
}
Ejemplo n.º 8
0
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;
}
Ejemplo n.º 9
0
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);
}
Ejemplo n.º 10
0
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);
}