Skip to content

Commit 576ff26

Browse files
committed
Merge branch 'inherit-only-stdhandles'
When spawning child processes, we do want them to inherit the standard handles so that we can talk to them. We do *not* want them to inherit any other handle, as that would hold a lock to the respective files (preventing them from being renamed, modified or deleted), and the child process would not know how to access that handle anyway. Happily, there is an API to make that happen. It is supported in Windows Vista and later, which is exactly what we promise to support in Git for Windows for the time being. This also means that we lift, at long last, the target Windows version from Windows XP to Windows Vista. Signed-off-by: Johannes Schindelin <[email protected]>
2 parents 1a4ee4d + cf2f735 commit 576ff26

File tree

6 files changed

+109
-16
lines changed

6 files changed

+109
-16
lines changed

compat/mingw.c

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,6 @@ int mingw_core_config(const char *var, const char *value, void *cb)
274274
}
275275

276276
static DWORD symlink_file_flags = 0, symlink_directory_flags = 1;
277-
DECLARE_PROC_ADDR(kernel32.dll, BOOLEAN, CreateSymbolicLinkW, LPCWSTR, LPCWSTR, DWORD);
278277

279278
enum phantom_symlink_result {
280279
PHANTOM_SYMLINK_RETRY,
@@ -1595,8 +1594,12 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
15951594
int fhin, int fhout, int fherr)
15961595
{
15971596
static int atexit_handler_initialized;
1598-
STARTUPINFOW si;
1597+
STARTUPINFOEXW si;
15991598
PROCESS_INFORMATION pi;
1599+
LPPROC_THREAD_ATTRIBUTE_LIST attr_list = NULL;
1600+
HANDLE stdhandles[3];
1601+
DWORD stdhandles_count = 0;
1602+
SIZE_T size;
16001603
struct strbuf args;
16011604
wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs, *wenvblk = NULL;
16021605
unsigned flags = CREATE_UNICODE_ENVIRONMENT;
@@ -1644,11 +1647,19 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
16441647
CloseHandle(cons);
16451648
}
16461649
memset(&si, 0, sizeof(si));
1647-
si.cb = sizeof(si);
1648-
si.dwFlags = STARTF_USESTDHANDLES;
1649-
si.hStdInput = winansi_get_osfhandle(fhin);
1650-
si.hStdOutput = winansi_get_osfhandle(fhout);
1651-
si.hStdError = winansi_get_osfhandle(fherr);
1650+
si.StartupInfo.cb = sizeof(si);
1651+
si.StartupInfo.hStdInput = winansi_get_osfhandle(fhin);
1652+
si.StartupInfo.hStdOutput = winansi_get_osfhandle(fhout);
1653+
si.StartupInfo.hStdError = winansi_get_osfhandle(fherr);
1654+
1655+
if (si.StartupInfo.hStdInput != INVALID_HANDLE_VALUE)
1656+
stdhandles[stdhandles_count++] = si.StartupInfo.hStdInput;
1657+
if (si.StartupInfo.hStdOutput != INVALID_HANDLE_VALUE)
1658+
stdhandles[stdhandles_count++] = si.StartupInfo.hStdOutput;
1659+
if (si.StartupInfo.hStdError != INVALID_HANDLE_VALUE)
1660+
stdhandles[stdhandles_count++] = si.StartupInfo.hStdError;
1661+
if (stdhandles_count)
1662+
si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
16521663

16531664
/* executables and the current directory don't support long paths */
16541665
if (*argv && !strcmp(cmd, *argv))
@@ -1707,8 +1718,30 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
17071718
wenvblk = make_environment_block(deltaenv);
17081719

17091720
memset(&pi, 0, sizeof(pi));
1710-
ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL, TRUE,
1711-
flags, wenvblk, dir ? wdir : NULL, &si, &pi);
1721+
if (stdhandles_count &&
1722+
(InitializeProcThreadAttributeList(NULL, 1, 0, &size) ||
1723+
GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
1724+
(attr_list = (LPPROC_THREAD_ATTRIBUTE_LIST)
1725+
(HeapAlloc(GetProcessHeap(), 0, size))) &&
1726+
InitializeProcThreadAttributeList(attr_list, 1, 0, &size) &&
1727+
UpdateProcThreadAttribute(attr_list, 0,
1728+
PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
1729+
stdhandles,
1730+
stdhandles_count * sizeof(HANDLE),
1731+
NULL, NULL)) {
1732+
si.lpAttributeList = attr_list;
1733+
flags |= EXTENDED_STARTUPINFO_PRESENT;
1734+
}
1735+
1736+
ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL,
1737+
stdhandles_count ? TRUE : FALSE,
1738+
flags, wenvblk, dir ? wdir : NULL,
1739+
&si.StartupInfo, &pi);
1740+
1741+
if (si.lpAttributeList)
1742+
DeleteProcThreadAttributeList(si.lpAttributeList);
1743+
if (attr_list)
1744+
HeapFree(GetProcessHeap(), 0, attr_list);
17121745

17131746
free(wenvblk);
17141747
free(wargs);
@@ -2687,7 +2720,7 @@ int symlink(const char *target, const char *link)
26872720
int len;
26882721

