]> Savannah Git Hosting - gnulib.git/commitdiff
test-utime: port to noatime file systems
authorPaul Eggert <eggert@cs.ucla.edu>
Fri, 9 Aug 2024 21:03:44 +0000 (14:03 -0700)
committerBruno Haible <bruno@clisp.org>
Mon, 12 Aug 2024 17:17:00 +0000 (19:17 +0200)
Problem encountered on Ubuntu 24.04 zfs mounted noatime.
* tests/test-fdutimensat.c (main):
* tests/test-futimens.h (test_futimens):
* tests/test-lutimens.h (test_lutimens):
* tests/test-utime.c (test_utime):
* tests/test-utimens-common.h (checkable_atime): New function.
* tests/test-utimens.h (test_utimens):
* tests/test-utimensat.c (main):
Do not check atime on file systems mounted noatime.

ChangeLog
doc/posix-functions/futimens.texi
doc/posix-functions/utimensat.texi
doc/posix-functions/utimes.texi
tests/test-fdutimensat.c
tests/test-futimens.h
tests/test-lutimens.h
tests/test-utime.c
tests/test-utimens-common.h
tests/test-utimens.h
tests/test-utimensat.c

index cc14fe592df8054f589040505cce9e6416d0b710..4ca2111a38154e96635888fb90209a227130f60f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2024-08-09  Paul Eggert  <eggert@cs.ucla.edu>
+
+       test-utime: port to noatime file systems
+       Problem encountered on Ubuntu 24.04 zfs mounted noatime.
+       * tests/test-fdutimensat.c (main):
+       * tests/test-futimens.h (test_futimens):
+       * tests/test-lutimens.h (test_lutimens):
+       * tests/test-utime.c (test_utime):
+       * tests/test-utimens-common.h (checkable_atime): New function.
+       * tests/test-utimens.h (test_utimens):
+       * tests/test-utimensat.c (main):
+       Do not check atime on file systems mounted noatime.
+
 2024-08-07  Bruno Haible  <bruno@clisp.org>
 
        Avoid compiler warnings in some configure tests.
index 84e6410b5ebbd73cc5ab8c39210ac9f9adaf9931..c4808308316785a92eda6330b572d015c965e075 100644 (file)
@@ -35,6 +35,10 @@ glibc 2.11, musl libc, Solaris 11.
 Portability problems not fixed by Gnulib:
 @itemize
 @item
+On file systems mounted with the @code{noatime} attribute,
+this function might not modify the access time as requested:
+Linux kernel 6.9.
+@item
 Some platforms lack the ability to change the timestamps of a file
 descriptor, so the replacement can fail with @code{ENOSYS}; the gnulib
 module @samp{utimens} provides a more reliable interface @code{fdutimens}.
index 147d8050fc811c7c785864bef6ea06c70a7625da..648144fdf8f0906b33735c6ca5e06bf07780b6d2 100644 (file)
@@ -44,6 +44,10 @@ AIX 7.2.
 Portability problems not fixed by Gnulib:
 @itemize
 @item
+On file systems mounted with the @code{noatime} attribute,
+this function might not modify the access time as requested:
+Linux kernel 6.9.
+@item
 On some platforms, timestamps of symbolic links cannot be modified, so
 the replacement fails with @code{ENOSYS} if passed the flag
 @code{AT_SYMLINK_NOFOLLOW} on a symlink.
index 13ceb9969036506eb7717f408967793c6a688e86..91304c48b8fef53bd422d697dacf041258e5dd62 100644 (file)
@@ -24,6 +24,10 @@ some platforms incorrectly round rather than truncate.  Use
 @code{utimensat(AT_FDCWD,file,times,0)}, or the gnulib module @code{utimens},
 instead.
 @item
+On file systems mounted with the @code{noatime} attribute,
+this function might not modify the access time as requested:
+Linux kernel 6.9.
+@item
 On some platforms, @code{utimes (file, NULL)} fails to set the
 file's timestamp to the current time:
 glibc 2.3.3.
