Example #1
0
size_t Archive::ReadHeader15()
{
  RawRead Raw(this);

  bool Decrypt=Encrypted && CurBlockPos>(int64)SFXSize+SIZEOF_MARKHEAD3;

  if (Decrypt)
  {
#ifdef RAR_NOCRYPT // For rarext.dll and unrar_nocrypt.dll.
    return 0;
#else
    RequestArcPassword();

    byte Salt[SIZE_SALT30];
    if (Read(Salt,SIZE_SALT30)!=SIZE_SALT30)
    {
      UnexpEndArcMsg();
      return 0;
    }
    HeadersCrypt.SetCryptKeys(false,CRYPT_RAR30,&Cmd->Password,Salt,NULL,0,NULL,NULL);
    Raw.SetCrypt(&HeadersCrypt);
#endif
  }

  Raw.Read(SIZEOF_SHORTBLOCKHEAD);
  if (Raw.Size()==0)
  {
    UnexpEndArcMsg();
    return 0;
  }

  ShortBlock.HeadCRC=Raw.Get2();

  ShortBlock.Reset();

  uint HeaderType=Raw.Get1();
  ShortBlock.Flags=Raw.Get2();
  ShortBlock.SkipIfUnknown=(ShortBlock.Flags & SKIP_IF_UNKNOWN)!=0;
  ShortBlock.HeadSize=Raw.Get2();

  ShortBlock.HeaderType=(HEADER_TYPE)HeaderType;
  if (ShortBlock.HeadSize<SIZEOF_SHORTBLOCKHEAD)
  {
    BrokenHeaderMsg();
    return 0;
  }

  // For simpler further processing we map header types common
  // for RAR 1.5 and 5.0 formats to RAR 5.0 values. It does not include
  // header types specific for RAR 1.5 - 4.x only.
  switch(ShortBlock.HeaderType)
  {
    case HEAD3_MAIN:    ShortBlock.HeaderType=HEAD_MAIN;     break;
    case HEAD3_FILE:    ShortBlock.HeaderType=HEAD_FILE;     break;
    case HEAD3_SERVICE: ShortBlock.HeaderType=HEAD_SERVICE;  break;
    case HEAD3_ENDARC:  ShortBlock.HeaderType=HEAD_ENDARC;   break;
  }
  CurHeaderType=ShortBlock.HeaderType;

  if (ShortBlock.HeaderType==HEAD3_CMT)
  {
    // Old style (up to RAR 2.9) comment header embedded into main
    // or file header. We must not read the entire ShortBlock.HeadSize here
    // to not break the comment processing logic later.
    Raw.Read(SIZEOF_COMMHEAD-SIZEOF_SHORTBLOCKHEAD);
  }
  else
    if (ShortBlock.HeaderType==HEAD_MAIN && (ShortBlock.Flags & MHD_COMMENT)!=0)
    {
      // Old style (up to RAR 2.9) main archive comment embedded into
      // the main archive header found. While we can read the entire 
      // ShortBlock.HeadSize here and remove this part of "if", it would be
      // waste of memory, because we'll read and process this comment data
      // in other function anyway and we do not need them here now.
      Raw.Read(SIZEOF_MAINHEAD3-SIZEOF_SHORTBLOCKHEAD);
    }
    else
      Raw.Read(ShortBlock.HeadSize-SIZEOF_SHORTBLOCKHEAD);

  NextBlockPos=CurBlockPos+FullHeaderSize(ShortBlock.HeadSize);

  switch(ShortBlock.HeaderType)
  {
    case HEAD_MAIN:
      MainHead.Reset();
      *(BaseBlock *)&MainHead=ShortBlock;
      MainHead.HighPosAV=Raw.Get2();
      MainHead.PosAV=Raw.Get4();

      Volume=(MainHead.Flags & MHD_VOLUME)!=0;
      Solid=(MainHead.Flags & MHD_SOLID)!=0;
      Locked=(MainHead.Flags & MHD_LOCK)!=0;
      Protected=(MainHead.Flags & MHD_PROTECT)!=0;
      Encrypted=(MainHead.Flags & MHD_PASSWORD)!=0;
      Signed=MainHead.PosAV!=0 || MainHead.HighPosAV!=0;
      MainHead.CommentInHeader=(MainHead.Flags & MHD_COMMENT)!=0;
    
      // Only for encrypted 3.0+ archives. 2.x archives did not have this
      // flag, so for non-encrypted archives, we'll set it later based on
      // file attributes.
      FirstVolume=(MainHead.Flags & MHD_FIRSTVOLUME)!=0;

      NewNumbering=(MainHead.Flags & MHD_NEWNUMBERING)!=0;
      break;
    case HEAD_FILE:
    case HEAD_SERVICE:
      {
        bool FileBlock=ShortBlock.HeaderType==HEAD_FILE;
        FileHeader *hd=FileBlock ? &FileHead:&SubHead;
        hd->Reset();

        *(BaseBlock *)hd=ShortBlock;

        hd->SplitBefore=(hd->Flags & LHD_SPLIT_BEFORE)!=0;
        hd->SplitAfter=(hd->Flags & LHD_SPLIT_AFTER)!=0;
        hd->Encrypted=(hd->Flags & LHD_PASSWORD)!=0;
        hd->SaltSet=(hd->Flags & LHD_SALT)!=0;
        hd->Solid=FileBlock && (hd->Flags & LHD_SOLID)!=0;
        hd->SubBlock=!FileBlock && (hd->Flags & LHD_SOLID)!=0;
        hd->Dir=(hd->Flags & LHD_WINDOWMASK)==LHD_DIRECTORY;
        hd->WinSize=hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5);
        hd->CommentInHeader=(hd->Flags & LHD_COMMENT)!=0;
        hd->Version=(hd->Flags & LHD_VERSION)!=0;
        
        hd->DataSize=Raw.Get4();
        uint LowUnpSize=Raw.Get4();
        hd->HostOS=Raw.Get1();

        hd->FileHash.Type=HASH_CRC32;
        hd->FileHash.CRC32=Raw.Get4();

        uint FileTime=Raw.Get4();
        hd->UnpVer=Raw.Get1();
        hd->Method=Raw.Get1()-0x30;
        size_t NameSize=Raw.Get2();
        hd->FileAttr=Raw.Get4();

        hd->CryptMethod=CRYPT_NONE;
        if (hd->Encrypted)
          switch(hd->UnpVer)
          {
            case 13: hd->CryptMethod=CRYPT_RAR13; break;
            case 15: hd->CryptMethod=CRYPT_RAR15; break;
            case 20: 
            case 26: hd->CryptMethod=CRYPT_RAR20; break;
            default: hd->CryptMethod=CRYPT_RAR30; break;
          }

        hd->HSType=HSYS_UNKNOWN;
        if (hd->HostOS==HOST_UNIX || hd->HostOS==HOST_BEOS)
          hd->HSType=HSYS_UNIX;
        else
          if (hd->HostOS<HOST_MAX)
            hd->HSType=HSYS_WINDOWS;

        hd->RedirType=FSREDIR_NONE;

        // RAR 4.x Unix symlink.
        if (hd->HostOS==HOST_UNIX && (hd->FileAttr & 0xF000)==0xA000)
        {
          hd->RedirType=FSREDIR_UNIXSYMLINK;
          *hd->RedirName=0;
        }

        hd->Inherited=!FileBlock && (hd->SubFlags & SUBHEAD_FLAGS_INHERITED)!=0;
        
        hd->LargeFile=(hd->Flags & LHD_LARGE)!=0;

        uint HighPackSize,HighUnpSize;
        if (hd->LargeFile)
        {
          HighPackSize=Raw.Get4();
          HighUnpSize=Raw.Get4();
          hd->UnknownUnpSize=(LowUnpSize==0xffffffff && HighUnpSize==0xffffffff);
        }
        else 
        {
          HighPackSize=HighUnpSize=0;
          // UnpSize equal to 0xffffffff without LHD_LARGE flag indicates
          // that we do not know the unpacked file size and must unpack it
          // until we find the end of file marker in compressed data.
          hd->UnknownUnpSize=(LowUnpSize==0xffffffff);
        }
        hd->PackSize=INT32TO64(HighPackSize,hd->DataSize);
        hd->UnpSize=INT32TO64(HighUnpSize,LowUnpSize);
        if (hd->UnknownUnpSize)
          hd->UnpSize=INT64NDF;

        char FileName[NM*4];
        size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
        Raw.GetB((byte *)FileName,ReadNameSize);
        FileName[ReadNameSize]=0;

        if (FileBlock)
        {
          if ((hd->Flags & LHD_UNICODE)!=0)
          {
            EncodeFileName NameCoder;
            size_t Length=strlen(FileName);
            Length++;
            NameCoder.Decode(FileName,(byte *)FileName+Length,
                             NameSize-Length,hd->FileName,
                             ASIZE(hd->FileName));
          }
          else
            *hd->FileName=0;

          char AnsiName[NM];
          IntToExt(FileName,AnsiName,ASIZE(AnsiName));
          GetWideName(AnsiName,hd->FileName,hd->FileName,ASIZE(hd->FileName));

#ifndef SFX_MODULE
          ConvertNameCase(hd->FileName);
#endif
          ConvertFileHeader(hd);
        }
        else
        {
          CharToWide(FileName,hd->FileName,ASIZE(hd->FileName));

          // Calculate the size of optional data.
          int DataSize=int(hd->HeadSize-NameSize-SIZEOF_FILEHEAD3);
          if ((hd->Flags & LHD_SALT)!=0)
            DataSize-=SIZE_SALT30;

          if (DataSize>0)
          {
            // Here we read optional additional fields for subheaders.
            // They are stored after the file name and before salt.
            hd->SubData.Alloc(DataSize);
            Raw.GetB(&hd->SubData[0],DataSize);
            if (hd->CmpName(SUBHEAD_TYPE_RR))
            {
              byte *D=&hd->SubData[8];
              RecoverySize=D[0]+((uint)D[1]<<8)+((uint)D[2]<<16)+((uint)D[3]<<24);
              RecoverySize*=512; // Sectors to size.
              int64 CurPos=Tell();
              RecoveryPercent=ToPercent(RecoverySize,CurPos);
              // Round fractional percent exceeding .5 to upper value.
              if (ToPercent(RecoverySize+CurPos/200,CurPos)>RecoveryPercent)
                RecoveryPercent++;
            }
          }

          if (hd->CmpName(SUBHEAD_TYPE_CMT))
            MainComment=true;
        }
        if ((hd->Flags & LHD_SALT)!=0)
          Raw.GetB(hd->Salt,SIZE_SALT30);
        hd->mtime.SetDos(FileTime);
        if ((hd->Flags & LHD_EXTTIME)!=0)
        {
          ushort Flags=Raw.Get2();
          RarTime *tbl[4];
          tbl[0]=&FileHead.mtime;
          tbl[1]=&FileHead.ctime;
          tbl[2]=&FileHead.atime;
          tbl[3]=NULL; // Archive time is not used now.
          for (int I=0;I<4;I++)
          {
            RarTime *CurTime=tbl[I];
            uint rmode=Flags>>(3-I)*4;
            if ((rmode & 8)==0 || CurTime==NULL)
              continue;
            if (I!=0)
            {
              uint DosTime=Raw.Get4();
              CurTime->SetDos(DosTime);
            }
            RarLocalTime rlt;
            CurTime->GetLocal(&rlt);
            if (rmode & 4)
              rlt.Second++;
            rlt.Reminder=0;
            int count=rmode&3;
            for (int J=0;J<count;J++)
            {
              byte CurByte=Raw.Get1();
              rlt.Reminder|=(((uint)CurByte)<<((J+3-count)*8));
            }
            CurTime->SetLocal(&rlt);
          }
        }
        NextBlockPos+=hd->PackSize;
        bool CRCProcessedOnly=hd->CommentInHeader;
        ushort HeaderCRC=Raw.GetCRC15(CRCProcessedOnly);
        if (hd->HeadCRC!=HeaderCRC)
        {
          BrokenHeader=true;
          ErrHandler.SetErrorCode(RARX_WARNING);

          // If we have a broken encrypted header, we do not need to display
          // the error message here, because it will be displayed for such
          // headers later in this function. Also such headers are unlikely
          // to have anything sensible in file name field, so it is useless
          // to display the file name.
          if (!Decrypt)
            uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName);
        }
      }
      break;
    case HEAD_ENDARC:
      *(BaseBlock *)&EndArcHead=ShortBlock;
      EndArcHead.NextVolume=(EndArcHead.Flags & EARC_NEXT_VOLUME)!=0;
      EndArcHead.DataCRC=(EndArcHead.Flags & EARC_DATACRC)!=0;
      EndArcHead.RevSpace=(EndArcHead.Flags & EARC_REVSPACE)!=0;
      EndArcHead.StoreVolNumber=(EndArcHead.Flags & EARC_VOLNUMBER)!=0;
      if (EndArcHead.DataCRC)
        EndArcHead.ArcDataCRC=Raw.Get4();
      if (EndArcHead.StoreVolNumber)
        VolNumber=EndArcHead.VolNumber=Raw.Get2();
      break;
