+static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=nn] <dir>";
+
+#define THEY_HAVE (1U << 0)
+#define OUR_REF (1U << 1)
+#define WANTED (1U << 2)
+#define MAX_HAS 256
+#define MAX_NEEDS 256
+static int nr_has = 0, nr_needs = 0, multi_ack = 0, nr_our_refs = 0;
+static unsigned char has_sha1[MAX_HAS][20];
+static unsigned char needs_sha1[MAX_NEEDS][20];
+static unsigned int timeout = 0;
+
+static void reset_timeout(void)
+{
+ alarm(timeout);
+}
+
+static int strip(char *line, int len)
+{
+ if (len && line[len-1] == '\n')
+ line[--len] = 0;
+ return len;
+}
+
+static void create_pack_file(void)
+{
+ int fd[2];
+ pid_t pid;
+ int create_full_pack = (nr_our_refs == nr_needs && !nr_has);
+
+ 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 (create_full_pack)
+ args = 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++ = "rev-list";
+ *p++ = "--objects";
+ if (create_full_pack || 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;
+ }
+ }
+ if (!create_full_pack)
+ for (i = 0; i < nr_has; i++) {
+ *p++ = buf;
+ *buf++ = '^';
+ memcpy(buf, sha1_to_hex(has_sha1[i]), 41);
+ buf += 41;
+ }
+ *p++ = NULL;
+ execv_git_cmd(argv);
+ die("git-upload-pack: unable to exec git-rev-list");
+ }
+ dup2(fd[0], 0);
+ close(fd[0]);
+ close(fd[1]);
+ execl_git_cmd("pack-objects", "--stdout", NULL);
+ die("git-upload-pack: unable to exec git-pack-objects");
+}