merge(3p/git): Merge git upstream at v2.26.2
This commit is contained in:
commit
5229c9b232
1006 changed files with 149006 additions and 60819 deletions
409
third_party/git/compat/mingw.c
vendored
409
third_party/git/compat/mingw.c
vendored
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue