|  | @@ -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));
 |