Skip to content

Commit 2d3f710

Browse files
committed
Merge pull request #1934 from benpeart/fscache-thread-safe-enable-gfw
fscache: make fscache_enable() thread safe
2 parents 8948d8f + 23ef8fd commit 2d3f710

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+826
-237
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*.perl eol=lf diff=perl
55
*.pl eof=lf diff=perl
66
*.pm eol=lf diff=perl
7+
*.png binary
78
*.py eol=lf diff=python
89
*.bat eol=crlf
910
/Documentation/**/*.txt eol=lf

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,7 @@ X =
706706
PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS))
707707

708708
TEST_BUILTINS_OBJS += test-chmtime.o
709+
TEST_BUILTINS_OBJS += test-cmp.o
709710
TEST_BUILTINS_OBJS += test-config.o
710711
TEST_BUILTINS_OBJS += test-ctype.o
711712
TEST_BUILTINS_OBJS += test-date.o
@@ -721,6 +722,7 @@ TEST_BUILTINS_OBJS += test-genzeros.o
721722
TEST_BUILTINS_OBJS += test-hash.o
722723
TEST_BUILTINS_OBJS += test-hashmap.o
723724
TEST_BUILTINS_OBJS += test-hash-speed.o
725+
TEST_BUILTINS_OBJS += test-iconv.o
724726
TEST_BUILTINS_OBJS += test-index-version.o
725727
TEST_BUILTINS_OBJS += test-json-writer.o
726728
TEST_BUILTINS_OBJS += test-lazy-init-name-hash.o

compat/mingw.c

Lines changed: 186 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include "../config.h"
1111
#include "dir.h"
1212
#include "../attr.h"
13+
#include "../string-list.h"
14+
#include "win32/fscache.h"
1315

1416
#define HCAST(type, handle) ((type)(intptr_t)handle)
1517

@@ -1387,6 +1389,65 @@ static char *lookup_prog(const char *dir, int dirlen, const char *cmd,
13871389
return NULL;
13881390
}
13891391

