//===-- Linux implementation of utimes ------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "src/sys/time/utimes.h" #include "hdr/fcntl_macros.h" #include "hdr/types/struct_timespec.h" #include "hdr/types/struct_timeval.h" #include "src/__support/OSUtil/syscall.h" #include "src/__support/common.h" #include "src/__support/libc_errno.h" #include namespace LIBC_NAMESPACE_DECL { #ifdef SYS_utimes constexpr auto UTIMES_SYSCALL_ID = SYS_utimes; #elif defined(SYS_utimensat) constexpr auto UTIMES_SYSCALL_ID = SYS_utimensat; #elif defined(SYS_utimensat_time64) constexpr auto UTIMES_SYSCALL_ID = SYS_utimensat_time64; #else #error "utimes, utimensat, utimensat_time64, syscalls not available." #endif LLVM_LIBC_FUNCTION(int, utimes, (const char *path, const struct timeval times[2])) { int ret; #ifdef SYS_utimes // No need to define a timespec struct, use the syscall directly. ret = LIBC_NAMESPACE::syscall_impl(UTIMES_SYSCALL_ID, path, times); #elif defined(SYS_utimensat) || defined(SYS_utimensat_time64) // the utimensat syscall requires a timespec struct, not timeval. struct timespec ts[2]; struct timespec *ts_ptr = nullptr; // default value if times is nullptr // convert the microsec values in timeval struct times // to nanosecond values in timespec struct ts if (times != nullptr) { // ensure consistent values if ((times[0].tv_usec < 0 || times[1].tv_usec < 0) || (times[0].tv_usec >= 1000000 || times[1].tv_usec >= 1000000)) { libc_errno = EINVAL; return -1; } // set seconds in ts ts[0].tv_sec = times[0].tv_sec; ts[1].tv_sec = times[1].tv_sec; // convert u-seconds to nanoseconds ts[0].tv_nsec = static_cast(times[0].tv_usec * 1000); ts[1].tv_nsec = static_cast(times[1].tv_usec * 1000); ts_ptr = ts; } // If times was nullptr, ts_ptr remains nullptr, which utimensat interprets // as setting times to the current time. // utimensat syscall. // flags=0 means don't follow symlinks (like utimes) ret = LIBC_NAMESPACE::syscall_impl(UTIMES_SYSCALL_ID, AT_FDCWD, path, ts_ptr, 0); #endif // SYS_utimensat if (ret < 0) { libc_errno = -ret; return -1; } return 0; } } // namespace LIBC_NAMESPACE_DECL