Skip to content

Commit

Permalink
Merge pull request git-for-windows#1934 from benpeart/fscache-thread-…
Browse files Browse the repository at this point in the history
…safe-enable-gfw

fscache: make fscache_enable() thread safe
  • Loading branch information
dscho committed Feb 7, 2019
2 parents d94e364 + 1822565 commit 3129e8b
Show file tree
Hide file tree
Showing 57 changed files with 830 additions and 237 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*.perl eol=lf diff=perl
*.pl eof=lf diff=perl
*.pm eol=lf diff=perl
*.png binary
*.py eol=lf diff=python
*.bat eol=crlf
/Documentation/**/*.txt eol=lf
Expand Down
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,7 @@ X =
PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS))

TEST_BUILTINS_OBJS += test-chmtime.o
TEST_BUILTINS_OBJS += test-cmp.o
TEST_BUILTINS_OBJS += test-config.o
TEST_BUILTINS_OBJS += test-ctype.o
TEST_BUILTINS_OBJS += test-date.o
Expand All @@ -737,6 +738,7 @@ TEST_BUILTINS_OBJS += test-genrandom.o
TEST_BUILTINS_OBJS += test-hash.o
TEST_BUILTINS_OBJS += test-hashmap.o
TEST_BUILTINS_OBJS += test-hash-speed.o
TEST_BUILTINS_OBJS += test-iconv.o
TEST_BUILTINS_OBJS += test-index-version.o
TEST_BUILTINS_OBJS += test-json-writer.o
TEST_BUILTINS_OBJS += test-lazy-init-name-hash.o
Expand Down
206 changes: 186 additions & 20 deletions compat/mingw.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include "../config.h"
#include "dir.h"
#include "../attr.h"
#include "../string-list.h"
#include "win32/fscache.h"

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

Expand Down Expand Up @@ -1387,6 +1389,65 @@ static char *lookup_prog(const char *dir, int dirlen, const char *cmd,
return NULL;
}

static char *path_lookup(const char *cmd, int exe_only);

static char *is_busybox_applet(const char *cmd)
{
static struct string_list applets = STRING_LIST_INIT_DUP;
static char *busybox_path;
static int busybox_path_initialized;

/* Avoid infinite loop */
if (!strncasecmp(cmd, "busybox", 7) &&
(!cmd[7] || !strcasecmp(cmd + 7, ".exe")))
return NULL;

if (!busybox_path_initialized) {
busybox_path = path_lookup("busybox.exe", 1);
busybox_path_initialized = 1;
}

/* Assume that sh is compiled in... */
if (!busybox_path || !strcasecmp(cmd, "sh"))
return xstrdup_or_null(busybox_path);

if (!applets.nr) {
struct child_process cp = CHILD_PROCESS_INIT;
struct strbuf buf = STRBUF_INIT;
char *p;

argv_array_pushl(&cp.args, busybox_path, "--help", NULL);

if (capture_command(&cp, &buf, 2048)) {
string_list_append(&applets, "");
return NULL;
}

/* parse output */
p = strstr(buf.buf, "Currently defined functions:\n");
if (!p) {
warning("Could not parse output of busybox --help");
string_list_append(&applets, "");
return NULL;
}
p = strchrnul(p, '\n');
for (;;) {
size_t len;

p += strspn(p, "\n\t ,");
len = strcspn(p, "\n\t ,");
if (!len)
break;
p[len] = '\0';
string_list_insert(&applets, p);
p = p + len + 1;
}
}

return string_list_has_string(&applets, cmd) ?
xstrdup(busybox_path) : NULL;
}

