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-exception
6//
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
24#ifdef SYS_utimes
25constexpr auto UTIMES_SYSCALL_ID = SYS_utimes;
26#elif defined(SYS_utimensat)
27constexpr auto UTIMES_SYSCALL_ID = SYS_utimensat;
28#elif defined(SYS_utimensat_time64)
29constexpr auto UTIMES_SYSCALL_ID = SYS_utimensat_time64;
30#else
31#error "utimes, utimensat, utimensat_time64, syscalls not available."
32#endif
33
34LLVM_LIBC_FUNCTION(int, utimes,
35 (const char *path, const struct timeval times[2])) {
36 int ret;
37
38#ifdef SYS_utimes
39 // No need to define a timespec struct, use the syscall directly.
40 ret = LIBC_NAMESPACE::syscall_impl<int>(UTIMES_SYSCALL_ID, path, times);
41#elif defined(SYS_utimensat) || defined(SYS_utimensat_time64)
42 // the utimensat syscall requires a timespec struct, not timeval.
43 struct timespec ts[2];
44 struct timespec *ts_ptr = nullptr; // default value if times is nullptr
45
46 // convert the microsec values in timeval struct times
47 // to nanosecond values in timespec struct ts
48 if (times != nullptr) {
49
50 // ensure consistent values
51 if ((times[0].tv_usec < 0 || times[1].tv_usec < 0) ||
52 (times[0].tv_usec >= 1000000 || times[1].tv_usec >= 1000000)) {
53 libc_errno = EINVAL;
54 return -1;
55 }
56
57 // set seconds in ts
58 ts[0].tv_sec = times[0].tv_sec;
59 ts[1].tv_sec = times[1].tv_sec;
60
61 // convert u-seconds to nanoseconds
62 ts[0].tv_nsec = times[0].tv_usec * 1000;
63 ts[1].tv_nsec = times[1].tv_usec * 1000;
64
65 ts_ptr = ts;
66 }
67
68 // If times was nullptr, ts_ptr remains nullptr, which utimensat interprets
69 // as setting times to the current time.
70
71 // utimensat syscall.
72 // flags=0 means don't follow symlinks (like utimes)
73 ret = LIBC_NAMESPACE::syscall_impl<int>(UTIMES_SYSCALL_ID, AT_FDCWD, path,
74 ts_ptr, 0);
75#endif // SYS_utimensat
76
77 if (ret < 0) {
78 libc_errno = -ret;
79 return -1;
80 }
81
82 return 0;
83}
84} // namespace LIBC_NAMESPACE_DECL
85

source code of libc/src/sys/time/linux/utimes.cpp