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
38 static int flags;
39
40 static uv_fs_t close_req;
41 static uv_fs_t mkdir_req;
42 static uv_fs_t open_req;
43 static uv_fs_t read_req;
44 static uv_fs_t rmdir_req;
45 static uv_fs_t unlink_req;
46 static uv_fs_t write_req;
47
48 static char buf[32];
49 static 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 */
53 static int sid = 0;
54
55 #define FILE_NAME_SIZE 128
56 static char absent_file[FILE_NAME_SIZE];
57 static char empty_file[FILE_NAME_SIZE];
58 static char dummy_file[FILE_NAME_SIZE];
59 static char empty_dir[] = "empty_dir";
60
setup(void)61 static void setup(void) {
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_OK(r);
72 ASSERT_OK(mkdir_req.result);
73 uv_fs_req_cleanup(&mkdir_req);
74 }
75
refresh(void)76 static void refresh(void) {
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_GE(r, 0);
93 ASSERT_GE(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_OK(r);
98 ASSERT_OK(close_req.result);
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_GE(r, 0);
107 ASSERT_GE(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_EQ(1, r);
113 ASSERT_EQ(1, write_req.result);
114 uv_fs_req_cleanup(&write_req);
115
116 r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
117 ASSERT_OK(r);
118 ASSERT_OK(close_req.result);
119 uv_fs_req_cleanup(&close_req);
120 }
121
cleanup(void)122 static void cleanup(void) {
123 unlink(absent_file);
124 unlink(empty_file);
125 unlink(dummy_file);
126 }
127
openFail(char * file,int error)128 static 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_EQ(r, error);
135 ASSERT_EQ(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_EQ(r, error);
141 ASSERT_EQ(open_req.result, error);
142 uv_fs_req_cleanup(&open_req);
143
144 cleanup();
145 }
146
refreshOpen(char * file)147 static 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_GE(r, 0);
154 ASSERT_GE(open_req.result, 0);
155 uv_fs_req_cleanup(&open_req);
156 }
157
writeExpect(char * file,char * expected,int size)158 static 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_EQ(1, r);
166 ASSERT_EQ(1, write_req.result);
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_EQ(1, r);
172 ASSERT_EQ(1, write_req.result);
173 uv_fs_req_cleanup(&write_req);
174
175 r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
176 ASSERT_OK(r);
177 ASSERT_OK(close_req.result);
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_GE(r, 0);
183 ASSERT_GE(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_EQ(r, size);
189 ASSERT_EQ(read_req.result, size);
190 ASSERT_OK(strncmp(buf, expected, size));
191 uv_fs_req_cleanup(&read_req);
192
193 r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
194 ASSERT_OK(r);
195 ASSERT_OK(close_req.result);
196 uv_fs_req_cleanup(&close_req);
197
198 cleanup();
199 }
200
writeFail(char * file,int error)201 static 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_EQ(r, error);
209 ASSERT_EQ(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_EQ(r, error);
215 ASSERT_EQ(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_OK(r);
220 ASSERT_OK(close_req.result);
221 uv_fs_req_cleanup(&close_req);
222
223 cleanup();
224 }
225
readExpect(char * file,char * expected,int size)226 static 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_EQ(r, size);
234 ASSERT_EQ(read_req.result, size);
235 ASSERT_OK(strncmp(buf, expected, size));
236 uv_fs_req_cleanup(&read_req);
237
238 r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
239 ASSERT_OK(r);
240 ASSERT_OK(close_req.result);
241 uv_fs_req_cleanup(&close_req);
242
243 cleanup();
244 }
245
readFail(char * file,int error)246 static 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_EQ(r, error);
254 ASSERT_EQ(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_EQ(r, error);
260 ASSERT_EQ(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_OK(r);
265 ASSERT_OK(close_req.result);
266 uv_fs_req_cleanup(&close_req);
267
268 cleanup();
269 }
270
fs_open_flags(int add_flags)271 static 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_EBADF);
280 readExpect(empty_file, "", 0);
281 writeFail(dummy_file, UV_EBADF);
282 readExpect(dummy_file, "a", 1);
283 writeFail(empty_dir, UV_EBADF);
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_EBADF);
290 readExpect(empty_file, "", 0);
291 writeFail(dummy_file, UV_EBADF);
292 readExpect(dummy_file, "a", 1);
293 writeFail(empty_dir, UV_EBADF);
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_EBADF);
320 writeExpect(empty_file, "bc", 2);
321 readFail(empty_file, UV_EBADF);
322 writeExpect(dummy_file, "bc", 2);
323 readFail(dummy_file, UV_EBADF);
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_EBADF);
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_EBADF);
358 writeExpect(empty_file, "bc", 2);
359 readFail(empty_file, UV_EBADF);
360 writeExpect(dummy_file, "abc", 3);
361 readFail(dummy_file, UV_EBADF);
362 writeFail(empty_dir, UV_EISDIR);
363 readFail(empty_dir, UV_EBADF);
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_EBADF);
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_EBADF);
379 writeExpect(empty_file, "bc", 2);
380 readFail(empty_file, UV_EBADF);
381 writeExpect(dummy_file, "abc", 3);
382 readFail(dummy_file, UV_EBADF);
383 writeFail(empty_dir, UV_EISDIR);
384 readFail(empty_dir, UV_EBADF);
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 }
TEST_IMPL(fs_open_flags)418 TEST_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(uv_default_loop());
428 return 0;
429 }
430
431 #else
432
433 typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */
434
435 #endif /* ifndef _WIN32 */
436