index 56a7b49e0a040853efccd3c7d081a843cdc1226a..82e46aabda65525ac2e17a161be37097c1bb31f3 100644 (file)
@@ -118,7 +118,7 @@ main (void)
   /* Directory relative tests.  */
   ASSERT (mkdir (BASE "dir", 0700) == 0);
   ASSERT (chdir (BASE "dir") == 0);
-  fd = creat ("file", 0600);
+  fd = open ("file", O_RDWR | O_CREAT | O_TRUNC, 0600);
   ASSERT (0 <= fd);
   errno = 0;
   ASSERT (fdutimensat (AT_FDCWD, fd, ".", NULL, 0) == -1);
@@ -126,13 +126,17 @@ main (void)
   {
     struct timespec ts[2];
     struct stat st;
+    bool check_atime = checkable_atime (fd, &st);
     ts[0].tv_sec = Y2K;
     ts[0].tv_nsec = 0;
     ts[1] = ts[0];
     ASSERT (fdutimensat (fd, dfd, BASE "dir/file", ts, 0) == 0);
     ASSERT (stat ("file", &st) == 0);
-    ASSERT (st.st_atime == Y2K);
-    ASSERT (get_stat_atime_ns (&st) == 0);
+    if (check_atime)
+      {
+        ASSERT (st.st_atime == Y2K);
+        ASSERT (get_stat_atime_ns (&st) == 0);
+      }
     ASSERT (st.st_mtime == Y2K);
     ASSERT (get_stat_mtime_ns (&st) == 0);
   }
