PageRenderTime 39ms CodeModel.GetById 14ms app.highlight 20ms RepoModel.GetById 2ms app.codeStats 0ms

/toolkit/xre/nsWindowsRestart.cpp

http://github.com/zpao/v8monkey
C++ | 327 lines | 213 code | 38 blank | 76 comment | 28 complexity | 3900729af384ea236de302c5bea33a10 MD5 | raw file
  1/* ***** BEGIN LICENSE BLOCK *****
  2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3 *
  4 * The contents of this file are subject to the Mozilla Public License Version
  5 * 1.1 (the "License"); you may not use this file except in compliance with
  6 * the License. You may obtain a copy of the License at
  7 * http://www.mozilla.org/MPL/
  8 *
  9 * Software distributed under the License is distributed on an "AS IS" basis,
 10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 11 * for the specific language governing rights and limitations under the
 12 * License.
 13 *
 14 * The Original Code is Mozilla XULRunner bootstrap.
 15 *
 16 * The Initial Developer of the Original Code is
 17 * Benjamin Smedberg <benjamin@smedbergs.us>.
 18 *
 19 * Portions created by the Initial Developer are Copyright (C) 2005
 20 * the Mozilla Foundation. All Rights Reserved.
 21 *
 22 * Contributor(s):
 23 *   Robert Strong <robert.bugzilla@gmail.com>
 24 *   Brian R. Bondy <netzen@gmail.com>
 25 *
 26 * Alternatively, the contents of this file may be used under the terms of
 27 * either the GNU General Public License Version 2 or later (the "GPL"), or
 28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 29 * in which case the provisions of the GPL or the LGPL are applicable instead
 30 * of those above. If you wish to allow use of your version of this file only
 31 * under the terms of either the GPL or the LGPL, and not to allow others to
 32 * use your version of this file under the terms of the MPL, indicate your
 33 * decision by deleting the provisions above and replace them with the notice
 34 * and other provisions required by the GPL or the LGPL. If you do not delete
 35 * the provisions above, a recipient may use your version of this file under
 36 * the terms of any one of the MPL, the GPL or the LGPL.
 37 *
 38 * ***** END LICENSE BLOCK ***** */
 39
 40// This file is not build directly. Instead, it is included in multiple
 41// shared objects.
 42
 43#ifdef nsWindowsRestart_cpp
 44#error "nsWindowsRestart.cpp is not a header file, and must only be included once."
 45#else
 46#define nsWindowsRestart_cpp
 47#endif
 48
 49#include "nsUTF8Utils.h"
 50
 51#include <shellapi.h>
 52
 53// Needed for CreateEnvironmentBlock
 54#include <userenv.h>
 55#pragma comment(lib, "userenv.lib")
 56
 57/**
 58 * Get the length that the string will take and takes into account the
 59 * additional length if the string needs to be quoted and if characters need to
 60 * be escaped.
 61 */
 62static int ArgStrLen(const PRUnichar *s)
 63{
 64  int backslashes = 0;
 65  int i = wcslen(s);
 66  BOOL hasDoubleQuote = wcschr(s, L'"') != NULL;
 67  // Only add doublequotes if the string contains a space or a tab
 68  BOOL addDoubleQuotes = wcspbrk(s, L" \t") != NULL;
 69
 70  if (addDoubleQuotes) {
 71    i += 2; // initial and final duoblequote
 72  }
 73
 74  if (hasDoubleQuote) {
 75    while (*s) {
 76      if (*s == '\\') {
 77        ++backslashes;
 78      } else {
 79        if (*s == '"') {
 80          // Escape the doublequote and all backslashes preceding the doublequote
 81          i += backslashes + 1;
 82        }
 83
 84        backslashes = 0;
 85      }
 86
 87      ++s;
 88    }
 89  }
 90
 91  return i;
 92}
 93
 94/**
 95 * Copy string "s" to string "d", quoting the argument as appropriate and
 96 * escaping doublequotes along with any backslashes that immediately precede
 97 * doublequotes.
 98 * The CRT parses this to retrieve the original argc/argv that we meant,
 99 * see STDARGV.C in the MSVC CRT sources.
100 *
101 * @return the end of the string
102 */
103static PRUnichar* ArgToString(PRUnichar *d, const PRUnichar *s)
104{
105  int backslashes = 0;
106  BOOL hasDoubleQuote = wcschr(s, L'"') != NULL;
107  // Only add doublequotes if the string contains a space or a tab
108  BOOL addDoubleQuotes = wcspbrk(s, L" \t") != NULL;
109
110  if (addDoubleQuotes) {
111    *d = '"'; // initial doublequote
112    ++d;
113  }
114
115  if (hasDoubleQuote) {
116    int i;
117    while (*s) {
118      if (*s == '\\') {
119        ++backslashes;
120      } else {
121        if (*s == '"') {
122          // Escape the doublequote and all backslashes preceding the doublequote
123          for (i = 0; i <= backslashes; ++i) {
124            *d = '\\';
125            ++d;
126          }
127        }
128
129        backslashes = 0;
130      }
131
132      *d = *s;
133      ++d; ++s;
134    }
135  } else {
136    wcscpy(d, s);
137    d += wcslen(s);
138  }
139
140  if (addDoubleQuotes) {
141    *d = '"'; // final doublequote
142    ++d;
143  }
144
145  return d;
146}
147
148/**
149 * Creates a command line from a list of arguments. The returned
150 * string is allocated with "malloc" and should be "free"d.
151 *
152 * argv is UTF8
153 */
154PRUnichar*
155MakeCommandLine(int argc, PRUnichar **argv)
156{
157  int i;
158  int len = 0;
159
160  // The + 1 of the last argument handles the allocation for null termination
161  for (i = 0; i < argc; ++i)
162    len += ArgStrLen(argv[i]) + 1;
163
164  // Protect against callers that pass 0 arguments
165  if (len == 0)
166    len = 1;
167
168  PRUnichar *s = (PRUnichar*) malloc(len * sizeof(PRUnichar));
169  if (!s)
170    return NULL;
171
172  PRUnichar *c = s;
173  for (i = 0; i < argc; ++i) {
174    c = ArgToString(c, argv[i]);
175    if (i + 1 != argc) {
176      *c = ' ';
177      ++c;
178    }
179  }
180
181  *c = '\0';
182
183  return s;
184}
185
186/**
187 * Convert UTF8 to UTF16 without using the normal XPCOM goop, which we
188 * can't link to updater.exe.
189 */
190static PRUnichar*
191AllocConvertUTF8toUTF16(const char *arg)
192{
193  // UTF16 can't be longer in units than UTF8
194  int len = strlen(arg);
195  PRUnichar *s = new PRUnichar[(len + 1) * sizeof(PRUnichar)];
196  if (!s)
197    return NULL;
198
199  ConvertUTF8toUTF16 convert(s);
200  convert.write(arg, len);
201  convert.write_terminator();
202  return s;
203}
204
205static void
206FreeAllocStrings(int argc, PRUnichar **argv)
207{
208  while (argc) {
209    --argc;
210    delete [] argv[argc];
211  }
212
213  delete [] argv;
214}
215
216/**
217 * Launch a child process with the specified arguments.
218 * @note argv[0] is ignored
219 * @note The form of this function that takes char **argv expects UTF-8
220 */
221
222BOOL
223WinLaunchChild(const PRUnichar *exePath, 
224               int argc, PRUnichar **argv, 
225               HANDLE userToken = NULL);
226
227BOOL
228WinLaunchChild(const PRUnichar *exePath, 
229               int argc, char **argv, 
230               HANDLE userToken)
231{
232  PRUnichar** argvConverted = new PRUnichar*[argc];
233  if (!argvConverted)
234    return FALSE;
235
236  for (int i = 0; i < argc; ++i) {
237    argvConverted[i] = AllocConvertUTF8toUTF16(argv[i]);
238    if (!argvConverted[i]) {
239      FreeAllocStrings(i, argvConverted);
240      return FALSE;
241    }
242  }
243
244  BOOL ok = WinLaunchChild(exePath, argc, argvConverted, userToken);
245  FreeAllocStrings(argc, argvConverted);
246  return ok;
247}
248
249BOOL
250WinLaunchChild(const PRUnichar *exePath, 
251               int argc, 
252               PRUnichar **argv, 
253               HANDLE userToken)
254{
255  PRUnichar *cl;
256  BOOL ok;
257
258  cl = MakeCommandLine(argc, argv);
259  if (!cl) {
260    return FALSE;
261  }
262
263  STARTUPINFOW si = {0};
264  si.cb = sizeof(STARTUPINFOW);
265  si.lpDesktop = L"winsta0\\Default";
266  PROCESS_INFORMATION pi = {0};
267
268  if (userToken == NULL) {
269    ok = CreateProcessW(exePath,
270                        cl,
271                        NULL,  // no special security attributes
272                        NULL,  // no special thread attributes
273                        FALSE, // don't inherit filehandles
274                        0,     // creation flags
275                        NULL,  // inherit my environment
276                        NULL,  // use my current directory
277                        &si,
278                        &pi);
279  } else {
280    // Create an environment block for the process we're about to start using
281    // the user's token.
282    LPVOID environmentBlock = NULL;
283    if (!CreateEnvironmentBlock(&environmentBlock, userToken, TRUE)) {
284      environmentBlock = NULL;
285    }
286
287    ok = CreateProcessAsUserW(userToken, 
288                              exePath,
289                              cl,
290                              NULL,  // no special security attributes
291                              NULL,  // no special thread attributes
292                              FALSE, // don't inherit filehandles
293                              0,     // creation flags
294                              environmentBlock,
295                              NULL,  // use my current directory
296                              &si,
297                              &pi);
298
299    if (environmentBlock) {
300      DestroyEnvironmentBlock(environmentBlock);
301    }
302  }
303
304  if (ok) {
305    CloseHandle(pi.hProcess);
306    CloseHandle(pi.hThread);
307  } else {
308    LPVOID lpMsgBuf = NULL;
309    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
310                  FORMAT_MESSAGE_FROM_SYSTEM |
311                  FORMAT_MESSAGE_IGNORE_INSERTS,
312                  NULL,
313                  GetLastError(),
314                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
315                  (LPTSTR) &lpMsgBuf,
316                  0,
317                  NULL);
318    wprintf(L"Error restarting: %s\n", lpMsgBuf ? lpMsgBuf : L"(null)");
319    if (lpMsgBuf)
320      LocalFree(lpMsgBuf);
321  }
322
323  free(cl);
324
325  return ok;
326}
327