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. */
24 test_lutimens (int (*func
) (char const *, struct timespec
const *), bool print
)
31 /* Non-symlinks should be handled just like utimens. */
33 ASSERT (func ("no_such", NULL
) == -1);
34 ASSERT (errno
== ENOENT
);
36 ASSERT (func ("no_such/", NULL
) == -1);
37 ASSERT (errno
== ENOENT
|| errno
== ENOTDIR
);
39 ASSERT (func ("", NULL
) == -1);
40 ASSERT (errno
== ENOENT
);
42 int fd
= open (BASE
"file", O_RDWR
| O_CREAT
| O_TRUNC
, 0600);
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];
56 ASSERT (func (BASE
"file/", ts
) == -1);
57 ASSERT (errno
== ENOTDIR
);
58 ASSERT (stat (BASE
"file", &st2
) == 0);
60 ASSERT (st1
.st_atime
== st2
.st_atime
);
61 ASSERT (st1
.st_mtime
== st2
.st_mtime
);
64 struct timespec ts
[2];
69 ASSERT (func (BASE
"file", ts
) == 0);
71 ASSERT (stat (BASE
"file", &st2
) == 0);
73 ASSERT (st2
.st_atime
== Y2K
);
74 ASSERT (st2
.st_mtime
== Y2K
);
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);
83 fputs ("skipping test: symlinks not supported on this file system\n",
88 result
= func (BASE
"link", NULL
);
90 /* Make sure we did not reference through link by accident. */
91 ASSERT (stat (BASE
"file", &st1
) == 0);
93 ASSERT (st1
.st_atime
== Y2K
);
94 ASSERT (st1
.st_mtime
== Y2K
);
95 ASSERT (lstat (BASE
"link", &st1
) == 0);
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);
104 fputs ("skipping test: "
105 "setting symlink time not supported on this file system\n",
110 ASSERT (lstat (BASE
"link", &st1
) == 0);
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
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];
128 ts
[0].tv_nsec
= UTIME_BOGUS_POS
;
132 ASSERT (func (BASE
"link", ts
) == -1);
133 ASSERT (errno
== EINVAL
);
136 struct timespec ts
[2];
140 ts
[1].tv_nsec
= UTIME_BOGUS_NEG
;
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];
157 ts
[0].tv_nsec
= BILLION
/ 2 - 1;
159 ts
[1].tv_nsec
= BILLION
- 1;
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
);
173 ASSERT (ctime_compare (&st1
, &st2
) < 0);
176 /* Play with UTIME_OMIT, UTIME_NOW. */
179 struct timespec ts
[2];
180 ts
[0].tv_sec
= BILLION
;
181 ts
[0].tv_nsec
= UTIME_OMIT
;
183 ts
[1].tv_nsec
= UTIME_NOW
;
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);
195 ASSERT (ctime_compare (&st2
, &st3
) < 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
));
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];
221 ASSERT (func (BASE
"link/", ts
) == 0);
223 /* On cygwin 1.5, stat() changes atime of directories, so only check
225 ASSERT (stat (BASE
"dir", &st1
) == 0);
226 ASSERT (st1
.st_mtime
== Y2K
);
227 ASSERT (lstat (BASE
"link", &st1
) == 0);
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);
236 ASSERT (st1
.st_atime
!= Y2K
);
237 ASSERT (st1
.st_mtime
!= Y2K
);
240 ASSERT (rmdir (BASE
"dir") == 0);
241 ASSERT (unlink (BASE
"link") == 0);