1 /* futimesat basic tests.
2 Copyright (C) 2021-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19 #include <dirent.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <sys/stat.h>
27 #include <sys/time.h>
28
29 #include <support/test-driver.h>
30 #include <support/temp_file.h>
31
32 #ifndef struct_stat
33 # define struct_stat struct stat64
34 # define fstat fstat64
35 # define fstatat fstatat64
36 #endif
37
38 static int dir_fd;
39
40 static void
prepare(int argc,char * argv[])41 prepare (int argc, char *argv[])
42 {
43 size_t test_dir_len = strlen (test_dir);
44 static const char dir_name[] = "/tst-futimesat.XXXXXX";
45
46 size_t dirbuflen = test_dir_len + sizeof (dir_name);
47 char *dirbuf = malloc (dirbuflen);
48 if (dirbuf == NULL)
49 {
50 puts ("out of memory");
51 exit (1);
52 }
53
54 snprintf (dirbuf, dirbuflen, "%s%s", test_dir, dir_name);
55 if (mkdtemp (dirbuf) == NULL)
56 {
57 puts ("cannot create temporary directory");
58 exit (1);
59 }
60
61 add_temp_file (dirbuf);
62
63 dir_fd = open (dirbuf, O_RDONLY | O_DIRECTORY);
64 if (dir_fd == -1)
65 {
66 puts ("cannot open directory");
67 exit (1);
68 }
69 }
70 #define PREPARE prepare
71
72 static int
do_test(void)73 do_test (void)
74 {
75 /* fdopendir takes over the descriptor, make a copy. */
76 int dupfd = dup (dir_fd);
77 if (dupfd == -1)
78 {
79 puts ("dup failed");
80 return 1;
81 }
82 if (lseek (dupfd, 0, SEEK_SET) != 0)
83 {
84 puts ("1st lseek failed");
85 return 1;
86 }
87
88 /* The directory should be empty safe the . and .. files. */
89 DIR *dir = fdopendir (dupfd);
90 if (dir == NULL)
91 {
92 puts ("fdopendir failed");
93 return 1;
94 }
95 struct dirent64 *d;
96 while ((d = readdir64 (dir)) != NULL)
97 if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0)
98 {
99 printf ("temp directory contains file \"%s\"\n", d->d_name);
100 return 1;
101 }
102 closedir (dir);
103
104 /* Try to create a file. */
105 int fd = openat (dir_fd, "some-file", O_CREAT|O_RDWR|O_EXCL, 0666);
106 if (fd == -1)
107 {
108 if (errno == ENOSYS)
109 {
110 puts ("*at functions not supported");
111 return 0;
112 }
113
114 puts ("file creation failed");
115 return 1;
116 }
117 write (fd, "hello", 5);
118 puts ("file created");
119
120 struct_stat st1;
121 if (fstat (fd, &st1) != 0)
122 {
123 puts ("fstat64 failed");
124 return 1;
125 }
126
127 close (fd);
128
129 struct timeval tv[2];
130 tv[0].tv_sec = st1.st_atime + 1;
131 tv[0].tv_usec = 0;
132 tv[1].tv_sec = st1.st_mtime + 1;
133 tv[1].tv_usec = 0;
134 if (futimesat (dir_fd, "some-file", tv) != 0)
135 {
136 puts ("futimesat failed");
137 return 1;
138 }
139
140 struct_stat st2;
141 if (fstatat (dir_fd, "some-file", &st2, 0) != 0)
142 {
143 puts ("fstatat64 failed");
144 return 1;
145 }
146
147 if (st2.st_mtime != tv[1].tv_sec
148 #ifdef _STATBUF_ST_NSEC
149 || st2.st_mtim.tv_nsec != 0
150 #endif
151 )
152 {
153 puts ("stat shows different mtime");
154 return 1;
155 }
156
157
158 if (unlinkat (dir_fd, "some-file", 0) != 0)
159 {
160 puts ("unlinkat failed");
161 return 1;
162 }
163
164 close (dir_fd);
165
166 return 0;
167 }
168
169 #include <support/test-driver.c>
170