diff --git a/Makefile b/Makefile index abfc073582..1d265a4d4f 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ PROGRAMS = \ git-receive-pack$X git-rev-parse$X \ git-send-pack$X git-show-branch$X git-shell$X \ git-show-index$X git-ssh-fetch$X \ - git-ssh-upload$X git-tar-tree$X git-unpack-file$X \ + git-ssh-upload$X git-unpack-file$X \ git-unpack-objects$X git-update-index$X git-update-server-info$X \ git-upload-pack$X git-verify-pack$X git-write-tree$X \ git-update-ref$X git-symbolic-ref$X \ @@ -172,7 +172,7 @@ BUILT_INS = git-log$X git-whatchanged$X git-show$X \ git-count-objects$X git-diff$X git-push$X \ git-grep$X git-add$X git-rm$X git-rev-list$X \ git-check-ref-format$X \ - git-init-db$X + git-init-db$X git-tar-tree$X git-upload-tar$X # what 'all' will build and 'install' will install, in gitexecdir ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS) @@ -221,7 +221,7 @@ LIB_OBJS = \ BUILTIN_OBJS = \ builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \ builtin-grep.o builtin-add.o builtin-rev-list.o builtin-check-ref-format.o \ - builtin-rm.o builtin-init-db.o + builtin-rm.o builtin-init-db.o builtin-tar-tree.o builtin-upload-tar.o GITLIBS = $(LIB_FILE) $(XDIFF_LIB) LIBS = $(GITLIBS) -lz diff --git a/tar-tree.c b/builtin-tar-tree.c similarity index 85% rename from tar-tree.c rename to builtin-tar-tree.c index 33087366c3..e97e0af985 100644 --- a/tar-tree.c +++ b/builtin-tar-tree.c @@ -7,11 +7,14 @@ #include "commit.h" #include "strbuf.h" #include "tar.h" +#include "builtin.h" +#include "pkt-line.h" #define RECORDSIZE (512) #define BLOCKSIZE (RECORDSIZE * 20) -static const char tar_tree_usage[] = "git-tar-tree [basedir]"; +static const char tar_tree_usage[] = +"git-tar-tree [--remote=] [basedir]"; static char block[BLOCKSIZE]; static unsigned long offset; @@ -301,7 +304,7 @@ static void traverse_tree(struct tree_desc *tree, struct strbuf *path) } } -int main(int argc, char **argv) +int generate_tar(int argc, const char **argv) { unsigned char sha1[20], tree_sha1[20]; struct commit *commit; @@ -348,3 +351,58 @@ int main(int argc, char **argv) free(current_path.buf); return 0; } + +static const char *exec = "git-upload-tar"; + +static int remote_tar(int argc, const char **argv) +{ + int fd[2], ret, len; + pid_t pid; + char buf[1024]; + char *url; + + if (argc < 3 || 4 < argc) + usage(tar_tree_usage); + + /* --remote= */ + url = strdup(argv[1]+9); + pid = git_connect(fd, url, exec); + if (pid < 0) + return 1; + + packet_write(fd[1], "want %s\n", argv[2]); + if (argv[3]) + packet_write(fd[1], "base %s\n", argv[3]); + packet_flush(fd[1]); + + len = packet_read_line(fd[0], buf, sizeof(buf)); + if (!len) + die("git-tar-tree: expected ACK/NAK, got EOF"); + if (buf[len-1] == '\n') + buf[--len] = 0; + if (strcmp(buf, "ACK")) { + if (5 < len && !strncmp(buf, "NACK ", 5)) + die("git-tar-tree: NACK %s", buf + 5); + die("git-tar-tree: protocol error"); + } + /* expect a flush */ + len = packet_read_line(fd[0], buf, sizeof(buf)); + if (len) + die("git-tar-tree: expected a flush"); + + /* Now, start reading from fd[0] and spit it out to stdout */ + ret = copy_fd(fd[0], 1); + close(fd[0]); + + ret |= finish_connect(pid); + return !!ret; +} + +int cmd_tar_tree(int argc, const char **argv, char **envp) +{ + if (argc < 2) + usage(tar_tree_usage); + if (!strncmp("--remote=", argv[1], 9)) + return remote_tar(argc, argv); + return generate_tar(argc, argv); +} diff --git a/builtin-upload-tar.c b/builtin-upload-tar.c new file mode 100644 index 0000000000..d4fa7b56c3 --- /dev/null +++ b/builtin-upload-tar.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2006 Junio C Hamano + */ +#include "cache.h" +#include "pkt-line.h" +#include "exec_cmd.h" +#include "builtin.h" + +static const char upload_tar_usage[] = "git-upload-tar "; + +static int nak(const char *reason) +{ + packet_write(1, "NACK %s\n", reason); + packet_flush(1); + return 1; +} + +int cmd_upload_tar(int argc, const char **argv, char **envp) +{ + int len; + const char *dir = argv[1]; + char buf[8192]; + unsigned char sha1[20]; + char *base = NULL; + char hex[41]; + int ac; + const char *av[4]; + + if (argc != 2) + usage(upload_tar_usage); + if (strlen(dir) < sizeof(buf)-1) + strcpy(buf, dir); /* enter-repo smudges its argument */ + else + packet_write(1, "NACK insanely long repository name %s\n", dir); + if (!enter_repo(buf, 0)) { + packet_write(1, "NACK not a git archive %s\n", dir); + packet_flush(1); + return 1; + } + + len = packet_read_line(0, buf, sizeof(buf)); + if (len < 5 || strncmp("want ", buf, 5)) + return nak("expected want"); + if (buf[len-1] == '\n') + buf[--len] = 0; + if (get_sha1(buf + 5, sha1)) + return nak("expected sha1"); + strcpy(hex, sha1_to_hex(sha1)); + + len = packet_read_line(0, buf, sizeof(buf)); + if (len) { + if (len < 5 || strncmp("base ", buf, 5)) + return nak("expected (optional) base"); + if (buf[len-1] == '\n') + buf[--len] = 0; + base = strdup(buf + 5); + len = packet_read_line(0, buf, sizeof(buf)); + } + if (len) + return nak("expected flush"); + + packet_write(1, "ACK\n"); + packet_flush(1); + + ac = 0; + av[ac++] = "tar-tree"; + av[ac++] = hex; + if (base) + av[ac++] = base; + av[ac++] = NULL; + execv_git_cmd(av); + /* should it return that is an error */ + return 1; +} diff --git a/builtin.h b/builtin.h index 34d5e6a7a9..c92e70221e 100644 --- a/builtin.h +++ b/builtin.h @@ -30,5 +30,7 @@ extern int cmd_add(int argc, const char **argv, char **envp); extern int cmd_rev_list(int argc, const char **argv, char **envp); extern int cmd_check_ref_format(int argc, const char **argv, char **envp); extern int cmd_init_db(int argc, const char **argv, char **envp); +extern int cmd_tar_tree(int argc, const char **argv, char **envp); +extern int cmd_upload_tar(int argc, const char **argv, char **envp); #endif diff --git a/git.c b/git.c index eab8c1f452..a5690e3ea8 100644 --- a/git.c +++ b/git.c @@ -55,6 +55,8 @@ static void handle_internal_command(int argc, const char **argv, char **envp) { "add", cmd_add }, { "rev-list", cmd_rev_list }, { "init-db", cmd_init_db }, + { "tar-tree", cmd_tar_tree }, + { "upload-tar", cmd_upload_tar }, { "check-ref-format", cmd_check_ref_format } }; int i;