From 3deda759198c2a69f280135c0af67e51518cce51 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 17 Nov 2007 22:41:11 +0100 Subject: [PATCH 01/16] upload-pack: Do not announce sideband support when it is not supported On Windows we currently don't support sideband communicaton. The protocol implementation is already disabled, but it was still announced in the server capabilities. --- upload-pack.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/upload-pack.c b/upload-pack.c index 34299308f8..84569a3aad 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -596,8 +596,11 @@ static void receive_needs(void) static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { - static const char *capabilities = "multi_ack thin-pack side-band" - " side-band-64k ofs-delta shallow no-progress"; + static const char *capabilities = "multi_ack thin-pack" +#ifndef __MINGW32__ + " side-band side-band-64k" +#endif + " ofs-delta shallow no-progress"; struct object *o = parse_object(sha1); if (!o) From 1f759eeede0597580be8ce26305550350e3c017a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 17 Nov 2007 23:09:28 +0100 Subject: [PATCH 02/16] fetch-pack: Prepare for a side-band demultiplexer in a thread. get_pack() receives a pair of file descriptors that communicate with upload-pack at the remote end. In order to support the case where the side-band demultiplexer runs in a thread, and, hence, in the same process as the main routine, we must not close the readable file descriptor early. The handling of the readable fd is changed in the case where upload-pack supports side-band communication: The old code closed the fd after it was inherited to the side-band demultiplexer process. Now we do not close it. The caller (do_fetch_pack) will close it later anyway. The demultiplexer is the only reader, it does not matter that the fd remains open in the main process as well as in unpack-objects/index-pack, which inherits it. The writable fd is not needed in get_pack(), hence, the old code closed the fd. For symmetry with the readable fd, we now do not close it; the caller (do_fetch_pack) will close it later anyway. Therefore, the new behavior is that the channel now remains open during the entire conversation, but this has no ill effects because upload-pack does not read from it once it has begun to send the pack data. For the same reason it does not matter that the writable fd is now inherited to the demultiplexer and unpack-objects/index-pack processes. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- builtin-fetch-pack.c | 42 ++++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index bb1742f1a2..807fa93b53 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -462,34 +462,12 @@ static int sideband_demux(int fd, void *data) { int *xd = data; - close(xd[1]); return recv_sideband("fetch-pack", xd[0], fd, 2); } -static void setup_sideband(int fd[2], int xd[2], struct async *demux) -{ - if (!use_sideband) { - fd[0] = xd[0]; - fd[1] = xd[1]; - return; - } - /* xd[] is talking with upload-pack; subprocess reads from - * xd[0], spits out band#2 to stderr, and feeds us band#1 - * through demux->out. - */ - demux->proc = sideband_demux; - demux->data = xd; - if (start_async(demux)) - die("fetch-pack: unable to fork off sideband demultiplexer"); - close(xd[0]); - fd[0] = demux->out; - fd[1] = xd[1]; -} - static int get_pack(int xd[2], char **pack_lockfile) { struct async demux; - int fd[2]; const char *argv[20]; char keep_arg[256]; char hdr_arg[256]; @@ -497,7 +475,20 @@ static int get_pack(int xd[2], char **pack_lockfile) int do_keep = args.keep_pack; struct child_process cmd; - setup_sideband(fd, xd, &demux); + memset(&demux, 0, sizeof(demux)); + if (use_sideband) { + /* xd[] is talking with upload-pack; subprocess reads from + * xd[0], spits out band#2 to stderr, and feeds us band#1 + * through demux->out. + */ + demux.proc = sideband_demux; + demux.data = xd; + if (start_async(&demux)) + die("fetch-pack: unable to fork off sideband" + " demultiplexer"); + } + else + demux.out = xd[0]; memset(&cmd, 0, sizeof(cmd)); cmd.argv = argv; @@ -506,7 +497,7 @@ static int get_pack(int xd[2], char **pack_lockfile) if (!args.keep_pack && unpack_limit) { struct pack_header header; - if (read_pack_header(fd[0], &header)) + if (read_pack_header(demux.out, &header)) die("protocol error: bad pack header"); snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%u,%u", ntohl(header.hdr_version), ntohl(header.hdr_entries)); @@ -542,11 +533,10 @@ static int get_pack(int xd[2], char **pack_lockfile) *av++ = hdr_arg; *av++ = NULL; - cmd.in = fd[0]; + cmd.in = demux.out; cmd.git_cmd = 1; if (start_command(&cmd)) die("fetch-pack: unable to fork off %s", argv[0]); - close(fd[1]); if (do_keep && pack_lockfile) *pack_lockfile = index_pack_lockfile(cmd.out); From f8fd915d0c397c59ccf2f0cb96552e19b440dde8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 18 Nov 2007 20:22:04 +0100 Subject: [PATCH 03/16] Move environment functions from spawn-pipe.c to compat/mingw.c We want to get rid of spawn-pipe.*, but these functions will be needed. On the way, the function signature was changed to avoid warnings about incompatible pointer types when the argument is the global variable "environ". --- compat/mingw.c | 39 +++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 4 ++++ spawn-pipe.c | 39 --------------------------------------- spawn-pipe.h | 3 --- 4 files changed, 43 insertions(+), 42 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 384b3b67a1..0456319ba6 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -536,6 +536,45 @@ void mingw_execvp(const char *cmd, const char **argv) mingw_free_path_split(path); } +char **copy_environ() +{ + return copy_env(environ); +} + +char **copy_env(char **env) +{ + char **s; + int n = 1; + for (s = env; *s; s++) + n++; + s = xmalloc(n*sizeof(char *)); + memcpy(s, env, n*sizeof(char *)); + return s; +} + +void env_unsetenv(char **env, const char *name) +{ + int src, dst; + size_t nmln; + + nmln = strlen(name); + + for (src = dst = 0; env[src]; ++src) { + size_t enln; + enln = strlen(env[src]); + if (enln > nmln) { + /* might match, and can test for '=' safely */ + if (0 == strncmp (env[src], name, nmln) + && '=' == env[src][nmln]) + /* matches, so skip */ + continue; + } + env[dst] = env[src]; + ++dst; + } + env[dst] = NULL; +} + int mingw_socket(int domain, int type, int protocol) { SOCKET s = WSASocket(domain, type, protocol, NULL, 0, 0); diff --git a/git-compat-util.h b/git-compat-util.h index a259da5eeb..768e7fc696 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -473,6 +473,10 @@ static inline int waitpid(pid_t pid, unsigned *status, unsigned options) #define SIGCHLD 0 #define SIGPIPE 0 +char **copy_environ(); +char **copy_env(char **env); +void env_unsetenv(char **env, const char *name); + unsigned int sleep (unsigned int __seconds); const char *inet_ntop(int af, const void *src, char *dst, size_t cnt); diff --git a/spawn-pipe.c b/spawn-pipe.c index 71232066c5..9cb0cf5b70 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -129,42 +129,3 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, return pid; } - -const char **copy_environ() -{ - return copy_env(environ); -} - -const char **copy_env(const char **env) -{ - const char **s; - int n = 1; - for (s = env; *s; s++) - n++; - s = xmalloc(n*sizeof(const char *)); - memcpy(s, env, n*sizeof(const char *)); - return s; -} - -void env_unsetenv(const char **env, const char *name) -{ - int src, dst; - size_t nmln; - - nmln = strlen(name); - - for (src = dst = 0; env[src]; ++src) { - size_t enln; - enln = strlen(env[src]); - if (enln > nmln) { - /* might match, and can test for '=' safely */ - if (0 == strncmp (env[src], name, nmln) - && '=' == env[src][nmln]) - /* matches, so skip */ - continue; - } - env[dst] = env[src]; - ++dst; - } - env[dst] = NULL; -} diff --git a/spawn-pipe.h b/spawn-pipe.h index 3807819ae8..9bf387e411 100644 --- a/spawn-pipe.h +++ b/spawn-pipe.h @@ -1,5 +1,2 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, char **path, int pin[], int pout[]); int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, int pin[], int pout[]); -const char **copy_environ(); -const char **copy_env(const char **env); -void env_unsetenv(const char **env, const char *name); From 3393222e4877c26a4d6ac8f43b7584efa4c571d3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 18 Nov 2007 20:25:03 +0100 Subject: [PATCH 04/16] Reimplement start_command() to work just like the old spawnvpe_pipe(). The idea is to duplicate the handles that we want to pass to the child to stdin, stdout, or stderr after making a backup duplicate, then spawn the child program, then duplicate the backups back in place. --- run-command.c | 161 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 137 insertions(+), 24 deletions(-) diff --git a/run-command.c b/run-command.c index e5d029f7a2..05934f708f 100644 --- a/run-command.c +++ b/run-command.c @@ -1,7 +1,6 @@ #include "cache.h" #include "run-command.h" #include "exec_cmd.h" -#include "spawn-pipe.h" static inline void close_pair(int fd[2]) { @@ -9,13 +8,17 @@ static inline void close_pair(int fd[2]) close(fd[1]); } +static inline void dup_devnull(int to) +{ + int fd = open("/dev/null", O_RDWR); + dup2(fd, to); + close(fd); +} + int start_command(struct child_process *cmd) { int need_in, need_out, need_err; - int fdin[2] = { -1, -1 }; - int fdout[2] = { -1, -1 }; - int fderr[2] = { -1, -1 }; - char **env = environ; + int fdin[2], fdout[2], fderr[2]; need_in = !cmd->no_stdin && cmd->in < 0; if (need_in) { @@ -50,53 +53,150 @@ int start_command(struct child_process *cmd) cmd->err = fderr[0]; } - { +#ifndef __MINGW32__ + cmd->pid = fork(); + if (!cmd->pid) { if (cmd->no_stdin) - fdin[0] = open("/dev/null", O_RDWR); + dup_devnull(0); else if (need_in) { - /* nothing */ + dup2(fdin[0], 0); + close_pair(fdin); } else if (cmd->in) { - fdin[0] = cmd->in; + dup2(cmd->in, 0); + close(cmd->in); } if (cmd->no_stdout) - fdout[1] = open("/dev/null", O_RDWR); + dup_devnull(1); else if (cmd->stdout_to_stderr) - fdout[1] = dup(2); + dup2(2, 1); else if (need_out) { - /* nothing */ + dup2(fdout[1], 1); + close_pair(fdout); } else if (cmd->out > 1) { - fdout[1] = cmd->out; + dup2(cmd->out, 1); + close(cmd->out); } if (cmd->no_stderr) - fderr[1] = open("/dev/null", O_RDWR); + dup_devnull(2); else if (need_err) { - /* nothing */ + dup2(fderr[1], 2); + close_pair(fderr); } - if (cmd->dir) - die("chdir in start_command() not implemented"); if (cmd->dir && chdir(cmd->dir)) die("exec %s: cd to %s failed (%s)", cmd->argv[0], cmd->dir, strerror(errno)); if (cmd->env) { - if (cmd->git_cmd) - die("modifying environment for git_cmd in start_command() not implemented"); - env = copy_environ(); for (; *cmd->env; cmd->env++) { if (strchr(*cmd->env, '=')) - die("setting environment in start_command() not implemented"); + putenv((char*)*cmd->env); else - env_unsetenv(env, *cmd->env); + unsetenv(*cmd->env); } } if (cmd->git_cmd) { - cmd->pid = spawnv_git_cmd(cmd->argv, fdin, fdout); + execv_git_cmd(cmd->argv); } else { - cmd->pid = spawnvpe_pipe(cmd->argv[0], cmd->argv, env, fdin, fdout); + execvp(cmd->argv[0], (char *const*) cmd->argv); + } + die("exec %s failed.", cmd->argv[0]); + } +#else + int s0 = -1, s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */ + const char *sargv0 = cmd->argv[0]; + char **env = environ; + struct strbuf git_cmd; + + if (cmd->no_stdin) { + s0 = dup(0); + dup_devnull(0); + } else if (need_in) { + s0 = dup(0); + dup2(fdin[0], 0); + } else if (cmd->in) { + s0 = dup(0); + dup2(cmd->in, 0); + } + + if (cmd->no_stdout) { + s1 = dup(1); + dup_devnull(1); + } else if (cmd->stdout_to_stderr) { + s1 = dup(1); + dup2(2, 1); + } else if (need_out) { + s1 = dup(1); + dup2(fdout[1], 1); + } else if (cmd->out > 1) { + s1 = dup(1); + dup2(cmd->out, 1); + } + + if (cmd->no_stderr) { + s2 = dup(2); + dup_devnull(2); + } else if (need_err) { + s2 = dup(2); + dup2(fderr[1], 2); + } + + if (cmd->dir) + die("chdir in start_command() not implemented"); + if (cmd->env) { + env = copy_environ(); + for (; *cmd->env; cmd->env++) { + if (strchr(*cmd->env, '=')) + die("setting environment in start_command() not implemented"); + else + env_unsetenv(env, *cmd->env); } } + + if (cmd->git_cmd) { + strbuf_init(&git_cmd, 0); + strbuf_addf(&git_cmd, "git-%s", cmd->argv[0]); + cmd->argv[0] = git_cmd.buf; + } + + char **path = mingw_get_path_split(); + const char *argv0 = cmd->argv[0]; + const char **qargv; + char *prog = mingw_path_lookup(argv0, path); + const char *interpr = parse_interpreter(prog); + int argc; + + for (argc = 0; cmd->argv[argc];) argc++; + qargv = xmalloc((argc+2)*sizeof(char*)); + if (!interpr) { + quote_argv(qargv, cmd->argv); + cmd->pid = spawnve(_P_NOWAIT, prog, qargv, (const char **)env); + } else { + qargv[0] = interpr; + cmd->argv[0] = prog; + quote_argv(&qargv[1], cmd->argv); + cmd->pid = spawnvpe(_P_NOWAIT, interpr, qargv, (const char **)env); + } + + free(qargv); /* TODO: quoted args should be freed, too */ + free(prog); + + mingw_free_path_split(path); + /* TODO: if (cmd->env) free env; */ + + if (cmd->git_cmd) + strbuf_release(&git_cmd); + + cmd->argv[0] = sargv0; + if (s0 >= 0) + dup2(s0, 0), close(s0); + if (s1 >= 0) + dup2(s1, 1), close(s1); + if (s2 >= 0) + dup2(s2, 2), close(s2); +#endif + if (cmd->pid < 0) { if (need_in) close_pair(fdin); @@ -107,6 +207,19 @@ int start_command(struct child_process *cmd) return -ERR_RUN_COMMAND_FORK; } + if (need_in) + close(fdin[0]); + else if (cmd->in) + close(cmd->in); + + if (need_out) + close(fdout[1]); + else if (cmd->out > 1) + close(cmd->out); + + if (need_err) + close(fderr[1]); + return 0; } From 855cdbbc3b3bb8975687ddfbe63cd10bf44e1410 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 18 Nov 2007 20:30:15 +0100 Subject: [PATCH 05/16] Remove now unused spawnv_git_cmd(). --- exec_cmd.c | 28 ---------------------------- exec_cmd.h | 1 - 2 files changed, 29 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 6aa842bb4f..9d22e78eb0 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -1,7 +1,6 @@ #include "cache.h" #include "exec_cmd.h" #include "quote.h" -#include "spawn-pipe.h" #define MAX_ARGS 32 extern char **environ; @@ -155,30 +154,3 @@ int execl_git_cmd(const char *cmd,...) argv[argc] = NULL; return execv_git_cmd(argv); } - -int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]) -{ - pid_t pid; - struct strbuf cmd; - const char *tmp; - - strbuf_init(&cmd, 0); - strbuf_addf(&cmd, "git-%s", argv[0]); - - /* argv[0] must be the git command, but the argv array - * belongs to the caller. Save argv[0] and - * restore it later. - */ - - tmp = argv[0]; - argv[0] = cmd.buf; - - trace_argv_printf(argv, -1, "trace: exec:"); - - pid = spawnvpe_pipe(cmd.buf, argv, environ, - pin, pout); - - argv[0] = tmp; - return pid; - -} diff --git a/exec_cmd.h b/exec_cmd.h index 9e8a28489e..a892355c82 100644 --- a/exec_cmd.h +++ b/exec_cmd.h @@ -6,7 +6,6 @@ extern const char* git_exec_path(void); extern void setup_path(const char *); extern int execv_git_cmd(const char **argv); /* NULL terminated */ extern int execl_git_cmd(const char *cmd, ...); -extern int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]); #endif /* GIT_EXEC_CMD_H */ From d51703c66552023b930724fcdd9e6324b0f42f5e Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 18 Nov 2007 20:33:36 +0100 Subject: [PATCH 06/16] Remove now unused spawn-pipe.c with spawnvpe_pipe() function. --- Makefile | 2 - connect.c | 1 - spawn-pipe.c | 131 --------------------------------------------------- spawn-pipe.h | 2 - 4 files changed, 136 deletions(-) delete mode 100644 spawn-pipe.c delete mode 100644 spawn-pipe.h diff --git a/Makefile b/Makefile index e8058c3f19..7f5a2e4f4b 100644 --- a/Makefile +++ b/Makefile @@ -291,7 +291,6 @@ LIB_H = \ diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \ run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \ tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \ - spawn-pipe.h \ utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h \ mailmap.h remote.h parse-options.h transport.h diffcore.h hash.h @@ -305,7 +304,6 @@ LIB_OBJS = \ date.o diff-delta.o entry.o exec_cmd.o ident.o \ pretty.o interpolate.o hash.o \ lockfile.o \ - spawn-pipe.o \ patch-ids.o \ object.o pack-check.o pack-write.o patch-delta.o path.o pkt-line.o \ sideband.o reachable.o reflog-walk.o \ diff --git a/connect.c b/connect.c index e11cf32321..0f10c40652 100644 --- a/connect.c +++ b/connect.c @@ -5,7 +5,6 @@ #include "refs.h" #include "run-command.h" #include "remote.h" -#include "spawn-pipe.h" static char *server_capabilities; diff --git a/spawn-pipe.c b/spawn-pipe.c deleted file mode 100644 index 9cb0cf5b70..0000000000 --- a/spawn-pipe.c +++ /dev/null @@ -1,131 +0,0 @@ -#include "git-compat-util.h" -#include "spawn-pipe.h" - -extern char **environ; - -/* cmd specifies the command to invoke. - * argv specifies its arguments; argv[0] will be replaced by the basename of cmd. - * env specifies the environment. - * pin and pout specify pipes; the read end of pin is made the standard input - * of the spawned process, and the write end of pout is mad the standard output. - * The respective unused ends of the pipes are closed both in the parent - * process as well as in the child process. - * Anyone of pin or pout can be NULL, or any one of the ends can be -1 to - * indicate that no processing shall occur. - */ -int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, - int pin[], int pout[]) -{ -#ifdef __MINGW32__ - char **path = mingw_get_path_split(); - - pid_t pid = spawnvppe_pipe(cmd, argv, env, path, pin, pout); - - mingw_free_path_split(path); -#else - pid_t pid = spawnvppe_pipe(cmd, argv, env, NULL, pin, pout); -#endif - return pid; -} - -int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, - char **path, - int pin[], int pout[]) -{ - const char *cmd_basename = strrchr(cmd, '/'); - const char *argv0 = argv[0]; - pid_t pid; - -#ifdef __MINGW32__ - int s0 = -1, s1 = -1, argc; - char *prog; - const char **qargv, *interpr; - - if (!cmd_basename) - cmd_basename = strrchr(cmd, '\\'); -#endif - - if (!cmd_basename) - cmd_basename = cmd; - else - cmd_basename++; - argv[0] = cmd_basename; - -#ifndef __MINGW32__ - pid = fork(); - if (pid < 0) - die("unable to fork"); - if (!pid) { - if (pin) { - if (pin[0] >= 0) { - dup2(pin[0], 0); - close(pin[0]); - } - if (pin[1] >= 0) - close(pin[1]); - } - if (pout) { - if (pout[1] >= 0) { - dup2(pout[1], 1); - close(pout[1]); - } - if (pout[0] >= 0) - close(pout[0]); - } - environ = env; - execvp(cmd, argv); - die("exec failed"); - } - - if (pin && pin[0] >= 0) - close(pin[0]); - if (pout && pout[1] >= 1) - close(pout[1]); -#else - if (pin) { - if (pin[0] >= 0) { - s0 = dup(0); - dup2(pin[0], 0); - close(pin[0]); - } - } - if (pout) { - if (pout[1] >= 0) { - s1 = dup(1); - dup2(pout[1], 1); - close(pout[1]); - } - } - - prog = mingw_path_lookup(cmd, path); - interpr = parse_interpreter(prog); - - for (argc = 0; argv[argc];) argc++; - qargv = xmalloc((argc+2)*sizeof(char*)); - if (!interpr) { - quote_argv(qargv, argv); - pid = spawnve(_P_NOWAIT, prog, qargv, env); - } else { - qargv[0] = interpr; - argv[0] = prog; - quote_argv(&qargv[1], argv); - pid = spawnvpe(_P_NOWAIT, interpr, qargv, env); - } - - free(qargv); /* TODO: quoted args should be freed, too */ - free(prog); - - if (s0 >= 0) { - dup2(s0, 0); - close(s0); - } - if (s1 >= 0) { - dup2(s1, 1); - close(s1); - } -#endif - - argv[0] = argv0; - - return pid; -} diff --git a/spawn-pipe.h b/spawn-pipe.h deleted file mode 100644 index 9bf387e411..0000000000 --- a/spawn-pipe.h +++ /dev/null @@ -1,2 +0,0 @@ -int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, char **path, int pin[], int pout[]); -int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, int pin[], int pout[]); From 8ddaf895a80c1d42bd0e923cb0f1f041d00a27ea Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 20:27:40 +0100 Subject: [PATCH 07/16] compat/mingw.c: Add cast of handle to fix warning [js: whitespace removed] Signed-off-by: Steffen Prohaska Signed-off-by: Johannes Sixt --- compat/mingw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 0456319ba6..b18231e903 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -235,7 +235,7 @@ int pipe(int filedes[2]) CloseHandle(h[0]); return -1; } - fd = _open_osfhandle(h[0], O_NOINHERIT); + fd = _open_osfhandle((int)h[0], O_NOINHERIT); if (fd < 0) { close(filedes[0]); close(filedes[1]); @@ -245,7 +245,7 @@ int pipe(int filedes[2]) } close(filedes[0]); filedes[0] = fd; - fd = _open_osfhandle(h[1], O_NOINHERIT); + fd = _open_osfhandle((int)h[1], O_NOINHERIT); if (fd < 0) { close(filedes[0]); close(filedes[1]); From f593be04806654aaff987f660e1998b0e19a9b8b Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 20:43:30 +0100 Subject: [PATCH 08/16] test-chmtime.c: Cast HANDLE to fix warning Signed-off-by: Steffen Prohaska Signed-off-by: Johannes Sixt --- test-chmtime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-chmtime.c b/test-chmtime.c index b6dc548a2a..8a1e6b8479 100644 --- a/test-chmtime.c +++ b/test-chmtime.c @@ -22,7 +22,7 @@ int git_utime (const char *file_name, const struct utimbuf *times) time_t_to_filetime(times->modtime, &mft); time_t_to_filetime(times->actime, &aft); - if (!SetFileTime(_get_osfhandle(fh), NULL, &aft, &mft)) { + if (!SetFileTime((HANDLE)_get_osfhandle(fh), NULL, &aft, &mft)) { errno = EINVAL; rc = -1; } else From a8d8425ec6f2b75c59562b6e9a7508ab623a2cd4 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 21:07:32 +0100 Subject: [PATCH 09/16] Fix prototypes for mingw_execve and mingw_execvp to match Posix This changes the prototypes to match http://www.opengroup.org/onlinepubs/7990989775/xsh/exec.html [js: updated message] Signed-off-by: Steffen Prohaska Signed-off-by: Johannes Sixt --- compat/mingw.c | 19 ++++++++++--------- git-compat-util.h | 6 +++--- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index b18231e903..ad44c86a98 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -352,7 +352,7 @@ static const char *quote_arg(const char *arg) return q; } -void quote_argv(const char **dst, const char **src) +void quote_argv(const char **dst, const char *const *src) { while (*src) *dst++ = quote_arg(*src++); @@ -394,7 +394,7 @@ const char *parse_interpreter(const char *cmd) return p+1; } -static int try_shell_exec(const char *cmd, const char **argv, const char **env) +static int try_shell_exec(const char *cmd, char *const *argv, char *const *env) { const char **sh_argv; int n; @@ -412,14 +412,14 @@ static int try_shell_exec(const char *cmd, const char **argv, const char **env) sh_argv = xmalloc((n+2)*sizeof(char*)); sh_argv[0] = interpr; sh_argv[1] = quote_arg(cmd); - quote_argv(&sh_argv[2], &argv[1]); - n = spawnvpe(_P_WAIT, interpr, sh_argv, env); + quote_argv(&sh_argv[2], (const char *const *)&argv[1]); + n = spawnvpe(_P_WAIT, interpr, sh_argv, (const char *const *)env); if (n == -1) return 1; /* indicate that we tried but failed */ exit(n); } -void mingw_execve(const char *cmd, const char **argv, const char **env) +void mingw_execve(const char *cmd, char *const *argv, char *const *env) { /* check if git_command is a shell script */ if (!try_shell_exec(cmd, argv, env)) { @@ -427,8 +427,9 @@ void mingw_execve(const char *cmd, const char **argv, const char **env) int n; for (n = 0; argv[n];) n++; qargv = xmalloc((n+1)*sizeof(char*)); - quote_argv(qargv, argv); - int ret = spawnve(_P_WAIT, cmd, qargv, env); + quote_argv(qargv, (const char *const *)argv); + int ret = spawnve(_P_WAIT, cmd, qargv, + (const char *const *)env); if (ret != -1) exit(ret); } @@ -522,13 +523,13 @@ void mingw_free_path_split(char **path) free(path); } -void mingw_execvp(const char *cmd, const char **argv) +void mingw_execvp(const char *cmd, char *const *argv) { char **path = mingw_get_path_split(); char *prog = mingw_path_lookup(cmd, path); if (prog) { - mingw_execve(prog, argv, (const char **) environ); + mingw_execve(prog, argv, environ); free(prog); } else errno = ENOENT; diff --git a/git-compat-util.h b/git-compat-util.h index 768e7fc696..c88186d685 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -451,9 +451,9 @@ static inline int kill(pid_t pid, int sig) static inline unsigned int alarm(unsigned int seconds) { return 0; } -void mingw_execve(const char *cmd, const char **argv, const char **env); +void mingw_execve(const char *cmd, char *const *argv, char * const *env); #define execve mingw_execve -extern void mingw_execvp(const char *cmd, const char **argv); +extern void mingw_execvp(const char *cmd, char *const *argv); #define execvp mingw_execvp typedef int pid_t; static inline int waitpid(pid_t pid, unsigned *status, unsigned options) @@ -527,7 +527,7 @@ static inline int getppid(void) { return 1; } static inline void sync(void) {} extern int getpagesize(void); /* defined in MinGW's libgcc.a */ -extern void quote_argv(const char **dst, const char **src); +extern void quote_argv(const char **dst, const char *const *src); extern const char *parse_interpreter(const char *cmd); extern char *mingw_path_lookup(const char *cmd, char **path); extern char **mingw_get_path_split(void); From f801325ed5fd9d3f4732dbef18f4270c4ea89654 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 19 Nov 2007 12:34:22 +0100 Subject: [PATCH 10/16] Implement a rudimentary poll() emulation for Windows. This emulation of poll() is by far not general. It assumes that the fds that are to be waited for are connected to pipes. The pipes are polled in a loop until data becomes available in at least one of them. If only a single fd is waited for, the implementation actually does not wait at all, but assumes that a subsequent read() will block. In order to not burn CPU time, it is yielded to other processes before the next round in the poll loop using Sleep(0). Note that any sleep timeout greater than zero will reduce the efficiency by a magnitude. Signed-off-by: Johannes Sixt --- compat/mingw.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index ad44c86a98..676aae573e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -259,7 +259,62 @@ int pipe(int filedes[2]) int poll(struct pollfd *ufds, unsigned int nfds, int timeout) { - return -1; + int i, pending; + + if (timeout != -1) + return errno = EINVAL, error("poll timeout not supported"); + + /* When there is only one fd to wait for, then we pretend that + * input is available and let the actual wait happen when the + * caller invokes read(). + */ + if (nfds == 1) { + if (!(ufds[0].events & POLLIN)) + return errno = EINVAL, error("POLLIN not set"); + ufds[0].revents = POLLIN; + return 0; + } + +repeat: + pending = 0; + for (i = 0; i < nfds; i++) { + DWORD avail = 0; + HANDLE h = (HANDLE) _get_osfhandle(ufds[i].fd); + if (h == INVALID_HANDLE_VALUE) + return -1; /* errno was set */ + + if (!(ufds[i].events & POLLIN)) + return errno = EINVAL, error("POLLIN not set"); + + /* this emulation works only for pipes */ + if (!PeekNamedPipe(h, NULL, 0, NULL, &avail, NULL)) { + int err = GetLastError(); + if (err == ERROR_BROKEN_PIPE) { + ufds[i].revents = POLLHUP; + pending++; + } else { + errno = EINVAL; + return error("PeekNamedPipe failed," + " GetLastError: %u", err); + } + } else if (avail) { + ufds[i].revents = POLLIN; + pending++; + } else + ufds[i].revents = 0; + } + if (!pending) { + /* The only times that we spin here is when the process + * that is connected through the pipes is waiting for + * its own input data to become available. But since + * the process (pack-objects) is itself CPU intensive, + * it will happily pick up the time slice that we are + * relinguishing here. + */ + Sleep(0); + goto repeat; + } + return 0; } #include From 40c18e8ee6fcb5128719ee6e1b5aabee689da436 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 19 Nov 2007 12:39:57 +0100 Subject: [PATCH 11/16] upload-pack: Remove MinGW specific code. Now that a poll() implementation is available, upload-pack also offers side-band communication. --- upload-pack.c | 45 ++------------------------------------------- 1 file changed, 2 insertions(+), 43 deletions(-) diff --git a/upload-pack.c b/upload-pack.c index 84569a3aad..75e2acb29e 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -174,7 +174,6 @@ static void create_pack_file(void) if (start_command(&pack_objects)) die("git-upload-pack: unable to fork git-pack-objects"); -#ifndef __MINGW32__ /* We read from pack_objects.err to capture stderr output for * progress bar, and pack_objects.out to capture the pack data. */ @@ -265,41 +264,6 @@ static void create_pack_file(void) goto fail; } } -#else - char *cp; - - /* We read from pack_objects.out to capture the pack data. */ - - while ((sz = xread(pack_objects.out, data+1, sizeof(data)-1)) > 0) { - cp = data+1; - /* Data ready; we keep the last byte to ourselves in case we - * detect broken rev-list, so that we can leave the stream - * corrupted. This is unfortunate -- unpack-objects would - * happily accept a valid pack data with trailing garbage, so - * appending garbage after we pass all the pack data is not - * good enough to signal breakage to downstream. - */ - if (0 <= buffered) { - *--cp = buffered; - sz++; - } - if (1 < sz) { - buffered = cp[sz-1] & 0xFF; - sz--; - } - else - buffered = -1; - sz = send_client_data(1, cp, sz); - if (sz < 0) - goto fail; - } - if (sz == 0) { - close(pack_objects.out); - pack_objects.out = -1; - } - else - goto fail; -#endif if (finish_command(&pack_objects)) { error("git-upload-pack: git-pack-objects died with error."); @@ -521,12 +485,10 @@ static void receive_needs(void) use_thin_pack = 1; if (strstr(line+45, "ofs-delta")) use_ofs_delta = 1; -#ifndef __MINGW32__ if (strstr(line+45, "side-band-64k")) use_sideband = LARGE_PACKET_MAX; else if (strstr(line+45, "side-band")) use_sideband = DEFAULT_PACKET_MAX; -#endif if (strstr(line+45, "no-progress")) no_progress = 1; @@ -596,11 +558,8 @@ static void receive_needs(void) static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { - static const char *capabilities = "multi_ack thin-pack" -#ifndef __MINGW32__ - " side-band side-band-64k" -#endif - " ofs-delta shallow no-progress"; + static const char *capabilities = "multi_ack thin-pack side-band" + " side-band-64k ofs-delta shallow no-progress"; struct object *o = parse_object(sha1); if (!o) From ad0b9993f9e21199cca77c0f04770e4013090d26 Mon Sep 17 00:00:00 2001 From: Dmitry Kakurin Date: Sat, 17 Nov 2007 20:32:08 +0100 Subject: [PATCH 12/16] compat/regex.c: Fix warnings In general, we don't add unnecessary braces. But in this case gcc warns about them. So this commit adds a few braces. The commit suppresses warnings about unitialized variables by initializing them to NULL. The change of bcmp_translate()'s parameter declaration is needed to avoid warnings about "discards qualifiers from pointer target type". [sp: split original commit; more detailed commit message. ] Signed-off-by: Dmitry Kakurin Signed-off-by: Steffen Prohaska --- compat/regex.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/compat/regex.c b/compat/regex.c index 2d57c70b9c..1d39e08d47 100644 --- a/compat/regex.c +++ b/compat/regex.c @@ -1597,10 +1597,12 @@ regex_compile (pattern, size, syntax, bufp) if (syntax & RE_NO_BK_PARENS) goto normal_backslash; if (COMPILE_STACK_EMPTY) + { if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) goto normal_backslash; else return REG_ERPAREN; + } handle_close: if (fixup_alt_jump) @@ -1617,10 +1619,12 @@ regex_compile (pattern, size, syntax, bufp) /* See similar code for backslashed left paren above. */ if (COMPILE_STACK_EMPTY) + { if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) goto normal_char; else return REG_ERPAREN; + } /* Since we just checked for an empty stack above, this ``can't happen''. */ @@ -3191,14 +3195,14 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) matching and the regnum-th regend points to right after where we stopped matching the regnum-th subexpression. (The zeroth register keeps track of what the whole pattern matches.) */ - const char **regstart, **regend; + const char **regstart = NULL, **regend = NULL; /* If a group that's operated upon by a repetition operator fails to match anything, then the register for its start will need to be restored because it will have been set to wherever in the string we are when we last see its open-group operator. Similarly for a register's end. */ - const char **old_regstart, **old_regend; + const char **old_regstart = NULL, **old_regend = NULL; /* The is_active field of reg_info helps us keep track of which (possibly nested) subexpressions we are currently in. The matched_something @@ -3206,14 +3210,14 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) matched any of the pattern so far this time through the reg_num-th subexpression. These two fields get reset each time through any loop their register is in. */ - register_info_type *reg_info; + register_info_type *reg_info = NULL; /* The following record the register info as found in the above variables when we find a match better than any we've seen before. This happens as we backtrack through the failure points, which in turn happens only if we have not yet matched the entire string. */ unsigned best_regs_set = false; - const char **best_regstart, **best_regend; + const char **best_regstart = NULL, **best_regend = NULL; /* Logically, this is `best_regend[0]'. But we don't want to have to allocate space for that if we're not allocating space for anything @@ -3226,8 +3230,8 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) const char *match_end = NULL; /* Used when we pop values we don't care about. */ - const char **reg_dummy; - register_info_type *reg_info_dummy; + const char **reg_dummy = NULL; + register_info_type *reg_info_dummy = NULL; #ifdef DEBUG /* Counts the total number of registers pushed. */ @@ -4561,10 +4565,12 @@ common_op_match_null_string_p (p, end, reg_info) bytes; nonzero otherwise. */ static int -bcmp_translate (s1, s2, len, translate) - unsigned char *s1, *s2; - register int len; - char *translate; +bcmp_translate( + unsigned char *s1, + unsigned char *s2, + int len, + char *translate +) { register unsigned char *p1 = s1, *p2 = s2; while (len) From 5a09d6a3ac8f4fa39e059ad61ece1aabd5a861e1 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 20:48:14 +0100 Subject: [PATCH 13/16] compat/pread.c: Add foward decl to fix warning read_in_full()'s is used in compat/pread.c. read_in_full() is declared in cache.h. But we can't include cache.h because too many macros are defined there. Using read_in_full() without including cache.h is dangerous because we wouldn't recognize if its prototyp changed. gcc issues a warning about that. This commit adds a forward decl to git-compat-util.h. git-compat-util.h is included by compat/pread.c _and_ cache.h. Hence, changes in cache.h would be detected. Signed-off-by: Steffen Prohaska --- git-compat-util.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/git-compat-util.h b/git-compat-util.h index c88186d685..b76f94fc05 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -153,6 +153,10 @@ extern int git_munmap(void *start, size_t length); #define pread git_pread extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset); #endif +/* Forward decl that will remind us if its twin in cache.h changes. + This function in used in compat/pread.c. But we can't include + cache.h there. */ +extern int read_in_full(int fd, void *buf, size_t count); #ifdef NO_SETENV #define setenv gitsetenv From c2849fc4b1a4618f2d81ef2597d7e40d7b2e048c Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 19:16:53 +0100 Subject: [PATCH 14/16] Fix ntohl() related warnings about printf formatting On Windows, ntohl() returns unsinged long. On Unix it returns uint32_t. This makes choosing a suitable printf format string hard. This commit introduces a mingw specific helper function git_ntohl() that casts to unsigned int before returning. This makes gcc's printf format check happy. It should be safe because we expect ntohl to use 32-bit numbers. Signed-off-by: Steffen Prohaska --- git-compat-util.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/git-compat-util.h b/git-compat-util.h index b76f94fc05..74412331d8 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -594,6 +594,10 @@ static inline int mingw_fcntl(int fd, int cmd, long arg) { return cmd == F_GETFD || cmd == F_SETFD ? 0 : (errno = EINVAL, -1); } #define fcntl mingw_fcntl +static inline unsigned int git_ntohl(unsigned int x) +{ return (unsigned int)ntohl(x); } +#define ntohl git_ntohl + #endif /* __MINGW32__ */ #endif From a6ed49cf52589d26235dc2461ebaf8b38446b061 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 21 Nov 2007 09:21:12 +0100 Subject: [PATCH 15/16] Fix error messages in timer implementation. There were some references to the progress indicator, where this implementation originally appeared. Signed-off-by: Johannes Sixt --- compat/mingw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 676aae573e..aa730e9bc1 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -760,10 +760,10 @@ static int start_timer_thread(void) timer_thread = (HANDLE) _beginthreadex(NULL, 0, ticktack, NULL, 0, NULL); if (!timer_thread ) return errno = ENOMEM, - error("cannot create progress indicator"); + error("cannot start timer thread"); } else return errno = ENOMEM, - error("cannot allocate resources for progress indicator"); + error("cannot allocate resources timer"); return 0; } From 726fb5ed5ded96f6a60a7adf41e50b6c00b4f246 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 17 Nov 2007 22:42:12 +0100 Subject: [PATCH 16/16] fetch-pack: Enable sideband communication. --- builtin-fetch-pack.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index 2f37b5cd24..807fa93b53 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -563,7 +563,6 @@ static struct ref *do_fetch_pack(int fd[2], fprintf(stderr, "Server supports multi_ack\n"); multi_ack = 1; } -#ifndef __MINGW32__ if (server_supports("side-band-64k")) { if (args.verbose) fprintf(stderr, "Server supports side-band-64k\n"); @@ -574,7 +573,6 @@ static struct ref *do_fetch_pack(int fd[2], fprintf(stderr, "Server supports side-band\n"); use_sideband = 1; } -#endif if (!ref) { packet_flush(fd[1]); die("no matching remote head");