This source file includes following definitions.
- validate_timespec
- update_timespec
- fdutimens
- utimens
- lutimens
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 #include <config.h>
23
24 #define _GL_UTIMENS_INLINE _GL_EXTERN_INLINE
25 #include "utimens.h"
26
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <stdbool.h>
30 #include <string.h>
31 #include <sys/stat.h>
32 #include <sys/time.h>
33 #include <unistd.h>
34 #include <utime.h>
35
36 #include "stat-time.h"
37 #include "timespec.h"
38
39
40
41
42
43 #if defined _WIN32 && ! defined __CYGWIN__ && ! defined EMACS_CONFIGURATION
44 # define USE_SETFILETIME
45 # define WIN32_LEAN_AND_MEAN
46 # include <windows.h>
47 # if GNULIB_MSVC_NOTHROW
48 # include "msvc-nothrow.h"
49 # else
50 # include <io.h>
51 # endif
52 #endif
53
54
55 #undef futimens
56 #if !HAVE_NEARLY_WORKING_UTIMENSAT
57 # undef utimensat
58 #endif
59
60
61
62 #ifndef REPLACE_FUNC_STAT_FILE
63 # define REPLACE_FUNC_STAT_FILE 0
64 #endif
65
66 #if HAVE_UTIMENSAT || HAVE_FUTIMENS
67
68
69
70
71
72
73
74
75
76
77
78 static int utimensat_works_really;
79 static int lutimensat_works_really;
80 #endif
81
82
83
84
85
86
87
88
89 static int
90 validate_timespec (struct timespec timespec[2])
91 {
92 int result = 0;
93 int utime_omit_count = 0;
94 if ((timespec[0].tv_nsec != UTIME_NOW
95 && timespec[0].tv_nsec != UTIME_OMIT
96 && ! (0 <= timespec[0].tv_nsec
97 && timespec[0].tv_nsec < TIMESPEC_HZ))
98 || (timespec[1].tv_nsec != UTIME_NOW
99 && timespec[1].tv_nsec != UTIME_OMIT
100 && ! (0 <= timespec[1].tv_nsec
101 && timespec[1].tv_nsec < TIMESPEC_HZ)))
102 {
103 errno = EINVAL;
104 return -1;
105 }
106
107
108
109
110 if (timespec[0].tv_nsec == UTIME_NOW
111 || timespec[0].tv_nsec == UTIME_OMIT)
112 {
113 timespec[0].tv_sec = 0;
114 result = 1;
115 if (timespec[0].tv_nsec == UTIME_OMIT)
116 utime_omit_count++;
117 }
118 if (timespec[1].tv_nsec == UTIME_NOW
119 || timespec[1].tv_nsec == UTIME_OMIT)
120 {
121 timespec[1].tv_sec = 0;
122 result = 1;
123 if (timespec[1].tv_nsec == UTIME_OMIT)
124 utime_omit_count++;
125 }
126 return result + (utime_omit_count == 1);
127 }
128
129
130
131
132
133
134
135 static bool
136 update_timespec (struct stat const *statbuf, struct timespec **ts)
137 {
138 struct timespec *timespec = *ts;
139 if (timespec[0].tv_nsec == UTIME_OMIT
140 && timespec[1].tv_nsec == UTIME_OMIT)
141 return true;
142 if (timespec[0].tv_nsec == UTIME_NOW
143 && timespec[1].tv_nsec == UTIME_NOW)
144 {
145 *ts = NULL;
146 return false;
147 }
148
149 if (timespec[0].tv_nsec == UTIME_OMIT)
150 timespec[0] = get_stat_atime (statbuf);
151 else if (timespec[0].tv_nsec == UTIME_NOW)
152 gettime (×pec[0]);
153
154 if (timespec[1].tv_nsec == UTIME_OMIT)
155 timespec[1] = get_stat_mtime (statbuf);
156 else if (timespec[1].tv_nsec == UTIME_NOW)
157 gettime (×pec[1]);
158
159 return false;
160 }
161
162
163
164
165
166
167
168
169
170
171
172 int
173 fdutimens (int fd, char const *file, struct timespec const timespec[2])
174 {
175 struct timespec adjusted_timespec[2];
176 struct timespec *ts = timespec ? adjusted_timespec : NULL;
177 int adjustment_needed = 0;
178 struct stat st;
179
180 if (ts)
181 {
182 adjusted_timespec[0] = timespec[0];
183 adjusted_timespec[1] = timespec[1];
184 adjustment_needed = validate_timespec (ts);
185 }
186 if (adjustment_needed < 0)
187 return -1;
188
189
190
191
192 if (fd < 0 && !file)
193 {
194 errno = EBADF;
195 return -1;
196 }
197
198
199
200
201
202
203
204
205
206
207
208 #if HAVE_BUGGY_NFS_TIME_STAMPS
209 if (fd < 0)
210 sync ();
211 else
212 fsync (fd);
213 #endif
214
215
216
217
218
219
220 #if HAVE_UTIMENSAT || HAVE_FUTIMENS
221 if (0 <= utimensat_works_really)
222 {
223 int result;
224 # if __linux__ || __sun
225
226
227
228
229
230
231
232
233
234
235
236
237 if (adjustment_needed == 2)
238 {
239 if (fd < 0 ? stat (file, &st) : fstat (fd, &st))
240 return -1;
241 if (ts[0].tv_nsec == UTIME_OMIT)
242 ts[0] = get_stat_atime (&st);
243 else if (ts[1].tv_nsec == UTIME_OMIT)
244 ts[1] = get_stat_mtime (&st);
245
246 adjustment_needed++;
247 }
248 # endif
249 # if HAVE_UTIMENSAT
250 if (fd < 0)
251 {
252 # if defined __APPLE__ && defined __MACH__
253 size_t len = strlen (file);
254 if (len > 0 && file[len - 1] == '/')
255 {
256 struct stat statbuf;
257 if (stat (file, &statbuf) < 0)
258 return -1;
259 if (!S_ISDIR (statbuf.st_mode))
260 {
261 errno = ENOTDIR;
262 return -1;
263 }
264 }
265 # endif
266 result = utimensat (AT_FDCWD, file, ts, 0);
267 # ifdef __linux__
268
269
270
271
272
273
274
275 if (0 < result)
276 errno = ENOSYS;
277 # endif
278 if (result == 0 || errno != ENOSYS)
279 {
280 utimensat_works_really = 1;
281 return result;
282 }
283 }
284 # endif
285 # if HAVE_FUTIMENS
286 if (0 <= fd)
287 {
288 result = futimens (fd, ts);
289 # ifdef __linux__
290
291 if (0 < result)
292 errno = ENOSYS;
293 # endif
294 if (result == 0 || errno != ENOSYS)
295 {
296 utimensat_works_really = 1;
297 return result;
298 }
299 }
300 # endif
301 }
302 utimensat_works_really = -1;
303 lutimensat_works_really = -1;
304 #endif
305
306 #ifdef USE_SETFILETIME
307
308
309
310 if (0 <= fd)
311 {
312 HANDLE handle;
313 FILETIME current_time;
314 FILETIME last_access_time;
315 FILETIME last_write_time;
316
317 handle = (HANDLE) _get_osfhandle (fd);
318 if (handle == INVALID_HANDLE_VALUE)
319 {
320 errno = EBADF;
321 return -1;
322 }
323
324 if (ts == NULL || ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW)
325 {
326
327
328
329
330
331 GetSystemTimeAsFileTime (¤t_time);
332 }
333
334 if (ts == NULL || ts[0].tv_nsec == UTIME_NOW)
335 {
336 last_access_time = current_time;
337 }
338 else if (ts[0].tv_nsec == UTIME_OMIT)
339 {
340 last_access_time.dwLowDateTime = 0;
341 last_access_time.dwHighDateTime = 0;
342 }
343 else
344 {
345 ULONGLONG time_since_16010101 =
346 (ULONGLONG) ts[0].tv_sec * 10000000 + ts[0].tv_nsec / 100 + 116444736000000000LL;
347 last_access_time.dwLowDateTime = (DWORD) time_since_16010101;
348 last_access_time.dwHighDateTime = time_since_16010101 >> 32;
349 }
350
351 if (ts == NULL || ts[1].tv_nsec == UTIME_NOW)
352 {
353 last_write_time = current_time;
354 }
355 else if (ts[1].tv_nsec == UTIME_OMIT)
356 {
357 last_write_time.dwLowDateTime = 0;
358 last_write_time.dwHighDateTime = 0;
359 }
360 else
361 {
362 ULONGLONG time_since_16010101 =
363 (ULONGLONG) ts[1].tv_sec * 10000000 + ts[1].tv_nsec / 100 + 116444736000000000LL;
364 last_write_time.dwLowDateTime = (DWORD) time_since_16010101;
365 last_write_time.dwHighDateTime = time_since_16010101 >> 32;
366 }
367
368 if (SetFileTime (handle, NULL, &last_access_time, &last_write_time))
369 return 0;
370 else
371 {
372 DWORD sft_error = GetLastError ();
373 #if 0
374 fprintf (stderr, "fdutimens SetFileTime error 0x%x\n", (unsigned int) sft_error);
375 #endif
376 switch (sft_error)
377 {
378 case ERROR_ACCESS_DENIED:
379 errno = EACCES;
380 break;
381 default:
382 errno = EINVAL;
383 break;
384 }
385 return -1;
386 }
387 }
388 #endif
389
390
391
392
393
394 if (adjustment_needed || (REPLACE_FUNC_STAT_FILE && fd < 0))
395 {
396 if (adjustment_needed != 3
397 && (fd < 0 ? stat (file, &st) : fstat (fd, &st)))
398 return -1;
399 if (ts && update_timespec (&st, &ts))
400 return 0;
401 }
402
403 {
404 #if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES
405 struct timeval timeval[2];
406 struct timeval *t;
407 if (ts)
408 {
409 timeval[0].tv_sec = ts[0].tv_sec;
410 timeval[0].tv_usec = ts[0].tv_nsec / 1000;
411 timeval[1].tv_sec = ts[1].tv_sec;
412 timeval[1].tv_usec = ts[1].tv_nsec / 1000;
413 t = timeval;
414 }
415 else
416 t = NULL;
417
418 if (fd < 0)
419 {
420 # if HAVE_FUTIMESAT
421 return futimesat (AT_FDCWD, file, t);
422 # endif
423 }
424 else
425 {
426
427
428
429
430
431
432
433
434
435
436
437 # if (HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) || HAVE_FUTIMES
438 # if HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG
439 # undef futimes
440 # define futimes(fd, t) futimesat (fd, NULL, t)
441 # endif
442 if (futimes (fd, t) == 0)
443 {
444 # if __linux__ && __GLIBC__
445
446
447
448
449
450 if (t)
451 {
452 bool abig = 500000 <= t[0].tv_usec;
453 bool mbig = 500000 <= t[1].tv_usec;
454 if ((abig | mbig) && fstat (fd, &st) == 0)
455 {
456
457
458 time_t adiff = st.st_atime - t[0].tv_sec;
459 time_t mdiff = st.st_mtime - t[1].tv_sec;
460
461 struct timeval *tt = NULL;
462 struct timeval truncated_timeval[2];
463 truncated_timeval[0] = t[0];
464 truncated_timeval[1] = t[1];
465 if (abig && adiff == 1 && get_stat_atime_ns (&st) == 0)
466 {
467 tt = truncated_timeval;
468 tt[0].tv_usec = 0;
469 }
470 if (mbig && mdiff == 1 && get_stat_mtime_ns (&st) == 0)
471 {
472 tt = truncated_timeval;
473 tt[1].tv_usec = 0;
474 }
475 if (tt)
476 futimes (fd, tt);
477 }
478 }
479 # endif
480
481 return 0;
482 }
483 # endif
484 }
485 #endif
486
487 if (!file)
488 {
489 #if ! ((HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) \
490 || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
491 errno = ENOSYS;
492 #endif
493 return -1;
494 }
495
496 #ifdef USE_SETFILETIME
497 return _gl_utimens_windows (file, ts);
498 #elif HAVE_WORKING_UTIMES
499 return utimes (file, t);
500 #else
501 {
502 struct utimbuf utimbuf;
503 struct utimbuf *ut;
504 if (ts)
505 {
506 utimbuf.actime = ts[0].tv_sec;
507 utimbuf.modtime = ts[1].tv_sec;
508 ut = &utimbuf;
509 }
510 else
511 ut = NULL;
512
513 return utime (file, ut);
514 }
515 #endif
516 }
517 }
518
519
520
521 int
522 utimens (char const *file, struct timespec const timespec[2])
523 {
524 return fdutimens (-1, file, timespec);
525 }
526
527
528
529
530
531 int
532 lutimens (char const *file, struct timespec const timespec[2])
533 {
534 struct timespec adjusted_timespec[2];
535 struct timespec *ts = timespec ? adjusted_timespec : NULL;
536 int adjustment_needed = 0;
537 struct stat st;
538
539 if (ts)
540 {
541 adjusted_timespec[0] = timespec[0];
542 adjusted_timespec[1] = timespec[1];
543 adjustment_needed = validate_timespec (ts);
544 }
545 if (adjustment_needed < 0)
546 return -1;
547
548
549
550
551
552
553 #if HAVE_UTIMENSAT
554 if (0 <= lutimensat_works_really)
555 {
556 int result;
557 # if __linux__ || __sun
558
559
560
561
562
563
564
565
566
567
568
569
570 if (adjustment_needed == 2)
571 {
572 if (lstat (file, &st))
573 return -1;
574 if (ts[0].tv_nsec == UTIME_OMIT)
575 ts[0] = get_stat_atime (&st);
576 else if (ts[1].tv_nsec == UTIME_OMIT)
577 ts[1] = get_stat_mtime (&st);
578
579 adjustment_needed++;
580 }
581 # endif
582 result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW);
583 # ifdef __linux__
584
585
586
587
588
589
590
591 if (0 < result)
592 errno = ENOSYS;
593 # endif
594 if (result == 0 || errno != ENOSYS)
595 {
596 utimensat_works_really = 1;
597 lutimensat_works_really = 1;
598 return result;
599 }
600 }
601 lutimensat_works_really = -1;
602 #endif
603
604
605
606
607
608 if (adjustment_needed || REPLACE_FUNC_STAT_FILE)
609 {
610 if (adjustment_needed != 3 && lstat (file, &st))
611 return -1;
612 if (ts && update_timespec (&st, &ts))
613 return 0;
614 }
615
616
617
618 #if HAVE_LUTIMES && !HAVE_UTIMENSAT
619 {
620 struct timeval timeval[2];
621 struct timeval *t;
622 int result;
623 if (ts)
624 {
625 timeval[0].tv_sec = ts[0].tv_sec;
626 timeval[0].tv_usec = ts[0].tv_nsec / 1000;
627 timeval[1].tv_sec = ts[1].tv_sec;
628 timeval[1].tv_usec = ts[1].tv_nsec / 1000;
629 t = timeval;
630 }
631 else
632 t = NULL;
633
634 result = lutimes (file, t);
635 if (result == 0 || errno != ENOSYS)
636 return result;
637 }
638 #endif
639
640
641 if (!(adjustment_needed || REPLACE_FUNC_STAT_FILE) && lstat (file, &st))
642 return -1;
643 if (!S_ISLNK (st.st_mode))
644 return fdutimens (-1, file, ts);
645 errno = ENOSYS;
646 return -1;
647 }