diff --git a/Utilities/File.cpp b/Utilities/File.cpp index d7f96e75dc..1e3dc38d87 100644 --- a/Utilities/File.cpp +++ b/Utilities/File.cpp @@ -794,7 +794,7 @@ fs::file::file(const std::string& path, bs_t mode) #ifdef _WIN32 DWORD access = 0; if (test(mode & fs::read)) access |= GENERIC_READ; - if (test(mode & fs::write)) access |= test(mode & fs::append) ? FILE_APPEND_DATA : GENERIC_WRITE; + if (test(mode & fs::write)) access |= DELETE | (test(mode & fs::append) ? FILE_APPEND_DATA : GENERIC_WRITE); DWORD disp = 0; if (test(mode & fs::create)) @@ -814,8 +814,13 @@ fs::file::file(const std::string& path, bs_t mode) disp = test(mode & fs::trunc) ? TRUNCATE_EXISTING : OPEN_EXISTING; } - DWORD share = FILE_SHARE_READ; - if (!test(mode & fs::unshare)) + DWORD share = 0; + if (!test(mode, fs::unread) || !test(mode & fs::write)) + { + share |= FILE_SHARE_READ; + } + + if (!test(mode, fs::lock + fs::unread) || !test(mode & fs::write)) { share |= FILE_SHARE_WRITE | FILE_SHARE_DELETE; } @@ -944,10 +949,17 @@ fs::file::file(const std::string& path, bs_t mode) if (test(mode & fs::append)) flags |= O_APPEND; if (test(mode & fs::create)) flags |= O_CREAT; - if (test(mode & fs::trunc)) flags |= O_TRUNC; + if (test(mode & fs::trunc) && !test(mode, fs::lock + fs::unread)) flags |= O_TRUNC; if (test(mode & fs::excl)) flags |= O_EXCL; - const int fd = ::open(path.c_str(), flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + int perm = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + + if (test(mode & fs::write) && test(mode & fs::unread)) + { + perm = 0; + } + + const int fd = ::open(path.c_str(), flags, perm); if (fd == -1) { @@ -955,13 +967,19 @@ fs::file::file(const std::string& path, bs_t mode) return; } - if (test(mode & fs::unshare) && ::flock(fd, LOCK_EX | LOCK_NB) != 0) + if (test(mode & fs::write) && test(mode, fs::lock + fs::unread) && ::flock(fd, LOCK_EX | LOCK_NB) != 0) { g_tls_error = errno == EWOULDBLOCK ? fs::error::acces : to_error(errno); ::close(fd); return; } + if (test(mode & fs::trunc) && test(mode, fs::lock + fs::unread)) + { + // Postpone truncation in order to avoid using O_TRUNC on a locked file + ::ftruncate(fd, 0); + } + class unix_file final : public file_base, public get_native_handle { const int m_fd; diff --git a/Utilities/File.h b/Utilities/File.h index b2c35a0c53..ae679a1ee7 100644 --- a/Utilities/File.h +++ b/Utilities/File.h @@ -25,7 +25,8 @@ namespace fs create, trunc, excl, - unshare, + lock, + unread, __bitset_enum_max }; @@ -36,7 +37,8 @@ namespace fs constexpr auto create = +open_mode::create; // Create file if it doesn't exist constexpr auto trunc = +open_mode::trunc; // Clear opened file if it's not empty constexpr auto excl = +open_mode::excl; // Failure if the file already exists (used with `create`) - constexpr auto unshare = +open_mode::unshare; // Prevent opening the file twice + constexpr auto lock = +open_mode::lock; // Prevent opening the file more than once + constexpr auto unread = +open_mode::unread; // Aggressively prevent reading the opened file (do not use) constexpr auto rewrite = open_mode::write + open_mode::create + open_mode::trunc; @@ -185,7 +187,7 @@ namespace fs file() = default; // Open file with specified mode - explicit file(const std::string& path, bs_t mode = ::fs::read); + explicit file(const std::string& path, bs_t mode = ::fs::read); // Open memory for read explicit file(const void* ptr, std::size_t size); @@ -400,7 +402,7 @@ namespace fs { m_dir = std::move(ptr); } - + std::unique_ptr release() { return std::move(m_dir); diff --git a/Utilities/Log.cpp b/Utilities/Log.cpp index 8fc12391f8..97da466863 100644 --- a/Utilities/Log.cpp +++ b/Utilities/Log.cpp @@ -18,6 +18,7 @@ using namespace std::literals::chrono_literals; #include #else #include +#include #endif #include @@ -309,7 +310,7 @@ logs::file_writer::file_writer(const std::string& name) try { - if (!m_file.open(buf_name, fs::read + fs::write + fs::create + fs::trunc + fs::unshare)) + if (!m_file.open(buf_name, fs::read + fs::rewrite + fs::lock)) { if (fs::g_tls_error == fs::error::acces) { @@ -361,11 +362,18 @@ logs::file_writer::file_writer(const std::string& name) // Actual log file (allowed to fail) m_fout.open(log_name, fs::rewrite); - // Compressed log - if (!m_fout2.open(log_name + ".gz", fs::rewrite) || deflateInit2(&m_zs, 9, Z_DEFLATED, 16 + 15, 9, Z_DEFAULT_STRATEGY) != Z_OK) + // Compressed log, make it inaccessible (foolproof) + if (!m_fout2.open(log_name + ".gz", fs::rewrite + fs::unread) || deflateInit2(&m_zs, 9, Z_DEFLATED, 16 + 15, 9, Z_DEFAULT_STRATEGY) != Z_OK) { m_fout2.close(); } + +#ifdef _WIN32 + // Autodelete compressed log file + FILE_DISPOSITION_INFO disp; + disp.DeleteFileW = TRUE; + SetFileInformationByHandle(m_fout2.get_handle(), FileDispositionInfo, &disp, sizeof(disp)); +#endif } catch (const std::exception& e) { @@ -443,9 +451,16 @@ logs::file_writer::~file_writer() } #ifdef _WIN32 + // Cancel compressed log file autodeletion + FILE_DISPOSITION_INFO disp; + disp.DeleteFileW = FALSE; + SetFileInformationByHandle(m_fout2.get_handle(), FileDispositionInfo, &disp, sizeof(disp)); + UnmapViewOfFile(m_fptr); CloseHandle(m_fmap); #else + // Restore compressed log file permissions + ::fchmod(m_fout2.get_handle(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ::munmap(m_fptr, s_log_size); #endif } @@ -591,7 +606,7 @@ void logs::file_listener::log(u64 stamp, const logs::message& msg, const std::st case level::_uninit: text = u8"· "; break; } - // Print miscosecond timestamp + // Print µs timestamp const u64 hours = stamp / 3600'000'000; const u64 mins = (stamp % 3600'000'000) / 60'000'000; const u64 secs = (stamp % 60'000'000) / 1'000'000;