Both functions are available since msvcr80.dll. Additionally function _mkgmtime64 is available since Windows Server 2003 in system msvcrt.dll library (which predates first x64 version, which was Windows Server 2003 SP1, and hence _mkgmtime64 is present in all x64 CRT versions) and function _mkgmtime32 is available since Windows Vista in system msvcrt.dll library.
For older CRT libraries provide emulation via musl libc __tm_to_secs() function and normalization via WinAPI FileTimeToSystemTime() function. We cannot use WinAPI SystemTimeToFileTime() function because it does not work with invalid / not-normalized structure as opposite of the CRT _mkgmtime function. Hence that is why the musl libc implementation is included. msvcrt _mkgmtime32() does not work for time before year 1970. Add similar underflow checks into mingw-w64 emulation. --- mingw-w64-crt/Makefile.am | 5 ++ mingw-w64-crt/lib-common/msvcrt.def.in | 6 +- mingw-w64-crt/misc/__tm_to_secs.h | 104 +++++++++++++++++++++++++ mingw-w64-crt/misc/_mkgmtime32.c | 35 +++++++++ mingw-w64-crt/misc/_mkgmtime64.c | 58 ++++++++++++++ 5 files changed, 205 insertions(+), 3 deletions(-) create mode 100644 mingw-w64-crt/misc/__tm_to_secs.h create mode 100644 mingw-w64-crt/misc/_mkgmtime32.c create mode 100644 mingw-w64-crt/misc/_mkgmtime64.c diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am index 68dc2c50b294..521fe1cf9fc7 100644 --- a/mingw-w64-crt/Makefile.am +++ b/mingw-w64-crt/Makefile.am @@ -578,6 +578,8 @@ src_msvcrt32=\ misc/_get_fmode.c \ misc/_gmtime64.c \ misc/_initterm_e.c \ + misc/_mkgmtime32.c \ + misc/_mkgmtime64.c \ misc/_set_doserrno.c \ misc/_set_fmode.c \ misc/_time64.c \ @@ -643,6 +645,7 @@ src_msvcrt64=\ misc/_get_doserrno.c \ misc/_get_fmode.c \ misc/_initterm_e.c \ + misc/_mkgmtime32.c \ misc/_set_doserrno.c \ misc/_set_fmode.c \ misc/output_format.c \ @@ -923,6 +926,8 @@ src_pre_msvcr80=\ misc/_invalid_parameter.c \ misc/_invalid_parameter_noinfo.c \ misc/_invoke_watson.c \ + misc/_mkgmtime32.c \ + misc/_mkgmtime64.c \ misc/_recalloc.c \ misc/_set_doserrno.c \ misc/_set_errno.c \ diff --git a/mingw-w64-crt/lib-common/msvcrt.def.in b/mingw-w64-crt/lib-common/msvcrt.def.in index 487db673bcc3..3d3586042695 100644 --- a/mingw-w64-crt/lib-common/msvcrt.def.in +++ b/mingw-w64-crt/lib-common/msvcrt.def.in @@ -1237,8 +1237,8 @@ F_X86_ANY(__CxxFrameHandler2) ___lc_collate_cp_func F_NON_I386(__pwctype_func) ; i386 __pwctype_func replaced by emu F_NON_I386(_abs64) ; i386 _abs64 replaced by emu -_mkgmtime -_mkgmtime64 +F_NON_I386(_mkgmtime) ; i386 _mkgmtime replaced by emu +F_NON_I386(_mkgmtime64) ; i386 _mkgmtime64 replaced by emu F_NON_I386(_rotl64) ; i386 _rotl64 replaced by emu F_NON_I386(_rotr64) ; i386 _rotr64 replaced by emu _wctype DATA @@ -1595,7 +1595,7 @@ _mbtowc_l _mbsnlen _mbstrnlen _memicmp_l -_mkgmtime32 F_I386(== _mkgmtime) ; i386 _mkgmtime32 replaced by alias +F_ARM_ANY(_mkgmtime32) ; i386 and x64 _mkgmtime32 replaced by emu F_ARM_ANY(_mktemp_s) ; i386 and x64 _mktemp_s replaced by emu _mktime32 F_I386(== mktime) ; i386 _mktime32 replaced by alias F_NON_I386(_msize_dbg) diff --git a/mingw-w64-crt/misc/__tm_to_secs.h b/mingw-w64-crt/misc/__tm_to_secs.h new file mode 100644 index 000000000000..3c17c2d34012 --- /dev/null +++ b/mingw-w64-crt/misc/__tm_to_secs.h @@ -0,0 +1,104 @@ +/* + Copyright © 2005-2020 Rich Felker, et al. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +static long long __year_to_secs(long long year, int *is_leap) +{ + if (year-2ULL <= 136) { + int y = year; + int leaps = (y-68)>>2; + if (!((y-68)&3)) { + leaps--; + if (is_leap) *is_leap = 1; + } else if (is_leap) *is_leap = 0; + return 31536000*(y-70) + 86400*leaps; + } + + int cycles, centuries, leaps, rem, dummy; + + if (!is_leap) is_leap = &dummy; + cycles = (year-100) / 400; + rem = (year-100) % 400; + if (rem < 0) { + cycles--; + rem += 400; + } + if (!rem) { + *is_leap = 1; + centuries = 0; + leaps = 0; + } else { + if (rem >= 200) { + if (rem >= 300) centuries = 3, rem -= 300; + else centuries = 2, rem -= 200; + } else { + if (rem >= 100) centuries = 1, rem -= 100; + else centuries = 0; + } + if (!rem) { + *is_leap = 0; + leaps = 0; + } else { + leaps = rem / 4U; + rem %= 4U; + *is_leap = !rem; + } + } + + leaps += 97*cycles + 24*centuries - *is_leap; + + return (year-100) * 31536000LL + leaps * 86400LL + 946684800 + 86400; +} + +static int __month_to_secs(int month, int is_leap) +{ + static const int secs_through_month[] = { + 0, 31*86400, 59*86400, 90*86400, + 120*86400, 151*86400, 181*86400, 212*86400, + 243*86400, 273*86400, 304*86400, 334*86400 }; + int t = secs_through_month[month]; + if (is_leap && month >= 2) t+=86400; + return t; +} + +static long long __tm_to_secs(const struct tm *tm) +{ + int is_leap; + long long year = tm->tm_year; + int month = tm->tm_mon; + if (month >= 12 || month < 0) { + int adj = month / 12; + month %= 12; + if (month < 0) { + adj--; + month += 12; + } + year += adj; + } + long long t = __year_to_secs(year, &is_leap); + t += __month_to_secs(month, is_leap); + t += 86400LL * (tm->tm_mday-1); + t += 3600LL * tm->tm_hour; + t += 60LL * tm->tm_min; + t += tm->tm_sec; + return t; +} diff --git a/mingw-w64-crt/misc/_mkgmtime32.c b/mingw-w64-crt/misc/_mkgmtime32.c new file mode 100644 index 000000000000..71c12f86f4b5 --- /dev/null +++ b/mingw-w64-crt/misc/_mkgmtime32.c @@ -0,0 +1,35 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +#include <time.h> +#include <stdint.h> + +static __time32_t __cdecl emu__mkgmtime32(struct tm *tmptr) +{ + struct tm tm64; + __time64_t time64; + + tm64 = *tmptr; + time64 = _mkgmtime64(&tm64); + + if (time64 == -1 || time64 < 0 || time64 > INT32_MAX) + return -1; + + *tmptr = tm64; + return (__time32_t)time64; +} + +#define RETT __time32_t +#define FUNC _mkgmtime32 +#define ARGS struct tm *tmptr +#define CALL tmptr +#include "msvcrt_or_emu_glue.h" + +/* On 32-bit systems is _mkgmtime ABI using 32-bit time_t */ +#ifndef _WIN64 +time_t __attribute__((alias("_mkgmtime32"))) __cdecl _mkgmtime(struct tm *tmptr); +extern time_t __attribute__((alias(__MINGW64_STRINGIFY(__MINGW_IMP_SYMBOL(_mkgmtime32))))) (__cdecl *__MINGW_IMP_SYMBOL(_mkgmtime))(struct tm *tmptr); +#endif diff --git a/mingw-w64-crt/misc/_mkgmtime64.c b/mingw-w64-crt/misc/_mkgmtime64.c new file mode 100644 index 000000000000..81b3421aa481 --- /dev/null +++ b/mingw-w64-crt/misc/_mkgmtime64.c @@ -0,0 +1,58 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +#include <windows.h> +#include <time.h> + +#include "__tm_to_secs.h" + +static const short int days_in_year[] = { -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 }; + +static __time64_t __cdecl emu__mkgmtime64(struct tm *tmptr) +{ + unsigned long long value; + SYSTEMTIME systemtime; + FILETIME filetime; + __time64_t time64; + + /* + * WinAPI SystemTimeToFileTime() function is converting tm-like struct + * to timestamp but it accepts only SYSTEMTIME with valid wMilliseconds, + * wSecond, wMinute, wHour, wDay, wMonth, wYear values. CRT mkgmtime() + * accepts also struct tm with invalid tm_sec, tm_min, tm_hour, tm_mday, + * tm_mon, tm_year values and normalize them on return. So we cannot use + * WinAPI SystemTimeToFileTime() function for conversion. Instead includes + * and use the __tm_to_secs() function from the musl libc implementation. + */ + + time64 = __tm_to_secs(tmptr); + + /* Convert the timestamp back to SYSTEMTIME for normalizing struct tm */ + value = (time64 * 10000000) + 116444736000000000LL; + filetime.dwLowDateTime = value & 0xffffffff; + filetime.dwHighDateTime = value >> 32; + if (!FileTimeToSystemTime(&filetime, &systemtime)) + return -1; + + /* Set back normalized values */ + tmptr->tm_sec = systemtime.wSecond; + tmptr->tm_min = systemtime.wMinute; + tmptr->tm_hour = systemtime.wHour; + tmptr->tm_mday = systemtime.wDay; + tmptr->tm_mon = systemtime.wMonth-1; + tmptr->tm_year = systemtime.wYear-1900; + tmptr->tm_wday = systemtime.wDayOfWeek; + tmptr->tm_yday = days_in_year[tmptr->tm_mon] + systemtime.wDay + ((systemtime.wMonth >= 3 && ((systemtime.wYear % 4 == 0 && systemtime.wYear % 100 != 0) || systemtime.wYear % 400 == 0)) ? 1 : 0); + tmptr->tm_isdst = 0; + + return time64; +} + +#define RETT __time64_t +#define FUNC _mkgmtime64 +#define ARGS struct tm *tmptr +#define CALL tmptr +#include "msvcrt_or_emu_glue.h" -- 2.20.1 _______________________________________________ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public