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