This source file includes following definitions.
- dev_info_hash
- dev_info_compare
- utimecmp
- utimecmpat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 #include <config.h>
21
22 #include "utimecmp.h"
23
24 #include <fcntl.h>
25 #include <limits.h>
26 #include <stdbool.h>
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include <sys/stat.h>
30 #include <time.h>
31 #include <unistd.h>
32
33 #include "dirname.h"
34 #include "hash.h"
35 #include "intprops.h"
36 #include "stat-time.h"
37 #include "verify.h"
38
39 #ifndef MAX
40 # define MAX(a, b) ((a) > (b) ? (a) : (b))
41 #endif
42
43 #define BILLION (1000 * 1000 * 1000)
44
45
46
47
48 #if HAVE_UTIMENSAT
49 enum { SYSCALL_RESOLUTION = 1 };
50 #elif defined _WIN32 && ! defined __CYGWIN__
51
52
53 enum { SYSCALL_RESOLUTION = 100 };
54 #elif ((HAVE_FUTIMESAT || HAVE_WORKING_UTIMES) \
55 && (defined HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC \
56 || defined HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC \
57 || defined HAVE_STRUCT_STAT_ST_ATIMENSEC \
58 || defined HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC \
59 || defined HAVE_STRUCT_STAT_ST_SPARE1))
60 enum { SYSCALL_RESOLUTION = 1000 };
61 #else
62 enum { SYSCALL_RESOLUTION = BILLION };
63 #endif
64
65
66 struct fs_res
67 {
68
69 dev_t dev;
70
71
72
73
74
75
76 int resolution;
77
78
79
80 bool exact;
81 };
82
83
84 static size_t
85 dev_info_hash (void const *x, size_t table_size)
86 {
87 struct fs_res const *p = x;
88
89
90 if (TYPE_SIGNED (dev_t) && SIZE_MAX < MAX (INT_MAX, TYPE_MAXIMUM (dev_t)))
91 {
92 uintmax_t dev = p->dev;
93 return dev % table_size;
94 }
95
96 return p->dev % table_size;
97 }
98
99
100 static bool
101 dev_info_compare (void const *x, void const *y)
102 {
103 struct fs_res const *a = x;
104 struct fs_res const *b = y;
105 return a->dev == b->dev;
106 }
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122 int
123 utimecmp (char const *dst_name,
124 struct stat const *dst_stat,
125 struct stat const *src_stat,
126 int options)
127 {
128 return utimecmpat (AT_FDCWD, dst_name, dst_stat, src_stat, options);
129 }
130
131 int
132 utimecmpat (int dfd, char const *dst_name,
133 struct stat const *dst_stat,
134 struct stat const *src_stat,
135 int options)
136 {
137
138
139
140
141
142
143
144
145
146
147
148
149
150 verify (TYPE_IS_INTEGER (time_t));
151
152
153 time_t dst_s = dst_stat->st_mtime;
154 time_t src_s = src_stat->st_mtime;
155 int dst_ns = get_stat_mtime_ns (dst_stat);
156 int src_ns = get_stat_mtime_ns (src_stat);
157
158 if (options & UTIMECMP_TRUNCATE_SOURCE)
159 {
160 #if defined _AIX
161
162
163
164 long long difference =
165 ((long long) dst_s - (long long) src_s) * BILLION
166 + ((long long) dst_ns - (long long) src_ns);
167 if (difference < 10000000 && difference > -10000000)
168 return 0;
169 #endif
170
171
172
173
174 static Hash_table *ht;
175
176
177 static struct fs_res *new_dst_res;
178 struct fs_res *dst_res = NULL;
179 struct fs_res tmp_dst_res;
180
181
182 int res;
183
184
185
186
187 if (dst_s == src_s && dst_ns == src_ns)
188 return 0;
189 if (dst_s <= src_s - 2)
190 return -1;
191 if (src_s <= dst_s - 2)
192 return 1;
193
194
195
196 if (! ht)
197 ht = hash_initialize (16, NULL, dev_info_hash, dev_info_compare, free);
198 if (ht)
199 {
200 if (! new_dst_res)
201 {
202 new_dst_res = malloc (sizeof *new_dst_res);
203 if (!new_dst_res)
204 goto low_memory;
205 new_dst_res->resolution = 2 * BILLION;
206 new_dst_res->exact = false;
207 }
208 new_dst_res->dev = dst_stat->st_dev;
209 dst_res = hash_insert (ht, new_dst_res);
210 if (! dst_res)
211 goto low_memory;
212
213 if (dst_res == new_dst_res)
214 {
215
216
217 new_dst_res = NULL;
218 }
219 }
220 else
221 {
222 low_memory:
223 if (ht)
224 {
225 tmp_dst_res.dev = dst_stat->st_dev;
226 dst_res = hash_lookup (ht, &tmp_dst_res);
227 }
228 if (!dst_res)
229 {
230 dst_res = &tmp_dst_res;
231 dst_res->resolution = 2 * BILLION;
232 dst_res->exact = false;
233 }
234 }
235
236 res = dst_res->resolution;
237
238 #ifdef _PC_TIMESTAMP_RESOLUTION
239
240 if (! dst_res->exact)
241 {
242 res = -1;
243 if (dfd == AT_FDCWD)
244 res = pathconf (dst_name, _PC_TIMESTAMP_RESOLUTION);
245 else
246 {
247 char *dstdir = mdir_name (dst_name);
248 if (dstdir)
249 {
250 int destdirfd = openat (dfd, dstdir,
251 O_SEARCH | O_CLOEXEC | O_DIRECTORY);
252 if (0 <= destdirfd)
253 {
254 res = fpathconf (destdirfd, _PC_TIMESTAMP_RESOLUTION);
255 close (destdirfd);
256 }
257 free (dstdir);
258 }
259 }
260 if (0 < res)
261 {
262 dst_res->resolution = res;
263 dst_res->exact = true;
264 }
265 }
266 #endif
267
268 if (! dst_res->exact)
269 {
270
271
272
273 time_t dst_a_s = dst_stat->st_atime;
274 time_t dst_c_s = dst_stat->st_ctime;
275 time_t dst_m_s = dst_s;
276 int dst_a_ns = get_stat_atime_ns (dst_stat);
277 int dst_c_ns = get_stat_ctime_ns (dst_stat);
278 int dst_m_ns = dst_ns;
279
280
281
282
283
284
285
286 {
287 bool odd_second = (dst_a_s | dst_c_s | dst_m_s) & 1;
288
289 if (SYSCALL_RESOLUTION == BILLION)
290 {
291 if (odd_second | dst_a_ns | dst_c_ns | dst_m_ns)
292 res = BILLION;
293 }
294 else
295 {
296 int a = dst_a_ns;
297 int c = dst_c_ns;
298 int m = dst_m_ns;
299
300
301
302 int SR10 = SYSCALL_RESOLUTION; SR10 *= 10;
303
304 if ((a % SR10 | c % SR10 | m % SR10) != 0)
305 res = SYSCALL_RESOLUTION;
306 else
307 for (res = SR10, a /= SR10, c /= SR10, m /= SR10;
308 (res < dst_res->resolution
309 && (a % 10 | c % 10 | m % 10) == 0);
310 res *= 10, a /= 10, c /= 10, m /= 10)
311 if (res == BILLION)
312 {
313 if (! odd_second)
314 res *= 2;
315 break;
316 }
317 }
318
319 dst_res->resolution = res;
320 }
321
322 if (SYSCALL_RESOLUTION < res)
323 {
324 struct timespec timespec[2];
325 struct stat dst_status;
326
327
328
329 src_ns -= src_ns % SYSCALL_RESOLUTION;
330
331
332
333
334 {
335 time_t s = src_s & ~ (res == 2 * BILLION ? 1 : 0);
336 if (src_s < dst_s || (src_s == dst_s && src_ns <= dst_ns))
337 return 1;
338 if (dst_s < s
339 || (dst_s == s && dst_ns < src_ns - src_ns % res))
340 return -1;
341 }
342
343
344
345
346
347
348
349 timespec[0].tv_sec = dst_a_s;
350 timespec[0].tv_nsec = dst_a_ns;
351 timespec[1].tv_sec = dst_m_s | (res == 2 * BILLION);
352 timespec[1].tv_nsec = dst_m_ns + res / 9;
353
354 if (utimensat (dfd, dst_name, timespec, AT_SYMLINK_NOFOLLOW))
355 return -2;
356
357
358 {
359 int stat_result
360 = fstatat (dfd, dst_name, &dst_status, AT_SYMLINK_NOFOLLOW);
361
362 if (stat_result
363 | (dst_status.st_mtime ^ dst_m_s)
364 | (get_stat_mtime_ns (&dst_status) ^ dst_m_ns))
365 {
366
367
368 timespec[1].tv_sec = dst_m_s;
369 timespec[1].tv_nsec = dst_m_ns;
370 utimensat (dfd, dst_name, timespec, AT_SYMLINK_NOFOLLOW);
371 }
372
373 if (stat_result != 0)
374 return -2;
375 }
376
377
378
379 {
380 int old_res = res;
381 int a = (BILLION * (dst_status.st_mtime & 1)
382 + get_stat_mtime_ns (&dst_status));
383
384 res = SYSCALL_RESOLUTION;
385
386 for (a /= res; a % 10 == 0; a /= 10)
387 {
388 if (res == BILLION)
389 {
390 res *= 2;
391 break;
392 }
393 res *= 10;
394 if (res == old_res)
395 break;
396 }
397 }
398 }
399
400 dst_res->resolution = res;
401 dst_res->exact = true;
402 }
403
404
405 src_s &= ~ (res == 2 * BILLION ? 1 : 0);
406 src_ns -= src_ns % res;
407 }
408
409
410 return (_GL_CMP (dst_s, src_s)
411 + ((dst_s == src_s ? ~0 : 0) & _GL_CMP (dst_ns, src_ns)));
412 }