index a6fd5c15cf114b45161c311702144591df031764..af8f630cc935ea47b9eb328808c8f472c5610c09 100644 (file)
@@ -24,14 +24,14 @@ static int
 test_futimens (int (*func) (int, struct timespec const *),
                bool print)
 {
-  int fd = creat (BASE "file", 0600);
+  int fd = open (BASE "file", O_RDWR | O_CREAT | O_TRUNC, 0600);
   int result;
   struct stat st1;
   struct stat st2;
   ASSERT (0 <= fd);
+  bool check_atime = checkable_atime (fd, &st1);
 
   /* Sanity check.  */
-  ASSERT (fstat (fd, &st1) == 0);
   nap ();
   errno = 0;
   result = func (fd, NULL);
@@ -117,8 +117,11 @@ test_futimens (int (*func) (int, struct timespec const *),
     ASSERT (errno == EINVAL);
   }
   ASSERT (fstat (fd, &st2) == 0);
-  ASSERT (st1.st_atime == st2.st_atime);
-  ASSERT (get_stat_atime_ns (&st1) == get_stat_atime_ns (&st2));
+  if (check_atime)
+    {
+      ASSERT (st1.st_atime == st2.st_atime);
+      ASSERT (get_stat_atime_ns (&st1) == get_stat_atime_ns (&st2));
+    }
   ASSERT (utimecmp (BASE "file", &st1, &st2, 0) == 0);
 
   /* Set both times.  */
@@ -130,9 +133,12 @@ test_futimens (int (*func) (int, struct timespec const *),
     ts[1].tv_nsec = BILLION - 1;
     ASSERT (func (fd, ts) == 0);
     ASSERT (fstat (fd, &st2) == 0);
-    ASSERT (st2.st_atime == Y2K);
-    ASSERT (0 <= get_stat_atime_ns (&st2));
-    ASSERT (get_stat_atime_ns (&st2) < BILLION / 2);
+    if (check_atime)
+      {
+        ASSERT (st2.st_atime == Y2K);
+        ASSERT (0 <= get_stat_atime_ns (&st2));
+        ASSERT (get_stat_atime_ns (&st2) < BILLION / 2);
+      }
     ASSERT (st2.st_mtime == Y2K);
     ASSERT (0 <= get_stat_mtime_ns (&st2));
     ASSERT (get_stat_mtime_ns (&st2) < BILLION);
@@ -151,9 +157,12 @@ test_futimens (int (*func) (int, struct timespec const *),
     nap ();
     ASSERT (func (fd, ts) == 0);
     ASSERT (fstat (fd, &st3) == 0);
-    ASSERT (st3.st_atime == Y2K);
-    ASSERT (0 <= get_stat_atime_ns (&st3));
-    ASSERT (get_stat_atime_ns (&st3) <= BILLION / 2);
+    if (check_atime)
+      {
+        ASSERT (st3.st_atime == Y2K);
+        ASSERT (0 <= get_stat_atime_ns (&st3));
+        ASSERT (get_stat_atime_ns (&st3) <= BILLION / 2);
+      }
     ASSERT (utimecmp (BASE "file", &st1, &st3, UTIMECMP_TRUNCATE_SOURCE) <= 0);
     if (check_ctime)
       ASSERT (ctime_compare (&st2, &st3) < 0);
@@ -162,8 +171,11 @@ test_futimens (int (*func) (int, struct timespec const *),
     ts[1].tv_nsec = UTIME_OMIT;
     ASSERT (func (fd, ts) == 0);
     ASSERT (fstat (fd, &st2) == 0);
-    ASSERT (st2.st_atime == BILLION);
-    ASSERT (get_stat_atime_ns (&st2) == 0);
+    if (check_atime)
+      {
+        ASSERT (st2.st_atime == BILLION);
+        ASSERT (get_stat_atime_ns (&st2) == 0);
+      }
     ASSERT (st3.st_mtime == st2.st_mtime);
     ASSERT (get_stat_mtime_ns (&st3) == get_stat_mtime_ns (&st2));
     if (check_ctime > 0)
index 385b3c0acc43c912929b5f4b0bc76e8dcd55f2b1..b909ec4b7537068278c3bd39cdac2556d5a04daa 100644 (file)
@@ -27,7 +27,6 @@ test_lutimens (int (*func) (char const *, struct timespec const *), bool print)
   int saved_errno;
   struct stat st1;
   struct stat st2;
-  bool atime_supported = true;
 
   /* Non-symlinks should be handled just like utimens.  */
   errno = 0;
@@ -39,10 +38,15 @@ test_lutimens (int (*func) (char const *, struct timespec const *), bool print)
   errno = 0;
   ASSERT (func ("", NULL) == -1);
   ASSERT (errno == ENOENT);
-  ASSERT (close (creat (BASE "file", 0600)) == 0);
-  ASSERT (stat (BASE "file", &st1) == 0);
+
+  int fd = open (BASE "file", O_RDWR | O_CREAT | O_TRUNC, 0600);
+  ASSERT (0 <= fd);
+
+  bool check_atime = checkable_atime (fd, &st1);
+  ASSERT (close (fd) == 0);
   ASSERT (st1.st_atime != Y2K);
   ASSERT (st1.st_mtime != Y2K);
+
   {
     struct timespec ts[2];
     ts[0].tv_sec = Y2K;
@@ -52,7 +56,8 @@ test_lutimens (int (*func) (char const *, struct timespec const *), bool print)
     ASSERT (func (BASE "file/", ts) == -1);
     ASSERT (errno == ENOTDIR);
     ASSERT (stat (BASE "file", &st2) == 0);
-    ASSERT (st1.st_atime == st2.st_atime);
+    if (check_atime)
+      ASSERT (st1.st_atime == st2.st_atime);
     ASSERT (st1.st_mtime == st2.st_mtime);
   }
   {
@@ -64,7 +69,8 @@ test_lutimens (int (*func) (char const *, struct timespec const *), bool print)
     ASSERT (func (BASE "file", ts) == 0);
   }
   ASSERT (stat (BASE "file", &st2) == 0);
-  ASSERT (st2.st_atime == Y2K);
+  if (check_atime)
+    ASSERT (st2.st_atime == Y2K);
   ASSERT (st2.st_mtime == Y2K);
   if (check_ctime)
     ASSERT (ctime_compare (&st1, &st2) < 0);
@@ -83,10 +89,12 @@ test_lutimens (int (*func) (char const *, struct timespec const *), bool print)
   saved_errno = errno;
   /* Make sure we did not reference through link by accident.  */
   ASSERT (stat (BASE "file", &st1) == 0);
-  ASSERT (st1.st_atime == Y2K);
+  if (check_atime)
+    ASSERT (st1.st_atime == Y2K);
   ASSERT (st1.st_mtime == Y2K);
   ASSERT (lstat (BASE "link", &st1) == 0);
-  ASSERT (st1.st_atime != Y2K);
+  if (check_atime)
+    ASSERT (st1.st_atime != Y2K);
   ASSERT (st1.st_mtime != Y2K);
   ASSERT (unlink (BASE "file") == 0);
   if (result == -1 && saved_errno == ENOSYS)
@@ -100,13 +108,16 @@ test_lutimens (int (*func) (char const *, struct timespec const *), bool print)
     }
   ASSERT (!result);
   ASSERT (lstat (BASE "link", &st1) == 0);
-  /* On cygwin, lstat() changes atime of symlinks, so that lutimens
-     can only effectively modify mtime.  */
   nap ();
   ASSERT (lstat (BASE "link", &st2) == 0);
-  if (st1.st_atime != st2.st_atime
-      || get_stat_atime_ns (&st1) != get_stat_atime_ns (&st2))
-    atime_supported = false;
+
+  /* On cygwin, lstat() changes atime of symlinks, so that lutimens
+     can effectively modify only mtime.  */
+  bool check_atime_on_symlinks
+    = (check_atime
+       && st1.st_atime == st2.st_atime
+       && get_stat_atime_ns (&st1) == get_stat_atime_ns (&st2));
+
   ASSERT (st1.st_ctime == st2.st_ctime);
   ASSERT (get_stat_ctime_ns (&st1) == get_stat_ctime_ns (&st2));
 
@@ -132,7 +143,7 @@ test_lutimens (int (*func) (char const *, struct timespec const *), bool print)
     ASSERT (errno == EINVAL);
   }
   ASSERT (lstat (BASE "link", &st2) == 0);
-  if (atime_supported)
+  if (check_atime_on_symlinks)
     {
       ASSERT (st1.st_atime == st2.st_atime);
       ASSERT (get_stat_atime_ns (&st1) == get_stat_atime_ns (&st2));
@@ -149,7 +160,7 @@ test_lutimens (int (*func) (char const *, struct timespec const *), bool print)
     nap ();
     ASSERT (func (BASE "link", ts) == 0);
     ASSERT (lstat (BASE "link", &st2) == 0);
-    if (atime_supported)
+    if (check_atime_on_symlinks)
       {
         ASSERT (st2.st_atime == Y2K);
         ASSERT (0 <= get_stat_atime_ns (&st2));
@@ -173,7 +184,7 @@ test_lutimens (int (*func) (char const *, struct timespec const *), bool print)
     nap ();
     ASSERT (func (BASE "link", ts) == 0);
     ASSERT (lstat (BASE "link", &st3) == 0);
-    if (atime_supported)
+    if (check_atime_on_symlinks)
       {
         ASSERT (st3.st_atime == Y2K);
         ASSERT (0 <= get_stat_atime_ns (&st3));
@@ -187,7 +198,7 @@ test_lutimens (int (*func) (char const *, struct timespec const *), bool print)
     ts[1].tv_nsec = UTIME_OMIT;
     ASSERT (func (BASE "link", ts) == 0);
     ASSERT (lstat (BASE "link", &st2) == 0);
-    if (atime_supported)
+    if (check_atime_on_symlinks)
       {
         ASSERT (st2.st_atime == BILLION);
         ASSERT (get_stat_atime_ns (&st2) == 0);
@@ -214,13 +225,15 @@ test_lutimens (int (*func) (char const *, struct timespec const *), bool print)
   ASSERT (stat (BASE "dir", &st1) == 0);
   ASSERT (st1.st_mtime == Y2K);
   ASSERT (lstat (BASE "link", &st1) == 0);
-  ASSERT (st1.st_atime != Y2K);
+  if (check_atime)
+    ASSERT (st1.st_atime != Y2K);
   ASSERT (st1.st_mtime != Y2K);
   ASSERT (func (BASE "link", NULL) == 0);
   ASSERT (stat (BASE "dir", &st1) == 0);
   ASSERT (st1.st_mtime == Y2K);
   ASSERT (lstat (BASE "link", &st1) == 0);
-  ASSERT (st1.st_atime != Y2K);
+  if (check_atime)
+    ASSERT (st1.st_atime != Y2K);
   ASSERT (st1.st_mtime != Y2K);
 
   /* Cleanup.  */
index 5e228d334bd4fc6460eb0a9c8e87ea6d87ab1376..f0ce08bf3c349ff11929bcabc413e1ac71121c3d 100644 (file)
@@ -35,8 +35,11 @@ test_utime (bool print)
   struct stat st1;
   struct stat st2;
 
-  ASSERT (close (creat (BASE "file", 0600)) == 0);
-  ASSERT (stat (BASE "file", &st1) == 0);
+  int fd = open (BASE "file", O_RDWR | O_CREAT | O_TRUNC, 0600);
+  ASSERT (0 <= fd);
+  bool check_atime = checkable_atime (fd, &st1);
+  ASSERT (close (fd) == 0);
+
   nap ();
   ASSERT (utime (BASE "file", NULL) == 0);
   ASSERT (stat (BASE "file", &st2) == 0);
@@ -76,8 +79,11 @@ test_utime (bool print)
     ASSERT (errno == ENOTDIR || errno == EINVAL);
   }
   ASSERT (stat (BASE "file", &st2) == 0);
-  ASSERT (st1.st_atime == st2.st_atime);
-  ASSERT (get_stat_atime_ns (&st1) == get_stat_atime_ns (&st2));
+  if (check_atime)
+    {
+      ASSERT (st1.st_atime == st2.st_atime);
+      ASSERT (get_stat_atime_ns (&st1) == get_stat_atime_ns (&st2));
+    }
   ASSERT (utimecmp (BASE "file", &st1, &st2, 0) == 0);
 
   /* Set both times.  */
@@ -86,9 +92,12 @@ test_utime (bool print)
     ts.actime = ts.modtime = Y2K;
     ASSERT (utime (BASE "file", &ts) == 0);
     ASSERT (stat (BASE "file", &st2) == 0);
-    ASSERT (st2.st_atime == Y2K);
-    ASSERT (0 <= get_stat_atime_ns (&st2));
-    ASSERT (get_stat_atime_ns (&st2) < BILLION / 2);
+    if (check_atime)
+      {
+        ASSERT (st2.st_atime == Y2K);
+        ASSERT (0 <= get_stat_atime_ns (&st2));
+        ASSERT (get_stat_atime_ns (&st2) < BILLION / 2);
+      }
     ASSERT (st2.st_mtime == Y2K);
     ASSERT (0 <= get_stat_mtime_ns (&st2));
     ASSERT (get_stat_mtime_ns (&st2) < BILLION);
@@ -115,7 +124,9 @@ test_utime (bool print)
     ts.actime = ts.modtime = Y2K;
     ASSERT (utime (BASE "link", &ts) == 0);
     ASSERT (lstat (BASE "link", &st2) == 0);
-    /* Can't compare atimes, since lstat() changes symlink atime on cygwin.  */
+    /* Make sure symlink time hasn't been modified.
+       Can't compare symlink atimes, since when utime follows the
+       symlink it might update the symlink atime.  */
     ASSERT (st1.st_mtime == st2.st_mtime);
     ASSERT (stat (BASE "link", &st2) == 0);
     ASSERT (st2.st_mtime == Y2K);
index 317a01b3dad5c4d598c30da1adc2b4cb3796e555..f9fdb9a86787a99449828451ff7b8ab3566432c6 100644 (file)
@@ -79,4 +79,25 @@ ctime_compare (struct stat const *a, struct stat const *b)
     return 0;
 }
 
+/* Test whether FD's file access times are updated by the file system.
+   FD must be readable.  Set *ST to the file's status, after any
+   change to its access time due to the test.  */
+static bool
+checkable_atime (int fd, struct stat *st)
+{
+  char buf[1];
+  struct stat st1, st2;
+
+  ASSERT (fstat (fd, &st1) == 0);
+  nap ();
+  ASSERT (read (fd, buf, sizeof buf) == 0);
+  ASSERT (fstat (fd, &st2) == 0);
+  bool check_atime
+    = (st1.st_atime != st2.st_atime
+       || get_stat_atime_ns (&st1) != get_stat_atime_ns (&st2));
+  if (st)
+    *st = st2;
+  return check_atime;
+}
+
 #endif /* GL_TEST_UTIMENS_COMMON */
index 83d785a4dd8a29f43bf53141b8bdfdc32975962c..575507f735ce73e971e270fabdfd2b2887544932 100644 (file)
@@ -26,13 +26,18 @@ test_utimens (int (*func) (char const *, struct timespec const *), bool print)
   struct stat st1;
   struct stat st2;
 
-  ASSERT (close (creat (BASE "file", 0600)) == 0);
+  int fd = open (BASE "file", O_RDWR | O_CREAT | O_TRUNC, 0600);
+  ASSERT (0 <= fd);
   /* If utimens truncates to worse resolution than the file system
      supports, then time can appear to go backwards between now and a
      follow-up utimens with UTIME_NOW or a NULL timespec.  Use
      UTIMECMP_TRUNCATE_SOURCE to compensate, with st1 as the
      source.  */
-  ASSERT (stat (BASE "file", &st1) == 0);
+  bool check_atime = checkable_atime (fd, &st1);
+  ASSERT (close (fd) == 0);
+  ASSERT (st1.st_atime != Y2K);
+  ASSERT (st1.st_mtime != Y2K);
+
   nap ();
   ASSERT (func (BASE "file", NULL) == 0);
   ASSERT (stat (BASE "file", &st2) == 0);
@@ -108,9 +113,12 @@ test_utimens (int (*func) (char const *, struct timespec const *), bool print)
     ts[1].tv_nsec = BILLION - 1;
     ASSERT (func (BASE "file", ts) == 0);
     ASSERT (stat (BASE "file", &st2) == 0);
-    ASSERT (st2.st_atime == Y2K);
-    ASSERT (0 <= get_stat_atime_ns (&st2));
-    ASSERT (get_stat_atime_ns (&st2) < BILLION / 2);
+    if (check_atime)
+      {
+        ASSERT (st2.st_atime == Y2K);
+        ASSERT (0 <= get_stat_atime_ns (&st2));
+        ASSERT (get_stat_atime_ns (&st2) < BILLION / 2);
+      }
     ASSERT (st2.st_mtime == Y2K);
     ASSERT (0 <= get_stat_mtime_ns (&st2));
     ASSERT (get_stat_mtime_ns (&st2) < BILLION);
@@ -129,9 +137,12 @@ test_utimens (int (*func) (char const *, struct timespec const *), bool print)
     nap ();
     ASSERT (func (BASE "file", ts) == 0);
     ASSERT (stat (BASE "file", &st3) == 0);
-    ASSERT (st3.st_atime == Y2K);
-    ASSERT (0 <= get_stat_atime_ns (&st3));
-    ASSERT (get_stat_atime_ns (&st3) < BILLION / 2);
+    if (check_atime)
+      {
+        ASSERT (st3.st_atime == Y2K);
+        ASSERT (0 <= get_stat_atime_ns (&st3));
+        ASSERT (get_stat_atime_ns (&st3) < BILLION / 2);
+      }
     /* See comment above about this utimecmp call.  */
     ASSERT (0 <= utimecmp (BASE "file", &st3, &st1, UTIMECMP_TRUNCATE_SOURCE));
     if (check_ctime)
@@ -141,8 +152,11 @@ test_utimens (int (*func) (char const *, struct timespec const *), bool print)
     ts[1].tv_nsec = UTIME_OMIT;
     ASSERT (func (BASE "file", ts) == 0);
     ASSERT (stat (BASE "file", &st2) == 0);
-    ASSERT (st2.st_atime == BILLION);
-    ASSERT (get_stat_atime_ns (&st2) == 0);
+    if (check_atime)
+      {
+        ASSERT (st2.st_atime == BILLION);
+        ASSERT (get_stat_atime_ns (&st2) == 0);
+      }
     ASSERT (st3.st_mtime == st2.st_mtime);
     ASSERT (get_stat_mtime_ns (&st3) == get_stat_mtime_ns (&st2));
     if (check_ctime > 0)
@@ -170,9 +184,19 @@ test_utimens (int (*func) (char const *, struct timespec const *), bool print)
     ts[1] = ts[0];
     ASSERT (func (BASE "link", ts) == 0);
     ASSERT (lstat (BASE "link", &st2) == 0);
-    /* Can't compare atimes, since lstat() changes symlink atime on cygwin.  */
+
+    /* Make sure symlink time hasn't been modified.
+       Can't compare symlink atimes, since when func follows the
+       symlink it might update the symlink atime.  */
     ASSERT (st1.st_mtime == st2.st_mtime);
+    ASSERT (get_stat_mtime_ns (&st1) == get_stat_mtime_ns (&st2));
+
     ASSERT (stat (BASE "link", &st2) == 0);
+    if (check_atime)
+      {
+        ASSERT (st2.st_atime == Y2K);
+        ASSERT (get_stat_atime_ns (&st2) == 0);
+      }
     ASSERT (st2.st_mtime == Y2K);
     ASSERT (get_stat_mtime_ns (&st2) == 0);
   }
index c248d6a3471fbac78081a83d2ddfdfc03e2ac36a..64c44e55ed096458da7839b5ff132a995ac80981 100644 (file)
@@ -94,8 +94,11 @@ main (void)
   /* Directory-relative tests.  */
   ASSERT (mkdir (BASE "dir", 0700) == 0);
   ASSERT (chdir (BASE "dir") == 0);
-  fd = creat ("file", 0600);
+  fd = open ("file", O_RDWR | O_CREAT | O_TRUNC, 0600);
   ASSERT (0 <= fd);
+
+  bool check_atime = checkable_atime (fd, NULL);
+
   errno = 0;
   ASSERT (utimensat (fd, ".", NULL, 0) == -1);
   ASSERT (errno == ENOTDIR);
@@ -108,8 +111,11 @@ main (void)
     ts[1].tv_nsec = 0;
     ASSERT (utimensat (dfd, BASE "dir/file", ts, AT_SYMLINK_NOFOLLOW) == 0);
     ASSERT (stat ("file", &st) == 0);
-    ASSERT (st.st_atime == Y2K);
-    ASSERT (get_stat_atime_ns (&st) == 0);
+    if (check_atime)
+      {
+        ASSERT (st.st_atime == Y2K);
+        ASSERT (get_stat_atime_ns (&st) == 0);
+      }
     ASSERT (st.st_mtime == Y2K);
     ASSERT (get_stat_mtime_ns (&st) == 0);
   }