Blame gnulib-tests/test-stat-time.c

Packit Service fdd496
/* Test of <stat-time.h>.
Packit Service fdd496
   Copyright (C) 2007-2017 Free Software Foundation, Inc.
Packit Service fdd496
Packit Service fdd496
   This program is free software: you can redistribute it and/or modify
Packit Service fdd496
   it under the terms of the GNU General Public License as published by
Packit Service fdd496
   the Free Software Foundation; either version 3 of the License, or
Packit Service fdd496
   (at your option) any later version.
Packit Service fdd496
Packit Service fdd496
   This program is distributed in the hope that it will be useful,
Packit Service fdd496
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service fdd496
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service fdd496
   GNU General Public License for more details.
Packit Service fdd496
Packit Service fdd496
   You should have received a copy of the GNU General Public License
Packit Service fdd496
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Service fdd496
Packit Service fdd496
/* Written by James Youngman <jay@gnu.org>, 2007.  */
Packit Service fdd496
Packit Service fdd496
#include <config.h>
Packit Service fdd496
Packit Service fdd496
#include "stat-time.h"
Packit Service fdd496
Packit Service fdd496
#include <fcntl.h>
Packit Service fdd496
#include <signal.h>
Packit Service fdd496
#include <stdio.h>
Packit Service fdd496
#include <sys/stat.h>
Packit Service fdd496
#include <unistd.h>
Packit Service fdd496
#include <time.h>
Packit Service fdd496
Packit Service fdd496
#include "macros.h"
Packit Service fdd496
Packit Service fdd496
#define BASE "test-stat-time.t"
Packit Service fdd496
#include "nap.h"
Packit Service fdd496
Packit Service fdd496
enum { NFILES = 4 };
Packit Service fdd496
Packit Service fdd496
static char filename_stamp1[50];
Packit Service fdd496
static char filename_testfile[50];
Packit Service fdd496
static char filename_stamp2[50];
Packit Service fdd496
static char filename_stamp3[50];
Packit Service fdd496
Packit Service fdd496
/* Use file names that are different at each run.
Packit Service fdd496
   This is necessary for test_birthtime() to pass on native Windows:
Packit Service fdd496
   On this platform, the file system apparently remembers the creation time
Packit Service fdd496
   of a file even after it is removed and created anew.  See
Packit Service fdd496
   "Windows NT Contains File System Tunneling Capabilities"
Packit Service fdd496
   <https://support.microsoft.com/en-us/help/172190/>  */
