diff --git a/src/win/error.c b/src/win/error.c index c512f35af97..642d1112e11 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -71,6 +71,7 @@ int uv_translate_sys_error(int sys_errno) { switch (sys_errno) { case ERROR_NOACCESS: return UV_EACCES; case WSAEACCES: return UV_EACCES; + case ERROR_ELEVATION_REQUIRED: return UV_EACCES; case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE; case WSAEADDRINUSE: return UV_EADDRINUSE; case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL; diff --git a/test/elevation.c b/test/elevation.c new file mode 100644 index 00000000000..11b7fad8eca --- /dev/null +++ b/test/elevation.c @@ -0,0 +1,3 @@ +int main(int argc, char **argv) { + return 0; +} diff --git a/test/test-error.c b/test/test-error.c index 4c4efa30cdd..ff53eb1d777 100644 --- a/test/test-error.c +++ b/test/test-error.c @@ -53,6 +53,7 @@ TEST_IMPL(error_message) { TEST_IMPL(sys_error) { #if defined(_WIN32) ASSERT(uv_translate_sys_error(ERROR_NOACCESS) == UV_EACCES); + ASSERT(uv_translate_sys_error(ERROR_ELEVATION_REQUIRED) == UV_EACCES); ASSERT(uv_translate_sys_error(WSAEADDRINUSE) == UV_EADDRINUSE); ASSERT(uv_translate_sys_error(ERROR_BAD_PIPE) == UV_EPIPE); #else diff --git a/test/test-list.h b/test/test-list.h index be3f9069cc7..dce8d0aa24f 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -230,6 +230,9 @@ TEST_DECLARE (spawn_fails) #ifndef _WIN32 TEST_DECLARE (spawn_fails_check_for_waitpid_cleanup) #endif +#ifdef _WIN32 +TEST_DECLARE (spawn_requires_elevation) +#endif TEST_DECLARE (spawn_exit_code) TEST_DECLARE (spawn_stdout) TEST_DECLARE (spawn_stdin) @@ -656,6 +659,9 @@ TASK_LIST_START TEST_ENTRY (spawn_fails) #ifndef _WIN32 TEST_ENTRY (spawn_fails_check_for_waitpid_cleanup) +#endif +#ifdef _WIN32 + TEST_ENTRY (spawn_requires_elevation) #endif TEST_ENTRY (spawn_exit_code) TEST_ENTRY (spawn_stdout) diff --git a/test/test-spawn.c b/test/test-spawn.c index 53a036969b6..fd64e523097 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -215,6 +215,52 @@ TEST_IMPL(spawn_fails_check_for_waitpid_cleanup) { #endif +#ifdef _WIN32 +TEST_IMPL(spawn_requires_elevation) { + int r; + uv_fs_t req; + char path[1024]; + size_t path_size = 1024; + + /* Find helper elevation.exe -- Assumed in same location as test runner */ + r = uv_exepath(exepath, &exepath_size); + ASSERT(r == 0); + exepath[exepath_size] = '\0'; + snprintf(path, path_size, "%s\\..\\elevation.exe", exepath); + uv_loop_t* loop = uv_default_loop(); + ASSERT(0 == uv_fs_realpath(loop, &req, path, NULL)); + + /* + * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW() + */ + if (req.result == UV_ENOSYS) { + uv_fs_req_cleanup(&req); + RETURN_SKIP("realpath is not supported on Windows XP"); + } + + ASSERT(req.ptr != NULL); + + init_process_options("", fail_cb); + options.file = options.args[0] = req.ptr; + + printf("Launching %s\n", (char*) req.ptr); + r = uv_spawn(uv_default_loop(), &process, &options); + printf("r = %d, %s - %s\n", r, uv_err_name(r), uv_strerror(r)); + + /* + * Will either succeed or fail depending on whether test is being run with + * elevated permissions + */ + ASSERT(r == 0 || r == UV_EACCES); + uv_close((uv_handle_t*) &process, NULL); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + + TEST_IMPL(spawn_exit_code) { int r; diff --git a/uv.gyp b/uv.gyp index b969a8cd5da..bf1143ff049 100644 --- a/uv.gyp +++ b/uv.gyp @@ -311,7 +311,6 @@ }], ] }, - { 'target_name': 'run-tests', 'type': 'executable', @@ -569,5 +568,27 @@ }, }, }, - ] + ], + 'conditions': [ + ['OS=="win"', { + 'targets': [ + { + 'target_name': 'elevation', + 'type': 'executable', + 'sources': [ + 'test/elevation.c' + ], + 'msvs_settings': { + 'VCLinkerTool': { + 'UACExecutionLevel': 2, # requireAdministrator + 'UACUIAccess': 'false', + }, + 'VCManifestTool': { + 'EmbedManifest': 'true', + } + }, + } + ], + }], + ], }