mirror of
https://github.com/NixOS/nix.git
synced 2024-11-26 00:32:28 +00:00
Add support for utimensat
as an alternative to lutimes
OpenBSD doesn't support `lutimes`, but does support `utimensat` which
subsumes it. In fact, all the BSDs, Linux, and newer macOS all support
it. So lets make this our first choice for the implementation.
In addition, let's get rid of the `lutimes` `ENOSYS` special case. The
Linux manpage says
> ENOSYS
>
> The kernel does not support this call; Linux 2.6.22 or later is
> required.
which I think is the origin of this check, but that's a very old version
of Linux at this point. The code can be simplified a lot of we drop
support for it here (as we've done elsewhere, anyways).
Co-Authored-By: John Ericson <John.Ericson@Obsidian.Systems>
(cherry picked from commit d023202811
)
This commit is contained in:
parent
7718688f52
commit
803943fce4
@ -89,9 +89,10 @@ AC_LANG_POP(C++)
|
|||||||
AC_CHECK_FUNCS([statvfs pipe2])
|
AC_CHECK_FUNCS([statvfs pipe2])
|
||||||
|
|
||||||
|
|
||||||
# Check for lutimes, optionally used for changing the mtime of
|
# Check for lutimes and utimensat, optionally used for changing the
|
||||||
# symlinks.
|
# mtime of symlinks.
|
||||||
AC_CHECK_FUNCS([lutimes])
|
AC_CHECK_DECLS([AT_SYMLINK_NOFOLLOW], [], [], [[#include <fcntl.h>]])
|
||||||
|
AC_CHECK_FUNCS([lutimes utimensat])
|
||||||
|
|
||||||
|
|
||||||
# Check whether the store optimiser can optimise symlinks.
|
# Check whether the store optimiser can optimise symlinks.
|
||||||
|
@ -574,7 +574,28 @@ void setWriteTime(
|
|||||||
time_t modificationTime,
|
time_t modificationTime,
|
||||||
std::optional<bool> optIsSymlink)
|
std::optional<bool> optIsSymlink)
|
||||||
{
|
{
|
||||||
#ifndef _WIN32
|
#ifdef _WIN32
|
||||||
|
// FIXME use `fs::last_write_time`.
|
||||||
|
//
|
||||||
|
// Would be nice to use std::filesystem unconditionally, but
|
||||||
|
// doesn't support access time just modification time.
|
||||||
|
//
|
||||||
|
// System clock vs File clock issues also make that annoying.
|
||||||
|
warn("Changing file times is not yet implemented on Windows, path is '%s'", path);
|
||||||
|
#elif HAVE_UTIMENSAT && HAVE_DECL_AT_SYMLINK_NOFOLLOW
|
||||||
|
struct timespec times[2] = {
|
||||||
|
{
|
||||||
|
.tv_sec = accessedTime,
|
||||||
|
.tv_nsec = 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.tv_sec = modificationTime,
|
||||||
|
.tv_nsec = 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if (utimensat(AT_FDCWD, path.c_str(), times, AT_SYMLINK_NOFOLLOW) == -1)
|
||||||
|
throw SysError("changing modification time of '%s' (using `utimensat`)", path);
|
||||||
|
#else
|
||||||
struct timeval times[2] = {
|
struct timeval times[2] = {
|
||||||
{
|
{
|
||||||
.tv_sec = accessedTime,
|
.tv_sec = accessedTime,
|
||||||
@ -585,42 +606,21 @@ void setWriteTime(
|
|||||||
.tv_usec = 0,
|
.tv_usec = 0,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
#endif
|
#if HAVE_LUTIMES
|
||||||
|
if (lutimes(path.c_str(), times) == -1)
|
||||||
auto nonSymlink = [&]{
|
throw SysError("changing modification time of '%s'", path);
|
||||||
|
#else
|
||||||
bool isSymlink = optIsSymlink
|
bool isSymlink = optIsSymlink
|
||||||
? *optIsSymlink
|
? *optIsSymlink
|
||||||
: fs::is_symlink(path);
|
: fs::is_symlink(path);
|
||||||
|
|
||||||
if (!isSymlink) {
|
if (!isSymlink) {
|
||||||
#ifdef _WIN32
|
if (utimes(path.c_str(), times) == -1)
|
||||||
// FIXME use `fs::last_write_time`.
|
|
||||||
//
|
|
||||||
// Would be nice to use std::filesystem unconditionally, but
|
|
||||||
// doesn't support access time just modification time.
|
|
||||||
//
|
|
||||||
// System clock vs File clock issues also make that annoying.
|
|
||||||
warn("Changing file times is not yet implemented on Windows, path is '%s'", path);
|
|
||||||
#else
|
|
||||||
if (utimes(path.c_str(), times) == -1) {
|
|
||||||
|
|
||||||
throw SysError("changing modification time of '%s' (not a symlink)", path);
|
throw SysError("changing modification time of '%s' (not a symlink)", path);
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
throw Error("Cannot modification time of symlink '%s'", path);
|
throw Error("Cannot modification time of symlink '%s'", path);
|
||||||
}
|
}
|
||||||
};
|
#endif
|
||||||
|
|
||||||
#if HAVE_LUTIMES
|
|
||||||
if (lutimes(path.c_str(), times) == -1) {
|
|
||||||
if (errno == ENOSYS)
|
|
||||||
nonSymlink();
|
|
||||||
else
|
|
||||||
throw SysError("changing modification time of '%s'", path);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
nonSymlink();
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +41,8 @@ check_funcs = [
|
|||||||
# Optionally used to try to close more file descriptors (e.g. before
|
# Optionally used to try to close more file descriptors (e.g. before
|
||||||
# forking) on Unix.
|
# forking) on Unix.
|
||||||
'sysconf',
|
'sysconf',
|
||||||
|
# Optionally used for changing the mtime of files and symlinks.
|
||||||
|
'utimensat',
|
||||||
]
|
]
|
||||||
foreach funcspec : check_funcs
|
foreach funcspec : check_funcs
|
||||||
define_name = 'HAVE_' + funcspec.underscorify().to_upper()
|
define_name = 'HAVE_' + funcspec.underscorify().to_upper()
|
||||||
@ -48,6 +50,8 @@ foreach funcspec : check_funcs
|
|||||||
configdata.set(define_name, define_value)
|
configdata.set(define_name, define_value)
|
||||||
endforeach
|
endforeach
|
||||||
|
|
||||||
|
configdata.set('HAVE_DECL_AT_SYMLINK_NOFOLLOW', cxx.has_header_symbol('fcntl.h', 'AT_SYMLINK_NOFOLLOW').to_int())
|
||||||
|
|
||||||
subdir('build-utils-meson/threads')
|
subdir('build-utils-meson/threads')
|
||||||
|
|
||||||
if host_machine.system() == 'windows'
|
if host_machine.system() == 'windows'
|
||||||
|
Loading…
Reference in New Issue
Block a user