]> git.ipfire.org Git - thirdparty/git.git/blobdiff - compat/mingw.c
Sync with 2.23.1
[thirdparty/git.git] / compat / mingw.c
index 6b765d936cfc8afe198b2735dafd4116c1706b58..bd24d913f93f3cc077eb0d7545dfebf2491a4aac 100644 (file)
@@ -363,6 +363,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 +392,12 @@ int mingw_mkdir(const char *path, int mode)
 {
        int ret;
        wchar_t wpath[MAX_PATH];
+
+       if (!is_valid_win32_path(path)) {
+               errno = EINVAL;
+               return -1;
+       }
+
        if (xutftowcs_path(wpath, path) < 0)
                return -1;
        ret = _wmkdir(wpath);
@@ -463,7 +471,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,6 +479,11 @@ int mingw_open (const char *filename, int oflags, ...)
        mode = va_arg(args, int);
        va_end(args);
 
+       if (!is_valid_win32_path(filename)) {
+               errno = create ? EINVAL : ENOENT;
+               return -1;
+       }
+
        if (filename && !strcmp(filename, "/dev/null"))
                filename = "nul";
 
@@ -537,6 +550,11 @@ FILE *mingw_fopen (const char *filename, const char *otype)
        int hide = needs_hiding(filename);
        FILE *file;
        wchar_t wfilename[MAX_PATH], wotype[4];
+       if (!is_valid_win32_path(filename)) {
+               int create = otype && strchr(otype, 'w');
+               errno = create ? EINVAL : ENOENT;
+               return NULL;
+       }
        if (filename && !strcmp(filename, "/dev/null"))
                filename = "nul";
        if (xutftowcs_path(wfilename, filename) < 0 ||
@@ -559,6 +577,11 @@ FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
        int hide = needs_hiding(filename);
        FILE *file;
        wchar_t wfilename[MAX_PATH], wotype[4];
+       if (!is_valid_win32_path(filename)) {
+               int create = otype && strchr(otype, 'w');
+               errno = create ? EINVAL : ENOENT;
+               return NULL;
+       }
        if (filename && !strcmp(filename, "/dev/null"))
                filename = "nul";
        if (xutftowcs_path(wfilename, filename) < 0 ||
@@ -1052,7 +1075,7 @@ static const char *quote_arg_msvc(const char *arg)
                                p++;
                                len++;
                        }
-                       if (*p == '"')
+                       if (*p == '"' || !*p)
                                n += count*2 + 1;
                        continue;
                }
@@ -1074,16 +1097,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 +1122,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 +1139,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);
@@ -1369,7 +1396,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;
 
@@ -1389,6 +1419,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;
 }
 
@@ -1404,7 +1444,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
        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;
 
        do_unset_environment_variables();
 
@@ -2365,6 +2406,50 @@ static void setup_windows_environment(void)
        }
 }
 
+int is_valid_win32_path(const char *path)
+{
+       int preceding_space_or_period = 0, i = 0, periods = 0;
+
+       if (!protect_ntfs)
+               return 1;
+
+       skip_dos_drive_prefix((char **)&path);
+
+       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;
+                       continue;
+               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