joyent/node — pull request #7540 by WernerWenz (2014-05-01 18:31:18+00:00)
Title: - Indirected process creation through "cmd.exe /c"

This patch redirects the CreateProcess logic used by child_process.spawn through cmd.exe.
This has quite some impact on the current behavior.
Reason for this patch is https://github.com/joyent/node/issues/2318

As cmd.exe is used, `search_path` and related functions are obsolete.
`UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS` is not used/supported anymore.
Escaping logic changed due to the indirection. (Need to escape for cmd processing)

Before merging, the following things should be reviewed:
- Is the allocated destination buffer large enough in any case?
- Are there any missing meta chars, not escaped?
- Are there any other possible cases (except ***), that may not be handled properly?

Test cases: (These and probably some additional ones should probably become unit tests)

Command | Arg 1 | Arg 2
------------- | -------------| ------------
`spawn("test.exe", ['Hello world'])`|`Hello world`|
`spawn("test.exe", ['"Hello world"'])`|`"Hello world"`|
`spawn("test.exe", ['"Hello world'])`|`"Hello world`|
`spawn("test.exe", ['Hello world"'])`|`Hello world"`|
`spawn("test.exe", ['"Hello', 'world"'])`|`"Hello`|`world"`
`spawn("test.exe", ['Hello"', '"world'])`|`Hello"`|`"world`
`spawn("test.exe", ['"Hello', '"world'])`|`"Hello`|`"world`
`spawn("test.exe", ['Hello"', 'world"'])`|`Hello"`|`world"`
`spawn("test.exe", ['!"Hello world"'])`|`!"Hello world"`|
`spawn("test.exe", ['escape>me'])`|`escape>me`|

(***)
As execution is indirected, there are side effects for commands like `spawn("echo", ['Hello world'])`.
This is due to the cmd interpreter not executing echo but interpreting it as internal command.
With the current implementation however, the above command wouldn't be executable at all to start with.

Command | output
------------- | -------------
`spawn("echo", ['Hello world'])`|`"Hello world"`
`spawn("echo", ['"Hello world"'])`|`"""Hello world"""`
`spawn("echo", ['"Hello world'])`|`"""Hello world"`
`spawn("echo", ['Hello world"'])`|`"Hello world"""`
`spawn("echo", ['"Hello', 'world"'])`|`"""Hello" "world"""`
`spawn("echo", ['Hello"', '"world'])`|`"Hello""" """world"`
`spawn("echo", ['"Hello', '"world'])`|`"""Hello" """world"`
`spawn("echo", ['Hello"', 'world"'])`|`"Hello""" "world"""`
`spawn("echo", ['!"Hello world"'])`|`"!""Hello world"""`
`spawn("echo", ['escape>me'])`|`escape>me`

This "issue" could be solved however, by treating any internal cmd commands specially.
More care should be taken when it comes to precedence. If a echo.exe or (echo.bat) is available.
cmd.exe will choose what to execute when passing 'echo', while the original variant would have executed echo.exe.