mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-23 05:20:06 +00:00
f5b6fd258b
This patch provides new __utimensat64 explicit 64 bit function for setting access and modification time of a file. Moreover, a 32 bit version - __utimensat has been refactored to internally use __utimensat64. The __utimensat is now supposed to be used on systems still supporting 32 bit time (__TIMESIZE != 64) - hence the necessary conversions to 64 bit struct __timespec64. When pointer to struct __timespec64 is NULL - the file access and modification time is set to the current one and no conversions from struct timespec to __timespec64 are performed. The new utimensat_time64 syscall available from Linux 5.1+ has been used, when applicable. The new helper function - __utimensat64_helper - has been introduced to facilitate code re-usage on function providing futimens syscall handling. The Linux kernel checks if passed tv_nsec value overflows, so there is no need to repeat it in glibc. When utimensat syscall on systems supporting 32 bit time ABI is used, the check is performed if passed data (which may have 64 bit tv_sec) fits into 32 bit range. Build tests: - The code has been tested on x86_64/x86 (native compilation): make PARALLELMFLAGS="-j8" && make xcheck PARALLELMFLAGS="-j8" - The glibc has been build tested (make PARALLELMFLAGS="-j8") for x86 (i386), x86_64-x32, and armv7 Run-time tests: - Run specific tests on ARM/x86 32bit systems (qemu): https://github.com/lmajewski/meta-y2038 and run tests: https://github.com/lmajewski/y2038-tests/commits/master - Use of cross-test-ssh.sh for ARM (armv7): make PARALLELMFLAGS="-j8" test-wrapper='./cross-test-ssh.sh root@192.168.7.2' xcheck Linux kernel, headers and minimal kernel version for glibc build test matrix: - Linux v5.1 (with utimensat_time64) and glibc build with v5.1 as minimal kernel version (--enable-kernel="5.1.0") The __ASSUME_TIME64_SYSCALLS flag defined. - Linux v5.1 and default minimal kernel version The __ASSUME_TIME64_SYSCALLS not defined, but kernel supports utimensat_time64 syscall. - Linux v4.19 (no utimensat_time64 support) with default minimal kernel version for contemporary glibc This kernel doesn't support utimensat_time64 syscall, so the fallback to utimensat is tested. The above tests were performed with Y2038 redirection applied as well as without (so the __TIMESIZE != 64 execution path is checked as well). No regressions were observed.
94 lines
2.8 KiB
C
94 lines
2.8 KiB
C
/* Change access and modification times of open file. Linux version.
|
|
Copyright (C) 2007-2019 Free Software Foundation, Inc.
|
|
This file is part of the GNU C Library.
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
The GNU C Library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with the GNU C Library; if not, see
|
|
<https://www.gnu.org/licenses/>. */
|
|
|
|
#include <errno.h>
|
|
#include <sys/stat.h>
|
|
#include <sysdep.h>
|
|
#include <time.h>
|
|
#include <kernel-features.h>
|
|
|
|
/* Helper function defined for easy reusage of the code which calls utimensat
|
|
and utimensat_time64 syscall. */
|
|
int
|
|
__utimensat64_helper (int fd, const char *file,
|
|
const struct __timespec64 tsp64[2], int flags)
|
|
{
|
|
#ifdef __ASSUME_TIME64_SYSCALLS
|
|
# ifndef __NR_utimensat_time64
|
|
# define __NR_utimensat_time64 __NR_utimensat
|
|
# endif
|
|
return INLINE_SYSCALL (utimensat_time64, 4, fd, file, &tsp64[0], flags);
|
|
#else
|
|
# ifdef __NR_utimensat_time64
|
|
int ret = INLINE_SYSCALL (utimensat_time64, 4, fd, file, &tsp64[0], flags);
|
|
if (ret == 0 || errno != ENOSYS)
|
|
return ret;
|
|
# endif
|
|
if (tsp64
|
|
&& (! in_time_t_range (tsp64[0].tv_sec)
|
|
|| ! in_time_t_range (tsp64[1].tv_sec)))
|
|
{
|
|
__set_errno (EOVERFLOW);
|
|
return -1;
|
|
}
|
|
|
|
struct timespec tsp32[2];
|
|
if (tsp64)
|
|
{
|
|
tsp32[0] = valid_timespec64_to_timespec (tsp64[0]);
|
|
tsp32[1] = valid_timespec64_to_timespec (tsp64[1]);
|
|
}
|
|
|
|
return INLINE_SYSCALL (utimensat, 4, fd, file, tsp64 ? &tsp32[0] : NULL,
|
|
flags);
|
|
#endif
|
|
|
|
}
|
|
libc_hidden_def (__utimensat64_helper)
|
|
|
|
/* Change the access time of FILE to TSP[0] and
|
|
the modification time of FILE to TSP[1].
|
|
|
|
Starting with 2.6.22 the Linux kernel has the utimensat syscall. */
|
|
int
|
|
__utimensat64 (int fd, const char *file, const struct __timespec64 tsp64[2],
|
|
int flags)
|
|
{
|
|
if (file == NULL)
|
|
return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
|
|
|
|
return __utimensat64_helper (fd, file, &tsp64[0], flags);
|
|
}
|
|
|
|
#if __TIMESIZE != 64
|
|
int
|
|
__utimensat (int fd, const char *file, const struct timespec tsp[2],
|
|
int flags)
|
|
{
|
|
struct __timespec64 tsp64[2];
|
|
if (tsp)
|
|
{
|
|
tsp64[0] = valid_timespec_to_timespec64 (tsp[0]);
|
|
tsp64[1] = valid_timespec_to_timespec64 (tsp[1]);
|
|
}
|
|
|
|
return __utimensat64 (fd, file, tsp ? &tsp64[0] : NULL, flags);
|
|
}
|
|
#endif
|
|
weak_alias (__utimensat, utimensat)
|