Windows: avoid the "dup dance" when spawning a child process
[gitweb.git] / compat / mingw.c
index 0d73f15fa894cb0ded20f0cdd1f7fec3da1643f1..73762473c55ea18e60aa74eab2fab5936a966df0 100644 (file)
@@ -3,8 +3,6 @@
 #include <conio.h>
 #include "../strbuf.h"
 
-#include <shellapi.h>
-
 static int err_win_to_posix(DWORD winerr)
 {
        int error = ENOSYS;
@@ -301,46 +299,25 @@ int gettimeofday(struct timeval *tv, void *tz)
 
 int pipe(int filedes[2])
 {
-       int fd;
-       HANDLE h[2], parent;
-
-       if (_pipe(filedes, 8192, 0) < 0)
-               return -1;
-
-       parent = GetCurrentProcess();
+       HANDLE h[2];
 
-       if (!DuplicateHandle (parent, (HANDLE)_get_osfhandle(filedes[0]),
-                       parent, &h[0], 0, FALSE, DUPLICATE_SAME_ACCESS)) {
-               close(filedes[0]);
-               close(filedes[1]);
+       /* this creates non-inheritable handles */
+       if (!CreatePipe(&h[0], &h[1], NULL, 8192)) {
+               errno = err_win_to_posix(GetLastError());
                return -1;
        }
-       if (!DuplicateHandle (parent, (HANDLE)_get_osfhandle(filedes[1]),
-                       parent, &h[1], 0, FALSE, DUPLICATE_SAME_ACCESS)) {
-               close(filedes[0]);
-               close(filedes[1]);
-               CloseHandle(h[0]);
-               return -1;
-       }
-       fd = _open_osfhandle((int)h[0], O_NOINHERIT);
-       if (fd < 0) {
-               close(filedes[0]);
-               close(filedes[1]);
+       filedes[0] = _open_osfhandle((int)h[0], O_NOINHERIT);
+       if (filedes[0] < 0) {
                CloseHandle(h[0]);
                CloseHandle(h[1]);
                return -1;
        }
-       close(filedes[0]);
-       filedes[0] = fd;
-       fd = _open_osfhandle((int)h[1], O_NOINHERIT);
-       if (fd < 0) {
+       filedes[1] = _open_osfhandle((int)h[1], O_NOINHERIT);
+       if (filedes[0] < 0) {
                close(filedes[0]);
-               close(filedes[1]);
                CloseHandle(h[1]);
                return -1;
        }
-       close(filedes[1]);
-       filedes[1] = fd;
        return 0;
 }
 
@@ -638,8 +615,8 @@ static int env_compare(const void *a, const void *b)
        return strcasecmp(*ea, *eb);
 }
 
-static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
-                          int prepend_cmd)
+static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
+                             int prepend_cmd, int fhin, int fhout, int fherr)
 {
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
@@ -675,9 +652,9 @@ static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
        memset(&si, 0, sizeof(si));
        si.cb = sizeof(si);
        si.dwFlags = STARTF_USESTDHANDLES;
-       si.hStdInput = (HANDLE) _get_osfhandle(0);
-       si.hStdOutput = (HANDLE) _get_osfhandle(1);
-       si.hStdError = (HANDLE) _get_osfhandle(2);
+       si.hStdInput = (HANDLE) _get_osfhandle(fhin);
+       si.hStdOutput = (HANDLE) _get_osfhandle(fhout);
+       si.hStdError = (HANDLE) _get_osfhandle(fherr);
 
        /* concatenate argv, quoting args as we go */
        strbuf_init(&args, 0);
@@ -732,7 +709,14 @@ static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
        return (pid_t)pi.hProcess;
 }
 
-pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env)
+static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
+                          int prepend_cmd)
+{
+       return mingw_spawnve_fd(cmd, argv, env, prepend_cmd, 0, 1, 2);
+}
+
+pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
+                    int fhin, int fhout, int fherr)
 {
        pid_t pid;
        char **path = get_path_split();
@@ -754,13 +738,15 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env)
                                pid = -1;
                        }
                        else {
-                               pid = mingw_spawnve(iprog, argv, env, 1);
+                               pid = mingw_spawnve_fd(iprog, argv, env, 1,
+                                                      fhin, fhout, fherr);
                                free(iprog);
                        }
                        argv[0] = argv0;
                }
                else
-                       pid = mingw_spawnve(prog, argv, env, 0);
+                       pid = mingw_spawnve_fd(prog, argv, env, 0,
+                                              fhin, fhout, fherr);
                free(prog);
        }
        free_path_split(path);
@@ -1338,8 +1324,22 @@ static const char *make_backslash_path(const char *path)
 void mingw_open_html(const char *unixpath)
 {
        const char *htmlpath = make_backslash_path(unixpath);
+       typedef HINSTANCE (WINAPI *T)(HWND, const char *,
+                       const char *, const char *, const char *, INT);
+       T ShellExecute;
+       HMODULE shell32;
+
+       shell32 = LoadLibrary("shell32.dll");
+       if (!shell32)
+               die("cannot load shell32.dll");
+       ShellExecute = (T)GetProcAddress(shell32, "ShellExecuteA");
+       if (!ShellExecute)
+               die("cannot run browser");
+
        printf("Launching default browser to display HTML ...\n");
        ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0);
+
+       FreeLibrary(shell32);
 }
 
 int link(const char *oldpath, const char *newpath)