aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2020-03-08 17:00:10 +0200
committerEli Zaretskii2020-03-08 17:00:10 +0200
commit66bc47d12aba72ff738a9f5575e0b93eefc641ba (patch)
treec85ff0ed19d5067a45bd81e7251248a6ae8cf279 /src
parent0a3f8da6e1a56ada409cf1677ac40fcc75a8a33c (diff)
downloademacs-66bc47d12aba72ff738a9f5575e0b93eefc641ba.tar.gz
emacs-66bc47d12aba72ff738a9f5575e0b93eefc641ba.zip
Fix the MinGW build as followup to recent "nofollow" changes
* 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.
Diffstat (limited to 'src')
-rw-r--r--src/fileio.c2
-rw-r--r--src/w32.c121
2 files changed, 77 insertions, 46 deletions
diff --git a/src/fileio.c b/src/fileio.c
index 82fd7989206..ffe79559a3f 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -2077,7 +2077,7 @@ permissions. */)
2077 report_file_error ("Copying permissions from", file); 2077 report_file_error ("Copying permissions from", file);
2078 case -3: 2078 case -3:
2079 xsignal2 (Qfile_date_error, 2079 xsignal2 (Qfile_date_error,
2080 build_string ("Resetting file times"), newname); 2080 build_string ("Cannot set file date"), newname);
2081 case -4: 2081 case -4:
2082 report_file_error ("Copying permissions to", newname); 2082 report_file_error ("Copying permissions to", newname);
2083 } 2083 }
diff --git a/src/w32.c b/src/w32.c
index 40f286ad6cf..698e10e234e 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -3178,33 +3178,9 @@ fdutimens (int fd, char const *file, struct timespec const timespec[2])
3178 return _futime (fd, &_ut); 3178 return _futime (fd, &_ut);
3179 } 3179 }
3180 else 3180 else
3181 { 3181 return utimensat (fd, file, timespec, 0);
3182 struct utimbuf ut;
3183
3184 ut.actime = timespec[0].tv_sec;
3185 ut.modtime = timespec[1].tv_sec;
3186 /* Call 'utime', which is implemented below, not the MS library
3187 function, which fails on directories. */
3188 return utime (file, &ut);
3189 }
3190} 3182}
3191 3183
3192/* Set the access and modification time stamps of FD (a.k.a. FILE) to be
3193 ATIME and MTIME, respectively.
3194 FD must be either negative -- in which case it is ignored --
3195 or a file descriptor that is open on FILE.
3196 If FD is nonnegative, then FILE can be NULL. */
3197static int
3198set_file_times (int fd, const char *filename,
3199 struct timespec atime, struct timespec mtime)
3200{
3201 struct timespec timespec[2];
3202 timespec[0] = atime;
3203 timespec[1] = mtime;
3204 return fdutimens (fd, filename, timespec);
3205}
3206
3207
3208/* ------------------------------------------------------------------------- */ 3184/* ------------------------------------------------------------------------- */
3209/* IO support and wrapper functions for the Windows API. */ 3185/* IO support and wrapper functions for the Windows API. */
3210/* ------------------------------------------------------------------------- */ 3186/* ------------------------------------------------------------------------- */
@@ -4985,7 +4961,7 @@ convert_time (FILETIME ft)
4985} 4961}
4986 4962
4987static void 4963static void
4988convert_from_time_t (time_t time, FILETIME * pft) 4964convert_from_timespec (struct timespec time, FILETIME * pft)
4989{ 4965{
4990 ULARGE_INTEGER tmp; 4966 ULARGE_INTEGER tmp;
4991 4967
@@ -4996,7 +4972,8 @@ convert_from_time_t (time_t time, FILETIME * pft)
4996 } 4972 }
4997 4973
4998 /* time in 100ns units since 1-Jan-1601 */ 4974 /* time in 100ns units since 1-Jan-1601 */
4999 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base; 4975 tmp.QuadPart =
4976 (ULONGLONG) time.tv_sec * 10000000L + time.tv_nsec / 100 + utc_base;
5000 pft->dwHighDateTime = tmp.HighPart; 4977 pft->dwHighDateTime = tmp.HighPart;
5001 pft->dwLowDateTime = tmp.LowPart; 4978 pft->dwLowDateTime = tmp.LowPart;
5002} 4979}
@@ -5663,8 +5640,8 @@ fstatat (int fd, char const *name, struct stat *st, int flags)
5663 return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW)); 5640 return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
5664} 5641}
5665 5642
5666/* Provide fstat and utime as well as stat for consistent handling of 5643/* Provide fstat and utimensat as well as stat for consistent handling
5667 file timestamps. */ 5644 of file timestamps. */
5668int 5645int
5669fstat (int desc, struct stat * buf) 5646fstat (int desc, struct stat * buf)
5670{ 5647{
@@ -5775,23 +5752,65 @@ fstat (int desc, struct stat * buf)
5775 return 0; 5752 return 0;
5776} 5753}
5777 5754
5778/* A version of 'utime' which handles directories as well as 5755/* Emulate utimensat. */
5779 files. */
5780 5756
5781int 5757int
5782utime (const char *name, struct utimbuf *times) 5758utimensat (int fd, const char *name, const struct timespec times[2], int flag)
5783{ 5759{
5784 struct utimbuf deftime; 5760 struct timespec ltimes[2];
5785 HANDLE fh; 5761 HANDLE fh;
5786 FILETIME mtime; 5762 FILETIME mtime;
5787 FILETIME atime; 5763 FILETIME atime;
5764 DWORD flags_and_attrs = FILE_FLAG_BACKUP_SEMANTICS;
5765
5766 /* Rely on a hack: an open directory is modeled as file descriptor 0.
5767 This is good enough for the current usage in Emacs, but is fragile.
5768
5769 FIXME: Add proper support for utimensat.
5770 Gnulib does this and can serve as a model. */
5771 char fullname[MAX_UTF8_PATH];
5772
5773 if (fd != AT_FDCWD)
5774 {
5775 char lastc = dir_pathname[strlen (dir_pathname) - 1];
5776
5777 if (_snprintf (fullname, sizeof fullname, "%s%s%s",
5778 dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", name)
5779 < 0)
5780 {
5781 errno = ENAMETOOLONG;
5782 return -1;
5783 }
5784 name = fullname;
5785 }
5788 5786
5789 if (times == NULL) 5787 if (times == NULL)
5790 { 5788 {
5791 deftime.modtime = deftime.actime = time (NULL); 5789 memset (ltimes, 0, sizeof (ltimes));
5792 times = &deftime; 5790 ltimes[0] = ltimes[1] = current_timespec ();
5791 }
5792 else
5793 {
5794 if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT)
5795 return 0; /* nothing to do */
5796 if ((times[0].tv_nsec != UTIME_NOW && times[0].tv_nsec != UTIME_OMIT
5797 && !(0 <= times[0].tv_nsec && times[0].tv_nsec < 1000000000))
5798 || (times[1].tv_nsec != UTIME_NOW && times[1].tv_nsec != UTIME_OMIT
5799 && !(0 <= times[1].tv_nsec && times[1].tv_nsec < 1000000000)))
5800 {
5801 errno = EINVAL; /* reject invalid timespec values */
5802 return -1;
5803 }
5804
5805 memcpy (ltimes, times, sizeof (ltimes));
5806 if (ltimes[0].tv_nsec == UTIME_NOW)
5807 ltimes[0] = current_timespec ();
5808 if (ltimes[1].tv_nsec == UTIME_NOW)
5809 ltimes[1] = current_timespec ();
5793 } 5810 }
5794 5811
5812 if (flag == AT_SYMLINK_NOFOLLOW)
5813 flags_and_attrs |= FILE_FLAG_OPEN_REPARSE_POINT;
5795 if (w32_unicode_filenames) 5814 if (w32_unicode_filenames)
5796 { 5815 {
5797 wchar_t name_utf16[MAX_PATH]; 5816 wchar_t name_utf16[MAX_PATH];
@@ -5805,7 +5824,7 @@ utime (const char *name, struct utimbuf *times)
5805 allows other processes to delete files inside it, 5824 allows other processes to delete files inside it,
5806 while we have the directory open. */ 5825 while we have the directory open. */
5807 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 5826 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5808 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); 5827 0, OPEN_EXISTING, flags_and_attrs, NULL);
5809 } 5828 }
5810 else 5829 else
5811 { 5830 {
@@ -5816,13 +5835,26 @@ utime (const char *name, struct utimbuf *times)
5816 5835
5817 fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES, 5836 fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES,
5818 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 5837 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5819 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); 5838 0, OPEN_EXISTING, flags_and_attrs, NULL);
5820 } 5839 }
5821 if (fh != INVALID_HANDLE_VALUE) 5840 if (fh != INVALID_HANDLE_VALUE)
5822 { 5841 {
5823 convert_from_time_t (times->actime, &atime); 5842 FILETIME *patime, *pmtime;
5824 convert_from_time_t (times->modtime, &mtime); 5843 if (ltimes[0].tv_nsec == UTIME_OMIT)
5825 if (!SetFileTime (fh, NULL, &atime, &mtime)) 5844 patime = NULL;
5845 else
5846 {
5847 convert_from_timespec (ltimes[0], &atime);
5848 patime = &atime;
5849 }
5850 if (ltimes[1].tv_nsec == UTIME_OMIT)
5851 pmtime = NULL;
5852 else
5853 {
5854 convert_from_timespec (ltimes[1], &mtime);
5855 pmtime = &mtime;
5856 }
5857 if (!SetFileTime (fh, NULL, patime, pmtime))
5826 { 5858 {
5827 CloseHandle (fh); 5859 CloseHandle (fh);
5828 errno = EACCES; 5860 errno = EACCES;
@@ -6741,16 +6773,16 @@ w32_copy_file (const char *from, const char *to,
6741 FIXME? */ 6773 FIXME? */
6742 else if (!keep_time) 6774 else if (!keep_time)
6743 { 6775 {
6744 struct timespec now; 6776 struct timespec tnow[2];
6745 DWORD attributes; 6777 DWORD attributes;
6746 6778
6779 tnow[0] = tnow[1] = current_timespec ();
6747 if (w32_unicode_filenames) 6780 if (w32_unicode_filenames)
6748 { 6781 {
6749 /* Ensure file is writable while its times are set. */ 6782 /* Ensure file is writable while its times are set. */
6750 attributes = GetFileAttributesW (to_w); 6783 attributes = GetFileAttributesW (to_w);
6751 SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY); 6784 SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY);
6752 now = current_timespec (); 6785 if (utimensat (AT_FDCWD, to, tnow, 0))
6753 if (set_file_times (-1, to, now, now))
6754 { 6786 {
6755 /* Restore original attributes. */ 6787 /* Restore original attributes. */
6756 SetFileAttributesW (to_w, attributes); 6788 SetFileAttributesW (to_w, attributes);
@@ -6765,8 +6797,7 @@ w32_copy_file (const char *from, const char *to,
6765 { 6797 {
6766 attributes = GetFileAttributesA (to_a); 6798 attributes = GetFileAttributesA (to_a);
6767 SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY); 6799 SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY);
6768 now = current_timespec (); 6800 if (utimensat (AT_FDCWD, to, tnow, 0))
6769 if (set_file_times (-1, to, now, now))
6770 { 6801 {
6771 SetFileAttributesA (to_a, attributes); 6802 SetFileAttributesA (to_a, attributes);
6772 if (acl) 6803 if (acl)