Packit Service fdd496
static void
Packit Service fdd496
initialize_filenames (void)
Packit Service fdd496
{
Packit Service fdd496
  long t = (long) time (NULL);
Packit Service fdd496
  sprintf (filename_stamp1,   "t-stt-%ld-stamp1", t);
Packit Service fdd496
  sprintf (filename_testfile, "t-stt-%ld-testfile", t);
Packit Service fdd496
  sprintf (filename_stamp2,   "t-stt-%ld-stamp2", t);
Packit Service fdd496
  sprintf (filename_stamp3,   "t-stt-%ld-stamp3", t);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static int
Packit Service fdd496
force_unlink (const char *filename)
Packit Service fdd496
{
Packit Service fdd496
  /* This chmod is necessary on mingw, where unlink() of a read-only file
Packit Service fdd496
     fails with EPERM.  */
Packit Service fdd496
  chmod (filename, 0600);
Packit Service fdd496
  return unlink (filename);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
cleanup (int sig)
Packit Service fdd496
{
Packit Service fdd496
  /* Remove temporary files.  */
Packit Service fdd496
  force_unlink (filename_stamp1);
Packit Service fdd496
  force_unlink (filename_testfile);
Packit Service fdd496
  force_unlink (filename_stamp2);
Packit Service fdd496
  force_unlink (filename_stamp3);
Packit Service fdd496
Packit Service fdd496
  if (sig != 0)
Packit Service fdd496
    _exit (1);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static int
Packit Service fdd496
open_file (const char *filename, int flags)
Packit Service fdd496
{
Packit Service fdd496
  int fd = open (filename, flags | O_WRONLY, 0500);
Packit Service fdd496
  if (fd >= 0)
Packit Service fdd496
    {
Packit Service fdd496
      close (fd);
Packit Service fdd496
      return 1;
Packit Service fdd496
    }
Packit Service fdd496
  else
Packit Service fdd496
    {
Packit Service fdd496
      return 0;
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
create_file (const char *filename)
Packit Service fdd496
{
Packit Service fdd496
  ASSERT (open_file (filename, O_CREAT | O_EXCL));
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
do_stat (const char *filename, struct stat *p)
Packit Service fdd496
{
Packit Service fdd496
  ASSERT (stat (filename, p) == 0);
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
prepare_test (struct stat *statinfo, struct timespec *modtimes)
Packit Service fdd496
{
Packit Service fdd496
  int i;
Packit Service fdd496
Packit Service fdd496
  create_file (filename_stamp1);
Packit Service fdd496
  nap ();
Packit Service fdd496
  create_file (filename_testfile);
Packit Service fdd496
  nap ();
Packit Service fdd496
  create_file (filename_stamp2);
Packit Service fdd496
  nap ();
Packit Service fdd496
  ASSERT (chmod (filename_testfile, 0400) == 0);
Packit Service fdd496
  nap ();
Packit Service fdd496
  create_file (filename_stamp3);
Packit Service fdd496
Packit Service fdd496
  do_stat (filename_stamp1,   &statinfo[0]);
Packit Service fdd496
  do_stat (filename_testfile, &statinfo[1]);
Packit Service fdd496
  do_stat (filename_stamp2,   &statinfo[2]);
Packit Service fdd496
  do_stat (filename_stamp3,   &statinfo[3]);
Packit Service fdd496
Packit Service fdd496
  /* Now use our access functions. */
Packit Service fdd496
  for (i = 0; i < NFILES; ++i)
Packit Service fdd496
    {
Packit Service fdd496
      modtimes[i] = get_stat_mtime (&statinfo[i]);
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
test_mtime (const struct stat *statinfo, struct timespec *modtimes)
Packit Service fdd496
{
Packit Service fdd496
  int i;
Packit Service fdd496
Packit Service fdd496
  /* Use the struct stat fields directly. */
Packit Service fdd496
  /* mtime(stamp1) < mtime(stamp2) */
Packit Service fdd496
  ASSERT (statinfo[0].st_mtime < statinfo[2].st_mtime
Packit Service fdd496
          || (statinfo[0].st_mtime == statinfo[2].st_mtime
Packit Service fdd496
              && (get_stat_mtime_ns (&statinfo[0])
Packit Service fdd496
                  < get_stat_mtime_ns (&statinfo[2]))));
Packit Service fdd496
  /* mtime(stamp2) < mtime(stamp3) */
Packit Service fdd496
  ASSERT (statinfo[2].st_mtime < statinfo[3].st_mtime
Packit Service fdd496
          || (statinfo[2].st_mtime == statinfo[3].st_mtime
Packit Service fdd496
              && (get_stat_mtime_ns (&statinfo[2])
Packit Service fdd496
                  < get_stat_mtime_ns (&statinfo[3]))));
Packit Service fdd496
Packit Service fdd496
  /* Now check the result of the access functions. */
Packit Service fdd496
  /* mtime(stamp1) < mtime(stamp2) */
Packit Service fdd496
  ASSERT (modtimes[0].tv_sec < modtimes[2].tv_sec
Packit Service fdd496
          || (modtimes[0].tv_sec == modtimes[2].tv_sec
Packit Service fdd496
              && modtimes[0].tv_nsec < modtimes[2].tv_nsec));
Packit Service fdd496
  /* mtime(stamp2) < mtime(stamp3) */
Packit Service fdd496
  ASSERT (modtimes[2].tv_sec < modtimes[3].tv_sec
Packit Service fdd496
          || (modtimes[2].tv_sec == modtimes[3].tv_sec
Packit Service fdd496
              && modtimes[2].tv_nsec < modtimes[3].tv_nsec));
Packit Service fdd496
Packit Service fdd496
  /* verify equivalence */
Packit Service fdd496
  for (i = 0; i < NFILES; ++i)
Packit Service fdd496
    {
Packit Service fdd496
      struct timespec ts;
Packit Service fdd496
      ts = get_stat_mtime (&statinfo[i]);
Packit Service fdd496
      ASSERT (ts.tv_sec == statinfo[i].st_mtime);
Packit Service fdd496
    }
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
#if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
Packit Service fdd496
/* Skip the ctime tests on native Windows platforms, because their
Packit Service fdd496
   st_ctime is either the same as st_mtime (plus or minus an offset)
Packit Service fdd496
   or set to the file _creation_ time, and is not influenced by rename
Packit Service fdd496
   or chmod.  */
Packit Service fdd496
# define test_ctime(ignored) ((void) 0)
Packit Service fdd496
#else
Packit Service fdd496
static void
Packit Service fdd496
test_ctime (const struct stat *statinfo)
Packit Service fdd496
{
Packit Service fdd496
  /* On some buggy NFS clients, mtime and ctime are disproportionately
Packit Service fdd496
     skewed from one another.  Skip this test in that case.  */
Packit Service fdd496
  if (statinfo[0].st_mtime != statinfo[0].st_ctime)
Packit Service fdd496
    return;
Packit Service fdd496
Packit Service fdd496
  /* mtime(stamp2) < ctime(testfile) */
Packit Service fdd496
  ASSERT (statinfo[2].st_mtime < statinfo[1].st_ctime
Packit Service fdd496
          || (statinfo[2].st_mtime == statinfo[1].st_ctime
Packit Service fdd496
              && (get_stat_mtime_ns (&statinfo[2])
Packit Service fdd496
                  < get_stat_ctime_ns (&statinfo[1]))));
Packit Service fdd496
}
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
static void
Packit Service fdd496
test_birthtime (const struct stat *statinfo,
Packit Service fdd496
                const struct timespec *modtimes,
Packit Service fdd496
                struct timespec *birthtimes)
Packit Service fdd496
{
Packit Service fdd496
  int i;
Packit Service fdd496
Packit Service fdd496
  /* Collect the birth times.  */
Packit Service fdd496
  for (i = 0; i < NFILES; ++i)
Packit Service fdd496
    {
Packit Service fdd496
      birthtimes[i] = get_stat_birthtime (&statinfo[i]);
Packit Service fdd496
      if (birthtimes[i].tv_nsec < 0)
Packit Service fdd496
        return;
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  /* mtime(stamp1) < birthtime(testfile) */
Packit Service fdd496
  ASSERT (modtimes[0].tv_sec < birthtimes[1].tv_sec
Packit Service fdd496
          || (modtimes[0].tv_sec == birthtimes[1].tv_sec
Packit Service fdd496
              && modtimes[0].tv_nsec < birthtimes[1].tv_nsec));
Packit Service fdd496
  /* birthtime(testfile) < mtime(stamp2) */
Packit Service fdd496
  ASSERT (birthtimes[1].tv_sec < modtimes[2].tv_sec
Packit Service fdd496
          || (birthtimes[1].tv_sec == modtimes[2].tv_sec
Packit Service fdd496
              && birthtimes[1].tv_nsec < modtimes[2].tv_nsec));
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
int
Packit Service fdd496
main (void)
Packit Service fdd496
{
Packit Service fdd496
  struct stat statinfo[NFILES];
Packit Service fdd496
  struct timespec modtimes[NFILES];
Packit Service fdd496
  struct timespec birthtimes[NFILES];
Packit Service fdd496
Packit Service fdd496
  initialize_filenames ();
Packit Service fdd496
Packit Service fdd496
#ifdef SIGHUP
Packit Service fdd496
  signal (SIGHUP, cleanup);
Packit Service fdd496
#endif
Packit Service fdd496
#ifdef SIGINT
Packit Service fdd496
  signal (SIGINT, cleanup);
Packit Service fdd496
#endif
Packit Service fdd496
#ifdef SIGQUIT
Packit Service fdd496
  signal (SIGQUIT, cleanup);
Packit Service fdd496
#endif
Packit Service fdd496
#ifdef SIGTERM
Packit Service fdd496
  signal (SIGTERM, cleanup);
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
  cleanup (0);
Packit Service fdd496
  prepare_test (statinfo, modtimes);
Packit Service fdd496
  test_mtime (statinfo, modtimes);
Packit Service fdd496
  test_ctime (statinfo);
Packit Service fdd496
  test_birthtime (statinfo, modtimes, birthtimes);
Packit Service fdd496
Packit Service fdd496
  cleanup (0);
Packit Service fdd496
  return 0;
Packit Service fdd496
}