diff options
-rw-r--r-- | src/build-data/os/cygwin.txt | 1 | ||||
-rw-r--r-- | src/build-data/os/darwin.txt | 1 | ||||
-rw-r--r-- | src/build-data/os/freebsd.txt | 1 | ||||
-rw-r--r-- | src/build-data/os/linux.txt | 1 | ||||
-rw-r--r-- | src/build-data/os/mingw.txt | 1 | ||||
-rw-r--r-- | src/build-data/os/netbsd.txt | 1 | ||||
-rw-r--r-- | src/build-data/os/openbsd.txt | 1 | ||||
-rw-r--r-- | src/build-data/os/windows.txt | 1 | ||||
-rw-r--r-- | src/lib/utils/calendar.cpp | 61 |
9 files changed, 64 insertions, 5 deletions
diff --git a/src/build-data/os/cygwin.txt b/src/build-data/os/cygwin.txt index eb5835a6f..be67e2607 100644 --- a/src/build-data/os/cygwin.txt +++ b/src/build-data/os/cygwin.txt @@ -13,4 +13,5 @@ doc_dir docs <target_features> gettimeofday getsid +timegm </target_features> diff --git a/src/build-data/os/darwin.txt b/src/build-data/os/darwin.txt index f5f2589fb..3a13b34e4 100644 --- a/src/build-data/os/darwin.txt +++ b/src/build-data/os/darwin.txt @@ -15,6 +15,7 @@ gmtime_r memset_s readdir getsid +timegm </target_features> <aliases> diff --git a/src/build-data/os/freebsd.txt b/src/build-data/os/freebsd.txt index 346145785..32767cb1f 100644 --- a/src/build-data/os/freebsd.txt +++ b/src/build-data/os/freebsd.txt @@ -8,4 +8,5 @@ gmtime_r dlopen readdir getsid +timegm </target_features> diff --git a/src/build-data/os/linux.txt b/src/build-data/os/linux.txt index cb78c33ff..48c3bf318 100644 --- a/src/build-data/os/linux.txt +++ b/src/build-data/os/linux.txt @@ -8,6 +8,7 @@ gmtime_r dlopen readdir getsid +timegm </target_features> <aliases> diff --git a/src/build-data/os/mingw.txt b/src/build-data/os/mingw.txt index 4f3e7f08b..cc98b11e6 100644 --- a/src/build-data/os/mingw.txt +++ b/src/build-data/os/mingw.txt @@ -23,6 +23,7 @@ mingw32 <target_features> cryptgenrandom loadlibrary +mkgmtime win32_virtual_lock win32_get_systemtime </target_features> diff --git a/src/build-data/os/netbsd.txt b/src/build-data/os/netbsd.txt index 346145785..32767cb1f 100644 --- a/src/build-data/os/netbsd.txt +++ b/src/build-data/os/netbsd.txt @@ -8,4 +8,5 @@ gmtime_r dlopen readdir getsid +timegm </target_features> diff --git a/src/build-data/os/openbsd.txt b/src/build-data/os/openbsd.txt index 5df133c8e..510a7accd 100644 --- a/src/build-data/os/openbsd.txt +++ b/src/build-data/os/openbsd.txt @@ -7,4 +7,5 @@ posix_mlock gmtime_r dlopen readdir +timegm </target_features> diff --git a/src/build-data/os/windows.txt b/src/build-data/os/windows.txt index c34f2e7ab..fd74fe817 100644 --- a/src/build-data/os/windows.txt +++ b/src/build-data/os/windows.txt @@ -15,6 +15,7 @@ install_cmd_exec "copy" cryptgenrandom gmtime_s loadlibrary +mkgmtime query_perf_counter virtual_lock rtlsecurezeromemory diff --git a/src/lib/utils/calendar.cpp b/src/lib/utils/calendar.cpp index f62303e49..966c97730 100644 --- a/src/lib/utils/calendar.cpp +++ b/src/lib/utils/calendar.cpp @@ -11,6 +11,7 @@ #include <ctime> #include <sstream> #include <iomanip> +#include <mutex> namespace Botan { @@ -34,11 +35,53 @@ std::tm do_gmtime(std::time_t time_val) return tm; } +#if !defined(BOTAN_TARGET_OS_HAS_TIMEGM) && !defined(BOTAN_TARGET_OS_HAS_MKGMTIME) + +#pragma message "Caution! A fallback version of timegm() is used which is not thread-safe" + +std::mutex ENV_TZ; + +std::time_t fallback_timegm(std::tm *tm) + { + std::time_t out; + std::string tz_backup; + + ENV_TZ.lock(); + + // Store current value of env variable TZ + const char* tz_env_pointer = ::getenv("TZ"); + if (tz_env_pointer != nullptr) + tz_backup = std::string(tz_env_pointer); + + // Clear value of TZ + ::setenv("TZ", "", 1); + ::tzset(); + + out = ::mktime(tm); + + // Restore TZ + if (!tz_backup.empty()) + { + // setenv makes a copy of the second argument + ::setenv("TZ", tz_backup.data(), 1); + } + else + { + ::unsetenv("TZ"); + } + ::tzset(); + + ENV_TZ.unlock(); + + return out; +} +#endif + } std::chrono::system_clock::time_point calendar_point::to_std_timepoint() { - if (year < 1900) + if (year < 1970) throw Invalid_Argument("calendar_point::to_std_timepoint() does not support years before 1990."); // 32 bit time_t ends at January 19, 2038 @@ -48,7 +91,9 @@ std::chrono::system_clock::time_point calendar_point::to_std_timepoint() if (year > 2037) throw Invalid_Argument("calendar_point::to_std_timepoint() does not support years after 2037."); + // std::tm: struct without any timezone information std::tm tm; + tm.tm_isdst = -1; // i.e. no DST information available tm.tm_sec = seconds; tm.tm_min = minutes; tm.tm_hour = hour; @@ -56,12 +101,18 @@ std::chrono::system_clock::time_point calendar_point::to_std_timepoint() tm.tm_mon = month - 1; tm.tm_year = year - 1900; - // Convert std::tm to std::time_t + // Define a function alias `botan_timegm` + #if defined(BOTAN_TARGET_OS_HAS_TIMEGM) + std::time_t (&botan_timegm)(std::tm *tm) = timegm; + #elif defined(BOTAN_TARGET_OS_HAS_MKGMTIME) // http://stackoverflow.com/questions/16647819/timegm-cross-platform - #if defined(BOTAN_TARGET_OS_IS_WINDOWS) - #define timegm _mkgmtime + std::time_t (&botan_timegm)(std::tm *tm) = _mkgmtime; + #else + std::time_t (&botan_timegm)(std::tm *tm) = fallback_timegm; #endif - std::time_t tt = timegm(&tm); + + // Convert std::tm to std::time_t + std::time_t tt = botan_timegm(&tm); if (tt == -1) throw Invalid_Argument("calendar_point couldn't be converted: " + to_string()); |