upload-pack: remove packet debugging harness
[gitweb.git] / compat / mingw.c
index 4423961768b7389e07090ba8531e086f21d678cf..b67362558046f354b167fe185369b3d2b98879c1 100644 (file)
@@ -178,7 +178,7 @@ static int ask_yes_no_if_possible(const char *format, ...)
        vsnprintf(question, sizeof(question), format, args);
        va_end(args);
 
-       if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) {
+       if ((retry_hook[0] = mingw_getenv("GIT_ASK_YESNO"))) {
                retry_hook[1] = question;
                return !run_command_v_opt(retry_hook, 0);
        }
@@ -256,6 +256,8 @@ int mingw_rmdir(const char *pathname)
 
        while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) {
                if (!is_file_in_use_error(GetLastError()))
+                       errno = err_win_to_posix(GetLastError());
+               if (errno != EACCES)
                        break;
                if (!is_dir_empty(pathname)) {
                        errno = ENOTEMPTY;
@@ -271,7 +273,7 @@ int mingw_rmdir(const char *pathname)
                Sleep(delay[tries]);
                tries++;
        }
-       while (ret == -1 && is_file_in_use_error(GetLastError()) &&
+       while (ret == -1 && errno == EACCES && is_file_in_use_error(GetLastError()) &&
               ask_yes_no_if_possible("Deletion of directory '%s' failed. "
                        "Should I try again?", pathname))
               ret = rmdir(pathname);
@@ -319,6 +321,31 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
        return write(fd, buf, min(count, 31 * 1024 * 1024));
 }
 
+static BOOL WINAPI ctrl_ignore(DWORD type)
+{
+       return TRUE;
+}
+
+#undef fgetc
+int mingw_fgetc(FILE *stream)
+{
+       int ch;
+       if (!isatty(_fileno(stream)))
+               return fgetc(stream);
+
+       SetConsoleCtrlHandler(ctrl_ignore, TRUE);
+       while (1) {
+               ch = fgetc(stream);
+               if (ch != EOF || GetLastError() != ERROR_OPERATION_ABORTED)
+                       break;
+
+               /* Ctrl+C was pressed, simulate SIGINT and retry */
+               mingw_raise(SIGINT);
+       }
+       SetConsoleCtrlHandler(ctrl_ignore, FALSE);
+       return ch;
+}
+
 #undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
@@ -335,6 +362,28 @@ FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
        return freopen(filename, otype, stream);
 }
 
+#undef fflush
+int mingw_fflush(FILE *stream)
+{
+       int ret = fflush(stream);
+
+       /*
+        * write() is used behind the scenes of stdio output functions.
+        * Since git code does not check for errors after each stdio write
+        * operation, it can happen that write() is called by a later
+        * stdio function even if an earlier write() call failed. In the
+        * case of a pipe whose readable end was closed, only the first
+        * call to write() reports EPIPE on Windows. Subsequent write()
+        * calls report EINVAL. It is impossible to notice whether this
+        * fflush invocation triggered such a case, therefore, we have to
+        * catch all EINVAL errors whole-sale.
+        */
+       if (ret && errno == EINVAL)
+               errno = EPIPE;
+
+       return ret;
+}
+
 /*
  * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
  * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
@@ -599,19 +648,6 @@ char *mingw_getcwd(char *pointer, int len)
        return ret;
 }
 
-#undef getenv
-char *mingw_getenv(const char *name)
-{
-       char *result = getenv(name);
-       if (!result && !strcmp(name, "TMPDIR")) {
-               /* on Windows it is TMP and TEMP */
-               result = getenv("TMP");
-               if (!result)
-                       result = getenv("TEMP");
-       }
-       return result;
-}
-
 /*
  * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
  * (Parsing C++ Command-Line Arguments)
@@ -711,7 +747,7 @@ static const char *parse_interpreter(const char *cmd)
  */
 static char **get_path_split(void)
 {
-       char *p, **path, *envpath = getenv("PATH");
+       char *p, **path, *envpath = mingw_getenv("PATH");
        int i, n = 0;
 
        if (!envpath || !*envpath)
@@ -1016,7 +1052,7 @@ static void mingw_execve(const char *cmd, char *const *argv, char *const *env)
        }
 }
 
-void mingw_execvp(const char *cmd, char *const *argv)
+int mingw_execvp(const char *cmd, char *const *argv)
 {
        char **path = get_path_split();
        char *prog = path_lookup(cmd, path, 0);
@@ -1028,11 +1064,13 @@ void mingw_execvp(const char *cmd, char *const *argv)
                errno = ENOENT;
 
        free_path_split(path);
+       return -1;
 }
 
-void mingw_execv(const char *cmd, char *const *argv)
+int mingw_execv(const char *cmd, char *const *argv)
 {
        mingw_execve(cmd, argv, environ);
+       return -1;
 }
 
 int mingw_kill(pid_t pid, int sig)
@@ -1128,6 +1166,36 @@ char **make_augmented_environ(const char *const *vars)
        return env;
 }
 
