diff --git a/compat/mingw.c b/compat/mingw.c index f22ab57461..18aecd9bf5 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -139,3 +139,91 @@ void sync(void) void openlog(const char *ident, int option, int facility) { } + +static const char *quote_arg(const char *arg) +{ + /* count chars to quote */ + int len = 0, n = 0; + int force_quotes = 0; + char *q, *d; + const char *p = arg; + while (*p) { + if (isspace(*p)) + force_quotes = 1; + else if (*p == '"' || *p == '\\') + n++; + len++; + p++; + } + if (!force_quotes && n == 0) + return arg; + + /* insert \ where necessary */ + d = q = xmalloc(len+n+3); + *d++ = '"'; + while (*arg) { + if (*arg == '"' || *arg == '\\') + *d++ = '\\'; + *d++ = *arg++; + } + *d++ = '"'; + *d++ = 0; + return q; +} + +static void quote_argv(const char **dst, const char **src) +{ + while (*src) + *dst++ = quote_arg(*src++); + *dst = NULL; +} + +static int try_shell_exec(const char *cmd, const char **argv, const char **env) +{ + char buf[100], *p; + const char **sh_argv; + int n; + int fd = open(cmd, O_RDONLY); + if (fd < 0) + return 0; + n = read(fd, buf, sizeof(buf)-1); + close(fd); + if (n < 5) /* at least '#!/sh' and not error */ + return 0; + + /* check whether the interpreter is sh */ + if (buf[0] != '#' || buf[1] != '!') + return 0; + buf[n] = '\0'; + p = strchr(buf, '\n'); + if (!p || + (p[-3] != '/' && p[-3] != '\\') || + p[-2] != 's' || p[-1] != 'h') + return 0; + + /* + * expand + * git-foo args... + * into + * sh git-foo args... + */ + for (n = 0; argv[n];) n++; + sh_argv = xmalloc((n+2)*sizeof(char*)); + sh_argv[0] = "sh"; + sh_argv[1] = cmd; + quote_argv(&sh_argv[2], &argv[1]); + n = spawnvpe(_P_WAIT, "sh", sh_argv, env); + if (n == -1) + return 1; /* indicate that we tried but failed */ + exit(n); +} + +void mingw_execve(const char *cmd, const char **argv, const char **env) +{ + /* check if git_command is a shell script */ + if (!try_shell_exec(cmd, argv, env)) { + int ret = spawnve(_P_WAIT, cmd, argv, env); + if (ret != -1) + exit(ret); + } +} diff --git a/git-compat-util.h b/git-compat-util.h index d361fcaee8..4b213815b7 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -306,6 +306,8 @@ int syslog(int type, char *bufp, ...); #define LOG_DAEMON 4 unsigned int alarm(unsigned int seconds); #include +void mingw_execve(const char *cmd, const char **argv, const char **env); +#define execve mingw_execve int fork(); typedef int pid_t; pid_t waitpid(pid_t pid, int *status, int options);