mirror of
https://github.com/git/git.git
synced 2026-01-25 10:03:24 +00:00
mingw: add experimental feature to redirect standard handles
On Windows, file handles need to be marked inheritable when they need to be used as standard input/output/error handles for a newly spawned process. The problem with that, of course, is that the "inheritable" flag is global and therefore can wreak havoc with highly multi-threaded applications: other spawned processes will *also* inherit those file handles, despite having *other* input/output/error handles, and never close the former handles because they do not know about them. Let's introduce a set of environment variables (GIT_REDIRECT_STDIN and friends) that point to files, or even better, named pipes and that are used by the spawned Git process. This helps work around above-mentioned issue: those named pipes will be opened in a non-inheritable way upon startup, and no handles are passed around. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
@@ -2139,6 +2139,47 @@ static char *wcstoutfdup_startup(char *buffer, const wchar_t *wcs, size_t len)
|
||||
return memcpy(malloc_startup(len), buffer, len);
|
||||
}
|
||||
|
||||
static void maybe_redirect_std_handle(const wchar_t *key, DWORD std_id, int fd,
|
||||
DWORD desired_access, DWORD flags)
|
||||
{
|
||||
DWORD create_flag = fd ? OPEN_ALWAYS : OPEN_EXISTING;
|
||||
wchar_t buf[MAX_LONG_PATH];
|
||||
DWORD max = ARRAY_SIZE(buf);
|
||||
HANDLE handle;
|
||||
DWORD ret = GetEnvironmentVariableW(key, buf, max);
|
||||
|
||||
if (!ret || ret >= max)
|
||||
return;
|
||||
|
||||
/* make sure this does not leak into child processes */
|
||||
SetEnvironmentVariableW(key, NULL);
|
||||
if (!wcscmp(buf, L"off")) {
|
||||
close(fd);
|
||||
handle = GetStdHandle(std_id);
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(handle);
|
||||
return;
|
||||
}
|
||||
handle = CreateFileW(buf, desired_access, 0, NULL, create_flag,
|
||||
flags, NULL);
|
||||
if (handle != INVALID_HANDLE_VALUE) {
|
||||
int new_fd = _open_osfhandle((intptr_t)handle, O_BINARY);
|
||||
SetStdHandle(std_id, handle);
|
||||
dup2(new_fd, fd);
|
||||
close(new_fd);
|
||||
}
|
||||
}
|
||||
|
||||
static void maybe_redirect_std_handles(void)
|
||||
{
|
||||
maybe_redirect_std_handle(L"GIT_REDIRECT_STDIN", STD_INPUT_HANDLE, 0,
|
||||
GENERIC_READ, FILE_ATTRIBUTE_NORMAL);
|
||||
maybe_redirect_std_handle(L"GIT_REDIRECT_STDOUT", STD_OUTPUT_HANDLE, 1,
|
||||
GENERIC_WRITE, FILE_ATTRIBUTE_NORMAL);
|
||||
maybe_redirect_std_handle(L"GIT_REDIRECT_STDERR", STD_ERROR_HANDLE, 2,
|
||||
GENERIC_WRITE, FILE_FLAG_NO_BUFFERING);
|
||||
}
|
||||
|
||||
void mingw_startup(void)
|
||||
{
|
||||
int i, maxlen, argc;
|
||||
@@ -2146,6 +2187,8 @@ void mingw_startup(void)
|
||||
wchar_t **wenv, **wargv;
|
||||
_startupinfo si;
|
||||
|
||||
maybe_redirect_std_handles();
|
||||
|
||||
/* get wide char arguments and environment */
|
||||
si.newmode = 0;
|
||||
if (__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si) < 0)
|
||||
|
||||
@@ -453,4 +453,10 @@ test_expect_success 're-init from a linked worktree' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success MINGW 'redirect std handles' '
|
||||
GIT_REDIRECT_STDOUT=output.txt git rev-parse --git-dir &&
|
||||
test .git = "$(cat output.txt)" &&
|
||||
test -z "$(GIT_REDIRECT_STDOUT=off git rev-parse --git-dir)"
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
Reference in New Issue
Block a user