merge(3p/git): Merge git upstream at v2.26.2

This commit is contained in:
Vincent Ambo 2020-05-22 17:46:45 +01:00
commit 5229c9b232
1006 changed files with 149006 additions and 60819 deletions

View file

@ -13,6 +13,19 @@
static const int delay[] = { 0, 1, 10, 20, 40 };
void open_in_gdb(void)
{
static struct child_process cp = CHILD_PROCESS_INIT;
extern char *_pgmptr;
argv_array_pushl(&cp.args, "mintty", "gdb", NULL);
argv_array_pushf(&cp.args, "--pid=%d", getpid());
cp.clean_on_exit = 1;
if (start_command(&cp) < 0)
die_errno("Could not start gdb");
sleep(1);
}
int err_win_to_posix(DWORD winerr)
{
int error = ENOSYS;
@ -114,6 +127,7 @@ int err_win_to_posix(DWORD winerr)
case ERROR_SHARING_BUFFER_EXCEEDED: error = ENFILE; break;
case ERROR_SHARING_VIOLATION: error = EACCES; break;
case ERROR_STACK_OVERFLOW: error = ENOMEM; break;
case ERROR_SUCCESS: BUG("err_win_to_posix() called without an error!");
case ERROR_SWAPERROR: error = ENOENT; break;
case ERROR_TOO_MANY_MODULES: error = EMFILE; break;
case ERROR_TOO_MANY_OPEN_FILES: error = EMFILE; break;
@ -212,6 +226,7 @@ enum hide_dotfiles_type {
HIDE_DOTFILES_DOTGITONLY
};
static int core_restrict_inherited_handles = -1;
static enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
static char *unset_environment_variables;
@ -231,6 +246,15 @@ int mingw_core_config(const char *var, const char *value, void *cb)
return 0;
}
if (!strcmp(var, "core.restrictinheritedhandles")) {
if (value && !strcasecmp(value, "auto"))
core_restrict_inherited_handles = -1;
else
core_restrict_inherited_handles =
git_config_bool(var, value);
return 0;
}
return 0;
}
@ -363,6 +387,8 @@ static inline int needs_hiding(const char *path)
/* ignore trailing slashes */
if (*path)
basename = path;
else
break;
}
if (hide_dotfiles == HIDE_DOTFILES_TRUE)
@ -390,6 +416,12 @@ int mingw_mkdir(const char *path, int mode)
{
int ret;
wchar_t wpath[MAX_PATH];
if (!is_valid_win32_path(path, 0)) {
errno = EINVAL;
return -1;
}
if (xutftowcs_path(wpath, path) < 0)
return -1;
ret = _wmkdir(wpath);
@ -463,7 +495,7 @@ int mingw_open (const char *filename, int oflags, ...)
typedef int (*open_fn_t)(wchar_t const *wfilename, int oflags, ...);
va_list args;
unsigned mode;
int fd;
int fd, create = (oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL);
wchar_t wfilename[MAX_PATH];
open_fn_t open_fn;
@ -471,16 +503,21 @@ int mingw_open (const char *filename, int oflags, ...)
mode = va_arg(args, int);
va_end(args);
if (filename && !strcmp(filename, "/dev/null"))
filename = "nul";
if (!is_valid_win32_path(filename, !create)) {
errno = create ? EINVAL : ENOENT;
return -1;
}
if ((oflags & O_APPEND) && !is_local_named_pipe_path(filename))
open_fn = mingw_open_append;
else
open_fn = _wopen;
if (xutftowcs_path(wfilename, filename) < 0)
if (filename && !strcmp(filename, "/dev/null"))
wcscpy(wfilename, L"nul");
else if (xutftowcs_path(wfilename, filename) < 0)
return -1;
fd = open_fn(wfilename, oflags, mode);
if (fd < 0 && (oflags & O_ACCMODE) != O_RDONLY && errno == EACCES) {
@ -538,10 +575,17 @@ FILE *mingw_fopen (const char *filename, const char *otype)
FILE *file;
wchar_t wfilename[MAX_PATH], wotype[4];
if (filename && !strcmp(filename, "/dev/null"))
filename = "nul";
if (xutftowcs_path(wfilename, filename) < 0 ||
xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
wcscpy(wfilename, L"nul");
else if (!is_valid_win32_path(filename, 1)) {
int create = otype && strchr(otype, 'w');
errno = create ? EINVAL : ENOENT;
return NULL;
} else if (xutftowcs_path(wfilename, filename) < 0)
return NULL;
if (xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
return NULL;
if (hide && !access(filename, F_OK) && set_hidden_flag(wfilename, 0)) {
error("could not unhide %s", filename);
return NULL;
@ -560,10 +604,17 @@ FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
FILE *file;
wchar_t wfilename[MAX_PATH], wotype[4];
if (filename && !strcmp(filename, "/dev/null"))
filename = "nul";
if (xutftowcs_path(wfilename, filename) < 0 ||
xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
wcscpy(wfilename, L"nul");
else if (!is_valid_win32_path(filename, 1)) {
int create = otype && strchr(otype, 'w');
errno = create ? EINVAL : ENOENT;
return NULL;
} else if (xutftowcs_path(wfilename, filename) < 0)
return NULL;
if (xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
return NULL;
if (hide && !access(filename, F_OK) && set_hidden_flag(wfilename, 0)) {
error("could not unhide %s", filename);
return NULL;
@ -984,16 +1035,16 @@ int pipe(int filedes[2])
struct tm *gmtime_r(const time_t *timep, struct tm *result)
{
/* gmtime() in MSVCRT.DLL is thread-safe, but not reentrant */
memcpy(result, gmtime(timep), sizeof(struct tm));
return result;
if (gmtime_s(result, timep) == 0)
return result;
return NULL;
}
struct tm *localtime_r(const time_t *timep, struct tm *result)
{
/* localtime() in MSVCRT.DLL is thread-safe, but not reentrant */
memcpy(result, localtime(timep), sizeof(struct tm));
return result;
if (localtime_s(result, timep) == 0)
return result;
return NULL;
}
char *mingw_getcwd(char *pointer, int len)
@ -1052,7 +1103,7 @@ static const char *quote_arg_msvc(const char *arg)
p++;
len++;
}
if (*p == '"')
if (*p == '"' || !*p)
n += count*2 + 1;
continue;
}
@ -1074,16 +1125,19 @@ static const char *quote_arg_msvc(const char *arg)
count++;
*d++ = *arg++;
}
if (*arg == '"') {
if (*arg == '"' || !*arg) {
while (count-- > 0)
*d++ = '\\';
/* don't escape the surrounding end quote */
if (!*arg)
break;
*d++ = '\\';
}
}
*d++ = *arg++;
}
*d++ = '"';
*d++ = 0;
*d++ = '\0';
return q;
}
@ -1096,13 +1150,14 @@ static const char *quote_arg_msys2(const char *arg)
for (p = arg; *p; p++) {
int ws = isspace(*p);
if (!ws && *p != '\\' && *p != '"' && *p != '{')
if (!ws && *p != '\\' && *p != '"' && *p != '{' && *p != '\'' &&
*p != '?' && *p != '*' && *p != '~')
continue;
if (!buf.len)
strbuf_addch(&buf, '"');
if (p != p2)
strbuf_add(&buf, p2, p - p2);
if (!ws && *p != '{')
if (*p == '\\' || *p == '"')
strbuf_addch(&buf, '\\');
p2 = p;
}
@ -1112,7 +1167,7 @@ static const char *quote_arg_msys2(const char *arg)
else if (!buf.len)
return arg;
else
strbuf_add(&buf, p2, p - p2),
strbuf_add(&buf, p2, p - p2);
strbuf_addch(&buf, '"');
return strbuf_detach(&buf, 0);
@ -1161,14 +1216,21 @@ static char *lookup_prog(const char *dir, int dirlen, const char *cmd,
int isexe, int exe_only)
{
char path[MAX_PATH];
wchar_t wpath[MAX_PATH];
snprintf(path, sizeof(path), "%.*s\\%s.exe", dirlen, dir, cmd);
if (!isexe && access(path, F_OK) == 0)
if (xutftowcs_path(wpath, path) < 0)
return NULL;
if (!isexe && _waccess(wpath, F_OK) == 0)
return xstrdup(path);
path[strlen(path)-4] = '\0';
if ((!exe_only || isexe) && access(path, F_OK) == 0)
if (!(GetFileAttributes(path) & FILE_ATTRIBUTE_DIRECTORY))
wpath[wcslen(wpath)-4] = '\0';
if ((!exe_only || isexe) && _waccess(wpath, F_OK) == 0) {
if (!(GetFileAttributesW(wpath) & FILE_ATTRIBUTE_DIRECTORY)) {
path[strlen(path)-4] = '\0';
return xstrdup(path);
}
}
return NULL;
}
@ -1183,7 +1245,7 @@ static char *path_lookup(const char *cmd, int exe_only)
int len = strlen(cmd);
int isexe = len >= 4 && !strcasecmp(cmd+len-4, ".exe");
if (strchr(cmd, '/') || strchr(cmd, '\\'))
if (strpbrk(cmd, "/\\"))
return xstrdup(cmd);
path = mingw_getenv("PATH");
@ -1229,11 +1291,6 @@ static int wenvcmp(const void *a, const void *b)
return _wcsnicmp(p, q, p_len);
}
/* We need a stable sort to convert the environment between UTF-16 <-> UTF-8 */
#ifndef INTERNAL_QSORT
#include "qsort.c"
#endif
/*
* Build an environment block combining the inherited environment
* merged with the given list of settings.
@ -1265,15 +1322,15 @@ static wchar_t *make_environment_block(char **deltaenv)
}
ALLOC_ARRAY(result, size);
memcpy(result, wenv, size * sizeof(*wenv));
COPY_ARRAY(result, wenv, size);
FreeEnvironmentStringsW(wenv);
return result;
}
/*
* If there is a deltaenv, let's accumulate all keys into `array`,
* sort them using the stable git_qsort() and then copy, skipping
* duplicate keys
* sort them using the stable git_stable_qsort() and then copy,
* skipping duplicate keys
*/
for (p = wenv; p && *p; ) {
ALLOC_GROW(array, nr + 1, alloc);
@ -1296,7 +1353,7 @@ static wchar_t *make_environment_block(char **deltaenv)
p += wlen + 1;
}
git_qsort(array, nr, sizeof(*array), wenvcmp);
git_stable_qsort(array, nr, sizeof(*array), wenvcmp);
ALLOC_ARRAY(result, size + delta_size);
for (p = result, i = 0; i < nr; i++) {
@ -1309,7 +1366,7 @@ static wchar_t *make_environment_block(char **deltaenv)
continue;
size = wcslen(array[i]) + 1;
memcpy(p, array[i], size * sizeof(*p));
COPY_ARRAY(p, array[i], size);
p += size;
}
*p = L'\0';
@ -1367,7 +1424,10 @@ static inline int match_last_path_component(const char *path, size_t *len,
static int is_msys2_sh(const char *cmd)
{
if (cmd && !strcmp(cmd, "sh")) {
if (!cmd)
return 0;
if (!strcmp(cmd, "sh")) {
static int ret = -1;
char *p;
@ -1387,6 +1447,16 @@ static int is_msys2_sh(const char *cmd)
}
return ret;
}
if (ends_with(cmd, "\\sh.exe")) {
static char *sh;
if (!sh)
sh = path_lookup("sh", 0);
return !fspathcmp(cmd, sh);
}
return 0;
}
@ -1394,15 +1464,34 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
const char *dir,
int 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;
BOOL ret;
HANDLE cons;
const char *(*quote_arg)(const char *arg) =
is_msys2_sh(*argv) ? quote_arg_msys2 : quote_arg_msvc;
is_msys2_sh(cmd ? cmd : *argv) ?
quote_arg_msys2 : quote_arg_msvc;
/* Make sure to override previous errors, if any */
errno = 0;
if (restrict_handle_inheritance < 0)
restrict_handle_inheritance = core_restrict_inherited_handles;
/*
* The following code to restrict which handles are inherited seems
* to work properly only on Windows 7 and later, so let's disable it
* on Windows Vista and 2008.
*/
if (restrict_handle_inheritance < 0)
restrict_handle_inheritance = GetVersion() >> 16 >= 7601;
do_unset_environment_variables();
@ -1431,11 +1520,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;
if (*argv && !strcmp(cmd, *argv))
wcmd[0] = L'\0';
@ -1468,16 +1569,98 @@ 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)
errno = err_win_to_posix(GetLastError());
if (ret && buf.len) {
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);
/*
@ -1562,7 +1745,7 @@ static int try_shell_exec(const char *cmd, char *const *argv)
while (argv[argc]) argc++;
ALLOC_ARRAY(argv2, argc + 1);
argv2[0] = (char *)cmd; /* full path to the script file */
memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);
COPY_ARRAY(&argv2[1], &argv[1], argc);
exec_id = trace2_exec(prog, argv2);
pid = mingw_spawnv(prog, argv2, 1);
if (pid >= 0) {
@ -1663,6 +1846,8 @@ char *mingw_getenv(const char *name)
if (!w_key)
die("Out of memory, (tried to allocate %u wchar_t's)", len_key);
xutftowcs(w_key, name, len_key);
/* GetEnvironmentVariableW() only sets the last error upon failure */
SetLastError(ERROR_SUCCESS);
len_value = GetEnvironmentVariableW(w_key, w_value, ARRAY_SIZE(w_value));
if (!len_value && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
free(w_key);
@ -2361,6 +2546,128 @@ static void setup_windows_environment(void)
}
}
int is_valid_win32_path(const char *path, int allow_literal_nul)
{
const char *p = path;
int preceding_space_or_period = 0, i = 0, periods = 0;
if (!protect_ntfs)
return 1;
skip_dos_drive_prefix((char **)&path);
goto segment_start;
for (;;) {
char c = *(path++);
switch (c) {
case '\0':
case '/': case '\\':
/* cannot end in ` ` or `.`, except for `.` and `..` */
if (preceding_space_or_period &&
(i != periods || periods > 2))
return 0;
if (!c)
return 1;
i = periods = preceding_space_or_period = 0;
segment_start:
switch (*path) {
case 'a': case 'A': /* AUX */
if (((c = path[++i]) != 'u' && c != 'U') ||
((c = path[++i]) != 'x' && c != 'X')) {
not_a_reserved_name:
path += i;
continue;
}
break;
case 'c': case 'C': /* COM<N>, CON, CONIN$, CONOUT$ */
if ((c = path[++i]) != 'o' && c != 'O')
goto not_a_reserved_name;
c = path[++i];
if (c == 'm' || c == 'M') { /* COM<N> */
if (!isdigit(path[++i]))
goto not_a_reserved_name;
} else if (c == 'n' || c == 'N') { /* CON */
c = path[i + 1];
if ((c == 'i' || c == 'I') &&
((c = path[i + 2]) == 'n' ||
c == 'N') &&
path[i + 3] == '$')
i += 3; /* CONIN$ */
else if ((c == 'o' || c == 'O') &&
((c = path[i + 2]) == 'u' ||
c == 'U') &&
((c = path[i + 3]) == 't' ||
c == 'T') &&
path[i + 4] == '$')
i += 4; /* CONOUT$ */
} else
goto not_a_reserved_name;
break;
case 'l': case 'L': /* LPT<N> */
if (((c = path[++i]) != 'p' && c != 'P') ||
((c = path[++i]) != 't' && c != 'T') ||
!isdigit(path[++i]))
goto not_a_reserved_name;
break;
case 'n': case 'N': /* NUL */
if (((c = path[++i]) != 'u' && c != 'U') ||
((c = path[++i]) != 'l' && c != 'L') ||
(allow_literal_nul &&
!path[i + 1] && p == path))
goto not_a_reserved_name;
break;
case 'p': case 'P': /* PRN */
if (((c = path[++i]) != 'r' && c != 'R') ||
((c = path[++i]) != 'n' && c != 'N'))
goto not_a_reserved_name;
break;
default:
continue;
}
/*
* So far, this looks like a reserved name. Let's see
* whether it actually is one: trailing spaces, a file
* extension, or an NTFS Alternate Data Stream do not
* matter, the name is still reserved if any of those
* follow immediately after the actual name.
*/
i++;
if (path[i] == ' ') {
preceding_space_or_period = 1;
while (path[++i] == ' ')
; /* skip all spaces */
}
c = path[i];
if (c && c != '.' && c != ':' && c != '/' && c != '\\')
goto not_a_reserved_name;
/* contains reserved name */
return 0;
case '.':
periods++;
/* fallthru */
case ' ':
preceding_space_or_period = 1;
i++;
continue;
case ':': /* DOS drive prefix was already skipped */
case '<': case '>': case '"': case '|': case '?': case '*':
/* illegal character */
return 0;
default:
if (c > '\0' && c < '\x20')
/* illegal character */
return 0;
}
preceding_space_or_period = 0;
i++;
}
}
#if !defined(_MSC_VER)
/*
* Disable MSVCRT command line wildcard expansion (__getmainargs called from