26892722
/* fail if symlinks are disabled or API is not supported (WinXP) */
2690-
if (!has_symlinks || !INIT_PROC_ADDR(CreateSymbolicLinkW)) {
2723+
if (!has_symlinks) {
26912724
errno = ENOSYS;
26922725
return -1;
26932726
}

compat/poll/poll.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,21 @@
2121
#ifndef _GL_POLL_H
2222
#define _GL_POLL_H
2323

24+
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600
25+
/* Vista has its own, socket-only poll() */
26+
#undef POLLIN
27+
#undef POLLPRI
28+
#undef POLLOUT
29+
#undef POLLERR
30+
#undef POLLHUP
31+
#undef POLLNVAL
32+
#undef POLLRDNORM
33+
#undef POLLRDBAND
34+
#undef POLLWRNORM
35+
#undef POLLWRBAND
36+
#define pollfd compat_pollfd
37+
#endif
38+
2439
/* fake a poll(2) environment */
2540
#define POLLIN 0x0001 /* any readable data available */
2641
#define POLLPRI 0x0002 /* OOB/Urgent readable data */

config.mak.uname

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -399,8 +399,6 @@ ifeq ($(uname_S),Windows)
399399
NO_GETTEXT = YesPlease
400400
NO_PYTHON = YesPlease
401401
ETAGS_TARGET = ETAGS
402-
NO_INET_PTON = YesPlease
403-
NO_INET_NTOP = YesPlease
404402
NO_POSIX_GOODIES = UnfortunatelyYes
405403
NATIVE_CRLF = YesPlease
406404
DEFAULT_HELP_FORMAT = html
@@ -568,8 +566,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
568566
NO_REGEX = YesPlease
569567
NO_PYTHON = YesPlease
570568
ETAGS_TARGET = ETAGS
571-
NO_INET_PTON = YesPlease
572-
NO_INET_NTOP = YesPlease
573569
NO_POSIX_GOODIES = UnfortunatelyYes
574570
DEFAULT_HELP_FORMAT = html
575571
COMPAT_CFLAGS += -DNOGDI -Icompat -Icompat/win32

git-compat-util.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,8 @@
172172
#define _SGI_SOURCE 1
173173

174174
#if defined(WIN32) && !defined(__CYGWIN__) /* Both MinGW and MSVC */
175-
# if defined (_MSC_VER) && !defined(_WIN32_WINNT)
176-
# define _WIN32_WINNT 0x0502
175+
# if !defined(_WIN32_WINNT)
176+
# define _WIN32_WINNT 0x0600
177177
# endif
178178
#define WIN32_LEAN_AND_MEAN /* stops windows.h including winsock.h */
179179
#include <winsock2.h>

t/helper/test-run-command.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,13 +188,58 @@ static int testsuite(int argc, const char **argv)
188188
return !!ret;
189189
}
190190

191+
static int inherit_handle(const char *argv0)
192+
{
193+
struct child_process cp = CHILD_PROCESS_INIT;
194+
char path[PATH_MAX];
195+
int tmp;
196+
197+
/* First, open an inheritable handle */
198+
sprintf(path, "out-XXXXXX");
199+
tmp = xmkstemp(path);
200+
201+
argv_array_pushl(&cp.args, argv0, "inherited-handle-child", NULL);
202+
cp.in = -1;
203+
cp.no_stdout = cp.no_stderr = 1;
204+
if (start_command(&cp) < 0)
205+
die("Could not start child process");
206+
207+
/* Then close it, and try to delete it. */
208+
close(tmp);
209+
if (unlink(path))
210+
die("Could not delete '%s'", path);
211+
212+
if (close(cp.in) < 0 || finish_command(&cp) < 0)
213+
die("Child did not finish");
214+
215+
return 0;
216+
}
217+
218+
static int inherit_handle_child(void)
219+
{
220+
struct strbuf buf = STRBUF_INIT;
221+
222+
if (strbuf_read(&buf, 0, 0) < 0)
223+
die("Could not read stdin");
224+
printf("Received %s\n", buf.buf);
225+
strbuf_release(&buf);
226+
227+
return 0;
228+
}
229+
191230
int cmd_main(int argc, const char **argv)
192231
{
193232
struct child_process proc = CHILD_PROCESS_INIT;
194233
int jobs;
195234

196235
if (argc > 1 && !strcmp(argv[1], "testsuite"))
197236
exit(testsuite(argc - 1, argv + 1));
237+
238+
if (!strcmp(argv[1], "inherited-handle"))
239+
exit(inherit_handle(argv[0]));
240+
if (!strcmp(argv[1], "inherited-handle-child"))
241+
exit(inherit_handle_child());
242+
198243
if (argc < 3)
199244
return 1;
200245
proc.argv = (const char **)argv + 2;

t/t0061-run-command.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ cat >hello-script <<-EOF
1313
EOF
1414
>empty
1515

16+
test_expect_success MINGW 'subprocess inherits only std handles' '
17+
test-run-command inherited-handle
18+
'
19+
1620
test_expect_success 'start_command reports ENOENT' '
1721
test-run-command start-command-ENOENT ./does-not-exist
1822
'

0 commit comments

Comments
 (0)