From f0f3f094c5fa05bafe1963d1ea13f1be39a6673b Mon Sep 17 00:00:00 2001 From: B Stack Date: Sun, 17 May 2020 11:17:28 -0400 Subject: add upstream 10.24 --- zen/dir_watcher.h | 4 ++-- zen/file_access.cpp | 15 +++++++-------- zen/file_error.h | 2 -- zen/file_traverser.cpp | 2 +- zen/globals.h | 17 +++++++++-------- zen/legacy_compiler.h | 48 +++--------------------------------------------- zen/open_ssl.cpp | 1 - zen/ring_buffer.h | 2 +- zen/shell_execute.cpp | 2 +- zen/shutdown.cpp | 4 ++-- zen/string_base.h | 49 ++++--------------------------------------------- zen/sys_error.h | 8 ++++---- zen/system.cpp | 41 +++++++++++++++++++++++++---------------- zen/thread.cpp | 2 ++ zen/thread.h | 5 +---- 15 files changed, 62 insertions(+), 140 deletions(-) (limited to 'zen') diff --git a/zen/dir_watcher.h b/zen/dir_watcher.h index 3103039d..bf71fda9 100644 --- a/zen/dir_watcher.h +++ b/zen/dir_watcher.h @@ -44,8 +44,8 @@ public: enum class ChangeType { - create, //informal! - update, //use for debugging/logging only! + create, // + update, //informal: use for debugging/logging only! remove, // baseFolderUnavailable, //1. not existing or 2. can't access }; diff --git a/zen/file_access.cpp b/zen/file_access.cpp index cb5a45ed..9a49cd55 100644 --- a/zen/file_access.cpp +++ b/zen/file_access.cpp @@ -127,6 +127,7 @@ std::optional zen::itemStillExists(const Zstring& itemPath) //throw Fi assert(!itemName.empty()); const std::optional parentType = itemStillExists(*parentPath); //throw FileError + if (parentType && *parentType != ItemType::FILE /*obscure, but possible (and not an error)*/) try { @@ -246,14 +247,12 @@ void zen::removeDirectoryPlain(const Zstring& dirPath) //throw FileError } throw FileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtPath(dirPath)), formatSystemError(functionName, ec)); } - /* - Windows: may spuriously fail with ERROR_DIR_NOT_EMPTY(145) even though all child items have - successfully been *marked* for deletion, but some application still has a handle open! - e.g. Open "C:\Test\Dir1\Dir2" (filled with lots of files) in Explorer, then delete "C:\Test\Dir1" via ::RemoveDirectory() => Error 145 - Sample code: http://us.generation-nt.com/answer/createfile-directory-handles-removing-parent-help-29126332.html - Alternatives: 1. move file/empty folder to some other location, then DeleteFile()/RemoveDirectory() - 2. use CreateFile/FILE_FLAG_DELETE_ON_CLOSE *without* FILE_SHARE_DELETE instead of DeleteFile() => early failure - */ + /* Windows: may spuriously fail with ERROR_DIR_NOT_EMPTY(145) even though all child items have + successfully been *marked* for deletion, but some application still has a handle open! + e.g. Open "C:\Test\Dir1\Dir2" (filled with lots of files) in Explorer, then delete "C:\Test\Dir1" via ::RemoveDirectory() => Error 145 + Sample code: http://us.generation-nt.com/answer/createfile-directory-handles-removing-parent-help-29126332.html + Alternatives: 1. move file/empty folder to some other location, then DeleteFile()/RemoveDirectory() + 2. use CreateFile/FILE_FLAG_DELETE_ON_CLOSE *without* FILE_SHARE_DELETE instead of DeleteFile() => early failure */ } diff --git a/zen/file_error.h b/zen/file_error.h index 55935eba..b9ce9419 100644 --- a/zen/file_error.h +++ b/zen/file_error.h @@ -7,9 +7,7 @@ #ifndef FILE_ERROR_H_839567308565656789 #define FILE_ERROR_H_839567308565656789 -#include #include "zstring.h" -#include "utf.h" #include "sys_error.h" //we'll need this later anyway! diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp index 48185516..28e62236 100644 --- a/zen/file_traverser.cpp +++ b/zen/file_traverser.cpp @@ -51,7 +51,7 @@ void zen::traverseFolder(const Zstring& dirPath, const Zstring& itemName = itemNameRaw; if (itemName.empty()) //checks result of normalizeUtfForPosix, too! - throw FileError(replaceCpy(_("Cannot read directory %x."), L"%x", fmtPath(dirPath)), formatSystemError("readdir", L"", L"Data corruption; item with empty name.")); + throw FileError(replaceCpy(_("Cannot read directory %x."), L"%x", fmtPath(dirPath)), formatSystemError("readdir", L"", L"Folder contains child item without a name.")); const Zstring& itemPath = appendSeparator(dirPath) + itemName; diff --git a/zen/globals.h b/zen/globals.h index 4c1453a2..876d2598 100644 --- a/zen/globals.h +++ b/zen/globals.h @@ -21,8 +21,7 @@ Solve static destruction order fiasco by providing shared ownership and serializ => use trivially-destructible POD only!!! ATTENTION: function-static globals have the compiler generate "magic statics" == compiler-genenerated locking code which will crash or leak memory when accessed after global is "dead" - => "solved" by FunStatGlobal, but we can't have "too many" of these... -*/ + => "solved" by FunStatGlobal, but we can't have "too many" of these... */ class PodSpinMutex { @@ -33,7 +32,11 @@ public: bool isLocked(); private: - std::atomic_flag flag_; //= ATOMIC_FLAG_INIT; rely entirely on static zero-initialization! => avoid potential contention with worker thread during Global<> construction! + std::atomic_flag flag_; /* => avoid potential contention with worker thread during Global<> construction! + - "For an atomic_flag with static storage duration, this guarantees static initialization:" => just what the doctor ordered! + - "[default initialization] initializes std::atomic_flag to clear state" - since C++20 => + - "std::atomic_flag is [...] guaranteed to be lock-free" + - interestingly, is_trivially_constructible_v<> is false, thanks to constexpr! https://developercommunity.visualstudio.com/content/problem/416343/stdatomic-no-longer-is-trivially-constructible.html */ }; @@ -43,7 +46,7 @@ class Global //don't use for function-scope statics! public: Global() { - static_assert(std::is_trivially_constructible_v&& std::is_trivially_destructible_v, "this memory needs to live forever"); + static_assert(std::is_trivially_destructible_v, "this memory needs to live forever"); assert(!pod_.spinLock.isLocked()); //we depend on static zero-initialization! assert(!pod_.inst); // } @@ -106,8 +109,7 @@ public: std::shared_ptr get() { - static_assert(std::is_trivially_constructible_v&& - std::is_trivially_destructible_v, "this class must not generate code for magic statics!"); + static_assert(std::is_trivially_destructible_v, "this class must not generate code for magic statics!"); pod_.spinLock.lock(); ZEN_ON_SCOPE_EXIT(pod_.spinLock.unlock()); @@ -184,8 +186,7 @@ void registerGlobalForDestruction(CleanUpEntry& entry) CleanUpEntry* head; } cleanUpList; - static_assert(std::is_trivially_constructible_v&& - std::is_trivially_destructible_v, "we must not generate code for magic statics!"); + static_assert(std::is_trivially_destructible_v, "we must not generate code for magic statics!"); cleanUpList.spinLock.lock(); ZEN_ON_SCOPE_EXIT(cleanUpList.spinLock.unlock()); diff --git a/zen/legacy_compiler.h b/zen/legacy_compiler.h index 8d44f3f7..b480aa6d 100644 --- a/zen/legacy_compiler.h +++ b/zen/legacy_compiler.h @@ -7,6 +7,9 @@ #ifndef LEGACY_COMPILER_H_839567308565656789 #define LEGACY_COMPILER_H_839567308565656789 + #include //C++20 + + #include //requires C++20 @@ -18,53 +21,8 @@ namespace std //--------------------------------------------------------------------------------- -#if __cpp_lib_span - #error get rid of workaround: -#endif - -template -class span -{ -public: - template - span(Iterator first, Iterator last) : size_(last - first), data_(first != last ? &*first : nullptr) {} - - template - span(Container& cont) : span(cont.begin(), cont.end()) {} - - using iterator = T*; - using const_iterator = const T*; - - iterator begin() { return data_; } - iterator end () { return data_ + size_; } - - const_iterator begin() const { return data_; } - const_iterator end () const { return data_ + size_; } - const_iterator cbegin() const { return begin(); } - const_iterator cend () const { return end (); } - T* data() const { return data_; } - size_t size() const { return size_; } - bool empty() const { return size_ == 0; } - -private: - const size_t size_; - T* const data_; -}; - - -#if __cpp_lib_math_constants - #error get rid of workaround: -#endif - -namespace numbers -{ -const double pi = 3.14159265358979323846; -const double e = 2.71828182845904523536; -const double sqrt2 = 1.41421356237309504880; -const double ln2 = 0.693147180559945309417; -} } diff --git a/zen/open_ssl.cpp b/zen/open_ssl.cpp index 1feeb1a9..64b20bb3 100644 --- a/zen/open_ssl.cpp +++ b/zen/open_ssl.cpp @@ -569,7 +569,6 @@ public: if (sslError == SSL_ERROR_ZERO_RETURN) return 0; //EOF + close_notify alert - warn_static("find a better solution for SSL_read_ex + EOF") #if OPENSSL_VERSION_NUMBER == 0x1010105fL //OpenSSL 1.1.1e const auto ec = ::ERR_peek_last_error(); if (sslError == SSL_ERROR_SSL && ERR_GET_REASON(ec) == SSL_R_UNEXPECTED_EOF_WHILE_READING) //EOF: only expected for HTTP/1.0 diff --git a/zen/ring_buffer.h b/zen/ring_buffer.h index 8cce8e80..a8d629c6 100644 --- a/zen/ring_buffer.h +++ b/zen/ring_buffer.h @@ -210,7 +210,7 @@ private: RingBuffer (const RingBuffer&) = delete; //wait until there is a reason to copy a RingBuffer RingBuffer& operator=(const RingBuffer&) = delete; // - RingBuffer(size_t capacity) : + explicit RingBuffer(size_t capacity) : rawMem_(static_cast(::operator new (capacity * sizeof(T)))), //throw std::bad_alloc capacity_(capacity) {} diff --git a/zen/shell_execute.cpp b/zen/shell_execute.cpp index 63696568..c8779bb8 100644 --- a/zen/shell_execute.cpp +++ b/zen/shell_execute.cpp @@ -240,7 +240,7 @@ void zen::openWithDefaultApp(const Zstring& itemPath) //throw FileError const Zstring cmdTemplate = R"(xdg-open "%x")"; //doesn't block => no need for time out! const Zstring cmdLine = replaceCpy(cmdTemplate, Zstr("%x"), itemPath); - if (const auto [exitCode, output] = consoleExecute(cmdLine, std::nullopt /*timeoutMs*/); //throw SysError, (SysErrorTimeOut) + if (const auto& [exitCode, output] = consoleExecute(cmdLine, std::nullopt /*timeoutMs*/); //throw SysError, (SysErrorTimeOut) exitCode != 0) throw SysError(formatSystemError(utfTo(cmdTemplate), replaceCpy(_("Exit code %x"), L"%x", numberTo(exitCode)), output)); } diff --git a/zen/shutdown.cpp b/zen/shutdown.cpp index 21e24527..8e8456df 100644 --- a/zen/shutdown.cpp +++ b/zen/shutdown.cpp @@ -19,7 +19,7 @@ void zen::shutdownSystem() //throw FileError { //https://linux.die.net/man/2/reboot => needs admin rights! //"systemctl" should work without admin rights: - const auto [exitCode, output] = consoleExecute("systemctl poweroff", std::nullopt /*timeoutMs*/); //throw SysError, (SysErrorTimeOut) + const auto& [exitCode, output] = consoleExecute("systemctl poweroff", std::nullopt /*timeoutMs*/); //throw SysError, (SysErrorTimeOut) if (!trimCpy(output).empty()) //see comment in suspendSystem() throw SysError(output); @@ -33,7 +33,7 @@ void zen::suspendSystem() //throw FileError try { //"systemctl" should work without admin rights: - const auto [exitCode, output] = consoleExecute("systemctl suspend", std::nullopt /*timeoutMs*/); //throw SysError, (SysErrorTimeOut) + const auto& [exitCode, output] = consoleExecute("systemctl suspend", std::nullopt /*timeoutMs*/); //throw SysError, (SysErrorTimeOut) //why does "systemctl suspend" return exit code 1 despite apparent success!?? if (!trimCpy(output).empty()) //at least we can assume "no output" on success throw SysError(output); diff --git a/zen/string_base.h b/zen/string_base.h index 5922c3ff..58e5d43a 100644 --- a/zen/string_base.h +++ b/zen/string_base.h @@ -12,9 +12,7 @@ #include #include #include "string_tools.h" -#if __cpp_impl_three_way_comparison && __cpp_lib_three_way_comparison #include -#endif //Zbase - a policy based string class optimizing performance and flexibility @@ -295,29 +293,15 @@ private: }; -#if __cpp_impl_three_way_comparison && __cpp_lib_three_way_comparison - #error implement! -#endif - template class SP> bool operator==(const Zbase& lhs, const Zbase& rhs); template class SP> bool operator==(const Zbase& lhs, const Char* rhs); template class SP> inline bool operator==(const Char* lhs, const Zbase& rhs) { return operator==(rhs, lhs); } -#if __cpp_impl_three_way_comparison && __cpp_lib_three_way_comparison template class SP> std::strong_ordering operator<=>(const Zbase& lhs, const Zbase& rhs); template class SP> std::strong_ordering operator<=>(const Zbase& lhs, const Char* rhs); template class SP> std::strong_ordering operator<=>(const Char* lhs, const Zbase& rhs); -#else -template class SP> inline bool operator!=(const Zbase& lhs, const Zbase& rhs) { return !operator==(lhs, rhs); } -template class SP> inline bool operator!=(const Zbase& lhs, const Char* rhs) { return !operator==(lhs, rhs); } -template class SP> inline bool operator!=(const Char* lhs, const Zbase& rhs) { return !operator==(lhs, rhs); } - -template class SP> bool operator<(const Zbase& lhs, const Zbase& rhs); -template class SP> bool operator<(const Zbase& lhs, const Char* rhs); -template class SP> bool operator<(const Char* lhs, const Zbase& rhs); -#endif template class SP> inline Zbase operator+(const Zbase& lhs, const Zbase& rhs) { return Zbase(lhs) += rhs; } template class SP> inline Zbase operator+(const Zbase& lhs, const Char* rhs) { return Zbase(lhs) += rhs; } @@ -498,12 +482,11 @@ bool operator==(const Zbase& lhs, const Char* rhs) } -#if __cpp_impl_three_way_comparison && __cpp_lib_three_way_comparison template class SP> inline std::strong_ordering operator<=>(const Zbase& lhs, const Zbase& rhs) { - return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), //respect embedded 0 - rhs.begin(), rhs.end()); + return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), //respect embedded 0 + rhs.begin(), rhs.end()); // } @@ -518,35 +501,11 @@ std::strong_ordering operator<=>(const Zbase& lhs, const Char* rhs) template class SP> inline std::strong_ordering operator<=>(const Char* lhs, const Zbase& rhs) { - return std::lexicographical_compare_three_way(lhs, lhs + strLength(lhs), //respect embedded 0 - rhs.begin(), rhs.end()); -} - -#else -template class SP> inline -bool operator<(const Zbase& lhs, const Zbase& rhs) -{ - return std::lexicographical_compare(lhs.begin(), lhs.end(), //respect embedded 0 - rhs.begin(), rhs.end()); -} - - -template class SP> inline -bool operator<(const Zbase& lhs, const Char* rhs) -{ - return std::lexicographical_compare(lhs.begin(), lhs.end(), //respect embedded 0 - rhs, rhs + strLength(rhs)); + return std::lexicographical_compare_three_way(lhs, lhs + strLength(lhs), + rhs.begin(), rhs.end()); //respect embedded 0 } -template class SP> inline -bool operator<(const Char* lhs, const Zbase& rhs) -{ - return std::lexicographical_compare(lhs, lhs + strLength(lhs), //respect embedded 0 - rhs.begin(), rhs.end()); -} -#endif - template class SP> inline size_t Zbase::length() const diff --git a/zen/sys_error.h b/zen/sys_error.h index 2dd3c188..01df17ab 100644 --- a/zen/sys_error.h +++ b/zen/sys_error.h @@ -7,10 +7,10 @@ #ifndef SYS_ERROR_H_3284791347018951324534 #define SYS_ERROR_H_3284791347018951324534 -#include -#include "scope_guard.h" -#include "i18n.h" -#include "utf.h" +//#include +#include "scope_guard.h" // +#include "utf.h" //not used by this header, but the "rest of the world" needs it! +#include "i18n.h" // #include diff --git a/zen/system.cpp b/zen/system.cpp index d9a169c7..aa967f71 100644 --- a/zen/system.cpp +++ b/zen/system.cpp @@ -96,22 +96,31 @@ std::wstring zen::getOsDescription() //throw FileError { try { - std::wstring osName; - std::wstring osVersion; - - if (const auto [exitCode, output] = consoleExecute("lsb_release --id -s", std::nullopt); //throw SysError - exitCode != 0) - throw SysError(formatSystemError("lsb_release --id", replaceCpy(_("Exit code %x"), L"%x", numberTo(exitCode)), output)); - else - osName = trimCpy(output); - - if (const auto [exitCode, output] = consoleExecute("lsb_release --release -s", std::nullopt); //throw SysError - exitCode != 0) - throw SysError(formatSystemError("lsb_release --release", replaceCpy(_("Exit code %x"), L"%x", numberTo(exitCode)), output)); - else - osVersion = trimCpy(output); - - return osName + L' ' + osVersion; //e.g. "CentOS 7.7.1908" + //"lsb_release" not available on some systems: https://freefilesync.org/forum/viewtopic.php?t=7191 + // => use /etc/os-release: https://www.freedesktop.org/software/systemd/man/os-release.html + std::string releaseInfo; + try + { + releaseInfo = loadBinContainer("/etc/os-release", nullptr /*notifyUnbufferedIO*/); //throw FileError + } + catch (const FileError& e) { throw SysError(e.toString()); } //further enrich with context info => SysError + + std::string osName; + std::string osVersion; + for (const std::string& line : split(releaseInfo, '\n', SplitType::SKIP_EMPTY)) //throw FileError + if (startsWith(line, "NAME=")) + osName = afterFirst(line, '=', IF_MISSING_RETURN_NONE); + else if (startsWith(line, "VERSION_ID=")) + osVersion = afterFirst(line, '=', IF_MISSING_RETURN_NONE); + + trim(osName, true, true, [](char c) { return c == '"' || c == '\''; }); + trim(osVersion, true, true, [](char c) { return c == '"' || c == '\''; }); + + if (osName .empty()) throw SysError(formatSystemError("/etc/os-release", L"", L"NAME missing.")); + if (osVersion.empty()) throw SysError(formatSystemError("/etc/os-release", L"", L"VERSION_ID missing.")); + + //PRETTY_NAME? too wordy! e.g. "Fedora 17 (Beefy Miracle)" + return utfTo(osName + ' ' + osVersion); //e.g. "CentOS Linux 7" } catch (const SysError& e) { throw FileError(_("Cannot get process information."), e.toString()); } diff --git a/zen/thread.cpp b/zen/thread.cpp index 6e8b8219..6b763f39 100644 --- a/zen/thread.cpp +++ b/zen/thread.cpp @@ -53,3 +53,5 @@ uint64_t zen::getMainThreadId() return globalMainThreadId; } + + diff --git a/zen/thread.h b/zen/thread.h index a1d5197c..99e61e1f 100644 --- a/zen/thread.h +++ b/zen/thread.h @@ -18,9 +18,6 @@ namespace zen { class InterruptionStatus; -#if __cpp_lib_jthread - #error refactor! -#endif class InterruptibleThread { public: @@ -92,7 +89,7 @@ template inline bool isReady(const std::future& f) { return f.wait_for(std::chrono::seconds(0)) == std::future_status::ready; } //------------------------------------------------------------------------------------------ -//wait until first job is successful or all failed: substitute until std::when_any is available +//wait until first job is successful or all failed //TODO: use std::when_any when available template class AsyncFirstResult -- cgit