#include "rar.hpp" static File *CreatedFiles[256]; static int RemoveCreatedActive=0; File::File() { hFile=BAD_HANDLE; *FileName=0; *FileNameW=0; NewFile=false; LastWrite=false; HandleType=FILE_HANDLENORMAL; SkipClose=false; IgnoreReadErrors=false; ErrorType=FILE_SUCCESS; OpenShared=false; AllowDelete=true; CloseCount=0; AllowExceptions=true; #ifdef _WIN_32 NoSequentialRead=false; #endif } File::~File() { if (hFile!=BAD_HANDLE && !SkipClose) if (NewFile) Delete(); else Close(); } void File::operator = (File &SrcFile) { hFile=SrcFile.hFile; strcpy(FileName,SrcFile.FileName); NewFile=SrcFile.NewFile; LastWrite=SrcFile.LastWrite; HandleType=SrcFile.HandleType; SrcFile.SkipClose=true; } bool File::Open(const char *Name,const wchar *NameW,bool OpenShared,bool Update) { ErrorType=FILE_SUCCESS; FileHandle hNewFile; if (File::OpenShared) OpenShared=true; #ifdef _WIN_32 uint Access=GENERIC_READ; if (Update) Access|=GENERIC_WRITE; uint ShareMode=FILE_SHARE_READ; if (OpenShared) ShareMode|=FILE_SHARE_WRITE; uint Flags=NoSequentialRead ? 0:FILE_FLAG_SEQUENTIAL_SCAN; if (WinNT() && NameW!=NULL && *NameW!=0) hNewFile=CreateFileW(NameW,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL); else hNewFile=CreateFile(Name,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL); if (hNewFile==BAD_HANDLE && GetLastError()==ERROR_FILE_NOT_FOUND) ErrorType=FILE_NOTFOUND; #else int flags=Update ? O_RDWR:O_RDONLY; #ifdef O_BINARY flags|=O_BINARY; #if defined(_AIX) && defined(_LARGE_FILE_API) flags|=O_LARGEFILE; #endif #endif #if defined(_EMX) && !defined(_DJGPP) int sflags=OpenShared ? SH_DENYNO:SH_DENYWR; int handle=sopen(Name,flags,sflags); #else int handle=open(Name,flags); #ifdef LOCK_EX #ifdef _OSF_SOURCE extern "C" int flock(int, int); #endif if (!OpenShared && Update && handle>=0 && flock(handle,LOCK_EX|LOCK_NB)==-1) { close(handle); return(false); } #endif #endif hNewFile=handle==-1 ? BAD_HANDLE:fdopen(handle,Update ? UPDATEBINARY:READBINARY); if (hNewFile==BAD_HANDLE && errno==ENOENT) ErrorType=FILE_NOTFOUND; #endif NewFile=false; HandleType=FILE_HANDLENORMAL; SkipClose=false; bool Success=hNewFile!=BAD_HANDLE; if (Success) { hFile=hNewFile; if (NameW!=NULL) strcpyw(FileNameW,NameW); else *FileNameW=0; if (Name!=NULL) strcpy(FileName,Name); else WideToChar(NameW,FileName); AddFileToList(hFile); } return(Success); } #if !defined(SHELL_EXT) && !defined(SFX_MODULE) void File::TOpen(const char *Name,const wchar *NameW) { if (!WOpen(Name,NameW)) ErrHandler.Exit(OPEN_ERROR); } #endif bool File::WOpen(const char *Name,const wchar *NameW) { if (Open(Name,NameW)) return(true); ErrHandler.OpenErrorMsg(Name); return(false); } bool File::Create(const char *Name,const wchar *NameW,bool ShareRead) { #ifdef _WIN_32 DWORD ShareMode=(ShareRead || File::OpenShared) ? FILE_SHARE_READ:0; if (WinNT() && NameW!=NULL && *NameW!=0) hFile=CreateFileW(NameW,GENERIC_READ|GENERIC_WRITE,ShareMode,NULL, CREATE_ALWAYS,0,NULL); else hFile=CreateFile(Name,GENERIC_READ|GENERIC_WRITE,ShareMode,NULL, CREATE_ALWAYS,0,NULL); #else hFile=fopen(Name,CREATEBINARY); #endif NewFile=true; HandleType=FILE_HANDLENORMAL; SkipClose=false; if (NameW!=NULL) strcpyw(FileNameW,NameW); else *FileNameW=0; if (Name!=NULL) strcpy(FileName,Name); else WideToChar(NameW,FileName); AddFileToList(hFile); return(hFile!=BAD_HANDLE); } void File::AddFileToList(FileHandle hFile) { if (hFile!=BAD_HANDLE) for (int I=0;ISize && FilePos-Size<=0xffffffff && FilePos+Size>0xffffffff) ErrHandler.WriteErrorFAT(FileName); #endif if (ErrHandler.AskRepeatWrite(FileName,false)) { #ifndef _WIN_32 clearerr(hFile); #endif if (Written0) Seek(Tell()-Written,SEEK_SET); continue; } ErrHandler.WriteError(NULL,FileName); } break; } LastWrite=true; } int File::Read(void *Data,size_t Size) { int64 FilePos=0; //initialized only to suppress some compilers warning if (IgnoreReadErrors) FilePos=Tell(); int ReadSize; while (true) { ReadSize=DirectRead(Data,Size); if (ReadSize==-1) { ErrorType=FILE_READERROR; if (AllowExceptions) if (IgnoreReadErrors) { ReadSize=0; for (size_t I=0;IMaxDeviceRead) Size=MaxDeviceRead; hFile=GetStdHandle(STD_INPUT_HANDLE); #else hFile=stdin; #endif } #endif #ifdef _WIN_32 DWORD Read; if (!ReadFile(hFile,Data,(DWORD)Size,&Read,NULL)) { if (IsDevice() && Size>MaxDeviceRead) return(DirectRead(Data,MaxDeviceRead)); if (HandleType==FILE_HANDLESTD && GetLastError()==ERROR_BROKEN_PIPE) return(0); return(-1); } return(Read); #else if (LastWrite) { fflush(hFile); LastWrite=false; } clearerr(hFile); size_t ReadSize=fread(Data,1,Size,hFile); if (ferror(hFile)) return(-1); return((int)ReadSize); #endif } void File::Seek(int64 Offset,int Method) { if (!RawSeek(Offset,Method) && AllowExceptions) ErrHandler.SeekError(FileName); } bool File::RawSeek(int64 Offset,int Method) { if (hFile==BAD_HANDLE) return(true); if (Offset<0 && Method!=SEEK_SET) { Offset=(Method==SEEK_CUR ? Tell():FileLength())+Offset; Method=SEEK_SET; } #ifdef _WIN_32 LONG HighDist=(LONG)(Offset>>32); if (SetFilePointer(hFile,(LONG)Offset,&HighDist,Method)==0xffffffff && GetLastError()!=NO_ERROR) return(false); #else LastWrite=false; #if defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE) && !defined(__VMS) if (fseeko(hFile,Offset,Method)!=0) #else if (fseek(hFile,(long)Offset,Method)!=0) #endif return(false); #endif return(true); } int64 File::Tell() { #ifdef _WIN_32 LONG HighDist=0; uint LowDist=SetFilePointer(hFile,0,&HighDist,FILE_CURRENT); if (LowDist==0xffffffff && GetLastError()!=NO_ERROR) if (AllowExceptions) ErrHandler.SeekError(FileName); else return(-1); return(INT32TO64(HighDist,LowDist)); #else #if defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE) return(ftello(hFile)); #else return(ftell(hFile)); #endif #endif } void File::Prealloc(int64 Size) { #ifdef _WIN_32 if (RawSeek(Size,SEEK_SET)) { Truncate(); Seek(0,SEEK_SET); } #endif } byte File::GetByte() { byte Byte=0; Read(&Byte,1); return(Byte); } void File::PutByte(byte Byte) { Write(&Byte,1); } bool File::Truncate() { #ifdef _WIN_32 return(SetEndOfFile(hFile)==TRUE); #else return(false); #endif } void File::SetOpenFileTime(RarTime *ftm,RarTime *ftc,RarTime *fta) { #ifdef _WIN_32 bool sm=ftm!=NULL && ftm->IsSet(); bool sc=ftc!=NULL && ftc->IsSet(); bool sa=fta!=NULL && fta->IsSet(); 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); #endif } void File::SetCloseFileTime(RarTime *ftm,RarTime *fta) { #if defined(_UNIX) || defined(_EMX) SetCloseFileTimeByName(FileName,ftm,fta); #endif } void File::SetCloseFileTimeByName(const char *Name,RarTime *ftm,RarTime *fta) { #if defined(_UNIX) || defined(_EMX) bool setm=ftm!=NULL && ftm->IsSet(); bool seta=fta!=NULL && fta->IsSet(); if (setm || seta) { struct utimbuf ut; if (setm) ut.modtime=ftm->GetUnix(); else ut.modtime=fta->GetUnix(); if (seta) ut.actime=fta->GetUnix(); else ut.actime=ut.modtime; utime(Name,&ut); } #endif } void File::GetOpenFileTime(RarTime *ft) { #ifdef _WIN_32 FILETIME FileTime; GetFileTime(hFile,NULL,NULL,&FileTime); *ft=FileTime; #endif #if defined(_UNIX) || defined(_EMX) struct stat st; fstat(fileno(hFile),&st); *ft=st.st_mtime; #endif } int64 File::FileLength() { SaveFilePos SavePos(*this); Seek(0,SEEK_END); return(Tell()); } void File::SetHandleType(FILE_HANDLETYPE Type) { HandleType=Type; } bool File::IsDevice() { if (hFile==BAD_HANDLE) return(false); #ifdef _WIN_32 uint Type=GetFileType(hFile); return(Type==FILE_TYPE_CHAR || Type==FILE_TYPE_PIPE); #else return(isatty(fileno(hFile))); #endif } #ifndef SFX_MODULE void File::fprintf(const char *fmt,...) { va_list argptr; va_start(argptr,fmt); safebuf char Msg[2*NM+1024],OutMsg[2*NM+1024]; vsprintf(Msg,fmt,argptr); #ifdef _WIN_32 for (int Src=0,Dest=0;;Src++) { char CurChar=Msg[Src]; if (CurChar=='\n') OutMsg[Dest++]='\r'; OutMsg[Dest++]=CurChar; if (CurChar==0) break; } #else strcpy(OutMsg,Msg); #endif Write(OutMsg,strlen(OutMsg)); va_end(argptr); } #endif bool File::RemoveCreated() { RemoveCreatedActive++; bool RetCode=true; for (int I=0;ISetExceptions(false); bool Success; if (CreatedFiles[I]->NewFile) Success=CreatedFiles[I]->Delete(); else Success=CreatedFiles[I]->Close(); if (Success) CreatedFiles[I]=NULL; else RetCode=false; } RemoveCreatedActive--; return(RetCode); } #ifndef SFX_MODULE int64 File::Copy(File &Dest,int64 Length) { Array Buffer(0x10000); int64 CopySize=0; bool CopyAll=(Length==INT64NDF); while (CopyAll || Length>0) { Wait(); size_t SizeToRead=(!CopyAll && Length<(int64)Buffer.Size()) ? (size_t)Length:Buffer.Size(); int ReadSize=Read(&Buffer[0],SizeToRead); if (ReadSize==0) break; Dest.Write(&Buffer[0],ReadSize); CopySize+=ReadSize; if (!CopyAll) Length-=ReadSize; } return(CopySize); } #endif