Example #1
0
File: dll.cpp Project: Bootz/nzbm
int PASCAL RARReadHeader(HANDLE hArcData,struct RARHeaderData *D)
{
  DataSet *Data=(DataSet *)hArcData;
  try
  {
    if ((Data->HeaderSize=(int)Data->Arc.SearchBlock(FILE_HEAD))<=0)
    {
      if (Data->Arc.Volume && Data->Arc.GetHeaderType()==ENDARC_HEAD &&
          (Data->Arc.EndArcHead.Flags & EARC_NEXT_VOLUME))
        if (MergeArchive(Data->Arc,NULL,false,'L'))
        {
          Data->Extract.SignatureFound=false;
          Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
          return(RARReadHeader(hArcData,D));
        }
        else
          return(ERAR_EOPEN);
      return(Data->Arc.BrokenFileHeader ? ERAR_BAD_DATA:ERAR_END_ARCHIVE);
    }
    if (Data->OpenMode==RAR_OM_LIST && (Data->Arc.NewLhd.Flags & LHD_SPLIT_BEFORE))
    {
      int Code=RARProcessFile(hArcData,RAR_SKIP,NULL,NULL);
      if (Code==0)
        return(RARReadHeader(hArcData,D));
      else
        return(Code);
    }
    strncpyz(D->ArcName,Data->Arc.FileName,ASIZE(D->ArcName));
    strncpyz(D->FileName,Data->Arc.NewLhd.FileName,ASIZE(D->FileName));
    D->Flags=Data->Arc.NewLhd.Flags;
    D->PackSize=Data->Arc.NewLhd.PackSize;
    D->UnpSize=Data->Arc.NewLhd.UnpSize;
    D->HostOS=Data->Arc.NewLhd.HostOS;
    D->FileCRC=Data->Arc.NewLhd.FileCRC;
    D->FileTime=Data->Arc.NewLhd.FileTime;
    D->UnpVer=Data->Arc.NewLhd.UnpVer;
    D->Method=Data->Arc.NewLhd.Method;
    D->FileAttr=Data->Arc.NewLhd.FileAttr;
    D->CmtSize=0;
    D->CmtState=0;
  }
  catch (int ErrCode)
  {
    return(RarErrorToDll(ErrCode));
  }
  return(0);
}
Example #2
0
void ListArchive(CommandData *Cmd)
{
  int64 SumPackSize=0,SumUnpSize=0;
  uint ArcCount=0,SumFileCount=0;
  bool Technical=(Cmd->Command[1]=='T');
  bool ShowService=Technical && Cmd->Command[2]=='A';
  bool Bare=(Cmd->Command[1]=='B');
  bool Verbose=(Cmd->Command[0]=='V');

  wchar ArcName[NM];
  while (Cmd->GetArcName(ArcName,ASIZE(ArcName)))
  {
    if (Cmd->ManualPassword)
      Cmd->Password.Clean(); // Clean user entered password before processing next archive.

    Archive Arc(Cmd);
#ifdef _WIN_ALL
    Arc.RemoveSequentialFlag();
#endif
    if (!Arc.WOpen(ArcName))
      continue;
    bool FileMatched=true;
    while (1)
    {
      int64 TotalPackSize=0,TotalUnpSize=0;
      uint FileCount=0;
      if (Arc.IsArchive(true))
      {
        bool TitleShown=false;
        if (!Bare)
        {
          Arc.ViewComment();
          mprintf(L"\n%s: %s",St(MListArchive),Arc.FileName);
          mprintf(L"\n%s: ",St(MListDetails));
          uint SetCount=0;
          const wchar *Fmt=Arc.Format==RARFMT14 ? L"RAR 1.4":(Arc.Format==RARFMT15 ? L"RAR 4":L"RAR 5");
          mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", Fmt);
          if (Arc.Solid)
            mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListSolid));
          if (Arc.SFXSize>0)
            mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListSFX));
          if (Arc.Volume)
            if (Arc.Format==RARFMT50)
            {
              // RAR 5.0 archives store the volume number in main header,
              // so it is already available now.
              if (SetCount++ > 0)
                mprintf(L", ");
              mprintf(St(MVolumeNumber),Arc.VolNumber+1);
            }
            else
              mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListVolume));
          if (Arc.Protected)
            mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListRR));
          if (Arc.Locked)
            mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListLock));
          if (Arc.Encrypted)
            mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListEncHead));
          mprintf(L"\n");
        }

        wchar VolNumText[50];
        *VolNumText=0;
        while(Arc.ReadHeader()>0)
        {
          HEADER_TYPE HeaderType=Arc.GetHeaderType();
          if (HeaderType==HEAD_ENDARC)
          {
#ifndef SFX_MODULE
            // Only RAR 1.5 archives store the volume number in end record.
            if (Arc.EndArcHead.StoreVolNumber && Arc.Format==RARFMT15)
              swprintf(VolNumText,ASIZE(VolNumText),L"%.10ls %d",St(MListVolume),Arc.VolNumber+1);
#endif
            if (Technical && ShowService)
            {
              mprintf(L"\n%12ls: %ls",St(MListService),L"EOF");
              if (*VolNumText!=0)
                mprintf(L"\n%12ls: %ls",St(MListFlags),VolNumText);
              mprintf(L"\n");
            }
            break;
          }
          switch(HeaderType)
          {
            case HEAD_FILE:
              FileMatched=Cmd->IsProcessFile(Arc.FileHead)!=0;
              if (FileMatched)
              {
                ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare);
                if (!Arc.FileHead.SplitBefore)
                {
                  TotalUnpSize+=Arc.FileHead.UnpSize;
                  FileCount++;
                }
                TotalPackSize+=Arc.FileHead.PackSize;
              }
              break;
            case HEAD_SERVICE:
              if (FileMatched && !Bare)
              {
                if (Technical && ShowService)
                  ListFileHeader(Arc,Arc.SubHead,TitleShown,Verbose,true,false);
              }
              break;
          }
          Arc.SeekToNext();
        }
        if (!Bare && !Technical)
          if (TitleShown)
          {
            wchar UnpSizeText[20];
            itoa(TotalUnpSize,UnpSizeText);
        
            wchar PackSizeText[20];
            itoa(TotalPackSize,PackSizeText);
        
            if (Verbose)
            {
              mprintf(L"\n----------- ---------  -------- ----- -------- -----  --------  ----");
              mprintf(L"\n%21ls %9ls %3d%%  %-25ls %u",UnpSizeText,
                      PackSizeText,ToPercentUnlim(TotalPackSize,TotalUnpSize),
                      VolNumText,FileCount);
            }
            else
            {
              mprintf(L"\n----------- ---------  -------- -----  ----");
              mprintf(L"\n%21ls  %-14ls  %u",UnpSizeText,VolNumText,FileCount);
            }

            SumFileCount+=FileCount;
            SumUnpSize+=TotalUnpSize;
            SumPackSize+=TotalPackSize;
            mprintf(L"\n");
          }
          else
            mprintf(St(MListNoFiles));

        ArcCount++;

#ifndef NOVOLUME
        if (Cmd->VolSize!=0 && (Arc.FileHead.SplitAfter ||
            Arc.GetHeaderType()==HEAD_ENDARC && Arc.EndArcHead.NextVolume) &&
            MergeArchive(Arc,NULL,false,Cmd->Command[0]))
        {
          Arc.Seek(0,SEEK_SET);
        }
        else
