Add support for "forcing" a ref on the remote side
[git.git] / receive-pack.c
1 #include "cache.h"
2 #include "pkt-line.h"
3 #include <sys/wait.h>
4
5 static const char receive_pack_usage[] = "git-receive-pack [--unpack=executable] <git-dir> [heads]";
6
7 static const char *unpacker = "git-unpack-objects";
8
9 static int path_match(const char *path, int nr, char **match)
10 {
11         int i;
12         int pathlen = strlen(path);
13
14         for (i = 0; i < nr; i++) {
15                 char *s = match[i];
16                 int len = strlen(s);
17
18                 if (!len || len > pathlen)
19                         continue;
20                 if (memcmp(path + pathlen - len, s, len))
21                         continue;
22                 if (pathlen > len && path[pathlen - len - 1] != '/')
23                         continue;
24                 *s = 0;
25                 return 1;
26         }
27         return 0;
28 }
29
30 static void show_ref(const char *path, unsigned char *sha1)
31 {
32         packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
33 }
34
35 static int read_ref(const char *path, unsigned char *sha1)
36 {
37         int ret = -1;
38         int fd = open(path, O_RDONLY);
39
40         if (fd >= 0) {
41                 char buffer[60];
42                 if (read(fd, buffer, sizeof(buffer)) >= 40)
43                         ret = get_sha1_hex(buffer, sha1);
44                 close(fd);
45         }
46         return ret;
47 }
48
49 static void write_head_info(const char *base, int nr, char **match)
50 {
51         DIR *dir = opendir(base);
52
53         if (dir) {
54                 struct dirent *de;
55                 int baselen = strlen(base);
56                 char *path = xmalloc(baselen + 257);
57                 memcpy(path, base, baselen);
58
59                 while ((de = readdir(dir)) != NULL) {
60                         char sha1[20];
61                         struct stat st;
62                         int namelen;
63
64                         if (de->d_name[0] == '.')
65                                 continue;
66                         namelen = strlen(de->d_name);
67                         if (namelen > 255)
68                                 continue;
69                         memcpy(path + baselen, de->d_name, namelen+1);
70                         if (lstat(path, &st) < 0)
71                                 continue;
72                         if (S_ISDIR(st.st_mode)) {
73                                 path[baselen + namelen] = '/';
74                                 path[baselen + namelen + 1] = 0;
75                                 write_head_info(path, nr, match);
76                                 continue;
77                         }
78                         if (read_ref(path, sha1) < 0)
79                                 continue;
80                         if (!has_sha1_file(sha1))
81                                 continue;
82                         if (nr && !path_match(path, nr, match))
83                                 continue;
84                         show_ref(path, sha1);
85                 }
86                 free(path);
87                 closedir(dir);
88         }
89 }
90
91 struct command {
92         struct command *next;
93         unsigned char old_sha1[20];
94         unsigned char new_sha1[20];
95         char ref_name[0];
96 };
97
98 struct command *commands = NULL;
99
100 static int is_all_zeroes(const char *hex)
101 {
102         int i;
103         for (i = 0; i < 40; i++)
104                 if (*hex++ != '0')
105                         return 0;
106         return 1;
107 }
108
109 static int verify_old_ref(const char *name, char *hex_contents)
110 {
111         int fd, ret;
112         char buffer[60];
113
114         if (is_all_zeroes(hex_contents))
115                 return 0;
116         fd = open(name, O_RDONLY);
117         if (fd < 0)
118                 return -1;
119         ret = read(fd, buffer, 40);
120         close(fd);
121         if (ret != 40)
122                 return -1;
123         if (memcmp(buffer, hex_contents, 40))
124                 return -1;
125         return 0;
126 }
127
128 static void update(const char *name, unsigned char *old_sha1, unsigned char *new_sha1)
129 {
130         char new_hex[60], *old_hex, *lock_name;
131         int newfd, namelen, written;
132
133         namelen = strlen(name);
134         lock_name = xmalloc(namelen + 10);
135         memcpy(lock_name, name, namelen);
136         memcpy(lock_name + namelen, ".lock", 6);
137
138         strcpy(new_hex, sha1_to_hex(new_sha1));
139         old_hex = sha1_to_hex(old_sha1);
140         if (!has_sha1_file(new_sha1))
141                 die("unpack should have generated %s, but I can't find it!", new_hex);
142
143         newfd = open(lock_name, O_CREAT | O_EXCL | O_WRONLY, 0644);
144         if (newfd < 0)
145                 die("unable to create %s (%s)", lock_name, strerror(errno));
146
147         /* Write the ref with an ending '\n' */
148         new_hex[40] = '\n';
149         new_hex[41] = 0;
150         written = write(newfd, new_hex, 41);
151         /* Remove the '\n' again */
152         new_hex[40] = 0;
153
154         close(newfd);
155         if (written != 41) {
156                 unlink(lock_name);
157                 die("unable to write %s", lock_name);
158         }
159         if (verify_old_ref(name, old_hex) < 0) {
160                 unlink(lock_name);
161                 die("%s changed during push", name);
162         }
163         if (rename(lock_name, name) < 0) {
164                 unlink(lock_name);
165                 die("unable to replace %s", name);
166         }
167         fprintf(stderr, "%s: %s -> %s\n", name, old_hex, new_hex);
168 }
169
170
171 /*
172  * This gets called after(if) we've successfully
173  * unpacked the data payload.
174  */
175 static void execute_commands(void)
176 {
177         struct command *cmd = commands;
178
179         while (cmd) {
180                 update(cmd->ref_name, cmd->old_sha1, cmd->new_sha1);
181                 cmd = cmd->next;
182         }
183 }
184
185 static void read_head_info(void)
186 {
187         struct command **p = &commands;
188         for (;;) {
189                 static char line[1000];
190                 unsigned char old_sha1[20], new_sha1[20];
191                 struct command *cmd;
192                 int len;
193
194                 len = packet_read_line(0, line, sizeof(line));
195                 if (!len)
196                         break;
197                 if (line[len-1] == '\n')
198                         line[--len] = 0;
199                 if (len < 83 ||
200                     line[40] != ' ' ||
201                     line[81] != ' ' ||
202                     get_sha1_hex(line, old_sha1) ||
203                     get_sha1_hex(line + 41, new_sha1))
204                         die("protocol error: expected old/new/ref, got '%s'", line);
205                 cmd = xmalloc(sizeof(struct command) + len - 80);
206                 memcpy(cmd->old_sha1, old_sha1, 20);
207                 memcpy(cmd->new_sha1, new_sha1, 20);
208                 memcpy(cmd->ref_name, line + 82, len - 81);
209                 cmd->next = NULL;
210                 *p = cmd;
211                 p = &cmd->next;
212         }
213 }
214
215 static void unpack(void)
216 {
217         pid_t pid = fork();
218
219         if (pid < 0)
220                 die("unpack fork failed");
221         if (!pid) {
222                 execlp(unpacker, unpacker, NULL);
223                 die("unpack execute failed");
224         }
225
226         for (;;) {
227                 int status, code;
228                 int retval = waitpid(pid, &status, 0);
229
230                 if (retval < 0) {
231                         if (errno == EINTR)
232                                 continue;
233                         die("waitpid failed (%s)", strerror(retval));
234                 }
235                 if (retval != pid)
236                         die("waitpid is confused");
237                 if (WIFSIGNALED(status))
238                         die("%s died of signal %d", unpacker, WTERMSIG(status));
239                 if (!WIFEXITED(status))
240                         die("%s died out of really strange complications", unpacker);
241                 code = WEXITSTATUS(status);
242                 if (code)
243                         die("%s exited with error code %d", unpacker, code);
244                 return;
245         }
246 }
247
248 int main(int argc, char **argv)
249 {
250         int i, nr_heads = 0;
251         const char *dir = NULL;
252         char **heads = NULL;
253
254         argv++;
255         for (i = 1; i < argc; i++) {
256                 const char *arg = *argv++;
257
258                 if (*arg == '-') {
259                         if (!strncmp(arg, "--unpack=", 9)) {
260                                 unpacker = arg+9;
261                                 continue;
262                         }
263                         /* Do flag handling here */
264                         usage(receive_pack_usage);
265                 }
266                 dir = arg;
267                 heads = argv;
268                 nr_heads = argc - i - 1;
269                 break;
270         }
271         if (!dir)
272                 usage(receive_pack_usage);
273
274         /* chdir to the directory. If that fails, try appending ".git" */
275         if (chdir(dir) < 0) {
276                 static char path[PATH_MAX];
277                 snprintf(path, sizeof(path), "%s.git", dir);
278                 if (chdir(path) < 0)
279                         die("unable to cd to %s", dir);
280         }
281
282         /* If we have a ".git" directory, chdir to it */
283         chdir(".git");
284         setenv("GIT_DIR", ".", 1);
285
286         if (access("objects", X_OK) < 0 || access("refs/heads", X_OK) < 0)
287                 die("%s doesn't appear to be a git directory", dir);
288         write_head_info("refs/", nr_heads, heads);
289
290         /* EOF */
291         packet_flush(1);
292
293         read_head_info();
294         if (commands) {
295                 unpack();
296                 execute_commands();
297         }
298         return 0;
299 }