mingw: implement nanosecond-precision file times

We no longer use any of MSVCRT's stat-functions, so there's no need to stick to a CRT-compatible 'struct stat' either. Define and use our own POSIX-2013-compatible 'struct stat' with nanosecond- precision file times. Note: This can cause performance issues when using Git variants with different file time resolutions, as the timestamps are stored in the Git index: after updating the index with a Git variant that uses second-precision file times, a nanosecond-aware Git will think that pretty much every single file listed in the index is out of date. Signed-off-by: Karsten Blees <blees@dcon.de> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Karsten Blees committed Oct 23, 2018 at 03:23 UTC d7e8c87421868ab7dab2814360d277a425b42bc5
3 files changed +36 -20
compat/mingw.c
+10 -8
@@ -592,9 +592,11 @@ static inline long long filetime_to_hnsec(const FILETIME *ft)
592 return winTime - 116444736000000000LL;
593 }
594
595 -static inline time_t filetime_to_time_t(const FILETIME *ft)
595 +static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
596 {
597 - return (time_t)(filetime_to_hnsec(ft) / 10000000);
597 + long long hnsec = filetime_to_hnsec(ft);
598 + ts->tv_sec = (time_t)(hnsec / 10000000);
599 + ts->tv_nsec = (hnsec % 10000000) * 100;
600 }
601
602 /**
@@ -653,9 +655,9 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
655 buf->st_size = fdata.nFileSizeLow |
656 (((off_t)fdata.nFileSizeHigh)<<32);
657 buf->st_dev = buf->st_rdev = 0; /* not used by Git */
656 - buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
657 - buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
658 - buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
658 + filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
659 + filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
660 + filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
661 if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
662 WIN32_FIND_DATAW findbuf;
663 HANDLE handle = FindFirstFileW(wfilename, &findbuf);
@@ -753,9 +755,9 @@ static int get_file_info_by_handle(HANDLE hnd, struct stat *buf)
755 buf->st_size = fdata.nFileSizeLow |
756 (((off_t)fdata.nFileSizeHigh)<<32);
757 buf->st_dev = buf->st_rdev = 0; /* not used by Git */
756 - buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
757 - buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
758 - buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
758 + filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
759 + filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
760 + filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
761 return 0;
762 }
763
compat/mingw.h
+26 -10
@@ -327,18 +327,41 @@ static inline int getrlimit(int resource, struct rlimit *rlp)
327 }
328
329 /*
330 - * Use mingw specific stat()/lstat()/fstat() implementations on Windows.
330 + * Use mingw specific stat()/lstat()/fstat() implementations on Windows,
331 + * including our own struct stat with 64 bit st_size and nanosecond-precision
332 + * file times.
333 */
334 #ifndef __MINGW64_VERSION_MAJOR
335 #define off_t off64_t
336 #define lseek _lseeki64
337 +struct timespec {
338 + time_t tv_sec;
339 + long tv_nsec;
340 +};
341 #endif
342
337 -/* use struct stat with 64 bit st_size */
343 +struct mingw_stat {
344 + _dev_t st_dev;
345 + _ino_t st_ino;
346 + _mode_t st_mode;
347 + short st_nlink;
348 + short st_uid;
349 + short st_gid;
350 + _dev_t st_rdev;
351 + off64_t st_size;
352 + struct timespec st_atim;
353 + struct timespec st_mtim;
354 + struct timespec st_ctim;
355 +};
356 +
357 +#define st_atime st_atim.tv_sec
358 +#define st_mtime st_mtim.tv_sec
359 +#define st_ctime st_ctim.tv_sec
360 +
361 #ifdef stat
362 #undef stat
363 #endif
341 -#define stat _stati64
364 +#define stat mingw_stat
365 int mingw_lstat(const char *file_name, struct stat *buf);
366 int mingw_stat(const char *file_name, struct stat *buf);
367 int mingw_fstat(int fd, struct stat *buf);
@@ -351,13 +374,6 @@ int mingw_fstat(int fd, struct stat *buf);
374 #endif
375 #define lstat mingw_lstat
376
354 -#ifndef _stati64
355 -# define _stati64(x,y) mingw_stat(x,y)
356 -#elif defined (_USE_32BIT_TIME_T)
357 -# define _stat32i64(x,y) mingw_stat(x,y)
358 -#else
359 -# define _stat64(x,y) mingw_stat(x,y)
360 -#endif
377
378 int mingw_utime(const char *file_name, const struct utimbuf *times);
379 #define utime mingw_utime
config.mak.uname
-2
@@ -370,7 +370,6 @@ ifeq ($(uname_S),Windows)
370 RUNTIME_PREFIX = YesPlease
371 HAVE_WPGMPTR = YesWeDo
372 NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
373 - NO_NSEC = YesPlease
373 USE_WIN32_MMAP = YesPlease
374 MMAP_PREVENTS_DELETE = UnfortunatelyYes
375 # USE_NED_ALLOCATOR = YesPlease
@@ -518,7 +517,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
517 RUNTIME_PREFIX = YesPlease
518 HAVE_WPGMPTR = YesWeDo
519 NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
521 - NO_NSEC = YesPlease
520 USE_WIN32_MMAP = YesPlease
521 MMAP_PREVENTS_DELETE = UnfortunatelyYes
522 USE_NED_ALLOCATOR = YesPlease