87 lines · cpp
1//===-- Linux implementation of utimes ------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "src/sys/time/utimes.h"10 11#include "hdr/fcntl_macros.h"12#include "hdr/types/struct_timespec.h"13#include "hdr/types/struct_timeval.h"14 15#include "src/__support/OSUtil/syscall.h"16#include "src/__support/common.h"17 18#include "src/__support/libc_errno.h"19 20#include <sys/syscall.h>21 22namespace LIBC_NAMESPACE_DECL {23 24LLVM_LIBC_FUNCTION(int, utimes,25 (const char *path, const struct timeval times[2])) {26 int ret;27 28#ifdef SYS_utimes29 // No need to define a timespec struct, use the syscall directly.30 ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_utimes, path, times);31#elif defined(SYS_utimensat) || defined(SYS_utimensat_time64)32 33#if defined(SYS_utimensat)34 constexpr auto UTIMES_SYSCALL_ID = SYS_utimensat;35#elif defined(SYS_utimensat_time64)36 constexpr auto UTIMES_SYSCALL_ID = SYS_utimensat_time64;37#endif38 39 // the utimensat syscall requires a timespec struct, not timeval.40 struct timespec ts[2];41 struct timespec *ts_ptr = nullptr; // default value if times is nullptr42 43 // convert the microsec values in timeval struct times44 // to nanosecond values in timespec struct ts45 if (times != nullptr) {46 47 // ensure consistent values48 if ((times[0].tv_usec < 0 || times[1].tv_usec < 0) ||49 (times[0].tv_usec >= 1000000 || times[1].tv_usec >= 1000000)) {50 libc_errno = EINVAL;51 return -1;52 }53 54 // set seconds in ts55 ts[0].tv_sec = times[0].tv_sec;56 ts[1].tv_sec = times[1].tv_sec;57 58 // convert u-seconds to nanoseconds59 ts[0].tv_nsec =60 static_cast<decltype(ts[0].tv_nsec)>(times[0].tv_usec * 1000);61 ts[1].tv_nsec =62 static_cast<decltype(ts[1].tv_nsec)>(times[1].tv_usec * 1000);63 64 ts_ptr = ts;65 }66 67 // If times was nullptr, ts_ptr remains nullptr, which utimensat interprets68 // as setting times to the current time.69 70 // utimensat syscall.71 // flags=0 means don't follow symlinks (like utimes)72 ret = LIBC_NAMESPACE::syscall_impl<int>(UTIMES_SYSCALL_ID, AT_FDCWD, path,73 ts_ptr, 0);74 75#else76#error "utimes, utimensat, utimensat_time64, syscalls not available."77#endif // SYS_utimensat78 79 if (ret < 0) {80 libc_errno = -ret;81 return -1;82 }83 84 return 0;85}86} // namespace LIBC_NAMESPACE_DECL87