Start new processes with our prepared environment variables
[TortoiseGit.git] / src / libgit2 / system-call.c
blob1a63e2ba32706f82960f6b112f6af9941cb9b73c
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2014 TortoiseGit
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "buffer.h"
21 #include "netops.h"
22 #include "system-call.h"
24 int command_start(wchar_t *cmd, COMMAND_HANDLE *commandHandle, LPWSTR pEnv)
26 SECURITY_ATTRIBUTES sa;
27 HANDLE hReadOut = INVALID_HANDLE_VALUE, hWriteOut = INVALID_HANDLE_VALUE, hReadIn = INVALID_HANDLE_VALUE, hWriteIn = INVALID_HANDLE_VALUE;
28 STARTUPINFOW si = { 0 };
29 PROCESS_INFORMATION pi = { 0 };
31 si.cb = sizeof(STARTUPINFOW);
33 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
34 sa.lpSecurityDescriptor = NULL;
35 sa.bInheritHandle = TRUE;
36 if (!CreatePipe(&hReadOut, &hWriteOut, &sa, 0)) {
37 giterr_set(GITERR_OS, "Could not create pipe");
38 return -1;
40 if (!CreatePipe(&hReadIn, &hWriteIn, &sa, 0)) {
41 giterr_set(GITERR_OS, "Could not create pipe");
42 CloseHandle(hReadOut);
43 CloseHandle(hWriteOut);
44 return -1;
47 si.hStdOutput = hWriteOut;
48 si.hStdInput = hReadIn;
49 si.hStdError = INVALID_HANDLE_VALUE;
51 // Ensure the read/write handle to the pipe for STDOUT resp. STDIN are not inherited.
52 if (!SetHandleInformation(hReadOut, HANDLE_FLAG_INHERIT, 0) || !SetHandleInformation(hWriteIn, HANDLE_FLAG_INHERIT, 0)) {
53 CloseHandle(hReadOut);
54 CloseHandle(hWriteOut);
55 CloseHandle(hReadIn);
56 CloseHandle(hWriteIn);
57 return -1;
60 si.wShowWindow = SW_HIDE;
61 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
63 if (!CreateProcessW(NULL, cmd, NULL, NULL, TRUE, pEnv ? CREATE_UNICODE_ENVIRONMENT : 0, pEnv, NULL, &si, &pi)) {
64 giterr_set(GITERR_OS, "Could not start external tool");
65 CloseHandle(hReadOut);
66 CloseHandle(hWriteOut);
67 CloseHandle(hReadIn);
68 CloseHandle(hWriteIn);
69 return -1;
72 AllowSetForegroundWindow(pi.dwProcessId);
73 WaitForInputIdle(pi.hProcess, 10000);
75 CloseHandle(hReadIn);
76 CloseHandle(hWriteOut);
78 commandHandle->pi = pi;
79 commandHandle->out = hReadOut;
80 commandHandle->in = hWriteIn;
81 commandHandle->running = TRUE;
82 return 0;
85 int command_read(COMMAND_HANDLE *commandHandle, char *buffer, size_t buf_size, size_t *bytes_read)
87 *bytes_read = 0;
89 if (!ReadFile(commandHandle->out, buffer, (DWORD)buf_size, (DWORD*)bytes_read, NULL)) {
90 giterr_set(GITERR_OS, "could not read data from external process");
91 return -1;
94 return 0;
97 int command_readall(COMMAND_HANDLE *commandHandle, git_buf *buf)
99 size_t bytes_read = 0;
100 do {
101 char buffer[65536];
102 command_read(commandHandle->out, buffer, sizeof(buffer), &bytes_read);
103 git_buf_put(buf, buffer, bytes_read);
104 } while (bytes_read);
106 return 0;
109 int command_write(COMMAND_HANDLE *commandHandle, const char *buffer, size_t len)
111 size_t off = 0;
112 DWORD written = 0;
114 do {
115 if (!WriteFile(commandHandle->in, buffer + off, (DWORD)(len - off), &written, NULL)) {
116 giterr_set(GITERR_OS, "could not write data to external process");
117 return -1;
120 off += written;
121 } while (off < len);
123 return 0;
126 int command_write_gitbuf(COMMAND_HANDLE *commandHandle, const git_buf *buf)
128 return command_write(commandHandle, buf->ptr, buf->size);
131 static void safeCloseHandle(HANDLE *handle)
133 if (*handle != INVALID_HANDLE_VALUE) {
134 CloseHandle(*handle);
135 *handle = INVALID_HANDLE_VALUE;
139 void command_close_stdin(COMMAND_HANDLE *commandHandle)
141 safeCloseHandle(&commandHandle->in);
144 void command_close_stdout(COMMAND_HANDLE *commandHandle)
146 safeCloseHandle(&commandHandle->out);
149 DWORD command_close(COMMAND_HANDLE *commandHandle)
151 if (!commandHandle->running)
152 return 1;
154 commandHandle->running = FALSE;
156 command_close_stdin(commandHandle);
157 command_close_stdout(commandHandle);
159 CloseHandle(commandHandle->pi.hThread);
161 WaitForSingleObject(commandHandle->pi.hProcess, INFINITE);
163 DWORD exitcode = MAXDWORD;
164 GetExitCodeProcess(commandHandle->pi.hProcess, &exitcode);
165 CloseHandle(commandHandle->pi.hProcess);
167 return exitcode;