Skip to content

Commit 74ef465

Browse files
committed
Merge branch 'js/mingw-redirect-std-handles' into maint
MinGW updates. * js/mingw-redirect-std-handles: mingw: document the standard handle redirection mingw: optionally redirect stderr/stdout via the same handle mingw: add experimental feature to redirect standard handles
2 parents 558d856 + b2f5571 commit 74ef465

File tree

3 files changed

+88
-0
lines changed

3 files changed

+88
-0
lines changed

Documentation/git.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,24 @@ of clones and fetches.
709709
the background which do not want to cause lock contention with
710710
other operations on the repository. Defaults to `1`.
711711

712+
`GIT_REDIRECT_STDIN`::
713+
`GIT_REDIRECT_STDOUT`::
714+
`GIT_REDIRECT_STDERR`::
715+
Windows-only: allow redirecting the standard input/output/error
716+
handles to paths specified by the environment variables. This is
717+
particularly useful in multi-threaded applications where the
718+
canonical way to pass standard handles via `CreateProcess()` is
719+
not an option because it would require the handles to be marked
720+
inheritable (and consequently *every* spawned process would
721+
inherit them, possibly blocking regular Git operations). The
722+
primary intended use case is to use named pipes for communication
723+
(e.g. `\\.\pipe\my-git-stdin-123`).
724+
+
725+
Two special values are supported: `off` will simply close the
726+
corresponding standard handle, and if `GIT_REDIRECT_STDERR` is
727+
`2>&1`, standard error will be redirected to the same handle as
728+
standard output.
729+
712730
Discussion[[Discussion]]
713731
------------------------
714732

compat/mingw.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2139,13 +2139,71 @@ static char *wcstoutfdup_startup(char *buffer, const wchar_t *wcs, size_t len)
21392139
return memcpy(malloc_startup(len), buffer, len);
21402140
}
21412141

2142+
static void maybe_redirect_std_handle(const wchar_t *key, DWORD std_id, int fd,
2143+
DWORD desired_access, DWORD flags)
2144+
{
2145+
DWORD create_flag = fd ? OPEN_ALWAYS : OPEN_EXISTING;
2146+
wchar_t buf[MAX_PATH];
2147+
DWORD max = ARRAY_SIZE(buf);
2148+
HANDLE handle;
2149+
DWORD ret = GetEnvironmentVariableW(key, buf, max);
2150+
2151+
if (!ret || ret >= max)
2152+
return;
2153+
2154+
/* make sure this does not leak into child processes */
2155+
SetEnvironmentVariableW(key, NULL);
2156+
if (!wcscmp(buf, L"off")) {
2157+
close(fd);
2158+
handle = GetStdHandle(std_id);
2159+
if (handle != INVALID_HANDLE_VALUE)
2160+
CloseHandle(handle);
2161+
return;
2162+
}
2163+
if (std_id == STD_ERROR_HANDLE && !wcscmp(buf, L"2>&1")) {
2164+
handle = GetStdHandle(STD_OUTPUT_HANDLE);
2165+
if (handle == INVALID_HANDLE_VALUE) {
2166+
close(fd);
2167+
handle = GetStdHandle(std_id);
2168+
if (handle != INVALID_HANDLE_VALUE)
2169+
CloseHandle(handle);
2170+
} else {
2171+
int new_fd = _open_osfhandle((intptr_t)handle, O_BINARY);
2172+
SetStdHandle(std_id, handle);
2173+
dup2(new_fd, fd);
2174+
/* do *not* close the new_fd: that would close stdout */
2175+
}
2176+
return;
2177+
}
2178+
handle = CreateFileW(buf, desired_access, 0, NULL, create_flag,
2179+
flags, NULL);
2180+
if (handle != INVALID_HANDLE_VALUE) {
2181+
int new_fd = _open_osfhandle((intptr_t)handle, O_BINARY);
2182+
SetStdHandle(std_id, handle);
2183+
dup2(new_fd, fd);
2184+
close(new_fd);
2185+
}
2186+
}
2187+
2188+
static void maybe_redirect_std_handles(void)
2189+
{
2190+
maybe_redirect_std_handle(L"GIT_REDIRECT_STDIN", STD_INPUT_HANDLE, 0,
2191+
GENERIC_READ, FILE_ATTRIBUTE_NORMAL);
2192+
maybe_redirect_std_handle(L"GIT_REDIRECT_STDOUT", STD_OUTPUT_HANDLE, 1,
2193+
GENERIC_WRITE, FILE_ATTRIBUTE_NORMAL);
2194+
maybe_redirect_std_handle(L"GIT_REDIRECT_STDERR", STD_ERROR_HANDLE, 2,
2195+
GENERIC_WRITE, FILE_FLAG_NO_BUFFERING);
2196+
}
2197+
21422198
void mingw_startup(void)
21432199
{
21442200
int i, maxlen, argc;
21452201
char *buffer;
21462202
wchar_t **wenv, **wargv;
21472203
_startupinfo si;
21482204

2205+
maybe_redirect_std_handles();
2206+
21492207
/* get wide char arguments and environment */
21502208
si.newmode = 0;
21512209
if (__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si) < 0)

t/t0001-init.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,4 +453,16 @@ test_expect_success 're-init from a linked worktree' '
453453
)
454454
'
455455

456+
test_expect_success MINGW 'redirect std handles' '
457+
GIT_REDIRECT_STDOUT=output.txt git rev-parse --git-dir &&
458+
test .git = "$(cat output.txt)" &&
459+
test -z "$(GIT_REDIRECT_STDOUT=off git rev-parse --git-dir)" &&
460+
test_must_fail env \
461+
GIT_REDIRECT_STDOUT=output.txt \
462+
GIT_REDIRECT_STDERR="2>&1" \
463+
git rev-parse --git-dir --verify refs/invalid &&
464+
printf ".git\nfatal: Needed a single revision\n" >expect &&
465+
test_cmp expect output.txt
466+
'
467+
456468
test_done

0 commit comments

Comments
 (0)