(root)/
coreutils-9.4/
gnulib-tests/
test-lutimens.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 lutimens(a,b) and
      20     utimensat(AT_FDCWD,a,b,AT_SYMLINK_NOFOLLOW).  FUNC is the function
      21     to test.  Assumes that BASE and ASSERT are already defined.  If
      22     PRINT, warn before skipping tests with status 77.  */
      23  static int
      24  test_lutimens (int (*func) (char const *, struct timespec const *), bool print)
      25  {
      26    int result;
      27    int saved_errno;
      28    struct stat st1;
      29    struct stat st2;
      30    bool atime_supported = true;
      31  
      32    /* Non-symlinks should be handled just like utimens.  */
      33    errno = 0;
      34    ASSERT (func ("no_such", NULL) == -1);
      35    ASSERT (errno == ENOENT);
      36    errno = 0;
      37    ASSERT (func ("no_such/", NULL) == -1);
      38    ASSERT (errno == ENOENT || errno == ENOTDIR);
      39    errno = 0;
      40    ASSERT (func ("", NULL) == -1);
      41    ASSERT (errno == ENOENT);
      42    ASSERT (close (creat (BASE "file", 0600)) == 0);
      43    ASSERT (stat (BASE "file", &st1) == 0);
      44    ASSERT (st1.st_atime != Y2K);
      45    ASSERT (st1.st_mtime != Y2K);
      46    {
      47      struct timespec ts[2];
      48      ts[0].tv_sec = Y2K;
      49      ts[0].tv_nsec = 0;
      50      ts[1] = ts[0];
      51      errno = 0;
      52      ASSERT (func (BASE "file/", ts) == -1);
      53      ASSERT (errno == ENOTDIR);
      54      ASSERT (stat (BASE "file", &st2) == 0);
      55      ASSERT (st1.st_atime == st2.st_atime);
      56      ASSERT (st1.st_mtime == st2.st_mtime);
      57    }
      58    {
      59      struct timespec ts[2];
      60      ts[0].tv_sec = Y2K;
      61      ts[0].tv_nsec = 0;
      62      ts[1] = ts[0];
      63      nap ();
      64      ASSERT (func (BASE "file", ts) == 0);
      65    }
      66    ASSERT (stat (BASE "file", &st2) == 0);
      67    ASSERT (st2.st_atime == Y2K);
      68    ASSERT (st2.st_mtime == Y2K);
      69    if (check_ctime)
      70      ASSERT (ctime_compare (&st1, &st2) < 0);
      71  
      72    /* Play with symlink timestamps.  */
      73    if (symlink (BASE "file", BASE "link"))
      74      {
      75        ASSERT (unlink (BASE "file") == 0);
      76        if (print)
      77          fputs ("skipping test: symlinks not supported on this file system\n",
      78                 stderr);
      79        return 77;
      80      }
      81    errno = 0;
      82    result = func (BASE "link", NULL);
      83    saved_errno = errno;
      84    /* Make sure we did not reference through link by accident.  */
      85    ASSERT (stat (BASE "file", &st1) == 0);
      86    ASSERT (st1.st_atime == Y2K);
      87    ASSERT (st1.st_mtime == Y2K);
      88    ASSERT (lstat (BASE "link", &st1) == 0);
      89    ASSERT (st1.st_atime != Y2K);
      90    ASSERT (st1.st_mtime != Y2K);
      91    ASSERT (unlink (BASE "file") == 0);
      92    if (result == -1 && saved_errno == ENOSYS)
      93      {
      94        ASSERT (unlink (BASE "link") == 0);
      95        if (print)
      96          fputs ("skipping test: "
      97                 "setting symlink time not supported on this file system\n",
      98                 stderr);
      99        return 77;
     100      }
     101    ASSERT (!result);
     102    ASSERT (lstat (BASE "link", &st1) == 0);
     103    /* On cygwin, lstat() changes atime of symlinks, so that lutimens
     104       can only effectively modify mtime.  */
     105    nap ();
     106    ASSERT (lstat (BASE "link", &st2) == 0);
     107    if (st1.st_atime != st2.st_atime
     108        || get_stat_atime_ns (&st1) != get_stat_atime_ns (&st2))
     109      atime_supported = false;
     110    ASSERT (st1.st_ctime == st2.st_ctime);
     111    ASSERT (get_stat_ctime_ns (&st1) == get_stat_ctime_ns (&st2));
     112  
     113    /* Invalid arguments.  */
     114    {
     115      struct timespec ts[2];
     116      ts[0].tv_sec = Y2K;
     117      ts[0].tv_nsec = UTIME_BOGUS_POS;
     118      ts[1].tv_sec = Y2K;
     119      ts[1].tv_nsec = 0;
     120      errno = 0;
     121      ASSERT (func (BASE "link", ts) == -1);
     122      ASSERT (errno == EINVAL);
     123    }
     124    {
     125      struct timespec ts[2];
     126      ts[0].tv_sec = Y2K;
     127      ts[0].tv_nsec = 0;
     128      ts[1].tv_sec = Y2K;
     129      ts[1].tv_nsec = UTIME_BOGUS_NEG;
     130      errno = 0;
     131      ASSERT (func (BASE "link", ts) == -1);
     132      ASSERT (errno == EINVAL);
     133    }
     134    ASSERT (lstat (BASE "link", &st2) == 0);
     135    if (atime_supported)
     136      {
     137        ASSERT (st1.st_atime == st2.st_atime);
     138        ASSERT (get_stat_atime_ns (&st1) == get_stat_atime_ns (&st2));
     139      }
     140    ASSERT (utimecmp (BASE "link", &st1, &st2, 0) == 0);
     141  
     142    /* Set both times.  */
     143    {
     144      struct timespec ts[2];
     145      ts[0].tv_sec = Y2K;
     146      ts[0].tv_nsec = BILLION / 2 - 1;
     147      ts[1].tv_sec = Y2K;
     148      ts[1].tv_nsec = BILLION - 1;
     149      nap ();
     150      ASSERT (func (BASE "link", ts) == 0);
     151      ASSERT (lstat (BASE "link", &st2) == 0);
     152      if (atime_supported)
     153        {
     154          ASSERT (st2.st_atime == Y2K);
     155          ASSERT (0 <= get_stat_atime_ns (&st2));
     156          ASSERT (get_stat_atime_ns (&st2) < BILLION / 2);
     157        }
     158      ASSERT (st2.st_mtime == Y2K);
     159      ASSERT (0 <= get_stat_mtime_ns (&st2));
     160      ASSERT (get_stat_mtime_ns (&st2) < BILLION);
     161      if (check_ctime)
     162        ASSERT (ctime_compare (&st1, &st2) < 0);
     163    }
     164  
     165    /* Play with UTIME_OMIT, UTIME_NOW.  */
     166    {
     167      struct stat st3;
     168      struct timespec ts[2];
     169      ts[0].tv_sec = BILLION;
     170      ts[0].tv_nsec = UTIME_OMIT;
     171      ts[1].tv_sec = 0;
     172      ts[1].tv_nsec = UTIME_NOW;
     173      nap ();
     174      ASSERT (func (BASE "link", ts) == 0);
     175      ASSERT (lstat (BASE "link", &st3) == 0);
     176      if (atime_supported)
     177        {
     178          ASSERT (st3.st_atime == Y2K);
     179          ASSERT (0 <= get_stat_atime_ns (&st3));
     180          ASSERT (get_stat_atime_ns (&st3) < BILLION / 2);
     181        }
     182      ASSERT (utimecmp (BASE "link", &st1, &st3, 0) <= 0);
     183      if (check_ctime)
     184        ASSERT (ctime_compare (&st2, &st3) < 0);
     185      nap ();
     186      ts[0].tv_nsec = 0;
     187      ts[1].tv_nsec = UTIME_OMIT;
     188      ASSERT (func (BASE "link", ts) == 0);
     189      ASSERT (lstat (BASE "link", &st2) == 0);
     190      if (atime_supported)
     191        {
     192          ASSERT (st2.st_atime == BILLION);
     193          ASSERT (get_stat_atime_ns (&st2) == 0);
     194        }
     195      ASSERT (st3.st_mtime == st2.st_mtime);
     196      ASSERT (get_stat_mtime_ns (&st3) == get_stat_mtime_ns (&st2));
     197      if (check_ctime > 0)
     198        ASSERT (ctime_compare (&st3, &st2) < 0);
     199    }
     200  
     201    /* Symlink to directory.  */
     202    ASSERT (unlink (BASE "link") == 0);
     203    ASSERT (symlink (BASE "dir", BASE "link") == 0);
     204    ASSERT (mkdir (BASE "dir", 0700) == 0);
     205    {
     206      struct timespec ts[2];
     207      ts[0].tv_sec = Y2K;
     208      ts[0].tv_nsec = 0;
     209      ts[1] = ts[0];
     210      ASSERT (func (BASE "link/", ts) == 0);
     211    }
     212    /* On cygwin 1.5, stat() changes atime of directories, so only check
     213       mtime.  */
     214    ASSERT (stat (BASE "dir", &st1) == 0);
     215    ASSERT (st1.st_mtime == Y2K);
     216    ASSERT (lstat (BASE "link", &st1) == 0);
     217    ASSERT (st1.st_atime != Y2K);
     218    ASSERT (st1.st_mtime != Y2K);
     219    ASSERT (func (BASE "link", NULL) == 0);
     220    ASSERT (stat (BASE "dir", &st1) == 0);
     221    ASSERT (st1.st_mtime == Y2K);
     222    ASSERT (lstat (BASE "link", &st1) == 0);
     223    ASSERT (st1.st_atime != Y2K);
     224    ASSERT (st1.st_mtime != Y2K);
     225  
     226    /* Cleanup.  */
     227    ASSERT (rmdir (BASE "dir") == 0);
     228    ASSERT (unlink (BASE "link") == 0);
     229    return 0;
     230  }