summaryrefslogtreecommitdiff
path: root/zen
diff options
context:
space:
mode:
authorB. Stack <bgstack15@gmail.com>2021-04-05 15:59:11 +0000
committerB. Stack <bgstack15@gmail.com>2021-04-05 15:59:11 +0000
commit8d28254d708c88ae4aaebbc82cbb6c91726aa390 (patch)
treedafb5e266c513a5ed9863401e62d246742861e0c /zen
parentMerge branch '11.7' into 'master' (diff)
parentadd upstream 11.9 (diff)
downloadFreeFileSync-11.9.tar.gz
FreeFileSync-11.9.tar.bz2
FreeFileSync-11.9.zip
Merge branch '11.9' into 'master'11.9
add upstream 11.9 See merge request opensource-tracking/FreeFileSync!32
Diffstat (limited to 'zen')
-rw-r--r--zen/process_exec.cpp9
-rw-r--r--zen/socket.h7
-rw-r--r--zen/sys_info.cpp60
-rw-r--r--zen/sys_info.h2
-rw-r--r--zen/time.h46
5 files changed, 107 insertions, 17 deletions
diff --git a/zen/process_exec.cpp b/zen/process_exec.cpp
index b82c2565..f51ceae2 100644
--- a/zen/process_exec.cpp
+++ b/zen/process_exec.cpp
@@ -81,11 +81,11 @@ std::pair<int /*exit code*/, std::string> processExecuteImpl(const Zstring& file
if (::pipe2(pipe, O_CLOEXEC) != 0)
THROW_LAST_SYS_ERROR("pipe2");
-
const int fdLifeSignR = pipe[0]; //for parent process
const int fdLifeSignW = pipe[1]; //for child process
ZEN_ON_SCOPE_EXIT(::close(fdLifeSignR));
auto guardFdLifeSignW = makeGuard<ScopeGuardRunMode::onExit>([&] { ::close(fdLifeSignW ); });
+
//--------------------------------------------------------------
//follow implemenation of ::system(): https://github.com/lattera/glibc/blob/master/sysdeps/posix/system.c
@@ -237,14 +237,17 @@ void zen::openWithDefaultApp(const Zstring& itemPath) //throw FileError
{
try
{
- const Zstring cmdTemplate = R"(xdg-open "%x")"; //doesn't block => no need for time out!
+ std::optional<int> timeoutMs;
+ const Zstring cmdTemplate = R"(xdg-open "%x")"; //*might* block!
+ timeoutMs = 0; //e.g. on Lubuntu if Firefox is started and not already running => no need time out! https://freefilesync.org/forum/viewtopic.php?t=8260
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, timeoutMs); //throw SysError, SysErrorTimeOut
exitCode != 0)
throw SysError(formatSystemError(utfTo<std::string>(cmdTemplate),
replaceCpy(_("Exit code %x"), L"%x", numberTo<std::wstring>(exitCode)), utfTo<std::wstring>(output)));
}
+ catch (SysErrorTimeOut&) {} //child process not failed yet => probably fine :>
catch (const SysError& e) { throw FileError(replaceCpy(_("Cannot open file %x."), L"%x", fmtPath(itemPath)), e.toString()); }
}
diff --git a/zen/socket.h b/zen/socket.h
index 2dd1ff4c..f9813852 100644
--- a/zen/socket.h
+++ b/zen/socket.h
@@ -14,6 +14,7 @@
#include <netdb.h> //getaddrinfo
+
namespace zen
{
#define THROW_LAST_SYS_ERROR_WSA(functionName) \
@@ -48,11 +49,15 @@ public:
const auto getConnectedSocket = [](const auto& /*::addrinfo*/ ai)
{
- SocketType testSocket = ::socket(ai.ai_family, ai.ai_socktype, ai.ai_protocol);
+ SocketType testSocket = ::socket(ai.ai_family, //int socket_family
+ SOCK_CLOEXEC |
+ ai.ai_socktype, //int socket_type
+ ai.ai_protocol); //int protocol
if (testSocket == invalidSocket)
THROW_LAST_SYS_ERROR_WSA("socket");
ZEN_ON_SCOPE_FAIL(closeSocket(testSocket));
+
if (::connect(testSocket, ai.ai_addr, static_cast<int>(ai.ai_addrlen)) != 0)
THROW_LAST_SYS_ERROR_WSA("connect");
diff --git a/zen/sys_info.cpp b/zen/sys_info.cpp
index 1a0d18f5..6eeab276 100644
--- a/zen/sys_info.cpp
+++ b/zen/sys_info.cpp
@@ -9,6 +9,7 @@
#include "file_access.h"
#include "sys_version.h"
#include "symlink_target.h"
+#include "time.h"
#include "file_io.h"
#include <ifaddrs.h>
@@ -23,16 +24,50 @@
using namespace zen;
-std::wstring zen::getUserName() //throw FileError
+Zstring zen::getUserName() //throw FileError
{
- //https://linux.die.net/man/3/getlogin
- //https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getlogin.2.html
- const char* loginUser = ::getlogin();
- if (!loginUser)
- THROW_LAST_FILE_ERROR(_("Cannot get process information."), "getlogin");
+ const uid_t userIdNo = ::getuid(); //never fails
+
+ if (userIdNo != 0) //nofail; root(0) => consider as request for elevation, NOT impersonation
+ {
+ std::vector<char> buf(std::max<long>(10000, ::sysconf(_SC_GETPW_R_SIZE_MAX))); //::sysconf may return long(-1)
+ 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;
+ }
+ //else root(0): what now!?
+
//getlogin() is smarter than simply evaluating $LOGNAME! even in contexts without
//$LOGNAME, e.g. "sudo su" on Ubuntu, it returns the correct non-root user!
- return utfTo<std::wstring>(loginUser);
+ if (const char* loginUser = ::getlogin()) //https://linux.die.net/man/3/getlogin
+ if (strLength(loginUser) > 0 && !equalString(loginUser, "root"))
+ return loginUser;
+ //BUT: getlogin() can fail with ENOENT on Linux Mint: https://freefilesync.org/forum/viewtopic.php?t=8181
+
+ auto tryGetNonRootUser = [](const char* varName) -> const char*
+ {
+ if (const char* buf = ::getenv(varName)) //no extended error reporting
+ if (strLength(buf) > 0 && !equalString(buf, "root"))
+ return buf;
+ return nullptr;
+ };
+ //getting a little desperate: variables used by installer.sh
+ if (const char* userName = tryGetNonRootUser("USER")) return userName;
+ if (const char* userName = tryGetNonRootUser("SUDO_USER")) return userName;
+ if (const char* userName = tryGetNonRootUser("LOGNAME")) return userName;
+
+ throw FileError(_("Cannot get process information."), L"Failed to determine non-root user name"); //should not happen?
+
}
@@ -94,6 +129,7 @@ ComputerModel zen::getComputerModel() //throw FileError
+
std::wstring zen::getOsDescription() //throw FileError
{
try
@@ -123,7 +159,7 @@ Zstring zen::getUserDataPath() //throw FileError
xdgCfgPath && xdgCfgPath[0] != 0)
return xdgCfgPath;
- return Zstring("/home/") + utfTo<Zstring>(getUserName()) + "/.config"; //throw FileError
+ return "/home/" + getUserName() + "/.config"; //throw FileError
}
@@ -133,13 +169,13 @@ Zstring zen::getUserDownloadsPath() //throw FileError
{
const Zstring cmdLine = ::getuid() == 0 ? //nofail; root(0) => consider as request for elevation, NOT impersonation
//sudo better be installed :>
- "sudo -u " + utfTo<Zstring>(getUserName()) + " xdg-user-dir DOWNLOAD" : //throw FileError
+ "sudo -u " + getUserName() + " xdg-user-dir DOWNLOAD" : //throw FileError
"xdg-user-dir DOWNLOAD";
const auto& [exitCode, output] = consoleExecute(cmdLine, std::nullopt /*timeoutMs*/); //throw SysError
- if (exitCode != 0)
- throw SysError(formatSystemError(cmdLine.c_str(),
- replaceCpy(_("Exit code %x"), L"%x", numberTo<std::wstring>(exitCode)), utfTo<std::wstring>(output)));
+ if (exitCode != 0) //fallback: probably correct 99.9% of the time anyway...
+ return "/home/" + getUserName() + "/Downloads"; //throw FileError
+
const Zstring& downloadsPath = trimCpy(output);
ASSERT_SYSERROR(!downloadsPath.empty());
return downloadsPath;
diff --git a/zen/sys_info.h b/zen/sys_info.h
index 4f83a9a3..54dc1aca 100644
--- a/zen/sys_info.h
+++ b/zen/sys_info.h
@@ -14,7 +14,7 @@ namespace zen
{
//COM needs to be initialized before calling any of these functions! CoInitializeEx/CoUninitialize
-std::wstring getUserName(); //throw FileError
+Zstring getUserName(); //throw FileError
struct ComputerModel
{
diff --git a/zen/time.h b/zen/time.h
index 903b2e87..e038eca3 100644
--- a/zen/time.h
+++ b/zen/time.h
@@ -147,12 +147,57 @@ TimeComp getLocalTime(time_t utc)
}
+//FILETIME: number of 100-nanosecond intervals since January 1, 1601 UTC
+//time_t: number of seconds since Jan. 1st 1970 UTC
+constexpr auto fileTimeTimetOffset = 11'644'473'600;
+
+
+warn_static("remove after test")
+#if 0
+inline
+TimeComp getUtcTime2(time_t utc)
+{
+ utc += year100UnixOffset; //first century not divisible by 400
+
+ long long remSecs = year100UnixOffset % (24 * 3600);
+ long long remDays = year100UnixOffset / (24 * 3600);
+
+ constexpr int daysPer400Years = 400 * 365 /*usual days per year*/ + 100 /*leap days */ - 3 /*no leap days for centuries not divisible by 400 */;
+
+ int year = 100 + (remDays / daysPer400Years) * 400;
+ remDays %= 400;
+
+ constexpr int daysPer100Years = 100 * 365 /*usual days per year*/ + 25 /*leap days */ - 1 /*no leap days for centuries not divisible by 400 */;
+
+ int addCenturies = remDays / daysPer100Years;
+ if (addCenturies == 4)
+ --addCenturies;
+
+ year += addCenturies * 100;
+ remDays -= addCenturies * daysPer100Years;
+
+ constexpr int daysPer4Years = 4 * 365 /*usual days per year*/ + 1 /*leap day */;
+
+
+
+ constexpr int daysPer100Years = 100 * 365 /*usual days per year*/ + 25 /*leap days */ - 1 /*no leap days for centuries not divisible by 400 */;
+ constexpr int daysPer100Years = 100 * 365 /*usual days per year*/ + 25 /*leap days */ - 1 /*no leap days for centuries not divisible by 400 */;
+ constexpr int daysPer100Years = 100 * 365 /*usual days per year*/ + 25 /*leap days */ - 1 /*no leap days for centuries not divisible by 400 */;
+ constexpr int daysPer100Years = 100 * 365 /*usual days per year*/ + 25 /*leap days */;
+
+
+
+}
+#endif
+
+
inline
TimeComp getUtcTime(time_t utc)
{
if (utc == -1) //failure code from std::time(nullptr)
return TimeComp();
+
std::tm ctc = {};
if (::gmtime_r(&utc, &ctc) == nullptr)
return TimeComp();
@@ -178,6 +223,7 @@ time_t utcToTimeT(const TimeComp& tc) //returns -1 on error
if (tc == TimeComp())
return -1;
+
std::tm ctc = impl::toClibTimeComponents(tc);
ctc.tm_isdst = 0; //"Zero (0) to indicate that standard time is in effect" => unused by _mkgmtime, but take no chances
return ::timegm(&ctc);
bgstack15