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>
This commit is contained in:
Karsten Blees 2018-10-23 03:23:22 -07:00 committed by Junio C Hamano
parent d75e697353
commit d7e8c87421
3 changed files with 36 additions and 20 deletions

View File

@ -592,9 +592,11 @@ static inline long long filetime_to_hnsec(const FILETIME *ft)
return winTime - 116444736000000000LL; return winTime - 116444736000000000LL;
} }
static inline time_t filetime_to_time_t(const FILETIME *ft) static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
{ {
return (time_t)(filetime_to_hnsec(ft) / 10000000); long long hnsec = filetime_to_hnsec(ft);
ts->tv_sec = (time_t)(hnsec / 10000000);
ts->tv_nsec = (hnsec % 10000000) * 100;
} }
/** /**
@ -653,9 +655,9 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
buf->st_size = fdata.nFileSizeLow | buf->st_size = fdata.nFileSizeLow |
(((off_t)fdata.nFileSizeHigh)<<32); (((off_t)fdata.nFileSizeHigh)<<32);
buf->st_dev = buf->st_rdev = 0; /* not used by Git */ buf->st_dev = buf->st_rdev = 0; /* not used by Git */
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
WIN32_FIND_DATAW findbuf; WIN32_FIND_DATAW findbuf;
HANDLE handle = FindFirstFileW(wfilename, &findbuf); HANDLE handle = FindFirstFileW(wfilename, &findbuf);
@ -753,9 +755,9 @@ static int get_file_info_by_handle(HANDLE hnd, struct stat *buf)
buf->st_size = fdata.nFileSizeLow | buf->st_size = fdata.nFileSizeLow |
(((off_t)fdata.nFileSizeHigh)<<32); (((off_t)fdata.nFileSizeHigh)<<32);
buf->st_dev = buf->st_rdev = 0; /* not used by Git */ buf->st_dev = buf->st_rdev = 0; /* not used by Git */
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
return 0; return 0;
} }

View File

@ -327,18 +327,41 @@ static inline int getrlimit(int resource, struct rlimit *rlp)
} }
/* /*
* Use mingw specific stat()/lstat()/fstat() implementations on Windows. * Use mingw specific stat()/lstat()/fstat() implementations on Windows,
* including our own struct stat with 64 bit st_size and nanosecond-precision
* file times.
*/ */
#ifndef __MINGW64_VERSION_MAJOR #ifndef __MINGW64_VERSION_MAJOR
#define off_t off64_t #define off_t off64_t
#define lseek _lseeki64 #define lseek _lseeki64
struct timespec {
time_t tv_sec;
long tv_nsec;
};
#endif #endif
/* use struct stat with 64 bit st_size */ struct mingw_stat {
_dev_t st_dev;
_ino_t st_ino;
_mode_t st_mode;
short st_nlink;
short st_uid;
short st_gid;
_dev_t st_rdev;
off64_t st_size;
struct timespec st_atim;
struct timespec st_mtim;
struct timespec st_ctim;
};
#define st_atime st_atim.tv_sec
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
#ifdef stat #ifdef stat
#undef stat #undef stat
#endif #endif
#define stat _stati64 #define stat mingw_stat
int mingw_lstat(const char *file_name, struct stat *buf); int mingw_lstat(const char *file_name, struct stat *buf);
int mingw_stat(const char *file_name, struct stat *buf); int mingw_stat(const char *file_name, struct stat *buf);
int mingw_fstat(int fd, struct stat *buf); int mingw_fstat(int fd, struct stat *buf);
@ -351,13 +374,6 @@ int mingw_fstat(int fd, struct stat *buf);
#endif #endif
#define lstat mingw_lstat #define lstat mingw_lstat
#ifndef _stati64
# define _stati64(x,y) mingw_stat(x,y)
#elif defined (_USE_32BIT_TIME_T)
# define _stat32i64(x,y) mingw_stat(x,y)
#else
# define _stat64(x,y) mingw_stat(x,y)
#endif
int mingw_utime(const char *file_name, const struct utimbuf *times); int mingw_utime(const char *file_name, const struct utimbuf *times);
#define utime mingw_utime #define utime mingw_utime

View File

@ -370,7 +370,6 @@ ifeq ($(uname_S),Windows)
RUNTIME_PREFIX = YesPlease RUNTIME_PREFIX = YesPlease
HAVE_WPGMPTR = YesWeDo HAVE_WPGMPTR = YesWeDo
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
NO_NSEC = YesPlease
USE_WIN32_MMAP = YesPlease USE_WIN32_MMAP = YesPlease
MMAP_PREVENTS_DELETE = UnfortunatelyYes MMAP_PREVENTS_DELETE = UnfortunatelyYes
# USE_NED_ALLOCATOR = YesPlease # USE_NED_ALLOCATOR = YesPlease
@ -518,7 +517,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
RUNTIME_PREFIX = YesPlease RUNTIME_PREFIX = YesPlease
HAVE_WPGMPTR = YesWeDo HAVE_WPGMPTR = YesWeDo
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
NO_NSEC = YesPlease
USE_WIN32_MMAP = YesPlease USE_WIN32_MMAP = YesPlease
MMAP_PREVENTS_DELETE = UnfortunatelyYes MMAP_PREVENTS_DELETE = UnfortunatelyYes
USE_NED_ALLOCATOR = YesPlease USE_NED_ALLOCATOR = YesPlease