diff options
| author | Eli Zaretskii | 2020-03-08 17:00:10 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2020-03-08 17:00:10 +0200 |
| commit | 66bc47d12aba72ff738a9f5575e0b93eefc641ba (patch) | |
| tree | c85ff0ed19d5067a45bd81e7251248a6ae8cf279 /src | |
| parent | 0a3f8da6e1a56ada409cf1677ac40fcc75a8a33c (diff) | |
| download | emacs-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.c | 2 | ||||
| -rw-r--r-- | src/w32.c | 121 |
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 | } |
| @@ -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. */ | ||
| 3197 | static int | ||
| 3198 | set_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 | ||
| 4987 | static void | 4963 | static void |
| 4988 | convert_from_time_t (time_t time, FILETIME * pft) | 4964 | convert_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. */ |
| 5668 | int | 5645 | int |
| 5669 | fstat (int desc, struct stat * buf) | 5646 | fstat (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 | ||
| 5781 | int | 5757 | int |
| 5782 | utime (const char *name, struct utimbuf *times) | 5758 | utimensat (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) |