|
@@ -2953,6 +2953,105 @@ load_windows_system_library(const TCHAR *library_name)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+/* Format a single argument for being put on a Windows command line.
|
|
|
+ * Returns a newly allocated string */
|
|
|
+static char *
|
|
|
+format_cmdline_argument(const char *arg)
|
|
|
+{
|
|
|
+ char *formatted_arg;
|
|
|
+ char need_quotes;
|
|
|
+ const char *c;
|
|
|
+ int i;
|
|
|
+ int bs_counter = 0;
|
|
|
+ /* Backslash we can point to when one is inserted into the string */
|
|
|
+ const char backslash = '\\';
|
|
|
+
|
|
|
+ /* Smartlist of *char */
|
|
|
+ smartlist_t *arg_chars;
|
|
|
+ arg_chars = smartlist_create();
|
|
|
+
|
|
|
+ /* Quote string if it contains whitespace or is empty */
|
|
|
+ need_quotes = (strchr(arg, ' ') || strchr(arg, '\t') || '\0' == arg[0]);
|
|
|
+
|
|
|
+ /* Build up smartlist of *chars */
|
|
|
+ for (c=arg; *c != '\0'; c++) {
|
|
|
+ if ('"' == *c) {
|
|
|
+ /* Double up backslashes preceding a quote */
|
|
|
+ for (i=0; i<(bs_counter*2); i++)
|
|
|
+ smartlist_add(arg_chars, (void*)&backslash);
|
|
|
+ bs_counter = 0;
|
|
|
+ /* Escape the quote */
|
|
|
+ smartlist_add(arg_chars, (void*)&backslash);
|
|
|
+ smartlist_add(arg_chars, (void*)c);
|
|
|
+ } else if ('\\' == *c) {
|
|
|
+ /* Count backslashes until we know whether to double up */
|
|
|
+ bs_counter++;
|
|
|
+ } else {
|
|
|
+ /* Don't double up slashes preceding a non-quote */
|
|
|
+ for (i=0; i<bs_counter; i++)
|
|
|
+ smartlist_add(arg_chars, (void*)&backslash);
|
|
|
+ bs_counter = 0;
|
|
|
+ smartlist_add(arg_chars, (void*)c);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* Don't double up trailing backslashes */
|
|
|
+ for (i=0; i<bs_counter; i++)
|
|
|
+ smartlist_add(arg_chars, (void*)&backslash);
|
|
|
+
|
|
|
+ /* Allocate space for argument, quotes (if needed), and terminator */
|
|
|
+ formatted_arg = tor_malloc(sizeof(char) *
|
|
|
+ (smartlist_len(arg_chars) + (need_quotes?2:0) + 1));
|
|
|
+
|
|
|
+ /* Add leading quote */
|
|
|
+ i=0;
|
|
|
+ if (need_quotes)
|
|
|
+ formatted_arg[i++] = '"';
|
|
|
+
|
|
|
+ /* Add characters */
|
|
|
+ SMARTLIST_FOREACH(arg_chars, char*, c,
|
|
|
+ {
|
|
|
+ formatted_arg[i++] = *c;
|
|
|
+ });
|
|
|
+
|
|
|
+ /* Add trailing quote */
|
|
|
+ if (need_quotes)
|
|
|
+ formatted_arg[i++] = '"';
|
|
|
+ formatted_arg[i] = '\0';
|
|
|
+
|
|
|
+ smartlist_free(arg_chars);
|
|
|
+ return formatted_arg;
|
|
|
+}
|
|
|
+
|
|
|
+/* Format a command line for use on Windows, which takes the command as a
|
|
|
+ * string rather than string array. Follows the rules from "Parsing C++
|
|
|
+ * Command-Line Arguments" in MSDN. Algorithm based on list2cmdline in the
|
|
|
+ * Python subprocess module. Returns a newly allocated string */
|
|
|
+char *
|
|
|
+tor_join_cmdline(const char *argv[])
|
|
|
+{
|
|
|
+ smartlist_t *argv_list;
|
|
|
+ char *joined_argv;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ /* Format each argument and put the result in a smartlist */
|
|
|
+ argv_list = smartlist_create();
|
|
|
+ for (i=0; argv[i] != NULL; i++) {
|
|
|
+ smartlist_add(argv_list, (void *)format_cmdline_argument(argv[i]));
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Join the arguments with whitespace */
|
|
|
+ joined_argv = smartlist_join_strings(argv_list, " ", 0, NULL);
|
|
|
+
|
|
|
+ /* Free the newly allocated arguments, and the smartlist */
|
|
|
+ SMARTLIST_FOREACH(argv_list, char *, arg,
|
|
|
+ {
|
|
|
+ tor_free(arg);
|
|
|
+ });
|
|
|
+ smartlist_free(argv_list);
|
|
|
+
|
|
|
+ return joined_argv;
|
|
|
+}
|
|
|
+
|
|
|
/** Format <b>child_state</b> and <b>saved_errno</b> as a hex string placed in
|
|
|
* <b>hex_errno</b>. Called between fork and _exit, so must be signal-handler
|
|
|
* safe.
|
|
@@ -3068,9 +3167,7 @@ tor_spawn_background(const char *const filename, const char **argv,
|
|
|
BOOL retval = FALSE;
|
|
|
|
|
|
SECURITY_ATTRIBUTES saAttr;
|
|
|
- smartlist_t *argv_list;
|
|
|
char *joined_argv;
|
|
|
- int i;
|
|
|
|
|
|
/* process_handle must not be NULL */
|
|
|
tor_assert(process_handle != NULL);
|
|
@@ -3116,12 +3213,7 @@ tor_spawn_background(const char *const filename, const char **argv,
|
|
|
|
|
|
/* Windows expects argv to be a whitespace delimited string, so join argv up
|
|
|
*/
|
|
|
- argv_list = smartlist_create();
|
|
|
- for (i=0; argv[i] != NULL; i++) {
|
|
|
- smartlist_add(argv_list, (void *)argv[i]);
|
|
|
- }
|
|
|
-
|
|
|
- joined_argv = smartlist_join_strings(argv_list, " ", 0, NULL);
|
|
|
+ joined_argv = tor_join_cmdline(argv);
|
|
|
|
|
|
ZeroMemory(&(process_handle->pid), sizeof(PROCESS_INFORMATION));
|
|
|
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
|