]> git.ipfire.org Git - thirdparty/git.git/blame - upload-pack.c
Make git-fetch-pack and git-upload-pack negotiate needs/haves fully
[thirdparty/git.git] / upload-pack.c
CommitLineData
def88e9a
LT
1#include "cache.h"
2#include "refs.h"
3#include "pkt-line.h"
4
5static const char upload_pack_usage[] = "git-upload-pack <dir>";
6
fb9040cc
LT
7#define MAX_HAS (16)
8#define MAX_NEEDS (16)
9static int nr_has = 0, nr_needs = 0;
10static unsigned char has_sha1[MAX_HAS][20];
11static unsigned char needs_sha1[MAX_NEEDS][20];
12
13static void create_pack_file(void)
14{
15 /*
16 * Here, we should do
17 *
18 * git-rev-list --objects needs_sha1 --not has_sha1 |
19 * git-pack-objects --stdout
20 *
21 * but we don't.
22 */
23}
24
def88e9a
LT
25static int got_sha1(char *hex, unsigned char *sha1)
26{
fb9040cc 27 int nr;
def88e9a
LT
28 if (get_sha1_hex(hex, sha1))
29 die("git-upload-pack: expected SHA1 object, got '%s'", hex);
fb9040cc
LT
30 if (!has_sha1_file(sha1))
31 return 0;
32 nr = nr_has;
33 if (nr < MAX_HAS) {
34 memcpy(has_sha1[nr], sha1, 20);
35 nr_has = nr+1;
36 }
37 return 1;
def88e9a
LT
38}
39
40static int get_common_commits(void)
41{
42 static char line[1000];
43 unsigned char sha1[20];
44 int len;
45
46 for(;;) {
47 len = packet_read_line(0, line, sizeof(line));
48
49 if (!len) {
50 packet_write(1, "NAK\n");
51 continue;
52 }
53 if (line[len-1] == '\n')
54 line[--len] = 0;
55 if (!strncmp(line, "have ", 5)) {
56 if (got_sha1(line+5, sha1)) {
57 packet_write(1, "ACK %s\n", sha1_to_hex(sha1));
58 break;
59 }
60 continue;
61 }
62 if (!strcmp(line, "done")) {
63 packet_write(1, "NAK\n");
64 return -1;
65 }
66 die("git-upload-pack: expected SHA1 list, got '%s'", line);
67 }
68
69 for (;;) {
70 len = packet_read_line(0, line, sizeof(line));
71 if (!len)
72 break;
73 if (!strncmp(line, "have ", 5)) {
74 got_sha1(line+5, sha1);
75 continue;
76 }
77 if (!strcmp(line, "done"))
78 break;
79 die("git-upload-pack: expected SHA1 list, got '%s'", line);
80 }
81 return 0;
82}
83
fb9040cc
LT
84static int receive_needs(void)
85{
86 static char line[1000];
87 int len, needs;
88
89 needs = 0;
90 for (;;) {
91 len = packet_read_line(0, line, sizeof(line));
92 if (!len)
93 return needs;
94
95 /*
96 * This is purely theoretical right now: git-fetch-pack only
97 * ever asks for a single HEAD
98 */
99 if (needs >= MAX_NEEDS)
100 die("I'm only doing a max of %d requests", MAX_NEEDS);
101 if (strncmp("want ", line, 5) || get_sha1_hex(line+5, needs_sha1[needs]))
102 die("git-upload-pack: protocol error, expected to get sha, not '%s'", line);
103 needs++;
104 }
105}
106
def88e9a
LT
107static int send_ref(const char *refname, const unsigned char *sha1)
108{
109 packet_write(1, "%s %s\n", sha1_to_hex(sha1), refname);
110 return 0;
111}
112
113static int upload_pack(void)
114{
115 for_each_ref(send_ref);
116 packet_flush(1);
fb9040cc
LT
117 nr_needs = receive_needs();
118 if (!nr_needs)
119 return 0;
def88e9a 120 get_common_commits();
fb9040cc 121 create_pack_file();
def88e9a
LT
122 return 0;
123}
124
125int main(int argc, char **argv)
126{
127 const char *dir;
128 if (argc != 2)
129 usage(upload_pack_usage);
130 dir = argv[1];
131 if (chdir(dir))
132 die("git-upload-pack unable to chdir to %s", dir);
133 chdir(".git");
134 if (access("objects", X_OK) || access("refs", X_OK))
135 die("git-upload-pack: %s doesn't seem to be a git archive", dir);
136 setenv("GIT_DIR", ".", 1);
137 upload_pack();
138 return 0;
139}