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 | |
61 | static 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 | |
76 | static 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 | |
122 | static void cleanup() { |
123 | unlink(absent_file); |
124 | unlink(empty_file); |
125 | unlink(dummy_file); |
126 | } |
127 | |
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(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 | |
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(r >= 0); |
154 | ASSERT(open_req.result >= 0); |
155 | uv_fs_req_cleanup(&open_req); |
156 | } |
157 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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_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 | } |
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(); |
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 | |