From 1bc01efed17c751e98fd6c5f9889759bfa9a8e9b Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sat, 19 Nov 2011 02:40:04 -0500 Subject: [PATCH] upload-archive: use start_command instead of fork The POSIX-function fork is not supported on Windows. Use our start_command API instead, respawning ourselves in a special "writer" mode to follow the alternate code path. Remove the NOT_MINGW-prereq for t5000, as git-archive --remote now works. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin.h | 1 + builtin/upload-archive.c | 43 +++++++++++----------------------------- git.c | 1 + t/t5000-tar-tree.sh | 10 +++++----- 4 files changed, 19 insertions(+), 36 deletions(-) diff --git a/builtin.h b/builtin.h index 0e9da90834..f2357a94cf 100644 --- a/builtin.h +++ b/builtin.h @@ -133,6 +133,7 @@ extern int cmd_update_index(int argc, const char **argv, const char *prefix); extern int cmd_update_ref(int argc, const char **argv, const char *prefix); extern int cmd_update_server_info(int argc, const char **argv, const char *prefix); extern int cmd_upload_archive(int argc, const char **argv, const char *prefix); +extern int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix); extern int cmd_upload_tar(int argc, const char **argv, const char *prefix); extern int cmd_var(int argc, const char **argv, const char *prefix); extern int cmd_verify_tag(int argc, const char **argv, const char *prefix); diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c index 2d0b38333e..b928beb8ed 100644 --- a/builtin/upload-archive.c +++ b/builtin/upload-archive.c @@ -6,6 +6,7 @@ #include "archive.h" #include "pkt-line.h" #include "sideband.h" +#include "run-command.h" static const char upload_archive_usage[] = "git upload-archive "; @@ -13,12 +14,9 @@ static const char upload_archive_usage[] = static const char deadchild[] = "git upload-archive: archiver died with error"; -static const char lostchild[] = -"git upload-archive: archiver process was lost"; - #define MAX_ARGS (64) -static int run_upload_archive(int argc, const char **argv, const char *prefix) +int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix) { const char *sent_argv[MAX_ARGS]; const char *arg_cmd = "argument "; @@ -96,8 +94,8 @@ static ssize_t process_input(int child_fd, int band) int cmd_upload_archive(int argc, const char **argv, const char *prefix) { - pid_t writer; - int fd1[2], fd2[2]; + struct child_process writer = { argv }; + /* * Set up sideband subprocess. * @@ -105,39 +103,24 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix) * multiplexed out to our fd#1. If the child dies, we tell the other * end over channel #3. */ - if (pipe(fd1) < 0 || pipe(fd2) < 0) { + argv[0] = "upload-archive--writer"; + writer.out = writer.err = -1; + writer.git_cmd = 1; + if (start_command(&writer)) { int err = errno; - packet_write(1, "NACK pipe failed on the remote side\n"); + packet_write(1, "NACK unable to spawn subprocess\n"); die("upload-archive: %s", strerror(err)); } - writer = fork(); - if (writer < 0) { - int err = errno; - packet_write(1, "NACK fork failed on the remote side\n"); - die("upload-archive: %s", strerror(err)); - } - if (!writer) { - /* child - connect fd#1 and fd#2 to the pipe */ - dup2(fd1[1], 1); - dup2(fd2[1], 2); - close(fd1[1]); close(fd2[1]); - close(fd1[0]); close(fd2[0]); /* we do not read from pipe */ - exit(run_upload_archive(argc, argv, prefix)); - } - - /* parent - read from child, multiplex and send out to fd#1 */ - close(fd1[1]); close(fd2[1]); /* we do not write to pipe */ packet_write(1, "ACK\n"); packet_flush(1); while (1) { struct pollfd pfd[2]; - int status; - pfd[0].fd = fd1[0]; + pfd[0].fd = writer.out; pfd[0].events = POLLIN; - pfd[1].fd = fd2[0]; + pfd[1].fd = writer.err; pfd[1].events = POLLIN; if (poll(pfd, 2, -1) < 0) { if (errno != EINTR) { @@ -156,9 +139,7 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix) if (process_input(pfd[0].fd, 1)) continue; - if (waitpid(writer, &status, 0) < 0) - error_clnt("%s", lostchild); - else if (!WIFEXITED(status) || WEXITSTATUS(status) > 0) + if (finish_command(&writer)) error_clnt("%s", deadchild); packet_flush(1); break; diff --git a/git.c b/git.c index 8e34903a65..250f4483ea 100644 --- a/git.c +++ b/git.c @@ -434,6 +434,7 @@ static void handle_internal_command(int argc, const char **argv) { "update-ref", cmd_update_ref, RUN_SETUP }, { "update-server-info", cmd_update_server_info, RUN_SETUP }, { "upload-archive", cmd_upload_archive }, + { "upload-archive--writer", cmd_upload_archive_writer }, { "var", cmd_var, RUN_SETUP_GENTLY }, { "verify-pack", cmd_verify_pack }, { "verify-tag", cmd_verify_tag, RUN_SETUP }, diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index d9068981f8..889842e7fc 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -96,7 +96,7 @@ test_expect_success 'git archive with --output' \ 'git archive --output=b4.tar HEAD && test_cmp b.tar b4.tar' -test_expect_success NOT_MINGW 'git archive --remote' \ +test_expect_success 'git archive --remote' \ 'git archive --remote=. HEAD >b5.tar && test_cmp b.tar b5.tar' @@ -266,7 +266,7 @@ test_expect_success 'archive --list mentions user filter' ' grep "^bar\$" output ' -test_expect_success NOT_MINGW 'archive --list shows only enabled remote filters' ' +test_expect_success 'archive --list shows only enabled remote filters' ' git archive --list --remote=. >output && ! grep "^tar\.foo\$" output && grep "^bar\$" output @@ -298,7 +298,7 @@ test_expect_success 'extension matching requires dot' ' test_cmp b.tar config-implicittar.foo ' -test_expect_success NOT_MINGW 'only enabled filters are available remotely' ' +test_expect_success 'only enabled filters are available remotely' ' test_must_fail git archive --remote=. --format=tar.foo HEAD \ >remote.tar.foo && git archive --remote=. --format=bar >remote.bar HEAD && @@ -341,12 +341,12 @@ test_expect_success GZIP,GUNZIP 'extract tgz file' ' test_cmp b.tar j.tar ' -test_expect_success GZIP,NOT_MINGW 'remote tar.gz is allowed by default' ' +test_expect_success GZIP 'remote tar.gz is allowed by default' ' git archive --remote=. --format=tar.gz HEAD >remote.tar.gz && test_cmp j.tgz remote.tar.gz ' -test_expect_success GZIP,NOT_MINGW 'remote tar.gz can be disabled' ' +test_expect_success GZIP 'remote tar.gz can be disabled' ' git config tar.tar.gz.remote false && test_must_fail git archive --remote=. --format=tar.gz HEAD \ >remote.tar.gz