diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 894c98fbf0..bceb432d78 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -890,6 +890,7 @@ struct uv_fs_s { uv_fs_cb cb; ssize_t result; void* ptr; + char* path; int errorno; UV_FS_PRIVATE_FIELDS }; diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index aeeb2a83a1..7ca2275fc2 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -40,7 +40,7 @@ #define ARGS4(a,b,c,d) (a), (b), (c), (d) #define WRAP_EIO(type, eiofunc, func, args) \ - uv_fs_req_init(loop, req, type, cb); \ + uv_fs_req_init(loop, req, type, path, cb); \ if (cb) { \ /* async */ \ uv_ref(loop); \ @@ -61,7 +61,7 @@ static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req, uv_fs_type fs_type, - uv_fs_cb cb) { + char* path, uv_fs_cb cb) { /* Make sure the thread pool is initialized. */ uv_eio_init(loop); @@ -72,12 +72,16 @@ static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req, uv_fs_type fs_type, req->cb = cb; req->result = 0; req->ptr = NULL; + req->path = path ? strdup(path) : NULL; req->errorno = 0; req->eio = NULL; } void uv_fs_req_cleanup(uv_fs_t* req) { + free(req->path); + req->path = NULL; + switch (req->fs_type) { case UV_FS_READDIR: assert(req->ptr); @@ -168,13 +172,14 @@ static int uv__fs_after(eio_req* eio) { int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { + char* path = NULL; WRAP_EIO(UV_FS_CLOSE, eio_close, close, ARGS1(file)); } int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int mode, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_OPEN, cb); + uv_fs_req_init(loop, req, UV_FS_OPEN, path, cb); if (cb) { /* async */ @@ -202,7 +207,7 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file fd, void* buf, size_t length, off_t offset, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_READ, cb); + uv_fs_req_init(loop, req, UV_FS_READ, NULL, cb); if (cb) { /* async */ @@ -238,7 +243,7 @@ int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, void* buf, size_t length, off_t offset, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_WRITE, cb); + uv_fs_req_init(loop, req, UV_FS_WRITE, NULL, cb); if (cb) { /* async */ @@ -284,7 +289,7 @@ int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, size_t size = 0; size_t d_namlen = 0; - uv_fs_req_init(loop, req, UV_FS_READDIR, cb); + uv_fs_req_init(loop, req, UV_FS_READDIR, path, cb); if (cb) { /* async */ @@ -340,7 +345,7 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { char* pathdup = path; int pathlen; - uv_fs_req_init(loop, req, UV_FS_STAT, cb); + uv_fs_req_init(loop, req, UV_FS_STAT, path, cb); /* TODO do this without duplicating the string. */ /* TODO security */ @@ -383,7 +388,7 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_FSTAT, cb); + uv_fs_req_init(loop, req, UV_FS_FSTAT, NULL, cb); if (cb) { /* async */ @@ -418,23 +423,27 @@ int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* ne int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { + char* path = NULL; WRAP_EIO(UV_FS_FSYNC, eio_fsync, fsync, ARGS1(file)) } int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { + char* path = NULL; WRAP_EIO(UV_FS_FDATASYNC, eio_fdatasync, fdatasync, ARGS1(file)) } int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file file, off_t offset, uv_fs_cb cb) { + char* path = NULL; WRAP_EIO(UV_FS_FTRUNCATE, eio_ftruncate, ftruncate, ARGS2(file, offset)) } int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd, uv_file in_fd, off_t in_offset, size_t length, uv_fs_cb cb) { + char* path = NULL; WRAP_EIO(UV_FS_SENDFILE, eio_sendfile, eio_sendfile_sync, ARGS4(out_fd, in_fd, in_offset, length)) } @@ -471,7 +480,7 @@ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { char* pathdup = path; int pathlen; - uv_fs_req_init(loop, req, UV_FS_LSTAT, cb); + uv_fs_req_init(loop, req, UV_FS_LSTAT, path, cb); /* TODO do this without duplicating the string. */ /* TODO security */ @@ -533,7 +542,7 @@ int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, status = -1; - uv_fs_req_init(loop, req, UV_FS_READLINK, cb); + uv_fs_req_init(loop, req, UV_FS_READLINK, path, cb); if (cb) { if ((req->eio = eio_readlink(path, EIO_PRI_DEFAULT, uv__fs_after, req))) { @@ -581,6 +590,7 @@ int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file, int mode, uv_fs_cb cb) { + char* path = NULL; WRAP_EIO(UV_FS_FCHMOD, eio_fchmod, fchmod, ARGS2(file, mode)) } @@ -593,6 +603,7 @@ int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, int uid, int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, int uid, int gid, uv_fs_cb cb) { + char* path = NULL; WRAP_EIO(UV_FS_FCHOWN, eio_fchown, fchown, ARGS3(file, uid, gid)) } diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 770b4df1fb..4cc597c392 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -97,6 +97,7 @@ static void uv_fs_req_init_async(uv_loop_t* loop, uv_fs_t* req, req->cb = cb; req->result = 0; req->ptr = NULL; + req->path = NULL; /* TODO https://github.com/joyent/libuv/issues/177 */ req->errorno = 0; req->last_error = 0; memset(&req->overlapped, 0, sizeof(req->overlapped)); @@ -115,13 +116,120 @@ static void uv_fs_req_init_sync(uv_loop_t* loop, uv_fs_t* req, req->errorno = 0; } +/* this is where the CRT stores the current umask */ +extern int _umaskval; void fs__open(uv_fs_t* req, const char* path, int flags, int mode) { - int result = _open(path, flags, mode); + DWORD access; + DWORD share; + SECURITY_ATTRIBUTES sa; + DWORD disposition; + DWORD attributes; + HANDLE file; + int result; + + /* convert flags and mode to CreateFile parameters */ + switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) { + case _O_RDONLY: + access = GENERIC_READ; + break; + case _O_WRONLY: + access = GENERIC_WRITE; + break; + case _O_RDWR: + access = GENERIC_READ | GENERIC_WRITE; + break; + default: + result = -1; + goto end; + } + + /* + * Here is where we deviate significantly from what CRT's _open() + * does. We indiscriminately use all the sharing modes, to match + * UNIX semantics. In particular, this ensures that the file can + * be deleted even whilst it's open, fixing issue #1449. + */ + share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + if (flags & _O_NOINHERIT) { + sa.bInheritHandle = FALSE; + } else { + sa.bInheritHandle = TRUE; + } + + switch (flags & (_O_CREAT | _O_EXCL | _O_TRUNC)) { + case 0: + case _O_EXCL: + disposition = OPEN_EXISTING; + break; + case _O_CREAT: + disposition = OPEN_ALWAYS; + break; + case _O_CREAT | _O_EXCL: + case _O_CREAT | _O_TRUNC | _O_EXCL: + disposition = CREATE_NEW; + break; + case _O_TRUNC: + case _O_TRUNC | _O_EXCL: + disposition = TRUNCATE_EXISTING; + break; + case _O_CREAT | _O_TRUNC: + disposition = CREATE_ALWAYS; + break; + default: + result = -1; + goto end; + } + + attributes = FILE_ATTRIBUTE_NORMAL; + if (flags & _O_CREAT) { + if (!((mode & ~_umaskval) & _S_IWRITE)) { + attributes |= FILE_ATTRIBUTE_READONLY; + } + } + + if (flags & _O_TEMPORARY ) { + attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY; + access |= DELETE; + } + + if (flags & _O_SHORT_LIVED) { + attributes |= FILE_ATTRIBUTE_TEMPORARY; + } + + switch (flags & (_O_SEQUENTIAL | _O_RANDOM)) { + case 0: + break; + case _O_SEQUENTIAL: + attributes |= FILE_FLAG_SEQUENTIAL_SCAN; + break; + case _O_RANDOM: + attributes |= FILE_FLAG_RANDOM_ACCESS; + break; + default: + result = -1; + goto end; + } + + file = CreateFileA(path, + access, + share, + &sa, + disposition, + attributes, + NULL); + if (file == INVALID_HANDLE_VALUE) { + result = -1; + goto end; + } + result = _open_osfhandle((intptr_t)file, flags); +end: SET_REQ_RESULT(req, result); } - void fs__close(uv_fs_t* req, uv_file file) { int result = _close(file); SET_REQ_RESULT(req, result); diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index f9c65787ed..1e119b6aea 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -240,6 +240,8 @@ static void open_cb(uv_fs_t* req) { ASSERT(0); } open_cb_count++; + ASSERT(req->path); + ASSERT(memcmp(req->path, "test_file2\0", 11) == 0); uv_fs_req_cleanup(req); memset(buf, 0, sizeof(buf)); r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf), -1, @@ -306,6 +308,8 @@ static void mkdir_cb(uv_fs_t* req) { ASSERT(req->fs_type == UV_FS_MKDIR); ASSERT(req->result != -1); mkdir_cb_count++; + ASSERT(req->path); + ASSERT(memcmp(req->path, "test_dir\0", 9) == 0); uv_fs_req_cleanup(req); } @@ -315,6 +319,8 @@ static void rmdir_cb(uv_fs_t* req) { ASSERT(req->fs_type == UV_FS_RMDIR); ASSERT(req->result != -1); rmdir_cb_count++; + ASSERT(req->path); + ASSERT(memcmp(req->path, "test_dir\0", 9) == 0); uv_fs_req_cleanup(req); } @@ -327,6 +333,8 @@ static void readdir_cb(uv_fs_t* req) { ASSERT(memcmp(req->ptr, "file1\0file2\0", 12) == 0 || memcmp(req->ptr, "file2\0file1\0", 12) == 0); readdir_cb_count++; + ASSERT(req->path); + ASSERT(memcmp(req->path, "test_dir\0", 9) == 0); uv_fs_req_cleanup(req); ASSERT(!req->ptr); } @@ -544,6 +552,7 @@ TEST_IMPL(fs_async_dir) { r = uv_fs_readdir(loop, &readdir_req, "test_dir", 0, NULL); readdir_cb(&readdir_req); + r = uv_fs_stat(loop, &stat_req, "test_dir", stat_cb); ASSERT(r == 0); uv_run(loop);