Skip to content

Commit

Permalink
win/spawn: run executables with no file extension
Browse files Browse the repository at this point in the history
  • Loading branch information
KyleFromKitware committed Dec 1, 2023
1 parent 5e30273 commit 62d0333
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 26 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/CI-win.yml
Expand Up @@ -91,7 +91,7 @@ jobs:
cmake --install build --prefix "`pwd`/build/usr"
mkdir -p build/usr/test build/usr/bin
cp -av test/fixtures build/usr/test
cp -av build/uv_run_tests_a.exe build/uv_run_tests.exe \
cp -av build/uv_run_tests_a.exe build/uv_run_tests.exe build/uv_run_tests_a_no_ext build/uv_run_tests_no_ext \
`${{ matrix.config.arch }}-w64-mingw32-gcc -print-file-name=libgcc_s_${{ matrix.config.libgcc }}-1.dll` \
`${{ matrix.config.arch }}-w64-mingw32-gcc -print-file-name=libwinpthread-1.dll` \
`${{ matrix.config.arch }}-w64-mingw32-gcc -print-file-name=libatomic-1.dll` \
Expand Down
12 changes: 12 additions & 0 deletions CMakeLists.txt
Expand Up @@ -703,6 +703,12 @@ if(LIBUV_BUILD_TESTS)
set_tests_properties(uv_test PROPERTIES ENVIRONMENT
"LIBPATH=${CMAKE_BINARY_DIR}:$ENV{LIBPATH}")
endif()
if(WIN32)
add_custom_command(TARGET uv_run_tests POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy
"$<TARGET_FILE:uv_run_tests>"
"$<TARGET_FILE_DIR:uv_run_tests>/uv_run_tests_no_ext")
endif()
add_executable(uv_run_tests_a ${uv_test_sources} uv_win_longpath.manifest)
target_compile_definitions(uv_run_tests_a PRIVATE ${uv_defines})
target_compile_options(uv_run_tests_a PRIVATE ${uv_cflags})
Expand All @@ -719,6 +725,12 @@ if(LIBUV_BUILD_TESTS)
set_target_properties(uv_run_tests PROPERTIES LINKER_LANGUAGE CXX)
set_target_properties(uv_run_tests_a PROPERTIES LINKER_LANGUAGE CXX)
endif()
if(WIN32)
add_custom_command(TARGET uv_run_tests_a POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy
"$<TARGET_FILE:uv_run_tests_a>"
"$<TARGET_FILE_DIR:uv_run_tests_a>/uv_run_tests_a_no_ext")
endif()
endif()

# Now for some gibbering horrors from beyond the stars...
Expand Down
6 changes: 6 additions & 0 deletions Makefile.am
Expand Up @@ -136,6 +136,12 @@ TESTS = test/run-tests
check_PROGRAMS = test/run-tests
test_run_tests_CFLAGS = $(AM_CFLAGS)

if WINNT
check-am: test/run-tests_no_ext
test/run-tests_no_ext: test/run-tests$(EXEEXT)
cp test/run-tests$(EXEEXT) test/run-tests_no_ext
endif