/*
* Determines the absolute path of cmd using the split path in path.
* If cmd contains a slash or backslash, no lookup is performed.
Expand Down Expand Up @@ -1415,6 +1476,9 @@ static char *path_lookup(const char *cmd, int exe_only)
path = sep + 1;
}

if (!prog && !isexe)
prog = is_busybox_applet(cmd);

return prog;
}

Expand Down Expand Up @@ -1606,11 +1670,16 @@ static int is_msys2_sh(const char *cmd)
}

static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv,
const char *dir,
int prepend_cmd, int fhin, int fhout, int fherr)
const char *dir, const char *prepend_cmd,
int fhin, int fhout, int fherr)
{
STARTUPINFOW si;
static int restrict_handle_inheritance = 1;
STARTUPINFOEXW si;
PROCESS_INFORMATION pi;
LPPROC_THREAD_ATTRIBUTE_LIST attr_list = NULL;
HANDLE stdhandles[3];
DWORD stdhandles_count = 0;
SIZE_T size;
struct strbuf args;
wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs, *wenvblk = NULL;
unsigned flags = CREATE_UNICODE_ENVIRONMENT;
Expand Down Expand Up @@ -1647,11 +1716,23 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
CloseHandle(cons);
}
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = winansi_get_osfhandle(fhin);
si.hStdOutput = winansi_get_osfhandle(fhout);
si.hStdError = winansi_get_osfhandle(fherr);
si.StartupInfo.cb = sizeof(si);
si.StartupInfo.hStdInput = winansi_get_osfhandle(fhin);
si.StartupInfo.hStdOutput = winansi_get_osfhandle(fhout);
si.StartupInfo.hStdError = winansi_get_osfhandle(fherr);

/* The list of handles cannot contain duplicates */
if (si.StartupInfo.hStdInput != INVALID_HANDLE_VALUE)
stdhandles[stdhandles_count++] = si.StartupInfo.hStdInput;
if (si.StartupInfo.hStdOutput != INVALID_HANDLE_VALUE &&
si.StartupInfo.hStdOutput != si.StartupInfo.hStdInput)
stdhandles[stdhandles_count++] = si.StartupInfo.hStdOutput;
if (si.StartupInfo.hStdError != INVALID_HANDLE_VALUE &&
si.StartupInfo.hStdError != si.StartupInfo.hStdInput &&
si.StartupInfo.hStdError != si.StartupInfo.hStdOutput)
stdhandles[stdhandles_count++] = si.StartupInfo.hStdError;
if (stdhandles_count)
si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;

/* executables and the current directory don't support long paths */
if (*argv && !strcmp(cmd, *argv))
Expand All @@ -1664,9 +1745,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
/* concatenate argv, quoting args as we go */
strbuf_init(&args, 0);
if (prepend_cmd) {
char *quoted = (char *)quote_arg(cmd);
char *quoted = (char *)quote_arg(prepend_cmd);
strbuf_addstr(&args, quoted);
if (quoted != cmd)
if (quoted != prepend_cmd)
free(quoted);
}
for (; *argv; argv++) {
Expand Down Expand Up @@ -1710,16 +1791,97 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
wenvblk = make_environment_block(deltaenv);

memset(&pi, 0, sizeof(pi));
ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL, TRUE,
flags, wenvblk, dir ? wdir : NULL, &si, &pi);
if (restrict_handle_inheritance && stdhandles_count &&
(InitializeProcThreadAttributeList(NULL, 1, 0, &size) ||
GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
(attr_list = (LPPROC_THREAD_ATTRIBUTE_LIST)
(HeapAlloc(GetProcessHeap(), 0, size))) &&
InitializeProcThreadAttributeList(attr_list, 1, 0, &size) &&
UpdateProcThreadAttribute(attr_list, 0,
PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
stdhandles,
stdhandles_count * sizeof(HANDLE),
NULL, NULL)) {
si.lpAttributeList = attr_list;
flags |= EXTENDED_STARTUPINFO_PRESENT;
}

ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL,
stdhandles_count ? TRUE : FALSE,
flags, wenvblk, dir ? wdir : NULL,
&si.StartupInfo, &pi);

