]> asedeno.scripts.mit.edu Git - git.git/blob - receive-pack.c
send-pack --keep: do not explode into loose objects on the receiving end.
[git.git] / receive-pack.c
1 #include "cache.h"
2 #include "refs.h"
3 #include "pkt-line.h"
4 #include "run-command.h"
5 #include "commit.h"
6 #include "object.h"
7
8 static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
9
10 static const char *unpacker[] = { "unpack-objects", NULL };
11 static const char *keep_packer[] = {
12         "index-pack", "--stdin", "--fix-thin", NULL
13 };
14
15 static int report_status;
16 static int keep_pack;
17
18 static char capabilities[] = "report-status keep-pack";
19 static int capabilities_sent;
20
21 static int show_ref(const char *path, const unsigned char *sha1)
22 {
23         if (capabilities_sent)
24                 packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
25         else
26                 packet_write(1, "%s %s%c%s\n",
27                              sha1_to_hex(sha1), path, 0, capabilities);
28         capabilities_sent = 1;
29         return 0;
30 }
31
32 static void write_head_info(void)
33 {
34         for_each_ref(show_ref);
35         if (!capabilities_sent)
36                 show_ref("capabilities^{}", null_sha1);
37
38 }
39
40 struct command {
41         struct command *next;
42         const char *error_string;
43         unsigned char old_sha1[20];
44         unsigned char new_sha1[20];
45         char ref_name[FLEX_ARRAY]; /* more */
46 };
47
48 static struct command *commands;
49
50 static int is_all_zeroes(const char *hex)
51 {
52         int i;
53         for (i = 0; i < 40; i++)
54                 if (*hex++ != '0')
55                         return 0;
56         return 1;
57 }
58
59 static int verify_old_ref(const char *name, char *hex_contents)
60 {
61         int fd, ret;
62         char buffer[60];
63
64         if (is_all_zeroes(hex_contents))
65                 return 0;
66         fd = open(name, O_RDONLY);
67         if (fd < 0)
68                 return -1;
69         ret = read(fd, buffer, 40);
70         close(fd);
71         if (ret != 40)
72                 return -1;
73         if (memcmp(buffer, hex_contents, 40))
74                 return -1;
75         return 0;
76 }
77
78 static char update_hook[] = "hooks/update";
79
80 static int run_update_hook(const char *refname,
81                            char *old_hex, char *new_hex)
82 {
83         int code;
84
85         if (access(update_hook, X_OK) < 0)
86                 return 0;
87         code = run_command(update_hook, refname, old_hex, new_hex, NULL);
88         switch (code) {
89         case 0:
90                 return 0;
91         case -ERR_RUN_COMMAND_FORK:
92                 return error("hook fork failed");
93         case -ERR_RUN_COMMAND_EXEC:
94                 return error("hook execute failed");
95         case -ERR_RUN_COMMAND_WAITPID:
96                 return error("waitpid failed");
97         case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
98                 return error("waitpid is confused");
99         case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
100                 return error("%s died of signal", update_hook);
101         case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
102                 return error("%s died strangely", update_hook);
103         default:
104                 error("%s exited with error code %d", update_hook, -code);
105                 return -code;
106         }
107 }
108
109 static int update(struct command *cmd)
110 {
111         const char *name = cmd->ref_name;
112         unsigned char *old_sha1 = cmd->old_sha1;
113         unsigned char *new_sha1 = cmd->new_sha1;
114         char new_hex[60], *old_hex, *lock_name;
115         int newfd, namelen, written;
116
117         cmd->error_string = NULL;
118         if (!strncmp(name, "refs/", 5) && check_ref_format(name + 5)) {
119                 cmd->error_string = "funny refname";
120                 return error("refusing to create funny ref '%s' locally",
121                              name);
122         }
123
124         namelen = strlen(name);
125         lock_name = xmalloc(namelen + 10);
126         memcpy(lock_name, name, namelen);
127         memcpy(lock_name + namelen, ".lock", 6);
128
129         strcpy(new_hex, sha1_to_hex(new_sha1));
130         old_hex = sha1_to_hex(old_sha1);
131         if (!has_sha1_file(new_sha1)) {
132                 cmd->error_string = "bad pack";
133                 return error("unpack should have generated %s, "
134                              "but I can't find it!", new_hex);
135         }
136         if (deny_non_fast_forwards && !is_null_sha1(old_sha1)) {
137                 struct commit *old_commit, *new_commit;
138                 struct commit_list *bases, *ent;
139
140                 old_commit = (struct commit *)parse_object(old_sha1);
141                 new_commit = (struct commit *)parse_object(new_sha1);
142                 bases = get_merge_bases(old_commit, new_commit, 1);
143                 for (ent = bases; ent; ent = ent->next)
144                         if (!hashcmp(old_sha1, ent->item->object.sha1))
145                                 break;
146                 free_commit_list(bases);
147                 if (!ent)
148                         return error("denying non-fast forward;"
149                                      " you should pull first");
150         }
151         safe_create_leading_directories(lock_name);
152
153         newfd = open(lock_name, O_CREAT | O_EXCL | O_WRONLY, 0666);
154         if (newfd < 0) {
155                 cmd->error_string = "can't lock";
156                 return error("unable to create %s (%s)",
157                              lock_name, strerror(errno));
158         }
159
160         /* Write the ref with an ending '\n' */
161         new_hex[40] = '\n';
162         new_hex[41] = 0;
163         written = write(newfd, new_hex, 41);
164         /* Remove the '\n' again */
165         new_hex[40] = 0;
166
167         close(newfd);
168         if (written != 41) {
169                 unlink(lock_name);
170                 cmd->error_string = "can't write";
171                 return error("unable to write %s", lock_name);
172         }
173         if (verify_old_ref(name, old_hex) < 0) {
174                 unlink(lock_name);
175                 cmd->error_string = "raced";
176                 return error("%s changed during push", name);
177         }
178         if (run_update_hook(name, old_hex, new_hex)) {
179                 unlink(lock_name);
180                 cmd->error_string = "hook declined";
181                 return error("hook declined to update %s", name);
182         }
183         else if (rename(lock_name, name) < 0) {
184                 unlink(lock_name);
185                 cmd->error_string = "can't rename";
186                 return error("unable to replace %s", name);
187         }
188         else {
189                 fprintf(stderr, "%s: %s -> %s\n", name, old_hex, new_hex);
190                 return 0;
191         }
192 }
193
194 static char update_post_hook[] = "hooks/post-update";
195
196 static void run_update_post_hook(struct command *cmd)
197 {
198         struct command *cmd_p;
199         int argc;
200         const char **argv;
201
202         if (access(update_post_hook, X_OK) < 0)
203                 return;
204         for (argc = 1, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
205                 if (cmd_p->error_string)
206                         continue;
207                 argc++;
208         }
209         argv = xmalloc(sizeof(*argv) * (1 + argc));
210         argv[0] = update_post_hook;
211
212         for (argc = 1, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
213                 char *p;
214                 if (cmd_p->error_string)
215                         continue;
216                 p = xmalloc(strlen(cmd_p->ref_name) + 1);
217                 strcpy(p, cmd_p->ref_name);
218                 argv[argc] = p;
219                 argc++;
220         }
221         argv[argc] = NULL;
222         run_command_v_opt(argc, argv, RUN_COMMAND_NO_STDIO);
223 }
224
225 /*
226  * This gets called after(if) we've successfully
227  * unpacked the data payload.
228  */
229 static void execute_commands(void)
230 {
231         struct command *cmd = commands;
232
233         while (cmd) {
234                 update(cmd);
235                 cmd = cmd->next;
236         }
237         run_update_post_hook(commands);
238 }
239
240 static void read_head_info(void)
241 {
242         struct command **p = &commands;
243         for (;;) {
244                 static char line[1000];
245                 unsigned char old_sha1[20], new_sha1[20];
246                 struct command *cmd;
247                 char *refname;
248                 int len, reflen;
249
250                 len = packet_read_line(0, line, sizeof(line));
251                 if (!len)
252                         break;
253                 if (line[len-1] == '\n')
254                         line[--len] = 0;
255                 if (len < 83 ||
256                     line[40] != ' ' ||
257                     line[81] != ' ' ||
258                     get_sha1_hex(line, old_sha1) ||
259                     get_sha1_hex(line + 41, new_sha1))
260                         die("protocol error: expected old/new/ref, got '%s'",
261                             line);
262
263                 refname = line + 82;
264                 reflen = strlen(refname);
265                 if (reflen + 82 < len) {
266                         if (strstr(refname + reflen + 1, "report-status"))
267                                 report_status = 1;
268                         if (strstr(refname + reflen + 1, "keep-pack"))
269                                 keep_pack = 1;
270                 }
271                 cmd = xmalloc(sizeof(struct command) + len - 80);
272                 hashcpy(cmd->old_sha1, old_sha1);
273                 hashcpy(cmd->new_sha1, new_sha1);
274                 memcpy(cmd->ref_name, line + 82, len - 81);
275                 cmd->error_string = "n/a (unpacker error)";
276                 cmd->next = NULL;
277                 *p = cmd;
278                 p = &cmd->next;
279         }
280 }
281
282 static const char *unpack(int *error_code)
283 {
284         int code;
285
286         if (keep_pack)
287                 code = run_command_v_opt(ARRAY_SIZE(keep_packer) - 1,
288                                          keep_packer, RUN_GIT_CMD);
289         else
290                 code = run_command_v_opt(ARRAY_SIZE(unpacker) - 1,
291                                          unpacker, RUN_GIT_CMD);
292
293         *error_code = 0;
294         switch (code) {
295         case 0:
296                 return NULL;
297         case -ERR_RUN_COMMAND_FORK:
298                 return "unpack fork failed";
299         case -ERR_RUN_COMMAND_EXEC:
300                 return "unpack execute failed";
301         case -ERR_RUN_COMMAND_WAITPID:
302                 return "waitpid failed";
303         case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
304                 return "waitpid is confused";
305         case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
306                 return "unpacker died of signal";
307         case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
308                 return "unpacker died strangely";
309         default:
310                 *error_code = -code;
311                 return "unpacker exited with error code";
312         }
313 }
314
315 static void report(const char *unpack_status)
316 {
317         struct command *cmd;
318         packet_write(1, "unpack %s\n",
319                      unpack_status ? unpack_status : "ok");
320         for (cmd = commands; cmd; cmd = cmd->next) {
321                 if (!cmd->error_string)
322                         packet_write(1, "ok %s\n",
323                                      cmd->ref_name);
324                 else
325                         packet_write(1, "ng %s %s\n",
326                                      cmd->ref_name, cmd->error_string);
327         }
328         packet_flush(1);
329 }
330
331 int main(int argc, char **argv)
332 {
333         int i;
334         char *dir = NULL;
335
336         argv++;
337         for (i = 1; i < argc; i++) {
338                 char *arg = *argv++;
339
340                 if (*arg == '-') {
341                         /* Do flag handling here */
342                         usage(receive_pack_usage);
343                 }
344                 if (dir)
345                         usage(receive_pack_usage);
346                 dir = arg;
347         }
348         if (!dir)
349                 usage(receive_pack_usage);
350
351         if (!enter_repo(dir, 0))
352                 die("'%s': unable to chdir or not a git archive", dir);
353
354         write_head_info();
355
356         /* EOF */
357         packet_flush(1);
358
359         read_head_info();
360         if (commands) {
361                 int code;
362                 const char *unpack_status = unpack(&code);
363                 if (!unpack_status)
364                         execute_commands();
365                 if (report_status)
366                         report(unpack_status);
367         }
368         return 0;
369 }