+#undef getenv
+
+/*
+ * The system's getenv looks up the name in a case-insensitive manner.
+ * This version tries a case-sensitive lookup and falls back to
+ * case-insensitive if nothing was found.  This is necessary because,
+ * as a prominent example, CMD sets 'Path', but not 'PATH'.
+ * Warning: not thread-safe.
+ */
+static char *getenv_cs(const char *name)
+{
+       size_t len = strlen(name);
+       int i = lookup_env(environ, name, len);
+       if (i >= 0)
+               return environ[i] + len + 1;    /* skip past name and '=' */
+       return getenv(name);
+}
+
+char *mingw_getenv(const char *name)
+{
+       char *result = getenv_cs(name);
+       if (!result && !strcmp(name, "TMPDIR")) {
+               /* on Windows it is TMP and TEMP */
+               result = getenv_cs("TMP");
+               if (!result)
+                       result = getenv_cs("TEMP");
+       }
+       return result;
+}
+
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it is null. It
@@ -1166,7 +1234,7 @@ static int WSAAPI getaddrinfo_stub(const char *node, const char *service,
        }
        ai->ai_addrlen = sizeof(struct sockaddr_in);
        if (hints && (hints->ai_flags & AI_CANONNAME))
-               ai->ai_canonname = h ? strdup(h->h_name) : NULL;
+               ai->ai_canonname = h ? xstrdup(h->h_name) : NULL;
        else
                ai->ai_canonname = NULL;
 
@@ -1304,6 +1372,13 @@ static void ensure_socket_initialization(void)
        initialized = 1;
 }
 
+#undef gethostname
+int mingw_gethostname(char *name, int namelen)
+{
+    ensure_socket_initialization();
+    return gethostname(name, namelen);
+}
+
 #undef gethostbyname
 struct hostent *mingw_gethostbyname(const char *host)
 {
@@ -1381,6 +1456,13 @@ int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen)
        return setsockopt(s, lvl, optname, (const char*)optval, optlen);
 }
 
+#undef shutdown
+int mingw_shutdown(int sockfd, int how)
+{
+       SOCKET s = (SOCKET)_get_osfhandle(sockfd);
+       return shutdown(s, how);
+}
+
 #undef listen
 int mingw_listen(int sockfd, int backlog)
 {
@@ -1491,7 +1573,7 @@ static HANDLE timer_event;
 static HANDLE timer_thread;
 static int timer_interval;
 static int one_shot;
-static sig_handler_t timer_fn = SIG_DFL;
+static sig_handler_t timer_fn = SIG_DFL, sigint_fn = SIG_DFL;
 
 /* The timer works like this:
  * The thread, ticktack(), is a trivial routine that most of the time
@@ -1505,10 +1587,7 @@ static sig_handler_t timer_fn = SIG_DFL;
 static unsigned __stdcall ticktack(void *dummy)
 {
        while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) {
-               if (timer_fn == SIG_DFL)
-                       die("Alarm");
-               if (timer_fn != SIG_IGN)
-                       timer_fn(SIGALRM);
+               mingw_raise(SIGALRM);
                if (one_shot)
                        break;
        }
@@ -1599,12 +1678,49 @@ int sigaction(int sig, struct sigaction *in, struct sigaction *out)
 sig_handler_t mingw_signal(int sig, sig_handler_t handler)
 {
        sig_handler_t old = timer_fn;
-       if (sig != SIGALRM)
+
+       switch (sig) {
+       case SIGALRM:
+               timer_fn = handler;
+               break;
+
+       case SIGINT:
+               sigint_fn = handler;
+               break;
+
+       default:
                return signal(sig, handler);
-       timer_fn = handler;
+       }
+
        return old;
 }
 
+#undef raise
+int mingw_raise(int sig)
+{
+       switch (sig) {
+       case SIGALRM:
+               if (timer_fn == SIG_DFL) {
+                       if (isatty(STDERR_FILENO))
+                               fputs("Alarm clock\n", stderr);
+                       exit(128 + SIGALRM);
+               } else if (timer_fn != SIG_IGN)
+                       timer_fn(SIGALRM);
+               return 0;
+
+       case SIGINT:
+               if (sigint_fn == SIG_DFL)
+                       exit(128 + SIGINT);
+               else if (sigint_fn != SIG_IGN)
+                       sigint_fn(SIGINT);
+               return 0;
+
+       default:
+               return raise(sig);
+       }
+}
+
+
 static const char *make_backslash_path(const char *path)
 {
        static char buf[PATH_MAX + 1];
@@ -1666,22 +1782,7 @@ int link(const char *oldpath, const char *newpath)
        return 0;
 }
 
-char *getpass(const char *prompt)
-{
-       struct strbuf buf = STRBUF_INIT;
-
-       fputs(prompt, stderr);
-       for (;;) {
-               char c = _getch();
-               if (c == '\r' || c == '\n')
-                       break;
-               strbuf_addch(&buf, c);
-       }
-       fputs("\n", stderr);
-       return strbuf_detach(&buf, NULL);
-}
-
-pid_t waitpid(pid_t pid, int *status, unsigned options)
+pid_t waitpid(pid_t pid, int *status, int options)
 {
        HANDLE h = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
            FALSE, pid);