123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828 |
- #include "rar.hpp"
- File::File()
- {
- hFile=FILE_BAD_HANDLE;
- *FileName=0;
- NewFile=false;
- LastWrite=false;
- HandleType=FILE_HANDLENORMAL;
- LineInput=false;
- SkipClose=false;
- ErrorType=FILE_SUCCESS;
- OpenShared=false;
- AllowDelete=true;
- AllowExceptions=true;
- PreserveAtime=false;
- #ifdef _WIN_ALL
- CreateMode=FMF_UNDEFINED;
- #endif
- ReadErrorMode=FREM_ASK;
- TruncatedAfterReadError=false;
- CurFilePos=0;
- }
- File::~File()
- {
- if (hFile!=FILE_BAD_HANDLE && !SkipClose)
- if (NewFile)
- Delete();
- else
- Close();
- }
- void File::operator = (File &SrcFile)
- {
- hFile=SrcFile.hFile;
- NewFile=SrcFile.NewFile;
- LastWrite=SrcFile.LastWrite;
- HandleType=SrcFile.HandleType;
- TruncatedAfterReadError=SrcFile.TruncatedAfterReadError;
- wcsncpyz(FileName,SrcFile.FileName,ASIZE(FileName));
- SrcFile.SkipClose=true;
- }
- bool File::Open(const wchar *Name,uint Mode)
- {
- ErrorType=FILE_SUCCESS;
- FileHandle hNewFile;
- bool OpenShared=File::OpenShared || (Mode & FMF_OPENSHARED)!=0;
- bool UpdateMode=(Mode & FMF_UPDATE)!=0;
- bool WriteMode=(Mode & FMF_WRITE)!=0;
- #ifdef _WIN_ALL
- uint Access=WriteMode ? GENERIC_WRITE:GENERIC_READ;
- if (UpdateMode)
- Access|=GENERIC_WRITE;
- uint ShareMode=(Mode & FMF_OPENEXCLUSIVE) ? 0 : FILE_SHARE_READ;
- if (OpenShared)
- ShareMode|=FILE_SHARE_WRITE;
- uint Flags=FILE_FLAG_SEQUENTIAL_SCAN;
- FindData FD;
- if (PreserveAtime)
- Access|=FILE_WRITE_ATTRIBUTES; // Needed to preserve atime.
- hNewFile=CreateFile(Name,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
- DWORD LastError;
- if (hNewFile==FILE_BAD_HANDLE)
- {
- LastError=GetLastError();
- wchar LongName[NM];
- if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
- {
- hNewFile=CreateFile(LongName,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
- // For archive names longer than 260 characters first CreateFile
- // (without \\?\) fails and sets LastError to 3 (access denied).
- // We need the correct "file not found" error code to decide
- // if we create a new archive or quit with "cannot create" error.
- // So we need to check the error code after \\?\ CreateFile again,
- // otherwise we'll fail to create new archives with long names.
- // But we cannot simply assign the new code to LastError,
- // because it would break "..\arcname.rar" relative names processing.
- // First CreateFile returns the correct "file not found" code for such
- // names, but "\\?\" CreateFile returns ERROR_INVALID_NAME treating
- // dots as a directory name. So we check only for "file not found"
- // error here and for other errors use the first CreateFile result.
- if (GetLastError()==ERROR_FILE_NOT_FOUND)
- LastError=ERROR_FILE_NOT_FOUND;
- }
- }
- if (hNewFile==FILE_BAD_HANDLE && LastError==ERROR_FILE_NOT_FOUND)
- ErrorType=FILE_NOTFOUND;
- if (PreserveAtime && hNewFile!=FILE_BAD_HANDLE)
- {
- FILETIME ft={0xffffffff,0xffffffff}; // This value prevents atime modification.
- SetFileTime(hNewFile,NULL,&ft,NULL);
- }
- #else
- int flags=UpdateMode ? O_RDWR:(WriteMode ? O_WRONLY:O_RDONLY);
- #ifdef O_BINARY
- flags|=O_BINARY;
- #if defined(_AIX) && defined(_LARGE_FILE_API)
- flags|=O_LARGEFILE;
- #endif
- #endif
- // NDK r20 has O_NOATIME, but fails to create files with it in Android 7+.
- #if defined(O_NOATIME)
- if (PreserveAtime)
- flags|=O_NOATIME;
- #endif
- char NameA[NM];
- WideToChar(Name,NameA,ASIZE(NameA));
- int handle=open(NameA,flags);
- #ifdef LOCK_EX
- #ifdef _OSF_SOURCE
- extern "C" int flock(int, int);
- #endif
- if (!OpenShared && UpdateMode && handle>=0 && flock(handle,LOCK_EX|LOCK_NB)==-1)
- {
- close(handle);
- return false;
- }
- #endif
- if (handle==-1)
- hNewFile=FILE_BAD_HANDLE;
- else
- {
- #ifdef FILE_USE_OPEN
- hNewFile=handle;
- #else
- hNewFile=fdopen(handle,UpdateMode ? UPDATEBINARY:READBINARY);
- #endif
- }
- if (hNewFile==FILE_BAD_HANDLE && errno==ENOENT)
- ErrorType=FILE_NOTFOUND;
- #endif
- NewFile=false;
- HandleType=FILE_HANDLENORMAL;
- SkipClose=false;
- bool Success=hNewFile!=FILE_BAD_HANDLE;
- if (Success)
- {
- hFile=hNewFile;
- wcsncpyz(FileName,Name,ASIZE(FileName));
- TruncatedAfterReadError=false;
- }
- return Success;
- }
- #if !defined(SFX_MODULE)
- void File::TOpen(const wchar *Name)
- {
- if (!WOpen(Name))
- ErrHandler.Exit(RARX_OPEN);
- }
- #endif
- bool File::WOpen(const wchar *Name)
- {
- if (Open(Name))
- return true;
- ErrHandler.OpenErrorMsg(Name);
- return false;
- }
- bool File::Create(const wchar *Name,uint Mode)
- {
- return false; /* // OPENMPT ADDITION
- // OpenIndiana based NAS and CIFS shares fail to set the file time if file
- // was created in read+write mode and some data was written and not flushed
- // before SetFileTime call. So we should use the write only mode if we plan
- // SetFileTime call and do not need to read from file.
- bool WriteMode=(Mode & FMF_WRITE)!=0;
- bool ShareRead=(Mode & FMF_SHAREREAD)!=0 || File::OpenShared;
- #ifdef _WIN_ALL
- CreateMode=Mode;
- uint Access=WriteMode ? GENERIC_WRITE:GENERIC_READ|GENERIC_WRITE;
- DWORD ShareMode=ShareRead ? FILE_SHARE_READ:0;
- // Windows automatically removes dots and spaces in the end of file name,
- // So we detect such names and process them with \\?\ prefix.
- wchar *LastChar=PointToLastChar(Name);
- bool Special=*LastChar=='.' || *LastChar==' ';
-
- if (Special && (Mode & FMF_STANDARDNAMES)==0)
- hFile=FILE_BAD_HANDLE;
- else
- hFile=CreateFile(Name,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
- if (hFile==FILE_BAD_HANDLE)
- {
- wchar LongName[NM];
- if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
- hFile=CreateFile(LongName,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
- }
- #else
- char NameA[NM];
- WideToChar(Name,NameA,ASIZE(NameA));
- #ifdef FILE_USE_OPEN
- hFile=open(NameA,(O_CREAT|O_TRUNC) | (WriteMode ? O_WRONLY : O_RDWR),0666);
- #else
- hFile=fopen(NameA,WriteMode ? WRITEBINARY:CREATEBINARY);
- #endif
- #endif
- NewFile=true;
- HandleType=FILE_HANDLENORMAL;
- SkipClose=false;
- wcsncpyz(FileName,Name,ASIZE(FileName));
- return hFile!=FILE_BAD_HANDLE;
- */ // OPENMPT ADDITION
- }
- #if !defined(SFX_MODULE)
- void File::TCreate(const wchar *Name,uint Mode)
- {
- if (!WCreate(Name,Mode))
- ErrHandler.Exit(RARX_FATAL);
- }
- #endif
- bool File::WCreate(const wchar *Name,uint Mode)
- {
- if (Create(Name,Mode))
- return true;
- ErrHandler.CreateErrorMsg(Name);
- return false;
- }
- bool File::Close()
- {
- bool Success=true;
- if (hFile!=FILE_BAD_HANDLE)
- {
- if (!SkipClose)
- {
- #ifdef _WIN_ALL
- // We use the standard system handle for stdout in Windows
- // and it must not be closed here.
- if (HandleType==FILE_HANDLENORMAL)
- Success=CloseHandle(hFile)==TRUE;
- #else
- #ifdef FILE_USE_OPEN
- Success=close(hFile)!=-1;
- #else
- Success=fclose(hFile)!=EOF;
- #endif
- #endif
- }
- hFile=FILE_BAD_HANDLE;
- }
- HandleType=FILE_HANDLENORMAL;
- if (!Success && AllowExceptions)
- ErrHandler.CloseError(FileName);
- return Success;
- }
- bool File::Delete()
- {
- if (HandleType!=FILE_HANDLENORMAL)
- return false;
- if (hFile!=FILE_BAD_HANDLE)
- Close();
- if (!AllowDelete)
- return false;
- return DelFile(FileName);
- }
- bool File::Rename(const wchar *NewName)
- {
- // No need to rename if names are already same.
- bool Success=wcscmp(FileName,NewName)==0;
- if (!Success)
- Success=RenameFile(FileName,NewName);
- if (Success)
- wcsncpyz(FileName,NewName,ASIZE(FileName));
- return Success;
- }
- bool File::Write(const void *Data,size_t Size)
- {
- return true; /* // OPENMPT ADDITION
- if (Size==0)
- return true;
- if (HandleType==FILE_HANDLESTD)
- {
- #ifdef _WIN_ALL
- hFile=GetStdHandle(STD_OUTPUT_HANDLE);
- #else
- // Cannot use the standard stdout here, because it already has wide orientation.
- if (hFile==FILE_BAD_HANDLE)
- {
- #ifdef FILE_USE_OPEN
- hFile=dup(STDOUT_FILENO); // Open new stdout stream.
- #else
- hFile=fdopen(dup(STDOUT_FILENO),"w"); // Open new stdout stream.
- #endif
- }
- #endif
- }
- bool Success;
- while (1)
- {
- Success=false;
- #ifdef _WIN_ALL
- DWORD Written=0;
- if (HandleType!=FILE_HANDLENORMAL)
- {
- // writing to stdout can fail in old Windows if data block is too large
- const size_t MaxSize=0x4000;
- for (size_t I=0;I<Size;I+=MaxSize)
- {
- Success=WriteFile(hFile,(byte *)Data+I,(DWORD)Min(Size-I,MaxSize),&Written,NULL)==TRUE;
- if (!Success)
- break;
- }
- }
- else
- Success=WriteFile(hFile,Data,(DWORD)Size,&Written,NULL)==TRUE;
- #else
- #ifdef FILE_USE_OPEN
- ssize_t Written=write(hFile,Data,Size);
- Success=Written==Size;
- #else
- int Written=fwrite(Data,1,Size,hFile);
- Success=Written==Size && !ferror(hFile);
- #endif
- #endif
- if (!Success && AllowExceptions && HandleType==FILE_HANDLENORMAL)
- {
- #if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(RARDLL)
- int ErrCode=GetLastError();
- int64 FilePos=Tell();
- uint64 FreeSize=GetFreeDisk(FileName);
- SetLastError(ErrCode);
- if (FreeSize>Size && FilePos-Size<=0xffffffff && FilePos+Size>0xffffffff)
- ErrHandler.WriteErrorFAT(FileName);
- #endif
- if (ErrHandler.AskRepeatWrite(FileName,false))
- {
- #if !defined(_WIN_ALL) && !defined(FILE_USE_OPEN)
- clearerr(hFile);
- #endif
- if (Written<Size && Written>0)
- Seek(Tell()-Written,SEEK_SET);
- continue;
- }
- ErrHandler.WriteError(NULL,FileName);
- }
- break;
- }
- LastWrite=true;
- return Success; // It can return false only if AllowExceptions is disabled.
- */ // OPENMPT ADDITION
- }
- int File::Read(void *Data,size_t Size)
- {
- if (TruncatedAfterReadError)
- return 0;
- int64 FilePos=0; // Initialized only to suppress some compilers warning.
- if (ReadErrorMode==FREM_IGNORE)
- FilePos=Tell();
- int TotalRead=0;
- while (true)
- {
- int ReadSize=DirectRead(Data,Size);
- if (ReadSize==-1)
- {
- ErrorType=FILE_READERROR;
- if (AllowExceptions)
- if (ReadErrorMode==FREM_IGNORE)
- {
- ReadSize=0;
- for (size_t I=0;I<Size;I+=512)
- {
- Seek(FilePos+I,SEEK_SET);
- size_t SizeToRead=Min(Size-I,512);
- int ReadCode=DirectRead(Data,SizeToRead);
- ReadSize+=(ReadCode==-1) ? 512:ReadCode;
- if (ReadSize!=-1)
- TotalRead+=ReadSize;
- }
- }
- else
- {
- bool Ignore=false,Retry=false,Quit=false;
- if (ReadErrorMode==FREM_ASK && HandleType==FILE_HANDLENORMAL)
- {
- ErrHandler.AskRepeatRead(FileName,Ignore,Retry,Quit);
- if (Retry)
- continue;
- }
- if (Ignore || ReadErrorMode==FREM_TRUNCATE)
- {
- TruncatedAfterReadError=true;
- return 0;
- }
- ErrHandler.ReadError(FileName);
- }
- }
- TotalRead+=ReadSize; // If ReadSize is -1, TotalRead is also set to -1 here.
- if (HandleType==FILE_HANDLESTD && !LineInput && ReadSize>0 && (uint)ReadSize<Size)
- {
- // Unlike regular files, for pipe we can read only as much as was
- // written at the other end of pipe. We had seen data coming in small
- // ~80 byte chunks when piping from 'type arc.rar'. Extraction code
- // would fail if we read an incomplete archive header from stdin.
- // So here we ensure that requested size is completely read.
- // But we return the available data immediately in "line input" mode,
- // when processing user's input in console prompts. Otherwise apps
- // piping user responses to multiple Ask() prompts can hang if no more
- // data is available yet and pipe isn't closed.
- Data=(byte*)Data+ReadSize;
- Size-=ReadSize;
- continue;
- }
- break;
- }
- if (TotalRead>0) // Can be -1 for error and AllowExceptions disabled.
- CurFilePos+=TotalRead;
- return TotalRead; // It can return -1 only if AllowExceptions is disabled.
- }
- // Returns -1 in case of error.
- int File::DirectRead(void *Data,size_t Size)
- {
- #ifdef _WIN_ALL
- const size_t MaxDeviceRead=20000;
- const size_t MaxLockedRead=32768;
- #endif
- if (HandleType==FILE_HANDLESTD)
- {
- #ifdef _WIN_ALL
- // if (Size>MaxDeviceRead)
- // Size=MaxDeviceRead;
- hFile=GetStdHandle(STD_INPUT_HANDLE);
- #else
- #ifdef FILE_USE_OPEN
- hFile=STDIN_FILENO;
- #else
- hFile=stdin;
- #endif
- #endif
- }
- #ifdef _WIN_ALL
- // For pipes like 'type file.txt | rar -si arcname' ReadFile may return
- // data in small ~4KB blocks. It may slightly reduce the compression ratio.
- 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;
- // We had a bug report about failure to archive 1C database lock file
- // 1Cv8tmp.1CL, which is a zero length file with a region above 200 KB
- // permanently locked. If our first read request uses too large buffer
- // and if we are in -dh mode, so we were able to open the file,
- // we'll fail with "Read error". So now we use try a smaller buffer size
- // in case of lock error.
- if (HandleType==FILE_HANDLENORMAL && Size>MaxLockedRead &&
- GetLastError()==ERROR_LOCK_VIOLATION)
- return DirectRead(Data,MaxLockedRead);
- return -1;
- }
- return Read;
- #else
- #ifdef FILE_USE_OPEN
- ssize_t ReadSize=read(hFile,Data,Size);
- if (ReadSize==-1)
- return -1;
- return (int)ReadSize;
- #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
- #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==FILE_BAD_HANDLE)
- return true;
- if (!IsSeekable())
- {
- if (Method==SEEK_CUR)
- {
- Offset+=CurFilePos;
- Method=SEEK_SET;
- }
- if (Method==SEEK_SET && Offset>=CurFilePos) // Reading for seek forward.
- {
- uint64 SkipSize=Offset-CurFilePos;
- while (SkipSize>0)
- {
- byte Buf[4096];
- int ReadSize=Read(Buf,(size_t)Min(SkipSize,ASIZE(Buf)));
- if (ReadSize<=0)
- return false;
- SkipSize-=ReadSize;
- }
- CurFilePos=Offset;
- return true;
- }
- return false; // Backward or end of file seek on unseekable file.
- }
- if (Offset<0 && Method!=SEEK_SET)
- {
- Offset=(Method==SEEK_CUR ? Tell():FileLength())+Offset;
- Method=SEEK_SET;
- }
- #ifdef _WIN_ALL
- LONG HighDist=(LONG)(Offset>>32);
- if (SetFilePointer(hFile,(LONG)Offset,&HighDist,Method)==0xffffffff &&
- GetLastError()!=NO_ERROR)
- return false;
- #else
- LastWrite=false;
- #ifdef FILE_USE_OPEN
- if (lseek(hFile,(off_t)Offset,Method)==-1)
- return false;
- #elif defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE) && !defined(__VMS)
- if (fseeko(hFile,Offset,Method)!=0)
- return false;
- #else
- if (fseek(hFile,(long)Offset,Method)!=0)
- return false;
- #endif
- #endif
- return true;
- }
- int64 File::Tell()
- {
- if (hFile==FILE_BAD_HANDLE)
- if (AllowExceptions)
- ErrHandler.SeekError(FileName);
- else
- return -1;
- if (!IsSeekable())
- return CurFilePos;
- #ifdef _WIN_ALL
- 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
- #ifdef FILE_USE_OPEN
- return lseek(hFile,0,SEEK_CUR);
- #elif defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE)
- return ftello(hFile);
- #else
- return ftell(hFile);
- #endif
- #endif
- }
- void File::Prealloc(int64 Size)
- {
- /* // OPENMPT ADDITION
- #ifdef _WIN_ALL
- if (RawSeek(Size,SEEK_SET))
- {
- Truncate();
- Seek(0,SEEK_SET);
- }
- #endif
- #if defined(_UNIX) && defined(USE_FALLOCATE)
- // fallocate is rather new call. Only latest kernels support it.
- // So we are not using it by default yet.
- int fd = GetFD();
- if (fd >= 0)
- fallocate(fd, 0, 0, Size);
- #endif
- */ // OPENMPT ADDITION
- }
- byte File::GetByte()
- {
- byte Byte=0;
- Read(&Byte,1);
- return Byte;
- }
- void File::PutByte(byte Byte)
- {
- Write(&Byte,1);
- }
- bool File::Truncate()
- {
- return false; /* // OPENMPT ADDITION
- #ifdef _WIN_ALL
- return SetEndOfFile(hFile)==TRUE;
- #else
- return ftruncate(GetFD(),(off_t)Tell())==0;
- #endif
- */ // OPENMPT ADDITION
- }
- void File::Flush()
- {
- return; /* // OPENMPT ADDITION
- #ifdef _WIN_ALL
- FlushFileBuffers(hFile);
- #else
- #ifndef FILE_USE_OPEN
- fflush(hFile);
- #endif
- fsync(GetFD());
- #endif
- */ // OPENMPT EDDITION
- }
- void File::SetOpenFileTime(RarTime *ftm,RarTime *ftc,RarTime *fta)
- {
- /* // OPENMPT ADDITION
- #ifdef _WIN_ALL
- // Workaround for OpenIndiana NAS time bug. If we cannot create a file
- // in write only mode, we need to flush the write buffer before calling
- // SetFileTime or file time will not be changed.
- if (CreateMode!=FMF_UNDEFINED && (CreateMode & FMF_WRITE)==0)
- FlushFileBuffers(hFile);
- 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->GetWinFT(&fm);
- if (sc)
- ftc->GetWinFT(&fc);
- if (sa)
- fta->GetWinFT(&fa);
- SetFileTime(hFile,sc ? &fc:NULL,sa ? &fa:NULL,sm ? &fm:NULL);
- #endif
- */ // OPENMPT ADDITION
- }
- void File::SetCloseFileTime(RarTime *ftm,RarTime *fta)
- {
- /* // OPENMPT ADDITION
- // Android APP_PLATFORM := android-14 does not support futimens and futimes.
- // Newer platforms support futimens, but fail on Android 4.2.
- // We have to use utime for Android.
- // Also we noticed futimens fail to set timestamps on NTFS partition
- // mounted to virtual Linux x86 machine, but utimensat worked correctly.
- // So we set timestamps for already closed files in Unix.
- #ifdef _UNIX
- SetCloseFileTimeByName(FileName,ftm,fta);
- #endif
- */ // OPENMPT ADDITION
- }
- void File::SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta)
- {
- /* // OPENMPT ADDITION
- #ifdef _UNIX
- bool setm=ftm!=NULL && ftm->IsSet();
- bool seta=fta!=NULL && fta->IsSet();
- if (setm || seta)
- {
- char NameA[NM];
- WideToChar(Name,NameA,ASIZE(NameA));
- #ifdef UNIX_TIME_NS
- timespec times[2];
- times[0].tv_sec=seta ? fta->GetUnix() : 0;
- times[0].tv_nsec=seta ? long(fta->GetUnixNS()%1000000000) : UTIME_NOW;
- times[1].tv_sec=setm ? ftm->GetUnix() : 0;
- times[1].tv_nsec=setm ? long(ftm->GetUnixNS()%1000000000) : UTIME_NOW;
- utimensat(AT_FDCWD,NameA,times,0);
- #else
- utimbuf ut;
- if (setm)
- ut.modtime=ftm->GetUnix();
- else
- ut.modtime=fta->GetUnix(); // Need to set something, cannot left it 0.
- if (seta)
- ut.actime=fta->GetUnix();
- else
- ut.actime=ut.modtime; // Need to set something, cannot left it 0.
- utime(NameA,&ut);
- #endif
- }
- #endif
- */ // OPENMPT ADDITION
- }
- void File::GetOpenFileTime(RarTime *ft)
- {
- /* // OPENMPT ADDITION
- #ifdef _WIN_ALL
- FILETIME FileTime;
- GetFileTime(hFile,NULL,NULL,&FileTime);
- ft->SetWinFT(&FileTime);
- #endif
- #if defined(_UNIX) || defined(_EMX)
- struct stat st;
- fstat(GetFD(),&st);
- ft->SetUnix(st.st_mtime);
- #endif
- */ // OPENMPT ADDITION
- }
- int64 File::FileLength()
- {
- int64 SavePos=Tell();
- Seek(0,SEEK_END);
- int64 Length=Tell();
- Seek(SavePos,SEEK_SET);
- return Length;
- }
- bool File::IsDevice()
- {
- if (hFile==FILE_BAD_HANDLE)
- return false;
- #ifdef _WIN_ALL
- uint Type=GetFileType(hFile);
- return Type==FILE_TYPE_CHAR || Type==FILE_TYPE_PIPE;
- #else
- return isatty(GetFD());
- #endif
- }
- #ifndef SFX_MODULE
- int64 File::Copy(File &Dest,int64 Length)
- {
- Array<byte> Buffer(File::CopyBufferSize());
- 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();
- byte *Buf=&Buffer[0];
- int ReadSize=Read(Buf,SizeToRead);
- if (ReadSize==0)
- break;
- size_t WriteSize=ReadSize;
- #ifdef _WIN_ALL
- // For FAT32 USB flash drives in Windows if first write is 4 KB or more,
- // write caching is disabled and "write through" is enabled, resulting
- // in bad performance, especially for many small files. It happens when
- // we create SFX archive on USB drive, because SFX module is written first.
- // So we split the first write to small 1 KB followed by rest of data.
- if (CopySize==0 && WriteSize>=4096)
- {
- const size_t FirstWrite=1024;
- Dest.Write(Buf,FirstWrite);
- Buf+=FirstWrite;
- WriteSize-=FirstWrite;
- }
- #endif
- Dest.Write(Buf,WriteSize);
- CopySize+=ReadSize;
- if (!CopyAll)
- Length-=ReadSize;
- }
- return CopySize;
- }
- #endif
|