This commit is contained in:
tao 2026-03-30 22:39:27 -04:00 committed by GitHub
commit d740da7960
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 84 additions and 6 deletions

View File

@ -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 extension 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

View File

@ -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

View File

@ -1161,7 +1161,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)
};
/*

View File

@ -1028,6 +1028,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);

View File

@ -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);

View File

@ -352,6 +352,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)
@ -1049,6 +1050,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)

View File

@ -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
}