Jim Meyering wrote: ... > Note however, that test-utimens is failing for me > on an ext4 + Fedora-12-alpha-based system due to this: > > /* See comment above about this utimecmp call. */ > ASSERT (0 <= utimecmp (BASE "file", &st2, &st1, > UTIMECMP_TRUNCATE_SOURCE)); > > That utimecmp assertion fails almost all the time due to the > comparison of two time stamps independently down-sampled > at different resolutions. > > It wasn't clear right away to me, so I wrote a program to > call clock_gettime, then utimensat-to-set-to-NOW, then stat. > Compare the clock_gettime result with st_mtime second and nanosecond values. > > I see ~1-millisecond-resolution FS timestamps > and higher-resolution clock_gettime times: > > d.ns: stat.ns - now.ns > > ds d.ns stat.ns now.ns (now.ns[i] - now.ns[i-1]) > ========================================== > 0 -579637 510150007 510729644 (0) > 0 -656640 510150007 510806647 (77003) > 0 -716861 510150007 510866868 (60221) > 0 -776398 510150007 510926405 (59537) > 0 -835731 510150007 510985738 (59333) > 0 -934985 510150007 511084992 (99254) > 0 3891 !!! 511150073 511146182 (61190) > 0 -55913 511150073 511205986 (59804) > 0 -115589 511150073 511265662 (59676) > 0 -175220 511150073 511325293 (59631) > 0 -234472 511150073 511384545 (59252) > 0 -293974 511150073 511444047 (59502) > 0 -353255 511150073 511503328 (59281) > 0 -412612 511150073 511562685 (59357) > 0 -472069 511150073 511622142 (59457) > 0 -531468 511150073 511681541 (59399) > 0 -591027 511150073 511741100 (59559) > 0 -650239 511150073 511800312 (59212) > 0 -709527 511150073 511859600 (59288) > 0 -769023 511150073 511919096 (59496) > 0 -828184 511150073 511978257 (59161) > 0 -899541 511150073 512049614 (71357) > 0 -959895 511150073 512109968 (60354) > 0 -19442 512150046 512169488 (59520) > 0 -78649 512150046 512228695 (59207) > 0 -138054 512150046 512288100 (59405) > 0 -197514 512150046 512347560 (59460) > 0 -256642 512150046 512406688 (59128) > 0 -315945 512150046 512465991 (59303) > 0 -375208 512150046 512525254 (59263) > 0 -434469 512150046 512584515 (59261) > 0 -493769 512150046 512643815 (59300) > 0 -553978 512150046 512704024 (60209) > 0 -613284 512150046 512763330 (59306) > 0 -672490 512150046 512822536 (59206) > 0 -731724 512150046 512881770 (59234) > 0 -790961 512150046 512941007 (59237) > 0 -850143 512150046 513000189 (59182) > 0 -920239 512150046 513070285 (70096) > 0 20804 !!! 513150503 513129699 (59414) > 0 -39840 513150503 513190343 (60644) > 0 -99067 513150503 513249570 (59227) > 0 -158482 513150503 513308985 (59415) > 0 -217610 513150503 513368113 (59128) > ... > > This failure may also be due to the way utimecmp works, > but I haven't delved into that code today.
FYI, here's the program I used to print the above table: #define _GNU_SOURCE 1 #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/stat.h> #include <sys/time.h> #include <time.h> #include <fcntl.h> #define BASE "test-utimens.t" #define ASSERT(expr) \ do \ { \ if (!(expr)) \ { \ fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \ fflush (stderr); \ abort (); \ } \ } \ while (0) #define func(a,b) utimensat(AT_FDCWD,a,b,0) int main (int argc, char **argv) { if (argc < 2) abort (); int signed_n = atoi (argv[1]); if (signed_n < 0) abort (); unsigned int n = signed_n; ASSERT (close (creat (BASE "file", 0600)) == 0); unsigned long prev_now_ns = 0; printf ("ds %8s %3s %12s %11s\n", "d.ns", "", "stat.ns", "now.ns"); printf ("==========================================\n"); unsigned int i; for (i = 0; i < n; i++) { struct stat st3; struct timespec ts[2] = { {0, UTIME_OMIT}, {0, UTIME_NOW} }; struct timespec now; clock_gettime (CLOCK_REALTIME, &now); ASSERT (func (BASE "file", ts) == 0); ASSERT (stat (BASE "file", &st3) == 0); long s_diff = st3.st_mtime - now.tv_sec; long ns_diff = st3.st_mtim.tv_nsec - now.tv_nsec; long delta_now = (i == 0 ? 0 : now.tv_nsec - prev_now_ns); printf ("%ld %8ld %3s %12ld %12ld (%ld)\n", s_diff, ns_diff, s_diff || 0 < ns_diff ? "!!!" : "", st3.st_mtim.tv_nsec, now.tv_nsec, delta_now); prev_now_ns = now.tv_nsec; } /* Cleanup. */ ASSERT (unlink (BASE "file") == 0); return 0; } ------------------------------------------------------ I compiled and ran it like this: gcc -W -Wall -Wformat -Wextra utimens.c -lrt && ./a.out 100 Note: not intended to be portable.