Skip to content
This repository was archived by the owner on May 4, 2018. It is now read-only.

Commit 8ed2ffb

Browse files
committed
Windows: when searching path, look only for .com and .exe files
1 parent 422c139 commit 8ed2ffb

File tree

1 file changed

+45
-70
lines changed

1 file changed

+45
-70
lines changed

src/win/process.c

+45-70
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,6 @@ typedef struct env_var {
5151
}
5252

5353

54-
static const wchar_t DEFAULT_PATH_EXT[10] = L".COM;.EXE";
55-
56-
5754
static void uv_process_init(uv_process_t* handle) {
5855
handle->type = UV_PROCESS;
5956
handle->flags = 0;
@@ -153,10 +150,14 @@ static wchar_t* search_path_join_test(const wchar_t* dir,
153150
wcsncpy(result_pos, name, name_len);
154151
result_pos += name_len;
155152

156-
/* Copy extension */
157153
if (ext_len) {
158-
result_pos[0] = L'.';
159-
result_pos++;
154+
/* Add a dot if the filename didn't end with one */
155+
if (name_len && result_pos[-1] != '.') {
156+
result_pos[0] = L'.';
157+
result_pos++;
158+
}
159+
160+
/* Copy extension */
160161
wcsncpy(result_pos, ext, ext_len);
161162
result_pos += ext_len;
162163
}
@@ -185,54 +186,39 @@ static wchar_t* path_search_walk_ext(const wchar_t *dir,
185186
int name_len,
186187
wchar_t *cwd,
187188
int cwd_len,
188-
const wchar_t *path_ext,
189189
int name_has_ext) {
190-
wchar_t* result = NULL;
191-
192-
const wchar_t *ext_start,
193-
*ext_end = path_ext;
190+
wchar_t* result;
194191

195-
/* If the name itself has a nonemtpy extension, try this extension first */
192+
/* If the name itself has a nonempty extension, try this extension first */
196193
if (name_has_ext) {
197194
result = search_path_join_test(dir, dir_len,
198195
name, name_len,
199196
L"", 0,
200197
cwd, cwd_len);
201-
}
202-
203-
/* Add path_ext extensions and try to find a name that matches */
204-
while (result == NULL) {
205-
if (*ext_end == L'\0') {
206-
break;
207-
}
208-
209-
/* Skip the separator that ext_end now points to */
210-
if (ext_end != path_ext) {
211-
ext_end++;
198+
if (result != NULL) {
199+
return result;
212200
}
201+
}
213202

214-
/* Find the next dot in path_ext */
215-
ext_start = wcschr(ext_end, L'.');
216-
if (ext_start == NULL) {
217-
break;
218-
}
219-
220-
/* Skip the dot */
221-
ext_start++;
222-
223-
/* Slice until we found a ; or alternatively a \0 */
224-
ext_end = wcschr(ext_start, L';');
225-
if (ext_end == NULL) {
226-
ext_end = wcschr(ext_start, '\0');
227-
}
203+
/* Try .com extension */
204+
result = search_path_join_test(dir, dir_len,
205+
name, name_len,
206+
L"com", 3,
207+
cwd, cwd_len);
208+
if (result != NULL) {
209+
return result;
210+
}
228211

229-
result = search_path_join_test(dir, dir_len,
230-
name, name_len,
231-
ext_start, (ext_end - ext_start),
232-
cwd, cwd_len);
212+
/* Try .exe extension */
213+
result = search_path_join_test(dir, dir_len,
214+
name, name_len,
215+
L"exe", 3,
216+
cwd, cwd_len);
217+
if (result != NULL) {
218+
return result;
233219
}
234220

235-
return result;
221+
return NULL;
236222
}
237223

238224

@@ -243,35 +229,28 @@ static wchar_t* path_search_walk_ext(const wchar_t *dir,
243229
*
244230
* It tries to return an absolute filename.
245231
*
246-
* Furthermore, it tries to follow the semantics that cmd.exe uses as closely
247-
* as possible:
232+
* Furthermore, it tries to follow the semantics that cmd.exe, with this
233+
* exception that PATHEXT environment variable isn't used. Since CreateProcess
234+
* can start only .com and .exe files, only those extensions are tried. This
235+
* behavior equals that of msvcrt's spawn functions.
248236
*
249237
* - Do not search the path if the filename already contains a path (either
250238
* relative or absolute).
251-
* (but do use path_ext)
252239
*
253240
* - If there's really only a filename, check the current directory for file,
254241
* then search all path directories.
255242
*
256-
* - If filename specifies has *any* extension, search for the file with the
243+
* - If filename specified has *any* extension, search for the file with the
257244
* specified extension first.
258-
* (not necessary an executable one or one that appears in path_ext;
259-
* *but* no extension or just a dot is *not* allowed)
260245
*
261246
* - If the literal filename is not found in a directory, try *appending*
262-
* (not replacing) extensions from path_ext in the specified order.
263-
* (an extension consisting of just a dot *may* appear in path_ext;
264-
* unlike what happens if the specified filename ends with a dot,
265-
* if path_ext specifies a single dot cmd.exe *does* look for an
266-
* extension-less file)
247+
* (not replacing) .com first and then .exe.
267248
*
268249
* - The path variable may contain relative paths; relative paths are relative
269250
* to the cwd.
270251
*
271252
* - Directories in path may or may not end with a trailing backslash.
272253
*
273-
* - Extensions path_ext portions must always start with a dot.
274-
*
275254
* - CMD does not trim leading/trailing whitespace from path/pathex entries
276255
* nor from the environment variables as a whole.
277256
*
@@ -281,13 +260,10 @@ static wchar_t* path_search_walk_ext(const wchar_t *dir,
281260
* continue searching.
282261
*
283262
* TODO: correctly interpret UNC paths
284-
* TODO: check with cmd what should happen when a pathext entry does not start
285-
* with a dot
286263
*/
287264
static wchar_t* search_path(const wchar_t *file,
288265
wchar_t *cwd,
289-
const wchar_t *path,
290-
const wchar_t *path_ext) {
266+
const wchar_t *path) {
291267
int file_has_dir;
292268
wchar_t* result = NULL;
293269
wchar_t *file_name_start;
@@ -320,12 +296,12 @@ static wchar_t* search_path(const wchar_t *file,
320296
name_has_ext = (dot != NULL && dot[1] != L'\0');
321297

322298
if (file_has_dir) {
323-
/* The file has a path inside, don't use path (but do use path_ex) */
299+
/* The file has a path inside, don't use path */
324300
result = path_search_walk_ext(
325301
file, file_name_start - file,
326302
file_name_start, file_len - (file_name_start - file),
327303
cwd, cwd_len,
328-
path_ext, name_has_ext);
304+
name_has_ext);
329305

330306
} else {
331307
const wchar_t *dir_start,
@@ -335,7 +311,7 @@ static wchar_t* search_path(const wchar_t *file,
335311
result = path_search_walk_ext(L"", 0,
336312
file, file_len,
337313
cwd, cwd_len,
338-
path_ext, name_has_ext);
314+
name_has_ext);
339315

340316
while (result == NULL) {
341317
if (*dir_end == L'\0') {
@@ -364,7 +340,7 @@ static wchar_t* search_path(const wchar_t *file,
364340
result = path_search_walk_ext(dir_start, dir_end - dir_start,
365341
file, file_len,
366342
cwd, cwd_len,
367-
path_ext, name_has_ext);
343+
name_has_ext);
368344
}
369345
}
370346

@@ -381,7 +357,7 @@ wchar_t* quote_cmd_arg(const wchar_t *source, wchar_t *target) {
381357
i, quote_hit;
382358
wchar_t* start;
383359

384-
/*
360+
/*
385361
* Check if the string must be quoted;
386362
* if unnecessary, don't do it, it may only confuse older programs.
387363
*/
@@ -397,7 +373,7 @@ wchar_t* quote_cmd_arg(const wchar_t *source, wchar_t *target) {
397373
}
398374

399375
if (NULL == wcspbrk(source, L"\"\\")) {
400-
/*
376+
/*
401377
* No embedded double quotes or backlashes, so I can just wrap
402378
* quote marks around the whole thing.
403379
*/
@@ -468,7 +444,7 @@ wchar_t* make_program_args(char** args, int verbatim_arguments) {
468444
arg_count++;
469445
}
470446

471-
/* Adjust for potential quotes. Also assume the worst-case scenario
447+
/* Adjust for potential quotes. Also assume the worst-case scenario
472448
/* that every character needs escaping, so we need twice as much space. */
473449
size = size * 2 + arg_count * 2;
474450

@@ -511,7 +487,7 @@ wchar_t* make_program_args(char** args, int verbatim_arguments) {
511487
* If we learn that people are passing in huge environment blocks
512488
* then we should probably qsort() the array and then bsearch()
513489
* to see if it contains this variable. But there are ownership
514-
* issues associated with that solution; this is the caller's
490+
* issues associated with that solution; this is the caller's
515491
* char**, and modifying it is rude.
516492
*/
517493
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
529505
* The way windows takes environment variables is different than what C does;
530506
* Windows wants a contiguous block of null-terminated strings, terminated
531507
* with an additional null.
532-
*
508+
*
533509
* Windows has a few "essential" environment variables. winsock will fail
534510
* to initialize if SYSTEMROOT is not defined; some APIs make reference to
535511
* 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) {
858834

859835
application_path = search_path(application,
860836
cwd,
861-
path,
862-
DEFAULT_PATH_EXT);
837+
path);
863838

864839
if (!application_path) {
865840
/* CreateProcess will fail, but this allows us to pass this error to */

0 commit comments

Comments
 (0)