From a748f3f3dc0adff1d8a83dfc098ed819658998d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20A=C3=9Fhauer?= Date: Wed, 8 Apr 2020 17:58:49 +0000 Subject: [PATCH 1/3] mingw: use modern strftime implementation if possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Microsoft introduced a new "Universal C Runtime Library" (UCRT) with Visual Studio 2015. The UCRT comes with a new strftime() implementation that supports more date formats. We link git against the older "Microsoft Visual C Runtime Library" (MSVCRT), so to use the UCRT strftime() we need to load it from ucrtbase.dll using DECLARE_PROC_ADDR()/INIT_PROC_ADDR(). Most supported Windows systems should have recieved the UCRT via Windows update, but in some cases only MSVCRT might be available. In that case we fall back to using that implementation. With this change, it is possible to use e.g. the `%g` and `%V` date format specifiers, e.g. git show -s --format=%cd --date=format:‘%g.%V’ HEAD Without this change, the user would see this error message on Windows: fatal: invalid strftime format: '‘%g.%V’' This fixes https://github.com/git-for-windows/git/issues/2495 Signed-off-by: Matthias Aßhauer Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- compat/mingw.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index d14065d60e..2136744af3 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -964,7 +964,16 @@ int mingw_utime (const char *file_name, const struct utimbuf *times) size_t mingw_strftime(char *s, size_t max, const char *format, const struct tm *tm) { - size_t ret = strftime(s, max, format, tm); + /* a pointer to the original strftime in case we can't find the UCRT version */ + static size_t (*fallback)(char *, size_t, const char *, const struct tm *) = strftime; + size_t ret; + DECLARE_PROC_ADDR(ucrtbase.dll, size_t, strftime, char *, size_t, + const char *, const struct tm *); + + if (INIT_PROC_ADDR(strftime)) + ret = strftime(s, max, format, tm); + else + ret = fallback(s, max, format, tm); if (!ret && errno == EINVAL) die("invalid strftime format: '%s'", format); From b6852e19794245566f7c961a434c56ca3b7a883b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 8 Apr 2020 18:06:49 +0000 Subject: [PATCH 2/3] mingw: do not treat `COM0` as a reserved file name In 4dc42c6c186 (mingw: refuse paths containing reserved names, 2019-12-21), we started disallowing file names that are reserved, e.g. `NUL`, `CONOUT$`, etc. This included `COM` where `` is a digit. Unfortunately, this includes `COM0` but only `COM1`, ..., `COM9` are reserved, according to the official documentation, `COM0` is mentioned in the "NT Namespaces" section but it is explicitly _omitted_ from the list of reserved names: https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions Tests corroborate this: it is totally possible to write a file called `com0.c` on Windows 10, but not `com1.c`. So let's tighten the code to disallow only the reserved `COM` file names, but to allow `COM0` again. This fixes https://github.com/git-for-windows/git/issues/2470. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- compat/mingw.c | 8 +++++--- t/t0060-path-utils.sh | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 2136744af3..f2c94f9d08 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2590,12 +2590,14 @@ int is_valid_win32_path(const char *path, int allow_literal_nul) continue; } break; - case 'c': case 'C': /* COM, CON, CONIN$, CONOUT$ */ + case 'c': case 'C': + /* COM1 ... COM9, CON, CONIN$, CONOUT$ */ if ((c = path[++i]) != 'o' && c != 'O') goto not_a_reserved_name; c = path[++i]; - if (c == 'm' || c == 'M') { /* COM */ - if (!isdigit(path[++i])) + if (c == 'm' || c == 'M') { /* COM1 ... COM9 */ + c = path[++i]; + if (c < '1' || c > '9') goto not_a_reserved_name; } else if (c == 'n' || c == 'N') { /* CON */ c = path[i + 1]; diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh index 2ea2d00c39..56db5c8aba 100755 --- a/t/t0060-path-utils.sh +++ b/t/t0060-path-utils.sh @@ -476,6 +476,7 @@ test_expect_success MINGW 'is_valid_path() on Windows' ' C:\\git \ comm \ conout.c \ + com0.c \ lptN \ \ --not \ @@ -488,6 +489,7 @@ test_expect_success MINGW 'is_valid_path() on Windows' ' "AUX.c" \ "abc/conOut\$ .xyz/test" \ lpt8 \ + com9.c \ "lpt*" \ Nul \ "PRN./abc" From 3efc128cd59fefb6aa159548d0cf7666ce5e34a9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 9 Apr 2020 10:21:47 +0000 Subject: [PATCH 3/3] mingw: help debugging by optionally executing bash with strace MSYS2's strace facility is very useful for debugging... With this patch, the bash will be executed through strace if the environment variable GIT_STRACE_COMMANDS is set, which comes in real handy when investigating issues in the test suite. Also support passing a path to a log file via GIT_STRACE_COMMANDS to force Git to call strace.exe with the `-o ` argument, i.e. to log into a file rather than print the log directly. That comes in handy when the output would otherwise misinterpreted by a calling process as part of Git's output. Note: the values "1", "yes" or "true" are *not* specifying paths, but tell Git to let strace.exe log directly to the console. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- compat/mingw.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index f2c94f9d08..178a70df61 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1488,6 +1488,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen const char *(*quote_arg)(const char *arg) = is_msys2_sh(cmd ? cmd : *argv) ? quote_arg_msys2 : quote_arg_msvc; + const char *strace_env; /* Make sure to override previous errors, if any */ errno = 0; @@ -1571,6 +1572,31 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen free(quoted); } + strace_env = getenv("GIT_STRACE_COMMANDS"); + if (strace_env) { + char *p = path_lookup("strace.exe", 1); + if (!p) + return error("strace not found!"); + if (xutftowcs_path(wcmd, p) < 0) { + free(p); + return -1; + } + free(p); + if (!strcmp("1", strace_env) || + !strcasecmp("yes", strace_env) || + !strcasecmp("true", strace_env)) + strbuf_insert(&args, 0, "strace ", 7); + else { + const char *quoted = quote_arg(strace_env); + struct strbuf buf = STRBUF_INIT; + strbuf_addf(&buf, "strace -o %s ", quoted); + if (quoted != strace_env) + free((char *)quoted); + strbuf_insert(&args, 0, buf.buf, buf.len); + strbuf_release(&buf); + } + } + ALLOC_ARRAY(wargs, st_add(st_mult(2, args.len), 1)); xutftowcs(wargs, args.buf, 2 * args.len + 1); strbuf_release(&args);