1 /* Test of <stat-time.h>.
2 Copyright (C) 2007-2024 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 <https://www.gnu.org/licenses/>. */
17 /* Written by James Youngman <jay@gnu.org>, 2007. */
21 #include "stat-time.h"
32 #define BASE "test-stat-time.t"
37 static char filename_stamp1
[50];
38 static char filename_testfile
[50];
39 static char filename_stamp2
[50];
40 static char filename_stamp3
[50];
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/> */
49 initialize_filenames (void)
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
);
59 force_unlink (const char *filename
)
61 /* This chmod is necessary on mingw, where unlink() of a read-only file
63 chmod (filename
, 0600);
64 return unlink (filename
);
70 /* Remove temporary files. */
71 force_unlink (filename_stamp1
);
72 force_unlink (filename_testfile
);
73 force_unlink (filename_stamp2
);
74 force_unlink (filename_stamp3
);
81 open_file (const char *filename
, int flags
)
83 int fd
= open (filename
, flags
| O_WRONLY
, 0500);
96 create_file (const char *filename
)
98 ASSERT (open_file (filename
, O_CREAT
| O_EXCL
));
102 do_stat (const char *filename
, struct stat
*p
)
104 ASSERT (stat (filename
, p
) == 0);
108 prepare_test (struct stat
*statinfo
, struct timespec
*modtimes
)
112 create_file (filename_stamp1
);
114 create_file (filename_testfile
);
116 create_file (filename_stamp2
);
118 ASSERT (chmod (filename_testfile
, 0400) == 0);
120 create_file (filename_stamp3
);
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]);
127 /* Now use our access functions. */
128 for (i
= 0; i
< NFILES
; ++i
)
130 modtimes
[i
] = get_stat_mtime (&statinfo
[i
]);
135 test_mtime (const struct stat
*statinfo
, struct timespec
*modtimes
)
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]))));
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
));
161 /* verify equivalence */
162 for (i
= 0; i
< NFILES
; ++i
)
165 ts
= get_stat_mtime (&statinfo
[i
]);
166 ASSERT (ts
.tv_sec
== statinfo
[i
].st_mtime
);
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
175 # define test_ctime(ignored) ((void) 0)
178 test_ctime (const struct stat
*statinfo
)
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
)
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]))));
194 test_birthtime (const struct stat
*statinfo
,
195 const struct timespec
*modtimes
,
196 struct timespec
*birthtimes
)
200 /* Collect the birth times. */
201 for (i
= 0; i
< NFILES
; ++i
)
203 birthtimes
[i
] = get_stat_birthtime (&statinfo
[i
]);
204 if (birthtimes
[i
].tv_nsec
< 0)
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
));
221 struct stat statinfo
[NFILES
];
222 struct timespec modtimes
[NFILES
];
223 struct timespec birthtimes
[NFILES
];
225 initialize_filenames ();
228 signal (SIGHUP
, cleanup
);
231 signal (SIGINT
, cleanup
);
234 signal (SIGQUIT
, cleanup
);
237 signal (SIGTERM
, cleanup
);
241 prepare_test (statinfo
, modtimes
);
242 test_mtime (statinfo
, modtimes
);
243 test_ctime (statinfo
);
244 test_birthtime (statinfo
, modtimes
, birthtimes
);
247 return test_exit_status
;