(root)/
coreutils-9.4/
gnulib-tests/
test-futimens.h
       1  /* Test of file timestamp modification functions.
       2     Copyright (C) 2009-2023 Free Software Foundation, Inc.
       3  
       4     This program is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU General Public License as published by
       6     the Free Software Foundation, either version 3 of the License, or
       7     (at your option) any later version.
       8  
       9     This program is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU General Public License for more details.
      13  
      14     You should have received a copy of the GNU General Public License
      15     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  #include "test-utimens-common.h"
      18  
      19  /* This file is designed to test both fdutimens(a,NULL,b) and
      20     futimens(a,b).  FUNC is the function to test.  Assumes that BASE
      21     and ASSERT are already defined.  If PRINT, warn before skipping
      22     tests with status 77.  */
      23  static int
      24  test_futimens (int (*func) (int, struct timespec const *),
      25                 bool print)
      26  {
      27    int fd = creat (BASE "file", 0600);
      28    int result;
      29    struct stat st1;
      30    struct stat st2;
      31    ASSERT (0 <= fd);
      32  
      33    /* Sanity check.  */
      34    ASSERT (fstat (fd, &st1) == 0);
      35    nap ();
      36    errno = 0;
      37    result = func (fd, NULL);
      38    if (result == -1 && errno == ENOSYS)
      39      {
      40        ASSERT (close (fd) == 0);
      41        ASSERT (unlink (BASE "file") == 0);
      42        if (print)
      43          fputs ("skipping test: "
      44                 "setting fd time not supported on this file system\n",
      45                 stderr);
      46        return 77;
      47      }
      48    ASSERT (!result);
      49    ASSERT (fstat (fd, &st2) == 0);
      50    /* If utimens truncates to worse resolution than the file system
      51       supports, then time can appear to go backwards between now and a
      52       follow-up utimens with UTIME_NOW or a NULL timespec.  Use
      53       UTIMECMP_TRUNCATE_SOURCE to compensate, with st1 as the
      54       source.  */
      55    ASSERT (0 <= utimecmp (BASE "file", &st2, &st1, UTIMECMP_TRUNCATE_SOURCE));
      56    if (check_ctime)
      57      ASSERT (ctime_compare (&st1, &st2) < 0);
      58    {
      59      /* On some NFS systems, the 'now' timestamp of creat or a NULL
      60         timespec is determined by the server, but the 'now' timestamp
      61         determined by gettime() (as is done when using UTIME_NOW) is
      62         determined by the client; since the two machines are not
      63         necessarily on the same clock, this is another case where time
      64         can appear to go backwards.  The rest of this test cares about
      65         client time, so manually use gettime() to set both times.  */
      66      struct timespec ts[2];
      67      gettime (&ts[0]);
      68      ts[1] = ts[0];
      69      ASSERT (func (fd, ts) == 0);
      70      ASSERT (fstat (fd, &st1) == 0);
      71      nap ();
      72    }
      73  
      74    /* Invalid arguments.  */
      75    {
      76      errno = 0;
      77      ASSERT (func (AT_FDCWD, NULL) == -1);
      78      ASSERT (errno == EBADF);
      79    }
      80    {
      81      errno = 0;
      82      ASSERT (func (-1, NULL) == -1);
      83      ASSERT (errno == EBADF);
      84    }
      85    {
      86      close (99);
      87      errno = 0;
      88      ASSERT (func (99, NULL) == -1);
      89      ASSERT (errno == EBADF);
      90    }
      91    {
      92      int fd0 = dup (0);
      93      ASSERT (0 <= fd0);
      94      ASSERT (close (fd0) == 0);
      95      errno = 0;
      96      ASSERT (func (fd0, NULL) == -1);
      97      ASSERT (errno == EBADF);
      98    }
      99    {
     100      struct timespec ts[2];
     101      ts[0].tv_sec = Y2K;
     102      ts[0].tv_nsec = UTIME_BOGUS_POS;
     103      ts[1].tv_sec = Y2K;
     104      ts[1].tv_nsec = 0;
     105      errno = 0;
     106      ASSERT (func (fd, ts) == -1);
     107      ASSERT (errno == EINVAL);
     108    }
     109    {
     110      struct timespec ts[2];
     111      ts[0].tv_sec = Y2K;
     112      ts[0].tv_nsec = 0;
     113      ts[1].tv_sec = Y2K;
     114      ts[1].tv_nsec = UTIME_BOGUS_NEG;
     115      errno = 0;
     116      ASSERT (func (fd, ts) == -1);
     117      ASSERT (errno == EINVAL);
     118    }
     119    ASSERT (fstat (fd, &st2) == 0);
     120    ASSERT (st1.st_atime == st2.st_atime);
     121    ASSERT (get_stat_atime_ns (&st1) == get_stat_atime_ns (&st2));
     122    ASSERT (utimecmp (BASE "file", &st1, &st2, 0) == 0);
     123  
     124    /* Set both times.  */
     125    {
     126      struct timespec ts[2];
     127      ts[0].tv_sec = Y2K;
     128      ts[0].tv_nsec = BILLION / 2 - 1;
     129      ts[1].tv_sec = Y2K;
     130      ts[1].tv_nsec = BILLION - 1;
     131      ASSERT (func (fd, ts) == 0);
     132      ASSERT (fstat (fd, &st2) == 0);
     133      ASSERT (st2.st_atime == Y2K);
     134      ASSERT (0 <= get_stat_atime_ns (&st2));
     135      ASSERT (get_stat_atime_ns (&st2) < BILLION / 2);
     136      ASSERT (st2.st_mtime == Y2K);
     137      ASSERT (0 <= get_stat_mtime_ns (&st2));
     138      ASSERT (get_stat_mtime_ns (&st2) < BILLION);
     139      if (check_ctime)
     140        ASSERT (ctime_compare (&st1, &st2) < 0);
     141    }
     142  
     143    /* Play with UTIME_OMIT, UTIME_NOW.  */
     144    {
     145      struct stat st3;
     146      struct timespec ts[2];
     147      ts[0].tv_sec = BILLION;
     148      ts[0].tv_nsec = UTIME_OMIT;
     149      ts[1].tv_sec = 0;
     150      ts[1].tv_nsec = UTIME_NOW;
     151      nap ();
     152      ASSERT (func (fd, ts) == 0);
     153      ASSERT (fstat (fd, &st3) == 0);
     154      ASSERT (st3.st_atime == Y2K);
     155      ASSERT (0 <= get_stat_atime_ns (&st3));
     156      ASSERT (get_stat_atime_ns (&st3) <= BILLION / 2);
     157      ASSERT (utimecmp (BASE "file", &st1, &st3, UTIMECMP_TRUNCATE_SOURCE) <= 0);
     158      if (check_ctime)
     159        ASSERT (ctime_compare (&st2, &st3) < 0);
     160      nap ();
     161      ts[0].tv_nsec = 0;
     162      ts[1].tv_nsec = UTIME_OMIT;
     163      ASSERT (func (fd, ts) == 0);
     164      ASSERT (fstat (fd, &st2) == 0);
     165      ASSERT (st2.st_atime == BILLION);
     166      ASSERT (get_stat_atime_ns (&st2) == 0);
     167      ASSERT (st3.st_mtime == st2.st_mtime);
     168      ASSERT (get_stat_mtime_ns (&st3) == get_stat_mtime_ns (&st2));
     169      if (check_ctime > 0)
     170        ASSERT (ctime_compare (&st3, &st2) < 0);
     171    }
     172  
     173    /* Cleanup.  */
     174    ASSERT (close (fd) == 0);
     175    ASSERT (unlink (BASE "file") == 0);
     176    return 0;
     177  }