]> git.ipfire.org Git - thirdparty/git.git/blobdiff - compat/mingw.c
Sync with 2.20.2
[thirdparty/git.git] / compat / mingw.c
index 8141f77189c66b07a1e1cd5ab92418d0de4617e5..0e14cab0126559217b07a049ba11d22621c83877 100644 (file)
@@ -390,6 +390,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 +469,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 +477,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 +548,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 +575,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 +1073,7 @@ static const char *quote_arg_msvc(const char *arg)
                                p++;
                                len++;
                        }
-                       if (*p == '"')
+                       if (*p == '"' || !*p)
                                n += count*2 + 1;
                        continue;
                }
@@ -1074,16 +1095,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;
 }
 
@@ -2464,6 +2488,50 @@ static void setup_windows_environment(void)
                setenv("TERM", "cygwin", 1);
 }
 
+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++;
+       }
+}
+
 /*
  * Disable MSVCRT command line wildcard expansion (__getmainargs called from
  * mingw startup code, see init.c in mingw runtime).