1392+
static char *path_lookup(const char *cmd, int exe_only);
1393+
1394+
static char *is_busybox_applet(const char *cmd)
1395+
{
1396+
static struct string_list applets = STRING_LIST_INIT_DUP;
1397+
static char *busybox_path;
1398+
static int busybox_path_initialized;
1399+
1400+
/* Avoid infinite loop */
1401+
if (!strncasecmp(cmd, "busybox", 7) &&
1402+
(!cmd[7] || !strcasecmp(cmd + 7, ".exe")))
1403+
return NULL;
1404+
1405+
if (!busybox_path_initialized) {
1406+
busybox_path = path_lookup("busybox.exe", 1);
1407+
busybox_path_initialized = 1;
1408+
}
1409+
1410+
/* Assume that sh is compiled in... */
1411+
if (!busybox_path || !strcasecmp(cmd, "sh"))
1412+
return xstrdup_or_null(busybox_path);
1413+
1414+
if (!applets.nr) {
1415+
struct child_process cp = CHILD_PROCESS_INIT;
1416+
struct strbuf buf = STRBUF_INIT;
1417+
char *p;
1418+
1419+
argv_array_pushl(&cp.args, busybox_path, "--help", NULL);
1420+
1421+
if (capture_command(&cp, &buf, 2048)) {
1422+
string_list_append(&applets, "");
1423+
return NULL;
1424+
}
1425+
1426+
/* parse output */
1427+
p = strstr(buf.buf, "Currently defined functions:\n");
1428+
if (!p) {
1429+
warning("Could not parse output of busybox --help");
1430+
string_list_append(&applets, "");
1431+
return NULL;
1432+
}
1433+
p = strchrnul(p, '\n');
1434+
for (;;) {
1435+
size_t len;
1436+
1437+
p += strspn(p, "\n\t ,");
1438+
len = strcspn(p, "\n\t ,");
1439+
if (!len)
1440+
break;
1441+
p[len] = '\0';
1442+
string_list_insert(&applets, p);
1443+
p = p + len + 1;
1444+
}
1445+
}
1446+
1447+
return string_list_has_string(&applets, cmd) ?
1448+
xstrdup(busybox_path) : NULL;
1449+
}
1450+
13901451
/*
13911452
* Determines the absolute path of cmd using the split path in path.
13921453
* If cmd contains a slash or backslash, no lookup is performed.
@@ -1415,6 +1476,9 @@ static char *path_lookup(const char *cmd, int exe_only)
14151476
path = sep + 1;
14161477
}
14171478

1479+
if (!prog && !isexe)
1480+
prog = is_busybox_applet(cmd);
1481+
14181482
return prog;
14191483
}
14201484

@@ -1606,11 +1670,16 @@ static int is_msys2_sh(const char *cmd)
16061670
}
16071671

16081672
static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv,
1609-
const char *dir,
1610-
int prepend_cmd, int fhin, int fhout, int fherr)
1673+
const char *dir, const char *prepend_cmd,
1674+
int fhin, int fhout, int fherr)
16111675
{
1612-
STARTUPINFOW si;
1676+
static int restrict_handle_inheritance = 1;
1677+
STARTUPINFOEXW si;
16131678
PROCESS_INFORMATION pi;
1679+
LPPROC_THREAD_ATTRIBUTE_LIST attr_list = NULL;
1680+
HANDLE stdhandles[3];
1681+
DWORD stdhandles_count = 0;
1682+
SIZE_T size;
16141683
struct strbuf args;
16151684
wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs, *wenvblk = NULL;
16161685
unsigned flags = CREATE_UNICODE_ENVIRONMENT;
@@ -1647,11 +1716,23 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
16471716
CloseHandle(cons);
16481717
}
16491718
memset(&si, 0, sizeof(si));
1650-
si.cb = sizeof(si);
1651-
si.dwFlags = STARTF_USESTDHANDLES;
1652-
si.hStdInput = winansi_get_osfhandle(fhin);
1653-
si.hStdOutput = winansi_get_osfhandle(fhout);
1654-
si.hStdError = winansi_get_osfhandle(fherr);
1719+
si.StartupInfo.cb = sizeof(si);
1720+
si.StartupInfo.hStdInput = winansi_get_osfhandle(fhin);
1721+
si.StartupInfo.hStdOutput = winansi_get_osfhandle(fhout);
1722+
si.StartupInfo.hStdError = winansi_get_osfhandle(fherr);
1723+
1724+
/* The list of handles cannot contain duplicates */
1725+
if (si.StartupInfo.hStdInput != INVALID_HANDLE_VALUE)
1726+
stdhandles[stdhandles_count++] = si.StartupInfo.hStdInput;
1727+
if (si.StartupInfo.hStdOutput != INVALID_HANDLE_VALUE &&
1728+
si.StartupInfo.hStdOutput != si.StartupInfo.hStdInput)
1729+
stdhandles[stdhandles_count++] = si.StartupInfo.hStdOutput;
1730+
if (si.StartupInfo.hStdError != INVALID_HANDLE_VALUE &&
1731+
si.StartupInfo.hStdError != si.StartupInfo.hStdInput &&
1732+
si.StartupInfo.hStdError != si.StartupInfo.hStdOutput)
1733+
stdhandles[stdhandles_count++] = si.StartupInfo.hStdError;
1734+
if (stdhandles_count)
1735+
si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
16551736

