1
#include "../git-compat-util.h"
2
+#include "../strbuf.h"
3
4
unsigned int _CRT_fmode = _O_BINARY;
5
187
return ret;
188
}
189
190
+/*
191
+ * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
192
+ * (Parsing C++ Command-Line Arguments)
193
+ */
194
+static const char *quote_arg(const char *arg)
195
+{
196
+ /* count chars to quote */
197
+ int len = 0, n = 0;
198
+ int force_quotes = 0;
199
+ char *q, *d;
200
+ const char *p = arg;
201
+ if (!*p) force_quotes = 1;
202
+ while (*p) {
203
+ if (isspace(*p) || *p == '*' || *p == '?' || *p == '{')
204
+ force_quotes = 1;
205
+ else if (*p == '"')
206
+ n++;
207
+ else if (*p == '\\') {
208
+ int count = 0;
209
+ while (*p == '\\') {
210
+ count++;
211
+ p++;
212
+ len++;
213
+ }
214
+ if (*p == '"')
215
+ n += count*2 + 1;
216
+ continue;
217
+ }
218
+ len++;
219
+ p++;
220
+ }
221
+ if (!force_quotes && n == 0)
222
+ return arg;
223
+
224
+ /* insert \ where necessary */
225
+ d = q = xmalloc(len+n+3);
226
+ *d++ = '"';
227
+ while (*arg) {
228
+ if (*arg == '"')
229
+ *d++ = '\\';
230
+ else if (*arg == '\\') {
231
+ int count = 0;
232
+ while (*arg == '\\') {
233
+ count++;
234
+ *d++ = *arg++;
235
+ }
236
+ if (*arg == '"') {
237
+ while (count-- > 0)
238
+ *d++ = '\\';
239
+ *d++ = '\\';
240
+ }
241
+ }
242
+ *d++ = *arg++;
243
+ }
244
+ *d++ = '"';
245
+ *d++ = 0;
246
+ return q;
247
+}
248
+
249
static const char *parse_interpreter(const char *cmd)
250
{
251
static char buf[100];
367
return prog;
368
}
369
370
+static int env_compare(const void *a, const void *b)
371
+{
372
+ char *const *ea = a;
373
+ char *const *eb = b;
374
+ return strcasecmp(*ea, *eb);
375
+}
376
+
377
+static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
378
+ int prepend_cmd)
379
+{
380
+ STARTUPINFO si;
381
+ PROCESS_INFORMATION pi;
382
+ struct strbuf envblk, args;
383
+ unsigned flags;
384
+ BOOL ret;
385
+
386
+ /* Determine whether or not we are associated to a console */
387
+ HANDLE cons = CreateFile("CONOUT$", GENERIC_WRITE,
388
+ FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
389
+ FILE_ATTRIBUTE_NORMAL, NULL);
390
+ if (cons == INVALID_HANDLE_VALUE) {
391
+ /* There is no console associated with this process.
392
+ * Since the child is a console process, Windows
393
+ * would normally create a console window. But
394
+ * since we'll be redirecting std streams, we do
395
+ * not need the console.
396
+ */
397
+ flags = CREATE_NO_WINDOW;
398
+ } else {
399
+ /* There is already a console. If we specified
400
+ * CREATE_NO_WINDOW here, too, Windows would
401
+ * disassociate the child from the console.
402
+ * Go figure!
403
+ */
404
+ flags = 0;
405
+ CloseHandle(cons);
406
+ }
407
+ memset(&si, 0, sizeof(si));
408
+ si.cb = sizeof(si);
409
+ si.dwFlags = STARTF_USESTDHANDLES;
410
+ si.hStdInput = (HANDLE) _get_osfhandle(0);
411
+ si.hStdOutput = (HANDLE) _get_osfhandle(1);
412
+ si.hStdError = (HANDLE) _get_osfhandle(2);
413
+
414
+ /* concatenate argv, quoting args as we go */
415
+ strbuf_init(&args, 0);
416
+ if (prepend_cmd) {
417
+ char *quoted = (char *)quote_arg(cmd);
418
+ strbuf_addstr(&args, quoted);
419
+ if (quoted != cmd)
420
+ free(quoted);
421
+ }
422
+ for (; *argv; argv++) {
423
+ char *quoted = (char *)quote_arg(*argv);
424
+ if (*args.buf)
425
+ strbuf_addch(&args, ' ');
426
+ strbuf_addstr(&args, quoted);
427
+ if (quoted != *argv)
428
+ free(quoted);
429
+ }
430
+
431
+ if (env) {
432
+ int count = 0;
433
+ char **e, **sorted_env;
434
+
435
+ for (e = env; *e; e++)
436
+ count++;
437
+
438
+ /* environment must be sorted */
439
+ sorted_env = xmalloc(sizeof(*sorted_env) * (count + 1));
440
+ memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1));
441
+ qsort(sorted_env, count, sizeof(*sorted_env), env_compare);
442
+
443
+ strbuf_init(&envblk, 0);
444
+ for (e = sorted_env; *e; e++) {
445
+ strbuf_addstr(&envblk, *e);
446
+ strbuf_addch(&envblk, '\0');
447
+ }
448
+ free(sorted_env);
449
+ }
450
+
451
+ memset(&pi, 0, sizeof(pi));
452
+ ret = CreateProcess(cmd, args.buf, NULL, NULL, TRUE, flags,
453
+ env ? envblk.buf : NULL, NULL, &si, &pi);
454
+
455
+ if (env)
456
+ strbuf_release(&envblk);
457
+ strbuf_release(&args);
458
+
459
+ if (!ret) {
460
+ errno = ENOENT;
461
+ return -1;
462
+ }
463
+ CloseHandle(pi.hThread);
464
+ return (pid_t)pi.hProcess;
465
+}
466
+
467
+pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env)
468
+{
469
+ pid_t pid;
470
+ char **path = get_path_split();
471
+ char *prog = path_lookup(cmd, path, 0);
472
+
473
+ if (!prog) {
474
+ errno = ENOENT;
475
+ pid = -1;
476
+ }
477
+ else {
478
+ const char *interpr = parse_interpreter(prog);
479
+
480
+ if (interpr) {
481
+ const char *argv0 = argv[0];
482
+ char *iprog = path_lookup(interpr, path, 1);
483
+ argv[0] = prog;
484
+ if (!iprog) {
485
+ errno = ENOENT;
486
+ pid = -1;
487
+ }
488
+ else {
489
+ pid = mingw_spawnve(iprog, argv, env, 1);
490
+ free(iprog);
491
+ }
492
+ argv[0] = argv0;
493
+ }
494
+ else
495
+ pid = mingw_spawnve(prog, argv, env, 0);
496
+ free(prog);
497
+ }
498
+ free_path_split(path);
499
+ return pid;
500
+}
501
+
502
static int try_shell_exec(const char *cmd, char *const *argv, char **env)
503
{
504
const char *interpr = parse_interpreter(cmd);
514
int argc = 0;
515
const char **argv2;
516
while (argv[argc]) argc++;
325
- argv2 = xmalloc(sizeof(*argv) * (argc+2));
326
- argv2[0] = (char *)interpr;
327
- argv2[1] = (char *)cmd; /* full path to the script file */
328
- memcpy(&argv2[2], &argv[1], sizeof(*argv) * argc);
329
- pid = spawnve(_P_NOWAIT, prog, argv2, (const char **)env);
517
+ argv2 = xmalloc(sizeof(*argv) * (argc+1));
518
+ argv2[0] = (char *)cmd; /* full path to the script file */
519
+ memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);
520
+ pid = mingw_spawnve(prog, argv2, env, 1);
521
if (pid >= 0) {
522
int status;
523
if (waitpid(pid, &status, 0) < 0)
538
if (!try_shell_exec(cmd, argv, (char **)env)) {
539
int pid, status;
540
350
- pid = spawnve(_P_NOWAIT, cmd, (const char **)argv, (const char **)env);
541
+ pid = mingw_spawnve(cmd, (const char **)argv, (char **)env, 0);
542
if (pid < 0)
543
return;
544
if (waitpid(pid, &status, 0) < 0)