From ae65dc37bcc9b1d9cef0b111131c79dc4ba1bf51 Mon Sep 17 00:00:00 2001 From: Ron Yorston <rmy@pobox.com> Date: Fri, 16 Aug 2019 09:33:29 +0100 Subject: win32: allow nanosecond precision in file times Modern Linux kernels use struct timespec to represent file times, thus allowing nanosecond precision. Update the WIN32 emulation of struct stat and stat(2) to do the same. --- include/mingw.h | 35 +++++++++++++++++++---------------- win32/mingw.c | 41 +++++++++++++++++++++++++++++------------ 2 files changed, 48 insertions(+), 28 deletions(-) diff --git a/include/mingw.h b/include/mingw.h index 07f9857e9..15ead7799 100644 --- a/include/mingw.h +++ b/include/mingw.h @@ -241,6 +241,19 @@ NOIMPL(mingw_sendto,SOCKET s UNUSED_PARAM, const char *buf UNUSED_PARAM, int len #define accept mingw_accept #define select mingw_select +/* + * sys/time.h + */ +#ifndef _TIMESPEC_DEFINED +#define _TIMESPEC_DEFINED +struct timespec { + time_t tv_sec; + long int tv_nsec; +}; +#endif + +int nanosleep(const struct timespec *req, struct timespec *rem); + /* * sys/stat.h */ @@ -300,12 +313,15 @@ struct mingw_stat { gid_t st_gid; dev_t st_rdev; off_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; blksize_t st_blksize; blkcnt_t st_blocks; }; +#define st_atime st_atim.tv_sec +#define st_mtime st_mtim.tv_sec +#define st_ctime st_ctim.tv_sec int mingw_lstat(const char *file_name, struct mingw_stat *buf); int mingw_stat(const char *file_name, struct mingw_stat *buf); @@ -324,19 +340,6 @@ int mingw_fstat(int fd, struct mingw_stat *buf); #define minor(x) 0 #define major(x) 0 -/* - * sys/time.h - */ -#ifndef _TIMESPEC_DEFINED -#define _TIMESPEC_DEFINED -struct timespec { - time_t tv_sec; - long int tv_nsec; -}; -#endif - -int nanosleep(const struct timespec *req, struct timespec *rem); - /* * sys/wait.h */ diff --git a/win32/mingw.c b/win32/mingw.c index 3f80b53f1..7e4d6a318 100644 --- a/win32/mingw.c +++ b/win32/mingw.c @@ -277,6 +277,17 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) return (time_t)(filetime_to_hnsec(ft) / 10000000); } +static inline struct timespec filetime_to_timespec(const FILETIME *ft) +{ + struct timespec ts; + long long winTime = filetime_to_hnsec(ft); + + ts.tv_sec = (time_t)(winTime / 10000000); + ts.tv_nsec = (long)(winTime % 10000000) * 100; + + return ts; +} + static inline mode_t file_attr_to_st_mode(DWORD attr) { mode_t fMode = S_IRUSR|S_IRGRP|S_IROTH; @@ -530,9 +541,9 @@ static int do_lstat(int follow, const char *file_name, struct mingw_stat *buf) /* Get the contents of a symlink, not its target. */ buf->st_mode = S_IFLNK|S_IRWXU|S_IRWXG|S_IRWXO; buf->st_size = name ? strlen(name) : 0; /* should use readlink */ - buf->st_atime = filetime_to_time_t(&(findbuf.ftLastAccessTime)); - buf->st_mtime = filetime_to_time_t(&(findbuf.ftLastWriteTime)); - buf->st_ctime = filetime_to_time_t(&(findbuf.ftCreationTime)); + buf->st_atim = filetime_to_timespec(&(findbuf.ftLastAccessTime)); + buf->st_mtim = filetime_to_timespec(&(findbuf.ftLastWriteTime)); + buf->st_ctim = filetime_to_timespec(&(findbuf.ftCreationTime)); } else { /* The file is not a symlink. */ @@ -542,9 +553,9 @@ static int do_lstat(int follow, const char *file_name, struct mingw_stat *buf) buf->st_mode |= S_IXUSR|S_IXGRP|S_IXOTH; buf->st_size = fdata.nFileSizeLow | (((off64_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)); + buf->st_atim = filetime_to_timespec(&(fdata.ftLastAccessTime)); + buf->st_mtim = filetime_to_timespec(&(fdata.ftLastWriteTime)); + buf->st_ctim = filetime_to_timespec(&(fdata.ftCreationTime)); } buf->st_nlink = S_ISDIR(buf->st_mode) ? 2 : 1; @@ -594,6 +605,9 @@ int mingw_stat(const char *file_name, struct mingw_stat *buf) return do_lstat(1, file_name, buf); } +#undef st_atime +#undef st_mtime +#undef st_ctime int mingw_fstat(int fd, struct mingw_stat *buf) { HANDLE fh = (HANDLE)_get_osfhandle(fd); @@ -612,9 +626,12 @@ int mingw_fstat(int fd, struct mingw_stat *buf) } buf->st_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH; buf->st_size = buf64.st_size; - buf->st_atime = buf64.st_atime; - buf->st_mtime = buf64.st_mtime; - buf->st_ctime = buf64.st_ctime; + buf->st_atim.tv_sec = buf64.st_atime; + buf->st_atim.tv_nsec = 0; + buf->st_mtim.tv_sec = buf64.st_mtime; + buf->st_mtim.tv_nsec = 0; + buf->st_ctim.tv_sec = buf64.st_ctime; + buf->st_ctim.tv_nsec = 0; buf->st_blocks = ((buf64.st_size+4095)>>12)<<3; #if ENABLE_FEATURE_EXTRA_FILE_DATA buf->st_dev = 0; @@ -628,9 +645,9 @@ int mingw_fstat(int fd, struct mingw_stat *buf) buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); buf->st_size = fdata.nFileSizeLow | (((off64_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)); + buf->st_atim = filetime_to_timespec(&(fdata.ftLastAccessTime)); + buf->st_mtim = filetime_to_timespec(&(fdata.ftLastWriteTime)); + buf->st_ctim = filetime_to_timespec(&(fdata.ftCreationTime)); buf->st_blocks = ((buf->st_size+4095)>>12)<<3; #if ENABLE_FEATURE_EXTRA_FILE_DATA buf->st_dev = fdata.dwVolumeSerialNumber; -- cgit v1.2.3-55-g6feb