1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-26 07:11:34 -08:00

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.
This commit is contained in:
Eli Zaretskii 2020-03-08 17:00:10 +02:00
parent 0a3f8da6e1
commit 66bc47d12a
5 changed files with 88 additions and 46 deletions

View 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

View 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_ */

View 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

View 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);
}

121
src/w32.c
View file

@ -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)