5 /* Windows-specific implementation of exec_program_v() */
10 #include "git-compat-util.h"
12 #include "systeminfo.h"
35 #define MAX_PROCESSING_TIME (60 * 1000)
37 static char **path_split(const char *envpath
)
39 char *orig
, *p
, **path
;
42 orig
= xstrdup(envpath
);
52 if (*dir
) /* not earlier, catches series of ; */
59 path
= (char **)xmalloc((n
+ 1) * sizeof(char *));
66 path
[i
++] = xstrdup(p
);
68 p
= p
+ strlen(p
) + 1;
78 static char *path_lookup_prog(const char *dir
, const char *cmd
)
81 int len
= strlen(cmd
);
82 int isexe
= len
>= 4 && 0 == strcasecmp(cmd
+ len
- 4, ".exe");
85 snprintf(path
, sizeof(path
), "%s/%s", dir
, cmd
);
87 snprintf(path
, sizeof(path
), "%s/%s.exe", dir
, cmd
);
90 if (0 == access(path
, F_OK
))
97 * Determines the absolute path of cmd using the the split path in path.
98 * If cmd contains a slash or backslash, no lookup is performed.
100 static char *path_lookup(const char *cmd
, char **path
)
104 if (strchr(cmd
, '/') || strchr(cmd
, '\\'))
107 while (!prog
&& *path
)
108 prog
= path_lookup_prog(*path
++, cmd
);
113 static const char *escape_arg(const char *arg
)
115 /* count chars to quote */
117 int force_quotes
= 0;
120 if (!*p
) force_quotes
= 1;
122 if (isspace(*p
) || *p
== '*' || *p
== '?' || *p
== '{')
126 else if (*p
== '\\') {
140 if (!force_quotes
&& n
== 0)
143 /* insert \ where necessary */
144 d
= q
= (char *)xmalloc(len
+n
+3);
149 else if (*arg
== '\\') {
151 while (*arg
== '\\') {
168 static void cmd_rec_init(const char **argv
, const char *envpath
,
173 char **path
= path_split(envpath
);
174 strbuf_init(&args
, 0);
176 rec
->cmd
= path_lookup(*argv
, path
);
181 for (; *argv
; argv
++) {
182 escaped
= (char *)escape_arg(*argv
);
184 strbuf_addch(&args
, ' ');
185 strbuf_addstr(&args
, escaped
);
186 if (escaped
!= *argv
)
190 rec
->args
= strbuf_detach(&args
, NULL
);
193 static void cmd_rec_final(struct cmd_rec
*rec
)
202 static BOOL
create_output_handles(PHANDLE hRead
, PHANDLE hWrite
, HANDLE hProc
)
206 /* create pipe with no inheritance */
207 if (!CreatePipe(hRead
, &hWriteTmp
, NULL
, 0))
210 /* dup write end with inheritance to hWrite and close hWriteTmp */
211 if (!DuplicateHandle(hProc
, hWriteTmp
, hProc
, hWrite
, 0, TRUE
,
212 DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
)) {
213 CloseHandle(hWriteTmp
);
220 static BOOL
create_handles(struct handles_rec
*hStd
, struct output_rec
*hOutput
)
222 HANDLE hProc
= GetCurrentProcess();
223 hStd
->in
= GetStdHandle(STD_INPUT_HANDLE
);
226 if (!create_output_handles(&hOutput
->out
, &hStd
->out
, hProc
))
230 if (!create_output_handles(&hOutput
->err
, &hStd
->err
, hProc
))
236 static BOOL
has_console(void)
238 HANDLE con
= CreateFile("CONOUT$", GENERIC_WRITE
, FILE_SHARE_WRITE
,
239 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
241 if (con
== INVALID_HANDLE_VALUE
) {
249 static void path_rec_init(const char *gitpath
, struct path_rec
*rec
)
251 struct strbuf path
= STRBUF_INIT
;
254 strbuf_addstr(&path
, gitpath
);
256 if ((rec
->envpath_old
= getenv("PATH"))) {
257 rec
->envpath_old
= xstrdup(rec
->envpath_old
);
258 strbuf_addch(&path
, ';');
259 strbuf_addstr(&path
, rec
->envpath_old
);
263 setenv("PATH", path
.buf
, 1);
264 rec
->envpath
= strbuf_detach(&path
, NULL
);
268 static void path_rec_final(struct path_rec
*rec
)
270 if (rec
->envpath_old
) {
271 setenv("PATH", rec
->envpath_old
, 1);
272 free(rec
->envpath_old
);
279 static void path_split_free(char **path
)
293 static HANDLE
process_init(struct cmd_rec cmdInfo
, const char *dir
,
294 struct handles_rec hStd
)
297 PROCESS_INFORMATION pi
;
301 flags
= has_console() ? 0 : CREATE_NO_WINDOW
;
303 memset(&pi
, 0, sizeof(pi
));
304 memset(&si
, 0, sizeof(si
));
306 si
.dwFlags
= STARTF_USESTDHANDLES
;
307 si
.hStdInput
= hStd
.in
;
308 si
.hStdOutput
= hStd
.out
;
309 si
.hStdError
= hStd
.err
;
311 success
= CreateProcess(cmdInfo
.cmd
, cmdInfo
.args
, NULL
, NULL
,
312 TRUE
, flags
, NULL
, dir
, &si
, &pi
);
317 /* close our end of the output handles */
318 CloseHandle(hStd
.out
);
319 CloseHandle(hStd
.err
);
321 CloseHandle(pi
.hThread
);
323 return success
? pi
.hProcess
: INVALID_HANDLE_VALUE
;
326 static int process_final(HANDLE hProc
, int wait
, struct strbuf
*output
,
327 struct strbuf
*error
, struct output_rec hOutput
)
333 res
= wait_for_process((pid_t
)hProc
, MAX_PROCESSING_TIME
, &status
);
341 int fd
= _open_osfhandle((intptr_t)hOutput
.out
, _O_RDONLY
);
342 strbuf_read(output
, fd
, 0);
346 int fd
= _open_osfhandle((intptr_t)hOutput
.err
, _O_RDONLY
);
347 strbuf_read(error
, fd
, 0);
351 status
= -ERR_RUN_COMMAND_WAITPID_NOEXIT
;
356 CloseHandle(hOutput
.out
);
357 CloseHandle(hOutput
.err
);
362 int exec_program_v(const char *working_directory
, struct strbuf
*output
,
363 struct strbuf
*error
, int flags
, const char **argv
)
365 struct handles_rec hStd
;
366 struct output_rec hOutput
;
367 struct path_rec pathInfo
= {NULL
, NULL
};
368 struct cmd_rec cmdInfo
= {NULL
, NULL
};
371 int wait
, status
= 0;
373 if (!(gitpath
= git_path()))
376 if (!create_handles(&hStd
, &hOutput
))
379 path_rec_init(gitpath
, &pathInfo
);
380 cmd_rec_init(argv
, pathInfo
.envpath
, &cmdInfo
);
383 hProc
= process_init(cmdInfo
, working_directory
, hStd
);
385 if (INVALID_HANDLE_VALUE
!= hProc
) {
386 wait
= WAITMODE
& flags
;
387 status
= process_final(hProc
, wait
, output
, error
, hOutput
);
391 cmd_rec_final(&cmdInfo
);
392 path_rec_final(&pathInfo
);