16561737
if (*argv && !strcmp(cmd, *argv))
16571738
wcmd[0] = L'\0';
@@ -1667,9 +1748,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
16671748
/* concatenate argv, quoting args as we go */
16681749
strbuf_init(&args, 0);
16691750
if (prepend_cmd) {
1670-
char *quoted = (char *)quote_arg(cmd);
1751+
char *quoted = (char *)quote_arg(prepend_cmd);
16711752
strbuf_addstr(&args, quoted);
1672-
if (quoted != cmd)
1753+
if (quoted != prepend_cmd)
16731754
free(quoted);
16741755
}
16751756
for (; *argv; argv++) {
@@ -1713,16 +1794,97 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
17131794
wenvblk = make_environment_block(deltaenv);
17141795

17151796
memset(&pi, 0, sizeof(pi));
1716-
ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL, TRUE,
1717-
flags, wenvblk, dir ? wdir : NULL, &si, &pi);
1797+
if (restrict_handle_inheritance && stdhandles_count &&
1798+
(InitializeProcThreadAttributeList(NULL, 1, 0, &size) ||
1799+
GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
1800+
(attr_list = (LPPROC_THREAD_ATTRIBUTE_LIST)
1801+
(HeapAlloc(GetProcessHeap(), 0, size))) &&
1802+
InitializeProcThreadAttributeList(attr_list, 1, 0, &size) &&
1803+
UpdateProcThreadAttribute(attr_list, 0,
1804+
PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
1805+
stdhandles,
1806+
stdhandles_count * sizeof(HANDLE),
1807+
NULL, NULL)) {
1808+
si.lpAttributeList = attr_list;
1809+
flags |= EXTENDED_STARTUPINFO_PRESENT;
1810+
}
1811+
1812+
ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL,
1813+
stdhandles_count ? TRUE : FALSE,
1814+
flags, wenvblk, dir ? wdir : NULL,
1815+
&si.StartupInfo, &pi);
1816+
1817+
/*
1818+
* On Windows 2008 R2, it seems that specifying certain types of handles
1819+
* (such as FILE_TYPE_CHAR or FILE_TYPE_PIPE) will always produce an
1820+
* error. Rather than playing finicky and fragile games, let's just try
1821+
* to detect this situation and simply try again without restricting any
1822+
* handle inheritance. This is still better than failing to create
1823+
* processes.
1824+
*/
1825+
if (!ret && restrict_handle_inheritance && stdhandles_count) {
1826+
DWORD err = GetLastError();
1827+
struct strbuf buf = STRBUF_INIT;
1828+
1829+
if (err != ERROR_NO_SYSTEM_RESOURCES &&
1830+
/*
1831+
* On Windows 7 and earlier, handles on pipes and character
1832+
* devices are inherited automatically, and cannot be
1833+
* specified in the thread handle list. Rather than trying
1834+
* to catch each and every corner case (and running the
1835+
* chance of *still* forgetting a few), let's just fall
1836+
* back to creating the process without trying to limit the
1837+
* handle inheritance.
1838+
*/
1839+
!(err == ERROR_INVALID_PARAMETER &&
1840+
GetVersion() >> 16 < 9200) &&
1841+
!getenv("SUPPRESS_HANDLE_INHERITANCE_WARNING")) {
1842+
DWORD fl = 0;
1843+
int i;
1844+
1845+
setenv("SUPPRESS_HANDLE_INHERITANCE_WARNING", "1", 1);
1846+
1847+
for (i = 0; i < stdhandles_count; i++) {
1848+
HANDLE h = stdhandles[i];
1849+
strbuf_addf(&buf, "handle #%d: %p (type %lx, "
1850+
"handle info (%d) %lx\n", i, h,
1851+
GetFileType(h),
1852+
GetHandleInformation(h, &fl),
1853+
fl);
1854+
}
1855+
strbuf_addstr(&buf, "\nThis is a bug; please report it "
1856+
"at\nhttps://github.com/git-for-windows/"
1857+
"git/issues/new\n\n"
1858+
"To suppress this warning, please set "
1859+
"the environment variable\n\n"
1860+
"\tSUPPRESS_HANDLE_INHERITANCE_WARNING=1"
1861+
"\n");
1862+
}
1863+
restrict_handle_inheritance = 0;
1864+
flags &= ~EXTENDED_STARTUPINFO_PRESENT;
1865+
ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL,
1866+
TRUE, flags, wenvblk, dir ? wdir : NULL,
1867+
&si.StartupInfo, &pi);
1868+
if (ret && buf.len) {
1869+
errno = err_win_to_posix(GetLastError());
1870+
warning("failed to restrict file handles (%ld)\n\n%s",
1871+
err, buf.buf);
1872+
}
1873+
strbuf_release(&buf);
1874+
} else if (!ret)
1875+
errno = err_win_to_posix(GetLastError());
1876+
1877+
if (si.lpAttributeList)
1878+
DeleteProcThreadAttributeList(si.lpAttributeList);
1879+
if (attr_list)
1880+
HeapFree(GetProcessHeap(), 0, attr_list);
17181881