#ifndef SFX_MODULE
    case HEAD3_CMT:
      *(BaseBlock *)&CommHead=ShortBlock;
      CommHead.UnpSize=Raw.Get2();
      CommHead.UnpVer=Raw.Get1();
      CommHead.Method=Raw.Get1();
      CommHead.CommCRC=Raw.Get2();
      break;
    case HEAD3_SIGN:
      *(BaseBlock *)&SignHead=ShortBlock;
      SignHead.CreationTime=Raw.Get4();
      SignHead.ArcNameSize=Raw.Get2();
      SignHead.UserNameSize=Raw.Get2();
      break;
    case HEAD3_AV:
      *(BaseBlock *)&AVHead=ShortBlock;
      AVHead.UnpVer=Raw.Get1();
      AVHead.Method=Raw.Get1();
      AVHead.AVVer=Raw.Get1();
      AVHead.AVInfoCRC=Raw.Get4();
      break;
    case HEAD3_PROTECT:
      *(BaseBlock *)&ProtectHead=ShortBlock;
      ProtectHead.DataSize=Raw.Get4();
      ProtectHead.Version=Raw.Get1();
      ProtectHead.RecSectors=Raw.Get2();
      ProtectHead.TotalBlocks=Raw.Get4();
      Raw.GetB(ProtectHead.Mark,8);
      NextBlockPos+=ProtectHead.DataSize;
      RecoverySize=ProtectHead.RecSectors*512;
      break;
    case HEAD3_OLDSERVICE:
      *(BaseBlock *)&SubBlockHead=ShortBlock;
      SubBlockHead.DataSize=Raw.Get4();
      NextBlockPos+=SubBlockHead.DataSize;
      SubBlockHead.SubType=Raw.Get2();
      SubBlockHead.Level=Raw.Get1();
      switch(SubBlockHead.SubType)
      {
        case UO_HEAD:
          *(SubBlockHeader *)&UOHead=SubBlockHead;
          UOHead.OwnerNameSize=Raw.Get2();
          UOHead.GroupNameSize=Raw.Get2();
          if (UOHead.OwnerNameSize>=ASIZE(UOHead.OwnerName))
            UOHead.OwnerNameSize=ASIZE(UOHead.OwnerName)-1;
          if (UOHead.GroupNameSize>=ASIZE(UOHead.GroupName))
            UOHead.GroupNameSize=ASIZE(UOHead.GroupName)-1;
          Raw.GetB(UOHead.OwnerName,UOHead.OwnerNameSize);
          Raw.GetB(UOHead.GroupName,UOHead.GroupNameSize);
          UOHead.OwnerName[UOHead.OwnerNameSize]=0;
          UOHead.GroupName[UOHead.GroupNameSize]=0;
          break;
        case MAC_HEAD:
          *(SubBlockHeader *)&MACHead=SubBlockHead;
          MACHead.fileType=Raw.Get4();
          MACHead.fileCreator=Raw.Get4();
          break;
        case EA_HEAD:
        case BEEA_HEAD:
        case NTACL_HEAD:
          *(SubBlockHeader *)&EAHead=SubBlockHead;
          EAHead.UnpSize=Raw.Get4();
          EAHead.UnpVer=Raw.Get1();
          EAHead.Method=Raw.Get1();
          EAHead.EACRC=Raw.Get4();
          break;
        case STREAM_HEAD:
          *(SubBlockHeader *)&StreamHead=SubBlockHead;
          StreamHead.UnpSize=Raw.Get4();
          StreamHead.UnpVer=Raw.Get1();
          StreamHead.Method=Raw.Get1();
          StreamHead.StreamCRC=Raw.Get4();
          StreamHead.StreamNameSize=Raw.Get2();
          if (StreamHead.StreamNameSize>=ASIZE(StreamHead.StreamName))
            StreamHead.StreamNameSize=ASIZE(StreamHead.StreamName)-1;
          Raw.GetB(StreamHead.StreamName,StreamHead.StreamNameSize);
          StreamHead.StreamName[StreamHead.StreamNameSize]=0;
          break;
      }
      break;
