From 8ed2ffb2bf35304675d06cd07c3f440dccd46eb2 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 18 Aug 2011 04:07:58 +0200 Subject: [PATCH] Windows: when searching path, look only for .com and .exe files --- src/win/process.c | 117 ++++++++++++++++++---------------------------- 1 file changed, 46 insertions(+), 71 deletions(-) diff --git a/src/win/process.c b/src/win/process.c index a484915b..22d06060 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -51,9 +51,6 @@ typedef struct env_var { } -static const wchar_t DEFAULT_PATH_EXT[10] = L".COM;.EXE"; - - static void uv_process_init(uv_process_t* handle) { handle->type = UV_PROCESS; handle->flags = 0; @@ -153,10 +150,14 @@ static wchar_t* search_path_join_test(const wchar_t* dir, wcsncpy(result_pos, name, name_len); result_pos += name_len; - /* Copy extension */ if (ext_len) { - result_pos[0] = L'.'; - result_pos++; + /* Add a dot if the filename didn't end with one */ + if (name_len && result_pos[-1] != '.') { + result_pos[0] = L'.'; + result_pos++; + } + + /* Copy extension */ wcsncpy(result_pos, ext, ext_len); result_pos += ext_len; } @@ -185,54 +186,39 @@ static wchar_t* path_search_walk_ext(const wchar_t *dir, int name_len, wchar_t *cwd, int cwd_len, - const wchar_t *path_ext, int name_has_ext) { - wchar_t* result = NULL; + wchar_t* result; - const wchar_t *ext_start, - *ext_end = path_ext; - - /* If the name itself has a nonemtpy extension, try this extension first */ + /* 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; + } } - /* Add path_ext extensions and try to find a name that matches */ - while (result == NULL) { - if (*ext_end == L'\0') { - break; - } - - /* Skip the separator that ext_end now points to */ - if (ext_end != path_ext) { - ext_end++; - } - - /* Find the next dot in path_ext */ - ext_start = wcschr(ext_end, L'.'); - if (ext_start == NULL) { - break; - } - - /* Skip the dot */ - ext_start++; - - /* Slice until we found a ; or alternatively a \0 */ - ext_end = wcschr(ext_start, L';'); - if (ext_end == NULL) { - ext_end = wcschr(ext_start, '\0'); - } - - result = search_path_join_test(dir, dir_len, - name, name_len, - ext_start, (ext_end - ext_start), - cwd, cwd_len); + /* Try .com extension */ + result = search_path_join_test(dir, dir_len, + name, name_len, + L"com", 3, + cwd, cwd_len); + if (result != NULL) { + return result; } - return result; + /* Try .exe extension */ + result = search_path_join_test(dir, dir_len, + name, name_len, + L"exe", 3, + cwd, cwd_len); + if (result != NULL) { + return result; + } + + return NULL; } @@ -243,35 +229,28 @@ static wchar_t* path_search_walk_ext(const wchar_t *dir, * * It tries to return an absolute filename. * - * Furthermore, it tries to follow the semantics that cmd.exe uses as closely - * as possible: + * Furthermore, it tries to follow the semantics that cmd.exe, with this + * exception that PATHEXT environment variable isn't used. Since CreateProcess + * can start only .com and .exe files, only those extensions are tried. This + * behavior equals that of msvcrt's spawn functions. * * - Do not search the path if the filename already contains a path (either * relative or absolute). - * (but do use path_ext) * * - If there's really only a filename, check the current directory for file, * then search all path directories. * - * - If filename specifies has *any* extension, search for the file with the + * - If filename specified has *any* extension, search for the file with the * specified extension first. - * (not necessary an executable one or one that appears in path_ext; - * *but* no extension or just a dot is *not* allowed) * * - If the literal filename is not found in a directory, try *appending* - * (not replacing) extensions from path_ext in the specified order. - * (an extension consisting of just a dot *may* appear in path_ext; - * unlike what happens if the specified filename ends with a dot, - * if path_ext specifies a single dot cmd.exe *does* look for an - * extension-less file) + * (not replacing) .com first and then .exe. * * - The path variable may contain relative paths; relative paths are relative * to the cwd. * * - Directories in path may or may not end with a trailing backslash. * - * - Extensions path_ext portions must always start with a dot. - * * - CMD does not trim leading/trailing whitespace from path/pathex entries * nor from the environment variables as a whole. * @@ -281,13 +260,10 @@ static wchar_t* path_search_walk_ext(const wchar_t *dir, * continue searching. * * TODO: correctly interpret UNC paths - * TODO: check with cmd what should happen when a pathext entry does not start - * with a dot */ static wchar_t* search_path(const wchar_t *file, wchar_t *cwd, - const wchar_t *path, - const wchar_t *path_ext) { + const wchar_t *path) { int file_has_dir; wchar_t* result = NULL; wchar_t *file_name_start; @@ -320,12 +296,12 @@ static wchar_t* search_path(const wchar_t *file, name_has_ext = (dot != NULL && dot[1] != L'\0'); if (file_has_dir) { - /* The file has a path inside, don't use path (but do use path_ex) */ + /* 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, - path_ext, name_has_ext); + name_has_ext); } else { const wchar_t *dir_start, @@ -335,7 +311,7 @@ static wchar_t* search_path(const wchar_t *file, result = path_search_walk_ext(L"", 0, file, file_len, cwd, cwd_len, - path_ext, name_has_ext); + name_has_ext); while (result == NULL) { if (*dir_end == L'\0') { @@ -364,7 +340,7 @@ static wchar_t* search_path(const wchar_t *file, result = path_search_walk_ext(dir_start, dir_end - dir_start, file, file_len, cwd, cwd_len, - path_ext, name_has_ext); + name_has_ext); } } @@ -381,7 +357,7 @@ wchar_t* quote_cmd_arg(const wchar_t *source, wchar_t *target) { i, quote_hit; wchar_t* start; - /* + /* * Check if the string must be quoted; * if unnecessary, don't do it, it may only confuse older programs. */ @@ -397,7 +373,7 @@ wchar_t* quote_cmd_arg(const wchar_t *source, wchar_t *target) { } if (NULL == wcspbrk(source, L"\"\\")) { - /* + /* * No embedded double quotes or backlashes, so I can just wrap * quote marks around the whole thing. */ @@ -468,7 +444,7 @@ wchar_t* make_program_args(char** args, int verbatim_arguments) { arg_count++; } - /* Adjust for potential quotes. Also assume the worst-case scenario + /* Adjust for potential quotes. Also assume the worst-case scenario /* that every character needs escaping, so we need twice as much space. */ size = size * 2 + arg_count * 2; @@ -511,7 +487,7 @@ error: * If we learn that people are passing in huge environment blocks * then we should probably qsort() the array and then bsearch() * to see if it contains this variable. But there are ownership - * issues associated with that solution; this is the caller's + * issues associated with that solution; this is the caller's * char**, and modifying it is rude. */ static void check_required_vars_contains_var(env_var_t* required, int size, const char* var) { @@ -529,7 +505,7 @@ static void check_required_vars_contains_var(env_var_t* required, int size, cons * The way windows takes environment variables is different than what C does; * Windows wants a contiguous block of null-terminated strings, terminated * with an additional null. - * + * * Windows has a few "essential" environment variables. winsock will fail * to initialize if SYSTEMROOT is not defined; some APIs make reference to * TEMP. SYSTEMDRIVE is probably also important. We therefore ensure that @@ -858,8 +834,7 @@ int uv_spawn(uv_process_t* process, uv_process_options_t options) { application_path = search_path(application, cwd, - path, - DEFAULT_PATH_EXT); + path); if (!application_path) { /* CreateProcess will fail, but this allows us to pass this error to */