crt: Provide emulation of _mktime64 function

Function _mktime64 is available since msvcr70.dll. For older msvcrt
versions provide mingw-w64 emulation via musl libc __tm_to_secs() function
with adjustment of _timezone and _dstbias variable variables, and
normalization via _localtime64() function which is now available in all
CRT import libraries (either as native symbols or as mingw-w64 emulation).
Adjustment of _dstbias needs to be done only when passed timestamp is
during the DST period which is detected by the _localtime64() function too.

Signed-off-by: Martin Storsjö <martin@martin.st>
diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am
index e8e5e73..2497a45 100644
--- a/mingw-w64-crt/Makefile.am
+++ b/mingw-w64-crt/Makefile.am
@@ -587,6 +587,7 @@
   misc/_localtime64.c \
   misc/_mkgmtime32.c \
   misc/_mkgmtime64.c \
+  misc/_mktime64.c \
   misc/_set_doserrno.c \
   misc/_set_fmode.c \
   misc/_time64.c \
@@ -902,6 +903,7 @@
   misc/_futime64.c \
   misc/_gmtime64.c \
   misc/_localtime64.c \
+  misc/_mktime64.c \
   misc/_time64.c \
   misc/_utime64.c \
   misc/_wctime64.c \
diff --git a/mingw-w64-crt/lib-common/msvcrt.def.in b/mingw-w64-crt/lib-common/msvcrt.def.in
index a1439b2..71054e1 100644
--- a/mingw-w64-crt/lib-common/msvcrt.def.in
+++ b/mingw-w64-crt/lib-common/msvcrt.def.in
@@ -1158,7 +1158,7 @@
 F_NON_I386(_futime64) ; i386 _futime64 replaced by emu
 F_NON_I386(_gmtime64) ; i386 _gmtime64 replaced by emu
 F_NON_I386(_localtime64) ; i386 _localtime64 replaced by emu
-_mktime64
+F_NON_I386(_mktime64) ; i386 _mktime64 replaced by emu
 F_X86_ANY(_osplatform DATA)
 F_NON_I386(_stat64) ; i386 _stat64 replaced by emu
 F_NON_I386(_time64) ; i386 _time64 replaced by emu
diff --git a/mingw-w64-crt/misc/_mktime64.c b/mingw-w64-crt/misc/_mktime64.c
new file mode 100644
index 0000000..924e663
--- /dev/null
+++ b/mingw-w64-crt/misc/_mktime64.c
@@ -0,0 +1,60 @@
+/**
+ * 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 __time64_t __cdecl emu__mktime64(struct tm *tmptr)
+{
+    __time64_t time64;
+    struct tm *tmptr2;
+    int tm_isdst;
+    long local_dstbias;
+    long local_timezone;
+
+    /* _tzset() initialize _daylight, _dstbias and _timezone variables,
+     * so it needs to be called before accessing those variables.
+     * If those variables are already initialized then _tzset() does
+     * not need to be called again. As _tzset() is an expensive call,
+     * guard repeated calls by static variable. As the _tzset() is a
+     * thread-safe call, the race condition is not a problem.
+     */
+    {
+        static volatile long tzset_called = 0;
+        if (!tzset_called) {
+            _tzset();
+            (void)InterlockedExchange(&tzset_called, 1);
+        }
+    }
+    local_dstbias = *__dstbias();
+    local_timezone = *__timezone();
+
+    tm_isdst = tmptr->tm_isdst;
+    time64 = __tm_to_secs(tmptr);
+    time64 += local_timezone;
+
+    tmptr2 = _localtime64(&time64);
+    if (!tmptr2)
+        return -1;
+
+    if (tm_isdst > 0 || (tm_isdst < 0 && tmptr2->tm_isdst > 0)) {
+        time64 += local_dstbias;
+        tmptr2 = _localtime64(&time64);
+        if (!tmptr2)
+            return -1;
+    }
+
+    *tmptr = *tmptr2;
+    return time64;
+}
+
+#define RETT __time64_t
+#define FUNC _mktime64
+#define ARGS struct tm *tmptr
+#define CALL tmptr
+#include "msvcrt_or_emu_glue.h"