diff options
Diffstat (limited to '3rdparty/lzma/CPP/Windows/FileDir.cpp')
-rw-r--r-- | 3rdparty/lzma/CPP/Windows/FileDir.cpp | 703 |
1 files changed, 621 insertions, 82 deletions
diff --git a/3rdparty/lzma/CPP/Windows/FileDir.cpp b/3rdparty/lzma/CPP/Windows/FileDir.cpp index da71b710bdc..5b1f340b5c7 100644 --- a/3rdparty/lzma/CPP/Windows/FileDir.cpp +++ b/3rdparty/lzma/CPP/Windows/FileDir.cpp @@ -2,8 +2,21 @@ #include "StdAfx.h" -#ifndef _UNICODE + +#ifndef _WIN32 +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <limits.h> +#include <unistd.h> +#include <time.h> +#include <utime.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> + #include "../Common/StringConvert.h" +#include "../Common/C_FileIO.h" #endif #include "FileDir.h" @@ -18,58 +31,94 @@ using namespace NWindows; using namespace NFile; using namespace NName; +#ifndef _WIN32 + +static bool FiTime_To_timespec(const CFiTime *ft, timespec &ts) +{ + if (ft) + { + ts = *ft; + return true; + } + // else + { + ts.tv_sec = 0; + ts.tv_nsec = + #ifdef UTIME_OMIT + UTIME_OMIT; // -2 keep old timesptamp + #else + // UTIME_NOW; -1 // set to the current time + 0; + #endif + return false; + } +} +#endif + namespace NWindows { namespace NFile { namespace NDir { +#ifdef _WIN32 + #ifndef UNDER_CE bool GetWindowsDir(FString &path) { - UINT needLength; + const unsigned kBufSize = MAX_PATH + 16; + UINT len; #ifndef _UNICODE if (!g_IsNT) { - TCHAR s[MAX_PATH + 2]; + TCHAR s[kBufSize + 1]; s[0] = 0; - needLength = ::GetWindowsDirectory(s, MAX_PATH + 1); + len = ::GetWindowsDirectory(s, kBufSize); path = fas2fs(s); } else #endif { - WCHAR s[MAX_PATH + 2]; + WCHAR s[kBufSize + 1]; s[0] = 0; - needLength = ::GetWindowsDirectoryW(s, MAX_PATH + 1); + len = ::GetWindowsDirectoryW(s, kBufSize); path = us2fs(s); } - return (needLength > 0 && needLength <= MAX_PATH); + return (len != 0 && len < kBufSize); } + +/* +new DOCs for GetSystemDirectory: + returned path does not end with a backslash unless the + system directory is the root directory. +*/ + bool GetSystemDir(FString &path) { - UINT needLength; + const unsigned kBufSize = MAX_PATH + 16; + UINT len; #ifndef _UNICODE if (!g_IsNT) { - TCHAR s[MAX_PATH + 2]; + TCHAR s[kBufSize + 1]; s[0] = 0; - needLength = ::GetSystemDirectory(s, MAX_PATH + 1); + len = ::GetSystemDirectory(s, kBufSize); path = fas2fs(s); } else #endif { - WCHAR s[MAX_PATH + 2]; + WCHAR s[kBufSize + 1]; s[0] = 0; - needLength = ::GetSystemDirectoryW(s, MAX_PATH + 1); + len = ::GetSystemDirectoryW(s, kBufSize); path = us2fs(s); } - return (needLength > 0 && needLength <= MAX_PATH); + return (len != 0 && len < kBufSize); } -#endif +#endif // UNDER_CE + -bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) +bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) { #ifndef _UNICODE if (!g_IsNT) @@ -83,7 +132,7 @@ bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const IF_USE_MAIN_PATH hDir = ::CreateFileW(fs2us(path), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - #ifdef WIN_LONG_PATH + #ifdef Z7_LONG_PATH if (hDir == INVALID_HANDLE_VALUE && USE_SUPER_PATH) { UString superPath; @@ -102,6 +151,8 @@ bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const return res; } + + bool SetFileAttrib(CFSTR path, DWORD attrib) { #ifndef _UNICODE @@ -116,7 +167,7 @@ bool SetFileAttrib(CFSTR path, DWORD attrib) IF_USE_MAIN_PATH if (::SetFileAttributesW(fs2us(path), attrib)) return true; - #ifdef WIN_LONG_PATH + #ifdef Z7_LONG_PATH if (USE_SUPER_PATH) { UString superPath; @@ -128,6 +179,17 @@ bool SetFileAttrib(CFSTR path, DWORD attrib) return false; } + +bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib) +{ + #ifdef _WIN32 + if ((attrib & 0xF0000000) != 0) + attrib &= 0x3FFF; + #endif + return SetFileAttrib(path, attrib); +} + + bool RemoveDir(CFSTR path) { #ifndef _UNICODE @@ -142,7 +204,7 @@ bool RemoveDir(CFSTR path) IF_USE_MAIN_PATH if (::RemoveDirectoryW(fs2us(path))) return true; - #ifdef WIN_LONG_PATH + #ifdef Z7_LONG_PATH if (USE_SUPER_PATH) { UString superPath; @@ -154,6 +216,7 @@ bool RemoveDir(CFSTR path) return false; } + bool MyMoveFile(CFSTR oldFile, CFSTR newFile) { #ifndef _UNICODE @@ -166,9 +229,11 @@ bool MyMoveFile(CFSTR oldFile, CFSTR newFile) #endif { IF_USE_MAIN_PATH_2(oldFile, newFile) + { if (::MoveFileW(fs2us(oldFile), fs2us(newFile))) return true; - #ifdef WIN_LONG_PATH + } + #ifdef Z7_LONG_PATH if (USE_SUPER_PATH_2) { UString d1, d2; @@ -181,7 +246,6 @@ bool MyMoveFile(CFSTR oldFile, CFSTR newFile) } #ifndef UNDER_CE - EXTERN_C_BEGIN typedef BOOL (WINAPI *Func_CreateHardLinkW)( LPCWSTR lpFileName, @@ -189,6 +253,7 @@ typedef BOOL (WINAPI *Func_CreateHardLinkW)( LPSECURITY_ATTRIBUTES lpSecurityAttributes ); EXTERN_C_END +#endif // UNDER_CE bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName) { @@ -205,14 +270,19 @@ bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName) else #endif { - Func_CreateHardLinkW my_CreateHardLinkW = (Func_CreateHardLinkW) - ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW"); + const + Func_CreateHardLinkW + my_CreateHardLinkW = Z7_GET_PROC_ADDRESS( + Func_CreateHardLinkW, ::GetModuleHandleW(L"kernel32.dll"), + "CreateHardLinkW"); if (!my_CreateHardLinkW) return false; IF_USE_MAIN_PATH_2(newFileName, existFileName) + { if (my_CreateHardLinkW(fs2us(newFileName), fs2us(existFileName), NULL)) return true; - #ifdef WIN_LONG_PATH + } + #ifdef Z7_LONG_PATH if (USE_SUPER_PATH_2) { UString d1, d2; @@ -224,7 +294,6 @@ bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName) return false; } -#endif /* WinXP-64 CreateDir(): @@ -263,7 +332,7 @@ bool CreateDir(CFSTR path) IF_USE_MAIN_PATH if (::CreateDirectoryW(fs2us(path), NULL)) return true; - #ifdef WIN_LONG_PATH + #ifdef Z7_LONG_PATH if ((!USE_MAIN_PATH || ::GetLastError() != ERROR_ALREADY_EXISTS) && USE_SUPER_PATH) { UString superPath; @@ -298,7 +367,7 @@ static bool CreateDir2(CFSTR path) IF_USE_MAIN_PATH if (::CreateDirectoryW(fs2us(path), NULL)) return true; - #ifdef WIN_LONG_PATH + #ifdef Z7_LONG_PATH if ((!USE_MAIN_PATH || ::GetLastError() != ERROR_ALREADY_EXISTS) && USE_SUPER_PATH) { UString superPath; @@ -324,12 +393,16 @@ static bool CreateDir2(CFSTR path) return fi.IsDir(); } +#endif // _WIN32 + +static bool CreateDir2(CFSTR path); + bool CreateComplexDir(CFSTR _path) { #ifdef _WIN32 { - DWORD attrib = NFind::GetFileAttrib(_path); + const DWORD attrib = NFind::GetFileAttrib(_path); if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0) return true; } @@ -339,13 +412,23 @@ bool CreateComplexDir(CFSTR _path) if (IsDriveRootPath_SuperAllowed(_path)) return false; - unsigned prefixSize = GetRootPrefixSize(_path); + const unsigned prefixSize = GetRootPrefixSize(_path); - #endif + #endif // UNDER_CE + + #else // _WIN32 + + // Posix + NFind::CFileInfo fi; + if (fi.Find(_path)) + { + if (fi.IsDir()) + return true; + } - #endif + #endif // _WIN32 - FString path = _path; + FString path (_path); int pos = path.ReverseFind_PathSepar(); if (pos >= 0 && (unsigned)pos == path.Len() - 1) @@ -355,8 +438,8 @@ bool CreateComplexDir(CFSTR _path) path.DeleteBack(); } - const FString path2 = path; - pos = path.Len(); + const FString path2 (path); + pos = (int)path.Len(); for (;;) { @@ -375,17 +458,17 @@ bool CreateComplexDir(CFSTR _path) return false; #endif - path.DeleteFrom(pos); + path.DeleteFrom((unsigned)pos); } while (pos < (int)path2.Len()) { - int pos2 = NName::FindSepar(path2.Ptr(pos + 1)); + int pos2 = NName::FindSepar(path2.Ptr((unsigned)pos + 1)); if (pos2 < 0) - pos = path2.Len(); + pos = (int)path2.Len(); else pos += 1 + pos2; - path.SetFrom(path2, pos); + path.SetFrom(path2, (unsigned)pos); if (!CreateDir(path)) return false; } @@ -393,6 +476,9 @@ bool CreateComplexDir(CFSTR _path) return true; } + +#ifdef _WIN32 + bool DeleteFileAlways(CFSTR path) { /* If alt stream, we also need to clear READ-ONLY attribute of main file before delete. @@ -403,7 +489,7 @@ bool DeleteFileAlways(CFSTR path) && (attrib & FILE_ATTRIBUTE_DIRECTORY) == 0 && (attrib & FILE_ATTRIBUTE_READONLY) != 0) { - if (!SetFileAttrib(path, attrib & ~FILE_ATTRIBUTE_READONLY)) + if (!SetFileAttrib(path, attrib & ~(DWORD)FILE_ATTRIBUTE_READONLY)) return false; } } @@ -422,7 +508,7 @@ bool DeleteFileAlways(CFSTR path) IF_USE_MAIN_PATH if (::DeleteFileW(fs2us(path))) return true; - #ifdef WIN_LONG_PATH + #ifdef Z7_LONG_PATH if (USE_SUPER_PATH) { UString superPath; @@ -434,6 +520,8 @@ bool DeleteFileAlways(CFSTR path) return false; } + + bool RemoveDirWithSubItems(const FString &path) { bool needRemoveSubItems = true; @@ -452,12 +540,14 @@ bool RemoveDirWithSubItems(const FString &path) if (needRemoveSubItems) { - FString s = path; + FString s (path); s.Add_PathSepar(); - unsigned prefixSize = s.Len(); - s += FCHAR_ANY_MASK; - NFind::CEnumerator enumerator(s); - NFind::CFileInfo fi; + const unsigned prefixSize = s.Len(); + NFind::CEnumerator enumerator; + enumerator.SetDirPrefix(s); + NFind::CDirEntry fi; + bool isError = false; + DWORD lastError = 0; while (enumerator.Next(fi)) { s.DeleteFrom(prefixSize); @@ -465,18 +555,32 @@ bool RemoveDirWithSubItems(const FString &path) if (fi.IsDir()) { if (!RemoveDirWithSubItems(s)) - return false; + { + lastError = GetLastError(); + isError = true; + } } else if (!DeleteFileAlways(s)) - return false; + { + lastError = GetLastError(); + isError = false; + } + } + if (isError) + { + SetLastError(lastError); + return false; } } + // we clear read-only attrib to remove read-only dir if (!SetFileAttrib(path, 0)) return false; return RemoveDir(path); } +#endif // _WIN32 + #ifdef UNDER_CE bool MyGetFullPathName(CFSTR path, FString &resFullPath) @@ -492,9 +596,14 @@ bool MyGetFullPathName(CFSTR path, FString &resFullPath) return GetFullPath(path, resFullPath); } +#ifdef _WIN32 + +/* Win10: SetCurrentDirectory() doesn't support long paths and + doesn't support super prefix "\\?\", if long path behavior is not + enabled in registry (LongPathsEnabled) and in manifest (longPathAware). */ + bool SetCurrentDir(CFSTR path) { - // SetCurrentDirectory doesn't support \\?\ prefix #ifndef _UNICODE if (!g_IsNT) { @@ -507,30 +616,80 @@ bool SetCurrentDir(CFSTR path) } } + +/* +we use system function GetCurrentDirectory() +new GetCurrentDirectory() DOCs: + - If the function fails, the return value is zero. + - If the function succeeds, the return value specifies + the number of characters that are written to the buffer, + not including the terminating null character. + - If the buffer is not large enough, the return value specifies + the required size of the buffer, in characters, + including the null-terminating character. + +GetCurrentDir() calls GetCurrentDirectory(). +GetCurrentDirectory() in win10 in tests: + the returned (path) does not end with a backslash, if + current directory is not root directory of drive. + But that behavior is not guarantied in specification docs. +*/ + bool GetCurrentDir(FString &path) { + const unsigned kBufSize = MAX_PATH + 16; path.Empty(); - DWORD needLength; + #ifndef _UNICODE if (!g_IsNT) { - TCHAR s[MAX_PATH + 2]; + TCHAR s[kBufSize + 1]; s[0] = 0; - needLength = ::GetCurrentDirectory(MAX_PATH + 1, s); + const DWORD len = ::GetCurrentDirectory(kBufSize, s); + if (len == 0 || len >= kBufSize) + return false; + s[kBufSize] = 0; // optional guard path = fas2fs(s); + return true; } else #endif { - WCHAR s[MAX_PATH + 2]; - s[0] = 0; - needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, s); - path = us2fs(s); + DWORD len; + { + WCHAR s[kBufSize + 1]; + s[0] = 0; + len = ::GetCurrentDirectoryW(kBufSize, s); + if (len == 0) + return false; + if (len < kBufSize) + { + s[kBufSize] = 0; // optional guard + path = us2fs(s); + return true; + } + } + UString temp; + const DWORD len2 = ::GetCurrentDirectoryW(len, temp.GetBuf(len)); + if (len2 == 0) + return false; + temp.ReleaseBuf_CalcLen(len); + if (temp.Len() != len2 || len - 1 != len2) + { + /* it's unexpected case, if current dir of process + was changed between two function calls, + or some unexpected function implementation */ + // SetLastError((DWORD)E_FAIL); // we can set some error code + return false; + } + path = us2fs(temp); + return true; } - return (needLength > 0 && needLength <= MAX_PATH); } -#endif +#endif // _WIN32 +#endif // UNDER_CE + bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName) { @@ -538,8 +697,9 @@ bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName if (!res) resDirPrefix = path; int pos = resDirPrefix.ReverseFind_PathSepar(); - resFileName = resDirPrefix.Ptr(pos + 1); - resDirPrefix.DeleteFrom(pos + 1); + pos++; + resFileName = resDirPrefix.Ptr((unsigned)pos); + resDirPrefix.DeleteFrom((unsigned)pos); return res; } @@ -549,50 +709,85 @@ bool GetOnlyDirPrefix(CFSTR path, FString &resDirPrefix) return GetFullPathAndSplit(path, resDirPrefix, resFileName); } + + bool MyGetTempPath(FString &path) { - path.Empty(); - DWORD needLength; + #ifdef _WIN32 + + /* + new DOCs for GetTempPathW(): + - The returned string ends with a backslash. + - The maximum possible return value is MAX_PATH+1 (261). + */ + + const unsigned kBufSize = MAX_PATH + 16; + DWORD len; #ifndef _UNICODE if (!g_IsNT) { - TCHAR s[MAX_PATH + 2]; + TCHAR s[kBufSize + 1]; s[0] = 0; - needLength = ::GetTempPath(MAX_PATH + 1, s); + len = ::GetTempPath(kBufSize, s); path = fas2fs(s); } else #endif { - WCHAR s[MAX_PATH + 2]; + WCHAR s[kBufSize + 1]; s[0] = 0; - needLength = ::GetTempPathW(MAX_PATH + 1, s);; + len = ::GetTempPathW(kBufSize, s); path = us2fs(s); } - return (needLength > 0 && needLength <= MAX_PATH); + /* win10: GetTempPathW() doesn't set backslash at the end of path, + if (buffer_size == len_of(path_with_backslash)). + So we normalize path here: */ + NormalizeDirPathPrefix(path); + return (len != 0 && len < kBufSize); + + #else // !_WIN32 + + // FIXME: improve that code + path = STRING_PATH_SEPARATOR "tmp"; + const char *s; + if (NFind::DoesDirExist_FollowLink(path)) + s = STRING_PATH_SEPARATOR "tmp" STRING_PATH_SEPARATOR; + else + s = "." STRING_PATH_SEPARATOR; + path = s; + return true; + + #endif } -static bool CreateTempFile(CFSTR prefix, bool addRandom, FString &path, NIO::COutFile *outFile) + +bool CreateTempFile2(CFSTR prefix, bool addRandom, AString &postfix, NIO::COutFile *outFile) { - UInt32 d = (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId(); + UInt32 d = + #ifdef _WIN32 + (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId(); + #else + (UInt32)(time(NULL) << 12) ^ ((UInt32)getppid() << 14) ^ (UInt32)(getpid()); + #endif + for (unsigned i = 0; i < 100; i++) { - path = prefix; + postfix.Empty(); if (addRandom) { - FChar s[16]; - UInt32 value = d; + char s[16]; + UInt32 val = d; unsigned k; for (k = 0; k < 8; k++) { - unsigned t = value & 0xF; - value >>= 4; - s[k] = (FChar)((t < 10) ? ('0' + t) : ('A' + (t - 10))); + const unsigned t = val & 0xF; + val >>= 4; + s[k] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); } s[k] = '\0'; if (outFile) - path += FChar('.'); - path += s; + postfix.Add_Dot(); + postfix += s; UInt32 step = GetTickCount() + 2; if (step == 0) step = 1; @@ -600,7 +795,9 @@ static bool CreateTempFile(CFSTR prefix, bool addRandom, FString &path, NIO::COu } addRandom = true; if (outFile) - path += FTEXT(".tmp"); + postfix += ".tmp"; + FString path (prefix); + path += postfix; if (NFind::DoesFileOrDirExist(path)) { SetLastError(ERROR_ALREADY_EXISTS); @@ -616,12 +813,12 @@ static bool CreateTempFile(CFSTR prefix, bool addRandom, FString &path, NIO::COu if (CreateDir(path)) return true; } - DWORD error = GetLastError(); + const DWORD error = GetLastError(); if (error != ERROR_FILE_EXISTS && error != ERROR_ALREADY_EXISTS) break; } - path.Empty(); + postfix.Empty(); return false; } @@ -629,8 +826,12 @@ bool CTempFile::Create(CFSTR prefix, NIO::COutFile *outFile) { if (!Remove()) return false; - if (!CreateTempFile(prefix, false, _path, outFile)) + _path.Empty(); + AString postfix; + if (!CreateTempFile2(prefix, false, postfix, outFile)) return false; + _path = prefix; + _path += postfix; _mustBeDeleted = true; return true; } @@ -639,11 +840,16 @@ bool CTempFile::CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFil { if (!Remove()) return false; + _path.Empty(); FString tempPath; if (!MyGetTempPath(tempPath)) return false; - if (!CreateTempFile(tempPath + namePrefix, true, _path, outFile)) + AString postfix; + tempPath += namePrefix; + if (!CreateTempFile2(tempPath, true, postfix, outFile)) return false; + _path = tempPath; + _path += postfix; _mustBeDeleted = true; return true; } @@ -658,23 +864,44 @@ bool CTempFile::Remove() bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore) { + // DWORD attrib = 0; if (deleteDestBefore) - if (NFind::DoesFileExist(name)) + { + if (NFind::DoesFileExist_Raw(name)) + { + // attrib = NFind::GetFileAttrib(name); if (!DeleteFileAlways(name)) return false; + } + } DisableDeleting(); return MyMoveFile(_path, name); + + /* + if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY)) + { + DWORD attrib2 = NFind::GetFileAttrib(name); + if (attrib2 != INVALID_FILE_ATTRIBUTES) + SetFileAttrib(name, attrib2 | FILE_ATTRIBUTE_READONLY); + } + */ } +#ifdef _WIN32 bool CTempDir::Create(CFSTR prefix) { if (!Remove()) return false; + _path.Empty(); FString tempPath; if (!MyGetTempPath(tempPath)) return false; - if (!CreateTempFile(tempPath + prefix, true, _path, NULL)) + tempPath += prefix; + AString postfix; + if (!CreateTempFile2(tempPath, true, postfix, NULL)) return false; + _path = tempPath; + _path += postfix; _mustBeDeleted = true; return true; } @@ -686,5 +913,317 @@ bool CTempDir::Remove() _mustBeDeleted = !RemoveDirWithSubItems(_path); return !_mustBeDeleted; } +#endif + + + +#ifndef _WIN32 + +bool RemoveDir(CFSTR path) +{ + return (rmdir(path) == 0); +} + + +static BOOL My_CopyFile(CFSTR oldFile, CFSTR newFile) +{ + NWindows::NFile::NIO::COutFile outFile; + if (!outFile.Create(newFile, false)) + return FALSE; + + NWindows::NFile::NIO::CInFile inFile; + if (!inFile.Open(oldFile)) + return FALSE; + + char buf[1 << 14]; + + for (;;) + { + const ssize_t num = inFile.read_part(buf, sizeof(buf)); + if (num == 0) + return TRUE; + if (num < 0) + return FALSE; + size_t processed; + const ssize_t num2 = outFile.write_full(buf, (size_t)num, processed); + if (num2 != num || processed != (size_t)num) + return FALSE; + } +} + + +bool MyMoveFile(CFSTR oldFile, CFSTR newFile) +{ + int res = rename(oldFile, newFile); + if (res == 0) + return true; + if (errno != EXDEV) // (oldFile and newFile are not on the same mounted filesystem) + return false; + + if (My_CopyFile(oldFile, newFile) == FALSE) + return false; + + struct stat info_file; + res = stat(oldFile, &info_file); + if (res != 0) + return false; + + /* + ret = chmod(dst,info_file.st_mode & g_umask.mask); + */ + return (unlink(oldFile) == 0); +} + + +bool CreateDir(CFSTR path) +{ + return (mkdir(path, 0777) == 0); // change it +} + +static bool CreateDir2(CFSTR path) +{ + return (mkdir(path, 0777) == 0); // change it +} + + +bool DeleteFileAlways(CFSTR path) +{ + return (remove(path) == 0); +} + +bool SetCurrentDir(CFSTR path) +{ + return (chdir(path) == 0); +} + + +bool GetCurrentDir(FString &path) +{ + path.Empty(); + + #define MY_PATH_MAX PATH_MAX + // #define MY_PATH_MAX 1024 + + char s[MY_PATH_MAX + 1]; + char *res = getcwd(s, MY_PATH_MAX); + if (res) + { + path = fas2fs(s); + return true; + } + { + // if (errno != ERANGE) return false; + #if defined(__GLIBC__) || defined(__APPLE__) + /* As an extension to the POSIX.1-2001 standard, glibc's getcwd() + allocates the buffer dynamically using malloc(3) if buf is NULL. */ + res = getcwd(NULL, 0); + if (res) + { + path = fas2fs(res); + ::free(res); + return true; + } + #endif + return false; + } +} + + + +// #undef UTIME_OMIT // to debug + +#ifndef UTIME_OMIT + /* we can define UTIME_OMIT for debian and another systems. + Is it OK to define UTIME_OMIT to -2 here, if UTIME_OMIT is not defined? */ + // #define UTIME_OMIT -2 +#endif + + + + + +bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) +{ + // need testing + /* + struct utimbuf buf; + struct stat st; + UNUSED_VAR(cTime) + + printf("\nstat = %s\n", path); + int ret = stat(path, &st); + + if (ret == 0) + { + buf.actime = st.st_atime; + buf.modtime = st.st_mtime; + } + else + { + time_t cur_time = time(0); + buf.actime = cur_time; + buf.modtime = cur_time; + } + + if (aTime) + { + UInt32 ut; + if (NTime::FileTimeToUnixTime(*aTime, ut)) + buf.actime = ut; + } + + if (mTime) + { + UInt32 ut; + if (NTime::FileTimeToUnixTime(*mTime, ut)) + buf.modtime = ut; + } + + return utime(path, &buf) == 0; + */ + + // if (!aTime && !mTime) return true; + + struct timespec times[2]; + UNUSED_VAR(cTime) + + bool needChange; + needChange = FiTime_To_timespec(aTime, times[0]); + needChange |= FiTime_To_timespec(mTime, times[1]); + + /* + if (mTime) + { + printf("\n time = %ld.%9ld\n", mTime->tv_sec, mTime->tv_nsec); + } + */ + + if (!needChange) + return true; + const int flags = 0; // follow link + // = AT_SYMLINK_NOFOLLOW; // don't follow link + return utimensat(AT_FDCWD, path, times, flags) == 0; +} + + + +struct C_umask +{ + mode_t mask; + + C_umask() + { + /* by security reasons we restrict attributes according + with process's file mode creation mask (umask) */ + const mode_t um = umask(0); // octal :0022 is expected + mask = 0777 & (~um); // octal: 0755 is expected + umask(um); // restore the umask + // printf("\n umask = 0%03o mask = 0%03o\n", um, mask); + + // mask = 0777; // debug we can disable the restriction: + } +}; + +static C_umask g_umask; + +// #define PRF(x) x; +#define PRF(x) + +#define TRACE_SetFileAttrib(msg) \ + PRF(printf("\nSetFileAttrib(%s, %x) : %s\n", (const char *)path, attrib, msg);) + +#define TRACE_chmod(s, mode) \ + PRF(printf("\n chmod(%s, %o)\n", (const char *)path, (unsigned)(mode));) + +int my_chown(CFSTR path, uid_t owner, gid_t group) +{ + return chown(path, owner, group); +} + +bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib) +{ + TRACE_SetFileAttrib("") + + struct stat st; + + bool use_lstat = true; + if (use_lstat) + { + if (lstat(path, &st) != 0) + { + TRACE_SetFileAttrib("bad lstat()") + return false; + } + // TRACE_chmod("lstat", st.st_mode); + } + else + { + if (stat(path, &st) != 0) + { + TRACE_SetFileAttrib("bad stat()") + return false; + } + } + + if (attrib & FILE_ATTRIBUTE_UNIX_EXTENSION) + { + TRACE_SetFileAttrib("attrib & FILE_ATTRIBUTE_UNIX_EXTENSION") + st.st_mode = attrib >> 16; + if (S_ISDIR(st.st_mode)) + { + // user/7z must be able to create files in this directory + st.st_mode |= (S_IRUSR | S_IWUSR | S_IXUSR); + } + else if (!S_ISREG(st.st_mode)) + return true; + } + else if (S_ISLNK(st.st_mode)) + { + /* for most systems: permissions for symlinks are fixed to rwxrwxrwx. + so we don't need chmod() for symlinks. */ + return true; + // SetLastError(ENOSYS); + // return false; + } + else + { + TRACE_SetFileAttrib("Only Windows Attributes") + // Only Windows Attributes + if (S_ISDIR(st.st_mode) + || (attrib & FILE_ATTRIBUTE_READONLY) == 0) + return true; + st.st_mode &= ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); // octal: ~0222; // disable write permissions + } + + int res; + /* + if (S_ISLNK(st.st_mode)) + { + printf("\nfchmodat()\n"); + TRACE_chmod(path, (st.st_mode) & g_umask.mask) + // AT_SYMLINK_NOFOLLOW is not implemted still in Linux. + res = fchmodat(AT_FDCWD, path, (st.st_mode) & g_umask.mask, + S_ISLNK(st.st_mode) ? AT_SYMLINK_NOFOLLOW : 0); + } + else + */ + { + TRACE_chmod(path, (st.st_mode) & g_umask.mask) + res = chmod(path, (st.st_mode) & g_umask.mask); + } + // TRACE_SetFileAttrib("End") + return (res == 0); +} + + +bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName) +{ + PRF(printf("\nhard link() %s -> %s\n", newFileName, existFileName);) + return (link(existFileName, newFileName) == 0); +} + +#endif // !_WIN32 + +// #endif }}} |