diff options
author | B. Stack <bgstack15@gmail.com> | 2021-04-05 15:59:11 +0000 |
---|---|---|
committer | B. Stack <bgstack15@gmail.com> | 2021-04-05 15:59:11 +0000 |
commit | 8d28254d708c88ae4aaebbc82cbb6c91726aa390 (patch) | |
tree | dafb5e266c513a5ed9863401e62d246742861e0c /zen | |
parent | Merge branch '11.7' into 'master' (diff) | |
parent | add upstream 11.9 (diff) | |
download | FreeFileSync-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.cpp | 9 | ||||
-rw-r--r-- | zen/socket.h | 7 | ||||
-rw-r--r-- | zen/sys_info.cpp | 60 | ||||
-rw-r--r-- | zen/sys_info.h | 2 | ||||
-rw-r--r-- | zen/time.h | 46 |
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 { @@ -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); |