/*
* On Windows 2008 R2, it seems that specifying certain types of handles
* (such as FILE_TYPE_CHAR or FILE_TYPE_PIPE) will always produce an
* error. Rather than playing finicky and fragile games, let's just try
* to detect this situation and simply try again without restricting any
* handle inheritance. This is still better than failing to create
* processes.
*/
if (!ret && restrict_handle_inheritance && stdhandles_count) {
DWORD err = GetLastError();
struct strbuf buf = STRBUF_INIT;

if (err != ERROR_NO_SYSTEM_RESOURCES &&
/*
* On Windows 7 and earlier, handles on pipes and character
* devices are inherited automatically, and cannot be
* specified in the thread handle list. Rather than trying
* to catch each and every corner case (and running the
* chance of *still* forgetting a few), let's just fall
* back to creating the process without trying to limit the
* handle inheritance.
*/
!(err == ERROR_INVALID_PARAMETER &&
GetVersion() >> 16 < 9200) &&
!getenv("SUPPRESS_HANDLE_INHERITANCE_WARNING")) {
DWORD fl = 0;
int i;

setenv("SUPPRESS_HANDLE_INHERITANCE_WARNING", "1", 1);

for (i = 0; i < stdhandles_count; i++) {
HANDLE h = stdhandles[i];
strbuf_addf(&buf, "handle #%d: %p (type %lx, "
"handle info (%d) %lx\n", i, h,
GetFileType(h),
GetHandleInformation(h, &fl),
fl);
}
strbuf_addstr(&buf, "\nThis is a bug; please report it "
"at\nhttps://github.com/git-for-windows/"
"git/issues/new\n\n"
"To suppress this warning, please set "
"the environment variable\n\n"
"\tSUPPRESS_HANDLE_INHERITANCE_WARNING=1"
"\n");
}
restrict_handle_inheritance = 0;
flags &= ~EXTENDED_STARTUPINFO_PRESENT;
ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL,
TRUE, flags, wenvblk, dir ? wdir : NULL,
&si.StartupInfo, &pi);
if (ret && buf.len) {
errno = err_win_to_posix(GetLastError());
warning("failed to restrict file handles (%ld)\n\n%s",
err, buf.buf);
}
strbuf_release(&buf);
} else if (!ret)
errno = err_win_to_posix(GetLastError());

if (si.lpAttributeList)
DeleteProcThreadAttributeList(si.lpAttributeList);
if (attr_list)
HeapFree(GetProcessHeap(), 0, attr_list);

free(wenvblk);
free(wargs);

if (!ret) {
errno = ENOENT;
if (!ret)
return -1;
}

CloseHandle(pi.hThread);

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

static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
static pid_t mingw_spawnv(const char *cmd, const char **argv,
const char *prepend_cmd)
{
return mingw_spawnve_fd(cmd, argv, NULL, NULL, prepend_cmd, 0, 1, 2);
}
Expand Down Expand Up @@ -1771,14 +1934,14 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
pid = -1;
}
else {
pid = mingw_spawnve_fd(iprog, argv, deltaenv, dir, 1,
pid = mingw_spawnve_fd(iprog, argv, deltaenv, dir, interpr,
fhin, fhout, fherr);
free(iprog);
}
argv[0] = argv0;
}
else
pid = mingw_spawnve_fd(prog, argv, deltaenv, dir, 0,
pid = mingw_spawnve_fd(prog, argv, deltaenv, dir, NULL,
fhin, fhout, fherr);
free(prog);
}
Expand All @@ -1804,7 +1967,7 @@ static int try_shell_exec(const char *cmd, char *const *argv)
ALLOC_ARRAY(argv2, argc + 1);
argv2[0] = (char *)cmd; /* full path to the script file */
memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);
pid = mingw_spawnv(prog, argv2, 1);
pid = mingw_spawnv(prog, argv2, interpr);
if (pid >= 0) {
int status;
if (waitpid(pid, &status, 0) < 0)
Expand All @@ -1824,7 +1987,7 @@ int mingw_execv(const char *cmd, char *const *argv)
if (!try_shell_exec(cmd, argv)) {
int pid, status;

pid = mingw_spawnv(cmd, (const char **)argv, 0);
pid = mingw_spawnv(cmd, (const char **)argv, NULL);
if (pid < 0)
return -1;
if (waitpid(pid, &status, 0) < 0)
Expand Down Expand Up @@ -2992,6 +3155,9 @@ int wmain(int argc, const wchar_t **wargv)
InitializeCriticalSection(&pinfo_cs);
InitializeCriticalSection(&phantom_symlinks_cs);

/* initialize critical section for fscache */
InitializeCriticalSection(&fscache_cs);

/* set up default file mode and file modes for stdin/out/err */
_fmode = _O_BINARY;
_setmode(_fileno(stdin), _O_BINARY);
Expand Down
Loading

0 comments on commit 3129e8b

Please sign in to comment.