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