summaryrefslogtreecommitdiff
path: root/zen
diff options
context:
space:
mode:
authorB. Stack <bgstack15@gmail.com>2022-06-26 11:59:57 -0400
committerB. Stack <bgstack15@gmail.com>2022-06-26 11:59:57 -0400
commit03efe856012a55165542a3ac5c9055c25723f5e8 (patch)
treef820b53379f3d14e103e2663e8b0ecd38d1b2105 /zen
parentMerge branch 'b11.21' into 'master' (diff)
downloadFreeFileSync-03efe856012a55165542a3ac5c9055c25723f5e8.tar.gz
FreeFileSync-03efe856012a55165542a3ac5c9055c25723f5e8.tar.bz2
FreeFileSync-03efe856012a55165542a3ac5c9055c25723f5e8.zip
add upstream 11.22
Diffstat (limited to 'zen')
-rw-r--r--zen/error_log.h43
-rw-r--r--zen/file_path.cpp2
-rw-r--r--zen/json.h9
-rw-r--r--zen/resolve_path.cpp30
-rw-r--r--zen/stl_tools.h5
-rw-r--r--zen/sys_info.cpp85
-rw-r--r--zen/sys_info.h1
-rw-r--r--zen/type_traits.h2
8 files changed, 92 insertions, 85 deletions
diff --git a/zen/error_log.h b/zen/error_log.h
index 357232f3..ff630cb8 100644
--- a/zen/error_log.h
+++ b/zen/error_log.h
@@ -32,30 +32,17 @@ struct LogEntry
std::string formatMessage(const LogEntry& entry);
+using ErrorLog = std::vector<LogEntry>;
-class ErrorLog
-{
-public:
- void logMsg(const std::wstring& msg, MessageType type, time_t time = std::time(nullptr));
+void logMsg(ErrorLog& log, const std::wstring& msg, MessageType type, time_t time = std::time(nullptr));
- struct Stats
- {
- int info = 0;
- int warning = 0;
- int error = 0;
- };
- Stats getStats() const;
-
- //subset of std::vector<> interface:
- using const_iterator = std::vector<LogEntry>::const_iterator;
- const_iterator begin() const { return entries_.begin(); }
- const_iterator end () const { return entries_.end (); }
- bool empty() const { return entries_.empty(); }
-
-private:
- std::vector<LogEntry> entries_;
+struct ErrorLogStats
+{
+ int info = 0;
+ int warning = 0;
+ int error = 0;
};
-
+ErrorLogStats getStats(const ErrorLog& log);
@@ -65,18 +52,17 @@ private:
//######################## implementation ##########################
inline
-void ErrorLog::logMsg(const std::wstring& msg, MessageType type, time_t time)
+void logMsg(ErrorLog& log, const std::wstring& msg, MessageType type, time_t time)
{
- entries_.push_back({time, type, utfTo<Zstringc>(msg)});
+ log.push_back({time, type, utfTo<Zstringc>(msg)});
}
-
inline
-ErrorLog::Stats ErrorLog::getStats() const
+ErrorLogStats getStats(const ErrorLog& log)
{
- Stats count;
- for (const LogEntry& entry : entries_)
+ ErrorLogStats count;
+ for (const LogEntry& entry : log)
switch (entry.type)
{
case MSG_TYPE_INFO:
@@ -89,7 +75,7 @@ ErrorLog::Stats ErrorLog::getStats() const
++count.error;
break;
}
- assert(std::ssize(entries_) == count.info + count.warning + count.error);
+ assert(std::ssize(log) == count.info + count.warning + count.error);
return count;
}
@@ -119,6 +105,7 @@ std::string formatMessage(const LogEntry& entry)
const Zstringc msg = trimCpy(entry.message);
static_assert(std::is_same_v<decltype(msg), const Zstringc>, "no worries about copying as long as we're using a ref-counted string!");
+ assert(msg == entry.message); //trimming shouldn't be needed usually!?
for (auto it = msg.begin(); it != msg.end(); )
if (*it == '\n')
diff --git a/zen/file_path.cpp b/zen/file_path.cpp
index 926b5c89..68137b90 100644
--- a/zen/file_path.cpp
+++ b/zen/file_path.cpp
@@ -35,7 +35,7 @@ std::optional<PathComponents> zen::parsePathComponents(const Zstring& itemPath)
pc = doParse(3 /*sepCountVolumeRoot*/, false /*rootWithSep*/);
if (!pc && startsWith(itemPath, "/media/")) //Ubuntu: e.g. /media/zenju/DEVICE_NAME
- if (const char* username = ::getenv("USER"))
+ if (const char* username = ::getenv("USER")) //no ownership transfer + no extended error reporting
if (startsWith(itemPath, std::string("/media/") + username + "/"))
pc = doParse(4 /*sepCountVolumeRoot*/, false /*rootWithSep*/);
diff --git a/zen/json.h b/zen/json.h
index 6cfd3bb3..3a9d73f3 100644
--- a/zen/json.h
+++ b/zen/json.h
@@ -22,8 +22,8 @@ struct JsonValue
boolean, //primitive types
number, //
string, //
- object,
array,
+ object,
};
/**/ JsonValue() {}
@@ -40,9 +40,10 @@ struct JsonValue
Type type = Type::null;
- std::string primVal; //for primitive types
- std::unordered_map<std::string, JsonValue> objectVal; //"[...] most implementations of JSON libraries do not accept duplicate keys [...]" => fine!
- std::vector<JsonValue> arrayVal;
+ std::string primVal; //for primitive types
+ std::vector<JsonValue> arrayVal;
+ std::map<std::string, JsonValue> objectVal; //"[...] most implementations of JSON libraries do not accept duplicate keys [...]" => fine!
+ //alternative: std::unordered_map => but let's keep std::map, so that objectVal is sorted for our unit tests
};
diff --git a/zen/resolve_path.cpp b/zen/resolve_path.cpp
index 2b1a82d3..357dab6a 100644
--- a/zen/resolve_path.cpp
+++ b/zen/resolve_path.cpp
@@ -9,8 +9,10 @@
#include "thread.h"
#include "file_access.h"
- #include <stdlib.h> //getenv()
- #include <unistd.h> //getcwd()
+#include <zen/sys_info.h>
+ // #include <stdlib.h> //getenv()
+ #include <unistd.h> //getuid()
+ #include <pwd.h> //getpwuid_r()
using namespace zen;
@@ -21,7 +23,7 @@ std::optional<Zstring> getEnvironmentVar(const Zchar* name)
{
assert(runningOnMainThread()); //getenv() is not thread-safe!
- const char* buffer = ::getenv(name); //no extended error reporting
+ const char* buffer = ::getenv(name); //no ownership transfer + no extended error reporting
if (!buffer)
return {};
Zstring value(buffer);
@@ -58,20 +60,19 @@ Zstring resolveRelativePath(const Zstring& relativePath)
if (!startsWith(pathTmp, FILE_NAME_SEPARATOR)) //absolute names are exactly those starting with a '/'
{
/* basic support for '~': strictly speaking this is a shell-layer feature, so "realpath()" won't handle it
- https://www.gnu.org/software/bash/manual/html_node/Tilde-Expansion.html
-
- https://linux.die.net/man/3/getpwuid: An application that wants to determine its user's home directory
- should inspect the value of HOME (rather than the value getpwuid(getuid())->pw_dir) since this allows
- the user to modify their notion of "the home directory" during a login session. */
+ https://www.gnu.org/software/bash/manual/html_node/Tilde-Expansion.html */
if (startsWith(pathTmp, "~/") || pathTmp == "~")
{
- if (const std::optional<Zstring> homeDir = getEnvironmentVar("HOME"))
- {
+ try
+ {
+ const Zstring& homePath = getUserHome(); //throw FileError
+
if (startsWith(pathTmp, "~/"))
- pathTmp = appendPath(*homeDir, pathTmp.c_str() + 2);
+ pathTmp = appendPath(homePath, pathTmp.c_str() + 2);
else //pathTmp == "~"
- pathTmp = *homeDir;
- }
+ pathTmp = homePath;
+ }
+ catch (FileError&) {}
//else: error! no further processing!
}
else
@@ -238,8 +239,7 @@ Zstring zen::getResolvedFilePath(const Zstring& pathPhrase) //noexcept
path = expandMacros(path); //expand before trimming!
- //remove leading/trailing whitespace before allowing misinterpretation in applyLongPathPrefix()
- trim(path); //attention: don't remove all whitespace from right, e.g. 0xa0 may be used as part of a folder name
+ trim(path); //remove leading/trailing whitespace before allowing misinterpretation in applyLongPathPrefix()
{
path = expandVolumeName(path); //may block for slow USB sticks and idle HDDs!
diff --git a/zen/stl_tools.h b/zen/stl_tools.h
index 9f7977db..2726a09d 100644
--- a/zen/stl_tools.h
+++ b/zen/stl_tools.h
@@ -78,11 +78,7 @@ template <class T> inline T* get( std::optional<T>& opt) { return opt
template <class T> inline const T* get(const std::optional<T>& opt) { return opt ? &*opt : nullptr; }
-
//===========================================================================
-template <class T> class SharedRef;
-template <class T, class... Args> SharedRef<T> makeSharedRef(Args&& ... args);
-
template <class T>
class SharedRef //why is there no std::shared_ref???
{
@@ -109,7 +105,6 @@ private:
template <class T, class... Args> inline
SharedRef<T> makeSharedRef(Args&& ... args) { return SharedRef<T>(std::make_shared<T>(std::forward<Args>(args)...)); }
-//===========================================================================
diff --git a/zen/sys_info.cpp b/zen/sys_info.cpp
index d208cc98..bc1bfe62 100644
--- a/zen/sys_info.cpp
+++ b/zen/sys_info.cpp
@@ -28,30 +28,32 @@ Zstring zen::getLoginUser() //throw FileError
{
auto tryGetNonRootUser = [](const char* varName) -> const char*
{
- if (const char* buf = ::getenv(varName)) //no extended error reporting
+ if (const char* buf = ::getenv(varName)) //no ownership transfer + no extended error reporting
if (strLength(buf) > 0 && !equalString(buf, "root"))
return buf;
return nullptr;
};
- const uid_t userIdNo = ::getuid(); //never fails
-
- if (userIdNo != 0) //nofail; non-root
+ if (const uid_t userIdNo = ::getuid(); //never fails
+ userIdNo != 0) //nofail; non-root
{
- std::vector<char> buf(std::max<long>(10000, ::sysconf(_SC_GETPW_R_SIZE_MAX))); //::sysconf may return long(-1)
+ //ugh, the world's stupidest API:
+ std::vector<char> buf(std::max<long>(10000, ::sysconf(_SC_GETPW_R_SIZE_MAX))); //::sysconf may return long(-1) or even a too small size!! WTF!
passwd buf2 = {};
- passwd* pwsEntry = nullptr;
- if (::getpwuid_r(userIdNo, //uid_t uid
- &buf2, //struct passwd* pwd
- &buf[0], //char* buf
- buf.size(), //size_t buflen
- &pwsEntry) != 0) //struct passwd** result
- THROW_LAST_FILE_ERROR(_("Cannot get process information."), "getpwuid_r");
-
- if (!pwsEntry)
- throw FileError(_("Cannot get process information."), L"no login found"); //should not happen?
-
- return pwsEntry->pw_name;
+ passwd* pwEntry = nullptr;
+ if (const int rv = ::getpwuid_r(userIdNo, //uid_t uid
+ &buf2, //struct passwd* pwd
+ &buf[0], //char* buf
+ buf.size(), //size_t buflen
+ &pwEntry); //struct passwd** result
+ rv != 0 || !pwEntry)
+ {
+ //"If an error occurs, errno is set appropriately" => why the fuck, then also return errno as return value!?
+ errno = rv != 0 ? rv : ENOENT;
+ THROW_LAST_FILE_ERROR(_("Cannot get process information."), "getpwuid_r(" + numberTo<std::string>(userIdNo) + ')');
+ }
+
+ return pwEntry->pw_name;
}
//else: root(0) => consider as request for elevation, NOT impersonation!
@@ -178,29 +180,49 @@ Zstring zen::getRealProcessPath() //throw FileError
}
-namespace
-{
-Zstring getUserDir() //throw FileError
+Zstring zen::getUserHome() //throw FileError
{
+ if (::getuid() != 0) //nofail; non-root
+ /* https://linux.die.net/man/3/getpwuid: An application that wants to determine its user's home directory
+ should inspect the value of HOME (rather than the value getpwuid(getuid())->pw_dir) since this allows
+ the user to modify their notion of "the home directory" during a login session. */
+ if (const char* homePath = ::getenv("HOME")) //no ownership transfer + no extended error reporting
+ return homePath;
+
+ //root(0) => consider as request for elevation, NOT impersonation!
+ //=> no support for HOME variable :(
+
const Zstring loginUser = getLoginUser(); //throw FileError
- if (loginUser == "root")
- return "/root";
- else
- return "/home/" + loginUser;
- //safer? sudo --user $userName sh -c 'echo $HOME'
-}
+ //ugh, the world's stupidest API:
+ std::vector<char> buf(std::max<long>(10000, ::sysconf(_SC_GETPW_R_SIZE_MAX))); //::sysconf may return long(-1) or even a too small size!! WTF!
+ passwd buf2 = {};
+ passwd* pwEntry = nullptr;
+ if (const int rv = ::getpwnam_r(loginUser.c_str(), //const char *name
+ &buf2, //struct passwd* pwd
+ &buf[0], //char* buf
+ buf.size(), //size_t buflen
+ &pwEntry); //struct passwd** result
+ rv != 0 || !pwEntry)
+ {
+ //"If an error occurs, errno is set appropriately" => why the fuck, then also return errno as return value!?
+ errno = rv != 0 ? rv : ENOENT;
+ THROW_LAST_FILE_ERROR(_("Cannot get process information."), "getpwnam_r(" + utfTo<std::string>(loginUser) + ')');
+ }
+
+ return pwEntry->pw_dir; //home directory
}
Zstring zen::getUserDataPath() //throw FileError
{
- if (::getuid() != 0) //nofail; root(0) => consider as request for elevation, NOT impersonation
- if (const char* xdgCfgPath = ::getenv("XDG_CONFIG_HOME"); //no extended error reporting
+ if (::getuid() != 0) //nofail; non-root
+ if (const char* xdgCfgPath = ::getenv("XDG_CONFIG_HOME"); //no ownership transfer + no extended error reporting
xdgCfgPath && xdgCfgPath[0] != 0)
return xdgCfgPath;
+ //root(0) => consider as request for elevation, NOT impersonation
- return getUserDir() + "/.config"; //throw FileError
+ return appendPath(getUserHome(), ".config"); //throw FileError
}
@@ -208,7 +230,7 @@ Zstring zen::getUserDownloadsPath() //throw FileError
{
try
{
- if (::getuid() != 0) //nofail; root(0) => consider as request for elevation, NOT impersonation
+ if (::getuid() != 0) //nofail; non-root
if (const auto& [exitCode, output] = consoleExecute("xdg-user-dir DOWNLOAD", std::nullopt /*timeoutMs*/); //throw SysError
exitCode == 0)
{
@@ -216,9 +238,10 @@ Zstring zen::getUserDownloadsPath() //throw FileError
ASSERT_SYSERROR(!downloadsPath.empty());
return downloadsPath;
}
+ //root(0) => consider as request for elevation, NOT impersonation
//fallback: probably correct 99.9% of the time anyway...
- return getUserDir() + "/Downloads"; //throw FileError
+ return appendPath(getUserHome(), "Downloads"); //throw FileError
}
catch (const SysError& e) { throw FileError(_("Cannot get process information."), e.toString()); }
}
diff --git a/zen/sys_info.h b/zen/sys_info.h
index 0393e1fb..ce07d7a1 100644
--- a/zen/sys_info.h
+++ b/zen/sys_info.h
@@ -35,6 +35,7 @@ Zstring getRealProcessPath(); //throw FileError
Zstring getUserDownloadsPath(); //throw FileError
Zstring getUserDataPath(); //throw FileError
+Zstring getUserHome(); //throw FileError
}
#endif //SYSTEM_H_4189731847832147508915
diff --git a/zen/type_traits.h b/zen/type_traits.h
index 28817aad..6186a2ae 100644
--- a/zen/type_traits.h
+++ b/zen/type_traits.h
@@ -100,7 +100,7 @@ Usage:
template <class Predicate>
struct LessDescending
{
- LessDescending(Predicate lessThan) : lessThan_(lessThan) {}
+ LessDescending(Predicate lessThan) : lessThan_(std::move(lessThan)) {}
template <class T> bool operator()(const T& lhs, const T& rhs) const { return lessThan_(rhs, lhs); }
private:
Predicate lessThan_;
bgstack15