Skip to content

Commit 44ae3e4

Browse files
committed
Merge pull request #1934 from benpeart/fscache-thread-safe-enable-gfw
fscache: make fscache_enable() thread safe
2 parents f704632 + 575e914 commit 44ae3e4

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

+830
-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
@@ -727,6 +727,7 @@ X =
727727
PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS))
728728

729729
TEST_BUILTINS_OBJS += test-chmtime.o
730+
TEST_BUILTINS_OBJS += test-cmp.o
730731
TEST_BUILTINS_OBJS += test-config.o
731732
TEST_BUILTINS_OBJS += test-ctype.o
732733
TEST_BUILTINS_OBJS += test-date.o
@@ -741,6 +742,7 @@ TEST_BUILTINS_OBJS += test-genrandom.o
741742
TEST_BUILTINS_OBJS += test-hash.o
742743
TEST_BUILTINS_OBJS += test-hashmap.o
743744
TEST_BUILTINS_OBJS += test-hash-speed.o
745+
TEST_BUILTINS_OBJS += test-iconv.o
744746
TEST_BUILTINS_OBJS += test-index-version.o
745747
TEST_BUILTINS_OBJS += test-json-writer.o
746748
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
/* executables and the current directory don't support long paths */
16571738
if (*argv && !strcmp(cmd, *argv))
@@ -1664,9 +1745,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
16641745
/* concatenate argv, quoting args as we go */
16651746
strbuf_init(&args, 0);
16661747
if (prepend_cmd) {
1667-
char *quoted = (char *)quote_arg(cmd);
1748+
char *quoted = (char *)quote_arg(prepend_cmd);
16681749
strbuf_addstr(&args, quoted);
1669-
if (quoted != cmd)
1750+
if (quoted != prepend_cmd)
16701751
free(quoted);
16711752
}
16721753
for (; *argv; argv++) {
@@ -1710,16 +1791,97 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
17101791
wenvblk = make_environment_block(deltaenv);
17111792

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

17161879
free(wenvblk);
17171880
free(wargs);
17181881

1719-
if (!ret) {
1720-
errno = ENOENT;
1882+
if (!ret)
17211883
return -1;
1722-
}
1884+
17231885
CloseHandle(pi.hThread);
17241886

17251887
/*
@@ -1743,7 +1905,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
17431905
return (pid_t)pi.dwProcessId;
17441906
}
17451907

1746-
static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
1908+
static pid_t mingw_spawnv(const char *cmd, const char **argv,
1909+
const char *prepend_cmd)
17471910
{
17481911
return mingw_spawnve_fd(cmd, argv, NULL, NULL, prepend_cmd, 0, 1, 2);
17491912
}
@@ -1771,14 +1934,14 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
17711934
pid = -1;
17721935
}
17731936
else {
1774-
pid = mingw_spawnve_fd(iprog, argv, deltaenv, dir, 1,
1937+
pid = mingw_spawnve_fd(iprog, argv, deltaenv, dir, interpr,
17751938
fhin, fhout, fherr);
17761939
free(iprog);
17771940
}
17781941
argv[0] = argv0;
17791942
}
17801943
else
1781-
pid = mingw_spawnve_fd(prog, argv, deltaenv, dir, 0,
1944+
pid = mingw_spawnve_fd(prog, argv, deltaenv, dir, NULL,
17821945
fhin, fhout, fherr);
17831946
free(prog);
17841947
}
@@ -1806,7 +1969,7 @@ static int try_shell_exec(const char *cmd, char *const *argv)
18061969
argv2[0] = (char *)cmd; /* full path to the script file */
18071970
memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);
18081971
exec_id = trace2_exec(prog, argv2);
1809-
pid = mingw_spawnv(prog, argv2, 1);
1972+
pid = mingw_spawnv(prog, argv2, interpr);
18101973
if (pid >= 0) {
18111974
int status;
18121975
if (waitpid(pid, &status, 0) < 0)
@@ -1830,7 +1993,7 @@ int mingw_execv(const char *cmd, char *const *argv)
18301993
int exec_id;
18311994

18321995
exec_id = trace2_exec(cmd, (const char **)argv);
1833-
pid = mingw_spawnv(cmd, (const char **)argv, 0);
1996+
pid = mingw_spawnv(cmd, (const char **)argv, NULL);
18341997
if (pid < 0) {
18351998
trace2_exec_result(exec_id, -1);
18361999
return -1;
@@ -3001,6 +3164,9 @@ int wmain(int argc, const wchar_t **wargv)
30013164
InitializeCriticalSection(&pinfo_cs);
30023165
InitializeCriticalSection(&phantom_symlinks_cs);
30033166

3167+
/* initialize critical section for fscache */
3168+
InitializeCriticalSection(&fscache_cs);
3169+
30043170
/* set up default file mode and file modes for stdin/out/err */
30053171
_fmode = _O_BINARY;
30063172
_setmode(_fileno(stdin), _O_BINARY);

0 commit comments

Comments
 (0)