summaryrefslogtreecommitdiff
path: root/lib/utimens.c
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2017-05-01 15:33:06 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2017-05-01 15:33:26 -0700
commit634d0a907ff7ba5901dfe3624e58d718f3f37cec (patch)
tree6bf86cf04d8b28a79693df9cdef1063c9b06ca76 /lib/utimens.c
parent16b49e214ad828de29ceb57ad1b443eece9bba03 (diff)
downloademacs-634d0a907ff7ba5901dfe3624e58d718f3f37cec.tar.gz
Merge from gnulib
This incorporates: 2017-05-01 New module 'localtime-buffer' 2017-04-30 utimens: Add support for native Windows * admin/merge-gnulib (AVOIDED_MODULES): Add tzset. * configure.ac (tzset): No need for Emacs itself to check now. * lib/gettimeofday.c, lib/time.in.h, lib/time_rz.c, lib/utimens.c: * m4/gettimeofday.m4, m4/time_h.m4, m4/time_rz.m4: Copy from gnulib. * lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate. * lib/localtime-buffer.c, lib/localtime-buffer.h: * m4/localtime-buffer.m4: New files, copied from gnulib. * src/editfns.c (init_editfns): Assume tzset is callable.
Diffstat (limited to 'lib/utimens.c')
-rw-r--r--lib/utimens.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/lib/utimens.c b/lib/utimens.c
index 3b451193350..0b3b8e2f3af 100644
--- a/lib/utimens.c
+++ b/lib/utimens.c
@@ -35,6 +35,12 @@
#include "stat-time.h"
#include "timespec.h"
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# include "msvc-nothrow.h"
+#endif
+
/* Avoid recursion with rpl_futimens or rpl_utimensat. */
#undef futimens
#undef utimensat
@@ -271,6 +277,82 @@ fdutimens (int fd, char const *file, struct timespec const timespec[2])
lutimensat_works_really = -1;
#endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+ /* On native Windows, use SetFileTime(). See
+ <https://msdn.microsoft.com/en-us/library/ms724933.aspx>
+ <https://msdn.microsoft.com/en-us/library/ms724284.aspx> */
+ if (0 <= fd)
+ {
+ HANDLE handle;
+ FILETIME current_time;
+ FILETIME last_access_time;
+ FILETIME last_write_time;
+
+ handle = (HANDLE) _get_osfhandle (fd);
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (ts == NULL || ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW)
+ {
+ /* GetSystemTimeAsFileTime
+ <https://msdn.microsoft.com/en-us/library/ms724397.aspx>.
+ It would be overkill to use
+ GetSystemTimePreciseAsFileTime
+ <https://msdn.microsoft.com/en-us/library/hh706895.aspx>. */
+ GetSystemTimeAsFileTime (&current_time);
+ }
+
+ if (ts == NULL || ts[0].tv_nsec == UTIME_NOW)
+ {
+ last_access_time = current_time;
+ }
+ else if (ts[0].tv_nsec == UTIME_OMIT)
+ {
+ last_access_time.dwLowDateTime = 0;
+ last_access_time.dwHighDateTime = 0;
+ }
+ else
+ {
+ ULONGLONG time_since_16010101 =
+ (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;
+ }
+
+ if (ts == NULL || ts[1].tv_nsec == UTIME_NOW)
+ {
+ last_write_time = current_time;
+ }
+ else if (ts[1].tv_nsec == UTIME_OMIT)
+ {
+ last_write_time.dwLowDateTime = 0;
+ last_write_time.dwHighDateTime = 0;
+ }
+ else
+ {
+ ULONGLONG time_since_16010101 =
+ (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;
+ }
+
+ if (SetFileTime (handle, NULL, &last_access_time, &last_write_time))
+ return 0;
+ else
+ {
+ #if 0
+ DWORD sft_error = GetLastError ();
+ fprintf (stderr, "utime SetFileTime error 0x%x\n", (unsigned int) sft_error);
+ #endif
+ errno = EINVAL;
+ return -1;
+ }
+ }
+#endif
+
/* The platform lacks an interface to set file timestamps with
nanosecond resolution, so do the best we can, discarding any
fractional part of the timestamp. */