#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 <key> [basedir]";
+static const char tar_tree_usage[] =
+"git-tar-tree [--remote=<repo>] <ent> [basedir]";
static char block[BLOCKSIZE];
static unsigned long offset;
static void traverse_tree(struct tree_desc *tree, struct strbuf *path)
{
int pathlen = path->len;
+ struct name_entry entry;
- while (tree->size) {
- const char *name;
- const unsigned char *sha1;
- unsigned mode;
+ while (tree_entry(tree, &entry)) {
void *eltbuf;
char elttype[20];
unsigned long eltsize;
- sha1 = tree_entry_extract(tree, &name, &mode);
- update_tree_entry(tree);
-
- eltbuf = read_sha1_file(sha1, elttype, &eltsize);
+ eltbuf = read_sha1_file(entry.sha1, elttype, &eltsize);
if (!eltbuf)
- die("cannot read %s", sha1_to_hex(sha1));
+ die("cannot read %s", sha1_to_hex(entry.sha1));
path->len = pathlen;
- strbuf_append_string(path, name);
- if (S_ISDIR(mode))
+ strbuf_append_string(path, entry.path);
+ if (S_ISDIR(entry.mode))
strbuf_append_string(path, "/");
- write_entry(sha1, path, mode, eltbuf, eltsize);
+ write_entry(entry.sha1, path, entry.mode, eltbuf, eltsize);
- if (S_ISDIR(mode)) {
+ if (S_ISDIR(entry.mode)) {
struct tree_desc subtree;
subtree.buf = eltbuf;
subtree.size = eltsize;
}
}
-int cmd_tar_tree(int argc, const char **argv, char** envp)
+static int generate_tar(int argc, const char **argv, char** envp)
{
unsigned char sha1[20], tree_sha1[20];
struct commit *commit;
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=<repo> */
+ 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, envp);
+}