1b7a77849SAndy Fiddaman /*
2b7a77849SAndy Fiddaman * This file and its contents are supplied under the terms of the
3b7a77849SAndy Fiddaman * Common Development and Distribution License ("CDDL"), version 1.0.
4b7a77849SAndy Fiddaman * You may only use this file in accordance with the terms of version
5b7a77849SAndy Fiddaman * 1.0 of the CDDL.
6b7a77849SAndy Fiddaman *
7b7a77849SAndy Fiddaman * A full copy of the text of the CDDL should have accompanied this
8b7a77849SAndy Fiddaman * source. A copy of the CDDL is also available via the Internet at
9b7a77849SAndy Fiddaman * http://www.illumos.org/license/CDDL.
10b7a77849SAndy Fiddaman */
11b7a77849SAndy Fiddaman
12b7a77849SAndy Fiddaman /*
13b7a77849SAndy Fiddaman * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
14b7a77849SAndy Fiddaman */
15b7a77849SAndy Fiddaman
16b7a77849SAndy Fiddaman /*
17b7a77849SAndy Fiddaman * Test the implementation of the various *utimes() and *utimens() functions
18b7a77849SAndy Fiddaman */
19b7a77849SAndy Fiddaman
20b7a77849SAndy Fiddaman #include <stdio.h>
21b7a77849SAndy Fiddaman #include <stdbool.h>
22b7a77849SAndy Fiddaman #include <stdlib.h>
23b7a77849SAndy Fiddaman #include <string.h>
24b7a77849SAndy Fiddaman #include <err.h>
25b7a77849SAndy Fiddaman #include <sys/sysmacros.h>
26b7a77849SAndy Fiddaman #include <sys/types.h>
27b7a77849SAndy Fiddaman #include <sys/time.h>
28b7a77849SAndy Fiddaman #include <sys/stat.h>
29b7a77849SAndy Fiddaman #include <fcntl.h>
30b7a77849SAndy Fiddaman #include <unistd.h>
31b7a77849SAndy Fiddaman #include <errno.h>
32b7a77849SAndy Fiddaman
33b7a77849SAndy Fiddaman timespec_t testtimes[] = {
34b7a77849SAndy Fiddaman {
35b7a77849SAndy Fiddaman .tv_sec = 1280793678,
36b7a77849SAndy Fiddaman .tv_nsec = 123456789
37b7a77849SAndy Fiddaman },
38b7a77849SAndy Fiddaman {
39b7a77849SAndy Fiddaman .tv_sec = 1492732800,
40b7a77849SAndy Fiddaman .tv_nsec = 17
41b7a77849SAndy Fiddaman },
42b7a77849SAndy Fiddaman {
43b7a77849SAndy Fiddaman .tv_sec = 1320796855,
44b7a77849SAndy Fiddaman .tv_nsec = 9
45b7a77849SAndy Fiddaman },
46b7a77849SAndy Fiddaman {
47b7a77849SAndy Fiddaman .tv_sec = 1498953611,
48b7a77849SAndy Fiddaman .tv_nsec = 987654321
49b7a77849SAndy Fiddaman }
50b7a77849SAndy Fiddaman };
51b7a77849SAndy Fiddaman
52b7a77849SAndy Fiddaman enum ttype {
53b7a77849SAndy Fiddaman UTIMES,
54b7a77849SAndy Fiddaman LUTIMES,
55b7a77849SAndy Fiddaman FUTIMES,
56b7a77849SAndy Fiddaman FUTIMESAT,
57b7a77849SAndy Fiddaman FUTIMENS,
58b7a77849SAndy Fiddaman UTIMENSAT
59b7a77849SAndy Fiddaman };
60b7a77849SAndy Fiddaman
61b7a77849SAndy Fiddaman static bool
compare_times(struct stat * st,bool trunc,timespec_t * atim,timespec_t * mtim,bool invert)62b7a77849SAndy Fiddaman compare_times(struct stat *st, bool trunc, timespec_t *atim, timespec_t *mtim,
63b7a77849SAndy Fiddaman bool invert)
64b7a77849SAndy Fiddaman {
65b7a77849SAndy Fiddaman bool ret = true;
66b7a77849SAndy Fiddaman
67b7a77849SAndy Fiddaman if (st->st_atim.tv_sec != atim->tv_sec) {
68b7a77849SAndy Fiddaman ret = false;
69b7a77849SAndy Fiddaman } else if (st->st_atim.tv_nsec != (
70b7a77849SAndy Fiddaman trunc ? atim->tv_nsec / 1000 * 1000 : atim->tv_nsec)) {
71b7a77849SAndy Fiddaman ret = false;
72b7a77849SAndy Fiddaman } else if (st->st_mtim.tv_sec != mtim->tv_sec) {
73b7a77849SAndy Fiddaman ret = false;
74b7a77849SAndy Fiddaman } else if (st->st_mtim.tv_nsec != (
75b7a77849SAndy Fiddaman trunc ? mtim->tv_nsec / 1000 * 1000 : mtim->tv_nsec)) {
76b7a77849SAndy Fiddaman ret = false;
77b7a77849SAndy Fiddaman }
78b7a77849SAndy Fiddaman
79b7a77849SAndy Fiddaman if ((!ret && !invert) || (ret && invert)) {
80b7a77849SAndy Fiddaman printf(" actual atime: %ld.%.9ld\n",
81b7a77849SAndy Fiddaman st->st_atim.tv_sec, st->st_atim.tv_nsec);
82b7a77849SAndy Fiddaman printf(" actual mtime: %ld.%.9ld\n",
83b7a77849SAndy Fiddaman st->st_mtim.tv_sec, st->st_mtim.tv_nsec);
84b7a77849SAndy Fiddaman }
85b7a77849SAndy Fiddaman
86b7a77849SAndy Fiddaman return (ret);
87b7a77849SAndy Fiddaman }
88b7a77849SAndy Fiddaman
89b7a77849SAndy Fiddaman static bool
compare_filetime(char * path,bool trunc,timespec_t * atim,timespec_t * mtim,bool invert)90b7a77849SAndy Fiddaman compare_filetime(char *path, bool trunc, timespec_t *atim, timespec_t *mtim,
91b7a77849SAndy Fiddaman bool invert)
92b7a77849SAndy Fiddaman {
93b7a77849SAndy Fiddaman struct stat st;
94b7a77849SAndy Fiddaman
95b7a77849SAndy Fiddaman if (stat(path, &st) == -1)
96b7a77849SAndy Fiddaman err(EXIT_FAILURE, "stat %s", path);
97b7a77849SAndy Fiddaman
98b7a77849SAndy Fiddaman return (compare_times(&st, trunc, atim, mtim, invert));
99b7a77849SAndy Fiddaman }
100b7a77849SAndy Fiddaman
101b7a77849SAndy Fiddaman static bool
compare_linktime(char * path,bool trunc,timespec_t * atim,timespec_t * mtim,bool invert)102b7a77849SAndy Fiddaman compare_linktime(char *path, bool trunc, timespec_t *atim, timespec_t *mtim,
103b7a77849SAndy Fiddaman bool invert)
104b7a77849SAndy Fiddaman {
105b7a77849SAndy Fiddaman struct stat st;
106b7a77849SAndy Fiddaman
107b7a77849SAndy Fiddaman if (lstat(path, &st) == -1)
108b7a77849SAndy Fiddaman err(EXIT_FAILURE, "lstat %s", path);
109b7a77849SAndy Fiddaman
110b7a77849SAndy Fiddaman return (compare_times(&st, trunc, atim, mtim, invert));
111b7a77849SAndy Fiddaman }
112b7a77849SAndy Fiddaman
113b7a77849SAndy Fiddaman static bool
reset(char * path,timespec_t * atim,timespec_t * mtim)114b7a77849SAndy Fiddaman reset(char *path, timespec_t *atim, timespec_t *mtim)
115b7a77849SAndy Fiddaman {
116b7a77849SAndy Fiddaman if (utimes(path, NULL) == -1)
117b7a77849SAndy Fiddaman err(EXIT_FAILURE, "utimes reset");
118b7a77849SAndy Fiddaman if (compare_filetime(path, true, atim, mtim, true)) {
119b7a77849SAndy Fiddaman warnx("reset failed");
120b7a77849SAndy Fiddaman return (false);
121b7a77849SAndy Fiddaman }
122b7a77849SAndy Fiddaman return (true);
123b7a77849SAndy Fiddaman }
124b7a77849SAndy Fiddaman
125b7a77849SAndy Fiddaman static bool
reset_link(char * lpath,timespec_t * atim,timespec_t * mtim)126b7a77849SAndy Fiddaman reset_link(char *lpath, timespec_t *atim, timespec_t *mtim)
127b7a77849SAndy Fiddaman {
128b7a77849SAndy Fiddaman if (lutimes(lpath, NULL) == -1)
129b7a77849SAndy Fiddaman err(EXIT_FAILURE, "lutimes reset");
130b7a77849SAndy Fiddaman if (compare_linktime(lpath, true, atim, mtim, true)) {
131b7a77849SAndy Fiddaman warnx("link reset failed");
132b7a77849SAndy Fiddaman return (false);
133b7a77849SAndy Fiddaman }
134b7a77849SAndy Fiddaman return (true);
135b7a77849SAndy Fiddaman }
136b7a77849SAndy Fiddaman
137b7a77849SAndy Fiddaman static bool
runtest(enum ttype fn,char * dir,timespec_t * atim,timespec_t * mtim)138b7a77849SAndy Fiddaman runtest(enum ttype fn, char *dir, timespec_t *atim, timespec_t *mtim)
139b7a77849SAndy Fiddaman {
140b7a77849SAndy Fiddaman char path[MAXPATHLEN + 1];
141b7a77849SAndy Fiddaman char lpath[MAXPATHLEN + 1];
142b7a77849SAndy Fiddaman struct timespec ts[2];
143b7a77849SAndy Fiddaman struct timeval tv[2];
144b7a77849SAndy Fiddaman int fd, lfd, dfd, ret = true;
145b7a77849SAndy Fiddaman
146b7a77849SAndy Fiddaman ts[0] = *atim;
147b7a77849SAndy Fiddaman ts[1] = *mtim;
148b7a77849SAndy Fiddaman TIMESPEC_TO_TIMEVAL(&tv[0], &ts[0]);
149b7a77849SAndy Fiddaman TIMESPEC_TO_TIMEVAL(&tv[1], &ts[1]);
150b7a77849SAndy Fiddaman
151b7a77849SAndy Fiddaman if (snprintf(path, sizeof (path), "%s/file", dir) >= sizeof (path))
152b7a77849SAndy Fiddaman err(EXIT_FAILURE, "snprintf failed to build file path");
153b7a77849SAndy Fiddaman
154b7a77849SAndy Fiddaman if ((fd = open(path, O_CREAT, 0644)) == -1)
155b7a77849SAndy Fiddaman err(EXIT_FAILURE, "open file %s", path);
156b7a77849SAndy Fiddaman
157b7a77849SAndy Fiddaman if (snprintf(lpath, sizeof (lpath), "%s/link", dir) >= sizeof (path))
158b7a77849SAndy Fiddaman err(EXIT_FAILURE, "snprintf failed to build link path");
159b7a77849SAndy Fiddaman
160b7a77849SAndy Fiddaman if (symlink(path, lpath) == -1)
161b7a77849SAndy Fiddaman err(EXIT_FAILURE, "link(%s)", lpath);
162b7a77849SAndy Fiddaman
163b7a77849SAndy Fiddaman if ((lfd = open(lpath, O_RDWR)) == -1)
164b7a77849SAndy Fiddaman err(EXIT_FAILURE, "open link(%s)", lpath);
165b7a77849SAndy Fiddaman
166b7a77849SAndy Fiddaman if ((dfd = open(dir, O_DIRECTORY|O_RDONLY)) == -1)
167b7a77849SAndy Fiddaman err(EXIT_FAILURE, "open dir(%s)", dir);
168b7a77849SAndy Fiddaman
169b7a77849SAndy Fiddaman switch (fn) {
170b7a77849SAndy Fiddaman case UTIMES:
171b7a77849SAndy Fiddaman printf("..... utimes()\n");
172b7a77849SAndy Fiddaman
173b7a77849SAndy Fiddaman if (utimes(path, tv) == -1)
174b7a77849SAndy Fiddaman err(EXIT_FAILURE, "utimes(%s)", path);
175b7a77849SAndy Fiddaman if (!compare_filetime(path, true, atim, mtim, false)) {
176b7a77849SAndy Fiddaman warnx("failed on file");
177b7a77849SAndy Fiddaman ret = false;
178b7a77849SAndy Fiddaman }
179b7a77849SAndy Fiddaman
180b7a77849SAndy Fiddaman if (!reset(path, atim, mtim))
181b7a77849SAndy Fiddaman ret = false;
182b7a77849SAndy Fiddaman
183b7a77849SAndy Fiddaman /* repeat against symbolic link path */
184b7a77849SAndy Fiddaman if (utimes(lpath, tv) == -1)
185b7a77849SAndy Fiddaman err(EXIT_FAILURE, "utimes(%s), link", lpath);
186b7a77849SAndy Fiddaman if (!compare_filetime(path, true, atim, mtim, false)) {
187b7a77849SAndy Fiddaman warnx("failed on file through link");
188b7a77849SAndy Fiddaman ret = false;
189b7a77849SAndy Fiddaman }
190b7a77849SAndy Fiddaman
191b7a77849SAndy Fiddaman break;
192b7a77849SAndy Fiddaman
193b7a77849SAndy Fiddaman case LUTIMES:
194b7a77849SAndy Fiddaman printf("..... lutimes()\n");
195b7a77849SAndy Fiddaman
196b7a77849SAndy Fiddaman /* Use lutimes() against a plain file */
197b7a77849SAndy Fiddaman if (lutimes(path, tv) == -1)
198b7a77849SAndy Fiddaman err(EXIT_FAILURE, "lutimes(%s)", path);
199b7a77849SAndy Fiddaman if (!compare_filetime(path, true, atim, mtim, false)) {
200b7a77849SAndy Fiddaman warnx("failed on file");
201b7a77849SAndy Fiddaman ret = false;
202b7a77849SAndy Fiddaman }
203b7a77849SAndy Fiddaman
204b7a77849SAndy Fiddaman if (!reset(path, atim, mtim))
205b7a77849SAndy Fiddaman ret = false;
206b7a77849SAndy Fiddaman
207b7a77849SAndy Fiddaman /* Set the time on the link, not on the target */
208b7a77849SAndy Fiddaman if (lutimes(lpath, tv) == -1)
209b7a77849SAndy Fiddaman err(EXIT_FAILURE, "lutimes(%s)", lpath);
210b7a77849SAndy Fiddaman if (!compare_linktime(lpath, true, atim, mtim, false)) {
211b7a77849SAndy Fiddaman warnx("link time is incorrect");
212b7a77849SAndy Fiddaman ret = false;
213b7a77849SAndy Fiddaman }
214b7a77849SAndy Fiddaman if (compare_filetime(path, true, atim, mtim, true)) {
215b7a77849SAndy Fiddaman warnx("target time was updated incorrectly");
216b7a77849SAndy Fiddaman ret = false;
217b7a77849SAndy Fiddaman }
218b7a77849SAndy Fiddaman
219b7a77849SAndy Fiddaman /* Reset the time on the path and link to the current time */
220b7a77849SAndy Fiddaman if (!reset(path, atim, mtim) || !reset_link(lpath, atim, mtim))
221b7a77849SAndy Fiddaman ret = false;
222b7a77849SAndy Fiddaman
223b7a77849SAndy Fiddaman /* and modify the target */
224b7a77849SAndy Fiddaman if (utimes(path, tv) == -1)
225b7a77849SAndy Fiddaman err(EXIT_FAILURE, "utimes(%s)", path);
226b7a77849SAndy Fiddaman /* Now the target should match but the link should not */
227b7a77849SAndy Fiddaman if (!compare_filetime(path, true, atim, mtim, false)) {
228b7a77849SAndy Fiddaman warnx("target time is incorrect");
229b7a77849SAndy Fiddaman ret = false;
230b7a77849SAndy Fiddaman }
231b7a77849SAndy Fiddaman if (compare_linktime(lpath, true, atim, mtim, true)) {
232b7a77849SAndy Fiddaman warnx("link time was updated incorrectly");
233b7a77849SAndy Fiddaman ret = false;
234b7a77849SAndy Fiddaman }
235b7a77849SAndy Fiddaman break;
236b7a77849SAndy Fiddaman
237b7a77849SAndy Fiddaman case FUTIMES:
238b7a77849SAndy Fiddaman printf("..... futimes()\n");
239b7a77849SAndy Fiddaman
240b7a77849SAndy Fiddaman if (futimes(fd, tv) == -1)
241b7a77849SAndy Fiddaman err(EXIT_FAILURE, "futimes(%s)", path);
242b7a77849SAndy Fiddaman if (!compare_filetime(path, true, atim, mtim, false)) {
243b7a77849SAndy Fiddaman warnx("failed on file");
244b7a77849SAndy Fiddaman ret = false;
245b7a77849SAndy Fiddaman }
246b7a77849SAndy Fiddaman
247b7a77849SAndy Fiddaman break;
248b7a77849SAndy Fiddaman
249b7a77849SAndy Fiddaman case FUTIMESAT: {
250b7a77849SAndy Fiddaman int rfd;
251b7a77849SAndy Fiddaman printf("..... futimesat()\n");
252b7a77849SAndy Fiddaman
253b7a77849SAndy Fiddaman /* NULL path, should modify the file for 'fd' */
254b7a77849SAndy Fiddaman if (futimesat(fd, NULL, tv) == -1)
255b7a77849SAndy Fiddaman err(EXIT_FAILURE, "futimesat(fd, NULL)");
256b7a77849SAndy Fiddaman if (!compare_filetime(path, true, atim, mtim, false)) {
257b7a77849SAndy Fiddaman warnx("failed with null path");
258b7a77849SAndy Fiddaman ret = false;
259b7a77849SAndy Fiddaman }
260b7a77849SAndy Fiddaman
261b7a77849SAndy Fiddaman if (!reset(path, atim, mtim))
262b7a77849SAndy Fiddaman ret = false;
263b7a77849SAndy Fiddaman
264b7a77849SAndy Fiddaman /* random descriptor, FQ path, descriptor is ignored */
265b7a77849SAndy Fiddaman if ((rfd = open("/dev/null", O_RDONLY)) == -1)
266b7a77849SAndy Fiddaman err(EXIT_FAILURE, "open(/dev/null)");
267b7a77849SAndy Fiddaman if (futimesat(rfd, path, tv) == -1)
268b7a77849SAndy Fiddaman err(EXIT_FAILURE, "futimesat(dnfd, %s)", path);
269b7a77849SAndy Fiddaman if (!compare_filetime(path, true, atim, mtim, false)) {
270b7a77849SAndy Fiddaman warnx("failed with random descriptor and fq path");
271b7a77849SAndy Fiddaman ret = false;
272b7a77849SAndy Fiddaman }
273b7a77849SAndy Fiddaman
274b7a77849SAndy Fiddaman if (!reset(path, atim, mtim))
275b7a77849SAndy Fiddaman ret = false;
276b7a77849SAndy Fiddaman
277b7a77849SAndy Fiddaman /* repeat against symbolic link path */
278b7a77849SAndy Fiddaman if (futimesat(rfd, lpath, tv) == -1)
279b7a77849SAndy Fiddaman err(EXIT_FAILURE, "futimesat(dnfd, %s), link", lpath);
280b7a77849SAndy Fiddaman if (!compare_filetime(path, true, atim, mtim, false)) {
281b7a77849SAndy Fiddaman warnx("failed through link with "
282b7a77849SAndy Fiddaman "random descriptor, fq path");
283b7a77849SAndy Fiddaman ret = false;
284b7a77849SAndy Fiddaman }
285b7a77849SAndy Fiddaman
286b7a77849SAndy Fiddaman (void) close(rfd);
287b7a77849SAndy Fiddaman
288b7a77849SAndy Fiddaman if (!reset(path, atim, mtim))
289b7a77849SAndy Fiddaman ret = false;
290b7a77849SAndy Fiddaman
291b7a77849SAndy Fiddaman /* relative to a directory */
292b7a77849SAndy Fiddaman if (futimesat(dfd, "file", tv) == -1)
293*6353250fSRobert Mustacchi err(EXIT_FAILURE, "futimesat(dir, file)");
294b7a77849SAndy Fiddaman if (!compare_filetime(path, true, atim, mtim, false)) {
295b7a77849SAndy Fiddaman warnx("failed relative to a directory");
296b7a77849SAndy Fiddaman ret = false;
297b7a77849SAndy Fiddaman }
298b7a77849SAndy Fiddaman
299b7a77849SAndy Fiddaman if (!reset(path, atim, mtim))
300b7a77849SAndy Fiddaman ret = false;
301b7a77849SAndy Fiddaman
302b7a77849SAndy Fiddaman /* repeat against symbolic link path */
303b7a77849SAndy Fiddaman if (futimesat(dfd, "link", tv) == -1)
304b7a77849SAndy Fiddaman err(EXIT_FAILURE, "futimesat(dir, link)");
305b7a77849SAndy Fiddaman if (!compare_filetime(path, true, atim, mtim, false)) {
306b7a77849SAndy Fiddaman warnx("failed through link relative to a directory");
307b7a77849SAndy Fiddaman ret = false;
308b7a77849SAndy Fiddaman }
309b7a77849SAndy Fiddaman
310b7a77849SAndy Fiddaman if (!reset(path, atim, mtim))
311b7a77849SAndy Fiddaman ret = false;
312b7a77849SAndy Fiddaman
313b7a77849SAndy Fiddaman /* AT_FDCWD */
314b7a77849SAndy Fiddaman if (fchdir(dfd) == -1)
315b7a77849SAndy Fiddaman err(EXIT_FAILURE, "fchdir(%s)", dir);
316b7a77849SAndy Fiddaman if (futimesat(AT_FDCWD, "file", tv) == -1)
317*6353250fSRobert Mustacchi err(EXIT_FAILURE, "futimesat(AT_FDCWD, file)");
318b7a77849SAndy Fiddaman if (!compare_filetime(path, true, atim, mtim, false)) {
319b7a77849SAndy Fiddaman warnx("failed with AT_FDCWD relative");
320b7a77849SAndy Fiddaman ret = false;
321b7a77849SAndy Fiddaman }
322b7a77849SAndy Fiddaman
323b7a77849SAndy Fiddaman if (!reset(path, atim, mtim))
324b7a77849SAndy Fiddaman ret = false;
325b7a77849SAndy Fiddaman
326b7a77849SAndy Fiddaman /* repeat against symbolic link path */
327b7a77849SAndy Fiddaman if (futimesat(AT_FDCWD, "link", tv) == -1)
328b7a77849SAndy Fiddaman err(EXIT_FAILURE, "futimesat(AT_FDCWD, link)");
329b7a77849SAndy Fiddaman if (!compare_filetime(path, true, atim, mtim, false)) {
330b7a77849SAndy Fiddaman warnx("failed through link with AT_FDCWD relative");
331b7a77849SAndy Fiddaman ret = false;
332b7a77849SAndy Fiddaman }
333b7a77849SAndy Fiddaman
334b7a77849SAndy Fiddaman break;
335b7a77849SAndy Fiddaman }
336b7a77849SAndy Fiddaman
337b7a77849SAndy Fiddaman case FUTIMENS:
338b7a77849SAndy Fiddaman printf("..... futimens()\n");
339b7a77849SAndy Fiddaman if (futimens(fd, ts) == -1)
340b7a77849SAndy Fiddaman err(EXIT_FAILURE, "futimesns(%s)", path);
341b7a77849SAndy Fiddaman if (!compare_filetime(path, false, atim, mtim, false)) {
342b7a77849SAndy Fiddaman warnx("failed with plain file fd");
343b7a77849SAndy Fiddaman ret = false;
344b7a77849SAndy Fiddaman }
345b7a77849SAndy Fiddaman
346b7a77849SAndy Fiddaman break;
347b7a77849SAndy Fiddaman
348b7a77849SAndy Fiddaman case UTIMENSAT: {
349b7a77849SAndy Fiddaman int rfd;
350b7a77849SAndy Fiddaman
351b7a77849SAndy Fiddaman printf("..... utimensat()\n");
352b7a77849SAndy Fiddaman
353b7a77849SAndy Fiddaman /* NULL path, expect EFAULT (cf. futimesat()) */
354b7a77849SAndy Fiddaman if (utimensat(fd, NULL, ts, 0) != -1 || errno != EFAULT) {
355b7a77849SAndy Fiddaman warnx("null path should return EFAULT but got %d/%s",
356b7a77849SAndy Fiddaman errno, strerror(errno));
357b7a77849SAndy Fiddaman ret = false;
358b7a77849SAndy Fiddaman }
359b7a77849SAndy Fiddaman
360b7a77849SAndy Fiddaman /* random descriptor, FQ path, descriptor is ignored */
361b7a77849SAndy Fiddaman if ((rfd = open("/dev/null", O_RDONLY)) == -1)
362b7a77849SAndy Fiddaman err(EXIT_FAILURE, "open(/dev/null)");
363b7a77849SAndy Fiddaman if (utimensat(rfd, path, ts, 0) == -1)
364b7a77849SAndy Fiddaman err(EXIT_FAILURE, "utimensat(dnfd, %s)", path);
365b7a77849SAndy Fiddaman if (!compare_filetime(path, false, atim, mtim, false)) {
366b7a77849SAndy Fiddaman warnx("failed with random descriptor, fq path");
367b7a77849SAndy Fiddaman ret = false;
368b7a77849SAndy Fiddaman }
369b7a77849SAndy Fiddaman
370b7a77849SAndy Fiddaman if (!reset(path, atim, mtim))
371b7a77849SAndy Fiddaman ret = false;
372b7a77849SAndy Fiddaman
373b7a77849SAndy Fiddaman /* repeat against symbolic link path */
374b7a77849SAndy Fiddaman if (utimensat(rfd, lpath, ts, 0) == -1)
375b7a77849SAndy Fiddaman err(EXIT_FAILURE, "utimensat(dnfd, link %s)", lpath);
376b7a77849SAndy Fiddaman if (!compare_filetime(path, false, atim, mtim, false)) {
377b7a77849SAndy Fiddaman warnx("failed against link with random descriptor, "
378b7a77849SAndy Fiddaman "fq path");
379b7a77849SAndy Fiddaman ret = false;
380b7a77849SAndy Fiddaman }
381b7a77849SAndy Fiddaman
382b7a77849SAndy Fiddaman (void) close(rfd);
383b7a77849SAndy Fiddaman
384b7a77849SAndy Fiddaman if (!reset(path, atim, mtim))
385b7a77849SAndy Fiddaman ret = false;
386b7a77849SAndy Fiddaman
387b7a77849SAndy Fiddaman /* relative to a directory */
388b7a77849SAndy Fiddaman if (utimensat(dfd, "file", ts, 0) == -1)
389*6353250fSRobert Mustacchi err(EXIT_FAILURE, "utimensat(dir, file)");
390b7a77849SAndy Fiddaman if (!compare_filetime(path, false, atim, mtim, false)) {
391b7a77849SAndy Fiddaman warnx("failed relative to a directory");
392b7a77849SAndy Fiddaman ret = false;
393b7a77849SAndy Fiddaman }
394b7a77849SAndy Fiddaman
395b7a77849SAndy Fiddaman if (!reset(path, atim, mtim))
396b7a77849SAndy Fiddaman ret = false;
397b7a77849SAndy Fiddaman
398b7a77849SAndy Fiddaman /* repeat against symbolic link path */
399b7a77849SAndy Fiddaman if (utimensat(dfd, "link", ts, 0) == -1)
400*6353250fSRobert Mustacchi err(EXIT_FAILURE, "utimensat(dir, link)");
401b7a77849SAndy Fiddaman if (!compare_filetime(path, false, atim, mtim, false)) {
402b7a77849SAndy Fiddaman warnx("failed through link relative to a directory");
403b7a77849SAndy Fiddaman ret = false;
404b7a77849SAndy Fiddaman }
405b7a77849SAndy Fiddaman
406b7a77849SAndy Fiddaman if (!reset(path, atim, mtim))
407b7a77849SAndy Fiddaman ret = false;
408b7a77849SAndy Fiddaman
409b7a77849SAndy Fiddaman /* AT_FDCWD */
410b7a77849SAndy Fiddaman if (fchdir(dfd) == -1)
411b7a77849SAndy Fiddaman err(EXIT_FAILURE, "fchdir(%s)", dir);
412b7a77849SAndy Fiddaman if (utimensat(AT_FDCWD, "file", ts, 0) == -1)
413b7a77849SAndy Fiddaman err(EXIT_FAILURE, "utimensat(AT_FDCWD, file)");
414b7a77849SAndy Fiddaman if (!compare_filetime(path, false, atim, mtim, false)) {
415b7a77849SAndy Fiddaman warnx("failed with AT_FDCWD relative");
416b7a77849SAndy Fiddaman ret = false;
417b7a77849SAndy Fiddaman }
418b7a77849SAndy Fiddaman
419b7a77849SAndy Fiddaman if (!reset(path, atim, mtim))
420b7a77849SAndy Fiddaman ret = false;
421b7a77849SAndy Fiddaman
422b7a77849SAndy Fiddaman /* repeat against symbolic link path */
423b7a77849SAndy Fiddaman if (utimensat(AT_FDCWD, "link", ts, 0) == -1)
424b7a77849SAndy Fiddaman err(EXIT_FAILURE, "utimensat(AT_FDCWD, link)");
425b7a77849SAndy Fiddaman if (!compare_filetime(path, false, atim, mtim, false)) {
426b7a77849SAndy Fiddaman warnx("failed through link with AT_FDCWD relative");
427b7a77849SAndy Fiddaman ret = false;
428b7a77849SAndy Fiddaman }
429b7a77849SAndy Fiddaman
430b7a77849SAndy Fiddaman if (!reset(path, atim, mtim))
431b7a77849SAndy Fiddaman ret = false;
432b7a77849SAndy Fiddaman
433b7a77849SAndy Fiddaman /*
434b7a77849SAndy Fiddaman * Check that none of the above operations have changed the
435b7a77849SAndy Fiddaman * timestamp on the link.
436b7a77849SAndy Fiddaman */
437b7a77849SAndy Fiddaman if (compare_linktime(lpath, true, atim, mtim, true)) {
438b7a77849SAndy Fiddaman warnx("link timestamp was unexpectedly modified");
439b7a77849SAndy Fiddaman ret = false;
440b7a77849SAndy Fiddaman }
441b7a77849SAndy Fiddaman
442b7a77849SAndy Fiddaman /* Set the time on the link, not on the target */
443b7a77849SAndy Fiddaman if (utimensat(AT_FDCWD, "link", ts, AT_SYMLINK_NOFOLLOW) == -1)
444b7a77849SAndy Fiddaman err(EXIT_FAILURE, "utimensat(AT_FDCWD, lflag)");
445b7a77849SAndy Fiddaman if (!compare_linktime(lpath, false, atim, mtim, false)) {
446b7a77849SAndy Fiddaman warnx("link time is incorrect");
447b7a77849SAndy Fiddaman ret = false;
448b7a77849SAndy Fiddaman }
449b7a77849SAndy Fiddaman if (compare_filetime(path, false, atim, mtim, true)) {
450b7a77849SAndy Fiddaman warnx("target time was updated incorrectly");
451b7a77849SAndy Fiddaman ret = false;
452b7a77849SAndy Fiddaman }
453b7a77849SAndy Fiddaman }
454b7a77849SAndy Fiddaman break;
455b7a77849SAndy Fiddaman }
456b7a77849SAndy Fiddaman
457b7a77849SAndy Fiddaman (void) close(dfd);
458b7a77849SAndy Fiddaman (void) close(lfd);
459b7a77849SAndy Fiddaman (void) close(fd);
460b7a77849SAndy Fiddaman
461b7a77849SAndy Fiddaman if (unlink(lpath) == -1)
462b7a77849SAndy Fiddaman err(EXIT_FAILURE, "unlink(%s)", lpath);
463b7a77849SAndy Fiddaman if (unlink(path) == -1)
464b7a77849SAndy Fiddaman err(EXIT_FAILURE, "unlink(%s)", path);
465b7a77849SAndy Fiddaman
466b7a77849SAndy Fiddaman if (!ret)
467b7a77849SAndy Fiddaman warnx("Test failed");
468b7a77849SAndy Fiddaman
469b7a77849SAndy Fiddaman return (ret);
470b7a77849SAndy Fiddaman }
471b7a77849SAndy Fiddaman
472b7a77849SAndy Fiddaman static bool
runtests(char * dir,timespec_t * atim,timespec_t * mtim)473b7a77849SAndy Fiddaman runtests(char *dir, timespec_t *atim, timespec_t *mtim)
474b7a77849SAndy Fiddaman {
475b7a77849SAndy Fiddaman bool ret = true;
476b7a77849SAndy Fiddaman
477b7a77849SAndy Fiddaman printf("Testing:\n... atime: %ld.%.9ld\n... mtime: %ld.%.9ld\n",
478b7a77849SAndy Fiddaman atim->tv_sec, atim->tv_nsec, mtim->tv_sec, mtim->tv_nsec);
479b7a77849SAndy Fiddaman
480b7a77849SAndy Fiddaman if (!runtest(UTIMES, dir, atim, mtim))
481b7a77849SAndy Fiddaman ret = false;
482b7a77849SAndy Fiddaman if (!runtest(LUTIMES, dir, atim, mtim))
483b7a77849SAndy Fiddaman ret = false;
484b7a77849SAndy Fiddaman if (!runtest(FUTIMES, dir, atim, mtim))
485b7a77849SAndy Fiddaman ret = false;
486b7a77849SAndy Fiddaman if (!runtest(FUTIMESAT, dir, atim, mtim))
487b7a77849SAndy Fiddaman ret = false;
488b7a77849SAndy Fiddaman if (!runtest(FUTIMENS, dir, atim, mtim))
489b7a77849SAndy Fiddaman ret = false;
490b7a77849SAndy Fiddaman if (!runtest(UTIMENSAT, dir, atim, mtim))
491b7a77849SAndy Fiddaman ret = false;
492b7a77849SAndy Fiddaman
493b7a77849SAndy Fiddaman return (ret);
494b7a77849SAndy Fiddaman }
495b7a77849SAndy Fiddaman
496b7a77849SAndy Fiddaman int
main(void)497b7a77849SAndy Fiddaman main(void)
498b7a77849SAndy Fiddaman {
499b7a77849SAndy Fiddaman char dir[] = "/tmp/utimes.XXXXXX";
500b7a77849SAndy Fiddaman int ret = EXIT_SUCCESS;
501b7a77849SAndy Fiddaman int i;
502b7a77849SAndy Fiddaman
503b7a77849SAndy Fiddaman if (mkdtemp(dir) == NULL)
504b7a77849SAndy Fiddaman err(EXIT_FAILURE, "failed to create temporary directory");
505b7a77849SAndy Fiddaman
506b7a77849SAndy Fiddaman for (i = 0; i < ARRAY_SIZE(testtimes); i += 2) {
507b7a77849SAndy Fiddaman if (!runtests(dir, &testtimes[i], &testtimes[i + 1]))
508b7a77849SAndy Fiddaman ret = EXIT_FAILURE;
509b7a77849SAndy Fiddaman }
510b7a77849SAndy Fiddaman
511b7a77849SAndy Fiddaman /*
512b7a77849SAndy Fiddaman * Some tests will have changed directory into 'dir' to test the
513b7a77849SAndy Fiddaman * AT_FDCWD case. Change back to / to avoid EBUSY when removing dir.
514b7a77849SAndy Fiddaman */
515b7a77849SAndy Fiddaman if (chdir("/") == -1)
516b7a77849SAndy Fiddaman err(EXIT_FAILURE, "chdir(/)");
517b7a77849SAndy Fiddaman if (rmdir(dir) == -1)
518b7a77849SAndy Fiddaman err(EXIT_FAILURE, "rmdir %s", dir);
519b7a77849SAndy Fiddaman
520b7a77849SAndy Fiddaman return (ret);
521b7a77849SAndy Fiddaman }
522