From c65336478ba90bf82206e73b18b8d0f003ef72ea Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Fri, 25 Sep 2015 18:02:55 +0200 Subject: [PATCH 1/2] Win32: replace MSVCRT's fstat() with a Win32-based implementation fstat() is the only stat-related CRT function for which we don't have a full replacement yet (and thus the only reason to stick with MSVCRT's 'struct stat' definition). Fully implement fstat(), in preparation of implementing a POSIX 2013 compatible 'struct stat' with nanosecond-precision file times. Signed-off-by: Karsten Blees --- compat/mingw.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 65f9894a536189..780e85e02625ad 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -792,18 +792,31 @@ int mingw_stat(const char *file_name, struct stat *buf) int mingw_fstat(int fd, struct stat *buf) { HANDLE fh = (HANDLE)_get_osfhandle(fd); - if (fh == INVALID_HANDLE_VALUE) { + DWORD avail, type = GetFileType(fh) & ~FILE_TYPE_REMOTE; + + switch (type) { + case FILE_TYPE_DISK: + return get_file_info_by_handle(fh, buf); + + case FILE_TYPE_CHAR: + case FILE_TYPE_PIPE: + /* initialize stat fields */ + memset(buf, 0, sizeof(*buf)); + buf->st_nlink = 1; + + if (type == FILE_TYPE_CHAR) { + buf->st_mode = _S_IFCHR; + } else { + buf->st_mode = _S_IFIFO; + if (PeekNamedPipe(fh, NULL, 0, NULL, &avail, NULL)) + buf->st_size = avail; + } + return 0; + + default: errno = EBADF; return -1; } - /* direct non-file handles to MS's fstat() */ - if (GetFileType(fh) != FILE_TYPE_DISK) - return _fstati64(fd, buf); - - if (!get_file_info_by_handle(fh, buf)) - return 0; - errno = EBADF; - return -1; } static inline void time_t_to_filetime(time_t t, FILETIME *ft) From a61683e5789b49dd0010fad11ad6cff1ccdf0cff Mon Sep 17 00:00:00 2001 From: Karsten Blees Date: Sat, 26 Sep 2015 02:03:28 +0200 Subject: [PATCH 2/2] Win32: 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: Due to performance issues when using git variants with different file time resolutions, this patch does *not* yet enable nanosecond precision in the Makefile (use 'make USE_NSEC=1'). Signed-off-by: Karsten Blees --- compat/mingw.c | 12 +++++------ compat/mingw.h | 48 +++++++++++++++++++++++++++++------------- compat/win32/fscache.c | 18 ++++++++-------- config.mak.uname | 2 -- 4 files changed, 48 insertions(+), 32 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 780e85e02625ad..ea7d1e48b4189d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -715,9 +715,9 @@ int mingw_lstat(const char *file_name, struct stat *buf) buf->st_size = S_ISLNK(buf->st_mode) ? MAX_LONG_PATH : fdata.nFileSizeLow | (((off_t) fdata.nFileSizeHigh) << 32); buf->st_dev = buf->st_rdev = 0; /* not used by Git */ - buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); - buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); - buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim)); + filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim)); + filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim)); return 0; } error: @@ -762,9 +762,9 @@ static int get_file_info_by_handle(HANDLE hnd, struct stat *buf) buf->st_nlink = 1; buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes, 0); buf->st_size = fdata.nFileSizeLow | (((off_t) fdata.nFileSizeHigh) << 32); - buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); - buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); - buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim)); + filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim)); + filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim)); return 0; } diff --git a/compat/mingw.h b/compat/mingw.h index c5dea2cf283ea8..62e9c3815dee28 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -331,24 +331,49 @@ static inline long long filetime_to_hnsec(const FILETIME *ft) return winTime - 116444736000000000LL; } -static inline time_t filetime_to_time_t(const FILETIME *ft) -{ - return (time_t)(filetime_to_hnsec(ft) / 10000000); -} - /* - * 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 #define off_t off64_t #define lseek _lseeki64 +struct timespec { + time_t tv_sec; + long tv_nsec; +}; #endif -/* use struct stat with 64 bit st_size */ +static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts) +{ + long long hnsec = filetime_to_hnsec(ft); + ts->tv_sec = (time_t)(hnsec / 10000000); + ts->tv_nsec = (hnsec % 10000000) * 100; +} + +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 #undef stat #endif -#define stat _stati64 +#define stat mingw_stat int mingw_lstat(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); @@ -361,13 +386,6 @@ int mingw_fstat(int fd, struct stat *buf); #endif extern int (*lstat)(const char *file_name, struct stat *buf); -#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); #define utime mingw_utime diff --git a/compat/win32/fscache.c b/compat/win32/fscache.c index b7caf2a02fcd33..846df4fcafff50 100644 --- a/compat/win32/fscache.c +++ b/compat/win32/fscache.c @@ -38,9 +38,9 @@ struct fsentry { struct { /* More stat members (only used for file entries). */ off64_t st_size; - time_t st_atime; - time_t st_mtime; - time_t st_ctime; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; }; }; }; @@ -151,9 +151,9 @@ static struct fsentry *fseentry_create_entry(struct fsentry *list, fdata->dwReserved0); fse->st_size = S_ISLNK(fse->st_mode) ? MAX_LONG_PATH : fdata->nFileSizeLow | (((off_t) fdata->nFileSizeHigh) << 32); - fse->st_atime = filetime_to_time_t(&(fdata->ftLastAccessTime)); - fse->st_mtime = filetime_to_time_t(&(fdata->ftLastWriteTime)); - fse->st_ctime = filetime_to_time_t(&(fdata->ftCreationTime)); + filetime_to_timespec(&(fdata->ftLastAccessTime), &(fse->st_atim)); + filetime_to_timespec(&(fdata->ftLastWriteTime), &(fse->st_mtim)); + filetime_to_timespec(&(fdata->ftCreationTime), &(fse->st_ctim)); return fse; } @@ -432,9 +432,9 @@ int fscache_lstat(const char *filename, struct stat *st) st->st_nlink = 1; st->st_mode = fse->st_mode; st->st_size = fse->st_size; - st->st_atime = fse->st_atime; - st->st_mtime = fse->st_mtime; - st->st_ctime = fse->st_ctime; + st->st_atim = fse->st_atim; + st->st_mtim = fse->st_mtim; + st->st_ctim = fse->st_ctim; /* don't forget to release fsentry */ fsentry_release(fse); diff --git a/config.mak.uname b/config.mak.uname index 48a17ed58ae213..5f3c7a0f93952a 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -354,7 +354,6 @@ ifeq ($(uname_S),Windows) NO_SVN_TESTS = YesPlease RUNTIME_PREFIX = YesPlease NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease - NO_NSEC = YesPlease USE_WIN32_MMAP = YesPlease # USE_NED_ALLOCATOR = YesPlease UNRELIABLE_FSTAT = UnfortunatelyYes @@ -504,7 +503,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_SVN_TESTS = YesPlease RUNTIME_PREFIX = YesPlease NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease - NO_NSEC = YesPlease USE_WIN32_MMAP = YesPlease USE_NED_ALLOCATOR = YesPlease UNRELIABLE_FSTAT = UnfortunatelyYes