Oops, I had verified the subsecond resolution support (through Cygwin's 'ls', as "ls -l --full-time") only for the case fd >= 0. For the case fd < 0, this patch adds the subsecond resolution support.
2017-05-07 Bruno Haible <br...@clisp.org> utimens: On native Windows, support 100ns resolution also if fd < 0. * lib/utime.in.h: Include <time.h>. (_gl_utimens_windows): New declaration. * lib/utime.c (_gl_utimens_windows): New function, based on utime. (utime): Invoke it. * lib/utimens.c (fdutimens): On native Windows, call _gl_utimens_windows instead of utime. * modules/utime (Depends-on): Add 'time'. diff --git a/lib/utime.c b/lib/utime.c index 230d36b..6226934 100644 --- a/lib/utime.c +++ b/lib/utime.c @@ -30,7 +30,7 @@ # include "malloca.h" int -utime (const char *name, const struct utimbuf *ts) +_gl_utimens_windows (const char *name, struct timespec ts[2]) { /* POSIX <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13> specifies: "More than two leading <slash> characters shall be treated as @@ -146,13 +146,13 @@ utime (const char *name, const struct utimbuf *ts) { { ULONGLONG time_since_16010101 = - (ULONGLONG) ts->actime * 10000000 + 116444736000000000LL; + (ULONGLONG) ts[0].tv_sec * 10000000 + ts[0].tv_nsec / 100 + 116444736000000000LL; last_access_time.dwLowDateTime = (DWORD) time_since_16010101; last_access_time.dwHighDateTime = time_since_16010101 >> 32; } { ULONGLONG time_since_16010101 = - (ULONGLONG) ts->modtime * 10000000 + 116444736000000000LL; + (ULONGLONG) ts[1].tv_sec * 10000000 + ts[1].tv_nsec / 100 + 116444736000000000LL; last_write_time.dwLowDateTime = (DWORD) time_since_16010101; last_write_time.dwHighDateTime = time_since_16010101 >> 32; } @@ -168,7 +168,7 @@ utime (const char *name, const struct utimbuf *ts) { #if 0 DWORD sft_error = GetLastError (); - fprintf (stderr, "utime SetFileTime error 0x%x\n", (unsigned int) sft_error); + fprintf (stderr, "utimens SetFileTime error 0x%x\n", (unsigned int) sft_error); #endif CloseHandle (handle); if (malloca_rname != NULL) @@ -181,7 +181,7 @@ utime (const char *name, const struct utimbuf *ts) failed: { #if 0 - fprintf (stderr, "utime CreateFile/GetFileAttributes error 0x%x\n", (unsigned int) error); + fprintf (stderr, "utimens CreateFile/GetFileAttributes error 0x%x\n", (unsigned int) error); #endif if (malloca_rname != NULL) freea (malloca_rname); @@ -237,4 +237,20 @@ utime (const char *name, const struct utimbuf *ts) } } +int +utime (const char *name, const struct utimbuf *ts) +{ + if (ts == NULL) + return _gl_utimens_windows (name, NULL); + else + { + struct timespec ts_with_nanoseconds[2]; + ts_with_nanoseconds[0].tv_sec = ts->actime; + ts_with_nanoseconds[0].tv_nsec = 0; + ts_with_nanoseconds[1].tv_sec = ts->modtime; + ts_with_nanoseconds[1].tv_nsec = 0; + return _gl_utimens_windows (name, ts_with_nanoseconds); + } +} + #endif diff --git a/lib/utime.in.h b/lib/utime.in.h index 8847e72..df80d8c 100644 --- a/lib/utime.in.h +++ b/lib/utime.in.h @@ -33,6 +33,11 @@ # include <sys/utime.h> #endif +#if @GNULIB_UTIME@ +/* Get struct timespec. */ +# include <time.h> +#endif + /* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ /* The definition of _GL_ARG_NONNULL is copied here. */ @@ -74,6 +79,10 @@ _GL_WARN_ON_USE (utime, # endif #endif +#if @GNULIB_UTIME@ +extern int _gl_utimens_windows (const char *filename, struct timespec ts[2]); +#endif + #endif /* _@GUARD_PREFIX@_UTIME_H */ #endif /* _@GUARD_PREFIX@_UTIME_H */ diff --git a/lib/utimens.c b/lib/utimens.c index b027cfb..b4bfa8e 100644 --- a/lib/utimens.c +++ b/lib/utimens.c @@ -473,7 +473,9 @@ fdutimens (int fd, char const *file, struct timespec const timespec[2]) return -1; } -#if HAVE_WORKING_UTIMES +#ifdef USE_SETFILETIME + return _gl_utimens_windows (file, ts); +#elif HAVE_WORKING_UTIMES return utimes (file, t); #else { diff --git a/modules/utime b/modules/utime index 545a24c..0fc34eb 100644 --- a/modules/utime +++ b/modules/utime @@ -7,6 +7,7 @@ m4/utime.m4 Depends-on: utime-h +time filename [test $HAVE_UTIME = 0 || test $REPLACE_UTIME = 1] malloca [test $HAVE_UTIME = 0 || test $REPLACE_UTIME = 1]