builtin-push: don't access freed transport->url
[git/git.git] / transport-helper.c
CommitLineData
6eb996b5
DB
1#include "cache.h"
2#include "transport.h"
3
4#include "run-command.h"
5#include "commit.h"
6#include "diff.h"
7#include "revision.h"
72ff8943 8#include "remote.h"
6eb996b5
DB
9
10struct helper_data
11{
12 const char *name;
13 struct child_process *helper;
14 unsigned fetch : 1;
e65e91ed 15 unsigned import : 1;
72ff8943
DB
16 /* These go from remote name (as in "list") to private name */
17 struct refspec *refspecs;
18 int refspec_nr;
6eb996b5
DB
19};
20
21static struct child_process *get_helper(struct transport *transport)
22{
23 struct helper_data *data = transport->data;
24 struct strbuf buf = STRBUF_INIT;
25 struct child_process *helper;
26 FILE *file;
72ff8943
DB
27 const char **refspecs = NULL;
28 int refspec_nr = 0;
29 int refspec_alloc = 0;
6eb996b5
DB
30
31 if (data->helper)
32 return data->helper;
33
34 helper = xcalloc(1, sizeof(*helper));
35 helper->in = -1;
36 helper->out = -1;
37 helper->err = 0;
38 helper->argv = xcalloc(4, sizeof(*helper->argv));
39 strbuf_addf(&buf, "remote-%s", data->name);
40 helper->argv[0] = strbuf_detach(&buf, NULL);
41 helper->argv[1] = transport->remote->name;
42 helper->argv[2] = transport->url;
43 helper->git_cmd = 1;
44 if (start_command(helper))
45 die("Unable to run helper: git %s", helper->argv[0]);
46 data->helper = helper;
47
3d913526 48 write_str_in_full(helper->in, "capabilities\n");
2d14d65c 49
41698375 50 file = xfdopen(helper->out, "r");
6eb996b5
DB
51 while (1) {
52 if (strbuf_getline(&buf, file, '\n') == EOF)
53 exit(128); /* child died, message supplied already */
54
55 if (!*buf.buf)
56 break;
57 if (!strcmp(buf.buf, "fetch"))
58 data->fetch = 1;
e65e91ed
DB
59 if (!strcmp(buf.buf, "import"))
60 data->import = 1;
72ff8943
DB
61 if (!data->refspecs && !prefixcmp(buf.buf, "refspec ")) {
62 ALLOC_GROW(refspecs,
63 refspec_nr + 1,
64 refspec_alloc);
65 refspecs[refspec_nr++] = strdup(buf.buf + strlen("refspec "));
66 }
67 }
68 if (refspecs) {
69 int i;
70 data->refspec_nr = refspec_nr;
71 data->refspecs = parse_fetch_refspec(refspec_nr, refspecs);
72 for (i = 0; i < refspec_nr; i++) {
73 free((char *)refspecs[i]);
74 }
75 free(refspecs);
6eb996b5 76 }
b962dbdc 77 strbuf_release(&buf);
6eb996b5
DB
78 return data->helper;
79}
80
81static int disconnect_helper(struct transport *transport)
82{
83 struct helper_data *data = transport->data;
84 if (data->helper) {
3d913526 85 write_str_in_full(data->helper->in, "\n");
6eb996b5
DB
86 close(data->helper->in);
87 finish_command(data->helper);
88 free((char *)data->helper->argv[0]);
89 free(data->helper->argv);
90 free(data->helper);
91 data->helper = NULL;
92 }
93 return 0;
94}
95
f2a37151
DB
96static int release_helper(struct transport *transport)
97{
72ff8943
DB
98 struct helper_data *data = transport->data;
99 free_refspec(data->refspec_nr, data->refspecs);
100 data->refspecs = NULL;
f2a37151
DB
101 disconnect_helper(transport);
102 free(transport->data);
103 return 0;
104}
105
6eb996b5 106static int fetch_with_fetch(struct transport *transport,
37148311 107 int nr_heads, struct ref **to_fetch)
6eb996b5
DB
108{
109 struct child_process *helper = get_helper(transport);
41698375 110 FILE *file = xfdopen(helper->out, "r");
6eb996b5
DB
111 int i;
112 struct strbuf buf = STRBUF_INIT;
113
114 for (i = 0; i < nr_heads; i++) {
1088261f 115 const struct ref *posn = to_fetch[i];
6eb996b5
DB
116 if (posn->status & REF_STATUS_UPTODATE)
117 continue;
2d14d65c
DB
118
119 strbuf_addf(&buf, "fetch %s %s\n",
120 sha1_to_hex(posn->old_sha1), posn->name);
121 write_in_full(helper->in, buf.buf, buf.len);
122 strbuf_reset(&buf);
123
6eb996b5
DB
124 if (strbuf_getline(&buf, file, '\n') == EOF)
125 exit(128); /* child died, message supplied already */
126 }
127 return 0;
128}
129
e65e91ed
DB
130static int get_importer(struct transport *transport, struct child_process *fastimport)
131{
132 struct child_process *helper = get_helper(transport);
133 memset(fastimport, 0, sizeof(*fastimport));
134 fastimport->in = helper->out;
135 fastimport->argv = xcalloc(5, sizeof(*fastimport->argv));
136 fastimport->argv[0] = "fast-import";
137 fastimport->argv[1] = "--quiet";
138
139 fastimport->git_cmd = 1;
140 return start_command(fastimport);
141}
142
143static int fetch_with_import(struct transport *transport,
144 int nr_heads, struct ref **to_fetch)
145{
146 struct child_process fastimport;
147 struct child_process *helper = get_helper(transport);
72ff8943 148 struct helper_data *data = transport->data;
e65e91ed
DB
149 int i;
150 struct ref *posn;
151 struct strbuf buf = STRBUF_INIT;
152
153 if (get_importer(transport, &fastimport))
154 die("Couldn't run fast-import");
155
156 for (i = 0; i < nr_heads; i++) {
157 posn = to_fetch[i];
158 if (posn->status & REF_STATUS_UPTODATE)
159 continue;
160
161 strbuf_addf(&buf, "import %s\n", posn->name);
162 write_in_full(helper->in, buf.buf, buf.len);
163 strbuf_reset(&buf);
164 }
165 disconnect_helper(transport);
166 finish_command(&fastimport);
b962dbdc
SR
167 free(fastimport.argv);
168 fastimport.argv = NULL;
e65e91ed
DB
169
170 for (i = 0; i < nr_heads; i++) {
72ff8943 171 char *private;
e65e91ed
DB
172 posn = to_fetch[i];
173 if (posn->status & REF_STATUS_UPTODATE)
174 continue;
72ff8943
DB
175 if (data->refspecs)
176 private = apply_refspecs(data->refspecs, data->refspec_nr, posn->name);
177 else
178 private = strdup(posn->name);
179 read_ref(private, posn->old_sha1);
180 free(private);
e65e91ed 181 }
b962dbdc 182 strbuf_release(&buf);
e65e91ed
DB
183 return 0;
184}
185
6eb996b5 186static int fetch(struct transport *transport,
37148311 187 int nr_heads, struct ref **to_fetch)
6eb996b5
DB
188{
189 struct helper_data *data = transport->data;
190 int i, count;
191
192 count = 0;
193 for (i = 0; i < nr_heads; i++)
194 if (!(to_fetch[i]->status & REF_STATUS_UPTODATE))
195 count++;
196
197 if (!count)
198 return 0;
199
200 if (data->fetch)
201 return fetch_with_fetch(transport, nr_heads, to_fetch);
202
e65e91ed
DB
203 if (data->import)
204 return fetch_with_import(transport, nr_heads, to_fetch);
205
6eb996b5
DB
206 return -1;
207}
208
f8ec9167
DB
209static int has_attribute(const char *attrs, const char *attr) {
210 int len;
211 if (!attrs)
212 return 0;
213
214 len = strlen(attr);
215 for (;;) {
216 const char *space = strchrnul(attrs, ' ');
217 if (len == space - attrs && !strncmp(attrs, attr, len))
218 return 1;
219 if (!*space)
220 return 0;
221 attrs = space + 1;
222 }
223}
224
6eb996b5
DB
225static struct ref *get_refs_list(struct transport *transport, int for_push)
226{
227 struct child_process *helper;
228 struct ref *ret = NULL;
229 struct ref **tail = &ret;
230 struct ref *posn;
231 struct strbuf buf = STRBUF_INIT;
232 FILE *file;
233
234 helper = get_helper(transport);
2d14d65c 235
3d913526 236 write_str_in_full(helper->in, "list\n");
6eb996b5 237
41698375 238 file = xfdopen(helper->out, "r");
6eb996b5
DB
239 while (1) {
240 char *eov, *eon;
241 if (strbuf_getline(&buf, file, '\n') == EOF)
242 exit(128); /* child died, message supplied already */
243
244 if (!*buf.buf)
245 break;
246
247 eov = strchr(buf.buf, ' ');
248 if (!eov)
249 die("Malformed response in ref list: %s", buf.buf);
250 eon = strchr(eov + 1, ' ');
251 *eov = '\0';
252 if (eon)
253 *eon = '\0';
254 *tail = alloc_ref(eov + 1);
255 if (buf.buf[0] == '@')
256 (*tail)->symref = xstrdup(buf.buf + 1);
257 else if (buf.buf[0] != '?')
258 get_sha1_hex(buf.buf, (*tail)->old_sha1);
f8ec9167
DB
259 if (eon) {
260 if (has_attribute(eon + 1, "unchanged")) {
261 (*tail)->status |= REF_STATUS_UPTODATE;
262 read_ref((*tail)->name, (*tail)->old_sha1);
263 }
264 }
6eb996b5
DB
265 tail = &((*tail)->next);
266 }
267 strbuf_release(&buf);
268
269 for (posn = ret; posn; posn = posn->next)
270 resolve_remote_symref(posn, ret);
271
272 return ret;
273}
274
c9e388bb 275int transport_helper_init(struct transport *transport, const char *name)
6eb996b5
DB
276{
277 struct helper_data *data = xcalloc(sizeof(*data), 1);
c9e388bb 278 data->name = name;
6eb996b5
DB
279
280 transport->data = data;
281 transport->get_refs_list = get_refs_list;
282 transport->fetch = fetch;
f2a37151 283 transport->disconnect = release_helper;
6eb996b5
DB
284 return 0;
285}