summaryrefslogtreecommitdiff
path: root/zen
diff options
context:
space:
mode:
authorB Stack <bgstack15@gmail.com>2020-05-17 17:14:47 +0000
committerB Stack <bgstack15@gmail.com>2020-05-17 17:14:47 +0000
commitcca3f71f16f85f5d506bf4bb7b3ec38fda31516a (patch)
tree1f52055b2f26fc2389d3ab4eb8d8d1e234a6316a /zen
parentMerge branch '10.23' into 'master' (diff)
parentadd upstream 10.24 (diff)
downloadFreeFileSync-cca3f71f16f85f5d506bf4bb7b3ec38fda31516a.tar.gz
FreeFileSync-cca3f71f16f85f5d506bf4bb7b3ec38fda31516a.tar.bz2
FreeFileSync-cca3f71f16f85f5d506bf4bb7b3ec38fda31516a.zip
Merge branch '10.24' into 'master'
add upstream 10.24 See merge request opensource-tracking/FreeFileSync!21
Diffstat (limited to 'zen')
-rw-r--r--zen/dir_watcher.h4
-rw-r--r--zen/file_access.cpp15
-rw-r--r--zen/file_error.h2
-rw-r--r--zen/file_traverser.cpp2
-rw-r--r--zen/globals.h17
-rw-r--r--zen/legacy_compiler.h48
-rw-r--r--zen/open_ssl.cpp1
-rw-r--r--zen/ring_buffer.h2
-rw-r--r--zen/shell_execute.cpp2
-rw-r--r--zen/shutdown.cpp4
-rw-r--r--zen/string_base.h49
-rw-r--r--zen/sys_error.h8
-rw-r--r--zen/system.cpp41
-rw-r--r--zen/thread.cpp2
-rw-r--r--zen/thread.h5
15 files changed, 62 insertions, 140 deletions
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<ItemType> zen::itemStillExists(const Zstring& itemPath) //throw Fi
assert(!itemName.empty());
const std::optional<ItemType> 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 <string>
#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<Pod>&& std::is_trivially_destructible_v<Pod>, "this memory needs to live forever");
+ static_assert(std::is_trivially_destructible_v<Pod>, "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<T> get()
{
- static_assert(std::is_trivially_constructible_v<FunStatGlobal>&&
- std::is_trivially_destructible_v<FunStatGlobal>, "this class must not generate code for magic statics!");
+ static_assert(std::is_trivially_destructible_v<FunStatGlobal>, "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<decltype(cleanUpList)>&&
- std::is_trivially_destructible_v<decltype(cleanUpList)>, "we must not generate code for magic statics!");
+ static_assert(std::is_trivially_destructible_v<decltype(cleanUpList)>, "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 <numbers> //C++20
+
+ #include <span> //requires C++20
@@ -18,53 +21,8 @@ namespace std
//---------------------------------------------------------------------------------
-#if __cpp_lib_span
- #error get rid of workaround:
-#endif
-
-template <class T>
-class span
-{
-public:
- template <class Iterator>
- span(Iterator first, Iterator last) : size_(last - first), data_(first != last ? &*first : nullptr) {}
-
- template <class Container>
- 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<std::byte*>(::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<std::string>(cmdTemplate), replaceCpy(_("Exit code %x"), L"%x", numberTo<std::wstring>(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 <cstdint>
#include <atomic>
#include "string_tools.h"
-#if __cpp_impl_three_way_comparison && __cpp_lib_three_way_comparison
#include <compare>
-#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 Char, template <class> class SP> bool operator==(const Zbase<Char, SP>& lhs, const Zbase<Char, SP>& rhs);
template <class Char, template <class> class SP> bool operator==(const Zbase<Char, SP>& lhs, const Char* rhs);
template <class Char, template <class> class SP> inline bool operator==(const Char* lhs, const Zbase<Char, SP>& rhs) { return operator==(rhs, lhs); }
-#if __cpp_impl_three_way_comparison && __cpp_lib_three_way_comparison
template <class Char, template <class> class SP> std::strong_ordering operator<=>(const Zbase<Char, SP>& lhs, const Zbase<Char, SP>& rhs);
template <class Char, template <class> class SP> std::strong_ordering operator<=>(const Zbase<Char, SP>& lhs, const Char* rhs);
template <class Char, template <class> class SP> std::strong_ordering operator<=>(const Char* lhs, const Zbase<Char, SP>& rhs);
-#else
-template <class Char, template <class> class SP> inline bool operator!=(const Zbase<Char, SP>& lhs, const Zbase<Char, SP>& rhs) { return !operator==(lhs, rhs); }
-template <class Char, template <class> class SP> inline bool operator!=(const Zbase<Char, SP>& lhs, const Char* rhs) { return !operator==(lhs, rhs); }
-template <class Char, template <class> class SP> inline bool operator!=(const Char* lhs, const Zbase<Char, SP>& rhs) { return !operator==(lhs, rhs); }
-
-template <class Char, template <class> class SP> bool operator<(const Zbase<Char, SP>& lhs, const Zbase<Char, SP>& rhs);
-template <class Char, template <class> class SP> bool operator<(const Zbase<Char, SP>& lhs, const Char* rhs);
-template <class Char, template <class> class SP> bool operator<(const Char* lhs, const Zbase<Char, SP>& rhs);
-#endif
template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(const Zbase<Char, SP>& lhs, const Zbase<Char, SP>& rhs) { return Zbase<Char, SP>(lhs) += rhs; }
template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(const Zbase<Char, SP>& lhs, const Char* rhs) { return Zbase<Char, SP>(lhs) += rhs; }
@@ -498,12 +482,11 @@ bool operator==(const Zbase<Char, SP>& lhs, const Char* rhs)
}
-#if __cpp_impl_three_way_comparison && __cpp_lib_three_way_comparison
template <class Char, template <class> class SP> inline
std::strong_ordering operator<=>(const Zbase<Char, SP>& lhs, const Zbase<Char, SP>& 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<Char, SP>& lhs, const Char* rhs)
template <class Char, template <class> class SP> inline
std::strong_ordering operator<=>(const Char* lhs, const Zbase<Char, SP>& rhs)
{
- return std::lexicographical_compare_three_way(lhs, lhs + strLength(lhs), //respect embedded 0
- rhs.begin(), rhs.end());
-}
-
-#else
-template <class Char, template <class> class SP> inline
-bool operator<(const Zbase<Char, SP>& lhs, const Zbase<Char, SP>& rhs)
-{
- return std::lexicographical_compare(lhs.begin(), lhs.end(), //respect embedded 0
- rhs.begin(), rhs.end());
-}
-
-
-template <class Char, template <class> class SP> inline
-bool operator<(const Zbase<Char, SP>& 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 Char, template <class> class SP> inline
-bool operator<(const Char* lhs, const Zbase<Char, SP>& rhs)
-{
- return std::lexicographical_compare(lhs, lhs + strLength(lhs), //respect embedded 0
- rhs.begin(), rhs.end());
-}
-#endif
-
template <class Char, template <class> class SP> inline
size_t Zbase<Char, SP>::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 <string>
-#include "scope_guard.h"
-#include "i18n.h"
-#include "utf.h"
+//#include <string>
+#include "scope_guard.h" //
+#include "utf.h" //not used by this header, but the "rest of the world" needs it!
+#include "i18n.h" //
#include <cerrno>
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<std::wstring>(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<std::wstring>(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<std::string>("/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<std::wstring>(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<typename T> inline
bool isReady(const std::future<T>& 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 T>
class AsyncFirstResult
bgstack15