From e5b7d2b2c17b1bd80d759350bb6d3cfa1303f687 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Fri, 14 May 2021 09:18:53 +0100 Subject: win32: implement futimens(2)/utimensat(2) The touch applet has been changed to use futimens(2)/utimensat(2). Provide implementations of these for WIN32. --- include/mingw.h | 10 +++++++ win32/mingw.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/include/mingw.h b/include/mingw.h index d48237add..89b26762a 100644 --- a/include/mingw.h +++ b/include/mingw.h @@ -34,6 +34,9 @@ int inet_pton(int af, const char *src, void *dst); #define O_DIRECT 0 #define O_SPECIAL 0x800000 +#define AT_FDCWD -100 +#define AT_SYMLINK_NOFOLLOW 0x100 + /* * grp.h */ @@ -348,6 +351,13 @@ int mingw_fstat(int fd, struct mingw_stat *buf); #define stat mingw_stat #define fstat mingw_fstat +#define UTIME_NOW ((1l << 30) - 1l) +#define UTIME_OMIT ((1l << 30) - 2l) + +int utimensat(int fd, const char *path, const struct timespec times[2], + int flags); +int futimens(int fd, const struct timespec times[2]); + /* * sys/sysinfo.h */ diff --git a/win32/mingw.c b/win32/mingw.c index 3bb79633a..182e3d4db 100644 --- a/win32/mingw.c +++ b/win32/mingw.c @@ -708,6 +708,14 @@ static inline void timeval_to_filetime(const struct timeval tv, FILETIME *ft) ft->dwHighDateTime = winTime >> 32; } +static inline void timespec_to_filetime(const struct timespec tv, FILETIME *ft) +{ + long long winTime = (tv.tv_sec * 10000000LL) + tv.tv_nsec / 100LL + + 116444736000000000LL; + ft->dwLowDateTime = winTime; + ft->dwHighDateTime = winTime >> 32; +} + int utimes(const char *file_name, const struct timeval tims[2]) { FILETIME mft, aft; @@ -731,13 +739,85 @@ int utimes(const char *file_name, const struct timeval tims[2]) } if (!SetFileTime(fh, NULL, &aft, &mft)) { - errno = EINVAL; + errno = err_win_to_posix(); rc = -1; } CloseHandle(fh); return rc; } +static int hutimens(HANDLE fh, const struct timespec times[2]) +{ + FILETIME now, aft, mft; + FILETIME *pft[2] = {&aft, &mft}; + int i; + + GetSystemTimeAsFileTime(&now); + + if (times) { + for (i = 0; i < 2; ++i) { + if (times[i].tv_nsec == UTIME_NOW) + *pft[i] = now; + else if (times[i].tv_nsec == UTIME_OMIT) + pft[i] = NULL; + else if (times[i].tv_nsec >= 0 && times[i].tv_nsec < 1000000000L) + timespec_to_filetime(times[i], pft[i]); + else { + errno = EINVAL; + return -1; + } + } + } else { + aft = mft = now; + } + + if (!SetFileTime(fh, NULL, pft[0], pft[1])) { + errno = err_win_to_posix(); + return -1; + } + return 0; +} + +int futimens(int fd, const struct timespec times[2]) +{ + HANDLE fh; + + fh = (HANDLE)_get_osfhandle(fd); + if (fh == INVALID_HANDLE_VALUE) { + errno = EBADF; + return -1; + } + + return hutimens(fh, times); +} + +int utimensat(int fd, const char *path, const struct timespec times[2], + int flags) +{ + int rc = -1; + HANDLE fh; + DWORD cflag = FILE_FLAG_BACKUP_SEMANTICS; + + if (!is_absolute_path(path) && fd != AT_FDCWD) { + errno = ENOSYS; // partial implementation + return rc; + } + + if (flags & AT_SYMLINK_NOFOLLOW) + cflag |= FILE_FLAG_OPEN_REPARSE_POINT; + + fh = CreateFile(path, FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING, + cflag, NULL); + if (fh == INVALID_HANDLE_VALUE) { + errno = err_win_to_posix(); + return rc; + } + + rc = hutimens(fh, times); + CloseHandle(fh); + return rc; +} + unsigned int sleep (unsigned int seconds) { Sleep(seconds*1000); -- cgit v1.2.3-55-g6feb