Permalink
Cannot retrieve contributors at this time
Fetching contributors…

#include "rar.hpp" | |
MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr) | |
{ | |
#ifdef _WIN_ALL | |
// Windows automatically removes dots and spaces in the end of directory | |
// name. So we detect such names and process them with \\?\ prefix. | |
wchar *LastChar=PointToLastChar(Name); | |
bool Special=*LastChar=='.' || *LastChar==' '; | |
BOOL RetCode=Special ? FALSE : CreateDirectory(Name,NULL); | |
if (RetCode==0 && !FileExist(Name)) | |
{ | |
wchar LongName[NM]; | |
if (GetWinLongPath(Name,LongName,ASIZE(LongName))) | |
RetCode=CreateDirectory(LongName,NULL); | |
} | |
if (RetCode!=0) // Non-zero return code means success for CreateDirectory. | |
{ | |
if (SetAttr) | |
SetFileAttr(Name,Attr); | |
return MKDIR_SUCCESS; | |
} | |
int ErrCode=GetLastError(); | |
if (ErrCode==ERROR_FILE_NOT_FOUND || ErrCode==ERROR_PATH_NOT_FOUND) | |
return MKDIR_BADPATH; | |
return MKDIR_ERROR; | |
#elif defined(_UNIX) | |
char NameA[NM]; | |
WideToChar(Name,NameA,ASIZE(NameA)); | |
mode_t uattr=SetAttr ? (mode_t)Attr:0777; | |
int ErrCode=mkdir(NameA,uattr); | |
if (ErrCode==-1) | |
return errno==ENOENT ? MKDIR_BADPATH:MKDIR_ERROR; | |
return MKDIR_SUCCESS; | |
#else | |
return MKDIR_ERROR; | |
#endif | |
} | |
bool CreatePath(const wchar *Path,bool SkipLastName) | |
{ | |
if (Path==NULL || *Path==0) | |
return false; | |
#if defined(_WIN_ALL) || defined(_EMX) | |
uint DirAttr=0; | |
#else | |
uint DirAttr=0777; | |
#endif | |
bool Success=true; | |
for (const wchar *s=Path;*s!=0;s++) | |
{ | |
wchar DirName[NM]; | |
if (s-Path>=ASIZE(DirName)) | |
break; | |
// Process all kinds of path separators, so user can enter Unix style | |
// path in Windows or Windows in Unix. s>Path check avoids attempting | |
// creating an empty directory for paths starting from path separator. | |
if (IsPathDiv(*s) && s>Path) | |
{ | |
#ifdef _WIN_ALL | |
// We must not attempt to create "D:" directory, because first | |
// CreateDirectory will fail, so we'll use \\?\D:, which forces Wine | |
// to create "D:" directory. | |
if (s==Path+2 && Path[1]==':') | |
continue; | |
#endif | |
wcsncpy(DirName,Path,s-Path); | |
DirName[s-Path]=0; | |
Success=MakeDir(DirName,true,DirAttr)==MKDIR_SUCCESS; | |
if (Success) | |
{ | |
mprintf(St(MCreatDir),DirName); | |
mprintf(L" %s",St(MOk)); | |
} | |
} | |
} | |
if (!SkipLastName && !IsPathDiv(*PointToLastChar(Path))) | |
Success=MakeDir(Path,true,DirAttr)==MKDIR_SUCCESS; | |
return Success; | |
} | |
void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta) | |
{ | |
#if defined(_WIN_ALL) | |
bool sm=ftm!=NULL && ftm->IsSet(); | |
bool sc=ftc!=NULL && ftc->IsSet(); | |
bool sa=fta!=NULL && fta->IsSet(); | |
uint DirAttr=GetFileAttr(Name); | |
bool ResetAttr=(DirAttr!=0xffffffff && (DirAttr & FILE_ATTRIBUTE_READONLY)!=0); | |
if (ResetAttr) | |
SetFileAttr(Name,0); | |
HANDLE hFile=CreateFile(Name,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE, | |
NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL); | |
if (hFile==INVALID_HANDLE_VALUE) | |
{ | |
wchar LongName[NM]; | |
if (GetWinLongPath(Name,LongName,ASIZE(LongName))) | |
hFile=CreateFile(LongName,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->GetWinFT(&fm); | |
if (sc) | |
ftc->GetWinFT(&fc); | |
if (sa) | |
fta->GetWinFT(&fa); | |
SetFileTime(hFile,sc ? &fc:NULL,sa ? &fa:NULL,sm ? &fm:NULL); | |
CloseHandle(hFile); | |
if (ResetAttr) | |
SetFileAttr(Name,DirAttr); | |
#endif | |
#if defined(_UNIX) || defined(_EMX) | |
File::SetCloseFileTimeByName(Name,ftm,fta); | |
#endif | |
} | |
bool IsRemovable(const wchar *Name) | |
{ | |
#if defined(_WIN_ALL) | |
wchar Root[NM]; | |
GetPathRoot(Name,Root,ASIZE(Root)); | |
int Type=GetDriveType(*Root!=0 ? Root:NULL); | |
return Type==DRIVE_REMOVABLE || Type==DRIVE_CDROM; | |
#else | |
return false; | |
#endif | |
} | |
#ifndef SFX_MODULE | |
int64 GetFreeDisk(const wchar *Name) | |
{ | |
#ifdef _WIN_ALL | |
wchar Root[NM]; | |
GetFilePath(Name,Root,ASIZE(Root)); | |
ULARGE_INTEGER uiTotalSize,uiTotalFree,uiUserFree; | |
uiUserFree.u.LowPart=uiUserFree.u.HighPart=0; | |
if (GetDiskFreeSpaceEx(*Root!=0 ? Root:NULL,&uiUserFree,&uiTotalSize,&uiTotalFree) && | |
uiUserFree.u.HighPart<=uiTotalFree.u.HighPart) | |
return INT32TO64(uiUserFree.u.HighPart,uiUserFree.u.LowPart); | |
return 0; | |
#elif defined(_UNIX) | |
wchar Root[NM]; | |
GetFilePath(Name,Root,ASIZE(Root)); | |
char RootA[NM]; | |
WideToChar(Root,RootA,ASIZE(RootA)); | |
struct statvfs sfs; | |
if (statvfs(*RootA!=0 ? RootA:".",&sfs)!=0) | |
return 0; | |
int64 FreeSize=sfs.f_bsize; | |
FreeSize=FreeSize*sfs.f_bavail; | |
return FreeSize; | |
#else | |
return 0; | |
#endif | |
} | |
#endif | |
#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT) | |
// Return 'true' for FAT and FAT32, so we can adjust the maximum supported | |
// file size to 4 GB for these file systems. | |
bool IsFAT(const wchar *Name) | |
{ | |
wchar Root[NM]; | |
GetPathRoot(Name,Root,ASIZE(Root)); | |
wchar FileSystem[MAX_PATH+1]; | |
if (GetVolumeInformation(Root,NULL,0,NULL,NULL,NULL,FileSystem,ASIZE(FileSystem))) | |
return wcscmp(FileSystem,L"FAT")==0 || wcscmp(FileSystem,L"FAT32")==0; | |
return false; | |
} | |
#endif | |
bool FileExist(const wchar *Name) | |
{ | |
#ifdef _WIN_ALL | |
return GetFileAttr(Name)!=0xffffffff; | |
#elif defined(ENABLE_ACCESS) | |
char NameA[NM]; | |
WideToChar(Name,NameA,ASIZE(NameA)); | |
return access(NameA,0)==0; | |
#else | |
FindData FD; | |
return FindFile::FastFind(Name,&FD); | |
#endif | |
} | |
bool WildFileExist(const wchar *Name) | |
{ | |
if (IsWildcard(Name)) | |
{ | |
FindFile Find; | |
Find.SetMask(Name); | |
FindData fd; | |
return Find.Next(&fd); | |
} | |
return FileExist(Name); | |
} | |
bool IsDir(uint Attr) | |
{ | |
#ifdef _WIN_ALL | |
return Attr!=0xffffffff && (Attr & FILE_ATTRIBUTE_DIRECTORY)!=0; | |
#endif | |
#if defined(_UNIX) | |
return (Attr & 0xF000)==0x4000; | |
#endif | |
} | |
bool IsUnreadable(uint Attr) | |
{ | |
#if defined(_UNIX) && defined(S_ISFIFO) && defined(S_ISSOCK) && defined(S_ISCHR) | |
return S_ISFIFO(Attr) || S_ISSOCK(Attr) || S_ISCHR(Attr); | |
#endif | |
return false; | |
} | |
bool IsLink(uint Attr) | |
{ | |
#ifdef _UNIX | |
return (Attr & 0xF000)==0xA000; | |
#elif defined(_WIN_ALL) | |
return (Attr & FILE_ATTRIBUTE_REPARSE_POINT)!=0; | |
#else | |
return false; | |
#endif | |
} | |
bool IsDeleteAllowed(uint FileAttr) | |
{ | |
#ifdef _WIN_ALL | |
return (FileAttr & (FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN))==0; | |
#else | |
return (FileAttr & (S_IRUSR|S_IWUSR))==(S_IRUSR|S_IWUSR); | |
#endif | |
} | |
void PrepareToDelete(const wchar *Name) | |
{ | |
#if defined(_WIN_ALL) || defined(_EMX) | |
SetFileAttr(Name,0); | |
#endif | |
#ifdef _UNIX | |
if (Name!=NULL) | |
{ | |
char NameA[NM]; | |
WideToChar(Name,NameA,ASIZE(NameA)); | |
chmod(NameA,S_IRUSR|S_IWUSR|S_IXUSR); | |
} | |
#endif | |
} | |
uint GetFileAttr(const wchar *Name) | |
{ | |
#ifdef _WIN_ALL | |
DWORD Attr=GetFileAttributes(Name); | |
if (Attr==0xffffffff) | |
{ | |
wchar LongName[NM]; | |
if (GetWinLongPath(Name,LongName,ASIZE(LongName))) | |
Attr=GetFileAttributes(LongName); | |
} | |
return Attr; | |
#else | |
char NameA[NM]; | |
WideToChar(Name,NameA,ASIZE(NameA)); | |
struct stat st; | |
if (stat(NameA,&st)!=0) | |
return 0; | |
return st.st_mode; | |
#endif | |
} | |
bool SetFileAttr(const wchar *Name,uint Attr) | |
{ | |
#ifdef _WIN_ALL | |
bool Success=SetFileAttributes(Name,Attr)!=0; | |
if (!Success) | |
{ | |
wchar LongName[NM]; | |
if (GetWinLongPath(Name,LongName,ASIZE(LongName))) | |
Success=SetFileAttributes(LongName,Attr)!=0; | |
} | |
return Success; | |
#elif defined(_UNIX) | |
char NameA[NM]; | |
WideToChar(Name,NameA,ASIZE(NameA)); | |
return chmod(NameA,(mode_t)Attr)==0; | |
#else | |
return false; | |
#endif | |
} | |
#if 0 | |
wchar *MkTemp(wchar *Name,size_t MaxSize) | |
{ | |
size_t Length=wcslen(Name); | |
RarTime CurTime; | |
CurTime.SetCurrentTime(); | |
// We cannot use CurTime.GetWin() as is, because its lowest bits can | |
// have low informational value, like being a zero or few fixed numbers. | |
uint Random=(uint)(CurTime.GetWin()/100000); | |
// Using PID we guarantee that different RAR copies use different temp names | |
// even if started in exactly the same time. | |
uint PID=0; | |
#ifdef _WIN_ALL | |
PID=(uint)GetCurrentProcessId(); | |
#elif defined(_UNIX) | |
PID=(uint)getpid(); | |
#endif | |
for (uint Attempt=0;;Attempt++) | |
{ | |
uint Ext=Random%50000+Attempt; | |
wchar RndText[50]; | |
swprintf(RndText,ASIZE(RndText),L"%u.%03u",PID,Ext); | |
if (Length+wcslen(RndText)>=MaxSize || Attempt==1000) | |
return NULL; | |
wcscpy(Name+Length,RndText); | |
if (!FileExist(Name)) | |
break; | |
} | |
return Name; | |
} | |
#endif | |
#if !defined(SFX_MODULE) | |
void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,uint Flags) | |
{ | |
SaveFilePos SavePos(*SrcFile); | |
#ifndef SILENT | |
int64 FileLength=Size==INT64NDF ? SrcFile->FileLength() : Size; | |
#endif | |
if ((Flags & (CALCFSUM_SHOWTEXT|CALCFSUM_SHOWPERCENT))!=0) | |
uiMsg(UIEVENT_FILESUMSTART); | |
if ((Flags & CALCFSUM_CURPOS)==0) | |
SrcFile->Seek(0,SEEK_SET); | |
const size_t BufSize=0x100000; | |
Array<byte> Data(BufSize); | |
DataHash HashCRC,HashBlake2; | |
HashCRC.Init(HASH_CRC32,Threads); | |
HashBlake2.Init(HASH_BLAKE2,Threads); | |
int64 BlockCount=0; | |
int64 TotalRead=0; | |
while (true) | |
{ | |
size_t SizeToRead; | |
if (Size==INT64NDF) // If we process the entire file. | |
SizeToRead=BufSize; // Then always attempt to read the entire buffer. | |
else | |
SizeToRead=(size_t)Min((int64)BufSize,Size); | |
int ReadSize=SrcFile->Read(&Data[0],SizeToRead); | |
if (ReadSize==0) | |
break; | |
TotalRead+=ReadSize; | |
if ((++BlockCount & 0xf)==0) | |
{ | |
#ifndef SILENT | |
if ((Flags & CALCFSUM_SHOWPROGRESS)!=0) | |
uiExtractProgress(TotalRead,FileLength,TotalRead,FileLength); | |
else | |
{ | |
if ((Flags & CALCFSUM_SHOWPERCENT)!=0) | |
uiMsg(UIEVENT_FILESUMPROGRESS,ToPercent(TotalRead,FileLength)); | |
} | |
#endif | |
Wait(); | |
} | |
if (CRC32!=NULL) | |
HashCRC.Update(&Data[0],ReadSize); | |
if (Blake2!=NULL) | |
HashBlake2.Update(&Data[0],ReadSize); | |
if (Size!=INT64NDF) | |
Size-=ReadSize; | |
} | |
if ((Flags & CALCFSUM_SHOWPERCENT)!=0) | |
uiMsg(UIEVENT_FILESUMEND); | |
if (CRC32!=NULL) | |
*CRC32=HashCRC.GetCRC32(); | |
if (Blake2!=NULL) | |
{ | |
HashValue Result; | |
HashBlake2.Result(&Result); | |
memcpy(Blake2,Result.Digest,sizeof(Result.Digest)); | |
} | |
} | |
#endif | |
bool RenameFile(const wchar *SrcName,const wchar *DestName) | |
{ | |
#ifdef _WIN_ALL | |
bool Success=MoveFile(SrcName,DestName)!=0; | |
if (!Success) | |
{ | |
wchar LongName1[NM],LongName2[NM]; | |
if (GetWinLongPath(SrcName,LongName1,ASIZE(LongName1)) && | |
GetWinLongPath(DestName,LongName2,ASIZE(LongName2))) | |
Success=MoveFile(LongName1,LongName2)!=0; | |
} | |
return Success; | |
#else | |
char SrcNameA[NM],DestNameA[NM]; | |
WideToChar(SrcName,SrcNameA,ASIZE(SrcNameA)); | |
WideToChar(DestName,DestNameA,ASIZE(DestNameA)); | |
bool Success=rename(SrcNameA,DestNameA)==0; | |
return Success; | |
#endif | |
} | |
bool DelFile(const wchar *Name) | |
{ | |
#ifdef _WIN_ALL | |
bool Success=DeleteFile(Name)!=0; | |
if (!Success) | |
{ | |
wchar LongName[NM]; | |
if (GetWinLongPath(Name,LongName,ASIZE(LongName))) | |
Success=DeleteFile(LongName)!=0; | |
} | |
return Success; | |
#else | |
char NameA[NM]; | |
WideToChar(Name,NameA,ASIZE(NameA)); | |
bool Success=remove(NameA)==0; | |
return Success; | |
#endif | |
} | |
#if defined(_WIN_ALL) && !defined(SFX_MODULE) | |
bool SetFileCompression(const wchar *Name,bool State) | |
{ | |
HANDLE hFile=CreateFile(Name,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) | |
{ | |
wchar LongName[NM]; | |
if (GetWinLongPath(Name,LongName,ASIZE(LongName))) | |
hFile=CreateFile(LongName,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; | |
} | |
#endif | |