]>
Commit | Line | Data |
---|---|---|
61221472 | 1 | #include "cache.h" |
f3a3214e | 2 | #include "pkt-line.h" |
61221472 LT |
3 | |
4 | static const char send_pack_usage[] = "git-send-pack [--exec=other] destination [heads]*"; | |
61221472 LT |
5 | static const char *exec = "git-receive-pack"; |
6 | ||
e4b5c7ff LT |
7 | struct ref { |
8 | struct ref *next; | |
9 | unsigned char old_sha1[20]; | |
10 | unsigned char new_sha1[20]; | |
11 | char name[0]; | |
12 | }; | |
13 | ||
94fdb7aa LT |
14 | static void exec_pack_objects(void) |
15 | { | |
16 | static char *args[] = { | |
17 | "git-pack-objects", | |
18 | "--stdout", | |
19 | NULL | |
20 | }; | |
21 | execvp("git-pack-objects", args); | |
22 | die("git-pack-objects exec failed (%s)", strerror(errno)); | |
23 | } | |
24 | ||
25 | static void exec_rev_list(struct ref *refs) | |
26 | { | |
27 | static char *args[1000]; | |
28 | int i = 0; | |
29 | ||
30 | args[i++] = "git-rev-list"; /* 0 */ | |
31 | args[i++] = "--objects"; /* 1 */ | |
32 | while (refs) { | |
33 | char *buf = malloc(100); | |
34 | if (i > 900) | |
35 | die("git-rev-list environment overflow"); | |
36 | args[i++] = buf; | |
37 | snprintf(buf, 50, "^%s", sha1_to_hex(refs->old_sha1)); | |
38 | buf += 50; | |
39 | args[i++] = buf; | |
40 | snprintf(buf, 50, "%s", sha1_to_hex(refs->new_sha1)); | |
41 | refs = refs->next; | |
42 | } | |
43 | args[i] = NULL; | |
44 | execvp("git-rev-list", args); | |
45 | die("git-rev-list exec failed (%s)", strerror(errno)); | |
46 | } | |
47 | ||
48 | static void rev_list(int fd, struct ref *refs) | |
49 | { | |
50 | int pipe_fd[2]; | |
51 | pid_t pack_objects_pid; | |
52 | ||
53 | if (pipe(pipe_fd) < 0) | |
54 | die("rev-list setup: pipe failed"); | |
55 | pack_objects_pid = fork(); | |
56 | if (!pack_objects_pid) { | |
57 | dup2(pipe_fd[0], 0); | |
58 | dup2(fd, 1); | |
59 | close(pipe_fd[0]); | |
60 | close(pipe_fd[1]); | |
61 | close(fd); | |
62 | exec_pack_objects(); | |
63 | die("pack-objects setup failed"); | |
64 | } | |
65 | if (pack_objects_pid < 0) | |
66 | die("pack-objects fork failed"); | |
67 | dup2(pipe_fd[1], 1); | |
68 | close(pipe_fd[0]); | |
69 | close(pipe_fd[1]); | |
70 | close(fd); | |
71 | exec_rev_list(refs); | |
72 | } | |
73 | ||
74 | static int pack_objects(int fd, struct ref *refs) | |
75 | { | |
76 | pid_t rev_list_pid; | |
77 | ||
78 | rev_list_pid = fork(); | |
79 | if (!rev_list_pid) { | |
80 | rev_list(fd, refs); | |
81 | die("rev-list setup failed"); | |
82 | } | |
83 | if (rev_list_pid < 0) | |
84 | die("rev-list fork failed"); | |
85 | /* | |
86 | * We don't wait for the rev-list pipeline in the parent: | |
87 | * we end up waiting for the other end instead | |
88 | */ | |
7ec4e608 | 89 | return 0; |
94fdb7aa | 90 | } |
e4b5c7ff LT |
91 | |
92 | static int read_ref(const char *ref, unsigned char *sha1) | |
93 | { | |
94 | int fd, ret; | |
e4b5c7ff | 95 | char buffer[60]; |
e4b5c7ff | 96 | |
723c31fe | 97 | fd = open(git_path("%s", ref), O_RDONLY); |
e4b5c7ff LT |
98 | if (fd < 0) |
99 | return -1; | |
100 | ret = -1; | |
101 | if (read(fd, buffer, sizeof(buffer)) >= 40) | |
102 | ret = get_sha1_hex(buffer, sha1); | |
103 | close(fd); | |
104 | return ret; | |
105 | } | |
106 | ||
d0efc8a7 | 107 | static int send_pack(int in, int out, int nr_match, char **match) |
61221472 | 108 | { |
94fdb7aa | 109 | struct ref *ref_list = NULL, **last_ref = &ref_list; |
7f8e9828 LT |
110 | struct ref *ref; |
111 | ||
61221472 | 112 | for (;;) { |
e4b5c7ff LT |
113 | unsigned char old_sha1[20]; |
114 | unsigned char new_sha1[20]; | |
61221472 | 115 | static char buffer[1000]; |
e4b5c7ff | 116 | char *name; |
f3a3214e LT |
117 | int len; |
118 | ||
119 | len = packet_read_line(in, buffer, sizeof(buffer)); | |
e4b5c7ff LT |
120 | if (!len) |
121 | break; | |
122 | if (buffer[len-1] == '\n') | |
123 | buffer[--len] = 0; | |
124 | ||
125 | if (len < 42 || get_sha1_hex(buffer, old_sha1) || buffer[40] != ' ') | |
126 | die("protocol error: expected sha/ref, got '%s'", buffer); | |
127 | name = buffer + 41; | |
d0efc8a7 LT |
128 | if (nr_match && !path_match(name, nr_match, match)) |
129 | continue; | |
7f8e9828 LT |
130 | if (read_ref(name, new_sha1) < 0) |
131 | return error("no such local reference '%s'", name); | |
132 | if (!has_sha1_file(old_sha1)) | |
133 | return error("remote '%s' points to object I don't have", name); | |
e4b5c7ff LT |
134 | if (!memcmp(old_sha1, new_sha1, 20)) { |
135 | fprintf(stderr, "'%s' unchanged\n", name); | |
7f8e9828 | 136 | continue; |
e4b5c7ff | 137 | } |
7f8e9828 LT |
138 | ref = xmalloc(sizeof(*ref) + len - 40); |
139 | memcpy(ref->old_sha1, old_sha1, 20); | |
140 | memcpy(ref->new_sha1, new_sha1, 20); | |
141 | memcpy(ref->name, buffer + 41, len - 40); | |
142 | ref->next = NULL; | |
143 | *last_ref = ref; | |
144 | last_ref = &ref->next; | |
145 | } | |
146 | ||
147 | for (ref = ref_list; ref; ref = ref->next) { | |
148 | char old_hex[60], *new_hex; | |
149 | strcpy(old_hex, sha1_to_hex(ref->old_sha1)); | |
150 | new_hex = sha1_to_hex(ref->new_sha1); | |
151 | packet_write(out, "%s %s %s", old_hex, new_hex, ref->name); | |
152 | fprintf(stderr, "'%s': updating from %s to %s\n", ref->name, old_hex, new_hex); | |
61221472 | 153 | } |
7f8e9828 | 154 | |
f3a3214e | 155 | packet_flush(out); |
94fdb7aa LT |
156 | if (ref_list) |
157 | pack_objects(out, ref_list); | |
61221472 LT |
158 | close(out); |
159 | return 0; | |
160 | } | |
161 | ||
61221472 LT |
162 | int main(int argc, char **argv) |
163 | { | |
164 | int i, nr_heads = 0; | |
165 | char *dest = NULL; | |
166 | char **heads = NULL; | |
7f8e9828 LT |
167 | int fd[2], ret; |
168 | pid_t pid; | |
61221472 LT |
169 | |
170 | argv++; | |
171 | for (i = 1; i < argc; i++) { | |
172 | char *arg = *argv++; | |
173 | ||
174 | if (*arg == '-') { | |
175 | if (!strncmp(arg, "--exec=", 7)) { | |
176 | exec = arg + 7; | |
177 | continue; | |
178 | } | |
179 | usage(send_pack_usage); | |
180 | } | |
181 | dest = arg; | |
182 | heads = argv; | |
183 | nr_heads = argc - i -1; | |
184 | break; | |
185 | } | |
186 | if (!dest) | |
187 | usage(send_pack_usage); | |
f7192598 | 188 | pid = git_connect(fd, dest, exec); |
7f8e9828 | 189 | if (pid < 0) |
61221472 | 190 | return 1; |
d0efc8a7 | 191 | ret = send_pack(fd[0], fd[1], nr_heads, heads); |
7f8e9828 LT |
192 | close(fd[0]); |
193 | close(fd[1]); | |
f7192598 | 194 | finish_connect(pid); |
7f8e9828 | 195 | return ret; |
61221472 | 196 | } |