1 #include <assert.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "uvwasi.h"
5 #include "uv.h"
6 
7 #define TEST_TMP_DIR "./out/tmp"
8 
9 static const uvwasi_timestamp_t ONE_SECOND = 1000000000;
10 static const uvwasi_timestamp_t TIME_THRESHOLD = 5000000000;  /* 5 seconds. */
11 
check_in_threshold(uvwasi_timestamp_t first,uvwasi_timestamp_t second)12 static void check_in_threshold(uvwasi_timestamp_t first,
13                                uvwasi_timestamp_t second) {
14   if (second < first)
15     assert(first - second < ONE_SECOND);
16   else
17     assert(second - first <= TIME_THRESHOLD);
18 }
19 
main(void)20 int main(void) {
21   const char* path = "./test-filestat-set-times.txt";
22   const char* linkname = "./symlink.txt";
23   uvwasi_fd_t fd;
24   uvwasi_t uvwasi;
25   uvwasi_options_t init_options;
26   uvwasi_rights_t fs_rights_base;
27   uvwasi_filestat_t stats;
28   uvwasi_filestat_t stats2;
29   uvwasi_errno_t err;
30   size_t pathsize;
31   size_t linksize;
32   uv_fs_t req;
33   int r;
34 
35   r = uv_fs_mkdir(NULL, &req, TEST_TMP_DIR, 0777, NULL);
36   uv_fs_req_cleanup(&req);
37   assert(r == 0 || r == UV_EEXIST);
38   pathsize = strlen(path) + 1;
39   linksize = strlen(linkname) + 1;
40 
41   uvwasi_options_init(&init_options);
42   init_options.preopenc = 1;
43   init_options.preopens = calloc(1, sizeof(uvwasi_preopen_t));
44   init_options.preopens[0].mapped_path = "/var";
45   init_options.preopens[0].real_path = TEST_TMP_DIR;
46 
47   err = uvwasi_init(&uvwasi, &init_options);
48   free(init_options.preopens);
49   assert(err == 0);
50 
51   /* Create a file. */
52   fs_rights_base = UVWASI_RIGHT_FD_FILESTAT_GET |
53                    UVWASI_RIGHT_FD_FILESTAT_SET_TIMES |
54                    UVWASI_RIGHT_PATH_FILESTAT_SET_TIMES |
55                    /* Windows fails with EPERM without this. */
56                    UVWASI_RIGHT_FD_WRITE;
57   err = uvwasi_path_open(&uvwasi,
58                          3,
59                          1,
60                          path,
61                          pathsize,
62                          UVWASI_O_CREAT,
63                          fs_rights_base,
64                          0,
65                          0,
66                          &fd);
67   assert(err == 0);
68 
69   /* Create a symlink. */
70   err = uvwasi_path_symlink(&uvwasi, path, pathsize, 3, linkname, linksize);
71   assert(err == 0);
72 
73   /* Stat the file to get initial times. */
74   err = uvwasi_fd_filestat_get(&uvwasi, fd, &stats);
75   assert(err == 0);
76   assert(stats.st_filetype == UVWASI_FILETYPE_REGULAR_FILE);
77   assert(stats.st_atim > 0);
78   assert(stats.st_mtim > 0);
79   assert(stats.st_ctim > 0);
80 
81   /* Test setting file times by file descriptor. */
82 
83   /* Set the file times to a specific time. */
84   err = uvwasi_fd_filestat_set_times(&uvwasi,
85                                      fd,
86                                      1,
87                                      ONE_SECOND,
88                                      UVWASI_FILESTAT_SET_ATIM |
89                                      UVWASI_FILESTAT_SET_MTIM);
90   /* uvwasi_fd_filestat_set_times() uses uv_fs_futime(), which can return ENOSYS
91      on AIX < 7.1. In that case, skip the rest of the test. */
92   if (err == UVWASI_ENOSYS)
93     goto exit;
94 
95   assert(err == 0);
96 
97   /* Get the new file times. */
98   err = uvwasi_fd_filestat_get(&uvwasi, fd, &stats2);
99   assert(err == 0);
100   assert(stats2.st_filetype == UVWASI_FILETYPE_REGULAR_FILE);
101   assert(stats2.st_atim == 0);
102   assert(stats2.st_mtim == ONE_SECOND);
103   assert(stats2.st_ctim > 0);
104 
105   /* Set the file times, but omit both values. */
106   err = uvwasi_fd_filestat_set_times(&uvwasi,
107                                      fd,
108                                      ONE_SECOND * 5,
109                                      ONE_SECOND * 9,
110                                      0);
111 
112   /* Get the new file times - they should be the same as before. */
113   err = uvwasi_fd_filestat_get(&uvwasi, fd, &stats2);
114   assert(err == 0);
115   assert(stats2.st_filetype == UVWASI_FILETYPE_REGULAR_FILE);
116   assert(stats2.st_atim == 0);
117   assert(stats2.st_mtim == ONE_SECOND);
118   assert(stats2.st_ctim > 0);
119 
120   /* Set the file times to the current time. */
121   err = uvwasi_fd_filestat_set_times(&uvwasi,
122                                      fd,
123                                      0,
124                                      0,
125                                      UVWASI_FILESTAT_SET_ATIM_NOW |
126                                      UVWASI_FILESTAT_SET_MTIM_NOW);
127   assert(err == 0);
128 
129   /* Get the new file times. */
130   err = uvwasi_fd_filestat_get(&uvwasi, fd, &stats2);
131   assert(err == 0);
132   assert(stats2.st_filetype == UVWASI_FILETYPE_REGULAR_FILE);
133   check_in_threshold(stats.st_atim, stats2.st_atim);
134   check_in_threshold(stats.st_mtim, stats2.st_mtim);
135   assert(stats2.st_ctim > 0);
136 
137   /* Close the file. */
138   err = uvwasi_fd_close(&uvwasi, fd);
139   assert(err == 0);
140 
141   /* Test setting file times by path. */
142 
143   /* Set the file times to a specific time. */
144   err = uvwasi_path_filestat_set_times(&uvwasi,
145                                        3,
146                                        0,
147                                        path,
148                                        pathsize,
149                                        ONE_SECOND + 1,
150                                        ONE_SECOND * 3,
151                                        UVWASI_FILESTAT_SET_ATIM |
152                                        UVWASI_FILESTAT_SET_MTIM);
153   /* uvwasi_path_filestat_set_times() uses uv_fs_lutime(), which can return
154      ENOSYS on AIX < 7.1 and z/OS. In that case, skip the rest of the test. */
155   if (err == UVWASI_ENOSYS)
156     goto exit;
157 
158   assert(err == 0);
159 
160   /* Get the new file times. */
161   err = uvwasi_path_filestat_get(&uvwasi, 3, 0, path, pathsize, &stats2);
162   assert(err == 0);
163   assert(stats2.st_filetype == UVWASI_FILETYPE_REGULAR_FILE);
164   assert(stats2.st_atim == ONE_SECOND);
165   assert(stats2.st_mtim == ONE_SECOND * 3);
166   assert(stats2.st_ctim > 0);
167 
168   /* If UVWASI_LOOKUP_SYMLINK_FOLLOW is not set update the link itself. */
169   err = uvwasi_path_filestat_set_times(&uvwasi,
170                                        3,
171                                        0,
172                                        linkname,
173                                        linksize,
174                                        ONE_SECOND * 5,
175                                        ONE_SECOND * 7,
176                                        UVWASI_FILESTAT_SET_ATIM |
177                                        UVWASI_FILESTAT_SET_MTIM);
178   assert(err == 0);
179 
180   /* Get the new file times. */
181   err = uvwasi_path_filestat_get(&uvwasi, 3, 0, linkname, linksize, &stats2);
182   assert(err == 0);
183   assert(stats2.st_filetype == UVWASI_FILETYPE_SYMBOLIC_LINK);
184   assert(stats2.st_atim == ONE_SECOND * 5);
185   assert(stats2.st_mtim == ONE_SECOND * 7);
186   assert(stats2.st_ctim > 0);
187 
188   /* Updating a symlink with UVWASI_LOOKUP_SYMLINK_FOLLOW should yield results
189      identical to updating the target file. */
190   err = uvwasi_path_filestat_set_times(&uvwasi,
191                                        3,
192                                        UVWASI_LOOKUP_SYMLINK_FOLLOW,
193                                        linkname,
194                                        linksize,
195                                        ONE_SECOND * 9,
196                                        ONE_SECOND * 11,
197                                        UVWASI_FILESTAT_SET_ATIM |
198                                        UVWASI_FILESTAT_SET_MTIM);
199   assert(err == 0);
200 
201   /* Get the new file times. */
202   err = uvwasi_path_filestat_get(&uvwasi,
203                                  3,
204                                  UVWASI_LOOKUP_SYMLINK_FOLLOW,
205                                  linkname,
206                                  linksize,
207                                  &stats2);
208   assert(err == 0);
209   assert(stats2.st_filetype == UVWASI_FILETYPE_REGULAR_FILE);
210   assert(stats2.st_atim == ONE_SECOND * 9);
211   assert(stats2.st_mtim == ONE_SECOND * 11);
212   assert(stats2.st_ctim > 0);
213 
214 exit:
215   /* Unlink the files. */
216   err = uvwasi_path_unlink_file(&uvwasi, 3, path, pathsize);
217   assert(err == 0);
218   err = uvwasi_path_unlink_file(&uvwasi, 3, linkname, linksize);
219   assert(err == 0);
220 
221   /* Clean things up. */
222   uvwasi_destroy(&uvwasi);
223 
224   return 0;
225 }
226