1 | /* Helpers for utimes/utimens conversions. |
2 | Copyright (C) 2015-2022 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <errno.h> |
20 | #include <hurd/hurd_types.h> |
21 | #include <stddef.h> |
22 | #include <sys/time.h> |
23 | |
24 | /* Initializes atime/mtime timespec structures from an array of timeval. */ |
25 | static inline void |
26 | utime_ts_from_tval (const struct timeval tvp[2], |
27 | struct timespec *atime, struct timespec *mtime) |
28 | { |
29 | if (tvp == NULL) |
30 | { |
31 | /* Setting the number of nanoseconds to UTIME_NOW tells the |
32 | underlying filesystems to use the current time. */ |
33 | atime->tv_sec = 0; |
34 | atime->tv_nsec = UTIME_NOW; |
35 | mtime->tv_sec = 0; |
36 | mtime->tv_nsec = UTIME_NOW; |
37 | } |
38 | else |
39 | { |
40 | TIMEVAL_TO_TIMESPEC (&tvp[0], atime); |
41 | TIMEVAL_TO_TIMESPEC (&tvp[1], mtime); |
42 | } |
43 | } |
44 | |
45 | /* Initializes atime/mtime time_value_t structures from an array of timeval. */ |
46 | static inline void |
47 | utime_tvalue_from_tval (const struct timeval tvp[2], |
48 | time_value_t *atime, time_value_t *mtime) |
49 | { |
50 | if (tvp == NULL) |
51 | /* Setting the number of microseconds to `-1' tells the |
52 | underlying filesystems to use the current time. */ |
53 | atime->microseconds = mtime->microseconds = -1; |
54 | else |
55 | { |
56 | atime->seconds = tvp[0].tv_sec; |
57 | atime->microseconds = tvp[0].tv_usec; |
58 | mtime->seconds = tvp[1].tv_sec; |
59 | mtime->microseconds = tvp[1].tv_usec; |
60 | } |
61 | } |
62 | |
63 | /* Changes the access time of the file behind PORT using a timeval array. */ |
64 | static inline error_t |
65 | hurd_futimes (const file_t port, const struct timeval tvp[2]) |
66 | { |
67 | error_t err; |
68 | struct timespec atime, mtime; |
69 | |
70 | utime_ts_from_tval (tvp, atime: &atime, mtime: &mtime); |
71 | |
72 | err = __file_utimens (port, atime, mtime); |
73 | |
74 | if (err == MIG_BAD_ID || err == EOPNOTSUPP) |
75 | { |
76 | time_value_t atim, mtim; |
77 | |
78 | utime_tvalue_from_tval (tvp, &atim, &mtim); |
79 | |
80 | err = __file_utimes (port, atim, mtim); |
81 | } |
82 | |
83 | return err; |
84 | } |
85 | |
86 | /* Initializes atime/mtime timespec structures from an array of timespec. */ |
87 | static inline void |
88 | utime_ts_from_tspec (const struct timespec tsp[2], |
89 | struct timespec *atime, struct timespec *mtime) |
90 | { |
91 | if (tsp == NULL) |
92 | { |
93 | /* Setting the number of nanoseconds to UTIME_NOW tells the |
94 | underlying filesystems to use the current time. */ |
95 | atime->tv_sec = 0; |
96 | atime->tv_nsec = UTIME_NOW; |
97 | mtime->tv_sec = 0; |
98 | mtime->tv_nsec = UTIME_NOW; |
99 | } |
100 | else |
101 | { |
102 | *atime = tsp[0]; |
103 | *mtime = tsp[1]; |
104 | } |
105 | } |
106 | |
107 | /* Initializes atime/mtime time_value_t structures from an array of timespec. */ |
108 | static inline void |
109 | utime_tvalue_from_tspec (const struct timespec tsp[2], |
110 | time_value_t *atime, time_value_t *mtime) |
111 | { |
112 | if (tsp == NULL) |
113 | /* Setting the number of microseconds to `-1' tells the |
114 | underlying filesystems to use the current time. */ |
115 | atime->microseconds = mtime->microseconds = -1; |
116 | else |
117 | { |
118 | if (tsp[0].tv_nsec == UTIME_NOW) |
119 | atime->microseconds = -1; |
120 | else if (tsp[0].tv_nsec == UTIME_OMIT) |
121 | atime->microseconds = -2; |
122 | else |
123 | TIMESPEC_TO_TIME_VALUE (atime, &(tsp[0])); |
124 | if (tsp[1].tv_nsec == UTIME_NOW) |
125 | mtime->microseconds = -1; |
126 | else if (tsp[1].tv_nsec == UTIME_OMIT) |
127 | mtime->microseconds = -2; |
128 | else |
129 | TIMESPEC_TO_TIME_VALUE (mtime, &(tsp[1])); |
130 | } |
131 | } |
132 | |
133 | /* Changes the access time of the file behind PORT using a timespec array. */ |
134 | static inline error_t |
135 | hurd_futimens (const file_t port, const struct timespec tsp[2]) |
136 | { |
137 | error_t err; |
138 | struct timespec atime, mtime; |
139 | |
140 | utime_ts_from_tspec (tsp, atime: &atime, mtime: &mtime); |
141 | |
142 | err = __file_utimens (port, atime, mtime); |
143 | |
144 | if (err == MIG_BAD_ID || err == EOPNOTSUPP) |
145 | { |
146 | time_value_t atim, mtim; |
147 | |
148 | utime_tvalue_from_tspec (tsp, &atim, &mtim); |
149 | |
150 | err = __file_utimes (port, atim, mtim); |
151 | } |
152 | |
153 | return err; |
154 | } |
155 | |