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