Skip to content

Commit

Permalink
Windows: when searching path, look only for .com and .exe files
Browse files Browse the repository at this point in the history
  • Loading branch information
piscisaureus committed Aug 18, 2011
1 parent 422c139 commit 8ed2ffb
Showing 1 changed file with 45 additions and 70 deletions.
115 changes: 45 additions & 70 deletions src/win/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;

const wchar_t *ext_start,
*ext_end = path_ext;
wchar_t* result;

/* 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);
}

/* 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++;
if (result != NULL) {
return result;
}
}

/* 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');
}
/* 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;
}

result = search_path_join_test(dir, dir_len,
name, name_len,
ext_start, (ext_end - ext_start),
cwd, cwd_len);
/* 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 result;
return NULL;
}


Expand All @@ -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.
*
Expand All @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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') {
Expand Down Expand Up @@ -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);
}
}

Expand All @@ -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.
*/
Expand All @@ -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.
*/
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -511,7 +487,7 @@ wchar_t* make_program_args(char** args, int verbatim_arguments) {
* 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) {
Expand All @@ -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
Expand Down Expand Up @@ -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 */
Expand Down

0 comments on commit 8ed2ffb

Please sign in to comment.