]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix the MinGW build as followup to recent "nofollow" changes
authorEli Zaretskii <eliz@gnu.org>
Sun, 8 Mar 2020 15:00:10 +0000 (17:00 +0200)
committerEli Zaretskii <eliz@gnu.org>
Sun, 8 Mar 2020 15:00:10 +0000 (17:00 +0200)
* src/w32.c (fdutimens): Call utimensat instead of utime.
(set_file_times): Function deleted.
(convert_from_timespec): Renamed from convert_from_time_t and
modified to accept 'struct timespec' argument instead of 'time_t'.
(utimensat): Renamed from utime and modified to accept 'struct
timespec [2]' argument and an additional argument FLAG.  Emulate
Posix 'utimensat'.  Call 'convert_from_timespec'.
(w32_copy_file): Call 'utimensat' instead of 'set_file_times'.
* src/fileio.c (Fcopy_file) [WINDOWSNT]: Make the error message be
identical to that on Posix platforms.

* nt/inc/sys/stat.h (utimensat): Provide prototype.
* nt/mingw-cfg.site (ac_cv_func_futimens)
(gl_cv_func_futimens_works, ac_cv_func_utimensat)
(gl_cv_func_utimensat_works): Override Gnulib tests.
* nt/gnulib-cfg.mk (OMIT_GNULIB_MODULE_futimens)
(OMIT_GNULIB_MODULE_utimensat): Disable these Gnulib modules.

nt/gnulib-cfg.mk
nt/inc/sys/stat.h
nt/mingw-cfg.site
src/fileio.c
src/w32.c

index 1d120a973d11e3b06fa68e8715069b3da109cc70..e3b945720d6039dba5cc9d9915fce7fca41a815a 100644 (file)
@@ -65,3 +65,5 @@ OMIT_GNULIB_MODULE_unistd = true
 OMIT_GNULIB_MODULE_canonicalize-lgpl = true
 OMIT_GNULIB_MODULE_fchmodat = true
 OMIT_GNULIB_MODULE_lchmod = true
+OMIT_GNULIB_MODULE_futimens = true
+OMIT_GNULIB_MODULE_utimensat = true
index 7bf780dbaa297ac70bd77c914a754ff62983fd85..f58d5ab65731cf463041a34d226d6574dba64ea0 100644 (file)
@@ -164,4 +164,9 @@ int __cdecl __MINGW_NOTHROW fstatat (int, char const *,
                                                 struct stat *, int);
 int __cdecl __MINGW_NOTHROW    chmod (const char*, int);
 
+/* Provide prototypes of library functions that are emulated on w32
+   and whose prototypes are usually found in sys/stat.h on POSIX
+   platforms.  */
+extern int utimensat (int, const char *, struct timespec const[2], int);
+
 #endif /* INC_SYS_STAT_H_ */
index 5bd5b834634f869fe5756c438e62c4bae8c0a150..2271eef98d6f649c1de2f58e38430e0f59606aa4 100644 (file)
@@ -105,6 +105,10 @@ gl_cv_func_fstatat_zero_flag=yes
 ac_cv_func_fchmodat=yes
 gl_cv_func_fchmodat_works="not-needed-so-yes"
 ac_cv_func_lchmod=yes
+ac_cv_func_futimens=not-needed
+gl_cv_func_futimens_works="not-needed-so-yes"
+ac_cv_func_utimensat=yes
+gl_cv_func_utimensat_works=yes
 # Aliased to _commit in ms-w32.h
 ac_cv_func_fsync=yes
 ac_cv_func_fdatasync=yes
index 82fd79892060afeadeef61d90135d22138bddcd2..ffe79559a3f0fd15465fb91e0ca672e519ac96c8 100644 (file)
@@ -2077,7 +2077,7 @@ permissions.  */)
       report_file_error ("Copying permissions from", file);
     case -3:
       xsignal2 (Qfile_date_error,
-               build_string ("Resetting file times"), newname);
+               build_string ("Cannot set file date"), newname);
     case -4:
       report_file_error ("Copying permissions to", newname);
     }
