openat: don’t close (-1)
[gnulib.git] / tests / test-lutimens.h
blobb909ec4b7537068278c3bd39cdac2556d5a04daa
1 /* Test of file timestamp modification functions.
2 Copyright (C) 2009-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 #include "test-utimens-common.h"
19 /* This file is designed to test both lutimens(a,b) and
20 utimensat(AT_FDCWD,a,b,AT_SYMLINK_NOFOLLOW). FUNC is the function
21 to test. Assumes that BASE and ASSERT are already defined. If
22 PRINT, warn before skipping tests with status 77. */
23 static int
24 test_lutimens (int (*func) (char const *, struct timespec const *), bool print)
26 int result;
27 int saved_errno;
28 struct stat st1;
29 struct stat st2;
31 /* Non-symlinks should be handled just like utimens. */
32 errno = 0;
33 ASSERT (func ("no_such", NULL) == -1);
34 ASSERT (errno == ENOENT);
35 errno = 0;
36 ASSERT (func ("no_such/", NULL) == -1);
37 ASSERT (errno == ENOENT || errno == ENOTDIR);
38 errno = 0;
39 ASSERT (func ("", NULL) == -1);
40 ASSERT (errno == ENOENT);
42 int fd = open (BASE "file", O_RDWR | O_CREAT | O_TRUNC, 0600);
43 ASSERT (0 <= fd);
45 bool check_atime = checkable_atime (fd, &st1);
46 ASSERT (close (fd) == 0);
47 ASSERT (st1.st_atime != Y2K);
48 ASSERT (st1.st_mtime != Y2K);
51 struct timespec ts[2];
52 ts[0].tv_sec = Y2K;
53 ts[0].tv_nsec = 0;
54 ts[1] = ts[0];
55 errno = 0;
56 ASSERT (func (BASE "file/", ts) == -1);
57 ASSERT (errno == ENOTDIR);
58 ASSERT (stat (BASE "file", &st2) == 0);
59 if (check_atime)
60 ASSERT (st1.st_atime == st2.st_atime);
61 ASSERT (st1.st_mtime == st2.st_mtime);
64 struct timespec ts[2];
65 ts[0].tv_sec = Y2K;
66 ts[0].tv_nsec = 0;
67 ts[1] = ts[0];
68 nap ();
69 ASSERT (func (BASE "file", ts) == 0);
71 ASSERT (stat (BASE "file", &st2) == 0);
72 if (check_atime)
73 ASSERT (st2.st_atime == Y2K);
74 ASSERT (st2.st_mtime == Y2K);
75 if (check_ctime)
76 ASSERT (ctime_compare (&st1, &st2) < 0);
78 /* Play with symlink timestamps. */
79 if (symlink (BASE "file", BASE "link"))
81 ASSERT (unlink (BASE "file") == 0);
82 if (print)
83 fputs ("skipping test: symlinks not supported on this file system\n",
84 stderr);
85 return 77;
87 errno = 0;
88 result = func (BASE "link", NULL);
89 saved_errno = errno;
90 /* Make sure we did not reference through link by accident. */
91 ASSERT (stat (BASE "file", &st1) == 0);
92 if (check_atime)
93 ASSERT (st1.st_atime == Y2K);
94 ASSERT (st1.st_mtime == Y2K);
95 ASSERT (lstat (BASE "link", &st1) == 0);
96 if (check_atime)
97 ASSERT (st1.st_atime != Y2K);
98 ASSERT (st1.st_mtime != Y2K);
99 ASSERT (unlink (BASE "file") == 0);
100 if (result == -1 && saved_errno == ENOSYS)
102 ASSERT (unlink (BASE "link") == 0);
103 if (print)
104 fputs ("skipping test: "
105 "setting symlink time not supported on this file system\n",
106 stderr);
107 return 77;
109 ASSERT (!result);
110 ASSERT (lstat (BASE "link", &st1) == 0);
111 nap ();
112 ASSERT (lstat (BASE "link", &st2) == 0);
114 /* On cygwin, lstat() changes atime of symlinks, so that lutimens
115 can effectively modify only mtime. */
116 bool check_atime_on_symlinks
117 = (check_atime
118 && st1.st_atime == st2.st_atime
119 && get_stat_atime_ns (&st1) == get_stat_atime_ns (&st2));
121 ASSERT (st1.st_ctime == st2.st_ctime);
122 ASSERT (get_stat_ctime_ns (&st1) == get_stat_ctime_ns (&st2));
124 /* Invalid arguments. */
126 struct timespec ts[2];
127 ts[0].tv_sec = Y2K;
128 ts[0].tv_nsec = UTIME_BOGUS_POS;
129 ts[1].tv_sec = Y2K;
130 ts[1].tv_nsec = 0;
131 errno = 0;
132 ASSERT (func (BASE "link", ts) == -1);
133 ASSERT (errno == EINVAL);
136 struct timespec ts[2];
137 ts[0].tv_sec = Y2K;
138 ts[0].tv_nsec = 0;
139 ts[1].tv_sec = Y2K;
140 ts[1].tv_nsec = UTIME_BOGUS_NEG;
141 errno = 0;
142 ASSERT (func (BASE "link", ts) == -1);
143 ASSERT (errno == EINVAL);
145 ASSERT (lstat (BASE "link", &st2) == 0);
146 if (check_atime_on_symlinks)
148 ASSERT (st1.st_atime == st2.st_atime);
149 ASSERT (get_stat_atime_ns (&st1) == get_stat_atime_ns (&st2));
151 ASSERT (utimecmp (BASE "link", &st1, &st2, 0) == 0);
153 /* Set both times. */
155 struct timespec ts[2];
156 ts[0].tv_sec = Y2K;
157 ts[0].tv_nsec = BILLION / 2 - 1;
158 ts[1].tv_sec = Y2K;
159 ts[1].tv_nsec = BILLION - 1;
160 nap ();
161 ASSERT (func (BASE "link", ts) == 0);
162 ASSERT (lstat (BASE "link", &st2) == 0);
163 if (check_atime_on_symlinks)
165 ASSERT (st2.st_atime == Y2K);
166 ASSERT (0 <= get_stat_atime_ns (&st2));
167 ASSERT (get_stat_atime_ns (&st2) < BILLION / 2);
169 ASSERT (st2.st_mtime == Y2K);
170 ASSERT (0 <= get_stat_mtime_ns (&st2));
171 ASSERT (get_stat_mtime_ns (&st2) < BILLION);
172 if (check_ctime)
173 ASSERT (ctime_compare (&st1, &st2) < 0);
176 /* Play with UTIME_OMIT, UTIME_NOW. */
178 struct stat st3;
179 struct timespec ts[2];
180 ts[0].tv_sec = BILLION;
181 ts[0].tv_nsec = UTIME_OMIT;
182 ts[1].tv_sec = 0;
183 ts[1].tv_nsec = UTIME_NOW;
184 nap ();
185 ASSERT (func (BASE "link", ts) == 0);
186 ASSERT (lstat (BASE "link", &st3) == 0);
187 if (check_atime_on_symlinks)
189 ASSERT (st3.st_atime == Y2K);
190 ASSERT (0 <= get_stat_atime_ns (&st3));
191 ASSERT (get_stat_atime_ns (&st3) < BILLION / 2);
193 ASSERT (utimecmp (BASE "link", &st1, &st3, 0) <= 0);
194 if (check_ctime)
195 ASSERT (ctime_compare (&st2, &st3) < 0);
196 nap ();
197 ts[0].tv_nsec = 0;
198 ts[1].tv_nsec = UTIME_OMIT;
199 ASSERT (func (BASE "link", ts) == 0);
200 ASSERT (lstat (BASE "link", &st2) == 0);
201 if (check_atime_on_symlinks)
203 ASSERT (st2.st_atime == BILLION);
204 ASSERT (get_stat_atime_ns (&st2) == 0);
206 ASSERT (st3.st_mtime == st2.st_mtime);
207 ASSERT (get_stat_mtime_ns (&st3) == get_stat_mtime_ns (&st2));
208 if (check_ctime > 0)
209 ASSERT (ctime_compare (&st3, &st2) < 0);
212 /* Symlink to directory. */
213 ASSERT (unlink (BASE "link") == 0);
214 ASSERT (symlink (BASE "dir", BASE "link") == 0);
215 ASSERT (mkdir (BASE "dir", 0700) == 0);
217 struct timespec ts[2];
218 ts[0].tv_sec = Y2K;
219 ts[0].tv_nsec = 0;
220 ts[1] = ts[0];
221 ASSERT (func (BASE "link/", ts) == 0);
223 /* On cygwin 1.5, stat() changes atime of directories, so only check
224 mtime. */
225 ASSERT (stat (BASE "dir", &st1) == 0);
226 ASSERT (st1.st_mtime == Y2K);
227 ASSERT (lstat (BASE "link", &st1) == 0);
228 if (check_atime)
229 ASSERT (st1.st_atime != Y2K);
230 ASSERT (st1.st_mtime != Y2K);
231 ASSERT (func (BASE "link", NULL) == 0);
232 ASSERT (stat (BASE "dir", &st1) == 0);
233 ASSERT (st1.st_mtime == Y2K);
234 ASSERT (lstat (BASE "link", &st1) == 0);
235 if (check_atime)
236 ASSERT (st1.st_atime != Y2K);
237 ASSERT (st1.st_mtime != Y2K);
239 /* Cleanup. */
240 ASSERT (rmdir (BASE "dir") == 0);
241 ASSERT (unlink (BASE "link") == 0);
242 return 0;