win,process: allow resolving .cmd and .bat files
Add a new `UV_PROCESS_WINDOWS_RESOLVE_BATCH` flag, which allows .cmd and .bat files to be considered when resolving an executable without an explicit extension on Windows. This is useful for some cross-platform solutions that may spawn processes without specifying extensions (#5088).
This commit is contained in:
parent
9f0101dcb8
commit
d9ec80a4bc
@ -94,6 +94,9 @@ modifies the child process behaviour:
|
||||
Changing the UID/GID is only supported on Unix, ``uv_spawn`` will fail on
|
||||
Windows with ``UV_ENOTSUP``.
|
||||
|
||||
* ``UV_PROCESS_WINDOWS_RESOLVE_BATCH`` - Considers .cmd and .bat files
|
||||
when resolving an executable without an explicit extensionon on Windows.
|
||||
Ignored on Unix.
|
||||
* ``UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS`` - No quoting or escaping of
|
||||
``uv_process_options_t.args`` is done on Windows. Ignored on Unix.
|
||||
* ``UV_PROCESS_DETACHED`` - Starts the child process in a new session, which
|
||||
|
||||
@ -92,7 +92,13 @@ Data types
|
||||
* search for the exact file name before trying variants with
|
||||
* extensions like '.exe' or '.cmd'.
|
||||
*/
|
||||
UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME = (1 << 7)
|
||||
UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME = (1 << 7),
|
||||
/*
|
||||
* Consider '.cmd' and '.bat' files when resolving an executable
|
||||
* without an explicit extension. This option is only meaningful
|
||||
* on Windows systems. On Unix it is silently ignored.
|
||||
*/
|
||||
UV_PROCESS_WINDOWS_RESOLVE_BATCH = (1 << 8)
|
||||
};
|
||||
|
||||
.. c:type:: uv_stdio_container_t
|
||||
|
||||
@ -1160,7 +1160,13 @@ enum uv_process_flags {
|
||||
* search for the exact file name before trying variants with
|
||||
* extensions like '.exe' or '.cmd'.
|
||||
*/
|
||||
UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME = (1 << 7)
|
||||
UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME = (1 << 7),
|
||||
/*
|
||||
* Consider '.cmd' and '.bat' files when resolving an executable
|
||||
* without an explicit extension. This option is only meaningful
|
||||
* on Windows systems. On Unix it is silently ignored.
|
||||
*/
|
||||
UV_PROCESS_WINDOWS_RESOLVE_BATCH = (1 << 8)
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@ -995,6 +995,7 @@ int uv_spawn(uv_loop_t* loop,
|
||||
UV_PROCESS_WINDOWS_HIDE |
|
||||
UV_PROCESS_WINDOWS_HIDE_CONSOLE |
|
||||
UV_PROCESS_WINDOWS_HIDE_GUI |
|
||||
UV_PROCESS_WINDOWS_RESOLVE_BATCH |
|
||||
UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
|
||||
|
||||
uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
|
||||
|
||||
@ -249,7 +249,8 @@ static WCHAR* path_search_walk_ext(const WCHAR *dir,
|
||||
size_t name_len,
|
||||
WCHAR *cwd,
|
||||
size_t cwd_len,
|
||||
int name_has_ext) {
|
||||
int name_has_ext,
|
||||
int resolve_batch) {
|
||||
WCHAR* result;
|
||||
|
||||
/* If the name itself has a nonempty extension, try this extension first */
|
||||
@ -281,6 +282,28 @@ static WCHAR* path_search_walk_ext(const WCHAR *dir,
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!resolve_batch) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Try .cmd extension */
|
||||
result = search_path_join_test(dir, dir_len,
|
||||
name, name_len,
|
||||
L"cmd", 3,
|
||||
cwd, cwd_len);
|
||||
if (result != NULL) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Try .bat extension */
|
||||
result = search_path_join_test(dir, dir_len,
|
||||
name, name_len,
|
||||
L"bat", 3,
|
||||
cwd, cwd_len);
|
||||
if (result != NULL) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -340,6 +363,7 @@ static WCHAR* search_path(const WCHAR *file,
|
||||
const WCHAR *dir_start, *dir_end, *dir_path;
|
||||
size_t dir_len;
|
||||
int name_has_ext;
|
||||
int resolve_batch = flags & UV_PROCESS_WINDOWS_RESOLVE_BATCH;
|
||||
|
||||
size_t file_len = wcslen(file);
|
||||
size_t cwd_len = wcslen(cwd);
|
||||
@ -373,7 +397,8 @@ static WCHAR* search_path(const WCHAR *file,
|
||||
file, file_name_start - file,
|
||||
file_name_start, file_len - (file_name_start - file),
|
||||
cwd, cwd_len,
|
||||
name_has_ext || (flags & UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME));
|
||||
name_has_ext || (flags & UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME),
|
||||
resolve_batch);
|
||||
|
||||
} else {
|
||||
dir_end = path;
|
||||
@ -383,7 +408,7 @@ static WCHAR* search_path(const WCHAR *file,
|
||||
result = path_search_walk_ext(L"", 0,
|
||||
file, file_len,
|
||||
cwd, cwd_len,
|
||||
name_has_ext);
|
||||
name_has_ext, resolve_batch);
|
||||
}
|
||||
|
||||
while (result == NULL) {
|
||||
@ -433,7 +458,7 @@ static WCHAR* search_path(const WCHAR *file,
|
||||
result = path_search_walk_ext(dir_path, dir_len,
|
||||
file, file_len,
|
||||
cwd, cwd_len,
|
||||
name_has_ext);
|
||||
name_has_ext, resolve_batch);
|
||||
}
|
||||
}
|
||||
|
||||
@ -928,6 +953,7 @@ int uv_spawn(uv_loop_t* loop,
|
||||
UV_PROCESS_WINDOWS_HIDE |
|
||||
UV_PROCESS_WINDOWS_HIDE_CONSOLE |
|
||||
UV_PROCESS_WINDOWS_HIDE_GUI |
|
||||
UV_PROCESS_WINDOWS_RESOLVE_BATCH |
|
||||
UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
|
||||
|
||||
err = uv__utf8_to_utf16_alloc(options->file, &application);
|
||||
|
||||
@ -351,6 +351,7 @@ TEST_DECLARE (spawn_quoted_path)
|
||||
TEST_DECLARE (spawn_tcp_server)
|
||||
TEST_DECLARE (spawn_exercise_sigchld_issue)
|
||||
TEST_DECLARE (spawn_relative_path)
|
||||
TEST_DECLARE (spawn_batch_file)
|
||||
TEST_DECLARE (fs_poll)
|
||||
TEST_DECLARE (fs_poll_getpath)
|
||||
TEST_DECLARE (fs_poll_close_request)
|
||||
@ -1043,6 +1044,7 @@ TASK_LIST_START
|
||||
TEST_ENTRY (spawn_tcp_server)
|
||||
TEST_ENTRY (spawn_exercise_sigchld_issue)
|
||||
TEST_ENTRY (spawn_relative_path)
|
||||
TEST_ENTRY (spawn_batch_file)
|
||||
TEST_ENTRY (fs_poll)
|
||||
TEST_ENTRY (fs_poll_getpath)
|
||||
TEST_ENTRY (fs_poll_close_request)
|
||||
|
||||
@ -1532,6 +1532,7 @@ TEST_IMPL(spawn_setuid_fails) {
|
||||
#endif
|
||||
|
||||
/* These flags should be ignored on Unices. */
|
||||
options.flags |= UV_PROCESS_WINDOWS_RESOLVE_BATCH;
|
||||
options.flags |= UV_PROCESS_WINDOWS_HIDE;
|
||||
options.flags |= UV_PROCESS_WINDOWS_HIDE_CONSOLE;
|
||||
options.flags |= UV_PROCESS_WINDOWS_HIDE_GUI;
|
||||
@ -2111,3 +2112,36 @@ TEST_IMPL(spawn_relative_path) {
|
||||
MAKE_VALGRIND_HAPPY(uv_default_loop());
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST_IMPL(spawn_batch_file) {
|
||||
#ifndef _WIN32
|
||||
RETURN_SKIP("Test for Windows");
|
||||
#else
|
||||
char filename[1024];
|
||||
FILE* file;
|
||||
uv_process_t process2;
|
||||
|
||||
snprintf(exepath, sizeof(exepath), "test_file_foo");
|
||||
snprintf(filename, sizeof(filename), "%s.bat", exepath);
|
||||
file = fopen(filename, "w");
|
||||
fprintf(file, "exit /B 1\r\n");
|
||||
fclose(file);
|
||||
|
||||
args[0] = exepath;
|
||||
args[1] = NULL;
|
||||
options.file = args[0];
|
||||
options.args = args;
|
||||
options.exit_cb = exit_cb;
|
||||
options.flags = 0;
|
||||
|
||||
ASSERT_EQ(uv_spawn(uv_default_loop(), &process, &options), UV_ENOENT);
|
||||
|
||||
options.flags |= UV_PROCESS_WINDOWS_RESOLVE_BATCH;
|
||||
ASSERT_OK(uv_spawn(uv_default_loop(), &process2, &options));
|
||||
ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT));
|
||||
|
||||
MAKE_VALGRIND_HAPPY(uv_default_loop());
|
||||
remove(filename);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user