1/* Copyright libuv project contributors. All rights reserved.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to
5 * deal in the Software without restriction, including without limitation the
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 * IN THE SOFTWARE.
20 */
21
22#ifdef _WIN32
23
24#include "uv.h"
25#include "task.h"
26
27#if defined(__unix__) || defined(__POSIX__) || \
28 defined(__APPLE__) || defined(__sun) || \
29 defined(_AIX) || defined(__MVS__) || \
30 defined(__HAIKU__)
31# include <unistd.h> /* unlink, rmdir */
32#else
33# include <direct.h>
34# define rmdir _rmdir
35# define unlink _unlink
36#endif
37
38static int flags;
39
40static uv_fs_t close_req;
41static uv_fs_t mkdir_req;
42static uv_fs_t open_req;
43static uv_fs_t read_req;
44static uv_fs_t rmdir_req;
45static uv_fs_t unlink_req;
46static uv_fs_t write_req;
47
48static char buf[32];
49static uv_buf_t iov;
50
51/* Opening the same file multiple times quickly can cause uv_fs_open to fail
52 * with EBUSY, so append an identifier to the file name for each operation */
53static int sid = 0;
54
55#define FILE_NAME_SIZE 128
56static char absent_file[FILE_NAME_SIZE];
57static char empty_file[FILE_NAME_SIZE];
58static char dummy_file[FILE_NAME_SIZE];
59static char empty_dir[] = "empty_dir";
60
61static void setup() {
62 int r;
63
64 /* empty_dir */
65 r = uv_fs_rmdir(NULL, &rmdir_req, empty_dir, NULL);
66 ASSERT(r == 0 || r == UV_ENOENT);
67 ASSERT(rmdir_req.result == 0 || rmdir_req.result == UV_ENOENT);
68 uv_fs_req_cleanup(&rmdir_req);
69
70 r = uv_fs_mkdir(NULL, &mkdir_req, empty_dir, 0755, NULL);
71 ASSERT(r == 0);
72 ASSERT(mkdir_req.result == 0);
73 uv_fs_req_cleanup(&mkdir_req);
74}
75
76static void refresh() {
77 int r;
78
79 /* absent_file */
80 sprintf(absent_file, "test_file_%d", sid++);
81
82 r = uv_fs_unlink(NULL, &unlink_req, absent_file, NULL);
83 ASSERT(r == 0 || r == UV_ENOENT);
84 ASSERT(unlink_req.result == 0 || unlink_req.result == UV_ENOENT);
85 uv_fs_req_cleanup(&unlink_req);
86
87 /* empty_file */
88 sprintf(empty_file, "test_file_%d", sid++);
89
90 r = uv_fs_open(NULL, &open_req, empty_file,
91 UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY, S_IWUSR | S_IRUSR, NULL);
92 ASSERT(r >= 0);
93 ASSERT(open_req.result >= 0);
94 uv_fs_req_cleanup(&open_req);
95
96 r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
97 ASSERT(r == 0);
98 ASSERT(close_req.result == 0);
99 uv_fs_req_cleanup(&close_req);
100
101 /* dummy_file */
102 sprintf(dummy_file, "test_file_%d", sid++);
103
104 r = uv_fs_open(NULL, &open_req, dummy_file,
105 UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY, S_IWUSR | S_IRUSR, NULL);
106 ASSERT(r >= 0);
107 ASSERT(open_req.result >= 0);
108 uv_fs_req_cleanup(&open_req);
109
110 iov = uv_buf_init("a", 1);
111 r = uv_fs_write(NULL, &write_req, open_req.result, &iov, 1, -1, NULL);
112 ASSERT(r == 1);
113 ASSERT(write_req.result == 1);
114 uv_fs_req_cleanup(&write_req);
115
116 r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
117 ASSERT(r == 0);
118 ASSERT(close_req.result == 0);
119 uv_fs_req_cleanup(&close_req);
120}
121
122static void cleanup() {
123 unlink(absent_file);
124 unlink(empty_file);
125 unlink(dummy_file);
126}
127
128static void openFail(char *file, int error) {
129 int r;
130
131 refresh();
132
133 r = uv_fs_open(NULL, &open_req, file, flags, S_IWUSR | S_IRUSR, NULL);
134 ASSERT(r == error);
135 ASSERT(open_req.result == error);
136 uv_fs_req_cleanup(&open_req);
137
138 /* Ensure the first call does not create the file */
139 r = uv_fs_open(NULL, &open_req, file, flags, S_IWUSR | S_IRUSR, NULL);
140 ASSERT(r == error);
141 ASSERT(open_req.result == error);
142 uv_fs_req_cleanup(&open_req);
143
144 cleanup();
145}
146
147static void refreshOpen(char *file) {
148 int r;
149
150 refresh();
151
152 r = uv_fs_open(NULL, &open_req, file, flags, S_IWUSR | S_IRUSR, NULL);
153 ASSERT(r >= 0);
154 ASSERT(open_req.result >= 0);
155 uv_fs_req_cleanup(&open_req);
156}
157
158static void writeExpect(char *file, char *expected, int size) {
159 int r;
160
161 refreshOpen(file);
162
163 iov = uv_buf_init("b", 1);
164 r = uv_fs_write(NULL, &write_req, open_req.result, &iov, 1, -1, NULL);
165 ASSERT(r == 1);
166 ASSERT(write_req.result == 1);
167 uv_fs_req_cleanup(&write_req);
168
169 iov = uv_buf_init("c", 1);
170 r = uv_fs_write(NULL, &write_req, open_req.result, &iov, 1, -1, NULL);
171 ASSERT(r == 1);
172 ASSERT(write_req.result == 1);
173 uv_fs_req_cleanup(&write_req);
174
175 r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
176 ASSERT(r == 0);
177 ASSERT(close_req.result == 0);
178 uv_fs_req_cleanup(&close_req);
179
180 /* Check contents */
181 r = uv_fs_open(NULL, &open_req, file, UV_FS_O_RDONLY, S_IWUSR | S_IRUSR, NULL);
182 ASSERT(r >= 0);
183 ASSERT(open_req.result >= 0);
184 uv_fs_req_cleanup(&open_req);
185
186 iov = uv_buf_init(buf, sizeof(buf));
187 r = uv_fs_read(NULL, &read_req, open_req.result, &iov, 1, -1, NULL);
188 ASSERT(r == size);
189 ASSERT(read_req.result == size);
190 ASSERT(strncmp(buf, expected, size) == 0);
191 uv_fs_req_cleanup(&read_req);
192
193 r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
194 ASSERT(r == 0);
195 ASSERT(close_req.result == 0);
196 uv_fs_req_cleanup(&close_req);
197
198 cleanup();
199}
200
201static void writeFail(char *file, int error) {
202 int r;
203
204 refreshOpen(file);
205
206 iov = uv_buf_init("z", 1);
207 r = uv_fs_write(NULL, &write_req, open_req.result, &iov, 1, -1, NULL);
208 ASSERT(r == error);
209 ASSERT(write_req.result == error);
210 uv_fs_req_cleanup(&write_req);
211
212 iov = uv_buf_init("z", 1);
213 r = uv_fs_write(NULL, &write_req, open_req.result, &iov, 1, -1, NULL);
214 ASSERT(r == error);
215 ASSERT(write_req.result == error);
216 uv_fs_req_cleanup(&write_req);
217
218 r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
219 ASSERT(r == 0);
220 ASSERT(close_req.result == 0);
221 uv_fs_req_cleanup(&close_req);
222
223 cleanup();
224}
225
226static void readExpect(char *file, char *expected, int size) {
227 int r;
228
229 refreshOpen(file);
230
231 iov = uv_buf_init(buf, sizeof(buf));
232 r = uv_fs_read(NULL, &read_req, open_req.result, &iov, 1, -1, NULL);
233 ASSERT(r == size);
234 ASSERT(read_req.result == size);
235 ASSERT(strncmp(buf, expected, size) == 0);
236 uv_fs_req_cleanup(&read_req);
237
238 r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
239 ASSERT(r == 0);
240 ASSERT(close_req.result == 0);
241 uv_fs_req_cleanup(&close_req);
242
243 cleanup();
244}
245
246static void readFail(char *file, int error) {
247 int r;
248
249 refreshOpen(file);
250
251 iov = uv_buf_init(buf, sizeof(buf));
252 r = uv_fs_read(NULL, &read_req, open_req.result, &iov, 1, -1, NULL);
253 ASSERT(r == error);
254 ASSERT(read_req.result == error);
255 uv_fs_req_cleanup(&read_req);
256
257 iov = uv_buf_init(buf, sizeof(buf));
258 r = uv_fs_read(NULL, &read_req, open_req.result, &iov, 1, -1, NULL);
259 ASSERT(r == error);
260 ASSERT(read_req.result == error);
261 uv_fs_req_cleanup(&read_req);
262
263 r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
264 ASSERT(r == 0);
265 ASSERT(close_req.result == 0);
266 uv_fs_req_cleanup(&close_req);
267
268 cleanup();
269}
270
271static void fs_open_flags(int add_flags) {
272 /* Follow the order from
273 * https://github.com/nodejs/node/blob/1a96abe849/lib/internal/fs/utils.js#L329-L354
274 */
275
276 /* r */
277 flags = add_flags | UV_FS_O_RDONLY;
278 openFail(absent_file, UV_ENOENT);
279 writeFail(empty_file, UV_EPERM);
280 readExpect(empty_file, "", 0);
281 writeFail(dummy_file, UV_EPERM);
282 readExpect(dummy_file, "a", 1);
283 writeFail(empty_dir, UV_EPERM);
284 readFail(empty_dir, UV_EISDIR);
285
286 /* rs */
287 flags = add_flags | UV_FS_O_RDONLY | UV_FS_O_SYNC;
288 openFail(absent_file, UV_ENOENT);
289 writeFail(empty_file, UV_EPERM);
290 readExpect(empty_file, "", 0);
291 writeFail(dummy_file, UV_EPERM);
292 readExpect(dummy_file, "a", 1);
293 writeFail(empty_dir, UV_EPERM);
294 readFail(empty_dir, UV_EISDIR);
295
296 /* r+ */
297 flags = add_flags | UV_FS_O_RDWR;
298 openFail(absent_file, UV_ENOENT);
299 writeExpect(empty_file, "bc", 2);
300 readExpect(empty_file, "", 0);
301 writeExpect(dummy_file, "bc", 2);
302 readExpect(dummy_file, "a", 1);
303 writeFail(empty_dir, UV_EISDIR);
304 readFail(empty_dir, UV_EISDIR);
305
306 /* rs+ */
307 flags = add_flags | UV_FS_O_RDWR | UV_FS_O_SYNC;
308 openFail(absent_file, UV_ENOENT);
309 writeExpect(empty_file, "bc", 2);
310 readExpect(empty_file, "", 0);
311 writeExpect(dummy_file, "bc", 2);
312 readExpect(dummy_file, "a", 1);
313 writeFail(empty_dir, UV_EISDIR);
314 readFail(empty_dir, UV_EISDIR);
315
316 /* w */
317 flags = add_flags | UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY;
318 writeExpect(absent_file, "bc", 2);
319 readFail(absent_file, UV_EPERM);
320 writeExpect(empty_file, "bc", 2);
321 readFail(empty_file, UV_EPERM);
322 writeExpect(dummy_file, "bc", 2);
323 readFail(dummy_file, UV_EPERM);
324 openFail(empty_dir, UV_EISDIR);
325
326 /* wx */
327 flags = add_flags | UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY |
328 UV_FS_O_EXCL;
329 writeExpect(absent_file, "bc", 2);
330 readFail(absent_file, UV_EPERM);
331 openFail(empty_file, UV_EEXIST);
332 openFail(dummy_file, UV_EEXIST);
333 openFail(empty_dir, UV_EEXIST);
334
335 /* w+ */
336 flags = add_flags | UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_RDWR;
337 writeExpect(absent_file, "bc", 2);
338 readExpect(absent_file, "", 0);
339 writeExpect(empty_file, "bc", 2);
340 readExpect(empty_file, "", 0);
341 writeExpect(dummy_file, "bc", 2);
342 readExpect(dummy_file, "", 0);
343 openFail(empty_dir, UV_EISDIR);
344
345 /* wx+ */
346 flags = add_flags | UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_RDWR |
347 UV_FS_O_EXCL;
348 writeExpect(absent_file, "bc", 2);
349 readExpect(absent_file, "", 0);
350 openFail(empty_file, UV_EEXIST);
351 openFail(dummy_file, UV_EEXIST);
352 openFail(empty_dir, UV_EEXIST);
353
354 /* a */
355 flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_WRONLY;
356 writeExpect(absent_file, "bc", 2);
357 readFail(absent_file, UV_EPERM);
358 writeExpect(empty_file, "bc", 2);
359 readFail(empty_file, UV_EPERM);
360 writeExpect(dummy_file, "abc", 3);
361 readFail(dummy_file, UV_EPERM);
362 writeFail(empty_dir, UV_EISDIR);
363 readFail(empty_dir, UV_EPERM);
364
365 /* ax */
366 flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_WRONLY |
367 UV_FS_O_EXCL;
368 writeExpect(absent_file, "bc", 2);
369 readFail(absent_file, UV_EPERM);
370 openFail(empty_file, UV_EEXIST);
371 openFail(dummy_file, UV_EEXIST);
372 openFail(empty_dir, UV_EEXIST);
373
374 /* as */
375 flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_WRONLY |
376 UV_FS_O_SYNC;
377 writeExpect(absent_file, "bc", 2);
378 readFail(absent_file, UV_EPERM);
379 writeExpect(empty_file, "bc", 2);
380 readFail(empty_file, UV_EPERM);
381 writeExpect(dummy_file, "abc", 3);
382 readFail(dummy_file, UV_EPERM);
383 writeFail(empty_dir, UV_EISDIR);
384 readFail(empty_dir, UV_EPERM);
385
386 /* a+ */
387 flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_RDWR;
388 writeExpect(absent_file, "bc", 2);
389 readExpect(absent_file, "", 0);
390 writeExpect(empty_file, "bc", 2);
391 readExpect(empty_file, "", 0);
392 writeExpect(dummy_file, "abc", 3);
393 readExpect(dummy_file, "a", 1);
394 writeFail(empty_dir, UV_EISDIR);
395 readFail(empty_dir, UV_EISDIR);
396
397 /* ax+ */
398 flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_RDWR |
399 UV_FS_O_EXCL;
400 writeExpect(absent_file, "bc", 2);
401 readExpect(absent_file, "", 0);
402 openFail(empty_file, UV_EEXIST);
403 openFail(dummy_file, UV_EEXIST);
404 openFail(empty_dir, UV_EEXIST);
405
406 /* as+ */
407 flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_RDWR |
408 UV_FS_O_SYNC;
409 writeExpect(absent_file, "bc", 2);
410 readExpect(absent_file, "", 0);
411 writeExpect(empty_file, "bc", 2);
412 readExpect(empty_file, "", 0);
413 writeExpect(dummy_file, "abc", 3);
414 readExpect(dummy_file, "a", 1);
415 writeFail(empty_dir, UV_EISDIR);
416 readFail(empty_dir, UV_EISDIR);
417}
418TEST_IMPL(fs_open_flags) {
419 setup();
420
421 fs_open_flags(0);
422 fs_open_flags(UV_FS_O_FILEMAP);
423
424 /* Cleanup. */
425 rmdir(empty_dir);
426
427 MAKE_VALGRIND_HAPPY();
428 return 0;
429}
430
431#else
432
433typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */
434
435#endif /* ifndef _WIN32 */
436