X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=upload-pack.c;h=83f5a35d2686401e9a70d7aafae07c88c7b6e936;hb=ab1630a3ed31d6ec5ae83769c78ed542fe3c4a28;hp=b454c9e11dbea4d023ec724252e14b4984bfba9b;hpb=fb9040cc83540fff9d05c8056433a4aa05b8a7c2;p=git.git diff --git a/upload-pack.c b/upload-pack.c index b454c9e1..83f5a35d 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -5,21 +5,74 @@ static const char upload_pack_usage[] = "git-upload-pack "; #define MAX_HAS (16) -#define MAX_NEEDS (16) +#define MAX_NEEDS (256) static int nr_has = 0, nr_needs = 0; static unsigned char has_sha1[MAX_HAS][20]; static unsigned char needs_sha1[MAX_NEEDS][20]; +static int strip(char *line, int len) +{ + if (len && line[len-1] == '\n') + line[--len] = 0; + return len; +} + static void create_pack_file(void) { - /* - * Here, we should do - * - * git-rev-list --objects needs_sha1 --not has_sha1 | - * git-pack-objects --stdout - * - * but we don't. - */ + int fd[2]; + pid_t pid; + + if (pipe(fd) < 0) + die("git-upload-pack: unable to create pipe"); + pid = fork(); + if (pid < 0) + die("git-upload-pack: unable to fork git-rev-list"); + + if (!pid) { + int i; + int args; + char **argv; + char *buf; + char **p; + + if (MAX_NEEDS <= nr_needs) + args = nr_has + 10; + else + args = nr_has + nr_needs + 5; + argv = xmalloc(args * sizeof(char *)); + buf = xmalloc(args * 45); + p = argv; + + dup2(fd[1], 1); + close(0); + close(fd[0]); + close(fd[1]); + *p++ = "git-rev-list"; + *p++ = "--objects"; + if (MAX_NEEDS <= nr_needs) + *p++ = "--all"; + else { + for (i = 0; i < nr_needs; i++) { + *p++ = buf; + memcpy(buf, sha1_to_hex(needs_sha1[i]), 41); + buf += 41; + } + } + for (i = 0; i < nr_has; i++) { + *p++ = buf; + *buf++ = '^'; + memcpy(buf, sha1_to_hex(has_sha1[i]), 41); + buf += 41; + } + *p++ = NULL; + execvp("git-rev-list", argv); + die("git-upload-pack: unable to exec git-rev-list"); + } + dup2(fd[0], 0); + close(fd[0]); + close(fd[1]); + execlp("git-pack-objects", "git-pack-objects", "--stdout", NULL); + die("git-upload-pack: unable to exec git-pack-objects"); } static int got_sha1(char *hex, unsigned char *sha1) @@ -50,8 +103,7 @@ static int get_common_commits(void) packet_write(1, "NAK\n"); continue; } - if (line[len-1] == '\n') - line[--len] = 0; + len = strip(line, len); if (!strncmp(line, "have ", 5)) { if (got_sha1(line+5, sha1)) { packet_write(1, "ACK %s\n", sha1_to_hex(sha1)); @@ -69,7 +121,8 @@ static int get_common_commits(void) for (;;) { len = packet_read_line(0, line, sizeof(line)); if (!len) - break; + continue; + len = strip(line, len); if (!strncmp(line, "have ", 5)) { got_sha1(line+5, sha1); continue; @@ -88,18 +141,24 @@ static int receive_needs(void) needs = 0; for (;;) { + unsigned char dummy[20], *sha1_buf; len = packet_read_line(0, line, sizeof(line)); if (!len) return needs; - /* - * This is purely theoretical right now: git-fetch-pack only - * ever asks for a single HEAD - */ - if (needs >= MAX_NEEDS) - die("I'm only doing a max of %d requests", MAX_NEEDS); - if (strncmp("want ", line, 5) || get_sha1_hex(line+5, needs_sha1[needs])) - die("git-upload-pack: protocol error, expected to get sha, not '%s'", line); + sha1_buf = dummy; + if (needs == MAX_NEEDS) { + fprintf(stderr, + "warning: supporting only a max of %d requests. " + "sending everything instead.\n", + MAX_NEEDS); + } + else if (needs < MAX_NEEDS) + sha1_buf = needs_sha1[needs]; + + if (strncmp("want ", line, 5) || get_sha1_hex(line+5, sha1_buf)) + die("git-upload-pack: protocol error, " + "expected to get sha, not '%s'", line); needs++; } } @@ -112,6 +171,7 @@ static int send_ref(const char *refname, const unsigned char *sha1) static int upload_pack(void) { + head_ref(send_ref); for_each_ref(send_ref); packet_flush(1); nr_needs = receive_needs(); @@ -128,12 +188,16 @@ int main(int argc, char **argv) if (argc != 2) usage(upload_pack_usage); dir = argv[1]; - if (chdir(dir)) - die("git-upload-pack unable to chdir to %s", dir); + + /* chdir to the directory. If that fails, try appending ".git" */ + if (chdir(dir) < 0) { + if (chdir(mkpath("%s.git", dir)) < 0) + die("git-upload-pack unable to chdir to %s", dir); + } chdir(".git"); if (access("objects", X_OK) || access("refs", X_OK)) die("git-upload-pack: %s doesn't seem to be a git archive", dir); - setenv("GIT_DIR", ".", 1); + putenv("GIT_DIR=."); upload_pack(); return 0; }