17191882
free(wenvblk);
17201883
free(wargs);
17211884

1722-
if (!ret) {
1723-
errno = ENOENT;
1885+
if (!ret)
17241886
return -1;
1725-
}
1887+
17261888
CloseHandle(pi.hThread);
17271889

17281890
/*
@@ -1746,7 +1908,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
17461908
return (pid_t)pi.dwProcessId;
17471909
}
17481910

1749-
static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
1911+
static pid_t mingw_spawnv(const char *cmd, const char **argv,
1912+
const char *prepend_cmd)
17501913
{
17511914
return mingw_spawnve_fd(cmd, argv, NULL, NULL, prepend_cmd, 0, 1, 2);
17521915
}
@@ -1774,14 +1937,14 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
17741937
pid = -1;
17751938
}
17761939
else {
1777-
pid = mingw_spawnve_fd(iprog, argv, deltaenv, dir, 1,
1940+
pid = mingw_spawnve_fd(iprog, argv, deltaenv, dir, interpr,
17781941
fhin, fhout, fherr);
17791942
free(iprog);
17801943
}
17811944
argv[0] = argv0;
17821945
}
17831946
else
1784-
pid = mingw_spawnve_fd(prog, argv, deltaenv, dir, 0,
1947+
pid = mingw_spawnve_fd(prog, argv, deltaenv, dir, NULL,
17851948
fhin, fhout, fherr);
17861949
free(prog);
17871950
}
@@ -1809,7 +1972,7 @@ static int try_shell_exec(const char *cmd, char *const *argv)
18091972
argv2[0] = (char *)cmd; /* full path to the script file */
18101973
memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);
18111974
exec_id = trace2_exec(prog, argv2);
1812-
pid = mingw_spawnv(prog, argv2, 1);
1975+
pid = mingw_spawnv(prog, argv2, interpr);
18131976
if (pid >= 0) {
18141977
int status;
18151978
if (waitpid(pid, &status, 0) < 0)
@@ -1833,7 +1996,7 @@ int mingw_execv(const char *cmd, char *const *argv)
18331996
int exec_id;
18341997

18351998
exec_id = trace2_exec(cmd, (const char **)argv);
1836-
pid = mingw_spawnv(cmd, (const char **)argv, 0);
1999+
pid = mingw_spawnv(cmd, (const char **)argv, NULL);
18372000
if (pid < 0) {
18382001
trace2_exec_result(exec_id, -1);
18392002
return -1;
@@ -3013,6 +3176,9 @@ int wmain(int argc, const wchar_t **wargv)
30133176
InitializeCriticalSection(&pinfo_cs);
30143177
InitializeCriticalSection(&phantom_symlinks_cs);
30153178

3179+
/* initialize critical section for fscache */
3180+
InitializeCriticalSection(&fscache_cs);
3181+
30163182
/* set up default file mode and file modes for stdin/out/err */
30173183
_fmode = _O_BINARY;
30183184
_setmode(_fileno(stdin), _O_BINARY);

0 commit comments

Comments
 (0)