Merge commit 'mingw/master' into work/towards-mingw

Conflicts:

	compat/mingw.c
	exec_cmd.c
	git-compat-util.h
	run-command.c
	spawn-pipe.c
This commit is contained in:
Steffen Prohaska
2007-11-21 21:49:22 +01:00
11 changed files with 257 additions and 305 deletions

View File

@@ -294,7 +294,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
@@ -308,7 +307,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 \

View File

@@ -463,34 +463,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];
@@ -498,7 +476,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;
@@ -507,7 +498,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));
@@ -543,11 +534,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);
@@ -574,7 +564,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");
@@ -585,7 +574,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");

View File

@@ -235,7 +235,7 @@ int pipe(int filedes[2])
CloseHandle(h[0]);
return -1;
}
fd = _open_osfhandle( (int) 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( (int) h[1], O_NOINHERIT);
fd = _open_osfhandle((int)h[1], O_NOINHERIT);
if (fd < 0) {
close(filedes[0]);
close(filedes[1]);
@@ -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 <time.h>
@@ -537,6 +592,45 @@ void mingw_execvp(const char *cmd, char *const *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);
@@ -666,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;
}

View File

@@ -5,7 +5,6 @@
#include "refs.h"
#include "run-command.h"
#include "remote.h"
#include "spawn-pipe.h"
static char *server_capabilities;

View File

@@ -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, (const char **)environ,
pin, pout);
argv[0] = tmp;
return pid;
}

View File

@@ -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 */

View File

@@ -480,6 +480,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);

View File

@@ -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 };
const char **env = (const char **)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;
}

View File

@@ -1,169 +0,0 @@
#include "git-compat-util.h"
#include "spawn-pipe.h"
/* 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;
}
const char **copy_environ()
{
return copy_env( (const char**)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;
}

View File

@@ -1,5 +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[]);
const char **copy_environ();
const char **copy_env(const char **env);
void env_unsetenv(const char **env, const char *name);

View File

@@ -142,10 +142,7 @@ static void create_pack_file(void)
struct async rev_list;
struct child_process pack_objects;
int create_full_pack = (nr_our_refs == want_obj.nr && !have_obj.nr);
char data[8193];
#ifndef __MINGW32__
char progress[128];
#endif
char data[8193], progress[128];
char abort_msg[] = "aborting due to possible repository "
"corruption on the remote side.";
int buffered = -1;
@@ -177,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.
*/
@@ -268,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.");
@@ -524,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;