diff options
author | Bert Belder <bertbelder@gmail.com> | 2011-08-05 11:15:04 +0400 |
---|---|---|
committer | Bert Belder <bertbelder@gmail.com> | 2011-08-05 11:15:04 +0400 |
commit | 08782931205bc4f6d28102ebc29fd806e8ccdf1f (patch) | |
tree | 994eda1c3ca8dad92d942b3444dae999ba22a8b9 /deps | |
parent | 30d20cf40595e5d0c31b6d3cab9afc9fe8c54bfb (diff) |
Upgrade libuv to c834d5de9e4747e5138bed9140320b44622ab6de
Diffstat (limited to 'deps')
-rw-r--r-- | deps/uv/include/uv.h | 1 | ||||
-rw-r--r-- | deps/uv/src/win/process.c | 140 | ||||
-rw-r--r-- | deps/uv/test/test-list.h | 2 | ||||
-rw-r--r-- | deps/uv/test/test-spawn.c | 73 |
4 files changed, 163 insertions, 53 deletions
diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index bb3e37c45d6..2ee7c315f2b 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -504,6 +504,7 @@ typedef struct uv_process_options_s { char** args; char** env; char* cwd; + int windows_verbatim_arguments; /* * The user should supply pointers to initialized uv_pipe_t structs for * stdio. The user is reponsible for calling uv_close on them. diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c index 489c2a16c86..7b4b562e85a 100644 --- a/deps/uv/src/win/process.c +++ b/deps/uv/src/win/process.c @@ -76,48 +76,6 @@ static void uv_process_init(uv_process_t* handle) { /* - * Quotes command line arguments - * Returns a pointer to the end (next char to be written) of the buffer - */ -static wchar_t* quote_cmd_arg(wchar_t *source, wchar_t *target, - wchar_t terminator) { - int len = wcslen(source), - i; - - // Check if the string must be quoted; - // if unnecessary, don't do it, it may only confuse older programs. - if (len == 0) { - goto quote; - } - for (i = 0; i < len; i++) { - if (source[i] == L' ' || source[i] == L'"') { - goto quote; - } - } - - // No quotation needed - wcsncpy(target, source, len); - target += len; - *(target++) = terminator; - return target; - -quote: - // Quote - *(target++) = L'"'; - for (i = 0; i < len; i++) { - if (source[i] == L'"' || source[i] == L'\\') { - *(target++) = '\\'; - } - *(target++) = source[i]; - } - *(target++) = L'"'; - *(target++) = terminator; - - return target; -} - - -/* * Path search functions */ @@ -403,8 +361,83 @@ static wchar_t* search_path(const wchar_t *file, return result; } +/* + * Quotes command line arguments + * Returns a pointer to the end (next char to be written) of the buffer + */ +wchar_t* quote_cmd_arg(const wchar_t *source, wchar_t *target) { + int len = wcslen(source), + 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. + */ + if (len == 0) { + return target; + } + + if (NULL == wcspbrk(source, L" \t\"")) { + /* No quotation needed */ + wcsncpy(target, source, len); + target += len; + return target; + } + + if (NULL == wcspbrk(source, L"\"\\")) { + /* + * No embedded double quotes or backlashes, so I can just wrap + * quote marks around the whole thing. + */ + *(target++) = L'"'; + wcsncpy(target, source, len); + target += len; + *(target++) = L'"'; + return target; + } + + /* + * Expected intput/output: + * input : hello"world + * output: "hello\"world" + * input : hello""world + * output: "hello\"\"world" + * input : hello\world + * output: hello\world + * input : hello\\world + * output: hello\\world + * input : hello\"world + * output: "hello\\\"world" + * input : hello\\"world + * output: "hello\\\\\"world" + * input : hello world\ + * output: "hello world\" + */ + + *(target++) = L'"'; + start = target; + quote_hit = 1; + + for (i = len; i > 0; --i) { + *(target++) = source[i - 1]; -static wchar_t* make_program_args(char** args) { + if (quote_hit && source[i - 1] == L'\\') { + *(target++) = L'\\'; + } else if(source[i - 1] == L'"') { + quote_hit = 1; + *(target++) = L'\\'; + } else { + quote_hit = 0; + } + } + target[0] = L'\0'; + wcsrev(start); + *(target++) = L'"'; + return target; +} + +wchar_t* make_program_args(char** args, int verbatim_arguments) { wchar_t* dst; wchar_t* ptr; char** arg; @@ -423,13 +456,9 @@ static wchar_t* make_program_args(char** args) { arg_count++; } - /* Adjust for potential quotes. */ - size *= 2; - - /* Arguments are separated with a space. */ - if (arg_count > 0) { - size += arg_count - 1; - } + /* 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; dst = (wchar_t*)malloc(size); if (!dst) { @@ -447,8 +476,13 @@ static wchar_t* make_program_args(char** args) { if (!len) { goto error; } - - ptr = quote_cmd_arg(buffer, ptr, *(arg + 1) ? L' ' : L'\0'); + if (verbatim_arguments) { + wcscpy(ptr, buffer); + ptr += len - 1; + } else { + ptr = quote_cmd_arg(buffer, ptr); + } + *ptr++ = *(arg + 1) ? L' ' : L'\0'; } free(buffer); @@ -743,7 +777,7 @@ int uv_spawn(uv_process_t* process, uv_process_options_t options) { process->exit_cb = options.exit_cb; UTF8_TO_UTF16(options.file, application); - arguments = options.args ? make_program_args(options.args) : NULL; + arguments = options.args ? make_program_args(options.args, options.windows_verbatim_arguments) : NULL; env = options.env ? make_program_env(options.env) : NULL; if (options.cwd) { diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index ebfdeb65569..08ed92a2bdd 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -69,6 +69,7 @@ TEST_DECLARE (spawn_stdin) TEST_DECLARE (spawn_and_kill) #ifdef _WIN32 TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows) +TEST_DECLARE (argument_escaping) #endif HELPER_DECLARE (tcp4_echo_server) HELPER_DECLARE (tcp6_echo_server) @@ -153,6 +154,7 @@ TASK_LIST_START TEST_ENTRY (spawn_and_kill) #ifdef _WIN32 TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows) + TEST_ENTRY (argument_escaping) #endif #if 0 diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c index 6378aab9811..18a9bb7d978 100644 --- a/deps/uv/test/test-spawn.c +++ b/deps/uv/test/test-spawn.c @@ -269,4 +269,77 @@ TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) { return 0; } + + +wchar_t* make_program_args(char** args, int verbatim_arguments); +wchar_t* quote_cmd_arg(const wchar_t *source, wchar_t *target); + +TEST_IMPL(argument_escaping) { + const wchar_t* test_str[] = { + L"HelloWorld", + L"Hello World", + L"Hello\"World", + L"Hello World\\", + L"Hello\\\"World", + L"Hello\\World", + L"Hello\\\\World", + L"Hello World\\", + L"c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\"" + }; + const int count = sizeof(test_str) / sizeof(*test_str); + wchar_t** test_output; + wchar_t* command_line; + wchar_t** cracked; + size_t total_size = 0; + int i; + int num_args; + + char* verbatim[] = { + "cmd.exe", + "/c", + "c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\"", + NULL + }; + wchar_t* verbatim_output; + wchar_t* non_verbatim_output; + + test_output = calloc(count, sizeof(wchar_t*)); + for (i = 0; i < count; ++i) { + test_output[i] = calloc(2 * (wcslen(test_str[i]) + 2), sizeof(wchar_t)); + quote_cmd_arg(test_str[i], test_output[i]); + wprintf(L"input : %s\n", test_str[i]); + wprintf(L"output: %s\n", test_output[i]); + total_size += wcslen(test_output[i]) + 1; + } + command_line = calloc(total_size + 1, sizeof(wchar_t)); + for (i = 0; i < count; ++i) { + wcscat(command_line, test_output[i]); + wcscat(command_line, L" "); + } + command_line[total_size - 1] = L'\0'; + + wprintf(L"command_line: %s\n", command_line); + + cracked = CommandLineToArgvW(command_line, &num_args); + for (i = 0; i < num_args; ++i) { + wprintf(L"%d: %s\t%s\n", i, test_str[i], cracked[i]); + ASSERT(wcscmp(test_str[i], cracked[i]) == 0); + } + + LocalFree(cracked); + for (i = 0; i < count; ++i) { + free(test_output[i]); + } + + verbatim_output = make_program_args(verbatim, 1); + non_verbatim_output = make_program_args(verbatim, 0); + + wprintf(L" verbatim_output: %s\n", verbatim_output); + wprintf(L"non_verbatim_output: %s\n", non_verbatim_output); + + ASSERT(wcscmp(verbatim_output, L"cmd.exe /c c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\"") == 0); + ASSERT(wcscmp(non_verbatim_output, L"cmd.exe /c \"c:\\path\\to\\node.exe --eval \\\"require('c:\\\\path\\\\to\\\\test.js')\\\"\"") == 0); + + return 0; +} #endif
\ No newline at end of file |