if SUNOS
# Can't be turned into a CC_CHECK_CFLAGS in configure.ac, it makes compilers
# on other platforms complain that the argument is unused during compilation.
Expand Down
37 changes: 12 additions & 25 deletions src/win/process.c
Expand Up @@ -249,19 +249,16 @@ static WCHAR* path_search_walk_ext(const WCHAR *dir,
const WCHAR *name,
size_t name_len,
WCHAR *cwd,
size_t cwd_len,
int name_has_ext) {
size_t cwd_len) {
WCHAR* result;

/* If the name itself has a nonempty extension, try this extension first */
if (name_has_ext) {
result = search_path_join_test(dir, dir_len,
name, name_len,
L"", 0,
cwd, cwd_len);
if (result != NULL) {
return result;
}
/* Try the name itself first */
result = search_path_join_test(dir, dir_len,
name, name_len,
L"", 0,
cwd, cwd_len);
if (result != NULL) {
return result;
}

/* Try .com extension */
Expand Down Expand Up @@ -304,8 +301,7 @@ static WCHAR* path_search_walk_ext(const WCHAR *dir,
* - If there's really only a filename, check the current directory for file,
* then search all path directories.
*
* - If filename specified has *any* extension, search for the file with the
* specified extension first.
* - Search for the file exactly as specified first.
*
* - If the literal filename is not found in a directory, try *appending*
* (not replacing) .com first and then .exe.
Expand Down Expand Up @@ -335,10 +331,8 @@ static WCHAR* search_path(const WCHAR *file,
int file_has_dir;
WCHAR* result = NULL;
WCHAR *file_name_start;
WCHAR *dot;
const WCHAR *dir_start, *dir_end, *dir_path;
size_t dir_len;
int name_has_ext;

size_t file_len = wcslen(file);
size_t cwd_len = wcslen(cwd);
Expand All @@ -362,17 +356,12 @@ static WCHAR* search_path(const WCHAR *file,

file_has_dir = file_name_start != file;

/* Check if the filename includes an extension */
dot = wcschr(file_name_start, L'.');
name_has_ext = (dot != NULL && dot[1] != L'\0');

if (file_has_dir) {
/* The file has a path inside, don't use path */
result = path_search_walk_ext(
file, file_name_start - file,
file_name_start, file_len - (file_name_start - file),
cwd, cwd_len,
name_has_ext);
cwd, cwd_len);

} else {
dir_end = path;
Expand All @@ -381,8 +370,7 @@ static WCHAR* search_path(const WCHAR *file,
/* The file is really only a name; look in cwd first, then scan path */
result = path_search_walk_ext(L"", 0,
file, file_len,
cwd, cwd_len,
name_has_ext);
cwd, cwd_len);
}

while (result == NULL) {
Expand Down Expand Up @@ -431,8 +419,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);
cwd, cwd_len);
}
}

Expand Down
4 changes: 4 additions & 0 deletions test/test-list.h
Expand Up @@ -506,6 +506,8 @@ TEST_DECLARE (listen_no_simultaneous_accepts)
TEST_DECLARE (fs_stat_root)
TEST_DECLARE (spawn_with_an_odd_path)
TEST_DECLARE (spawn_no_path)
TEST_DECLARE (spawn_no_ext)
TEST_DECLARE (spawn_path_no_ext)
TEST_DECLARE (ipc_listen_after_bind_twice)
TEST_DECLARE (win32_signum_number)
#else
Expand Down Expand Up @@ -1025,6 +1027,8 @@ TASK_LIST_START
TEST_ENTRY (fs_stat_root)
TEST_ENTRY (spawn_with_an_odd_path)
TEST_ENTRY (spawn_no_path)
TEST_ENTRY (spawn_no_ext)
TEST_ENTRY (spawn_path_no_ext)
TEST_ENTRY (ipc_listen_after_bind_twice)
TEST_ENTRY (win32_signum_number)
#else
Expand Down
61 changes: 61 additions & 0 deletions test/test-spawn.c
Expand Up @@ -1394,6 +1394,67 @@ TEST_IMPL(spawn_no_path) {
MAKE_VALGRIND_HAPPY(uv_default_loop());
return 0;
}


TEST_IMPL(spawn_no_ext) {
char new_exepath[1024];

init_process_options("spawn_helper1", exit_cb);
memcpy(new_exepath, exepath, exepath_size - (sizeof(".exe") - sizeof(char)));
strcpy(new_exepath + exepath_size - (sizeof(".exe") / sizeof(char) - 1), "_no_ext");
options.file = options.args[0] = new_exepath;

ASSERT_OK(uv_spawn(uv_default_loop(), &process, &options));
ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT));

ASSERT_EQ(1, exit_cb_called);
ASSERT_EQ(1, close_cb_called);

MAKE_VALGRIND_HAPPY(uv_default_loop());
return 0;
}


TEST_IMPL(spawn_path_no_ext) {
int r;
int len;
int file_len;
char file[64];
char path[1024];
char* env[2];

/* Set up the process, but make sure that the file to run is relative and
* requires a lookup into PATH. */
init_process_options("spawn_helper1", exit_cb);

/* Set up the PATH env variable */
for (len = strlen(exepath), file_len = 0;
exepath[len - 1] != '/' && exepath[len - 1] != '\\';
len--, file_len++);
memcpy(file, exepath + len, file_len - (sizeof(".exe") - sizeof(char)));
strcpy(file + file_len - (sizeof(".exe") / sizeof(char) - 1), "_no_ext");
exepath[len] = 0;
strcpy(path, "PATH=");
strcpy(path + 5, exepath);

env[0] = path;
env[1] = NULL;

options.file = options.args[0] = file;
options.env = env;

r = uv_spawn(uv_default_loop(), &process, &options);
ASSERT_OK(r);

r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT_OK(r);

ASSERT_EQ(1, exit_cb_called);
ASSERT_EQ(1, close_cb_called);

MAKE_VALGRIND_HAPPY(uv_default_loop());
return 0;
}
#endif

#ifndef _WIN32
Expand Down

0 comments on commit 62d0333

Please sign in to comment.