1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
//===-- 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 <sys/syscall.h>
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<int>(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<decltype(ts[0].tv_nsec)>(times[0].tv_usec * 1000);
ts[1].tv_nsec =
static_cast<decltype(ts[1].tv_nsec)>(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<int>(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
|