Make test-stat-time pass on mingw.
[gnulib.git] / tests / test-stat-time.c
1 /* Test of <stat-time.h>.
2    Copyright (C) 2007-2008 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 <http://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 <stdlib.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29
30 #define ASSERT(expr) \
31   do                                                                         \
32     {                                                                        \
33       if (!(expr))                                                           \
34         {                                                                    \
35           fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
36           fflush (stderr);                                                   \
37           abort ();                                                          \
38         }                                                                    \
39     }                                                                        \
40   while (0)
41
42 enum { NFILES = 4 };
43
44 static void
45 force_unlink (const char *filename)
46 {
47   /* This chmod is necessary on mingw, where unlink() of a read-only file
48      fails with EPERM.  */
49   chmod (filename, 0600);
50   unlink (filename);
51 }
52
53 static void
54 cleanup (int sig)
55 {
56   /* Remove temporary files.  */
57   force_unlink ("t-stt-stamp1");
58   force_unlink ("t-stt-testfile");
59   force_unlink ("t-stt-stamp2");
60   force_unlink ("t-stt-renamed");
61   force_unlink ("t-stt-stamp3");
62
63   if (sig != 0)
64     _exit (1);
65 }
66
67 static int
68 open_file (const char *filename, int flags)
69 {
70   int fd = open (filename, flags | O_WRONLY, 0500);
71   if (fd >= 0)
72     {
73       close (fd);
74       return 1;
75     }
76   else
77     {
78       return 0;
79     }
80 }
81
82 static void
83 create_file (const char *filename)
84 {
85   ASSERT (open_file (filename, O_CREAT | O_EXCL));
86 }
87
88 static void
89 do_stat (const char *filename, struct stat *p)
90 {
91   ASSERT (stat (filename, p) == 0);
92 }
93
94 static void
95 prepare_test (struct stat *statinfo, struct timespec *modtimes)
96 {
97   int i;
98
99   create_file ("t-stt-stamp1");
100   sleep (2);
101   create_file ("t-stt-testfile");
102   sleep (2);
103   create_file ("t-stt-stamp2");
104   sleep (2);
105   ASSERT (chmod ("t-stt-testfile", 0400) == 0);
106   sleep (2);
107   create_file ("t-stt-stamp3");
108
109   do_stat ("t-stt-stamp1",  &statinfo[0]);
110   do_stat ("t-stt-testfile", &statinfo[1]);
111   do_stat ("t-stt-stamp2",  &statinfo[2]);
112   do_stat ("t-stt-stamp3",  &statinfo[3]);
113
114   /* Now use our access functions. */
115   for (i = 0; i < NFILES; ++i)
116     {
117       modtimes[i] = get_stat_mtime (&statinfo[i]);
118     }
119 }
120
121 static void
122 test_mtime (const struct stat *statinfo, struct timespec *modtimes)
123 {
124   int i;
125
126   /* Use the struct stat fields directly. */
127   ASSERT (statinfo[0].st_mtime < statinfo[2].st_mtime); /* mtime(stamp1) < mtime(stamp2) */
128   ASSERT (statinfo[2].st_mtime < statinfo[3].st_mtime); /* mtime(stamp2) < mtime(stamp3) */
129
130   /* Now check the result of the access functions. */
131   ASSERT (modtimes[0].tv_sec < modtimes[2].tv_sec); /* mtime(stamp1) < mtime(stamp2) */
132   ASSERT (modtimes[2].tv_sec < modtimes[3].tv_sec); /* mtime(stamp2) < mtime(stamp3) */
133
134   /* verify equivalence */
135   for (i = 0; i < NFILES; ++i)
136     {
137       struct timespec ts;
138       ts = get_stat_mtime (&statinfo[i]);
139       ASSERT (ts.tv_sec == statinfo[i].st_mtime);
140     }
141 }
142
143 static void
144 test_ctime (const struct stat *statinfo)
145 {
146   ASSERT (statinfo[2].st_mtime < statinfo[1].st_ctime); /* mtime(stamp2) < ctime(renamed) */
147
148   ASSERT (statinfo[2].st_mtime < statinfo[1].st_ctime); /* mtime(stamp2) < ctime(renamed) */
149 }
150
151 static void
152 test_birthtime (const struct stat *statinfo,
153                 const struct timespec *modtimes,
154                 struct timespec *birthtimes)
155 {
156   int i;
157
158   /* Collect the birth times.. */
159   for (i = 0; i < NFILES; ++i)
160     {
161       birthtimes[i] = get_stat_birthtime (&statinfo[i]);
162       if (birthtimes[i].tv_nsec < 0)
163         return;
164     }
165
166   ASSERT (modtimes[0].tv_sec < birthtimes[1].tv_sec); /* mtime(stamp1) < birthtime(renamed) */
167   ASSERT (birthtimes[1].tv_sec < modtimes[2].tv_sec); /* birthtime(renamed) < mtime(stamp2) */
168 }
169
170 int
171 main ()
172 {
173   struct stat statinfo[NFILES];
174   struct timespec modtimes[NFILES];
175   struct timespec birthtimes[NFILES];
176
177 #ifdef SIGHUP
178   signal (SIGHUP, cleanup);
179 #endif
180 #ifdef SIGINT
181   signal (SIGINT, cleanup);
182 #endif
183 #ifdef SIGQUIT
184   signal (SIGQUIT, cleanup);
185 #endif
186 #ifdef SIGTERM
187   signal (SIGTERM, cleanup);
188 #endif
189
190   cleanup (0);
191   prepare_test (statinfo, modtimes);
192   test_mtime (statinfo, modtimes);
193   /* Skip the ctime tests on native Windows platforms, because there st_ctime
194      is either the same as st_mtime (plus or minus an offset) or set to the
195      file _creation_ time, and is not influenced by rename or chmod.  */
196 #if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)
197   test_ctime (statinfo);
198 #endif
199   test_birthtime (statinfo, modtimes, birthtimes);
200
201   cleanup (0);
202   return 0;
203 }