root/maint/gnulib/tests/test-stat-time.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. initialize_filenames
  2. force_unlink
  3. cleanup
  4. open_file
  5. create_file
  6. do_stat
  7. prepare_test
  8. test_mtime
  9. test_ctime
  10. test_birthtime
  11. main

   1 /* Test of <stat-time.h>.
   2    Copyright (C) 2007-2021 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 /* Written by James Youngman <jay@gnu.org>, 2007.  */
  18 
  19 #include <config.h>
  20 
  21 #include "stat-time.h"
  22 
  23 #include <fcntl.h>
  24 #include <signal.h>
  25 #include <stdio.h>
  26 #include <sys/stat.h>
  27 #include <unistd.h>
  28 #include <time.h>
  29 
  30 #include "macros.h"
  31 
  32 #define BASE "test-stat-time.t"
  33 #include "nap.h"
  34 
  35 enum { NFILES = 4 };
  36 
  37 static char filename_stamp1[50];
  38 static char filename_testfile[50];
  39 static char filename_stamp2[50];
  40 static char filename_stamp3[50];
  41 
  42 /* Use file names that are different at each run.
  43    This is necessary for test_birthtime() to pass on native Windows:
  44    On this platform, the file system apparently remembers the creation time
  45    of a file even after it is removed and created anew.  See
  46    "Windows NT Contains File System Tunneling Capabilities"
  47    <https://support.microsoft.com/en-us/help/172190/>  */
  48 static void
  49 initialize_filenames (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  50 {
  51   long t = (long) time (NULL);
  52   sprintf (filename_stamp1,   "t-stt-%ld-stamp1", t);
  53   sprintf (filename_testfile, "t-stt-%ld-testfile", t);
  54   sprintf (filename_stamp2,   "t-stt-%ld-stamp2", t);
  55   sprintf (filename_stamp3,   "t-stt-%ld-stamp3", t);
  56 }
  57 
  58 static int
  59 force_unlink (const char *filename)
     /* [previous][next][first][last][top][bottom][index][help] */
  60 {
  61   /* This chmod is necessary on mingw, where unlink() of a read-only file
  62      fails with EPERM.  */
  63   chmod (filename, 0600);
  64   return unlink (filename);
  65 }
  66 
  67 static void
  68 cleanup (int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
  69 {
  70   /* Remove temporary files.  */
  71   force_unlink (filename_stamp1);
  72   force_unlink (filename_testfile);
  73   force_unlink (filename_stamp2);
  74   force_unlink (filename_stamp3);
  75 
  76   if (sig != 0)
  77     _exit (1);
  78 }
  79 
  80 static int
  81 open_file (const char *filename, int flags)
     /* [previous][next][first][last][top][bottom][index][help] */
  82 {
  83   int fd = open (filename, flags | O_WRONLY, 0500);
  84   if (fd >= 0)
  85     {
  86       close (fd);
  87       return 1;
  88     }
  89   else
  90     {
  91       return 0;
  92     }
  93 }
  94 
  95 static void
  96 create_file (const char *filename)
     /* [previous][next][first][last][top][bottom][index][help] */
  97 {
  98   ASSERT (open_file (filename, O_CREAT | O_EXCL));
  99 }
 100 
 101 static void
 102 do_stat (const char *filename, struct stat *p)
     /* [previous][next][first][last][top][bottom][index][help] */
 103 {
 104   ASSERT (stat (filename, p) == 0);
 105 }
 106 
 107 static void
 108 prepare_test (struct stat *statinfo, struct timespec *modtimes)
     /* [previous][next][first][last][top][bottom][index][help] */
 109 {
 110   int i;
 111 
 112   create_file (filename_stamp1);
 113   nap ();
 114   create_file (filename_testfile);
 115   nap ();
 116   create_file (filename_stamp2);
 117   nap ();
 118   ASSERT (chmod (filename_testfile, 0400) == 0);
 119   nap ();
 120   create_file (filename_stamp3);
 121 
 122   do_stat (filename_stamp1,   &statinfo[0]);
 123   do_stat (filename_testfile, &statinfo[1]);
 124   do_stat (filename_stamp2,   &statinfo[2]);
 125   do_stat (filename_stamp3,   &statinfo[3]);
 126 
 127   /* Now use our access functions. */
 128   for (i = 0; i < NFILES; ++i)
 129     {
 130       modtimes[i] = get_stat_mtime (&statinfo[i]);
 131     }
 132 }
 133 
 134 static void
 135 test_mtime (const struct stat *statinfo, struct timespec *modtimes)
     /* [previous][next][first][last][top][bottom][index][help] */
 136 {
 137   int i;
 138 
 139   /* Use the struct stat fields directly. */
 140   /* mtime(stamp1) < mtime(stamp2) */
 141   ASSERT (statinfo[0].st_mtime < statinfo[2].st_mtime
 142           || (statinfo[0].st_mtime == statinfo[2].st_mtime
 143               && (get_stat_mtime_ns (&statinfo[0])
 144                   < get_stat_mtime_ns (&statinfo[2]))));
 145   /* mtime(stamp2) < mtime(stamp3) */
 146   ASSERT (statinfo[2].st_mtime < statinfo[3].st_mtime
 147           || (statinfo[2].st_mtime == statinfo[3].st_mtime
 148               && (get_stat_mtime_ns (&statinfo[2])
 149                   < get_stat_mtime_ns (&statinfo[3]))));
 150 
 151   /* Now check the result of the access functions. */
 152   /* mtime(stamp1) < mtime(stamp2) */
 153   ASSERT (modtimes[0].tv_sec < modtimes[2].tv_sec
 154           || (modtimes[0].tv_sec == modtimes[2].tv_sec
 155               && modtimes[0].tv_nsec < modtimes[2].tv_nsec));
 156   /* mtime(stamp2) < mtime(stamp3) */
 157   ASSERT (modtimes[2].tv_sec < modtimes[3].tv_sec
 158           || (modtimes[2].tv_sec == modtimes[3].tv_sec
 159               && modtimes[2].tv_nsec < modtimes[3].tv_nsec));
 160 
 161   /* verify equivalence */
 162   for (i = 0; i < NFILES; ++i)
 163     {
 164       struct timespec ts;
 165       ts = get_stat_mtime (&statinfo[i]);
 166       ASSERT (ts.tv_sec == statinfo[i].st_mtime);
 167     }
 168 }
 169 
 170 #if defined _WIN32 && !defined __CYGWIN__
 171 /* Skip the ctime tests on native Windows platforms, because their
 172    st_ctime is either the same as st_mtime (plus or minus an offset)
 173    or set to the file _creation_ time, and is not influenced by rename
 174    or chmod.  */
 175 # define test_ctime(ignored) ((void) 0)
 176 #else
 177 static void
 178 test_ctime (const struct stat *statinfo)
     /* [previous][next][first][last][top][bottom][index][help] */
 179 {
 180   /* On some buggy NFS clients, mtime and ctime are disproportionately
 181      skewed from one another.  Skip this test in that case.  */
 182   if (statinfo[0].st_mtime != statinfo[0].st_ctime)
 183     return;
 184 
 185   /* mtime(stamp2) < ctime(testfile) */
 186   ASSERT (statinfo[2].st_mtime < statinfo[1].st_ctime
 187           || (statinfo[2].st_mtime == statinfo[1].st_ctime
 188               && (get_stat_mtime_ns (&statinfo[2])
 189                   < get_stat_ctime_ns (&statinfo[1]))));
 190 }
 191 #endif
 192 
 193 static void
 194 test_birthtime (const struct stat *statinfo,
     /* [previous][next][first][last][top][bottom][index][help] */
 195                 const struct timespec *modtimes,
 196                 struct timespec *birthtimes)
 197 {
 198   int i;
 199 
 200   /* Collect the birth times.  */
 201   for (i = 0; i < NFILES; ++i)
 202     {
 203       birthtimes[i] = get_stat_birthtime (&statinfo[i]);
 204       if (birthtimes[i].tv_nsec < 0)
 205         return;
 206     }
 207 
 208   /* mtime(stamp1) < birthtime(testfile) */
 209   ASSERT (modtimes[0].tv_sec < birthtimes[1].tv_sec
 210           || (modtimes[0].tv_sec == birthtimes[1].tv_sec
 211               && modtimes[0].tv_nsec < birthtimes[1].tv_nsec));
 212   /* birthtime(testfile) < mtime(stamp2) */
 213   ASSERT (birthtimes[1].tv_sec < modtimes[2].tv_sec
 214           || (birthtimes[1].tv_sec == modtimes[2].tv_sec
 215               && birthtimes[1].tv_nsec < modtimes[2].tv_nsec));
 216 }
 217 
 218 int
 219 main (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 220 {
 221   struct stat statinfo[NFILES];
 222   struct timespec modtimes[NFILES];
 223   struct timespec birthtimes[NFILES];
 224 
 225   initialize_filenames ();
 226 
 227 #ifdef SIGHUP
 228   signal (SIGHUP, cleanup);
 229 #endif
 230 #ifdef SIGINT
 231   signal (SIGINT, cleanup);
 232 #endif
 233 #ifdef SIGQUIT
 234   signal (SIGQUIT, cleanup);
 235 #endif
 236 #ifdef SIGTERM
 237   signal (SIGTERM, cleanup);
 238 #endif
 239 
 240   cleanup (0);
 241   prepare_test (statinfo, modtimes);
 242   test_mtime (statinfo, modtimes);
 243   test_ctime (statinfo);
 244   test_birthtime (statinfo, modtimes, birthtimes);
 245 
 246   cleanup (0);
 247   return 0;
 248 }

/* [previous][next][first][last][top][bottom][index][help] */