#endif
          break;
      }
      else
      {
        if (Cmd->ArcNames.ItemsCount()<2 && !Bare)
          mprintf(St(MNotRAR),Arc.FileName);
        break;
      }
    }
  }

  if (ArcCount>1 && !Bare && !Technical)
  {
    wchar UnpSizeText[20],PackSizeText[20];
    itoa(SumUnpSize,UnpSizeText);
    itoa(SumPackSize,PackSizeText);

    if (Verbose)
      mprintf(L"%21ls %9ls %3d%% %26ls %u",UnpSizeText,PackSizeText,
              ToPercentUnlim(SumPackSize,SumUnpSize),L"",SumFileCount);
    else
      mprintf(L"%21ls %16s %lu",UnpSizeText,L"",SumFileCount);
  }
}
Example #3
0
File: dll.cpp Project: 1ldk/mpc-hc
int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestName,wchar *DestPathW,wchar *DestNameW)
{
  DataSet *Data=(DataSet *)hArcData;
  try
  {
    Data->Cmd.DllError=0;
    if (Data->OpenMode==RAR_OM_LIST || Data->OpenMode==RAR_OM_LIST_INCSPLIT ||
        Operation==RAR_SKIP && !Data->Arc.Solid)
    {
      if (Data->Arc.Volume && Data->Arc.GetHeaderType()==HEAD_FILE &&
          Data->Arc.FileHead.SplitAfter)
        if (MergeArchive(Data->Arc,NULL,false,'L'))
        {
          Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
          return ERAR_SUCCESS;
        }
        else
          return ERAR_EOPEN;
      Data->Arc.SeekToNext();
    }
    else
    {
      Data->Cmd.DllOpMode=Operation;

      *Data->Cmd.ExtrPath=0;
      *Data->Cmd.DllDestName=0;

      if (DestPath!=NULL)
      {
        char ExtrPathA[NM];
        strncpyz(ExtrPathA,DestPath,ASIZE(ExtrPathA)-2);
#ifdef _WIN_ALL
        // We must not apply OemToCharBuffA directly to DestPath,
        // because we do not know DestPath length and OemToCharBuffA
        // does not stop at 0.
        OemToCharA(ExtrPathA,ExtrPathA);
#endif
        CharToWide(ExtrPathA,Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath));
        AddEndSlash(Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath));
      }
      if (DestName!=NULL)
      {
        char DestNameA[NM];
        strncpyz(DestNameA,DestName,ASIZE(DestNameA)-2);
#ifdef _WIN_ALL
        // We must not apply OemToCharBuffA directly to DestName,
        // because we do not know DestName length and OemToCharBuffA
        // does not stop at 0.
        OemToCharA(DestNameA,DestNameA);
#endif
        CharToWide(DestNameA,Data->Cmd.DllDestName,ASIZE(Data->Cmd.DllDestName));
      }

      if (DestPathW!=NULL)
      {
        wcsncpy(Data->Cmd.ExtrPath,DestPathW,ASIZE(Data->Cmd.ExtrPath));
        AddEndSlash(Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath));
      }

      if (DestNameW!=NULL)
        wcsncpyz(Data->Cmd.DllDestName,DestNameW,ASIZE(Data->Cmd.DllDestName));

      wcscpy(Data->Cmd.Command,Operation==RAR_EXTRACT ? L"X":L"T");
      Data->Cmd.Test=Operation!=RAR_EXTRACT;
      bool Repeat=false;
      Data->Extract.ExtractCurrentFile(Data->Arc,Data->HeaderSize,Repeat);

      // Now we process extra file information if any.
      //
      // Archive can be closed if we process volumes, next volume is missing
      // and current one is already removed or deleted. So we need to check
      // if archive is still open to avoid calling file operations on
      // the invalid file handle. Some of our file operations like Seek()
      // process such invalid handle correctly, some not.
      while (Data->Arc.IsOpened() && Data->Arc.ReadHeader()!=0 && 
             Data->Arc.GetHeaderType()==HEAD_SERVICE)
      {
        Data->Extract.ExtractCurrentFile(Data->Arc,Data->HeaderSize,Repeat);
        Data->Arc.SeekToNext();
      }
      Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
    }
  }
  catch (std::bad_alloc&)
  {
    return ERAR_NO_MEMORY;
  }
  catch (RAR_EXIT ErrCode)
  {
    return Data->Cmd.DllError!=0 ? Data->Cmd.DllError : RarErrorToDll(ErrCode);
  }
  return Data->Cmd.DllError;
}
Example #4
0
File: dll.cpp Project: 1ldk/mpc-hc
int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D)
{
  DataSet *Data=(DataSet *)hArcData;
  try
  {
    if ((Data->HeaderSize=(int)Data->Arc.SearchBlock(HEAD_FILE))<=0)
    {
      if (Data->Arc.Volume && Data->Arc.GetHeaderType()==HEAD_ENDARC &&
          Data->Arc.EndArcHead.NextVolume)
        if (MergeArchive(Data->Arc,NULL,false,'L'))
        {
          Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
          return RARReadHeaderEx(hArcData,D);
        }
        else
          return ERAR_EOPEN;

      if (Data->Arc.BrokenHeader)
        return ERAR_BAD_DATA;

      // Might be necessary if RARSetPassword is still called instead of
      // open callback for RAR5 archives and if password is invalid.
      if (Data->Arc.FailedHeaderDecryption)
        return ERAR_BAD_PASSWORD;
      
      return ERAR_END_ARCHIVE;
    }
    FileHeader *hd=&Data->Arc.FileHead;
    if (Data->OpenMode==RAR_OM_LIST && hd->SplitBefore)
    {
      int Code=RARProcessFile(hArcData,RAR_SKIP,NULL,NULL);
      if (Code==0)
        return RARReadHeaderEx(hArcData,D);
      else
        return Code;
    }
    wcsncpy(D->ArcNameW,Data->Arc.FileName,ASIZE(D->ArcNameW));
    WideToChar(D->ArcNameW,D->ArcName,ASIZE(D->ArcName));

    wcsncpy(D->FileNameW,hd->FileName,ASIZE(D->FileNameW));
    WideToChar(D->FileNameW,D->FileName,ASIZE(D->FileName));
#ifdef _WIN_ALL
    CharToOemA(D->FileName,D->FileName);
#endif

    D->Flags=0;
    if (hd->SplitBefore)
      D->Flags|=RHDF_SPLITBEFORE;
    if (hd->SplitAfter)
      D->Flags|=RHDF_SPLITAFTER;
    if (hd->Encrypted)
      D->Flags|=RHDF_ENCRYPTED;
    if (hd->Solid)
      D->Flags|=RHDF_SOLID;
    if (hd->Dir)
      D->Flags|=RHDF_DIRECTORY;

    D->PackSize=uint(hd->PackSize & 0xffffffff);
    D->PackSizeHigh=uint(hd->PackSize>>32);
    D->UnpSize=uint(hd->UnpSize & 0xffffffff);
    D->UnpSizeHigh=uint(hd->UnpSize>>32);
    D->HostOS=hd->HSType==HSYS_WINDOWS ? HOST_WIN32:HOST_UNIX;
    if (Data->Arc.Format==RARFMT50)
      D->UnpVer=Data->Arc.FileHead.UnpVer==0 ? 50 : 200; // If it is not 0, just set it to something big.
    else
      D->UnpVer=Data->Arc.FileHead.UnpVer;
    D->FileCRC=hd->FileHash.CRC32;
    D->FileTime=hd->mtime.GetDos();
    D->Method=hd->Method+0x30;
    D->FileAttr=hd->FileAttr;
    D->CmtSize=0;
    D->CmtState=0;

    D->DictSize=uint(hd->WinSize/1024);

    switch (hd->FileHash.Type)
    {
      case HASH_RAR14:
      case HASH_CRC32:
        D->HashType=RAR_HASH_CRC32;
        break;
      case HASH_BLAKE2:
        D->HashType=RAR_HASH_BLAKE2;
        memcpy(D->Hash,hd->FileHash.Digest,BLAKE2_DIGEST_SIZE);
        break;
      default:
        D->HashType=RAR_HASH_NONE;
        break;
    }
    
  }
  catch (RAR_EXIT ErrCode)
  {
    return Data->Cmd.DllError!=0 ? Data->Cmd.DllError : RarErrorToDll(ErrCode);
  }
  return ERAR_SUCCESS;
}
Example #5
0
int ComprDataIO::UnpRead(byte *Addr,size_t Count)
{
  int RetCode=0,TotalRead=0;
  byte *ReadAddr;
  ReadAddr=Addr;
  while (Count > 0)
  {
    Archive *SrcArc=(Archive *)SrcFile;

    size_t ReadSize=((int64)Count>UnpPackedSize) ? (size_t)UnpPackedSize:Count;
    if (UnpackFromMemory)
    {
      memcpy(Addr,UnpackFromMemoryAddr,UnpackFromMemorySize);
      RetCode=(int)UnpackFromMemorySize;
      UnpackFromMemorySize=0;
    }
    else
    {
      if (!SrcFile->IsOpened())
        return(-1);
      RetCode=SrcFile->Read(ReadAddr,ReadSize);
      FileHeader *hd=SubHead!=NULL ? SubHead:&SrcArc->NewLhd;
      if (hd->Flags & LHD_SPLIT_AFTER)
        PackedCRC=CRC(PackedCRC,ReadAddr,RetCode);
    }
    CurUnpRead+=RetCode;
    TotalRead+=RetCode;
#ifndef NOVOLUME
    // These variable are not used in NOVOLUME mode, so it is better
    // to exclude commands below to avoid compiler warnings.
    ReadAddr+=RetCode;
    Count-=RetCode;
#endif
    UnpPackedSize-=RetCode;
    if (UnpPackedSize == 0 && UnpVolume)
    {
#ifndef NOVOLUME
      if (!MergeArchive(*SrcArc,this,true,CurrentCommand))
#endif
      {
        NextVolumeMissing=true;
        return(-1);
      }
    }
    else
      break;
  }
  Archive *SrcArc=(Archive *)SrcFile;
  if (SrcArc!=NULL)
    ShowUnpRead(SrcArc->CurBlockPos+CurUnpRead,UnpArcSize);
  if (RetCode!=-1)
  {
    RetCode=TotalRead;
#ifndef NOCRYPT
    if (Decryption)
#ifndef SFX_MODULE
      if (Decryption<20)
        Decrypt.Crypt(Addr,RetCode,(Decryption==15) ? NEW_CRYPT : OLD_DECODE);
      else
        if (Decryption==20)
          for (int I=0;I<RetCode;I+=16)
            Decrypt.DecryptBlock20(&Addr[I]);
        else
#endif
        {
          int CryptSize=(RetCode & 0xf)==0 ? RetCode:((RetCode & ~0xf)+16);
          Decrypt.DecryptBlock(Addr,CryptSize);
        }
#endif
  }
  Wait();
  return(RetCode);
}
Example #6
0
/*
* Inspired from llink (by lundman) which in turn was loosely based on
* patches from XBMC (by elupus).
*/
int ComprDataIO::UnpReadSeek(char *file, uint64_t offset)
{
	uint64_t OldPos;
	uint64_t HeadSize;
	Archive *SrcArc = (Archive *)SrcFile;

	if (!SrcFile->IsOpened()) {
		return(-1);
	}

	HeadSize = SrcArc->Tell() - CurUnpRead;

#ifdef DEBUG
	printf("\n%s: Seek begin, HeadSize=%d\n", __func__, HeadSize);
	printf("%s: offset=%llu, ", __func__, offset);
	printf("readpos=%llu, ", ReadPos);
	printf("diff=%llu, ", offset - ReadPos);
	printf("tell=%llu, ", SrcArc->Tell());
	printf("CurUnpRead=%llu\n", CurUnpRead);
#endif

	/* Dumb backward seek, reset to beginning and forward seek */
	if (offset < ReadPos) {
#ifdef DEBUG
		printf("Seeking backwards\n");
#endif
		SrcArc->Close();
		SrcArc->Open(SrcArc->FirstVolumeName, SrcArc->FirstVolumeNameW);

		if (SrcArc->GetHeaderType() != FILE_HEAD)
			SrcArc->SearchBlock(FILE_HEAD);
		do {
#ifdef DEBUG
			printf("File: %s, ", SrcArc->NewLhd.FileName);
			printf("packsize=%llu, ", SrcArc->NewLhd.FullPackSize);
			printf("method=%x\n", SrcArc->NewLhd.Method);
#endif
			/* XXX: fix unicode */
			if (_stricmp(SrcArc->NewLhd.FileName, file) == 0){
				SVP_LogMsg3(" ComprDataIO::UnpReadSeek match %s %s | %s ", file , SrcArc->FileName,  CStringA(SrcArc->FileNameW));
				//strcpy(SrcArc->FileName ,  CStringA(SrcArc->FileNameW));
				break;
			}
			//if (strcasecmp(SrcArc->NewLhd.FileName, file) == 0)
			//	break;
		} while (SrcArc->SearchBlock(FILE_HEAD));

		UnpVolume = true;
		SrcArc->Seek(SrcArc->CurBlockPos, SEEK_CUR);
		SrcArc->ReadHeader();

		CurUnpRead = ReadPos = 0;
	}

#ifdef DEBUG
	printf("%s: offset=%llu, ", __func__, offset);
	printf("readpos=%llu, ", ReadPos);
	printf("diff=%llu, ", offset - ReadPos);
	printf("tell=%llu, ", SrcArc->Tell());
	printf("CurUnpRead=%llu\n", CurUnpRead);
#endif

	/* Forward seek to correct volume */
	if (offset > ReadPos + SrcArc->NewLhd.FullPackSize - CurUnpRead) {
#ifdef DEBUG
		printf("%s: Seeking forward, ", __func__);
		printf("FullPackSize=%llu\n", SrcArc->NewLhd.FullPackSize);
#endif
		OldPos = ReadPos;
		ReadPos -= CurUnpRead;

		for (;;) {
			ReadPos += SrcArc->NewLhd.FullPackSize;

#ifdef DEBUG
			printf("%s: New readpos=%llu, ", __func__, ReadPos);
			printf("offset=%llu\n", offset);
#endif
			if (ReadPos >= offset) {	
				ReadPos -= SrcArc->NewLhd.FullPackSize;
#ifdef DEBUG
				printf("%s: offset reached\n", __func__);
#endif
				break;
			}
			if (!MergeArchive(*SrcArc, this, true, CurrentCommand)) {
				NextVolumeMissing = true;
#ifdef DEBUG
				printf("%s: volume missing\n", __func__);
#endif
				return (-1);
			}
		}
	}
	else {
		ReadPos -= CurUnpRead;
	}

#ifdef DEBUG
	printf("%s: offset=%llu, ", __func__, offset);
	printf("readpos=%llu, ", ReadPos);
	printf("diff=%llu, ", offset - ReadPos);
	printf("tell=%llu, ", SrcArc->Tell());
	printf("CurUnpRead=%llu\n", CurUnpRead);
#endif

	/* Absolute number of bytes read */
	CurUnpRead = offset - ReadPos;
	ReadPos += CurUnpRead;
	UnpPackedSize = SrcArc->NewLhd.FullPackSize - CurUnpRead;

	SrcFile->Seek(CurUnpRead + HeadSize, SEEK_SET);

#ifdef DEBUG
	printf("%s: offset=%llu, ", __func__, offset);
	printf("readpos=%llu, ", ReadPos);
	printf("diff=%llu, ", offset - ReadPos);
	printf("tell=%llu, ", SrcArc->Tell());
	printf("CurUnpRead=%llu, ", CurUnpRead);
	printf("UnpPackedSize=%llu\n", UnpPackedSize);
	printf("Seek complete\n\n");
#endif

	return (0);
}
Example #7
0
int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D)
{
  DataSet *Data=(DataSet *)hArcData;
  //try
  //{
    if ((Data->HeaderSize=(int)Data->Arc.SearchBlock(FILE_HEAD))<=0)
    {
      if (Data->Arc.Volume && Data->Arc.GetHeaderType()==ENDARC_HEAD &&
          (Data->Arc.EndArcHead.Flags & EARC_NEXT_VOLUME))
        if (MergeArchive(Data->Arc,NULL,false,'L'))
        {
          Data->Extract.SignatureFound=false;
          Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
          return(RARReadHeaderEx(hArcData,D));
        }
        else
          return(ERAR_EOPEN);
      return(Data->Arc.BrokenFileHeader ? ERAR_BAD_DATA:ERAR_END_ARCHIVE);
    }
    if (Data->OpenMode==RAR_OM_LIST && (Data->Arc.NewLhd.Flags & LHD_SPLIT_BEFORE))
    {
      int Code=RARProcessFile(hArcData,RAR_SKIP,NULL,NULL);
      if (Code==0)
        return(RARReadHeaderEx(hArcData,D));
      else
        return(Code);
    }
    strncpyz(D->ArcName,Data->Arc.FileName,ASIZE(D->ArcName));
    if (*Data->Arc.FileNameW)
      strncpyw(D->ArcNameW,Data->Arc.FileNameW,sizeof(D->ArcNameW));
    else
      CharToWide(Data->Arc.FileName,D->ArcNameW);
    strncpyz(D->FileName,Data->Arc.NewLhd.FileName,ASIZE(D->FileName));
    if (*Data->Arc.NewLhd.FileNameW)
      strncpyw(D->FileNameW,Data->Arc.NewLhd.FileNameW,sizeof(D->FileNameW));
    else
    {
#ifdef _WIN_32
      char AnsiName[NM];
      OemToChar(Data->Arc.NewLhd.FileName,AnsiName);
      if (!CharToWide(AnsiName,D->FileNameW,ASIZE(D->FileNameW)))
        *D->FileNameW=0;
#else
      if (!CharToWide(Data->Arc.NewLhd.FileName,D->FileNameW,ASIZE(D->FileNameW)))
        *D->FileNameW=0;
#endif
    }
    D->Flags=Data->Arc.NewLhd.Flags;
    D->PackSize=Data->Arc.NewLhd.PackSize;
    D->PackSizeHigh=Data->Arc.NewLhd.HighPackSize;
    D->UnpSize=Data->Arc.NewLhd.UnpSize;
    D->UnpSizeHigh=Data->Arc.NewLhd.HighUnpSize;
    D->HostOS=Data->Arc.NewLhd.HostOS;
    D->FileCRC=Data->Arc.NewLhd.FileCRC;
    D->FileTime=Data->Arc.NewLhd.FileTime;
    D->UnpVer=Data->Arc.NewLhd.UnpVer;
    D->Method=Data->Arc.NewLhd.Method;
    D->FileAttr=Data->Arc.NewLhd.FileAttr;
    D->CmtSize=0;
    D->CmtState=0;
//  }
 // catch (int ErrCode)
  //{
  //  return(RarErrorToDll(ErrCode));
 // }
  return(0);
}
Example #8
0
int ComprDataIO::UnpRead(unsigned char *Addr,unsigned int Count)
{
  int RetCode=0,TotalRead=0;
  unsigned char *ReadAddr;
  ReadAddr=Addr;
  while (Count > 0)
  {
    Archive *SrcArc=(Archive *)SrcFile;

    unsigned int ReadSize=(Count>UnpPackedSize) ? int64to32(UnpPackedSize):Count;
    if (UnpackFromMemory)
    {
      memcpy(Addr,UnpackFromMemoryAddr,UnpackFromMemorySize);
      RetCode=UnpackFromMemorySize;
      UnpackFromMemorySize=0;
    }
    else
    {
      if (!SrcFile->IsOpened())
        return(-1);
      RetCode=SrcFile->Read(ReadAddr,ReadSize);
      FileHeader *hd=SubHead!=NULL ? SubHead:&SrcArc->NewLhd;
      if (hd->Flags & LHD_SPLIT_AFTER)
        PackedCRC=CRC(PackedCRC,ReadAddr,ReadSize);
    }
    CurUnpRead+=RetCode;
    ReadAddr+=RetCode;
    TotalRead+=RetCode;
    Count-=RetCode;
    UnpPackedSize-=RetCode;
    if (UnpPackedSize == 0 && UnpVolume)
    {
#ifndef NOVOLUME
      if (!MergeArchive(*SrcArc,this,true,CurrentCommand))
#endif
      {
        NextVolumeMissing=true;
        return(-1);
      }
    }
    else
      break;
  }
  Archive *SrcArc=(Archive *)SrcFile;
  if (SrcArc!=NULL)
    ShowUnpRead(SrcArc->CurBlockPos+CurUnpRead,UnpArcSize);
  if (RetCode!=-1)
  {
    RetCode=TotalRead;
#ifndef NOCRYPT
    if (Decryption)
#ifndef SFX_MODULE
      if (Decryption<20)
        Decrypt.Crypt(Addr,RetCode,(Decryption==15) ? NEW_CRYPT : OLD_DECODE);
      else
        if (Decryption==20)
          for (unsigned int I=0;I<RetCode;I+=16)
            Decrypt.DecryptBlock20(&Addr[I]);
        else
#endif
        {
          int CryptSize=(RetCode & 0xf)==0 ? RetCode:((RetCode & ~0xf)+16);
          Decrypt.DecryptBlock(Addr,CryptSize);
        }
#endif
  }
  Wait();
  return(RetCode);
}
Example #9
0
int ComprDataIO::UnpRead(byte *Addr,uint Count)
{
  int RetCode=0,TotalRead=0;
  byte *ReadAddr;
  ReadAddr=Addr;
  while (Count > 0)
  {
    Archive *SrcArc=(Archive *)SrcFile;

    uint ReadSize=(Count>UnpPackedSize) ? int64to32(UnpPackedSize):Count;
    if (UnpackFromMemory)
    {
      memcpy(Addr,UnpackFromMemoryAddr,UnpackFromMemorySize);
      RetCode=UnpackFromMemorySize;
      UnpackFromMemorySize=0;
    }
    else
    {
      bool bRead = true;
      if (!SrcFile->IsOpened())
      {
        NextVolumeMissing = true;
        return(-1);
      }
      if (UnpackToMemory)
        if (hSeek->Wait(1)) // we are seeking
        {
          if (m_iSeekTo > CurUnpStart+SrcArc->NewLhd.FullPackSize) // need to seek outside this block
          {
            TotalRead += (int)(SrcArc->NextBlockPos-SrcFile->Tell());
            CurUnpRead=CurUnpStart+SrcArc->NewLhd.FullPackSize;
            UnpPackedSize=0;
            RetCode = 0;
            bRead = false;
          }
          else
          {
            Int64 iStartOfFile = SrcArc->NextBlockPos-SrcArc->NewLhd.FullPackSize;
            m_iStartOfBuffer = CurUnpStart;
            Int64 iSeekTo=m_iSeekTo-CurUnpStart<MAXWINMEMSIZE/2?iStartOfFile:iStartOfFile+m_iSeekTo-CurUnpStart-MAXWINMEMSIZE/2;
            if (iSeekTo == iStartOfFile) // front
            {
              if (CurUnpStart+MAXWINMEMSIZE>SrcArc->NewLhd.FullUnpSize)
              {
                m_iSeekTo=iStartOfFile;
                UnpPackedSize = SrcArc->NewLhd.FullPackSize;
              }
              else 
              {
                m_iSeekTo=MAXWINMEMSIZE-(m_iSeekTo-CurUnpStart);
                UnpPackedSize = SrcArc->NewLhd.FullPackSize - (m_iStartOfBuffer - CurUnpStart);
              }
            }
            else
            {
              m_iStartOfBuffer = m_iSeekTo-MAXWINMEMSIZE/2; // front
              if (m_iSeekTo+MAXWINMEMSIZE/2>SrcArc->NewLhd.FullUnpSize)
              {
                iSeekTo = iStartOfFile+SrcArc->NewLhd.FullPackSize-MAXWINMEMSIZE;
                m_iStartOfBuffer = CurUnpStart+SrcArc->NewLhd.FullPackSize-MAXWINMEMSIZE;
                m_iSeekTo = MAXWINMEMSIZE-(m_iSeekTo-m_iStartOfBuffer);
                UnpPackedSize = MAXWINMEMSIZE;
              }
              else 
              {
                m_iSeekTo=MAXWINMEMSIZE/2;
                UnpPackedSize = SrcArc->NewLhd.FullPackSize - (m_iStartOfBuffer - CurUnpStart);
              }  
            }

            SrcFile->Seek(iSeekTo,SEEK_SET);
            TotalRead = 0;
            CurUnpRead = CurUnpStart + iSeekTo - iStartOfFile;
            CurUnpWrite = SrcFile->Tell() - iStartOfFile + CurUnpStart;
            
            hSeek->Reset();
            hSeekDone->Signal();
          }
        }
      if (bRead)
      {
        ReadSize=(Count>UnpPackedSize) ? int64to32(UnpPackedSize):Count;
        RetCode=SrcFile->Read(ReadAddr,ReadSize);
        FileHeader *hd=SubHead!=NULL ? SubHead:&SrcArc->NewLhd;
        if (hd->Flags & LHD_SPLIT_AFTER)
        {
          PackedCRC=CRC(PackedCRC,ReadAddr,ReadSize);
        }
      }
    }
    CurUnpRead+=RetCode;
    ReadAddr+=RetCode;
    TotalRead+=RetCode;
    Count-=RetCode;
    UnpPackedSize-=RetCode;
    if (UnpPackedSize == 0 && UnpVolume)
    {
#ifndef NOVOLUME
      if (!MergeArchive(*SrcArc,this,true,CurrentCommand))
#endif
      {
        NextVolumeMissing=true;
        return(-1);
      }
      CurUnpStart = CurUnpRead;
      /*if (m_pDlgProgress)
      {
        CURL url(SrcArc->FileName);
        m_pDlgProgress->SetLine(0,url.GetWithoutUserDetails()); // update currently extracted rar file
        m_pDlgProgress->Progress();
      }*/
    }
    else
      break;
  }
  Archive *SrcArc=(Archive *)SrcFile;
  if (SrcArc!=NULL)
    ShowUnpRead(SrcArc->CurBlockPos+CurUnpRead,UnpArcSize);
  if (RetCode!=-1)
  {
    RetCode=TotalRead;
#ifndef NOCRYPT
    if (Decryption)
    {
#ifndef SFX_MODULE
      if (Decryption<20)
        Decrypt.Crypt(Addr,RetCode,(Decryption==15) ? NEW_CRYPT : OLD_DECODE);
      else if (Decryption==20)
        for (int I=0;I<RetCode;I+=16)
          Decrypt.DecryptBlock20(&Addr[I]);
      else
#endif
      {
        int CryptSize=(RetCode & 0xf)==0 ? RetCode:((RetCode & ~0xf)+16);
        Decrypt.DecryptBlock(Addr,CryptSize);
      }
    }
#endif
  }
  Wait();
  return(RetCode);
}
Example #10
0
bool CmdExtract::ExtractCurrentFile(CommandData *Cmd,Archive &Arc,size_t HeaderSize,bool &Repeat)
{
  wchar Command=Cmd->Command[0];
  if (HeaderSize==0)
    if (DataIO.UnpVolume)
    {
#ifdef NOVOLUME
      return false;
#else
      if (!MergeArchive(Arc,&DataIO,false,Command))
      {
        ErrHandler.SetErrorCode(RARX_WARNING);
        return false;
      }
#endif
    }
    else
      return false;
  HEADER_TYPE HeaderType=Arc.GetHeaderType();
  if (HeaderType!=HEAD_FILE)
  {
#ifndef SFX_MODULE
    if (HeaderType==HEAD3_OLDSERVICE && PrevExtracted)
      SetExtraInfo20(Cmd,Arc,DestFileName);
#endif
    if (HeaderType==HEAD_SERVICE && PrevExtracted)
      SetExtraInfo(Cmd,Arc,DestFileName);
    if (HeaderType==HEAD_ENDARC)
      if (Arc.EndArcHead.NextVolume)
      {
#ifndef NOVOLUME
        if (!MergeArchive(Arc,&DataIO,false,Command))
        {
          ErrHandler.SetErrorCode(RARX_WARNING);
          return false;
        }
#endif
        Arc.Seek(Arc.CurBlockPos,SEEK_SET);
        return true;
      }
      else
        return false;
    Arc.SeekToNext();
    return true;
  }
  PrevExtracted=false;

  if (!Cmd->Recurse && MatchedArgs>=Cmd->FileArgs.ItemsCount() && AllMatchesExact)
    return false;

  int MatchType=MATCH_WILDSUBPATH;

  bool EqualNames=false;
  int MatchNumber=Cmd->IsProcessFile(Arc.FileHead,&EqualNames,MatchType);
  bool ExactMatch=MatchNumber!=0;
#ifndef SFX_MODULE
  if (Cmd->ExclPath==EXCL_BASEPATH)
  {
    *Cmd->ArcPath=0;
    if (ExactMatch)
    {
      Cmd->FileArgs.Rewind();
      if (Cmd->FileArgs.GetString(Cmd->ArcPath,ASIZE(Cmd->ArcPath),MatchNumber-1))
        *PointToName(Cmd->ArcPath)=0;
    }
  }
#endif
  if (ExactMatch && !EqualNames)
    AllMatchesExact=false;

  Arc.ConvertAttributes();

#if !defined(SFX_MODULE) && !defined(RARDLL)
  if (Arc.FileHead.SplitBefore && FirstFile)
  {
    wchar CurVolName[NM];
    wcsncpyz(CurVolName,ArcName,ASIZE(CurVolName));
    VolNameToFirstName(ArcName,ArcName,Arc.NewNumbering);

    if (wcsicomp(ArcName,CurVolName)!=0 && FileExist(ArcName))
    {
      // If first volume name does not match the current name and if such
      // volume name really exists, let's unpack from this first volume.
      Repeat=true;
      return false;
    }
#ifndef RARDLL
    if (!ReconstructDone)
    {
      ReconstructDone=true;

      if (RecVolumesRestore(Cmd,Arc.FileName,true))
      {
        Repeat=true;
        return false;
      }
    }
#endif
    wcsncpyz(ArcName,CurVolName,ASIZE(ArcName));
  }
#endif

  wchar ArcFileName[NM];
  ConvertPath(Arc.FileHead.FileName,ArcFileName);

  if (Arc.FileHead.Version)
  {
    if (Cmd->VersionControl!=1 && !EqualNames)
    {
      if (Cmd->VersionControl==0)
        ExactMatch=false;
      int Version=ParseVersionFileName(ArcFileName,false);
      if (Cmd->VersionControl-1==Version)
        ParseVersionFileName(ArcFileName,true);
      else
        ExactMatch=false;
    }
  }
  else
    if (!Arc.IsArcDir() && Cmd->VersionControl>1)
      ExactMatch=false;

  DataIO.UnpVolume=Arc.FileHead.SplitAfter;
  DataIO.NextVolumeMissing=false;

  Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET);

  bool ExtrFile=false;
  bool SkipSolid=false;

