Issue #13863: fix incorrect .pyc timestamps on Windows / NTFS (apparently due to buggy fstat)
diff --git a/Python/import.c b/Python/import.c
index 7daba06..92363b3 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -904,10 +904,9 @@
    remove the file. */
 
 static void
-write_compiled_module(PyCodeObject *co, char *cpathname, struct stat *srcstat)
+write_compiled_module(PyCodeObject *co, char *cpathname, struct stat *srcstat, time_t mtime)
 {
     FILE *fp;
-    time_t mtime = srcstat->st_mtime;
 #ifdef MS_WINDOWS   /* since Windows uses different permissions  */
     mode_t mode = srcstat->st_mode & ~S_IEXEC;
     /* Issue #6074: We ensure user write access, so we can delete it later
@@ -993,6 +992,38 @@
     return 1;
 }
 
+#ifdef MS_WINDOWS
+
+/* Seconds between 1.1.1601 and 1.1.1970 */
+static __int64 secs_between_epochs = 11644473600;
+
+/* Get mtime from file pointer. */
+
+static time_t
+win32_mtime(FILE *fp, char *pathname)
+{
+    __int64 filetime;
+    HANDLE fh;
+    BY_HANDLE_FILE_INFORMATION file_information;
+
+    fh = (HANDLE)_get_osfhandle(fileno(fp));
+    if (fh == INVALID_HANDLE_VALUE ||
+        !GetFileInformationByHandle(fh, &file_information)) {
+        PyErr_Format(PyExc_RuntimeError,
+                     "unable to get file status from '%s'",
+                     pathname);
+        return -1;
+    }
+    /* filetime represents the number of 100ns intervals since
+       1.1.1601 (UTC).  Convert to seconds since 1.1.1970 (UTC). */
+    filetime = (__int64)file_information.ftLastWriteTime.dwHighDateTime << 32 |
+               file_information.ftLastWriteTime.dwLowDateTime;
+    return filetime / 10000000 - secs_between_epochs;
+}
+
+#endif  /* #ifdef MS_WINDOWS */
+
+
 /* Load a source module from a given file and return its module
    object WITH INCREMENTED REFERENCE COUNT.  If there's a matching
    byte-compiled file, use that instead. */
@@ -1006,6 +1037,7 @@
     char *cpathname;
     PyCodeObject *co = NULL;
     PyObject *m;
+    time_t mtime;
 
     if (fstat(fileno(fp), &st) != 0) {
         PyErr_Format(PyExc_RuntimeError,
@@ -1013,13 +1045,21 @@
                      pathname);
         return NULL;
     }
-    if (sizeof st.st_mtime > 4) {
+
+#ifdef MS_WINDOWS
+    mtime = win32_mtime(fp, pathname);
+    if (mtime == (time_t)-1 && PyErr_Occurred())
+        return NULL;
+#else
+    mtime = st.st_mtime;
+#endif
+    if (sizeof mtime > 4) {
         /* Python's .pyc timestamp handling presumes that the timestamp fits
            in 4 bytes. Since the code only does an equality comparison,
            ordering is not important and we can safely ignore the higher bits
            (collisions are extremely unlikely).
          */
-        st.st_mtime &= 0xFFFFFFFF;
+        mtime &= 0xFFFFFFFF;
     }
     buf = PyMem_MALLOC(MAXPATHLEN+1);
     if (buf == NULL) {
@@ -1028,7 +1068,7 @@
     cpathname = make_compiled_pathname(pathname, buf,
                                        (size_t)MAXPATHLEN + 1);
     if (cpathname != NULL &&
-        (fpc = check_compiled_module(pathname, st.st_mtime, cpathname))) {
+        (fpc = check_compiled_module(pathname, mtime, cpathname))) {
         co = read_compiled_module(cpathname, fpc);
         fclose(fpc);
         if (co == NULL)
@@ -1053,7 +1093,7 @@
             if (b < 0)
                 goto error_exit;
             if (!b)
-                write_compiled_module(co, cpathname, &st);
+                write_compiled_module(co, cpathname, &st, mtime);
         }
     }
     m = PyImport_ExecCodeModuleEx(name, (PyObject *)co, pathname);