diff options
author | Simon Warta <[email protected]> | 2015-07-27 13:04:56 +0200 |
---|---|---|
committer | Simon Warta <[email protected]> | 2015-07-27 13:04:56 +0200 |
commit | 4aa3efdf15c9d9746d31e6e57d5137152f5fd29f (patch) | |
tree | aaa398b0f162e7a6cf2d340d0aedb63d351fc69d | |
parent | 519cb1d28e082524797905016cc338a846f88011 (diff) | |
parent | 18e055b6dcb5688a8c669cdbc54d53541681a21e (diff) |
Merge pull request #205 from webmaster128/mktime
Add timegm() fallbacks using mktime+TZ or boost
-rw-r--r-- | doc/os.rst | 54 | ||||
-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 | 99 | ||||
-rw-r--r-- | src/lib/vendor/boost/info.txt | 1 | ||||
-rwxr-xr-x | src/scripts/update_docs.py | 100 | ||||
-rw-r--r-- | src/tests/catchy/test_utils.cpp | 41 |
13 files changed, 292 insertions, 11 deletions
diff --git a/doc/os.rst b/doc/os.rst new file mode 100644 index 000000000..9e1ee641e --- /dev/null +++ b/doc/os.rst @@ -0,0 +1,54 @@ +Botan OS information +======================================== + +OS Features +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A summary of OS features as defined in ``src/build-data/os``. + +:: + + a: aix + a: android + c: cygwin + d: darwin + d: dragonfly + f: freebsd + h: haiku + h: hpux + h: hurd + i: irix + l: linux + m: mingw + n: nacl + n: netbsd + o: openbsd + q: qnx + s: solaris + w: windows + +.. csv-table:: + :header: "Feature", "a", "a", "c", "d", "d", "f", "h", "h", "h", "i", "l", "m", "n", "n", "o", "q", "s", "w" + + "clock_gettime", " ", "X", " ", " ", "X", "X", " ", " ", " ", " ", "X", " ", " ", "X", "X", "X", " ", " " + "cryptgenrandom", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", "X" + "dlopen", " ", "X", " ", "X", " ", "X", " ", " ", " ", " ", "X", " ", " ", "X", "X", "X", " ", " " + "getsid", "X", " ", "X", "X", " ", "X", "X", "X", " ", "X", "X", " ", " ", "X", " ", "X", "X", " " + "gettimeofday", "X", "X", "X", "X", "X", "X", "X", "X", " ", "X", "X", " ", "X", "X", "X", "X", "X", " " + "gmtime_r", " ", "X", " ", "X", " ", "X", "X", " ", " ", " ", "X", " ", " ", "X", "X", "X", " ", " " + "gmtime_s", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X" + "loadlibrary", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", "X" + "memset_s", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " " + "mkgmtime", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", "X" + "posix_mlock", " ", "X", " ", " ", "X", "X", " ", " ", "X", " ", "X", " ", " ", "X", "X", "X", "X", " " + "query_perf_counter", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X" + "readdir", " ", "X", " ", "X", " ", "X", " ", " ", " ", " ", "X", " ", " ", "X", "X", " ", " ", " " + "rtlsecurezeromemory", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X" + "stl_filesystem_msvc", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X" + "timegm", " ", " ", "X", "X", " ", "X", " ", " ", " ", " ", "X", " ", " ", "X", "X", " ", " ", " " + "virtual_lock", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X" + "win32_get_systemtime", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " " + "win32_virtual_lock", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " " + +.. note:: + This file is auto generated by ``src/scripts/update_docs.py``. Dont modify it manually. 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 0ef8be356..f071a7328 100644 --- a/src/lib/utils/calendar.cpp +++ b/src/lib/utils/calendar.cpp @@ -11,6 +11,11 @@ #include <ctime> #include <sstream> #include <iomanip> +#include <mutex> + +#if defined(BOTAN_HAS_BOOST_DATETIME) +#include <boost/date_time/posix_time/posix_time_types.hpp> +#endif namespace Botan { @@ -26,7 +31,7 @@ std::tm do_gmtime(std::time_t time_val) gmtime_r(&time_val, &tm); // Unix/SUSv2 #else std::tm* tm_p = std::gmtime(&time_val); - if (tm_p == 0) + if (tm_p == nullptr) throw Encoding_Error("time_t_to_tm could not convert"); tm = *tm_p; #endif @@ -34,11 +39,83 @@ std::tm do_gmtime(std::time_t time_val) return tm; } +#if !defined(BOTAN_TARGET_OS_HAS_TIMEGM) && !defined(BOTAN_TARGET_OS_HAS_MKGMTIME) + +#if defined(BOTAN_HAS_BOOST_DATETIME) + +std::time_t boost_timegm(std::tm *tm) + { + const int sec = tm->tm_sec; + const int min = tm->tm_min; + const int hour = tm->tm_hour; + const int day = tm->tm_mday; + const int mon = tm->tm_mon + 1; + const int year = tm->tm_year + 1900; + + std::time_t out; + + { + using namespace boost::posix_time; + using namespace boost::gregorian; + const auto epoch = ptime(date(1970, 01, 01)); + const auto time = ptime(date(year, mon, day), + hours(hour) + minutes(min) + seconds(sec)); + const time_duration diff(time - epoch); + out = diff.ticks() / diff.ticks_per_second(); + } + + return out; + } + +#else + +#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 // BOTAN_HAS_BOOST_DATETIME + +#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 +125,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 +135,20 @@ 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; + #elif defined(BOTAN_HAS_BOOST_DATETIME) + std::time_t (&botan_timegm)(std::tm *tm) = boost_timegm; + #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()); diff --git a/src/lib/vendor/boost/info.txt b/src/lib/vendor/boost/info.txt index c335dcd74..8748c0bf1 100644 --- a/src/lib/vendor/boost/info.txt +++ b/src/lib/vendor/boost/info.txt @@ -1,5 +1,6 @@ define BOOST_FILESYSTEM 20131228 define BOOST_ASIO 20131228 +define BOOST_DATETIME 20150720 load_on vendor diff --git a/src/scripts/update_docs.py b/src/scripts/update_docs.py new file mode 100755 index 000000000..03b9dd67b --- /dev/null +++ b/src/scripts/update_docs.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 + +""" +A script to automatically write docs to /docs. Currently it generates +os.rst, a feature table of OS features. + +Requires Python 3. + +(C) 2015 Simon Warta (Kullo GmbH) + +Botan is released under the Simplified BSD License (see license.txt) +""" + +# global +import argparse +import glob +import os +import sys + +# Assume this script is in botan/src/scripts +botan_root = os.path.join(os.path.dirname(sys.argv[0]), "..", "..") + +# locale +sys.path.append(botan_root) +from configure import OsInfo + +parser = argparse.ArgumentParser(description="") +parser.add_argument('--verbose', dest='verbose', action='store_const', + const=True, default=False, + help='Verbose output (default: false)') +args = parser.parse_args() + +def update_os(): + PAGE_TITLE="Botan OS information" + TABLE_TITLE="OS Features" + + files = [] + files += glob.glob(botan_root + '/src/build-data/os/*.txt') + files.sort() + + if len(files) == 0: + print("No info.txt files found.") + sys.exit(1) + + f1 = open(os.path.join(botan_root, 'doc', 'os.rst'), 'w+') + + all_features = set() + oss = {} + + for filename in files: + o = OsInfo(filename) + oss[o.basename] = o + all_features |= set(o.target_features) + if args.verbose: + print(o.basename) + print(o.target_features) + + featurelist = list(all_features) + featurelist.sort() + oslist = list(oss.keys()) + oslist.sort() + + if args.verbose: + print(featurelist) + + print(PAGE_TITLE, file=f1) + print("========================================", file=f1) + print("", file=f1) + + print(TABLE_TITLE, file=f1) + print("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", file=f1) + print("", file=f1) + + print("A summary of OS features as defined in ``src/build-data/os``.", file=f1) + print("", file=f1) + + print("::", file=f1) + print("", file=f1) + for o in oslist: + print(" %s: %s" % (o[0:1], o), file=f1) + print("", file=f1) + + print('.. csv-table::', file=f1) + print(' :header: "Feature", "' + '", "'.join([o[0:1] for o in oslist]) + '"', file=f1) + print('', file=f1) + + for f in featurelist: + line = ' "' + f + '"' + for o in oslist: + line += ', "' + line += 'X' if f in oss[o].target_features else ' ' + line += '"' + print(line, file=f1) + print("", file=f1) + print(".. note::", file=f1) + print(" This file is auto generated by ``src/scripts/%s``. Dont modify it manually." + % os.path.basename(sys.argv[0]), file=f1) + +if __name__ == '__main__': + update_os() diff --git a/src/tests/catchy/test_utils.cpp b/src/tests/catchy/test_utils.cpp index ad4191e3c..702d82f9c 100644 --- a/src/tests/catchy/test_utils.cpp +++ b/src/tests/catchy/test_utils.cpp @@ -100,6 +100,7 @@ TEST_CASE("calendar_point constructor works", "[utils]") TEST_CASE("calendar_point to stl timepoint and back", "[utils]") { + SECTION("default test") { auto in = calendar_point(1988, 04, 23, 14, 37, 28); auto out = calendar_value(in.to_std_timepoint()); @@ -111,7 +112,20 @@ TEST_CASE("calendar_point to stl timepoint and back", "[utils]") CHECK(( out.seconds == 28 )); } - SECTION("latest possible time point") + // _mkgmtime on Windows does not work for dates before 1970 + SECTION("first possible time point") + { + auto in = calendar_point(1970, 01, 01, 00, 00, 00); + auto out = calendar_value(in.to_std_timepoint()); + CHECK(( out.year == 1970 )); + CHECK(( out.month == 01 )); + CHECK(( out.day == 01 )); + CHECK(( out.hour == 00 )); + CHECK(( out.minutes == 00 )); + CHECK(( out.seconds == 00 )); + } + + SECTION("latest possible time point") { auto in = calendar_point(2037, 12, 31, 23, 59, 59); auto out = calendar_value(in.to_std_timepoint()); @@ -123,13 +137,30 @@ TEST_CASE("calendar_point to stl timepoint and back", "[utils]") CHECK(( out.seconds == 59 )); } - SECTION("year too early") + SECTION("year too early") { - auto in = calendar_point(1800, 01, 01, 0, 0, 0); - CHECK_THROWS( in.to_std_timepoint() ); + { + auto in = calendar_point(1800, 01, 01, 0, 0, 0); + CHECK_THROWS( in.to_std_timepoint() ); + } + + { + auto in = calendar_point(1899, 12, 31, 23, 59, 59); + CHECK_THROWS( in.to_std_timepoint() ); + } + + { + auto in = calendar_point(1969, 12, 31, 23, 59, 58); // time_t = -2 + CHECK_THROWS( in.to_std_timepoint() ); + } + + { + auto in = calendar_point(1969, 12, 31, 23, 59, 59); // time_t = -1 + CHECK_THROWS( in.to_std_timepoint() ); + } } - SECTION("year too late") + SECTION("year too late") { auto in = calendar_point(2038, 01, 01, 0, 0, 0); CHECK_THROWS( in.to_std_timepoint() ); |