index 40f286ad6cf1c3adbcfc7f3f57284aec4b992b37..698e10e234e0f785e0641f9e9224975e12f93087 100644 (file)
--- a/src/w32.c
+++ b/src/w32.c
@@ -3178,33 +3178,9 @@ fdutimens (int fd, char const *file, struct timespec const timespec[2])
       return _futime (fd, &_ut);
     }
   else
-    {
-      struct utimbuf ut;
-
-      ut.actime = timespec[0].tv_sec;
-      ut.modtime = timespec[1].tv_sec;
-      /* Call 'utime', which is implemented below, not the MS library
-        function, which fails on directories.  */
-      return utime (file, &ut);
-    }
+    return utimensat (fd, file, timespec, 0);
 }
 
-/* Set the access and modification time stamps of FD (a.k.a. FILE) to be
-   ATIME and MTIME, respectively.
-   FD must be either negative -- in which case it is ignored --
-   or a file descriptor that is open on FILE.
-   If FD is nonnegative, then FILE can be NULL.  */
-static int
-set_file_times (int fd, const char *filename,
-               struct timespec atime, struct timespec mtime)
-{
-  struct timespec timespec[2];
-  timespec[0] = atime;
-  timespec[1] = mtime;
-  return fdutimens (fd, filename, timespec);
-}
-
-
 /* ------------------------------------------------------------------------- */
 /* IO support and wrapper functions for the Windows API. */
 /* ------------------------------------------------------------------------- */
@@ -4985,7 +4961,7 @@ convert_time (FILETIME ft)
 }
 
 static void
-convert_from_time_t (time_t time, FILETIME * pft)
+convert_from_timespec (struct timespec time, FILETIME * pft)
 {
   ULARGE_INTEGER tmp;
 
@@ -4996,7 +4972,8 @@ convert_from_time_t (time_t time, FILETIME * pft)
     }
 
   /* time in 100ns units since 1-Jan-1601 */
-  tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
+  tmp.QuadPart =
+    (ULONGLONG) time.tv_sec * 10000000L + time.tv_nsec / 100 + utc_base;
   pft->dwHighDateTime = tmp.HighPart;
   pft->dwLowDateTime = tmp.LowPart;
 }
@@ -5663,8 +5640,8 @@ fstatat (int fd, char const *name, struct stat *st, int flags)
   return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
 }
 
-/* Provide fstat and utime as well as stat for consistent handling of
-   file timestamps. */
+/* Provide fstat and utimensat as well as stat for consistent handling
+   of file timestamps. */
 int
 fstat (int desc, struct stat * buf)
 {
@@ -5775,23 +5752,65 @@ fstat (int desc, struct stat * buf)
   return 0;
 }
 
-/* A version of 'utime' which handles directories as well as
-   files.  */
+/* Emulate utimensat.  */
 
 int
