bool EnumConfigPaths(uint Number,wchar *Path,size_t MaxSize,bool Create) { #ifdef _UNIX static const wchar *ConfPath[]={ L"/etc", L"/etc/rar", L"/usr/lib", L"/usr/local/lib", L"/usr/local/etc" }; if (Number==0) { char *EnvStr=getenv("HOME"); if (EnvStr!=NULL) GetWideName(EnvStr,NULL,Path,MaxSize); else wcsncpyz(Path, ConfPath[0], MaxSize); return true; } Number--; if (Number>=ASIZE(ConfPath)) return false; wcsncpyz(Path,ConfPath[Number], MaxSize); return true; #elif defined(_WIN_ALL) if (Number>1) return false; if (Number==0) GetRarDataPath(Path,MaxSize,Create); else { GetModuleFileName(NULL,Path,(DWORD)MaxSize); RemoveNameFromPath(Path); } return true; #else return false; #endif }
bool CmdExtract::ExtrDllGetPassword() { if (!Cmd->Password.IsSet()) { if (Cmd->Callback!=NULL) { wchar PasswordW[MAXPASSWORD]; *PasswordW=0; if (Cmd->Callback(UCM_NEEDPASSWORDW,Cmd->UserData,(LPARAM)PasswordW,ASIZE(PasswordW))==-1) *PasswordW=0; if (*PasswordW==0) { char PasswordA[MAXPASSWORD]; *PasswordA=0; if (Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)PasswordA,ASIZE(PasswordA))==-1) *PasswordA=0; GetWideName(PasswordA,NULL,PasswordW,ASIZE(PasswordW)); cleandata(PasswordA,sizeof(PasswordA)); } Cmd->Password.Set(PasswordW); cleandata(PasswordW,sizeof(PasswordW)); Cmd->ManualPassword=true; } if (!Cmd->Password.IsSet()) return false; } return true; }
void PASCAL RARSetPassword(HANDLE hArcData,char *Password) { DataSet *Data=(DataSet *)hArcData; wchar PasswordW[MAXPASSWORD]; GetWideName(Password,NULL,PasswordW,ASIZE(PasswordW)); Data->Cmd.Password.Set(PasswordW); cleandata(PasswordW,sizeof(PasswordW)); }
bool SetFileCompression(char *Name,wchar *NameW,bool State) { wchar FileNameW[NM]; GetWideName(Name,NameW,FileNameW); HANDLE hFile=CreateFileW(FileNameW,FILE_READ_DATA|FILE_WRITE_DATA, FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_SEQUENTIAL_SCAN,NULL); if (hFile==INVALID_HANDLE_VALUE) return(false); SHORT NewState=State ? COMPRESSION_FORMAT_DEFAULT:COMPRESSION_FORMAT_NONE; DWORD Result; int RetCode=DeviceIoControl(hFile,FSCTL_SET_COMPRESSION,&NewState, sizeof(NewState),NULL,0,&Result,NULL); CloseHandle(hFile); return(RetCode!=0); }
// Check the path length and display the error message if it is too long. void ErrorHandler::CheckLongPathErrMsg(const char *FileName,const wchar *FileNameW) { #if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined (SILENT) && defined(MAX_PATH) if (GetLastError()==ERROR_PATH_NOT_FOUND) { wchar WideFileName[NM]; GetWideName(FileName,FileNameW,WideFileName,ASIZE(WideFileName)); size_t NameLength=wcslen(WideFileName); if (!IsFullPath(WideFileName)) { wchar CurDir[NM]; GetCurrentDirectoryW(ASIZE(CurDir),CurDir); NameLength+=wcslen(CurDir)+1; } if (NameLength>MAX_PATH) { Log(NULL,St(MMaxPathLimit),MAX_PATH); } } #endif }
void SetDirTime(const char *Name,const wchar *NameW,RarTime *ftm,RarTime *ftc,RarTime *fta) { #ifdef _WIN_32 if (!WinNT()) return; bool sm=ftm!=NULL && ftm->IsSet(); bool sc=ftc!=NULL && ftc->IsSet(); bool sa=fta!=NULL && fta->IsSet(); unsigned int DirAttr=GetFileAttr(Name,NameW); bool ResetAttr=(DirAttr!=0xffffffff && (DirAttr & FA_RDONLY)!=0); if (ResetAttr) SetFileAttr(Name,NameW,0); wchar DirNameW[NM]; GetWideName(Name,NameW,DirNameW); HANDLE hFile=CreateFileW(DirNameW,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL); if (hFile==INVALID_HANDLE_VALUE) return; FILETIME fm,fc,fa; if (sm) ftm->GetWin32(&fm); if (sc) ftc->GetWin32(&fc); if (sa) fta->GetWin32(&fa); SetFileTime(hFile,sc ? &fc:NULL,sa ? &fa:NULL,sm ? &fm:NULL); CloseHandle(hFile); if (ResetAttr) SetFileAttr(Name,NameW,DirAttr); #endif #if defined(_UNIX) || defined(_EMX) File::SetCloseFileTimeByName(Name,ftm,fta); #endif }
HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r) { DataSet *Data=NULL; try { r->OpenResult=0; Data=new DataSet; Data->Cmd.DllError=0; Data->OpenMode=r->OpenMode; Data->Cmd.FileArgs.AddString(L"*"); char AnsiArcName[NM]; *AnsiArcName=0; if (r->ArcName!=NULL) { strncpyz(AnsiArcName,r->ArcName,ASIZE(AnsiArcName)); #ifdef _WIN_ALL if (!AreFileApisANSI()) { OemToCharBuffA(r->ArcName,AnsiArcName,ASIZE(AnsiArcName)); AnsiArcName[ASIZE(AnsiArcName)-1]=0; } #endif } wchar ArcName[NM]; GetWideName(AnsiArcName,r->ArcNameW,ArcName,ASIZE(ArcName)); Data->Cmd.AddArcName(ArcName); Data->Cmd.Overwrite=OVERWRITE_ALL; Data->Cmd.VersionControl=1; Data->Cmd.Callback=r->Callback; Data->Cmd.UserData=r->UserData; // Open shared mode is added by request of dll users, who need to // browse and unpack archives while downloading. Data->Cmd.OpenShared = true; if (!Data->Arc.Open(ArcName,FMF_OPENSHARED)) { r->OpenResult=ERAR_EOPEN; delete Data; return NULL; } if (!Data->Arc.IsArchive(false)) { if (Data->Cmd.DllError!=0) r->OpenResult=Data->Cmd.DllError; else { RAR_EXIT ErrCode=ErrHandler.GetErrorCode(); if (ErrCode!=RARX_SUCCESS && ErrCode!=RARX_WARNING) r->OpenResult=RarErrorToDll(ErrCode); else r->OpenResult=ERAR_BAD_ARCHIVE; } delete Data; return NULL; } r->Flags=0; if (Data->Arc.Volume) r->Flags|=0x01; if (Data->Arc.Locked) r->Flags|=0x04; if (Data->Arc.Solid) r->Flags|=0x08; if (Data->Arc.NewNumbering) r->Flags|=0x10; if (Data->Arc.Signed) r->Flags|=0x20; if (Data->Arc.Protected) r->Flags|=0x40; if (Data->Arc.Encrypted) r->Flags|=0x80; if (Data->Arc.FirstVolume) r->Flags|=0x100; Array<wchar> CmtDataW; if (r->CmtBufSize!=0 && Data->Arc.GetComment(&CmtDataW)) { Array<char> CmtData(CmtDataW.Size()*4+1); memset(&CmtData[0],0,CmtData.Size()); WideToChar(&CmtDataW[0],&CmtData[0],CmtData.Size()-1); size_t Size=strlen(&CmtData[0])+1; r->Flags|=2; r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1; r->CmtSize=(uint)Min(Size,r->CmtBufSize); memcpy(r->CmtBuf,&CmtData[0],r->CmtSize-1); if (Size<=r->CmtBufSize) r->CmtBuf[r->CmtSize-1]=0; } else r->CmtState=r->CmtSize=0; Data->Extract.ExtractArchiveInit(Data->Arc); return (HANDLE)Data; } catch (RAR_EXIT ErrCode) { if (Data!=NULL && Data->Cmd.DllError!=0) r->OpenResult=Data->Cmd.DllError; else r->OpenResult=RarErrorToDll(ErrCode); if (Data != NULL) delete Data; return NULL; } catch (std::bad_alloc&) // Catch 'new' exception. { r->OpenResult=ERAR_NO_MEMORY; if (Data != NULL) delete Data; } return NULL; // To make compilers happy. }
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; }
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 } } }
void PASCAL RARSetPassword(HANDLE hArcData,char *Password) { DataSet *Data=(DataSet *)hArcData; GetWideName(Password,NULL,Data->Cmd.Password,ASIZE(Data->Cmd.Password)); }
bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,char Command) { RAROptions *Cmd=Arc.GetRAROptions(); int HeaderType=Arc.GetHeaderType(); FileHeader *hd=HeaderType==NEWSUB_HEAD ? &Arc.SubHead:&Arc.NewLhd; bool SplitHeader=(HeaderType==FILE_HEAD || HeaderType==NEWSUB_HEAD) && (hd->Flags & LHD_SPLIT_AFTER)!=0; if (DataIO!=NULL && SplitHeader && hd->UnpVer>=20 && hd->FileCRC!=0xffffffff && DataIO->PackedCRC!=~hd->FileCRC) { Log(Arc.FileName,St(MDataBadCRC),hd->FileName,Arc.FileName); } int64 PosBeforeClose=Arc.Tell(); if (DataIO!=NULL) DataIO->ProcessedArcSize+=Arc.FileLength(); Arc.Close(); char NextName[NM]; wchar NextNameW[NM]; strcpy(NextName,Arc.FileName); wcscpy(NextNameW,Arc.FileNameW); NextVolumeName(NextName,NextNameW,ASIZE(NextName),(Arc.NewMhd.Flags & MHD_NEWNUMBERING)==0 || Arc.OldFormat); #if !defined(SFX_MODULE) && !defined(RARDLL) bool RecoveryDone=false; #endif bool FailedOpen=false,OldSchemeTested=false; #if !defined(GUI) && !defined(SILENT) // In -vp mode we force the pause before next volume even if it is present // and even if we are on the hard disk. It is important when user does not // want to process partially downloaded volumes preliminary. if (Cmd->VolumePause && !AskNextVol(NextName,NextNameW)) FailedOpen=true; #endif if (!FailedOpen) while (!Arc.Open(NextName,NextNameW,0)) { // We need to open a new volume which size was not calculated // in total size before, so we cannot calculate the total progress // anymore. Let's reset the total size to zero and stop // the total progress. if (DataIO!=NULL) DataIO->TotalArcSize=0; if (!OldSchemeTested) { // Checking for new style volumes renamed by user to old style // name format. Some users did it for unknown reason. char AltNextName[NM]; wchar AltNextNameW[NM]; strcpy(AltNextName,Arc.FileName); wcscpy(AltNextNameW,Arc.FileNameW); NextVolumeName(AltNextName,AltNextNameW,ASIZE(AltNextName),true); OldSchemeTested=true; if (Arc.Open(AltNextName,AltNextNameW,0)) { strcpy(NextName,AltNextName); wcscpy(NextNameW,AltNextNameW); break; } } #ifdef RARDLL bool DllVolChanged=false; if (Cmd->Callback!=NULL) { GetWideName(NextName,NextNameW,NextNameW,ASIZE(NextNameW)); char CurName[ASIZE(NextName)]; strcpy(CurName,NextName); wchar CurNameW[ASIZE(NextNameW)]; wcscpy(CurNameW,NextNameW); if (Cmd->Callback(UCM_CHANGEVOLUMEW,Cmd->UserData,(LPARAM)NextNameW,RAR_VOL_ASK)!=-1 && wcscmp(CurNameW,NextNameW)!=0) { *NextName=0; DllVolChanged=true; } else if (Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextName,RAR_VOL_ASK)!=-1 && strcmp(CurName,NextName)!=0) { *NextNameW=0; DllVolChanged=true; } } if (!DllVolChanged && Cmd->ChangeVolProc!=NULL) { // Here we preserve ESP value. It is necessary for those developers, // who still define ChangeVolProc callback as "C" type function, // even though in year 2001 we announced in unrar.dll whatsnew.txt // that it will be PASCAL type (for compatibility with Visual Basic). #if defined(_MSC_VER) #ifndef _WIN_64 __asm mov ebx,esp #endif #elif defined(_WIN_ALL) && defined(__BORLANDC__) _EBX=_ESP; #endif int RetCode=Cmd->ChangeVolProc(NextName,RAR_VOL_ASK); // Restore ESP after ChangeVolProc with wrongly defined calling // convention broken it. #if defined(_MSC_VER) #ifndef _WIN_64 __asm mov esp,ebx #endif #elif defined(_WIN_ALL) && defined(__BORLANDC__) _ESP=_EBX; #endif if (RetCode!=0) { *NextNameW=0; DllVolChanged=true; } } if (!DllVolChanged) { Cmd->DllError=ERAR_EOPEN; FailedOpen=true; break; } #else // !RARDLL #if !defined(SFX_MODULE) && !defined(_WIN_CE) if (!RecoveryDone) { RecVolumes RecVol; RecVol.Restore(Cmd,Arc.FileName,Arc.FileNameW,true); RecoveryDone=true; continue; } #endif #ifndef GUI if (!Cmd->VolumePause && !IsRemovable(NextName)) { FailedOpen=true; break; } #endif #ifndef SILENT if (Cmd->AllYes || !AskNextVol(NextName,NextNameW)) #endif { FailedOpen=true; break; } #endif // RARDLL } if (FailedOpen) { #if !defined(SILENT) && !defined(_WIN_CE) Log(Arc.FileName,St(MAbsNextVol),NextName); #endif Arc.Open(Arc.FileName,Arc.FileNameW,0); Arc.Seek(PosBeforeClose,SEEK_SET); return(false); } Arc.CheckArc(true); #ifdef RARDLL if (Cmd->Callback!=NULL) { GetWideName(NextName,NextNameW,NextNameW,ASIZE(NextNameW)); if (Cmd->Callback(UCM_CHANGEVOLUMEW,Cmd->UserData,(LPARAM)NextNameW,RAR_VOL_NOTIFY)==-1) return(false); if (Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextName,RAR_VOL_NOTIFY)==-1) return(false); } if (Cmd->ChangeVolProc!=NULL) { #if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__) _EBX=_ESP; #endif int RetCode=Cmd->ChangeVolProc(NextName,RAR_VOL_NOTIFY); #if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__) _ESP=_EBX; #endif if (RetCode==0) return(false); } #endif if (Command=='T' || Command=='X' || Command=='E') mprintf(St(Command=='T' ? MTestVol:MExtrVol),Arc.FileName); if (SplitHeader) Arc.SearchBlock(HeaderType); else Arc.ReadHeader(); if (Arc.GetHeaderType()==FILE_HEAD) { Arc.ConvertAttributes(); Arc.Seek(Arc.NextBlockPos-Arc.NewLhd.FullPackSize,SEEK_SET); } #ifndef GUI if (ShowFileName) { char OutName[NM]; IntToExt(Arc.NewLhd.FileName,OutName); #ifdef UNICODE_SUPPORTED bool WideName=(Arc.NewLhd.Flags & LHD_UNICODE) && UnicodeEnabled(); if (WideName) { wchar NameW[NM]; ConvertPath(Arc.NewLhd.FileNameW,NameW); char Name[NM]; if (WideToChar(NameW,Name) && IsNameUsable(Name)) strcpy(OutName,Name); } #endif mprintf(St(MExtrPoints),OutName); if (!Cmd->DisablePercentage) mprintf(" "); } #endif if (DataIO!=NULL) { if (HeaderType==ENDARC_HEAD) DataIO->UnpVolume=false; else { DataIO->UnpVolume=(hd->Flags & LHD_SPLIT_AFTER)!=0; DataIO->SetPackedSizeToRead(hd->FullPackSize); } #ifdef SFX_MODULE DataIO->UnpArcSize=Arc.FileLength(); #endif // Reset the size of packed data read from current volume. It is used // to display the total progress and preceding volumes are already // compensated with ProcessedArcSize, so we need to reset this variable. DataIO->CurUnpRead=0; DataIO->PackedCRC=0xffffffff; // DataIO->SetFiles(&Arc,NULL); } return(true); }
bool FileCreate(RAROptions *Cmd,File *NewFile,char *Name,wchar *NameW, OVERWRITE_MODE Mode,bool *UserReject,int64 FileSize, uint FileTime,bool WriteOnly) { if (UserReject!=NULL) *UserReject=false; #if defined(_WIN_ALL) && !defined(_WIN_CE) bool ShortNameChanged=false; #endif while (FileExist(Name,NameW)) { #if defined(_WIN_ALL) && !defined(_WIN_CE) if (!ShortNameChanged) { // Avoid the infinite loop if UpdateExistingShortName returns // the same name. ShortNameChanged=true; // Maybe our long name matches the short name of existing file. // Let's check if we can change the short name. wchar WideName[NM]; GetWideName(Name,NameW,WideName,ASIZE(WideName)); if (UpdateExistingShortName(WideName)) { if (Name!=NULL && *Name!=0) WideToChar(WideName,Name); if (NameW!=NULL && *NameW!=0) wcscpy(NameW,WideName); continue; } } // Allow short name check again. It is necessary, because rename and // autorename below can change the name, so we need to check it again. ShortNameChanged=false; #endif if (Mode==OVERWRITE_NONE) { if (UserReject!=NULL) *UserReject=true; return(false); } // Must be before Cmd->AllYes check or -y switch would override -or. if (Mode==OVERWRITE_AUTORENAME) { if (!GetAutoRenamedName(Name,NameW)) Mode=OVERWRITE_DEFAULT; continue; } #ifdef SILENT Mode=OVERWRITE_ALL; #endif // This check must be after OVERWRITE_AUTORENAME processing or -y switch // would override -or. if (Cmd->AllYes || Mode==OVERWRITE_ALL) break; if (Mode==OVERWRITE_DEFAULT || Mode==OVERWRITE_FORCE_ASK) { char NewName[NM]; wchar NewNameW[NM]; *NewNameW=0; eprintf(St(MFileExists),Name); int Choice=Ask(St(MYesNoAllRenQ)); if (Choice==1) break; if (Choice==2) { if (UserReject!=NULL) *UserReject=true; return(false); } if (Choice==3) { Cmd->Overwrite=OVERWRITE_ALL; break; } if (Choice==4) { if (UserReject!=NULL) *UserReject=true; Cmd->Overwrite=OVERWRITE_NONE; return(false); } if (Choice==5) { #ifndef GUI mprintf(St(MAskNewName)); #ifdef _WIN_ALL File SrcFile; SrcFile.SetHandleType(FILE_HANDLESTD); int Size=SrcFile.Read(NewName,sizeof(NewName)-1); NewName[Size]=0; OemToCharA(NewName,NewName); #else if (fgets(NewName,sizeof(NewName),stdin)==NULL) { // Process fgets failure as if user answered 'No'. if (UserReject!=NULL) *UserReject=true; return(false); } #endif RemoveLF(NewName); #endif if (PointToName(NewName)==NewName) strcpy(PointToName(Name),NewName); else strcpy(Name,NewName); if (NameW!=NULL) { if (PointToName(NewNameW)==NewNameW) wcscpy(PointToName(NameW),NewNameW); else wcscpy(NameW,NewNameW); } continue; } if (Choice==6) ErrHandler.Exit(RARX_USERBREAK); } } uint FileMode=WriteOnly ? FMF_WRITE|FMF_SHAREREAD:FMF_UPDATE|FMF_SHAREREAD; if (NewFile!=NULL && NewFile->Create(Name,NameW,FileMode)) return(true); PrepareToDelete(Name,NameW); CreatePath(Name,NameW,true); return(NewFile!=NULL ? NewFile->Create(Name,NameW,FileMode):DelFile(Name,NameW)); }
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); }