#endif
    default:
      if (ShortBlock.Flags & LONG_BLOCK)
        NextBlockPos+=Raw.Get4();
      break;
  }
Example #2
0
size_t Archive::ReadHeader()
{
  // Once we failed to decrypt an encrypted block, there is no reason to
  // attempt to do it further. We'll never be successful and only generate
  // endless errors.
  if (FailedHeaderDecryption)
    return 0;

  CurBlockPos=Tell();

#ifndef SFX_MODULE
  if (OldFormat)
    return(ReadOldHeader());
#endif

  RawRead Raw(this);

  bool Decrypt=Encrypted && CurBlockPos>=(int64)SFXSize+SIZEOF_MARKHEAD+SIZEOF_NEWMHD;

  if (Decrypt)
  {
#if defined(SHELL_EXT) || defined(RAR_NOCRYPT)
    return(0);
#else
    if (Read(HeadersSalt,SALT_SIZE)!=SALT_SIZE)
    {
      UnexpEndArcMsg();
      return(0);
    }
    if (*Cmd->Password==0)
    {
#ifdef RARDLL
      char PasswordA[MAXPASSWORD];
      if (Cmd->Callback==NULL ||
          Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)PasswordA,ASIZE(PasswordA))==-1)
      {
        Close();
        //ErrHandler.Exit(USER_BREAK); original
        ErrHandler.Exit(NO_PASSWORD_ERROR);
      }
      GetWideName(PasswordA,NULL,Cmd->Password,ASIZE(Cmd->Password));
#else
      if (!GetPassword(PASSWORD_ARCHIVE,FileName,FileNameW,Cmd->Password,ASIZE(Cmd->Password)))
      {
        Close();
        ErrHandler.Exit(USER_BREAK);
      }
#endif
    }
    HeadersCrypt.SetCryptKeys(Cmd->Password,HeadersSalt,false,false,NewMhd.EncryptVer>=36);
    Raw.SetCrypt(&HeadersCrypt);
