xref: /libuv/test/test-fs-open-flags.c (revision 011a1ac1)
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