truncate: New module.
[gnulib/ericb.git] / tests / test-stat-time.c
blob7b9cebfdd9b8da4473fc69bf0c519b4961e451c6
1 /* Test of <stat-time.h>.
2 Copyright (C) 2007-2017 Free Software Foundation, Inc.
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.
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.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 /* Written by James Youngman <jay@gnu.org>, 2007. */
19 #include <config.h>
21 #include "stat-time.h"
23 #include <fcntl.h>
24 #include <signal.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
28 #include "macros.h"
30 #define BASE "test-stat-time.t"
31 #include "nap.h"
33 enum { NFILES = 4 };
35 static int
36 force_unlink (const char *filename)
38 /* This chmod is necessary on mingw, where unlink() of a read-only file
39 fails with EPERM. */
40 chmod (filename, 0600);
41 return unlink (filename);
44 static void
45 cleanup (int sig)
47 /* Remove temporary files. */
48 force_unlink ("t-stt-stamp1");
49 force_unlink ("t-stt-testfile");
50 force_unlink ("t-stt-stamp2");
51 force_unlink ("t-stt-renamed");
52 force_unlink ("t-stt-stamp3");
54 if (sig != 0)
55 _exit (1);
58 static int
59 open_file (const char *filename, int flags)
61 int fd = open (filename, flags | O_WRONLY, 0500);
62 if (fd >= 0)
64 close (fd);
65 return 1;
67 else
69 return 0;
73 static void
74 create_file (const char *filename)
76 ASSERT (open_file (filename, O_CREAT | O_EXCL));
79 static void
80 do_stat (const char *filename, struct stat *p)
82 ASSERT (stat (filename, p) == 0);
85 static void
86 prepare_test (struct stat *statinfo, struct timespec *modtimes)
88 int i;
90 create_file ("t-stt-stamp1");
91 nap ();
92 create_file ("t-stt-testfile");
93 nap ();
94 create_file ("t-stt-stamp2");
95 nap ();
96 ASSERT (chmod ("t-stt-testfile", 0400) == 0);
97 nap ();
98 create_file ("t-stt-stamp3");
100 do_stat ("t-stt-stamp1", &statinfo[0]);
101 do_stat ("t-stt-testfile", &statinfo[1]);
102 do_stat ("t-stt-stamp2", &statinfo[2]);
103 do_stat ("t-stt-stamp3", &statinfo[3]);
105 /* Now use our access functions. */
106 for (i = 0; i < NFILES; ++i)
108 modtimes[i] = get_stat_mtime (&statinfo[i]);
112 static void
113 test_mtime (const struct stat *statinfo, struct timespec *modtimes)
115 int i;
117 /* Use the struct stat fields directly. */
118 /* mtime(stamp1) < mtime(stamp2) */
119 ASSERT (statinfo[0].st_mtime < statinfo[2].st_mtime
120 || (statinfo[0].st_mtime == statinfo[2].st_mtime
121 && (get_stat_mtime_ns (&statinfo[0])
122 < get_stat_mtime_ns (&statinfo[2]))));
123 /* mtime(stamp2) < mtime(stamp3) */
124 ASSERT (statinfo[2].st_mtime < statinfo[3].st_mtime
125 || (statinfo[2].st_mtime == statinfo[3].st_mtime
126 && (get_stat_mtime_ns (&statinfo[2])
127 < get_stat_mtime_ns (&statinfo[3]))));
129 /* Now check the result of the access functions. */
130 /* mtime(stamp1) < mtime(stamp2) */
131 ASSERT (modtimes[0].tv_sec < modtimes[2].tv_sec
132 || (modtimes[0].tv_sec == modtimes[2].tv_sec
133 && modtimes[0].tv_nsec < modtimes[2].tv_nsec));
134 /* mtime(stamp2) < mtime(stamp3) */
135 ASSERT (modtimes[2].tv_sec < modtimes[3].tv_sec
136 || (modtimes[2].tv_sec == modtimes[3].tv_sec
137 && modtimes[2].tv_nsec < modtimes[3].tv_nsec));
139 /* verify equivalence */
140 for (i = 0; i < NFILES; ++i)
142 struct timespec ts;
143 ts = get_stat_mtime (&statinfo[i]);
144 ASSERT (ts.tv_sec == statinfo[i].st_mtime);
148 #if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
149 /* Skip the ctime tests on native Windows platforms, because their
150 st_ctime is either the same as st_mtime (plus or minus an offset)
151 or set to the file _creation_ time, and is not influenced by rename
152 or chmod. */
153 # define test_ctime(ignored) ((void) 0)
154 #else
155 static void
156 test_ctime (const struct stat *statinfo)
158 /* On some buggy NFS clients, mtime and ctime are disproportionately
159 skewed from one another. Skip this test in that case. */
160 if (statinfo[0].st_mtime != statinfo[0].st_ctime)
161 return;
163 /* mtime(stamp2) < ctime(renamed) */
164 ASSERT (statinfo[2].st_mtime < statinfo[1].st_ctime
165 || (statinfo[2].st_mtime == statinfo[1].st_ctime
166 && (get_stat_mtime_ns (&statinfo[2])
167 < get_stat_ctime_ns (&statinfo[1]))));
169 #endif
171 static void
172 test_birthtime (const struct stat *statinfo,
173 const struct timespec *modtimes,
174 struct timespec *birthtimes)
176 int i;
178 /* Collect the birth times. */
179 for (i = 0; i < NFILES; ++i)
181 birthtimes[i] = get_stat_birthtime (&statinfo[i]);
182 if (birthtimes[i].tv_nsec < 0)
183 return;
186 /* mtime(stamp1) < birthtime(renamed) */
187 ASSERT (modtimes[0].tv_sec < birthtimes[1].tv_sec
188 || (modtimes[0].tv_sec == birthtimes[1].tv_sec
189 && modtimes[0].tv_nsec < birthtimes[1].tv_nsec));
190 /* birthtime(renamed) < mtime(stamp2) */
191 ASSERT (birthtimes[1].tv_sec < modtimes[2].tv_sec
192 || (birthtimes[1].tv_sec == modtimes[2].tv_sec
193 && birthtimes[1].tv_nsec < modtimes[2].tv_nsec));
197 main (void)
199 struct stat statinfo[NFILES];
200 struct timespec modtimes[NFILES];
201 struct timespec birthtimes[NFILES];
203 #ifdef SIGHUP
204 signal (SIGHUP, cleanup);
205 #endif
206 #ifdef SIGINT
207 signal (SIGINT, cleanup);
208 #endif
209 #ifdef SIGQUIT
210 signal (SIGQUIT, cleanup);
211 #endif
212 #ifdef SIGTERM
213 signal (SIGTERM, cleanup);
214 #endif
216 cleanup (0);
217 prepare_test (statinfo, modtimes);
218 test_mtime (statinfo, modtimes);
219 test_ctime (statinfo);
220 test_birthtime (statinfo, modtimes, birthtimes);
222 cleanup (0);
223 return 0;