]> git.proxmox.com Git - libgit2.git/blame - src/remote.c
Merge pull request #537 from nulltoken/fix/download-segfault
[libgit2.git] / src / remote.c
CommitLineData
9c82357b 1/*
bb742ede 2 * Copyright (C) 2009-2011 the libgit2 contributors
9c82357b 3 *
bb742ede
VM
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
9c82357b
CMN
6 */
7
8#include "git2/remote.h"
9#include "git2/config.h"
10#include "git2/types.h"
11
12#include "config.h"
13#include "repository.h"
14#include "remote.h"
e1d88030 15#include "fetch.h"
441f57c2 16#include "refs.h"
9c82357b
CMN
17
18static int refspec_parse(git_refspec *refspec, const char *str)
19{
20 char *delim;
21
22 memset(refspec, 0x0, sizeof(git_refspec));
23
24 if (*str == '+') {
25 refspec->force = 1;
26 str++;
27 }
28
29 delim = strchr(str, ':');
30 if (delim == NULL)
31 return git__throw(GIT_EOBJCORRUPTED, "Failed to parse refspec. No ':'");
32
33 refspec->src = git__strndup(str, delim - str);
34 if (refspec->src == NULL)
35 return GIT_ENOMEM;
36
37 refspec->dst = git__strdup(delim + 1);
38 if (refspec->dst == NULL) {
3286c408 39 git__free(refspec->src);
9c82357b
CMN
40 refspec->src = NULL;
41 return GIT_ENOMEM;
42 }
43
44 return GIT_SUCCESS;
45}
46
47static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const char *var)
48{
49 const char *val;
50 int error;
51
52 error = git_config_get_string(cfg, var, &val);
53 if (error < GIT_SUCCESS)
54 return error;
55
2dc31040 56 return refspec_parse(refspec, val);
9c82357b
CMN
57}
58
617bfdf4 59int git_remote_new(git_remote **out, git_repository *repo, const char *url, const char *name)
778e1c73
CMN
60{
61 git_remote *remote;
62
4bef3565
VM
63 /* name is optional */
64 assert(out && repo && url);
617bfdf4 65
778e1c73
CMN
66 remote = git__malloc(sizeof(git_remote));
67 if (remote == NULL)
68 return GIT_ENOMEM;
69
70 memset(remote, 0x0, sizeof(git_remote));
71 remote->repo = repo;
617bfdf4 72
d88d4311
VM
73 if (git_vector_init(&remote->refs, 32, NULL) < 0) {
74 git_remote_free(remote);
75 return GIT_ENOMEM;
76 }
77
778e1c73
CMN
78 remote->url = git__strdup(url);
79 if (remote->url == NULL) {
d88d4311 80 git_remote_free(remote);
778e1c73
CMN
81 return GIT_ENOMEM;
82 }
83
617bfdf4
CMN
84 if (name != NULL) {
85 remote->name = git__strdup(name);
86 if (remote->name == NULL) {
d88d4311 87 git_remote_free(remote);
617bfdf4
CMN
88 return GIT_ENOMEM;
89 }
90 }
91
778e1c73
CMN
92 *out = remote;
93 return GIT_SUCCESS;
94}
95
9462c471 96int git_remote_load(git_remote **out, git_repository *repo, const char *name)
9c82357b
CMN
97{
98 git_remote *remote;
99 char *buf = NULL;
100 const char *val;
101 int ret, error, buf_len;
9462c471 102 git_config *config;
9c82357b 103
9462c471
VM
104 assert(out && repo && name);
105
106 error = git_repository_config__weakptr(&config, repo);
107 if (error < GIT_SUCCESS)
108 return error;
4bef3565 109
9c82357b
CMN
110 remote = git__malloc(sizeof(git_remote));
111 if (remote == NULL)
112 return GIT_ENOMEM;
113
114 memset(remote, 0x0, sizeof(git_remote));
115 remote->name = git__strdup(name);
116 if (remote->name == NULL) {
117 error = GIT_ENOMEM;
118 goto cleanup;
119 }
120
d88d4311
VM
121 if (git_vector_init(&remote->refs, 32, NULL) < 0) {
122 error = GIT_ENOMEM;
123 goto cleanup;
124 }
125
9c82357b 126 /* "fetch" is the longest var name we're interested in */
932669b8 127 buf_len = strlen("remote.") + strlen(".fetch") + strlen(name) + 1;
9c82357b
CMN
128 buf = git__malloc(buf_len);
129 if (buf == NULL) {
130 error = GIT_ENOMEM;
131 goto cleanup;
132 }
133
84dd3820 134 ret = p_snprintf(buf, buf_len, "%s.%s.%s", "remote", name, "url");
9c82357b
CMN
135 if (ret < 0) {
136 error = git__throw(GIT_EOSERR, "Failed to build config var name");
137 goto cleanup;
138 }
139
9462c471 140 error = git_config_get_string(config, buf, &val);
9c82357b 141 if (error < GIT_SUCCESS) {
87d9869f 142 error = git__rethrow(error, "Remote's url doesn't exist");
9c82357b
CMN
143 goto cleanup;
144 }
145
9462c471 146 remote->repo = repo;
9c82357b
CMN
147 remote->url = git__strdup(val);
148 if (remote->url == NULL) {
149 error = GIT_ENOMEM;
150 goto cleanup;
151 }
152
84dd3820 153 ret = p_snprintf(buf, buf_len, "%s.%s.%s", "remote", name, "fetch");
9c82357b
CMN
154 if (ret < 0) {
155 error = git__throw(GIT_EOSERR, "Failed to build config var name");
156 goto cleanup;
157 }
158
9462c471 159 error = parse_remote_refspec(config, &remote->fetch, buf);
2dc31040
CMN
160 if (error < GIT_SUCCESS) {
161 error = git__rethrow(error, "Failed to get fetch refspec");
9c82357b 162 goto cleanup;
2dc31040 163 }
9c82357b 164
84dd3820 165 ret = p_snprintf(buf, buf_len, "%s.%s.%s", "remote", name, "push");
9c82357b
CMN
166 if (ret < 0) {
167 error = git__throw(GIT_EOSERR, "Failed to build config var name");
168 goto cleanup;
169 }
170
9462c471 171 error = parse_remote_refspec(config, &remote->push, buf);
2dc31040
CMN
172 /* Not finding push is fine */
173 if (error == GIT_ENOTFOUND)
174 error = GIT_SUCCESS;
9c82357b 175
9c82357b
CMN
176 if (error < GIT_SUCCESS)
177 goto cleanup;
178
179 *out = remote;
180
181cleanup:
3286c408 182 git__free(buf);
9462c471 183
9c82357b
CMN
184 if (error < GIT_SUCCESS)
185 git_remote_free(remote);
186
187 return error;
188}
189
4bef3565 190const char *git_remote_name(git_remote *remote)
9c82357b 191{
4bef3565 192 assert(remote);
9c82357b
CMN
193 return remote->name;
194}
195
4bef3565 196const char *git_remote_url(git_remote *remote)
9c82357b 197{
4bef3565 198 assert(remote);
9c82357b
CMN
199 return remote->url;
200}
201
4bef3565 202const git_refspec *git_remote_fetchspec(git_remote *remote)
9c82357b 203{
4bef3565 204 assert(remote);
9c82357b
CMN
205 return &remote->fetch;
206}
207
4bef3565 208const git_refspec *git_remote_pushspec(git_remote *remote)
9c82357b 209{
4bef3565 210 assert(remote);
9c82357b
CMN
211 return &remote->push;
212}
213
0ac2726f 214int git_remote_connect(git_remote *remote, int direction)
9ba49bb5
CMN
215{
216 int error;
217 git_transport *t;
218
4bef3565
VM
219 assert(remote);
220
9ba49bb5
CMN
221 error = git_transport_new(&t, remote->url);
222 if (error < GIT_SUCCESS)
223 return git__rethrow(error, "Failed to create transport");
224
b5a8aa94 225 error = t->connect(t, direction);
9ba49bb5
CMN
226 if (error < GIT_SUCCESS) {
227 error = git__rethrow(error, "Failed to connect the transport");
228 goto cleanup;
229 }
230
231 remote->transport = t;
232
233cleanup:
234 if (error < GIT_SUCCESS)
b5a8aa94 235 t->free(t);
9ba49bb5
CMN
236
237 return error;
238}
239
d88d4311 240int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload)
9ba49bb5 241{
d88d4311
VM
242 assert(remote);
243
b2337143 244 if (!remote->transport || !remote->transport->connected)
d88d4311
VM
245 return git__throw(GIT_ERROR, "The remote is not connected");
246
247 return remote->transport->ls(remote->transport, list_cb, payload);
9ba49bb5
CMN
248}
249
48a65a07
CMN
250int git_remote_download(char **filename, git_remote *remote)
251{
95057b85
CMN
252 int error;
253
4bef3565
VM
254 assert(filename && remote);
255
95057b85
CMN
256 if ((error = git_fetch_negotiate(remote)) < 0)
257 return git__rethrow(error, "Error negotiating");
258
48a65a07
CMN
259 return git_fetch_download_pack(filename, remote);
260}
261
4bef3565 262int git_remote_update_tips(git_remote *remote)
441f57c2
CMN
263{
264 int error = GIT_SUCCESS;
517bda19 265 unsigned int i = 0;
97769280 266 git_buf refname = GIT_BUF_INIT;
d88d4311 267 git_vector *refs = &remote->refs;
441f57c2
CMN
268 git_remote_head *head;
269 git_reference *ref;
270 struct git_refspec *spec = &remote->fetch;
271
4bef3565
VM
272 assert(remote);
273
d88d4311 274 if (refs->length == 0)
517bda19
CMN
275 return GIT_SUCCESS;
276
277 /* HEAD is only allowed to be the first in the list */
d88d4311 278 head = refs->contents[0];
517bda19
CMN
279 if (!strcmp(head->name, GIT_HEAD_FILE)) {
280 error = git_reference_create_oid(&ref, remote->repo, GIT_FETCH_HEAD_FILE, &head->oid, 1);
281 i = 1;
39157563 282 git_reference_free(ref);
517bda19
CMN
283 if (error < GIT_SUCCESS)
284 return git__rethrow(error, "Failed to update FETCH_HEAD");
285 }
286
d88d4311
VM
287 for (; i < refs->length; ++i) {
288 head = refs->contents[i];
517bda19 289
97769280 290 error = git_refspec_transform_r(&refname, spec, head->name);
441f57c2 291 if (error < GIT_SUCCESS)
97769280 292 break;
441f57c2 293
97769280 294 error = git_reference_create_oid(&ref, remote->repo, refname.ptr, &head->oid, 1);
441f57c2 295 if (error < GIT_SUCCESS)
97769280 296 break;
39157563
CMN
297
298 git_reference_free(ref);
441f57c2
CMN
299 }
300
97769280
RB
301 git_buf_free(&refname);
302
303 return error;
441f57c2
CMN
304}
305
6ac3b707
CMN
306int git_remote_connected(git_remote *remote)
307{
4bef3565 308 assert(remote);
6ac3b707
CMN
309 return remote->transport == NULL ? 0 : remote->transport->connected;
310}
311
4cf01e9a
CMN
312void git_remote_disconnect(git_remote *remote)
313{
4bef3565
VM
314 assert(remote);
315
4cf01e9a
CMN
316 if (remote->transport != NULL) {
317 if (remote->transport->connected)
318 remote->transport->close(remote->transport);
319
320 remote->transport->free(remote->transport);
a3147114 321 remote->transport = NULL;
4cf01e9a
CMN
322 }
323}
324
9c82357b
CMN
325void git_remote_free(git_remote *remote)
326{
2aae2188
CMN
327 if (remote == NULL)
328 return;
329
3286c408
VM
330 git__free(remote->fetch.src);
331 git__free(remote->fetch.dst);
332 git__free(remote->push.src);
333 git__free(remote->push.dst);
334 git__free(remote->url);
335 git__free(remote->name);
d88d4311 336 git_vector_free(&remote->refs);
4cf01e9a 337 git_remote_disconnect(remote);
3286c408 338 git__free(remote);
9c82357b 339}