]>
Commit | Line | Data |
---|---|---|
def88e9a LT |
1 | #include "cache.h" |
2 | #include "refs.h" | |
3 | #include "pkt-line.h" | |
4 | ||
5 | static const char upload_pack_usage[] = "git-upload-pack <dir>"; | |
6 | ||
fb9040cc | 7 | #define MAX_HAS (16) |
319aae27 | 8 | #define MAX_NEEDS (256) |
fb9040cc LT |
9 | static int nr_has = 0, nr_needs = 0; |
10 | static unsigned char has_sha1[MAX_HAS][20]; | |
11 | static unsigned char needs_sha1[MAX_NEEDS][20]; | |
12 | ||
75bfc6c2 LT |
13 | static int strip(char *line, int len) |
14 | { | |
15 | if (len && line[len-1] == '\n') | |
16 | line[--len] = 0; | |
17 | return len; | |
18 | } | |
19 | ||
fb9040cc LT |
20 | static void create_pack_file(void) |
21 | { | |
75bfc6c2 LT |
22 | int fd[2]; |
23 | pid_t pid; | |
24 | ||
25 | if (pipe(fd) < 0) | |
26 | die("git-upload-pack: unable to create pipe"); | |
27 | pid = fork(); | |
28 | if (pid < 0) | |
29 | die("git-upload-pack: unable to fork git-rev-list"); | |
30 | ||
31 | if (!pid) { | |
32 | int i; | |
33 | int args = nr_has + nr_needs + 5; | |
34 | char **argv = xmalloc(args * sizeof(char *)); | |
35 | char *buf = xmalloc(args * 45); | |
36 | char **p = argv; | |
37 | ||
38 | dup2(fd[1], 1); | |
39 | close(0); | |
40 | close(fd[0]); | |
41 | close(fd[1]); | |
42 | *p++ = "git-rev-list"; | |
43 | *p++ = "--objects"; | |
44 | for (i = 0; i < nr_needs; i++) { | |
45 | *p++ = buf; | |
46 | memcpy(buf, sha1_to_hex(needs_sha1[i]), 41); | |
47 | buf += 41; | |
48 | } | |
49 | for (i = 0; i < nr_has; i++) { | |
50 | *p++ = buf; | |
51 | *buf++ = '^'; | |
52 | memcpy(buf, sha1_to_hex(has_sha1[i]), 41); | |
53 | buf += 41; | |
54 | } | |
55 | *p++ = NULL; | |
56 | execvp("git-rev-list", argv); | |
57 | die("git-upload-pack: unable to exec git-rev-list"); | |
58 | } | |
59 | dup2(fd[0], 0); | |
60 | close(fd[0]); | |
61 | close(fd[1]); | |
62 | execlp("git-pack-objects", "git-pack-objects", "--stdout", NULL); | |
63 | die("git-upload-pack: unable to exec git-pack-objects"); | |
fb9040cc LT |
64 | } |
65 | ||
def88e9a LT |
66 | static int got_sha1(char *hex, unsigned char *sha1) |
67 | { | |
fb9040cc | 68 | int nr; |
def88e9a LT |
69 | if (get_sha1_hex(hex, sha1)) |
70 | die("git-upload-pack: expected SHA1 object, got '%s'", hex); | |
fb9040cc LT |
71 | if (!has_sha1_file(sha1)) |
72 | return 0; | |
73 | nr = nr_has; | |
74 | if (nr < MAX_HAS) { | |
75 | memcpy(has_sha1[nr], sha1, 20); | |
76 | nr_has = nr+1; | |
77 | } | |
78 | return 1; | |
def88e9a LT |
79 | } |
80 | ||
81 | static int get_common_commits(void) | |
82 | { | |
83 | static char line[1000]; | |
84 | unsigned char sha1[20]; | |
85 | int len; | |
86 | ||
87 | for(;;) { | |
88 | len = packet_read_line(0, line, sizeof(line)); | |
89 | ||
90 | if (!len) { | |
91 | packet_write(1, "NAK\n"); | |
92 | continue; | |
93 | } | |
75bfc6c2 | 94 | len = strip(line, len); |
def88e9a LT |
95 | if (!strncmp(line, "have ", 5)) { |
96 | if (got_sha1(line+5, sha1)) { | |
97 | packet_write(1, "ACK %s\n", sha1_to_hex(sha1)); | |
98 | break; | |
99 | } | |
100 | continue; | |
101 | } | |
102 | if (!strcmp(line, "done")) { | |
103 | packet_write(1, "NAK\n"); | |
104 | return -1; | |
105 | } | |
106 | die("git-upload-pack: expected SHA1 list, got '%s'", line); | |
107 | } | |
108 | ||
109 | for (;;) { | |
110 | len = packet_read_line(0, line, sizeof(line)); | |
111 | if (!len) | |
75bfc6c2 LT |
112 | continue; |
113 | len = strip(line, len); | |
def88e9a LT |
114 | if (!strncmp(line, "have ", 5)) { |
115 | got_sha1(line+5, sha1); | |
116 | continue; | |
117 | } | |
118 | if (!strcmp(line, "done")) | |
119 | break; | |
120 | die("git-upload-pack: expected SHA1 list, got '%s'", line); | |
121 | } | |
122 | return 0; | |
123 | } | |
124 | ||
fb9040cc LT |
125 | static int receive_needs(void) |
126 | { | |
127 | static char line[1000]; | |
128 | int len, needs; | |
129 | ||
130 | needs = 0; | |
131 | for (;;) { | |
132 | len = packet_read_line(0, line, sizeof(line)); | |
133 | if (!len) | |
134 | return needs; | |
135 | ||
136 | /* | |
137 | * This is purely theoretical right now: git-fetch-pack only | |
138 | * ever asks for a single HEAD | |
139 | */ | |
140 | if (needs >= MAX_NEEDS) | |
141 | die("I'm only doing a max of %d requests", MAX_NEEDS); | |
142 | if (strncmp("want ", line, 5) || get_sha1_hex(line+5, needs_sha1[needs])) | |
143 | die("git-upload-pack: protocol error, expected to get sha, not '%s'", line); | |
144 | needs++; | |
145 | } | |
146 | } | |
147 | ||
def88e9a LT |
148 | static int send_ref(const char *refname, const unsigned char *sha1) |
149 | { | |
150 | packet_write(1, "%s %s\n", sha1_to_hex(sha1), refname); | |
151 | return 0; | |
152 | } | |
153 | ||
154 | static int upload_pack(void) | |
155 | { | |
723c31fe | 156 | head_ref(send_ref); |
def88e9a LT |
157 | for_each_ref(send_ref); |
158 | packet_flush(1); | |
fb9040cc LT |
159 | nr_needs = receive_needs(); |
160 | if (!nr_needs) | |
161 | return 0; | |
def88e9a | 162 | get_common_commits(); |
fb9040cc | 163 | create_pack_file(); |
def88e9a LT |
164 | return 0; |
165 | } | |
166 | ||
167 | int main(int argc, char **argv) | |
168 | { | |
169 | const char *dir; | |
170 | if (argc != 2) | |
171 | usage(upload_pack_usage); | |
172 | dir = argv[1]; | |
113b9475 LT |
173 | |
174 | /* chdir to the directory. If that fails, try appending ".git" */ | |
175 | if (chdir(dir) < 0) { | |
176 | if (chdir(mkpath("%s.git", dir)) < 0) | |
177 | die("git-upload-pack unable to chdir to %s", dir); | |
178 | } | |
def88e9a LT |
179 | chdir(".git"); |
180 | if (access("objects", X_OK) || access("refs", X_OK)) | |
181 | die("git-upload-pack: %s doesn't seem to be a git archive", dir); | |
e72a7d45 | 182 | putenv("GIT_DIR=."); |
def88e9a LT |
183 | upload_pack(); |
184 | return 0; | |
185 | } |