#endif
  }

  Raw.Read(SIZEOF_SHORTBLOCKHEAD);
  if (Raw.Size()==0)
  {
    UnexpEndArcMsg();
    return(0);
  }

  Raw.Get(ShortBlock.HeadCRC);
  byte HeadType;
  Raw.Get(HeadType);
  ShortBlock.HeadType=(HEADER_TYPE)HeadType;
  Raw.Get(ShortBlock.Flags);
  Raw.Get(ShortBlock.HeadSize);
  if (ShortBlock.HeadSize<SIZEOF_SHORTBLOCKHEAD)
  {
#ifndef SHELL_EXT
    Log(FileName,St(MLogFileHead),"???");
#endif
    BrokenFileHeader=true;
    ErrHandler.SetErrorCode(CRC_ERROR);
    return(0);
  }

  if (ShortBlock.HeadType==COMM_HEAD)
  {
    // Old style (up to RAR 2.9) comment header embedded into main
    // or file header. We must not read the entire ShortBlock.HeadSize here
    // to not break the comment processing logic later.
    Raw.Read(SIZEOF_COMMHEAD-SIZEOF_SHORTBLOCKHEAD);
  }
  else
    if (ShortBlock.HeadType==MAIN_HEAD && (ShortBlock.Flags & MHD_COMMENT)!=0)
    {
      // Old style (up to RAR 2.9) main archive comment embedded into
      // the main archive header found. While we can read the entire 
      // ShortBlock.HeadSize here and remove this part of "if", it would be
      // waste of memory, because we'll read and process this comment data
      // in other function anyway and we do not need them here now.
      Raw.Read(SIZEOF_NEWMHD-SIZEOF_SHORTBLOCKHEAD);
    }
    else
      Raw.Read(ShortBlock.HeadSize-SIZEOF_SHORTBLOCKHEAD);

  NextBlockPos=CurBlockPos+ShortBlock.HeadSize;

  switch(ShortBlock.HeadType)
  {
    case MAIN_HEAD:
      *(BaseBlock *)&NewMhd=ShortBlock;
      Raw.Get(NewMhd.HighPosAV);
      Raw.Get(NewMhd.PosAV);
      if (NewMhd.Flags & MHD_ENCRYPTVER)
        Raw.Get(NewMhd.EncryptVer);
      break;
    case ENDARC_HEAD:
      *(BaseBlock *)&EndArcHead=ShortBlock;
      if (EndArcHead.Flags & EARC_DATACRC)
        Raw.Get(EndArcHead.ArcDataCRC);
      if (EndArcHead.Flags & EARC_VOLNUMBER)
        Raw.Get(EndArcHead.VolNumber);
      break;
    case FILE_HEAD:
    case NEWSUB_HEAD:
      {
        FileHeader *hd=ShortBlock.HeadType==FILE_HEAD ? &NewLhd:&SubHead;
        *(BaseBlock *)hd=ShortBlock;
        Raw.Get(hd->PackSize);
        Raw.Get(hd->UnpSize);
        Raw.Get(hd->HostOS);
        Raw.Get(hd->FileCRC);
        Raw.Get(hd->FileTime);
        Raw.Get(hd->UnpVer);
        Raw.Get(hd->Method);
        Raw.Get(hd->NameSize);
        Raw.Get(hd->FileAttr);
        if (hd->Flags & LHD_LARGE)
        {
          Raw.Get(hd->HighPackSize);
          Raw.Get(hd->HighUnpSize);
        }
        else 
        {
          hd->HighPackSize=hd->HighUnpSize=0;
          if (hd->UnpSize==0xffffffff)
          {
            // UnpSize equal to 0xffffffff without LHD_LARGE flag indicates
            // that we do not know the unpacked file size and must unpack it
            // until we find the end of file marker in compressed data.
            hd->UnpSize=(uint)(INT64NDF);
            hd->HighUnpSize=(uint)(INT64NDF>>32);
          }
        }
        hd->FullPackSize=INT32TO64(hd->HighPackSize,hd->PackSize);
        hd->FullUnpSize=INT32TO64(hd->HighUnpSize,hd->UnpSize);

        char FileName[NM*4];
        size_t NameSize=Min(hd->NameSize,sizeof(FileName)-1);
        Raw.Get((byte *)FileName,NameSize);
        FileName[NameSize]=0;

        strncpyz(hd->FileName,FileName,ASIZE(hd->FileName));

        if (hd->HeadType==NEWSUB_HEAD)
        {
          // Let's calculate the size of optional data.
          int DataSize=hd->HeadSize-hd->NameSize-SIZEOF_NEWLHD;
          if (hd->Flags & LHD_SALT)
            DataSize-=SALT_SIZE;
          if (DataSize>0)
          {
            // Here we read optional additional fields for subheaders.
            // They are stored after the file name and before salt.
            hd->SubData.Alloc(DataSize);
            Raw.Get(&hd->SubData[0],DataSize);
            if (hd->CmpName(SUBHEAD_TYPE_RR))
            {
              byte *D=&hd->SubData[8];
              RecoverySectors=D[0]+((uint)D[1]<<8)+((uint)D[2]<<16)+((uint)D[3]<<24);
            }
          }
        }
        else
          if (hd->HeadType==FILE_HEAD)
          {
            if (hd->Flags & LHD_UNICODE)
            {
              EncodeFileName NameCoder;
              size_t Length=strlen(FileName);
              if (Length==hd->NameSize)
              {
                UtfToWide(FileName,hd->FileNameW,sizeof(hd->FileNameW)/sizeof(hd->FileNameW[0])-1);
                WideToChar(hd->FileNameW,hd->FileName,sizeof(hd->FileName)/sizeof(hd->FileName[0])-1);
                ExtToInt(hd->FileName,hd->FileName);
              }
              else
              {
                Length++;
                NameCoder.Decode(FileName,(byte *)FileName+Length,
                                 hd->NameSize-Length,hd->FileNameW,
                                 sizeof(hd->FileNameW)/sizeof(hd->FileNameW[0]));
              }
              if (*hd->FileNameW==0)
                hd->Flags &= ~LHD_UNICODE;
            }
            else
              *hd->FileNameW=0;
#ifndef SFX_MODULE
            ConvertNameCase(hd->FileName);
            ConvertNameCase(hd->FileNameW);
#endif
            ConvertUnknownHeader();
          }
        if (hd->Flags & LHD_SALT)
          Raw.Get(hd->Salt,SALT_SIZE);
        hd->mtime.SetDos(hd->FileTime);
        hd->ctime.Reset();
        hd->atime.Reset();
        hd->arctime.Reset();
        if (hd->Flags & LHD_EXTTIME)
        {
          ushort Flags;
          Raw.Get(Flags);
          RarTime *tbl[4];
          tbl[0]=&NewLhd.mtime;
          tbl[1]=&NewLhd.ctime;
          tbl[2]=&NewLhd.atime;
          tbl[3]=&NewLhd.arctime;
          for (int I=0;I<4;I++)
          {
            RarTime *CurTime=tbl[I];
            uint rmode=Flags>>(3-I)*4;
            if ((rmode & 8)==0)
              continue;
            if (I!=0)
            {
              uint DosTime;
              Raw.Get(DosTime);
              CurTime->SetDos(DosTime);
            }
            RarLocalTime rlt;
            CurTime->GetLocal(&rlt);
            if (rmode & 4)
              rlt.Second++;
            rlt.Reminder=0;
            int count=rmode&3;
            for (int J=0;J<count;J++)
            {
              byte CurByte;
              Raw.Get(CurByte);
              rlt.Reminder|=(((uint)CurByte)<<((J+3-count)*8));
            }
            CurTime->SetLocal(&rlt);
          }
        }
        NextBlockPos+=hd->FullPackSize;
        bool CRCProcessedOnly=(hd->Flags & LHD_COMMENT)!=0;
        HeaderCRC=~Raw.GetCRC(CRCProcessedOnly)&0xffff;
        if (hd->HeadCRC!=HeaderCRC)
        {
          if (hd->HeadType==NEWSUB_HEAD && strlen(hd->FileName)<ASIZE(hd->FileName)-5)
            strcat(hd->FileName,"- ???");
          BrokenFileHeader=true;
          ErrHandler.SetErrorCode(WARNING);

          // If we have a broken encrypted header, we do not need to display
          // the error message here, because it will be displayed for such
          // headers later in this function. Also such headers are unlikely
          // to have anything sensible in file name field, so it is useless
          // to display the file name.
          bool EncBroken=Decrypt && ShortBlock.HeadCRC!=(~Raw.GetCRC(false)&0xffff);
          if (!EncBroken)
          {
#ifndef SHELL_EXT
            Log(Archive::FileName,St(MLogFileHead),IntNameToExt(hd->FileName));
            Alarm();
#endif
          }
        }
      }
Example #3
0
int Archive::ReadHeader()
{
  CurBlockPos=Tell();

#ifndef SFX_MODULE
  if (OldFormat)
    return(ReadOldHeader());
#endif

  RawRead Raw(this);

  bool Decrypt=Encrypted && CurBlockPos>=SFXSize+SIZEOF_MARKHEAD+SIZEOF_NEWMHD;

  if (Decrypt)
  {
#if defined(SHELL_EXT) || defined(NOCRYPT)
    return(0);
#else
    if (Read(HeadersSalt,SALT_SIZE)!=SALT_SIZE)
      return(0);
    if (*Cmd->Password==0)
#ifdef RARDLL
      if (Cmd->Callback==NULL ||
          Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)Cmd->Password,sizeof(Cmd->Password))==-1)
      {
        Close();
        ErrHandler.Exit(USER_BREAK);
      }

#else
      if (!GetPassword(PASSWORD_ARCHIVE,FileName,Cmd->Password,sizeof(Cmd->Password)))
      {
        Close();
        ErrHandler.Exit(USER_BREAK);
      }
#endif
    HeadersCrypt.SetCryptKeys(Cmd->Password,HeadersSalt,false,false,NewMhd.EncryptVer>=36);
    Raw.SetCrypt(&HeadersCrypt);
#endif
  }

  Raw.Read(SIZEOF_SHORTBLOCKHEAD);
  if (Raw.Size()==0)
  {
    Int64 ArcSize=FileLength();
    if (CurBlockPos>ArcSize || NextBlockPos>ArcSize)
    {
  #ifndef SHELL_EXT
      Log(FileName,St(MLogUnexpEOF));
  #endif
      ErrHandler.SetErrorCode(WARNING);
    }
    return(0);
  }

  Raw.Get(ShortBlock.HeadCRC);
  byte HeadType;
  Raw.Get(HeadType);
  ShortBlock.HeadType=(HEADER_TYPE)HeadType;
  Raw.Get(ShortBlock.Flags);
  Raw.Get(ShortBlock.HeadSize);
  if (ShortBlock.HeadSize<SIZEOF_SHORTBLOCKHEAD)
  {
#ifndef SHELL_EXT
    Log(FileName,St(MLogFileHead),"???");
#endif
    BrokenFileHeader=true;
    ErrHandler.SetErrorCode(CRC_ERROR);
    return(0);
  }

  if (ShortBlock.HeadType==COMM_HEAD)
    Raw.Read(SIZEOF_COMMHEAD-SIZEOF_SHORTBLOCKHEAD);
  else
    if (ShortBlock.HeadType==MAIN_HEAD && (ShortBlock.Flags & MHD_COMMENT)!=0)
      Raw.Read(SIZEOF_NEWMHD-SIZEOF_SHORTBLOCKHEAD);
    else
      Raw.Read(ShortBlock.HeadSize-SIZEOF_SHORTBLOCKHEAD);

  NextBlockPos=CurBlockPos+ShortBlock.HeadSize;

  switch(ShortBlock.HeadType)
  {
    case MAIN_HEAD:
      *(BaseBlock *)&NewMhd=ShortBlock;
      Raw.Get(NewMhd.HighPosAV);
      Raw.Get(NewMhd.PosAV);
      if (NewMhd.Flags & MHD_ENCRYPTVER)
        Raw.Get(NewMhd.EncryptVer);
      break;
    case ENDARC_HEAD:
      *(BaseBlock *)&EndArcHead=ShortBlock;
      if (EndArcHead.Flags & EARC_DATACRC)
        Raw.Get(EndArcHead.ArcDataCRC);
      if (EndArcHead.Flags & EARC_VOLNUMBER)
        Raw.Get(EndArcHead.VolNumber);
      break;
    case FILE_HEAD:
    case NEWSUB_HEAD:
      {
        FileHeader *hd=ShortBlock.HeadType==FILE_HEAD ? &NewLhd:&SubHead;
        *(BaseBlock *)hd=ShortBlock;
        Raw.Get(hd->PackSize);
        Raw.Get(hd->UnpSize);
        Raw.Get(hd->HostOS);
        Raw.Get(hd->FileCRC);
        Raw.Get(hd->FileTime);
        Raw.Get(hd->UnpVer);
        Raw.Get(hd->Method);
        Raw.Get(hd->NameSize);
        Raw.Get(hd->FileAttr);
        if (hd->Flags & LHD_LARGE)
        {
          Raw.Get(hd->HighPackSize);
          Raw.Get(hd->HighUnpSize);
        }
        else 
        {
          hd->HighPackSize=hd->HighUnpSize=0;
          if (hd->UnpSize==0xffffffff)
          {
            hd->UnpSize=int64to32(INT64MAX);
            hd->HighUnpSize=int64to32(INT64MAX>>32);
          }
        }
        hd->FullPackSize=int32to64(hd->HighPackSize,hd->PackSize);
        hd->FullUnpSize=int32to64(hd->HighUnpSize,hd->UnpSize);

        char FileName[NM*4];
        int NameSize=Min(hd->NameSize,sizeof(FileName)-1);
        Raw.Get((byte *)FileName,NameSize);
        FileName[NameSize]=0;

        strncpyz(hd->FileName,FileName,ASIZE(hd->FileName));

        if (hd->HeadType==NEWSUB_HEAD)
        {
          int DataSize=hd->HeadSize-hd->NameSize-SIZEOF_NEWLHD;
          if (hd->Flags & LHD_SALT)
            DataSize-=SALT_SIZE;
          if (DataSize>0)
          {
            hd->SubData.Alloc(DataSize);
            Raw.Get(&hd->SubData[0],DataSize);
            if (hd->CmpName(SUBHEAD_TYPE_RR))
            {
              byte *D=&hd->SubData[8];
              RecoverySectors=D[0]+((uint)D[1]<<8)+((uint)D[2]<<16)+((uint)D[3]<<24);
            }
          }
        }
        else
          if (hd->HeadType==FILE_HEAD)
          {
            if (hd->Flags & LHD_UNICODE)
            {
              EncodeFileName NameCoder;
              int Length=strlen(FileName);
              if (Length==hd->NameSize)
              {
                UtfToWide(FileName,hd->FileNameW,sizeof(hd->FileNameW)/sizeof(hd->FileNameW[0])-1);
                WideToChar(hd->FileNameW,hd->FileName,sizeof(hd->FileName)/sizeof(hd->FileName[0])-1);
                ExtToInt(hd->FileName,hd->FileName);
              }
              else
              {
                Length++;
                NameCoder.Decode(FileName,(byte *)FileName+Length,
                                 hd->NameSize-Length,hd->FileNameW,
                                 sizeof(hd->FileNameW)/sizeof(hd->FileNameW[0]));
              }
              if (*hd->FileNameW==0)
                hd->Flags &= ~LHD_UNICODE;
            }
            else
              *hd->FileNameW=0;
#ifndef SFX_MODULE
            ConvertNameCase(hd->FileName);
            ConvertNameCase(hd->FileNameW);
#endif
            ConvertUnknownHeader();
          }
        if (hd->Flags & LHD_SALT)
          Raw.Get(hd->Salt,SALT_SIZE);
        hd->mtime.SetDos(hd->FileTime);
        hd->ctime.Reset();
        hd->atime.Reset();
        hd->arctime.Reset();
        if (hd->Flags & LHD_EXTTIME)
        {
          ushort Flags;
          Raw.Get(Flags);
          RarTime *tbl[4];
          tbl[0]=&NewLhd.mtime;
          tbl[1]=&NewLhd.ctime;
          tbl[2]=&NewLhd.atime;
          tbl[3]=&NewLhd.arctime;
          for (int I=0;I<4;I++)
          {
            RarTime *CurTime=tbl[I];
            uint rmode=Flags>>(3-I)*4;
            if ((rmode & 8)==0)
              continue;
            if (I!=0)
            {
              uint DosTime;
              Raw.Get(DosTime);
              CurTime->SetDos(DosTime);
            }
            RarLocalTime rlt;
            CurTime->GetLocal(&rlt);
            if (rmode & 4)
              rlt.Second++;
            rlt.Reminder=0;
            int count=rmode&3;
            for (int J=0;J<count;J++)
            {
              byte CurByte;
              Raw.Get(CurByte);
              rlt.Reminder|=(((uint)CurByte)<<((J+3-count)*8));
            }
            CurTime->SetLocal(&rlt);
          }
        }
        NextBlockPos+=hd->FullPackSize;
        bool CRCProcessedOnly=(hd->Flags & LHD_COMMENT)!=0;
        HeaderCRC=~Raw.GetCRC(CRCProcessedOnly)&0xffff;
        if (hd->HeadCRC!=HeaderCRC)
        {
          if (hd->HeadType==NEWSUB_HEAD)
            strcat(hd->FileName,"- ???");
          BrokenFileHeader=true;
          ErrHandler.SetErrorCode(WARNING);
#ifndef SHELL_EXT
          Log(Archive::FileName,St(MLogFileHead),IntNameToExt(hd->FileName));
          Alarm();
#endif
        }
      }
Example #4
0
int Archive::ReadHeader()
{
  CurBlockPos=Tell();

#ifndef SFX_MODULE
  if (OldFormat)
    return(ReadOldHeader());
#endif

  RawRead Raw(this);

  bool Decrypt=Encrypted && CurBlockPos>=SFXSize+SIZEOF_MARKHEAD+SIZEOF_NEWMHD;

  if (Decrypt)
  {
#if defined(SHELL_EXT) || defined(NOCRYPT)
    return(0);
#else
    if (Read(HeadersSalt,SALT_SIZE)!=SALT_SIZE)
      return(0);
    if (*Cmd->Password==0)
#ifdef RARDLL
      if (Cmd->Callback==NULL ||
          Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LONG)Cmd->Password,sizeof(Cmd->Password))==-1)
      {
        Close();
        ErrHandler.Exit(USER_BREAK);
      }

#else
      if (!GetPassword(PASSWORD_ARCHIVE,FileName,Cmd->Password,sizeof(Cmd->Password)))
      {
        Close();
        ErrHandler.Exit(USER_BREAK);
      }
#endif
    HeadersCrypt.SetCryptKeys(Cmd->Password,HeadersSalt,false);
    Raw.SetCrypt(&HeadersCrypt);
#endif
  }

  Raw.Read(SIZEOF_SHORTBLOCKHEAD);
  if (Raw.Size()==0)
  {
    Int64 ArcSize=FileLength();
    if (CurBlockPos>ArcSize || NextBlockPos>ArcSize)
    {
  #ifndef SHELL_EXT
      Log(FileName,St(MLogUnexpEOF));
  #endif
      ErrHandler.SetErrorCode(WARNING);
    }
    return(0);
  }

  Raw.Get(ShortBlock.HeadCRC);
  unsigned char HeadType;
  Raw.Get(HeadType);
  ShortBlock.HeadType=(HEADER_TYPE)HeadType;
  Raw.Get(ShortBlock.Flags);
  Raw.Get(ShortBlock.HeadSize);
  if (ShortBlock.HeadSize<SIZEOF_SHORTBLOCKHEAD)
  {
#ifndef SHELL_EXT
    Log(FileName,St(MLogFileHead),"???");
#endif
    BrokenFileHeader=true;
    ErrHandler.SetErrorCode(CRC_ERROR);
    return(0);
  }

  if (ShortBlock.HeadType==COMM_HEAD)
    Raw.Read(SIZEOF_COMMHEAD-SIZEOF_SHORTBLOCKHEAD);
  else
    if (ShortBlock.HeadType==MAIN_HEAD && (ShortBlock.Flags & MHD_COMMENT)!=0)
      Raw.Read(SIZEOF_NEWMHD-SIZEOF_SHORTBLOCKHEAD);
    else
      Raw.Read(ShortBlock.HeadSize-SIZEOF_SHORTBLOCKHEAD);

  NextBlockPos=CurBlockPos+ShortBlock.HeadSize;

  switch(ShortBlock.HeadType)
  {
    case MAIN_HEAD:
      *(BaseBlock *)&NewMhd=ShortBlock;
      Raw.Get(NewMhd.HighPosAV);
      Raw.Get(NewMhd.PosAV);
      break;
    case ENDARC_HEAD:
      *(BaseBlock *)&EndArcHead=ShortBlock;
      if (EndArcHead.Flags & EARC_DATACRC)
        Raw.Get(EndArcHead.ArcDataCRC);
      break;
    case FILE_HEAD:
    case NEWSUB_HEAD:
      {
        FileHeader *hd=ShortBlock.HeadType==FILE_HEAD ? &NewLhd:&SubHead;
        *(BaseBlock *)hd=ShortBlock;
        Raw.Get(hd->PackSize);
        Raw.Get(hd->UnpSize);
        Raw.Get(hd->HostOS);
        Raw.Get(hd->FileCRC);
        Raw.Get(hd->FileTime);
        Raw.Get(hd->UnpVer);
        Raw.Get(hd->Method);
        Raw.Get(hd->NameSize);
        Raw.Get(hd->FileAttr);
        if (hd->Flags & LHD_LARGE)
        {
          Raw.Get(hd->HighPackSize);
          Raw.Get(hd->HighUnpSize);
        }
        else 
          hd->HighPackSize=hd->HighUnpSize=0;
        hd->FullPackSize=int32to64(hd->HighPackSize,hd->PackSize);
        hd->FullUnpSize=int32to64(hd->HighUnpSize,hd->UnpSize);

        char FileName[NM*4];
        int NameSize=Min(hd->NameSize,sizeof(FileName)-1);
        Raw.Get((unsigned char *)FileName,NameSize);
        FileName[NameSize]=0;

        strncpy(hd->FileName,FileName,sizeof(hd->FileName));
        hd->FileName[sizeof(hd->FileName)-1]=0;

        if (hd->HeadType==NEWSUB_HEAD)
        {
          int DataSize=hd->HeadSize-hd->NameSize-SIZEOF_NEWLHD;
          if (hd->Flags & LHD_SALT)
            DataSize-=SALT_SIZE;
          if (DataSize>0)
          {
            hd->SubData.Alloc(DataSize);
            Raw.Get(&hd->SubData[0],DataSize);
            if (hd->CmpName(SUBHEAD_TYPE_RR))
            {
              unsigned char *D=&hd->SubData[8];
              RecoverySectors=D[0]+((unsigned int)D[1]<<8)+((unsigned int)D[2]<<16)+((unsigned int)D[3]<<24);
            }
          }
        }
        else
          if (hd->HeadType==FILE_HEAD)
          {
            if (hd->Flags & LHD_UNICODE)
            {
              EncodeFileName NameCoder;
              int Length=strlen(FileName)+1;
              NameCoder.Decode(FileName,(unsigned char *)FileName+Length,
                               hd->NameSize-Length,hd->FileNameW,
                               sizeof(hd->FileNameW)/sizeof(hd->FileNameW[0]));
              if (*hd->FileNameW==0)
                hd->Flags &= ~LHD_UNICODE;
            }
            else
              *hd->FileNameW=0;
#ifndef SFX_MODULE
            ConvertNameCase(hd->FileName);
            ConvertNameCase(hd->FileNameW);
#endif
            ConvertUnknownHeader();
          }
        if (hd->Flags & LHD_SALT)
          Raw.Get(hd->Salt,SALT_SIZE);
        hd->mtime.SetDos(hd->FileTime);
        hd->ctime.Reset();
        hd->atime.Reset();
        hd->arctime.Reset();
        if (hd->Flags & LHD_EXTTIME)
        {
          unsigned short Flags;
          Raw.Get(Flags);
          RarTime *tbl[4];
          tbl[0]=&NewLhd.mtime;
          tbl[1]=&NewLhd.ctime;
          tbl[2]=&NewLhd.atime;
          tbl[3]=&NewLhd.arctime;
          for (int I=0;I<4;I++)
          {
            RarTime *CurTime=tbl[I];
            unsigned int rmode=Flags>>(3-I)*4;
            if ((rmode & 8)==0)
              continue;
            if (I!=0)
            {
              unsigned int DosTime;
              Raw.Get(DosTime);
              CurTime->SetDos(DosTime);
            }
            RarLocalTime rlt;
            CurTime->GetLocal(&rlt);
            if (rmode & 4)
              rlt.Second++;
            rlt.Reminder=0;
            int count=rmode&3;
            for (int J=0;J<count;J++)
            {
              unsigned char CurByte;
              Raw.Get(CurByte);
              rlt.Reminder|=(((unsigned int)CurByte)<<((J+3-count)*8));
            }
            CurTime->SetLocal(&rlt);
          }
        }
        NextBlockPos+=hd->FullPackSize;
        bool CRCProcessedOnly=(hd->Flags & LHD_COMMENT)!=0;
        HeaderCRC=~Raw.GetCRC(CRCProcessedOnly)&0xffff;
        if (hd->HeadCRC!=HeaderCRC)
        {
          if (hd->HeadType==NEWSUB_HEAD)
            strcat(hd->FileName,"- ???");
          BrokenFileHeader=true;
          ErrHandler.SetErrorCode(WARNING);
#ifndef SHELL_EXT
          Log(Archive::FileName,St(MLogFileHead),IntNameToExt(hd->FileName));
          Alarm();
#endif
        }
      }
      break;
#ifndef SFX_MODULE
    case COMM_HEAD:
      *(BaseBlock *)&CommHead=ShortBlock;
      Raw.Get(CommHead.UnpSize);
      Raw.Get(CommHead.UnpVer);
      Raw.Get(CommHead.Method);
      Raw.Get(CommHead.CommCRC);
      break;
    case SIGN_HEAD:
      *(BaseBlock *)&SignHead=ShortBlock;
      Raw.Get(SignHead.CreationTime);
      Raw.Get(SignHead.ArcNameSize);
      Raw.Get(SignHead.UserNameSize);
      break;
    case AV_HEAD:
      *(BaseBlock *)&AVHead=ShortBlock;
      Raw.Get(AVHead.UnpVer);
      Raw.Get(AVHead.Method);
      Raw.Get(AVHead.AVVer);
      Raw.Get(AVHead.AVInfoCRC);
      break;
    case PROTECT_HEAD:
      *(BaseBlock *)&ProtectHead=ShortBlock;
      Raw.Get(ProtectHead.DataSize);
      Raw.Get(ProtectHead.Version);
      Raw.Get(ProtectHead.RecSectors);
      Raw.Get(ProtectHead.TotalBlocks);
      Raw.Get(ProtectHead.Mark,8);
      NextBlockPos+=ProtectHead.DataSize;
      RecoverySectors=ProtectHead.RecSectors;
      break;
    case SUB_HEAD:
      *(BaseBlock *)&SubBlockHead=ShortBlock;
      Raw.Get(SubBlockHead.DataSize);
      NextBlockPos+=SubBlockHead.DataSize;
      Raw.Get(SubBlockHead.SubType);
      Raw.Get(SubBlockHead.Level);
      switch(SubBlockHead.SubType)
      {
        case UO_HEAD:
          *(SubBlockHeader *)&UOHead=SubBlockHead;
          Raw.Get(UOHead.OwnerNameSize);
          Raw.Get(UOHead.GroupNameSize);
          Raw.Get((unsigned char *)UOHead.OwnerName,UOHead.OwnerNameSize);
          Raw.Get((unsigned char *)UOHead.GroupName,UOHead.GroupNameSize);
          if (UOHead.OwnerNameSize>NM-1)
            UOHead.OwnerNameSize=NM-1;
          if (UOHead.GroupNameSize>NM-1)
            UOHead.GroupNameSize=NM-1;
          UOHead.OwnerName[UOHead.OwnerNameSize]=0;
          UOHead.GroupName[UOHead.GroupNameSize]=0;
          break;
        case MAC_HEAD:
          *(SubBlockHeader *)&MACHead=SubBlockHead;
          Raw.Get(MACHead.fileType);
          Raw.Get(MACHead.fileCreator);
          break;
        case EA_HEAD:
        case BEEA_HEAD:
        case NTACL_HEAD:
          *(SubBlockHeader *)&EAHead=SubBlockHead;
          Raw.Get(EAHead.UnpSize);
          Raw.Get(EAHead.UnpVer);
          Raw.Get(EAHead.Method);
          Raw.Get(EAHead.EACRC);
          break;
        case STREAM_HEAD:
          *(SubBlockHeader *)&StreamHead=SubBlockHead;
          Raw.Get(StreamHead.UnpSize);
          Raw.Get(StreamHead.UnpVer);
          Raw.Get(StreamHead.Method);
          Raw.Get(StreamHead.StreamCRC);
          Raw.Get(StreamHead.StreamNameSize);
          if (StreamHead.StreamNameSize>NM-1)
            StreamHead.StreamNameSize=NM-1;
          Raw.Get((unsigned char *)StreamHead.StreamName,StreamHead.StreamNameSize);
          StreamHead.StreamName[StreamHead.StreamNameSize]=0;
          break;
      }
      break;
#endif
    default:
      if (ShortBlock.Flags & LONG_BLOCK)
      {
        unsigned int DataSize;
        Raw.Get(DataSize);
        NextBlockPos+=DataSize;
      }
      break;
  }