@@ -904,10 +904,9 @@ open_exclusive(char *filename, mode_t mode)
904904 remove the file. */
905905
906906static void
907- write_compiled_module (PyCodeObject * co , char * cpathname , struct stat * srcstat )
907+ write_compiled_module (PyCodeObject * co , char * cpathname , struct stat * srcstat , time_t mtime )
908908{
909909 FILE * fp ;
910- time_t mtime = srcstat -> st_mtime ;
911910#ifdef MS_WINDOWS /* since Windows uses different permissions */
912911 mode_t mode = srcstat -> st_mode & ~S_IEXEC ;
913912 /* Issue #6074: We ensure user write access, so we can delete it later
@@ -993,6 +992,38 @@ update_compiled_module(PyCodeObject *co, char *pathname)
993992 return 1 ;
994993}
995994
995+ #ifdef MS_WINDOWS
996+
997+ /* Seconds between 1.1.1601 and 1.1.1970 */
998+ static __int64 secs_between_epochs = 11644473600 ;
999+
1000+ /* Get mtime from file pointer. */
1001+
1002+ static time_t
1003+ win32_mtime (FILE * fp , char * pathname )
1004+ {
1005+ __int64 filetime ;
1006+ HANDLE fh ;
1007+ BY_HANDLE_FILE_INFORMATION file_information ;
1008+
1009+ fh = (HANDLE )_get_osfhandle (fileno (fp ));
1010+ if (fh == INVALID_HANDLE_VALUE ||
1011+ !GetFileInformationByHandle (fh , & file_information )) {
1012+ PyErr_Format (PyExc_RuntimeError ,
1013+ "unable to get file status from '%s'" ,
1014+ pathname );
1015+ return -1 ;
1016+ }
1017+ /* filetime represents the number of 100ns intervals since
1018+ 1.1.1601 (UTC). Convert to seconds since 1.1.1970 (UTC). */
1019+ filetime = (__int64 )file_information .ftLastWriteTime .dwHighDateTime << 32 |
1020+ file_information .ftLastWriteTime .dwLowDateTime ;
1021+ return filetime / 10000000 - secs_between_epochs ;
1022+ }
1023+
1024+ #endif /* #ifdef MS_WINDOWS */
1025+
1026+
9961027/* Load a source module from a given file and return its module
9971028 object WITH INCREMENTED REFERENCE COUNT. If there's a matching
9981029 byte-compiled file, use that instead. */
@@ -1006,20 +1037,29 @@ load_source_module(char *name, char *pathname, FILE *fp)
10061037 char * cpathname ;
10071038 PyCodeObject * co = NULL ;
10081039 PyObject * m ;
1040+ time_t mtime ;
10091041
10101042 if (fstat (fileno (fp ), & st ) != 0 ) {
10111043 PyErr_Format (PyExc_RuntimeError ,
10121044 "unable to get file status from '%s'" ,
10131045 pathname );
10141046 return NULL ;
10151047 }
1016- if (sizeof st .st_mtime > 4 ) {
1048+
1049+ #ifdef MS_WINDOWS
1050+ mtime = win32_mtime (fp , pathname );
1051+ if (mtime == (time_t )- 1 && PyErr_Occurred ())
1052+ return NULL ;
1053+ #else
1054+ mtime = st .st_mtime ;
1055+ #endif
1056+ if (sizeof mtime > 4 ) {
10171057 /* Python's .pyc timestamp handling presumes that the timestamp fits
10181058 in 4 bytes. Since the code only does an equality comparison,
10191059 ordering is not important and we can safely ignore the higher bits
10201060 (collisions are extremely unlikely).
10211061 */
1022- st . st_mtime &= 0xFFFFFFFF ;
1062+ mtime &= 0xFFFFFFFF ;
10231063 }
10241064 buf = PyMem_MALLOC (MAXPATHLEN + 1 );
10251065 if (buf == NULL ) {
@@ -1028,7 +1068,7 @@ load_source_module(char *name, char *pathname, FILE *fp)
10281068 cpathname = make_compiled_pathname (pathname , buf ,
10291069 (size_t )MAXPATHLEN + 1 );
10301070 if (cpathname != NULL &&
1031- (fpc = check_compiled_module (pathname , st . st_mtime , cpathname ))) {
1071+ (fpc = check_compiled_module (pathname , mtime , cpathname ))) {
10321072 co = read_compiled_module (cpathname , fpc );
10331073 fclose (fpc );
10341074 if (co == NULL )
@@ -1053,7 +1093,7 @@ load_source_module(char *name, char *pathname, FILE *fp)
10531093 if (b < 0 )
10541094 goto error_exit ;
10551095 if (!b )
1056- write_compiled_module (co , cpathname , & st );
1096+ write_compiled_module (co , cpathname , & st , mtime );
10571097 }
10581098 }
10591099 m = PyImport_ExecCodeModuleEx (name , (PyObject * )co , pathname );
0 commit comments