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(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(r == 0);
72  ASSERT(mkdir_req.result == 0);
73  uv_fs_req_cleanup(&mkdir_req);
74}
75
76static 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(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(void) {
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_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}
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