#ifndef SFX_MODULE
  if (FirstFile && (ExactMatch || Arc.Solid) && Arc.FileHead.SplitBefore)
  {
    if (ExactMatch)
    {
      Log(Arc.FileName,St(MUnpCannotMerge),ArcFileName);
#ifdef RARDLL
      Cmd->DllError=ERAR_BAD_DATA;
#endif
      ErrHandler.SetErrorCode(RARX_OPEN);
    }
    ExactMatch=false;
  }

  FirstFile=false;
#endif

  if (ExactMatch || (SkipSolid=Arc.Solid)!=0)
  {

    ExtrPrepareName(Cmd,Arc,ArcFileName,DestFileName,ASIZE(DestFileName));

    // DestFileName can be set empty in case of excessive -ap switch.
    ExtrFile=!SkipSolid && *DestFileName!=0 && !Arc.FileHead.SplitBefore;

    if ((Cmd->FreshFiles || Cmd->UpdateFiles) && (Command=='E' || Command=='X'))
    {
      FindData FD;
      if (FindFile::FastFind(DestFileName,&FD))
      {
        if (FD.mtime >= Arc.FileHead.mtime)
        {
          // If directory already exists and its modification time is newer 
          // than start of extraction, it is likely it was created 
          // when creating a path to one of already extracted items. 
          // In such case we'll better update its time even if archived 
          // directory is older.

          if (!FD.IsDir || FD.mtime<StartTime)
            ExtrFile=false;
        }
      }
      else
        if (Cmd->FreshFiles)
          ExtrFile=false;
    }

    if (Arc.FileHead.Encrypted)
    {
#ifdef RARDLL
      if (!ExtrDllGetPassword(Cmd))
        return false;
#else
      if (!ExtrGetPassword(Cmd,Arc,ArcFileName))
      {
        PasswordCancelled=true;
        return false;
      }
#endif
      // Skip only the current encrypted file if empty password is entered.
      if (!Password.IsSet())
      {
        ErrHandler.SetErrorCode(RARX_WARNING);
#ifdef RARDLL
        Cmd->DllError=ERAR_MISSING_PASSWORD;
#endif
        ExtrFile=false;
      }
    }

#ifdef RARDLL
    if (*Cmd->DllDestName!=0)
    {
      wcsncpyz(DestFileName,Cmd->DllDestName,ASIZE(DestFileName));

//      Do we need this code?
//      if (Cmd->DllOpMode!=RAR_EXTRACT)
//        ExtrFile=false;
    }
#endif

    if (!CheckUnpVer(Arc,ArcFileName))
    {
      ExtrFile=false;
      ErrHandler.SetErrorCode(RARX_WARNING);
#ifdef RARDLL
      Cmd->DllError=ERAR_UNKNOWN_FORMAT;
#endif
    }

    File CurFile;

    bool LinkEntry=Arc.FileHead.RedirType!=FSREDIR_NONE;
    if (LinkEntry && Arc.FileHead.RedirType!=FSREDIR_FILECOPY)
    {
      if (ExtrFile && Command!='P' && !Cmd->Test)
      {
        // Overwrite prompt for symbolic and hard links.
        bool UserReject=false;
        if (FileExist(DestFileName) && !UserReject)
          FileCreate(Cmd,NULL,DestFileName,ASIZE(DestFileName),Cmd->Overwrite,&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime);
        if (UserReject)
          ExtrFile=false;
      }
    }
    else
      if (Arc.IsArcDir())
      {
        if (!ExtrFile || Command=='P' || Command=='I' || Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
          return true;
        TotalFileCount++;
        ExtrCreateDir(Cmd,Arc,ArcFileName);
        return true;
      }
      else
        if (ExtrFile) // Create files and file copies (FSREDIR_FILECOPY).
          ExtrFile=ExtrCreateFile(Cmd,Arc,CurFile);

    if (!ExtrFile && Arc.Solid)
    {
      SkipSolid=true;
      ExtrFile=true;

    }
    if (ExtrFile)
    {
      bool TestMode=Cmd->Test || SkipSolid; // Unpack to memory, not to disk.

      if (!SkipSolid)
      {
        if (!TestMode && Command!='P' && CurFile.IsDevice())
        {
          Log(Arc.FileName,St(MInvalidName),DestFileName);
          ErrHandler.WriteError(Arc.FileName,DestFileName);
        }
        TotalFileCount++;
      }
      FileCount++;
#ifndef GUI
      if (Command!='I')
        if (SkipSolid)
          mprintf(St(MExtrSkipFile),ArcFileName);
        else
          switch(Cmd->Test ? 'T':Command) // "Test" can be also enabled by -t switch.
          {
            case 'T':
              mprintf(St(MExtrTestFile),ArcFileName);
              break;
#ifndef SFX_MODULE
            case 'P':
              mprintf(St(MExtrPrinting),ArcFileName);
              break;
#endif
            case 'X':
            case 'E':
              mprintf(St(MExtrFile),DestFileName);
              break;
          }
      if (!Cmd->DisablePercentage)
        mprintf(L"     ");
#endif

      SecPassword FilePassword=Password;
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
      ConvertDosPassword(Arc,FilePassword);
#endif

      byte PswCheck[SIZE_PSWCHECK];
      DataIO.SetEncryption(false,Arc.FileHead.CryptMethod,&FilePassword,
             Arc.FileHead.SaltSet ? Arc.FileHead.Salt:NULL,
             Arc.FileHead.InitV,Arc.FileHead.Lg2Count,
             PswCheck,Arc.FileHead.HashKey);
      bool WrongPassword=false;

      // If header is damaged, we cannot rely on password check value,
      // because it can be damaged too.
      if (Arc.FileHead.Encrypted && Arc.FileHead.UsePswCheck &&
          memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0 &&
          !Arc.BrokenHeader)
      {
        Log(Arc.FileName,St(MWrongPassword));
        ErrHandler.SetErrorCode(RARX_BADPWD);
        WrongPassword=true;
      }
      DataIO.CurUnpRead=0;
      DataIO.CurUnpWrite=0;
      DataIO.UnpHash.Init(Arc.FileHead.FileHash.Type,Cmd->Threads);
      DataIO.PackedDataHash.Init(Arc.FileHead.FileHash.Type,Cmd->Threads);
      DataIO.SetPackedSizeToRead(Arc.FileHead.PackSize);
      DataIO.SetFiles(&Arc,&CurFile);
      DataIO.SetTestMode(TestMode);
      DataIO.SetSkipUnpCRC(SkipSolid);
      if (!TestMode && !WrongPassword && !Arc.BrokenHeader &&
          (Arc.FileHead.PackSize<<11)>Arc.FileHead.UnpSize &&
          (Arc.FileHead.UnpSize<100000000 || Arc.FileLength()>Arc.FileHead.PackSize))
        CurFile.Prealloc(Arc.FileHead.UnpSize);

      CurFile.SetAllowDelete(!Cmd->KeepBroken);

      bool FileCreateMode=!TestMode && !SkipSolid && Command!='P';
      bool ShowChecksum=true; // Display checksum verification result.

      bool LinkSuccess=true; // Assume success for test mode.
      if (LinkEntry)
      {
        FILE_SYSTEM_REDIRECT Type=Arc.FileHead.RedirType;

        if (Type==FSREDIR_HARDLINK || Type==FSREDIR_FILECOPY)
        {
          wchar NameExisting[NM];
          ExtrPrepareName(Cmd,Arc,Arc.FileHead.RedirName,NameExisting,ASIZE(NameExisting));
          if (FileCreateMode && *NameExisting!=0) // *NameExisting can be 0 in case of excessive -ap switch.
            if (Type==FSREDIR_HARDLINK)
              LinkSuccess=ExtractHardlink(DestFileName,NameExisting,ASIZE(NameExisting));
            else
              LinkSuccess=ExtractFileCopy(Cmd,CurFile,Arc.FileName,DestFileName,NameExisting,ASIZE(NameExisting));
        }
        else
          if (Type==FSREDIR_UNIXSYMLINK || Type==FSREDIR_WINSYMLINK || Type==FSREDIR_JUNCTION)
          {
            if (FileCreateMode)
              LinkSuccess=ExtractSymlink(Cmd,DataIO,Arc,DestFileName);
          }
          else
          {
#ifndef SFX_MODULE
            Log(Arc.FileName,St(MUnknownExtra),DestFileName);
#endif
            LinkSuccess=false;
          }
          
          if (!LinkSuccess || Arc.Format==RARFMT15 && !FileCreateMode)
          {
            // RAR 5.x links have a valid data checksum even in case of
            // failure, because they do not store any data.
            // We do not want to display "OK" in this case.
            // For 4.x symlinks we verify the checksum only when extracting,
            // but not when testing an archive.
            ShowChecksum=false;
          }
          PrevExtracted=FileCreateMode && LinkSuccess;
      }
      else
        if (!Arc.FileHead.SplitBefore && !WrongPassword)
          if (Arc.FileHead.Method==0)
            UnstoreFile(DataIO,Arc.FileHead.UnpSize);
          else
          {
            Unp->Init(Arc.FileHead.WinSize,Arc.FileHead.Solid);
            Unp->SetDestSize(Arc.FileHead.UnpSize);
#ifndef SFX_MODULE
            if (Arc.Format!=RARFMT50 && Arc.FileHead.UnpVer<=15)
              Unp->DoUnpack(15,FileCount>1 && Arc.Solid);
            else
#endif
              Unp->DoUnpack(Arc.FileHead.UnpVer,Arc.FileHead.Solid);
          }

      Arc.SeekToNext();

      bool ValidCRC=DataIO.UnpHash.Cmp(&Arc.FileHead.FileHash,Arc.FileHead.UseHashKey ? Arc.FileHead.HashKey:NULL);

      // We set AnySolidDataUnpackedWell to true if we found at least one
      // valid non-zero solid file in preceding solid stream. If it is true
      // and if current encrypted file is broken, we do not need to hint
      // about a wrong password and can report CRC error only.
      if (!Arc.FileHead.Solid)
        AnySolidDataUnpackedWell=false; // Reset the flag, because non-solid file is found.
      else
        if (Arc.FileHead.Method!=0 && Arc.FileHead.UnpSize>0 && ValidCRC)
          AnySolidDataUnpackedWell=true;
 
      bool BrokenFile=false;
      
      // Checksum is not calculated in skip solid mode for performance reason.
      if (!SkipSolid && ShowChecksum)
      {
        if (!WrongPassword && ValidCRC)
        {
#ifndef GUI
          if (Command!='P' && Command!='I')
            mprintf(L"%s%s ",Cmd->DisablePercentage ? L" ":L"\b\b\b\b\b ",
              Arc.FileHead.FileHash.Type==HASH_NONE ? L"  ?":St(MOk));
#endif
        }
        else
        {
          if (!WrongPassword)
            if (Arc.FileHead.Encrypted && (!Arc.FileHead.UsePswCheck || 
                Arc.BrokenHeader) && !AnySolidDataUnpackedWell)
            {
              Log(Arc.FileName,St(MEncrBadCRC),ArcFileName);
            }
            else
            {
              Log(Arc.FileName,St(MCRCFailed),ArcFileName);
            }
          BrokenFile=true;
          ErrHandler.SetErrorCode(RARX_CRC);
#ifdef RARDLL
          // If we already have ERAR_EOPEN as result of missing volume,
          // we should not replace it with less precise ERAR_BAD_DATA.
          if (Cmd->DllError!=ERAR_EOPEN)
            Cmd->DllError=ERAR_BAD_DATA;
#endif
        }
      }
#ifndef GUI
      else
        mprintf(L"\b\b\b\b\b     ");
#endif

      if (!TestMode && !WrongPassword && (Command=='X' || Command=='E') &&
          (!LinkEntry || Arc.FileHead.RedirType==FSREDIR_FILECOPY && LinkSuccess) && 
          (!BrokenFile || Cmd->KeepBroken))
      {
        // We could preallocate more space that really written to broken file.
        if (BrokenFile)
          CurFile.Truncate();

#if defined(_WIN_ALL) || defined(_EMX)
        if (Cmd->ClearArc)
          Arc.FileHead.FileAttr&=~FILE_ATTRIBUTE_ARCHIVE;
#endif


        CurFile.SetOpenFileTime(
          Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime,
          Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.FileHead.ctime,
          Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime);
        CurFile.Close();
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
        if (Cmd->SetCompressedAttr &&
            (Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0)
          SetFileCompression(CurFile.FileName,true);
#endif
#ifdef _UNIX
        if (Cmd->ProcessOwners && Arc.Format==RARFMT50 && Arc.FileHead.UnixOwnerSet)
          SetUnixOwner(Arc,CurFile.FileName);
#endif

        CurFile.SetCloseFileTime(
          Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime,
          Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime);
        if (!Cmd->IgnoreGeneralAttr)
          SetFileAttr(CurFile.FileName,Arc.FileHead.FileAttr);
        PrevExtracted=true;
      }
    }
  }
  if (ExactMatch)
    MatchedArgs++;
  if (DataIO.NextVolumeMissing)
    return false;
  if (!ExtrFile)
    if (!Arc.Solid)
      Arc.SeekToNext();
    else
      if (!SkipSolid)
        return false;
  return true;
}
Example #11
0
int ComprDataIO::UnpRead(byte *Addr,size_t Count)
{
#ifndef RAR_NOCRYPT
  // In case of encryption we need to align read size to encryption 
  // block size. We can do it by simple masking, because unpack read code
  // always reads more than CRYPT_BLOCK_SIZE, so we do not risk to make it 0.
  if (Decryption)
    Count&=~CRYPT_BLOCK_MASK;
#endif
  int ReadSize=0,TotalRead=0;
  byte *ReadAddr;
  ReadAddr=Addr;
  while (Count > 0)
  {
    Archive *SrcArc=(Archive *)SrcFile;

    if (UnpackFromMemory)
    {
      memcpy(Addr,UnpackFromMemoryAddr,UnpackFromMemorySize);
      ReadSize=(int)UnpackFromMemorySize;
      UnpackFromMemorySize=0;
    }
    else
    {
      size_t SizeToRead=((int64)Count>UnpPackedSize) ? (size_t)UnpPackedSize:Count;
      if (SizeToRead==0)
        return 0;
      if (!SrcFile->IsOpened())
        return(-1);
      ReadSize=SrcFile->Read(ReadAddr,SizeToRead);
      FileHeader *hd=SubHead!=NULL ? SubHead:&SrcArc->FileHead;
      if (hd->SplitAfter)
        PackedDataHash.Update(ReadAddr,ReadSize);
    }
    CurUnpRead+=ReadSize;
    TotalRead+=ReadSize;
#ifndef NOVOLUME
    // These variable are not used in NOVOLUME mode, so it is better
    // to exclude commands below to avoid compiler warnings.
    ReadAddr+=ReadSize;
    Count-=ReadSize;
#endif
    UnpPackedSize-=ReadSize;
    if (UnpPackedSize == 0 && UnpVolume)
    {
#ifndef NOVOLUME
      if (!MergeArchive(*SrcArc,this,true,CurrentCommand))
#endif
      {
        NextVolumeMissing=true;
        return(-1);
      }
    }
    else
      break;
  }
  Archive *SrcArc=(Archive *)SrcFile;
  if (SrcArc!=NULL)
    ShowUnpRead(SrcArc->CurBlockPos+CurUnpRead,UnpArcSize);
  if (ReadSize!=-1)
  {
    ReadSize=TotalRead;
#ifndef RAR_NOCRYPT
    if (Decryption)
      Decrypt.DecryptBlock(Addr,ReadSize);
#endif
  }
  Wait();
  return ReadSize;
}
Example #12
0
int ComprDataIO::UnpRead(byte *Addr,size_t Count)
{
#ifndef RAR_NOCRYPT
  // In case of encryption we need to align read size to encryption 
  // block size. We can do it by simple masking, because unpack read code
  // always reads more than CRYPT_BLOCK_SIZE, so we do not risk to make it 0.
  if (Decryption)
    Count &= ~CRYPT_BLOCK_MASK;
#endif
  
  int ReadSize=0,TotalRead=0;
  byte *ReadAddr;
  ReadAddr=Addr;
  while (Count > 0)
  {
    Archive *SrcArc=(Archive *)SrcFile;

    if (UnpackFromMemory)
    {
      memcpy(Addr,UnpackFromMemoryAddr,UnpackFromMemorySize);
      ReadSize=(int)UnpackFromMemorySize;
      UnpackFromMemorySize=0;
    }
    else
    {
      size_t SizeToRead=((int64)Count>UnpPackedSize) ? (size_t)UnpPackedSize:Count;
      if (SizeToRead > 0)
      {
        if (UnpVolume && Decryption && (int64)Count>UnpPackedSize)
        {
          // We need aligned blocks for decryption and we want "Keep broken
          // files" to work efficiently with missing encrypted volumes.
          // So for last data block in volume we adjust the size to read to
          // next equal or smaller block producing aligned total block size.
          // So we'll ask for next volume only when processing few unaligned
          // bytes left in the end, when most of data is already extracted.
          size_t NewTotalRead = TotalRead + SizeToRead;
          size_t Adjust = NewTotalRead - (NewTotalRead  & ~CRYPT_BLOCK_MASK);
          size_t NewSizeToRead = SizeToRead - Adjust;
          if ((int)NewSizeToRead > 0)
            SizeToRead = NewSizeToRead;
        }

        if (!SrcFile->IsOpened())
          return -1;
        ReadSize=SrcFile->Read(ReadAddr,SizeToRead);
        FileHeader *hd=SubHead!=NULL ? SubHead:&SrcArc->FileHead;
        if (hd->SplitAfter)
          PackedDataHash.Update(ReadAddr,ReadSize);
      }
    }
    CurUnpRead+=ReadSize;
    TotalRead+=ReadSize;
#ifndef NOVOLUME
    // These variable are not used in NOVOLUME mode, so it is better
    // to exclude commands below to avoid compiler warnings.
    ReadAddr+=ReadSize;
    Count-=ReadSize;
#endif
    UnpPackedSize-=ReadSize;

    // Do not ask for next volume if we read something from current volume.
    // If next volume is missing, we need to process all data from current
    // volume before aborting. It helps to recover all possible data
    // in "Keep broken files" mode. But if we process encrypted data,
    // we ask for next volume also if we have non-aligned encryption block.
    // Since we adjust data size for decryption earlier above,
    // it does not hurt "Keep broken files" mode efficiency.
    if (UnpVolume && UnpPackedSize == 0 && 
        (ReadSize==0 || Decryption && (TotalRead & CRYPT_BLOCK_MASK) != 0) )
    {
#ifndef NOVOLUME
      if (!MergeArchive(*SrcArc,this,true,CurrentCommand))
#endif
      {
        NextVolumeMissing=true;
        return -1;
      }
    }
    else
      break;
  }
  Archive *SrcArc=(Archive *)SrcFile;
  if (SrcArc!=NULL)
    ShowUnpRead(SrcArc->CurBlockPos+CurUnpRead,UnpArcSize);
  if (ReadSize!=-1)
  {
    ReadSize=TotalRead;
#ifndef RAR_NOCRYPT
    if (Decryption)
      Decrypt.DecryptBlock(Addr,ReadSize);
#endif
  }
  Wait();
  return ReadSize;
}
Example #13
0
int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestName,wchar *DestPathW,wchar *DestNameW, string sParfileName)
{
	DataSet *Data=(DataSet *)hArcData;
	try
	{
		Data->Arc.m_sParfileName = sParfileName;

		if (Data->OpenMode==RAR_OM_LIST || Operation==RAR_SKIP && !Data->Arc.Solid)
		{
			if (/*Data->OpenMode==RAR_OM_LIST && */Data->Arc.Volume &&
				Data->Arc.GetHeaderType()==FILE_HEAD &&
				(Data->Arc.NewLhd.Flags & LHD_SPLIT_AFTER)!=0)
				if (MergeArchive(Data->Arc,NULL,false,'L'))
				{
					Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
					return(0);
				}
				else
					return(ERAR_EOPEN);
			Data->Arc.SeekToNext();
		}
		else
		{
			if (DestPath!=NULL || DestName!=NULL)
			{
				OemToChar(NullToEmpty(DestPath),Data->Cmd.ExtrPath);
				OemToChar(NullToEmpty(DestName),Data->Cmd.ArcName);
				AddEndSlash(Data->Cmd.ExtrPath);
			}
			else
			{
				*Data->Cmd.ExtrPath=0;
			}

			if (DestPathW!=NULL || DestNameW!=NULL)
			{
				strncpyw(Data->Cmd.ExtrPathW,NullToEmpty(DestPathW),NM-2);
				AddEndSlash(Data->Cmd.ExtrPathW);
			}
			else
			{
				*Data->Cmd.ExtrPathW=0;
			}

			strcpy(Data->Cmd.Command,Operation==RAR_EXTRACT ? "X":"T");
			Data->Cmd.Test=Operation!=RAR_EXTRACT;
			bool Repeat=false;

			Data->Extract.ExtractCurrentFile(&Data->Cmd,Data->Arc,Data->HeaderSize,Repeat);

			while (Data->Arc.ReadHeader()!=0 && Data->Arc.GetHeaderType()==NEWSUB_HEAD)
			{
				Data->Extract.ExtractCurrentFile(&Data->Cmd,Data->Arc,Data->HeaderSize,Repeat);
				Data->Arc.SeekToNext();
			}
			Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
		}
	}
	catch (int ErrCode)
	{
		return(RarErrorToDll(ErrCode));
	}
	catch(...)
	{
		return -1;
	}
	return 0;
}
Example #14
0
int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestName,wchar *DestPathW,wchar *DestNameW)
{
  DataSet *Data=(DataSet *)hArcData;
  try
  {
    Data->Cmd.DllError=0;
    if (Data->OpenMode==RAR_OM_LIST || Data->OpenMode==RAR_OM_LIST_INCSPLIT ||
        Operation==RAR_SKIP && !Data->Arc.Solid)
    {
      if (Data->Arc.Volume &&
          Data->Arc.GetHeaderType()==FILE_HEAD &&
          (Data->Arc.NewLhd.Flags & LHD_SPLIT_AFTER)!=0)
        if (MergeArchive(Data->Arc,NULL,false,'L'))
        {
          Data->Extract.SignatureFound=false;
          Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
          return(0);
        }
        else
          return(ERAR_EOPEN);
      Data->Arc.SeekToNext();
    }
    else
    {
      Data->Cmd.DllOpMode=Operation;

      if (DestPath!=NULL || DestName!=NULL)
      {
#ifdef _WIN_ALL
        OemToCharA(NullToEmpty(DestPath),Data->Cmd.ExtrPath);
#else
        strcpy(Data->Cmd.ExtrPath,NullToEmpty(DestPath));
#endif
        AddEndSlash(Data->Cmd.ExtrPath);
#ifdef _WIN_ALL
        OemToCharA(NullToEmpty(DestName),Data->Cmd.DllDestName);
#else
        strcpy(Data->Cmd.DllDestName,NullToEmpty(DestName));
#endif
      }
      else
      {
        *Data->Cmd.ExtrPath=0;
        *Data->Cmd.DllDestName=0;
      }

      if (DestPathW!=NULL || DestNameW!=NULL)
      {
        wcsncpy(Data->Cmd.ExtrPathW,NullToEmpty(DestPathW),NM-2);
        AddEndSlash(Data->Cmd.ExtrPathW);
        wcsncpy(Data->Cmd.DllDestNameW,NullToEmpty(DestNameW),NM-1);

        if (*Data->Cmd.DllDestNameW!=0 && *Data->Cmd.DllDestName==0)
          WideToChar(Data->Cmd.DllDestNameW,Data->Cmd.DllDestName);
      }
      else
      {
        *Data->Cmd.ExtrPathW=0;
        *Data->Cmd.DllDestNameW=0;
      }

      strcpy(Data->Cmd.Command,Operation==RAR_EXTRACT ? "X":"T");
      Data->Cmd.Test=Operation!=RAR_EXTRACT;
      bool Repeat=false;
      Data->Extract.ExtractCurrentFile(&Data->Cmd,Data->Arc,Data->HeaderSize,Repeat);

      // Now we process extra file information if any.
      //
      // Archive can be closed if we process volumes, next volume is missing
      // and current one is already removed or deleted. So we need to check
      // if archive is still open to avoid calling file operations on
      // the invalid file handle. Some of our file operations like Seek()
      // process such invalid handle correctly, some not.
      while (Data->Arc.IsOpened() && Data->Arc.ReadHeader()!=0 &&
             Data->Arc.GetHeaderType()==NEWSUB_HEAD)
      {
        Data->Extract.ExtractCurrentFile(&Data->Cmd,Data->Arc,Data->HeaderSize,Repeat);
        Data->Arc.SeekToNext();
      }
      Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
    }
  }
  catch (RAR_EXIT ErrCode)
  {
    return(Data->Cmd.DllError!=0 ? Data->Cmd.DllError:RarErrorToDll(ErrCode));
  }
  return(Data->Cmd.DllError);
}
Example #15
0
int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestName,wchar *DestPathW,wchar *DestNameW)
{
  DataSet *Data=(DataSet *)hArcData;
  //try
  //{
    Data->Cmd.DllError=0;
    if (Data->OpenMode==RAR_OM_LIST || Data->OpenMode==RAR_OM_LIST_INCSPLIT ||
        Operation==RAR_SKIP && !Data->Arc.Solid)
    {
      if (Data->Arc.Volume &&
          Data->Arc.GetHeaderType()==FILE_HEAD &&
          (Data->Arc.NewLhd.Flags & LHD_SPLIT_AFTER)!=0)
        if (MergeArchive(Data->Arc,NULL,false,'L'))
        {
          Data->Extract.SignatureFound=false;
          Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
          return(0);
        }
        else
          return(ERAR_EOPEN);
      Data->Arc.SeekToNext();
    }
    else
    {
      Data->Cmd.DllOpMode=Operation;

      if (DestPath!=NULL || DestName!=NULL)
      {
#ifdef _WIN_32
        OemToChar(NullToEmpty(DestPath),Data->Cmd.ExtrPath);
#else
        strcpy(Data->Cmd.ExtrPath,NullToEmpty(DestPath));
#endif
        AddEndSlash(Data->Cmd.ExtrPath);
#ifdef _WIN_32
        OemToChar(NullToEmpty(DestName),Data->Cmd.DllDestName);
#else
        strcpy(Data->Cmd.DllDestName,NullToEmpty(DestName));
#endif
      }
      else
      {
        *Data->Cmd.ExtrPath=0;
        *Data->Cmd.DllDestName=0;
      }

      if (DestPathW!=NULL || DestNameW!=NULL)
      {
        strncpyw(Data->Cmd.ExtrPathW,NullToEmpty(DestPathW),NM-2);
        AddEndSlash(Data->Cmd.ExtrPathW);
        strncpyw(Data->Cmd.DllDestNameW,NullToEmpty(DestNameW),NM-1);

        if (*Data->Cmd.DllDestNameW!=0 && *Data->Cmd.DllDestName==0)
          WideToChar(Data->Cmd.DllDestNameW,Data->Cmd.DllDestName);
      }
      else
      {
        *Data->Cmd.ExtrPathW=0;
        *Data->Cmd.DllDestNameW=0;
      }

      strcpy(Data->Cmd.Command,Operation==RAR_EXTRACT ? "X":"T");
      Data->Cmd.Test=Operation!=RAR_EXTRACT;
      bool Repeat=false;
      Data->Extract.ExtractCurrentFile(&Data->Cmd,Data->Arc,Data->HeaderSize,Repeat);

      while (Data->Arc.ReadHeader()!=0 && Data->Arc.GetHeaderType()==NEWSUB_HEAD)
      {
        Data->Extract.ExtractCurrentFile(&Data->Cmd,Data->Arc,Data->HeaderSize,Repeat);
        Data->Arc.SeekToNext();
      }
      Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
    }
  //}
  //catch (int ErrCode)
  //{
   // return(RarErrorToDll(ErrCode));
  //}
  return(Data->Cmd.DllError);
}
Example #16
0
bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
{
  wchar Command=Cmd->Command[0];
  if (HeaderSize==0)
  {
    if (DataIO.UnpVolume)
    {
#ifdef NOVOLUME
      return false;
#else
      // Supposing we unpack an old RAR volume without end of archive record
      // and last file is not split between volumes.
      if (!MergeArchive(Arc,&DataIO,false,Command))
      {
        ErrHandler.SetErrorCode(RARX_WARNING);
        return false;
      }
#endif
    }
    else
      return false;
  }
  HEADER_TYPE HeaderType=Arc.GetHeaderType();
  if (HeaderType!=HEAD_FILE)
  {
#ifndef SFX_MODULE
    if (HeaderType==HEAD3_OLDSERVICE && PrevExtracted)
      SetExtraInfo20(Cmd,Arc,DestFileName);
#endif
    if (HeaderType==HEAD_SERVICE && PrevExtracted)
      SetExtraInfo(Cmd,Arc,DestFileName);
    if (HeaderType==HEAD_ENDARC)
    {
      if (Arc.EndArcHead.NextVolume)
      {
#ifndef NOVOLUME
        if (!MergeArchive(Arc,&DataIO,false,Command))
        {
          ErrHandler.SetErrorCode(RARX_WARNING);
          return false;
        }
#endif
        Arc.Seek(Arc.CurBlockPos,SEEK_SET);
        return true;
      }
      else
        return false;
    }
    Arc.SeekToNext();
    return true;
  }
  PrevExtracted=false;

  if (!Cmd->Recurse && MatchedArgs>=Cmd->FileArgs.ItemsCount() && AllMatchesExact)
    return false;

  int MatchType=MATCH_WILDSUBPATH;

  bool EqualNames=false;
  wchar MatchedArg[NM];
  int MatchNumber=Cmd->IsProcessFile(Arc.FileHead,&EqualNames,MatchType,MatchedArg,ASIZE(MatchedArg));
  bool MatchFound=MatchNumber!=0;
#ifndef SFX_MODULE
  if (Cmd->ExclPath==EXCL_BASEPATH)
  {
    wcsncpyz(Cmd->ArcPath,MatchedArg,ASIZE(Cmd->ArcPath));
    *PointToName(Cmd->ArcPath)=0;
    if (IsWildcard(Cmd->ArcPath)) // Cannot correctly process path*\* masks here.
      *Cmd->ArcPath=0;
  }
#endif
  if (MatchFound && !EqualNames)
    AllMatchesExact=false;

  Arc.ConvertAttributes();

#if !defined(SFX_MODULE) && !defined(RARDLL)
  if (Arc.FileHead.SplitBefore && FirstFile)
  {
    wchar CurVolName[NM];
    wcsncpyz(CurVolName,ArcName,ASIZE(CurVolName));
    VolNameToFirstName(ArcName,ArcName,ASIZE(ArcName),Arc.NewNumbering);

    if (wcsicomp(ArcName,CurVolName)!=0 && FileExist(ArcName))
    {
      // If first volume name does not match the current name and if such
      // volume name really exists, let's unpack from this first volume.
      Repeat=true;
      return false;
    }
#ifndef RARDLL
    if (!ReconstructDone)
    {
      ReconstructDone=true;
      if (RecVolumesRestore(Cmd,Arc.FileName,true))
      {
        Repeat=true;
        return false;
      }
    }
#endif
    wcsncpyz(ArcName,CurVolName,ASIZE(ArcName));
  }
#endif

  wchar ArcFileName[NM];
  ConvertPath(Arc.FileHead.FileName,ArcFileName);

  if (Arc.FileHead.Version)
  {
    if (Cmd->VersionControl!=1 && !EqualNames)
    {
      if (Cmd->VersionControl==0)
        MatchFound=false;
      int Version=ParseVersionFileName(ArcFileName,false);
      if (Cmd->VersionControl-1==Version)
        ParseVersionFileName(ArcFileName,true);
      else
        MatchFound=false;
    }
  }
  else
    if (!Arc.IsArcDir() && Cmd->VersionControl>1)
      MatchFound=false;

  DataIO.UnpVolume=Arc.FileHead.SplitAfter;
  DataIO.NextVolumeMissing=false;

  Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET);

  bool ExtrFile=false;
  bool SkipSolid=false;

