From 7fd7e8264f4430e642ac21dc386aed2f99f5f567 Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Wed, 18 Jan 2023 08:34:52 +0530 Subject: [PATCH] win,fs: fix readlink errno for a non-symlink file (#3719) In Node.js, fs.readlink() on a non-symlink file used to throw an UNKNOWN error on Windows. This change maps ERROR_NOT_A_REPARSE_POINT to UV_EINVAL, so that now it throws EINVAL just like other platforms. This is handled explicitly in `fs__readlink`, since elsewhere it might map to EPERM instead (such as in `link`). --- src/win/fs.c | 5 ++++- test/test-fs.c | 57 +++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index efc23934..1f813c3e 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -2662,7 +2662,10 @@ static void fs__readlink(uv_fs_t* req) { } if (fs__readlink_handle(handle, (char**) &req->ptr, NULL) != 0) { - SET_REQ_WIN32_ERROR(req, GetLastError()); + DWORD error = GetLastError(); + SET_REQ_WIN32_ERROR(req, error); + if (error == ERROR_NOT_A_REPARSE_POINT) + req->result = UV_EINVAL; CloseHandle(handle); return; } diff --git a/test/test-fs.c b/test/test-fs.c index ebf41050..3d7b7008 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -2047,20 +2047,53 @@ TEST_IMPL(fs_link) { TEST_IMPL(fs_readlink) { - uv_fs_t req; + /* Must return UV_ENOENT on an inexistent file */ + { + uv_fs_t req; - loop = uv_default_loop(); - ASSERT(0 == uv_fs_readlink(loop, &req, "no_such_file", dummy_cb)); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(dummy_cb_count == 1); - ASSERT_NULL(req.ptr); - ASSERT(req.result == UV_ENOENT); - uv_fs_req_cleanup(&req); + loop = uv_default_loop(); + ASSERT(0 == uv_fs_readlink(loop, &req, "no_such_file", dummy_cb)); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(dummy_cb_count == 1); + ASSERT_NULL(req.ptr); + ASSERT(req.result == UV_ENOENT); + uv_fs_req_cleanup(&req); - ASSERT(UV_ENOENT == uv_fs_readlink(NULL, &req, "no_such_file", NULL)); - ASSERT_NULL(req.ptr); - ASSERT(req.result == UV_ENOENT); - uv_fs_req_cleanup(&req); + ASSERT(UV_ENOENT == uv_fs_readlink(NULL, &req, "no_such_file", NULL)); + ASSERT_NULL(req.ptr); + ASSERT(req.result == UV_ENOENT); + uv_fs_req_cleanup(&req); + } + + /* Must return UV_EINVAL on a non-symlink file */ + { + int r; + uv_fs_t req; + uv_file file; + + /* Setup */ + + /* Create a non-symlink file */ + r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); + file = req.result; + uv_fs_req_cleanup(&req); + + r = uv_fs_close(NULL, &req, file, NULL); + ASSERT_EQ(r, 0); + ASSERT_EQ(req.result, 0); + uv_fs_req_cleanup(&req); + + /* Test */ + r = uv_fs_readlink(NULL, &req, "test_file", NULL); + ASSERT_EQ(r, UV_EINVAL); + uv_fs_req_cleanup(&req); + + /* Cleanup */ + unlink("test_file"); + } MAKE_VALGRIND_HAPPY(); return 0;