-utime (const char *name, struct utimbuf *times)
+utimensat (int fd, const char *name, const struct timespec times[2], int flag)
 {
-  struct utimbuf deftime;
+  struct timespec ltimes[2];
   HANDLE fh;
   FILETIME mtime;
   FILETIME atime;
+  DWORD flags_and_attrs = FILE_FLAG_BACKUP_SEMANTICS;
+
+  /* Rely on a hack: an open directory is modeled as file descriptor 0.
+     This is good enough for the current usage in Emacs, but is fragile.
+
+     FIXME: Add proper support for utimensat.
+     Gnulib does this and can serve as a model.  */
+  char fullname[MAX_UTF8_PATH];
+
+  if (fd != AT_FDCWD)
+    {
+      char lastc = dir_pathname[strlen (dir_pathname) - 1];
+
+      if (_snprintf (fullname, sizeof fullname, "%s%s%s",
+                    dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", name)
+         < 0)
+       {
+         errno = ENAMETOOLONG;
+         return -1;
+       }
+      name = fullname;
+    }
 
   if (times == NULL)
     {
-      deftime.modtime = deftime.actime = time (NULL);
-      times = &deftime;
+      memset (ltimes, 0, sizeof (ltimes));
+      ltimes[0] = ltimes[1] = current_timespec ();
+    }
+  else
+    {
+      if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT)
+       return 0;               /* nothing to do */
+      if ((times[0].tv_nsec != UTIME_NOW && times[0].tv_nsec != UTIME_OMIT
+          && !(0 <= times[0].tv_nsec && times[0].tv_nsec < 1000000000))
+         || (times[1].tv_nsec != UTIME_NOW && times[1].tv_nsec != UTIME_OMIT
+             && !(0 <= times[1].tv_nsec && times[1].tv_nsec < 1000000000)))
+       {
+         errno = EINVAL;       /* reject invalid timespec values */
+         return -1;
+       }
+
+      memcpy (ltimes, times, sizeof (ltimes));
+      if (ltimes[0].tv_nsec == UTIME_NOW)
+       ltimes[0] = current_timespec ();
+      if (ltimes[1].tv_nsec == UTIME_NOW)
+       ltimes[1] = current_timespec ();
     }
 
+  if (flag == AT_SYMLINK_NOFOLLOW)
+    flags_and_attrs |= FILE_FLAG_OPEN_REPARSE_POINT;
   if (w32_unicode_filenames)
     {
       wchar_t name_utf16[MAX_PATH];
@@ -5805,7 +5824,7 @@ utime (const char *name, struct utimbuf *times)
                           allows other processes to delete files inside it,
                           while we have the directory open.  */
                        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                       0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+                       0, OPEN_EXISTING, flags_and_attrs, NULL);
     }
   else
     {
@@ -5816,13 +5835,26 @@ utime (const char *name, struct utimbuf *times)
 
       fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES,
                        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                       0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+                       0, OPEN_EXISTING, flags_and_attrs, NULL);
     }
   if (fh != INVALID_HANDLE_VALUE)
     {
-      convert_from_time_t (times->actime, &atime);
-      convert_from_time_t (times->modtime, &mtime);
-      if (!SetFileTime (fh, NULL, &atime, &mtime))
+      FILETIME *patime, *pmtime;
+      if (ltimes[0].tv_nsec == UTIME_OMIT)
+       patime = NULL;
+      else
+       {
+         convert_from_timespec (ltimes[0], &atime);
+         patime = &atime;
+       }
+      if (ltimes[1].tv_nsec == UTIME_OMIT)
+       pmtime = NULL;
+      else
+       {
+         convert_from_timespec (ltimes[1], &mtime);
+         pmtime = &mtime;
+       }
+      if (!SetFileTime (fh, NULL, patime, pmtime))
        {
          CloseHandle (fh);
          errno = EACCES;
@@ -6741,16 +6773,16 @@ w32_copy_file (const char *from, const char *to,
      FIXME?  */
   else if (!keep_time)
     {
-      struct timespec now;
+      struct timespec tnow[2];
       DWORD attributes;
 
+      tnow[0] = tnow[1] = current_timespec ();
       if (w32_unicode_filenames)
        {
          /* Ensure file is writable while its times are set.  */
          attributes = GetFileAttributesW (to_w);
          SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY);
-         now = current_timespec ();
-         if (set_file_times (-1, to, now, now))
+         if (utimensat (AT_FDCWD, to, tnow, 0))
            {
              /* Restore original attributes.  */
              SetFileAttributesW (to_w, attributes);
@@ -6765,8 +6797,7 @@ w32_copy_file (const char *from, const char *to,
        {
          attributes = GetFileAttributesA (to_a);
          SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY);
-         now = current_timespec ();
-         if (set_file_times (-1, to, now, now))
+         if (utimensat (AT_FDCWD, to, tnow, 0))
            {
              SetFileAttributesA (to_a, attributes);
              if (acl)