#ifndef SFX_MODULE
  if (FirstFile && (MatchFound || Arc.Solid) && Arc.FileHead.SplitBefore)
  {
    if (MatchFound)
    {
      uiMsg(UIERROR_NEEDPREVVOL,Arc.FileName,ArcFileName);
#ifdef RARDLL
      Cmd->DllError=ERAR_BAD_DATA;
#endif
      ErrHandler.SetErrorCode(RARX_OPEN);
    }
    MatchFound=false;
  }

  FirstFile=false;
#endif

  if (MatchFound || (SkipSolid=Arc.Solid)!=0)
  {
    // First common call of uiStartFileExtract. It is done before overwrite
    // prompts, so if SkipSolid state is changed below, we'll need to make
    // additional uiStartFileExtract calls with updated parameters.
    if (!uiStartFileExtract(ArcFileName,!Cmd->Test,Cmd->Test && Command!='I',SkipSolid))
      return false;

    ExtrPrepareName(Arc,ArcFileName,DestFileName,ASIZE(DestFileName));

    // DestFileName can be set empty in case of excessive -ap switch.
    ExtrFile=!SkipSolid && *DestFileName!=0 && !Arc.FileHead.SplitBefore;

    if ((Cmd->FreshFiles || Cmd->UpdateFiles) && (Command=='E' || Command=='X'))
    {
      FindData FD;
      if (FindFile::FastFind(DestFileName,&FD))
      {
        if (FD.mtime >= Arc.FileHead.mtime)
        {
          // If directory already exists and its modification time is newer 
          // than start of extraction, it is likely it was created 
          // when creating a path to one of already extracted items. 
          // In such case we'll better update its time even if archived 
          // directory is older.

          if (!FD.IsDir || FD.mtime<StartTime)
            ExtrFile=false;
        }
      }
      else
        if (Cmd->FreshFiles)
          ExtrFile=false;
    }

    if (Arc.FileHead.Encrypted)
    {
#ifdef RARDLL
      if (!ExtrDllGetPassword())
        return false;
#else
      if (!ExtrGetPassword(Arc,ArcFileName))
      {
        PasswordCancelled=true;
        return false;
      }
#endif
      // Skip only the current encrypted file if empty password is entered.
      if (!Cmd->Password.IsSet())
      {
        ErrHandler.SetErrorCode(RARX_WARNING);
#ifdef RARDLL
        Cmd->DllError=ERAR_MISSING_PASSWORD;
#endif
        ExtrFile=false;
      }
    }

#ifdef RARDLL
    if (*Cmd->DllDestName!=0)
      wcsncpyz(DestFileName,Cmd->DllDestName,ASIZE(DestFileName));
#endif

    if (!CheckUnpVer(Arc,ArcFileName))
    {
      ExtrFile=false;
      ErrHandler.SetErrorCode(RARX_FATAL);
#ifdef RARDLL
      Cmd->DllError=ERAR_UNKNOWN_FORMAT;
#endif
    }

    File CurFile;

    bool LinkEntry=Arc.FileHead.RedirType!=FSREDIR_NONE;
    if (LinkEntry && Arc.FileHead.RedirType!=FSREDIR_FILECOPY)
    {
      if (ExtrFile && Command!='P' && !Cmd->Test)
      {
        // Overwrite prompt for symbolic and hard links.
        bool UserReject=false;
        if (FileExist(DestFileName) && !UserReject)
          FileCreate(Cmd,NULL,DestFileName,ASIZE(DestFileName),&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime);
        if (UserReject)
          ExtrFile=false;
      }
    }
    else
      if (Arc.IsArcDir())
      {
        if (!ExtrFile || Command=='P' || Command=='I' || Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
          return true;
        TotalFileCount++;
        ExtrCreateDir(Arc,ArcFileName);
        return true;
      }
      else
        if (ExtrFile) // Create files and file copies (FSREDIR_FILECOPY).
          ExtrFile=ExtrCreateFile(Arc,CurFile);

    if (!ExtrFile && Arc.Solid)
    {
      SkipSolid=true;
      ExtrFile=true;

      // We changed SkipSolid, so we need to call uiStartFileExtract
      // with "Skip" parameter to change the operation status 
      // from "extracting" to "skipping". For example, it can be necessary
      // if user answered "No" to overwrite prompt when unpacking
      // a solid archive.
      if (!uiStartFileExtract(ArcFileName,false,false,true))
        return false;
    }
    if (ExtrFile)
    {
      bool TestMode=Cmd->Test || SkipSolid; // Unpack to memory, not to disk.

      if (!SkipSolid)
      {
        if (!TestMode && Command!='P' && CurFile.IsDevice())
        {
          uiMsg(UIERROR_INVALIDNAME,Arc.FileName,DestFileName);
          ErrHandler.WriteError(Arc.FileName,DestFileName);
        }
        TotalFileCount++;
      }
      FileCount++;
#ifndef GUI
      if (Command!='I')
      {
        if (SkipSolid)
          mprintf(St(MExtrSkipFile),ArcFileName);
        else
          switch(Cmd->Test ? 'T':Command) // "Test" can be also enabled by -t switch.
          {
            case 'T':
              mprintf(St(MExtrTestFile),ArcFileName);
              break;
#ifndef SFX_MODULE
            case 'P':
              mprintf(St(MExtrPrinting),ArcFileName);
              break;
#endif
            case 'X':
            case 'E':
              mprintf(St(MExtrFile),DestFileName);
              break;
          }
      }
      if (!Cmd->DisablePercentage)
        mprintf(L"     ");
#endif

      SecPassword FilePassword=Cmd->Password;
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
      ConvertDosPassword(Arc,FilePassword);
#endif

      byte PswCheck[SIZE_PSWCHECK];
      DataIO.SetEncryption(false,Arc.FileHead.CryptMethod,&FilePassword,
             Arc.FileHead.SaltSet ? Arc.FileHead.Salt:NULL,
             Arc.FileHead.InitV,Arc.FileHead.Lg2Count,
             PswCheck,Arc.FileHead.HashKey);
      bool WrongPassword=false;

      // If header is damaged, we cannot rely on password check value,
      // because it can be damaged too.
      if (Arc.FileHead.Encrypted && Arc.FileHead.UsePswCheck &&
          memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0 &&
          !Arc.BrokenHeader)
      {
        uiMsg(UIERROR_BADPSW,Arc.FileName);
        ErrHandler.SetErrorCode(RARX_BADPWD);
        WrongPassword=true;
      }
      DataIO.CurUnpRead=0;
      DataIO.CurUnpWrite=0;
      DataIO.UnpHash.Init(Arc.FileHead.FileHash.Type,Cmd->Threads);
      DataIO.PackedDataHash.Init(Arc.FileHead.FileHash.Type,Cmd->Threads);
      DataIO.SetPackedSizeToRead(Arc.FileHead.PackSize);
      DataIO.SetFiles(&Arc,&CurFile);
      DataIO.SetTestMode(TestMode);
      DataIO.SetSkipUnpCRC(SkipSolid);

#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT)
      if (!TestMode && !WrongPassword && !Arc.BrokenHeader &&
          Arc.FileHead.UnpSize>0xffffffff && (Fat32 || !NotFat32))
      {
        if (!Fat32) // Not detected yet.
          NotFat32=!(Fat32=IsFAT(Cmd->ExtrPath));
        if (Fat32)
          uiMsg(UIMSG_FAT32SIZE); // Inform user about FAT32 size limit.
      }
#endif

      if (!TestMode && !WrongPassword && !Arc.BrokenHeader &&
          (Arc.FileHead.PackSize<<11)>Arc.FileHead.UnpSize &&
          (Arc.FileHead.UnpSize<100000000 || Arc.FileLength()>Arc.FileHead.PackSize))
        CurFile.Prealloc(Arc.FileHead.UnpSize);

      CurFile.SetAllowDelete(!Cmd->KeepBroken);

      bool FileCreateMode=!TestMode && !SkipSolid && Command!='P';
      bool ShowChecksum=true; // Display checksum verification result.

      bool LinkSuccess=true; // Assume success for test mode.
      if (LinkEntry)
      {
        FILE_SYSTEM_REDIRECT Type=Arc.FileHead.RedirType;

        if (Type==FSREDIR_HARDLINK || Type==FSREDIR_FILECOPY)
        {
          wchar NameExisting[NM];
          ExtrPrepareName(Arc,Arc.FileHead.RedirName,NameExisting,ASIZE(NameExisting));
          if (FileCreateMode && *NameExisting!=0) // *NameExisting can be 0 in case of excessive -ap switch.
          {
            if (Type==FSREDIR_HARDLINK)
              LinkSuccess=ExtractHardlink(DestFileName,NameExisting,ASIZE(NameExisting));
            else
              LinkSuccess=ExtractFileCopy(CurFile,Arc.FileName,DestFileName,NameExisting,ASIZE(NameExisting));
          }
        }
        else
          if (Type==FSREDIR_UNIXSYMLINK || Type==FSREDIR_WINSYMLINK || Type==FSREDIR_JUNCTION)
          {
            if (FileCreateMode)
              LinkSuccess=ExtractSymlink(Cmd,DataIO,Arc,DestFileName);
          }
          else
          {
            uiMsg(UIERROR_UNKNOWNEXTRA, Arc.FileName, DestFileName);
            LinkSuccess=false;
          }
          
          if (!LinkSuccess || (Arc.Format==RARFMT15 && !FileCreateMode))
          {
            // RAR 5.x links have a valid data checksum even in case of
            // failure, because they do not store any data.
            // We do not want to display "OK" in this case.
            // For 4.x symlinks we verify the checksum only when extracting,
            // but not when testing an archive.
            ShowChecksum=false;
          }
          PrevExtracted=FileCreateMode && LinkSuccess;
      }
      else
        if (!Arc.FileHead.SplitBefore && !WrongPassword)
        {
          if (Arc.FileHead.Method==0)
            UnstoreFile(DataIO,Arc.FileHead.UnpSize);
          else
          {
#ifdef _ANDROID
            // malloc and new do not report memory allocation errors
            // in Android, so if free memory is set, check it here
            // trying to prevent crash.
            if (Cmd->FreeMem!=0 && Cmd->FreeMem < Arc.FileHead.WinSize)
              throw std::bad_alloc();
#endif
            Unp->Init(Arc.FileHead.WinSize,Arc.FileHead.Solid);
            Unp->SetDestSize(Arc.FileHead.UnpSize);
#ifndef SFX_MODULE
            if (Arc.Format!=RARFMT50 && Arc.FileHead.UnpVer<=15)
              Unp->DoUnpack(15,FileCount>1 && Arc.Solid);
            else
#endif
              Unp->DoUnpack(Arc.FileHead.UnpVer,Arc.FileHead.Solid);
          }
        }

      Arc.SeekToNext();

      // We check for "split after" flag to detect partially extracted files
      // from incomplete volume sets. For them file header contains packed
      // data hash, which must not be compared against unpacked data hash
      // to prevent accidental match. Moreover, for -m0 volumes packed data
      // hash would match truncated unpacked data hash and lead to fake "OK"
      // in incomplete volume set.
      bool ValidCRC=!Arc.FileHead.SplitAfter && DataIO.UnpHash.Cmp(&Arc.FileHead.FileHash,Arc.FileHead.UseHashKey ? Arc.FileHead.HashKey:NULL);

      // We set AnySolidDataUnpackedWell to true if we found at least one
      // valid non-zero solid file in preceding solid stream. If it is true
      // and if current encrypted file is broken, we do not need to hint
      // about a wrong password and can report CRC error only.
      if (!Arc.FileHead.Solid)
        AnySolidDataUnpackedWell=false; // Reset the flag, because non-solid file is found.
      else
        if (Arc.FileHead.Method!=0 && Arc.FileHead.UnpSize>0 && ValidCRC)
          AnySolidDataUnpackedWell=true;
 
      bool BrokenFile=false;
      
      // Checksum is not calculated in skip solid mode for performance reason.
      if (!SkipSolid && ShowChecksum)
      {
        if (!WrongPassword && ValidCRC)
        {
#ifndef GUI
          if (Command!='P' && Command!='I')
            mprintf(L"%s%s ",Cmd->DisablePercentage ? L" ":L"\b\b\b\b\b ",
              Arc.FileHead.FileHash.Type==HASH_NONE ? L"  ?":St(MOk));
#endif
        }
        else
        {
          if (!WrongPassword)
          {
            if (Arc.FileHead.Encrypted && (!Arc.FileHead.UsePswCheck ||
                Arc.BrokenHeader) && !AnySolidDataUnpackedWell)
              uiMsg(UIERROR_CHECKSUMENC,Arc.FileName,ArcFileName);
            else
              uiMsg(UIERROR_CHECKSUM,Arc.FileName,ArcFileName);
          }
          BrokenFile=true;
          ErrHandler.SetErrorCode(RARX_CRC);
#ifdef RARDLL
          // If we already have ERAR_EOPEN as result of missing volume,
          // we should not replace it with less precise ERAR_BAD_DATA.
          if (Cmd->DllError!=ERAR_EOPEN)
            Cmd->DllError=WrongPassword ? ERAR_BAD_PASSWORD : ERAR_BAD_DATA;
#endif
        }
      }
#ifndef GUI
      else
        mprintf(L"\b\b\b\b\b     ");
#endif

      if (!TestMode && !WrongPassword && (Command=='X' || Command=='E') &&
          (!LinkEntry || (Arc.FileHead.RedirType==FSREDIR_FILECOPY && LinkSuccess)) && 
          (!BrokenFile || Cmd->KeepBroken))
      {
        // We could preallocate more space that really written to broken file.
        if (BrokenFile)
          CurFile.Truncate();

#if defined(_WIN_ALL) || defined(_EMX)
        if (Cmd->ClearArc)
          Arc.FileHead.FileAttr&=~FILE_ATTRIBUTE_ARCHIVE;
#endif


        CurFile.SetOpenFileTime(
          Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime,
          Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.FileHead.ctime,
          Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime);
        CurFile.Close();
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
        if (Cmd->SetCompressedAttr &&
            (Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0)
          SetFileCompression(CurFile.FileName,true);
#endif
#ifdef _UNIX
        if (Cmd->ProcessOwners && Arc.Format==RARFMT50 && Arc.FileHead.UnixOwnerSet)
          SetUnixOwner(Arc,CurFile.FileName);
#endif

        CurFile.SetCloseFileTime(
          Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime,
          Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime);
        if (!Cmd->IgnoreGeneralAttr && !SetFileAttr(CurFile.FileName,Arc.FileHead.FileAttr))
          uiMsg(UIERROR_FILEATTR,Arc.FileName,CurFile.FileName);

        PrevExtracted=true;
      }
    }
  }
  if (MatchFound)
    MatchedArgs++;
  if (DataIO.NextVolumeMissing)
    return false;
  if (!ExtrFile)
  {
    if (!Arc.Solid)
      Arc.SeekToNext();
    else
      if (!SkipSolid)
        return false;
  }
  return true;
}
Example #17
0
bool CmdExtract::ExtractCurrentFile(CommandData *Cmd,Archive &Arc,size_t HeaderSize,bool &Repeat)
{
  char Command=*Cmd->Command;
  if (HeaderSize==0)
    if (DataIO.UnpVolume)
    {
#ifdef NOVOLUME
      return(false);
#else
      if (!MergeArchive(Arc,&DataIO,false,Command))
      {
        ErrHandler.SetErrorCode(WARNING);
        return(false);
      }
      SignatureFound=false;
#endif
    }
    else
      return(false);
  int HeadType=Arc.GetHeaderType();
  if (HeadType!=FILE_HEAD)
  {
    if (HeadType==AV_HEAD || HeadType==SIGN_HEAD)
      SignatureFound=true;
#if !defined(SFX_MODULE) && !defined(_WIN_CE)
    if (HeadType==SUB_HEAD && PrevExtracted)
      SetExtraInfo(Cmd,Arc,DestFileName,*DestFileNameW ? DestFileNameW:NULL);
#endif
    if (HeadType==NEWSUB_HEAD)
    {
      if (Arc.SubHead.CmpName(SUBHEAD_TYPE_AV))
        SignatureFound=true;
#if !defined(NOSUBBLOCKS) && !defined(_WIN_CE)
      if (PrevExtracted)
        SetExtraInfoNew(Cmd,Arc,DestFileName,*DestFileNameW ? DestFileNameW:NULL);
#endif
    }
    if (HeadType==ENDARC_HEAD)
      if (Arc.EndArcHead.Flags & EARC_NEXT_VOLUME)
      {
#ifndef NOVOLUME
        if (!MergeArchive(Arc,&DataIO,false,Command))
        {
          ErrHandler.SetErrorCode(WARNING);
          return(false);
        }
        SignatureFound=false;
#endif
        Arc.Seek(Arc.CurBlockPos,SEEK_SET);
        return(true);
      }
      else
        return(false);
    Arc.SeekToNext();
    return(true);
  }
  PrevExtracted=false;

  if (SignatureFound ||
      !Cmd->Recurse && MatchedArgs>=Cmd->FileArgs->ItemsCount() &&
      AllMatchesExact)
    return(false);

  char ArcFileName[NM];
  IntToExt(Arc.NewLhd.FileName,Arc.NewLhd.FileName);
  strcpy(ArcFileName,Arc.NewLhd.FileName);

  wchar ArcFileNameW[NM];
  *ArcFileNameW=0;

  int MatchType=MATCH_WILDSUBPATH;

  bool EqualNames=false;
  int MatchNumber=Cmd->IsProcessFile(Arc.NewLhd,&EqualNames,MatchType);
  bool ExactMatch=MatchNumber!=0;
#if !defined(SFX_MODULE) && !defined(_WIN_CE)
  if (Cmd->ExclPath==EXCL_BASEPATH)
  {
    *Cmd->ArcPath=0;
    if (ExactMatch)
    {
      Cmd->FileArgs->Rewind();
      if (Cmd->FileArgs->GetString(Cmd->ArcPath,NULL,sizeof(Cmd->ArcPath),MatchNumber-1))
        *PointToName(Cmd->ArcPath)=0;
    }
  }
#endif
  if (ExactMatch && !EqualNames)
    AllMatchesExact=false;

#ifdef UNICODE_SUPPORTED
  bool WideName=(Arc.NewLhd.Flags & LHD_UNICODE) && UnicodeEnabled();
#else
  bool WideName=false;
#endif

#ifdef _APPLE
  if (WideName)
  {
    WideToUtf(Arc.NewLhd.FileNameW,ArcFileName,sizeof(ArcFileName));
    WideName=false;
  }
#endif

  wchar *DestNameW=WideName ? DestFileNameW:NULL;

#ifdef UNICODE_SUPPORTED
  if (WideName)
  {
    ConvertPath(Arc.NewLhd.FileNameW,ArcFileNameW);
    char Name[NM];
    if (WideToChar(ArcFileNameW,Name) && IsNameUsable(Name))
      strcpy(ArcFileName,Name);
  }
#endif

  ConvertPath(ArcFileName,ArcFileName);

  if (Arc.IsArcLabel())
    return(true);

  if (Arc.NewLhd.Flags & LHD_VERSION)
  {
    if (Cmd->VersionControl!=1 && !EqualNames)
    {
      if (Cmd->VersionControl==0)
        ExactMatch=false;
      int Version=ParseVersionFileName(ArcFileName,ArcFileNameW,false);
      if (Cmd->VersionControl-1==Version)
        ParseVersionFileName(ArcFileName,ArcFileNameW,true);
      else
        ExactMatch=false;
    }
  }
  else
    if (!Arc.IsArcDir() && Cmd->VersionControl>1)
      ExactMatch=false;

  Arc.ConvertAttributes();

#ifndef SFX_MODULE
  if ((Arc.NewLhd.Flags & (LHD_SPLIT_BEFORE/*|LHD_SOLID*/)) && FirstFile)
  {
    char CurVolName[NM];
    strcpy(CurVolName,ArcName);

    VolNameToFirstName(ArcName,ArcName,(Arc.NewMhd.Flags & MHD_NEWNUMBERING)!=0);
    if (stricomp(ArcName,CurVolName)!=0 && FileExist(ArcName))
    {
      *ArcNameW=0;
      Repeat=true;
      return(false);
    }
#if !defined(RARDLL) && !defined(_WIN_CE)
    if (!ReconstructDone)
    {
      ReconstructDone=true;

      RecVolumes RecVol;
      if (RecVol.Restore(Cmd,Arc.FileName,Arc.FileNameW,true))
      {
        Repeat=true;
        return(false);
      }
    }
#endif
    strcpy(ArcName,CurVolName);
  }
#endif
  DataIO.UnpVolume=(Arc.NewLhd.Flags & LHD_SPLIT_AFTER)!=0;
  DataIO.NextVolumeMissing=false;

  Arc.Seek(Arc.NextBlockPos-Arc.NewLhd.FullPackSize,SEEK_SET);

  bool TestMode=false;
  bool ExtrFile=false;
  bool SkipSolid=false;

#ifndef SFX_MODULE
  if (FirstFile && (ExactMatch || Arc.Solid) && (Arc.NewLhd.Flags & (LHD_SPLIT_BEFORE/*|LHD_SOLID*/))!=0)
  {
    if (ExactMatch)
    {
      Log(Arc.FileName,St(MUnpCannotMerge),ArcFileName);
#ifdef RARDLL
      Cmd->DllError=ERAR_BAD_DATA;
#endif
      ErrHandler.SetErrorCode(OPEN_ERROR);
    }
    ExactMatch=false;
  }

  FirstFile=false;
#endif

  if (ExactMatch || (SkipSolid=Arc.Solid)!=0)
  {
    if ((Arc.NewLhd.Flags & LHD_PASSWORD)!=0)
#ifndef RARDLL
      if (*Password==0)
#endif
      {
#ifdef RARDLL
        if (*Cmd->Password==0)
          if (Cmd->Callback==NULL ||
              Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)Cmd->Password,sizeof(Cmd->Password))==-1)
            return(false);
        strcpy(Password,Cmd->Password);

#else
        if (!GetPassword(PASSWORD_FILE,ArcFileName,Password,sizeof(Password)))
        {
          PasswordCancelled=true;
          return(false);
        }
#endif
      }
#if !defined(GUI) && !defined(SILENT)
      else
        if (!PasswordAll && (!Arc.Solid || Arc.NewLhd.UnpVer>=20 && (Arc.NewLhd.Flags & LHD_SOLID)==0))
        {
          eprintf(St(MUseCurPsw),ArcFileName);
          switch(Cmd->AllYes ? 1:Ask(St(MYesNoAll)))
          {
            case -1:
              ErrHandler.Exit(USER_BREAK);
            case 2:
              if (!GetPassword(PASSWORD_FILE,ArcFileName,Password,sizeof(Password)))
              {
                return(false);
              }
              break;
            case 3:
              PasswordAll=true;
              break;
          }
        }
#endif

#ifndef SFX_MODULE
    if (*Cmd->ExtrPath==0 && *Cmd->ExtrPathW!=0)
      WideToChar(Cmd->ExtrPathW,DestFileName);
    else
#endif
      strcpy(DestFileName,Cmd->ExtrPath);


#ifndef SFX_MODULE
    if (Cmd->AppendArcNameToPath)
    {
      strcat(DestFileName,PointToName(Arc.FirstVolumeName));
      SetExt(DestFileName,NULL);
      AddEndSlash(DestFileName);
    }
#endif

    char *ExtrName=ArcFileName;

    bool EmptyName=false;
#ifndef SFX_MODULE
    size_t Length=strlen(Cmd->ArcPath);
    if (Length>1 && IsPathDiv(Cmd->ArcPath[Length-1]) &&
        strlen(ArcFileName)==Length-1)
      Length--;
    if (Length>0 && strnicomp(Cmd->ArcPath,ArcFileName,Length)==0)
    {
      ExtrName+=Length;
      while (*ExtrName==CPATHDIVIDER)
        ExtrName++;
      if (*ExtrName==0)
        EmptyName=true;
    }
#endif

    bool AbsPaths=Cmd->ExclPath==EXCL_ABSPATH && Command=='X' && IsDriveDiv(':');
    if (AbsPaths)
      *DestFileName=0;

    if (Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
      strcat(DestFileName,PointToName(ExtrName));
    else
      strcat(DestFileName,ExtrName);

    char DiskLetter=etoupper(DestFileName[0]);

    if (AbsPaths && DestFileName[1]=='_' && IsPathDiv(DestFileName[2]) &&
        DiskLetter>='A' && DiskLetter<='Z')
      DestFileName[1]=':';

#ifndef SFX_MODULE
    if (!WideName && *Cmd->ExtrPathW!=0)
    {
      DestNameW=DestFileNameW;
      WideName=true;
      CharToWide(ArcFileName,ArcFileNameW);
    }
#endif

    if (WideName)
    {
      if (*Cmd->ExtrPathW!=0)
        strcpyw(DestFileNameW,Cmd->ExtrPathW);
      else
        CharToWide(Cmd->ExtrPath,DestFileNameW);

#ifndef SFX_MODULE
      if (Cmd->AppendArcNameToPath)
      {
        wchar FileNameW[NM];
        if (*Arc.FirstVolumeNameW!=0)
          strcpyw(FileNameW,Arc.FirstVolumeNameW);
        else
          CharToWide(Arc.FirstVolumeName,FileNameW);
        strcatw(DestFileNameW,PointToName(FileNameW));
        SetExt(DestFileNameW,NULL);
        AddEndSlash(DestFileNameW);
      }
#endif
      wchar *ExtrNameW=ArcFileNameW;
#ifndef SFX_MODULE
      if (Length>0)
      {
        wchar ArcPathW[NM];
        GetWideName(Cmd->ArcPath,Cmd->ArcPathW,ArcPathW);
        Length=strlenw(ArcPathW);
      }
      ExtrNameW+=Length;
      while (*ExtrNameW==CPATHDIVIDER)
        ExtrNameW++;
#endif

      if (AbsPaths)
        *DestFileNameW=0;

      if (Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
        strcatw(DestFileNameW,PointToName(ExtrNameW));
      else
        strcatw(DestFileNameW,ExtrNameW);

      if (AbsPaths && DestFileNameW[1]=='_' && IsPathDiv(DestFileNameW[2]))
        DestFileNameW[1]=':';
    }
    else
      *DestFileNameW=0;

    ExtrFile=!SkipSolid && !EmptyName && (Arc.NewLhd.Flags & LHD_SPLIT_BEFORE)==0;

    if ((Cmd->FreshFiles || Cmd->UpdateFiles) && (Command=='E' || Command=='X'))
    {
      struct FindData FD;
      if (FindFile::FastFind(DestFileName,DestNameW,&FD))
      {
        if (FD.mtime >= Arc.NewLhd.mtime)
        {
          // If directory already exists and its modification time is newer 
          // than start of extraction, it is likely it was created 
          // when creating a path to one of already extracted items. 
          // In such case we'll better update its time even if archived 
          // directory is older.

          if (!FD.IsDir || FD.mtime<StartTime)
            ExtrFile=false;
        }
      }
      else
        if (Cmd->FreshFiles)
          ExtrFile=false;
    }

    // Skip encrypted file if no password is specified.
    if ((Arc.NewLhd.Flags & LHD_PASSWORD)!=0 && *Password==0)
    {
      ErrHandler.SetErrorCode(WARNING);
#ifdef RARDLL
      Cmd->DllError=ERAR_MISSING_PASSWORD;
#endif
      ExtrFile=false;
    }

#ifdef RARDLL
    if (*Cmd->DllDestName)
    {
      strncpyz(DestFileName,Cmd->DllDestName,ASIZE(DestFileName));
      *DestFileNameW=0;
      if (Cmd->DllOpMode!=RAR_EXTRACT)
        ExtrFile=false;
    }
    if (*Cmd->DllDestNameW)
    {
      strncpyzw(DestFileNameW,Cmd->DllDestNameW,ASIZE(DestFileNameW));
      DestNameW=DestFileNameW;
      if (Cmd->DllOpMode!=RAR_EXTRACT)
        ExtrFile=false;
    }
#endif

#ifdef SFX_MODULE
    if ((Arc.NewLhd.UnpVer!=UNP_VER && Arc.NewLhd.UnpVer!=29) &&
        Arc.NewLhd.Method!=0x30)
#else
    if (Arc.NewLhd.UnpVer<13 || Arc.NewLhd.UnpVer>UNP_VER)
#endif
    {
#ifndef SILENT
      Log(Arc.FileName,St(MUnknownMeth),ArcFileName);
#ifndef SFX_MODULE
      Log(Arc.FileName,St(MVerRequired),Arc.NewLhd.UnpVer/10,Arc.NewLhd.UnpVer%10);
#endif
#endif
      ExtrFile=false;
      ErrHandler.SetErrorCode(WARNING);
#ifdef RARDLL
      Cmd->DllError=ERAR_UNKNOWN_FORMAT;
#endif
    }

    File CurFile;

    if (!IsLink(Arc.NewLhd.FileAttr))
      if (Arc.IsArcDir())
      {
        if (!ExtrFile || Command=='P' || Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
          return(true);
        if (SkipSolid)
        {
#ifndef GUI
          mprintf(St(MExtrSkipFile),ArcFileName);
#endif
          return(true);
        }
        TotalFileCount++;
        if (Cmd->Test)
        {
#ifndef GUI
          mprintf(St(MExtrTestFile),ArcFileName);
          mprintf(" %s",St(MOk));
#endif
          return(true);
        }
        MKDIR_CODE MDCode=MakeDir(DestFileName,DestNameW,!Cmd->IgnoreGeneralAttr,Arc.NewLhd.FileAttr);
        bool DirExist=false;
        if (MDCode!=MKDIR_SUCCESS)
        {
          DirExist=FileExist(DestFileName,DestNameW);
          if (DirExist && !IsDir(GetFileAttr(DestFileName,DestNameW)))
          {
            bool UserReject;
            FileCreate(Cmd,NULL,DestFileName,DestNameW,Cmd->Overwrite,&UserReject,Arc.NewLhd.FullUnpSize,Arc.NewLhd.FileTime);
            DirExist=false;
          }
          CreatePath(DestFileName,DestNameW,true);
          MDCode=MakeDir(DestFileName,DestNameW,!Cmd->IgnoreGeneralAttr,Arc.NewLhd.FileAttr);
        }
        if (MDCode==MKDIR_SUCCESS)
        {
#ifndef GUI
          mprintf(St(MCreatDir),DestFileName);
          mprintf(" %s",St(MOk));
#endif
          PrevExtracted=true;
        }
        else
          if (DirExist)
          {
            if (!Cmd->IgnoreGeneralAttr)
              SetFileAttr(DestFileName,DestNameW,Arc.NewLhd.FileAttr);
            PrevExtracted=true;
          }
          else
          {
            Log(Arc.FileName,St(MExtrErrMkDir),DestFileName);
            ErrHandler.SysErrMsg();
#ifdef RARDLL
            Cmd->DllError=ERAR_ECREATE;
#endif
            ErrHandler.SetErrorCode(CREATE_ERROR);
          }
        if (PrevExtracted)
        {
#if defined(_WIN_32) && !defined(_WIN_CE) && !defined(SFX_MODULE)
          if (Cmd->SetCompressedAttr &&
              (Arc.NewLhd.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT())
            SetFileCompression(DestFileName,DestNameW,true);
#endif
          SetDirTime(DestFileName,DestNameW,
            Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.NewLhd.mtime,
            Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.NewLhd.ctime,
            Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.NewLhd.atime);
        }
        return(true);
      }
      else
      {
        if (Cmd->Test && ExtrFile)
          TestMode=true;
#if !defined(GUI) && !defined(SFX_MODULE)
        if (Command=='P' && ExtrFile)
          CurFile.SetHandleType(FILE_HANDLESTD);
#endif
        if ((Command=='E' || Command=='X') && ExtrFile && !Cmd->Test)
        {
          bool UserReject;
          if (!FileCreate(Cmd,&CurFile,DestFileName,DestNameW,Cmd->Overwrite,&UserReject,Arc.NewLhd.FullUnpSize,Arc.NewLhd.FileTime))
          {
            ExtrFile=false;
            if (!UserReject)
            {
              ErrHandler.CreateErrorMsg(Arc.FileName,DestFileName);
              ErrHandler.SetErrorCode(CREATE_ERROR);
#ifdef RARDLL
              Cmd->DllError=ERAR_ECREATE;
#endif
              if (!IsNameUsable(DestFileName))
              {
                Log(Arc.FileName,St(MCorrectingName));
                char OrigName[sizeof(DestFileName)];
                strncpyz(OrigName,DestFileName,ASIZE(OrigName));

                MakeNameUsable(DestFileName,true);
                CreatePath(DestFileName,NULL,true);
                if (FileCreate(Cmd,&CurFile,DestFileName,NULL,Cmd->Overwrite,&UserReject,Arc.NewLhd.FullUnpSize,Arc.NewLhd.FileTime))
                {
#ifndef SFX_MODULE
                  Log(Arc.FileName,St(MRenaming),OrigName,DestFileName);
#endif
                  ExtrFile=true;
                }
                else
                  ErrHandler.CreateErrorMsg(Arc.FileName,DestFileName);
              }
            }
          }
        }
      }

    if (!ExtrFile && Arc.Solid)
    {
      SkipSolid=true;
      TestMode=true;
      ExtrFile=true;

    }
    if (ExtrFile)
    {
      if (!SkipSolid)
      {
        if (!TestMode && Command!='P' && CurFile.IsDevice())
        {
          Log(Arc.FileName,St(MInvalidName),DestFileName);
          ErrHandler.WriteError(Arc.FileName,DestFileName);
        }
        TotalFileCount++;
      }
      FileCount++;
#ifndef GUI
      if (Command!='I')
        if (SkipSolid)
          mprintf(St(MExtrSkipFile),ArcFileName);
        else
          switch(Cmd->Test ? 'T':Command)
          {
            case 'T':
              mprintf(St(MExtrTestFile),ArcFileName);
              break;
#ifndef SFX_MODULE
            case 'P':
              mprintf(St(MExtrPrinting),ArcFileName);
              break;
#endif
            case 'X':
            case 'E':
              mprintf(St(MExtrFile),DestFileName);
              break;
          }
      if (!Cmd->DisablePercentage)
        mprintf("     ");
#endif
      DataIO.CurUnpRead=0;
      DataIO.CurUnpWrite=0;
      DataIO.UnpFileCRC=Arc.OldFormat ? 0 : 0xffffffff;
      DataIO.PackedCRC=0xffffffff;
      DataIO.SetEncryption(
        (Arc.NewLhd.Flags & LHD_PASSWORD) ? Arc.NewLhd.UnpVer:0,Password,
        (Arc.NewLhd.Flags & LHD_SALT) ? Arc.NewLhd.Salt:NULL,false,
        Arc.NewLhd.UnpVer>=36);
      DataIO.SetPackedSizeToRead(Arc.NewLhd.FullPackSize);
      DataIO.SetFiles(&Arc,&CurFile);
      DataIO.SetTestMode(TestMode);
      DataIO.SetSkipUnpCRC(SkipSolid);
#ifndef _WIN_CE
      if (!TestMode && !Arc.BrokenFileHeader &&
          (Arc.NewLhd.FullPackSize<<11)>Arc.NewLhd.FullUnpSize &&
          (Arc.NewLhd.FullUnpSize<100000000 || Arc.FileLength()>Arc.NewLhd.FullPackSize))
        CurFile.Prealloc(Arc.NewLhd.FullUnpSize);
#endif

      CurFile.SetAllowDelete(!Cmd->KeepBroken);

      bool LinkCreateMode=!Cmd->Test && !SkipSolid;
      if (ExtractLink(DataIO,Arc,DestFileName,DataIO.UnpFileCRC,LinkCreateMode))
        PrevExtracted=LinkCreateMode;
      else
        if ((Arc.NewLhd.Flags & LHD_SPLIT_BEFORE)==0)
          if (Arc.NewLhd.Method==0x30)
            UnstoreFile(DataIO,Arc.NewLhd.FullUnpSize);
          else
          {
            Unp->SetDestSize(Arc.NewLhd.FullUnpSize);
#ifndef SFX_MODULE
            if (Arc.NewLhd.UnpVer<=15)
              Unp->DoUnpack(15,FileCount>1 && Arc.Solid);
            else
#endif
              Unp->DoUnpack(Arc.NewLhd.UnpVer,(Arc.NewLhd.Flags & LHD_SOLID)!=0);
          }

      if (Arc.IsOpened())
        Arc.SeekToNext();

      bool BrokenFile=false;
      if (!SkipSolid)
      {
        if (Arc.OldFormat && UINT32(DataIO.UnpFileCRC)==UINT32(Arc.NewLhd.FileCRC) ||
            !Arc.OldFormat && UINT32(DataIO.UnpFileCRC)==UINT32(Arc.NewLhd.FileCRC^0xffffffff))
        {
#ifndef GUI
          if (Command!='P' && Command!='I')
            mprintf("%s%s ",Cmd->DisablePercentage ? " ":"\b\b\b\b\b ",St(MOk));
#endif
        }
        else
        {
          char *BadArcName=/*(Arc.NewLhd.Flags & LHD_SPLIT_BEFORE) ? NULL:*/Arc.FileName;
          if (Arc.NewLhd.Flags & LHD_PASSWORD)
          {
            Log(BadArcName,St(MEncrBadCRC),ArcFileName);
          }
          else
          {
            Log(BadArcName,St(MCRCFailed),ArcFileName);
          }
          BrokenFile=true;
          ErrHandler.SetErrorCode(CRC_ERROR);
#ifdef RARDLL
          Cmd->DllError=ERAR_BAD_DATA;
#endif
          Alarm();
        }
      }
#ifndef GUI
      else
        mprintf("\b\b\b\b\b     ");
#endif

      if (!TestMode && (Command=='X' || Command=='E') &&
          !IsLink(Arc.NewLhd.FileAttr))
      {
#if defined(_WIN_32) || defined(_EMX)
        if (Cmd->ClearArc)
          Arc.NewLhd.FileAttr&=~FA_ARCH;
/*
        else
          Arc.NewLhd.FileAttr|=FA_ARCH; //set archive bit for unpacked files (file is not backed up)
*/
#endif
        if (!BrokenFile || Cmd->KeepBroken)
        {
          if (BrokenFile)
            CurFile.Truncate();
          CurFile.SetOpenFileTime(
            Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.NewLhd.mtime,
            Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.NewLhd.ctime,
            Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.NewLhd.atime);
          CurFile.Close();
#if defined(_WIN_32) && !defined(_WIN_CE) && !defined(SFX_MODULE)
          if (Cmd->SetCompressedAttr &&
              (Arc.NewLhd.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT())
            SetFileCompression(CurFile.FileName,CurFile.FileNameW,true);
#endif
          CurFile.SetCloseFileTime(
            Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.NewLhd.mtime,
            Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.NewLhd.atime);
          if (!Cmd->IgnoreGeneralAttr)
            SetFileAttr(CurFile.FileName,CurFile.FileNameW,Arc.NewLhd.FileAttr);
          PrevExtracted=true;
        }
      }
    }
  }
  if (ExactMatch)
    MatchedArgs++;
  if (DataIO.NextVolumeMissing || !Arc.IsOpened())
    return(false);
  if (!ExtrFile)
    if (!Arc.Solid)
      Arc.SeekToNext();
    else
      if (!SkipSolid)
        return(false);
  return(true);
}