]> git.proxmox.com Git - libgit2.git/blame - src/remote.c
Error messages for a couple other boundary conditions
[libgit2.git] / src / remote.c
CommitLineData
9c82357b 1/*
359fc2d2 2 * Copyright (C) the libgit2 contributors. All rights reserved.
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
9c82357b
CMN
8#include "git2/config.h"
9#include "git2/types.h"
c07d9c95 10#include "git2/oid.h"
1ffd0806 11#include "git2/net.h"
9c82357b
CMN
12
13#include "config.h"
14#include "repository.h"
15#include "remote.h"
e1d88030 16#include "fetch.h"
441f57c2 17#include "refs.h"
b0f6e45d
ET
18#include "refspec.h"
19#include "fetchhead.h"
9c82357b 20
8171998f
CMN
21#include <regex.h>
22
4330ab26 23static int add_refspec(git_remote *remote, const char *string, bool is_fetch)
9c82357b 24{
4330ab26 25 git_refspec *spec;
9c82357b 26
4330ab26
CMN
27 spec = git__calloc(1, sizeof(git_refspec));
28 GITERR_CHECK_ALLOC(spec);
29
1be680c4
CMN
30 if (git_refspec__parse(spec, string, is_fetch) < 0) {
31 git__free(spec);
32 return -1;
33 }
4330ab26
CMN
34
35 spec->push = !is_fetch;
1be680c4
CMN
36 if (git_vector_insert(&remote->refspecs, spec) < 0) {
37 git_refspec__free(spec);
38 git__free(spec);
39 return -1;
40 }
9c82357b 41
4330ab26 42 return 0;
9c82357b
CMN
43}
44
24f2f94e
CMN
45static int download_tags_value(git_remote *remote, git_config *cfg)
46{
47 const char *val;
48 git_buf buf = GIT_BUF_INIT;
49 int error;
50
51 if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_UNSET)
52 return 0;
53
54 /* This is the default, let's see if we need to change it */
55 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO;
56 if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
57 return -1;
58
59 error = git_config_get_string(&val, cfg, git_buf_cstr(&buf));
60 git_buf_free(&buf);
61 if (!error && !strcmp(val, "--no-tags"))
62 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
3230a44f
CMN
63 else if (!error && !strcmp(val, "--tags"))
64 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
24f2f94e
CMN
65
66 if (error == GIT_ENOTFOUND)
67 error = 0;
68
69 return error;
70}
71
032ba9e4 72static int ensure_remote_name_is_valid(const char *name)
73{
2bca5b67 74 int error = 0;
032ba9e4 75
2bca5b67 76 if (!git_remote_is_valid_name(name)) {
032ba9e4 77 giterr_set(
78 GITERR_CONFIG,
79 "'%s' is not a valid remote name.", name);
80 error = GIT_EINVALIDSPEC;
81 }
82
83 return error;
84}
85
874dcb25 86static int create_internal(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
778e1c73
CMN
87{
88 git_remote *remote;
44f36f6e
BS
89 git_buf fetchbuf = GIT_BUF_INIT;
90 int error = -1;
778e1c73 91
4bef3565 92 /* name is optional */
874dcb25 93 assert(out && repo && url);
617bfdf4 94
59bccf33 95 remote = git__calloc(1, sizeof(git_remote));
4376f7f6 96 GITERR_CHECK_ALLOC(remote);
778e1c73 97
778e1c73 98 remote->repo = repo;
250b95b2 99 remote->check_cert = 1;
b0f6e45d 100 remote->update_fetchhead = 1;
617bfdf4 101
4376f7f6 102 if (git_vector_init(&remote->refs, 32, NULL) < 0)
44f36f6e 103 goto on_error;
d88d4311 104
778e1c73 105 remote->url = git__strdup(url);
4376f7f6 106 GITERR_CHECK_ALLOC(remote->url);
778e1c73 107
617bfdf4
CMN
108 if (name != NULL) {
109 remote->name = git__strdup(name);
4376f7f6 110 GITERR_CHECK_ALLOC(remote->name);
617bfdf4
CMN
111 }
112
baaa8a44 113 if (fetch != NULL) {
4330ab26 114 if (add_refspec(remote, fetch, true) < 0)
baaa8a44
CMN
115 goto on_error;
116 }
117
c648d4a8
CMN
118 /* A remote without a name doesn't download tags */
119 if (!name) {
120 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
121 }
122
778e1c73 123 *out = remote;
44f36f6e 124 git_buf_free(&fetchbuf);
4376f7f6 125 return 0;
baaa8a44
CMN
126
127on_error:
128 git_remote_free(remote);
44f36f6e
BS
129 git_buf_free(&fetchbuf);
130 return error;
778e1c73
CMN
131}
132
592f466c
BS
133static int ensure_remote_doesnot_exist(git_repository *repo, const char *name)
134{
135 int error;
136 git_remote *remote;
137
138 error = git_remote_load(&remote, repo, name);
139
140 if (error == GIT_ENOTFOUND)
141 return 0;
142
143 if (error < 0)
144 return error;
145
146 git_remote_free(remote);
147
148 giterr_set(
149 GITERR_CONFIG,
150 "Remote '%s' already exists.", name);
151
152 return GIT_EEXISTS;
153}
154
f19304d2 155
874dcb25
BS
156int git_remote_create(git_remote **out, git_repository *repo, const char *name, const char *url)
157{
158 git_buf buf = GIT_BUF_INIT;
c5193e3c 159 git_remote *remote = NULL;
874dcb25
BS
160 int error;
161
162 if ((error = ensure_remote_name_is_valid(name)) < 0)
163 return error;
164
f19304d2 165 if ((error = ensure_remote_doesnot_exist(repo, name)) < 0)
166 return error;
167
874dcb25
BS
168 if (git_buf_printf(&buf, "+refs/heads/*:refs/remotes/%s/*", name) < 0)
169 return -1;
170
c5193e3c 171 if (create_internal(&remote, repo, name, url, git_buf_cstr(&buf)) < 0)
874dcb25
BS
172 goto on_error;
173
174 git_buf_free(&buf);
175
c5193e3c 176 if (git_remote_save(remote) < 0)
874dcb25
BS
177 goto on_error;
178
c5193e3c 179 *out = remote;
180
874dcb25
BS
181 return 0;
182
183on_error:
184 git_buf_free(&buf);
c5193e3c 185 git_remote_free(remote);
874dcb25
BS
186 return -1;
187}
188
0642c143 189int git_remote_create_inmemory(git_remote **out, git_repository *repo, const char *fetch, const char *url)
874dcb25
BS
190{
191 int error;
192 git_remote *remote;
193
79000951 194 if ((error = create_internal(&remote, repo, NULL, url, fetch)) < 0)
874dcb25
BS
195 return error;
196
874dcb25
BS
197 *out = remote;
198 return 0;
199}
200
4330ab26
CMN
201struct refspec_cb_data {
202 git_remote *remote;
203 int fetch;
204};
205
206static int refspec_cb(const git_config_entry *entry, void *payload)
207{
208 const struct refspec_cb_data *data = (struct refspec_cb_data *)payload;
209
210 return add_refspec(data->remote, entry->value, data->fetch);
211}
212
9462c471 213int git_remote_load(git_remote **out, git_repository *repo, const char *name)
9c82357b
CMN
214{
215 git_remote *remote;
f0f3a18a 216 git_buf buf = GIT_BUF_INIT;
9c82357b 217 const char *val;
4376f7f6 218 int error = 0;
9462c471 219 git_config *config;
4330ab26
CMN
220 struct refspec_cb_data data;
221
9c82357b 222
9462c471
VM
223 assert(out && repo && name);
224
032ba9e4 225 if ((error = ensure_remote_name_is_valid(name)) < 0)
226 return error;
227
4376f7f6
CMN
228 if (git_repository_config__weakptr(&config, repo) < 0)
229 return -1;
4bef3565 230
9c82357b 231 remote = git__malloc(sizeof(git_remote));
4376f7f6 232 GITERR_CHECK_ALLOC(remote);
9c82357b
CMN
233
234 memset(remote, 0x0, sizeof(git_remote));
250b95b2 235 remote->check_cert = 1;
b0f6e45d 236 remote->update_fetchhead = 1;
9c82357b 237 remote->name = git__strdup(name);
4376f7f6 238 GITERR_CHECK_ALLOC(remote->name);
9c82357b 239
4330ab26 240 if ((git_vector_init(&remote->refs, 32, NULL) < 0) ||
1be680c4 241 (git_vector_init(&remote->refspecs, 2, NULL))) {
2fb9d6de 242 error = -1;
243 goto cleanup;
244 }
d88d4311 245
2fb9d6de 246 if (git_buf_printf(&buf, "remote.%s.url", name) < 0) {
247 error = -1;
248 goto cleanup;
249 }
9c82357b 250
29e948de 251 if ((error = git_config_get_string(&val, config, git_buf_cstr(&buf))) < 0)
9c82357b 252 goto cleanup;
83885891 253
0da81d2b 254 if (strlen(val) == 0) {
c1cd036e 255 giterr_set(GITERR_INVALID, "Malformed remote '%s' - missing URL", name);
83885891
JSS
256 error = -1;
257 goto cleanup;
258 }
9c82357b 259
9462c471 260 remote->repo = repo;
9c82357b 261 remote->url = git__strdup(val);
4376f7f6 262 GITERR_CHECK_ALLOC(remote->url);
9c82357b 263
3ed4b501
SC
264 git_buf_clear(&buf);
265 if (git_buf_printf(&buf, "remote.%s.pushurl", name) < 0) {
266 error = -1;
267 goto cleanup;
268 }
269
270 error = git_config_get_string(&val, config, git_buf_cstr(&buf));
0da81d2b
CMN
271 if (error == GIT_ENOTFOUND) {
272 val = NULL;
3ed4b501 273 error = 0;
0da81d2b 274 }
3ed4b501
SC
275
276 if (error < 0) {
277 error = -1;
278 goto cleanup;
279 }
280
281 if (val) {
282 remote->pushurl = git__strdup(val);
283 GITERR_CHECK_ALLOC(remote->pushurl);
284 }
285
f0f3a18a 286 git_buf_clear(&buf);
2fb9d6de 287 if (git_buf_printf(&buf, "remote.%s.fetch", name) < 0) {
288 error = -1;
289 goto cleanup;
290 }
9c82357b 291
4330ab26
CMN
292 data.remote = remote;
293 data.fetch = true;
294 error = git_config_get_multivar(config, git_buf_cstr(&buf), NULL, refspec_cb, &data);
904b67e6 295 if (error == GIT_ENOTFOUND)
4376f7f6 296 error = 0;
9554cd51 297
4376f7f6
CMN
298 if (error < 0) {
299 error = -1;
9c82357b 300 goto cleanup;
2dc31040 301 }
9c82357b 302
f0f3a18a 303 git_buf_clear(&buf);
2fb9d6de 304 if (git_buf_printf(&buf, "remote.%s.push", name) < 0) {
305 error = -1;
306 goto cleanup;
307 }
9c82357b 308
4330ab26
CMN
309 data.fetch = false;
310 error = git_config_get_multivar(config, git_buf_cstr(&buf), NULL, refspec_cb, &data);
904b67e6 311 if (error == GIT_ENOTFOUND)
4376f7f6 312 error = 0;
9c82357b 313
4376f7f6
CMN
314 if (error < 0) {
315 error = -1;
9c82357b 316 goto cleanup;
4376f7f6 317 }
9c82357b 318
24f2f94e
CMN
319 if (download_tags_value(remote, config) < 0)
320 goto cleanup;
321
9c82357b
CMN
322 *out = remote;
323
324cleanup:
f0f3a18a 325 git_buf_free(&buf);
9462c471 326
4376f7f6 327 if (error < 0)
9c82357b
CMN
328 git_remote_free(remote);
329
330 return error;
331}
332
4330ab26 333static int update_config_refspec(const git_remote *remote, git_config *config, int direction)
4fe5520a 334{
4330ab26
CMN
335 git_buf name = GIT_BUF_INIT;
336 int push;
337 const char *dir;
338 size_t i;
4fe5520a 339 int error = -1;
340
4330ab26
CMN
341 push = direction == GIT_DIRECTION_PUSH;
342 dir = push ? "push" : "fetch";
4fe5520a 343
4330ab26
CMN
344 if (git_buf_printf(&name, "remote.%s.%s", remote->name, dir) < 0)
345 return -1;
4fe5520a 346
4330ab26
CMN
347 /* Clear out the existing config */
348 do {
349 error = git_config_delete_entry(config, git_buf_cstr(&name));
350 } while (!error);
4fe5520a 351
4330ab26
CMN
352 if (error != GIT_ENOTFOUND)
353 return error;
354
1be680c4 355 for (i = 0; i < remote->refspecs.length; i++) {
4330ab26 356 git_refspec *spec = git_vector_get(&remote->refspecs, i);
4330ab26
CMN
357
358 if (spec->push != push)
359 continue;
360
1be680c4 361 if ((error = git_config_set_multivar(config, git_buf_cstr(&name), "", spec->string)) < 0) {
4330ab26
CMN
362 goto cleanup;
363 }
364 }
365
366 giterr_clear();
367 error = 0;
4fe5520a 368
369cleanup:
370 git_buf_free(&name);
4fe5520a 371
372 return error;
373}
374
89e5ed98
CMN
375int git_remote_save(const git_remote *remote)
376{
218c88a9 377 int error;
89e5ed98 378 git_config *config;
218c88a9 379 const char *tagopt = NULL;
4fe5520a 380 git_buf buf = GIT_BUF_INIT;
89e5ed98 381
e497b16c 382 assert(remote);
383
c07b52df 384 if (!remote->name) {
874dcb25
BS
385 giterr_set(GITERR_INVALID, "Can't save an in-memory remote.");
386 return GIT_EINVALIDSPEC;
a71c27cc
BS
387 }
388
032ba9e4 389 if ((error = ensure_remote_name_is_valid(remote->name)) < 0)
390 return error;
89e5ed98 391
4376f7f6
CMN
392 if (git_repository_config__weakptr(&config, remote->repo) < 0)
393 return -1;
89e5ed98 394
cb020f0d 395 if (git_buf_printf(&buf, "remote.%s.url", remote->name) < 0)
4376f7f6 396 return -1;
89e5ed98 397
4376f7f6
CMN
398 if (git_config_set_string(config, git_buf_cstr(&buf), remote->url) < 0) {
399 git_buf_free(&buf);
400 return -1;
401 }
89e5ed98 402
413d5563
SC
403 git_buf_clear(&buf);
404 if (git_buf_printf(&buf, "remote.%s.pushurl", remote->name) < 0)
405 return -1;
3ed4b501 406
413d5563 407 if (remote->pushurl) {
3ed4b501
SC
408 if (git_config_set_string(config, git_buf_cstr(&buf), remote->pushurl) < 0) {
409 git_buf_free(&buf);
410 return -1;
411 }
413d5563 412 } else {
54b2a37a 413 int error = git_config_delete_entry(config, git_buf_cstr(&buf));
413d5563
SC
414 if (error == GIT_ENOTFOUND) {
415 error = 0;
c48e8700 416 giterr_clear();
413d5563
SC
417 }
418 if (error < 0) {
419 git_buf_free(&buf);
420 return -1;
421 }
3ed4b501
SC
422 }
423
4330ab26
CMN
424 if (update_config_refspec(remote, config, GIT_DIRECTION_FETCH) < 0)
425 goto on_error;
89e5ed98 426
4330ab26
CMN
427 if (update_config_refspec(remote, config, GIT_DIRECTION_PUSH) < 0)
428 goto on_error;
89e5ed98 429
218c88a9
CMN
430 /*
431 * What action to take depends on the old and new values. This
432 * is describes by the table below. tagopt means whether the
433 * is already a value set in the config
434 *
435 * AUTO ALL or NONE
436 * +-----------------------+
437 * tagopt | remove | set |
438 * +---------+-------------|
439 * !tagopt | nothing | set |
440 * +---------+-------------+
441 */
442
443 git_buf_clear(&buf);
444 if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
445 goto on_error;
446
447 error = git_config_get_string(&tagopt, config, git_buf_cstr(&buf));
448 if (error < 0 && error != GIT_ENOTFOUND)
449 goto on_error;
450
451 if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
452 if (git_config_set_string(config, git_buf_cstr(&buf), "--tags") < 0)
453 goto on_error;
454 } else if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
455 if (git_config_set_string(config, git_buf_cstr(&buf), "--no-tags") < 0)
456 goto on_error;
457 } else if (tagopt) {
54b2a37a 458 if (git_config_delete_entry(config, git_buf_cstr(&buf)) < 0)
218c88a9
CMN
459 goto on_error;
460 }
461
89e5ed98 462 git_buf_free(&buf);
4376f7f6
CMN
463
464 return 0;
465
466on_error:
467 git_buf_free(&buf);
4376f7f6 468 return -1;
89e5ed98
CMN
469}
470
df705148 471const char *git_remote_name(const git_remote *remote)
9c82357b 472{
4bef3565 473 assert(remote);
9c82357b
CMN
474 return remote->name;
475}
476
df705148 477const char *git_remote_url(const git_remote *remote)
9c82357b 478{
4bef3565 479 assert(remote);
9c82357b
CMN
480 return remote->url;
481}
482
76501590
SC
483int git_remote_set_url(git_remote *remote, const char* url)
484{
485 assert(remote);
486 assert(url);
487
488 git__free(remote->url);
489 remote->url = git__strdup(url);
490 GITERR_CHECK_ALLOC(remote->url);
491
492 return 0;
493}
494
df705148 495const char *git_remote_pushurl(const git_remote *remote)
76501590
SC
496{
497 assert(remote);
498 return remote->pushurl;
499}
500
501int git_remote_set_pushurl(git_remote *remote, const char* url)
502{
503 assert(remote);
504
505 git__free(remote->pushurl);
506 if (url) {
507 remote->pushurl = git__strdup(url);
508 GITERR_CHECK_ALLOC(remote->pushurl);
509 } else {
510 remote->pushurl = NULL;
511 }
512 return 0;
513}
514
eff5b499
SC
515const char* git_remote__urlfordirection(git_remote *remote, int direction)
516{
517 assert(remote);
518
df705148 519 if (direction == GIT_DIRECTION_FETCH) {
eff5b499
SC
520 return remote->url;
521 }
522
df705148 523 if (direction == GIT_DIRECTION_PUSH) {
eff5b499
SC
524 return remote->pushurl ? remote->pushurl : remote->url;
525 }
526
527 return NULL;
528}
529
df705148 530int git_remote_connect(git_remote *remote, git_direction direction)
9ba49bb5 531{
9ba49bb5 532 git_transport *t;
c0c39025 533 const char *url;
41fb1ca0 534 int flags = GIT_TRANSPORTFLAGS_NONE;
9ba49bb5 535
4bef3565
VM
536 assert(remote);
537
41fb1ca0
PK
538 t = remote->transport;
539
c0c39025 540 url = git_remote__urlfordirection(remote, direction);
eff5b499
SC
541 if (url == NULL )
542 return -1;
543
41fb1ca0
PK
544 /* A transport could have been supplied in advance with
545 * git_remote_set_transport */
613d5eb9 546 if (!t && git_transport_new(&t, remote, url) < 0)
4376f7f6 547 return -1;
9ba49bb5 548
41fb1ca0 549 if (t->set_callbacks &&
df705148 550 t->set_callbacks(t, remote->callbacks.progress, NULL, remote->callbacks.payload) < 0)
41fb1ca0 551 goto on_error;
613d5eb9 552
41fb1ca0
PK
553 if (!remote->check_cert)
554 flags |= GIT_TRANSPORTFLAGS_NO_CHECK_CERT;
e03e71da 555
59bccf33 556 if (t->connect(t, url, remote->cred_acquire_cb, remote->cred_acquire_payload, direction, flags) < 0)
4376f7f6 557 goto on_error;
9ba49bb5
CMN
558
559 remote->transport = t;
560
4376f7f6 561 return 0;
9ba49bb5 562
4376f7f6
CMN
563on_error:
564 t->free(t);
613d5eb9
PK
565
566 if (t == remote->transport)
567 remote->transport = NULL;
568
4376f7f6 569 return -1;
9ba49bb5
CMN
570}
571
d88d4311 572int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload)
9ba49bb5 573{
d88d4311
VM
574 assert(remote);
575
41fb1ca0 576 return remote->transport->ls(remote->transport, list_cb, payload);
9ba49bb5
CMN
577}
578
613d5eb9
PK
579int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url)
580{
581 git_config *cfg;
582 const char *val;
583
584 assert(remote);
585
a71c27cc 586 if (!proxy_url || !remote->repo)
613d5eb9
PK
587 return -1;
588
589 *proxy_url = NULL;
590
591 if (git_repository_config__weakptr(&cfg, remote->repo) < 0)
592 return -1;
593
594 /* Go through the possible sources for proxy configuration, from most specific
595 * to least specific. */
596
597 /* remote.<name>.proxy config setting */
598 if (remote->name && 0 != *(remote->name)) {
599 git_buf buf = GIT_BUF_INIT;
600
601 if (git_buf_printf(&buf, "remote.%s.proxy", remote->name) < 0)
602 return -1;
603
604 if (!git_config_get_string(&val, cfg, git_buf_cstr(&buf)) &&
605 val && ('\0' != *val)) {
606 git_buf_free(&buf);
607
608 *proxy_url = git__strdup(val);
609 GITERR_CHECK_ALLOC(*proxy_url);
610 return 0;
611 }
612
613 git_buf_free(&buf);
614 }
615
616 /* http.proxy config setting */
617 if (!git_config_get_string(&val, cfg, "http.proxy") &&
618 val && ('\0' != *val)) {
619 *proxy_url = git__strdup(val);
620 GITERR_CHECK_ALLOC(*proxy_url);
621 return 0;
622 }
623
624 /* HTTP_PROXY / HTTPS_PROXY environment variables */
625 val = use_ssl ? getenv("HTTPS_PROXY") : getenv("HTTP_PROXY");
626
627 if (val && ('\0' != *val)) {
628 *proxy_url = git__strdup(val);
629 GITERR_CHECK_ALLOC(*proxy_url);
630 return 0;
631 }
632
633 return 0;
634}
635
d8488457
CMN
636static int store_refs(git_remote_head *head, void *payload)
637{
638 git_vector *refs = (git_vector *)payload;
639
640 return git_vector_insert(refs, head);
641}
642
643static int dwim_refspecs(git_vector *refspecs, git_vector *refs)
644{
645 git_buf buf = GIT_BUF_INIT;
646 git_refspec *spec;
647 size_t i, j, pos;
648 git_remote_head key;
649
650 const char* formatters[] = {
651 GIT_REFS_DIR "%s",
652 GIT_REFS_TAGS_DIR "%s",
653 GIT_REFS_HEADS_DIR "%s",
654 NULL
655 };
656
657 git_vector_foreach(refspecs, i, spec) {
658 if (spec->dwim)
659 continue;
660
661 /* shorthand on the lhs */
662 if (git__prefixcmp(spec->src, GIT_REFS_DIR)) {
663 for (j = 0; formatters[j]; j++) {
664 git_buf_clear(&buf);
665 if (git_buf_printf(&buf, formatters[j], spec->src) < 0)
666 return -1;
667
668 key.name = (char *) git_buf_cstr(&buf);
669 if (!git_vector_search(&pos, refs, &key)) {
670 /* we found something to match the shorthand, set src to that */
671 git__free(spec->src);
672 spec->src = git_buf_detach(&buf);
673 }
674 }
675 }
676
677 if (spec->dst && git__prefixcmp(spec->dst, GIT_REFS_DIR)) {
678 /* if it starts with "remotes" then we just prepend "refs/" */
679 if (!git__prefixcmp(spec->dst, "remotes/")) {
680 git_buf_puts(&buf, GIT_REFS_DIR);
681 } else {
682 git_buf_puts(&buf, GIT_REFS_HEADS_DIR);
683 }
684
685 if (git_buf_puts(&buf, spec->dst) < 0)
686 return -1;
687
688 git__free(spec->dst);
689 spec->dst = git_buf_detach(&buf);
690 }
691
692 spec->dwim = 1;
693 }
694
9c5d4b2e 695 git_buf_free(&buf);
d8488457
CMN
696 return 0;
697}
698
699static int remote_head_cmp(const void *_a, const void *_b)
700{
701 const git_remote_head *a = (git_remote_head *) _a;
702 const git_remote_head *b = (git_remote_head *) _b;
703
704 return git__strcmp_cb(a->name, b->name);
705}
706
216863c4
BS
707int git_remote_download(
708 git_remote *remote,
7d222e13 709 git_transfer_progress_callback progress_cb,
216863c4 710 void *progress_payload)
48a65a07 711{
95057b85 712 int error;
d8488457 713 git_vector refs;
95057b85 714
1e3b8ed5 715 assert(remote);
4bef3565 716
d8488457
CMN
717 if (git_vector_init(&refs, 16, remote_head_cmp) < 0)
718 return -1;
719
720 if (git_remote_ls(remote, store_refs, &refs) < 0) {
721 return -1;
722 }
723
724 error = dwim_refspecs(&remote->refspecs, &refs);
725 git_vector_free(&refs);
726 if (error < 0)
727 return -1;
728
95057b85 729 if ((error = git_fetch_negotiate(remote)) < 0)
4376f7f6 730 return error;
95057b85 731
1e3b8ed5 732 return git_fetch_download_pack(remote, progress_cb, progress_payload);
48a65a07
CMN
733}
734
b0f6e45d
ET
735static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *update_heads, const char *fetchspec_src)
736{
737 unsigned int i;
738 git_remote_head *remote_ref;
739
740 assert(update_heads && fetchspec_src);
741
742 *out = NULL;
7d4b65f6 743
744 git_vector_foreach(update_heads, i, remote_ref) {
745 if (strcmp(remote_ref->name, fetchspec_src) == 0) {
746 *out = remote_ref;
747 break;
b0f6e45d
ET
748 }
749 }
750
751 return 0;
752}
753
4330ab26 754static int remote_head_for_ref(git_remote_head **out, git_refspec *spec, git_vector *update_heads, git_reference *ref)
b0f6e45d
ET
755{
756 git_reference *resolved_ref = NULL;
757 git_reference *tracking_ref = NULL;
758 git_buf remote_name = GIT_BUF_INIT;
759 int error = 0;
760
4330ab26 761 assert(out && spec && ref);
b0f6e45d
ET
762
763 *out = NULL;
764
765 if ((error = git_reference_resolve(&resolved_ref, ref)) < 0 ||
766 (!git_reference_is_branch(resolved_ref)) ||
a258d8e3 767 (error = git_branch_upstream(&tracking_ref, resolved_ref)) < 0 ||
4330ab26 768 (error = git_refspec_transform_l(&remote_name, spec, git_reference_name(tracking_ref))) < 0) {
b0f6e45d
ET
769 /* Not an error if HEAD is orphaned or no tracking branch */
770 if (error == GIT_ENOTFOUND)
771 error = 0;
772
773 goto cleanup;
774 }
775
776 error = remote_head_for_fetchspec_src(out, update_heads, git_buf_cstr(&remote_name));
777
778cleanup:
779 git_reference_free(tracking_ref);
780 git_reference_free(resolved_ref);
781 git_buf_free(&remote_name);
782 return error;
783}
784
4330ab26 785static int git_remote_write_fetchhead(git_remote *remote, git_refspec *spec, git_vector *update_heads)
b0f6e45d 786{
b0f6e45d
ET
787 git_reference *head_ref = NULL;
788 git_fetchhead_ref *fetchhead_ref;
789 git_remote_head *remote_ref, *merge_remote_ref;
790 git_vector fetchhead_refs;
791 bool include_all_fetchheads;
792 unsigned int i = 0;
793 int error = 0;
794
795 assert(remote);
796
404eadb0
CMN
797 /* no heads, nothing to do */
798 if (update_heads->length == 0)
799 return 0;
800
b0f6e45d
ET
801 if (git_vector_init(&fetchhead_refs, update_heads->length, git_fetchhead_ref_cmp) < 0)
802 return -1;
803
804 /* Iff refspec is * (but not subdir slash star), include tags */
805 include_all_fetchheads = (strcmp(GIT_REFS_HEADS_DIR "*", git_refspec_src(spec)) == 0);
806
807 /* Determine what to merge: if refspec was a wildcard, just use HEAD */
808 if (git_refspec_is_wildcard(spec)) {
809 if ((error = git_reference_lookup(&head_ref, remote->repo, GIT_HEAD_FILE)) < 0 ||
4330ab26 810 (error = remote_head_for_ref(&merge_remote_ref, spec, update_heads, head_ref)) < 0)
b0f6e45d
ET
811 goto cleanup;
812 } else {
813 /* If we're fetching a single refspec, that's the only thing that should be in FETCH_HEAD. */
814 if ((error = remote_head_for_fetchspec_src(&merge_remote_ref, update_heads, git_refspec_src(spec))) < 0)
815 goto cleanup;
816 }
817
818 /* Create the FETCH_HEAD file */
7d4b65f6 819 git_vector_foreach(update_heads, i, remote_ref) {
b0f6e45d
ET
820 int merge_this_fetchhead = (merge_remote_ref == remote_ref);
821
822 if (!include_all_fetchheads &&
823 !git_refspec_src_matches(spec, remote_ref->name) &&
824 !merge_this_fetchhead)
825 continue;
826
827 if (git_fetchhead_ref_create(&fetchhead_ref,
828 &remote_ref->oid,
829 merge_this_fetchhead,
830 remote_ref->name,
831 git_remote_url(remote)) < 0)
832 goto cleanup;
833
834 if (git_vector_insert(&fetchhead_refs, fetchhead_ref) < 0)
835 goto cleanup;
836 }
837
838 git_fetchhead_write(remote->repo, &fetchhead_refs);
839
840cleanup:
841 for (i = 0; i < fetchhead_refs.length; ++i)
842 git_fetchhead_ref_free(fetchhead_refs.contents[i]);
843
844 git_vector_free(&fetchhead_refs);
845 git_reference_free(head_ref);
846
847 return error;
848}
849
4330ab26 850static int update_tips_for_spec(git_remote *remote, git_refspec *spec, git_vector *refs)
441f57c2 851{
a37ddf7e 852 int error = 0, autotag;
517bda19 853 unsigned int i = 0;
97769280 854 git_buf refname = GIT_BUF_INIT;
f184836b 855 git_oid old;
a37ddf7e 856 git_odb *odb;
441f57c2
CMN
857 git_remote_head *head;
858 git_reference *ref;
a37ddf7e 859 git_refspec tagspec;
4330ab26 860 git_vector update_heads;
441f57c2 861
4bef3565
VM
862 assert(remote);
863
acd17006 864 if (git_repository_odb__weakptr(&odb, remote->repo) < 0)
a37ddf7e
CMN
865 return -1;
866
3230a44f 867 if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
a37ddf7e
CMN
868 return -1;
869
41fb1ca0 870 /* Make a copy of the transport's refs */
4330ab26 871 if (git_vector_init(&update_heads, 16, NULL) < 0)
41fb1ca0 872 return -1;
585a2eb7 873
41fb1ca0 874 /* Let's go find HEAD, if it exists. Check only the first ref in the vector. */
4330ab26
CMN
875 if (refs->length > 0) {
876 head = git_vector_get(refs, 0);
41fb1ca0
PK
877
878 if (!strcmp(head->name, GIT_HEAD_FILE)) {
2508cc66 879 if (git_reference_create(&ref, remote->repo, GIT_FETCH_HEAD_FILE, &head->oid, 1) < 0)
41fb1ca0
PK
880 goto on_error;
881
882 i = 1;
883 git_reference_free(ref);
884 }
517bda19
CMN
885 }
886
4330ab26
CMN
887 for (; i < refs->length; ++i) {
888 head = git_vector_get(refs, i);
9063be1f 889 autotag = 0;
517bda19 890
a37ddf7e
CMN
891 /* Ignore malformed ref names (which also saves us from tag^{} */
892 if (!git_reference_is_valid_name(head->name))
893 continue;
894
d8488457 895 if (git_refspec_src_matches(spec, head->name) && spec->dst) {
a37ddf7e
CMN
896 if (git_refspec_transform_r(&refname, spec, head->name) < 0)
897 goto on_error;
898 } else if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
3230a44f
CMN
899
900 if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_ALL)
901 autotag = 1;
a37ddf7e
CMN
902
903 if (!git_refspec_src_matches(&tagspec, head->name))
904 continue;
905
906 git_buf_clear(&refname);
907 if (git_buf_puts(&refname, head->name) < 0)
908 goto on_error;
909 } else {
910 continue;
911 }
912
913 if (autotag && !git_odb_exists(odb, &head->oid))
914 continue;
f184836b 915
b0f6e45d
ET
916 if (git_vector_insert(&update_heads, head) < 0)
917 goto on_error;
918
2508cc66 919 error = git_reference_name_to_id(&old, remote->repo, refname.ptr);
904b67e6 920 if (error < 0 && error != GIT_ENOTFOUND)
f184836b
CMN
921 goto on_error;
922
904b67e6 923 if (error == GIT_ENOTFOUND)
f184836b
CMN
924 memset(&old, 0, GIT_OID_RAWSZ);
925
b7f167da 926 if (!git_oid__cmp(&old, &head->oid))
f184836b 927 continue;
441f57c2 928
a37ddf7e 929 /* In autotag mode, don't overwrite any locally-existing tags */
2508cc66 930 error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag);
a37ddf7e 931 if (error < 0 && error != GIT_EEXISTS)
944d250f 932 goto on_error;
39157563
CMN
933
934 git_reference_free(ref);
f184836b 935
b3aaa7a7 936 if (remote->callbacks.update_tips != NULL) {
df705148 937 if (remote->callbacks.update_tips(refname.ptr, &old, &head->oid, remote->callbacks.payload) < 0)
f184836b
CMN
938 goto on_error;
939 }
441f57c2
CMN
940 }
941
b0f6e45d 942 if (git_remote_update_fetchhead(remote) &&
4330ab26 943 (error = git_remote_write_fetchhead(remote, spec, &update_heads)) < 0)
b0f6e45d
ET
944 goto on_error;
945
b0f6e45d 946 git_vector_free(&update_heads);
a37ddf7e 947 git_refspec__free(&tagspec);
97769280 948 git_buf_free(&refname);
f184836b
CMN
949 return 0;
950
951on_error:
b0f6e45d 952 git_vector_free(&update_heads);
a37ddf7e 953 git_refspec__free(&tagspec);
f184836b
CMN
954 git_buf_free(&refname);
955 return -1;
97769280 956
441f57c2
CMN
957}
958
4330ab26
CMN
959int git_remote_update_tips(git_remote *remote)
960{
961 git_refspec *spec;
962 git_vector refs;
963 size_t i;
964
965 if (git_vector_init(&refs, 16, NULL) < 0)
966 return -1;
967
d8488457 968 if (git_remote_ls(remote, store_refs, &refs) < 0)
4330ab26
CMN
969 goto on_error;
970
971 git_vector_foreach(&remote->refspecs, i, spec) {
972 if (spec->push)
973 continue;
974
975 if (update_tips_for_spec(remote, spec, &refs) < 0)
976 goto on_error;
977 }
978
979 git_vector_free(&refs);
980 return 0;
981
982on_error:
983 git_vector_free(&refs);
984 return -1;
985}
986
6ac3b707
CMN
987int git_remote_connected(git_remote *remote)
988{
4bef3565 989 assert(remote);
41fb1ca0
PK
990
991 if (!remote->transport || !remote->transport->is_connected)
992 return 0;
993
994 /* Ask the transport if it's connected. */
613d5eb9 995 return remote->transport->is_connected(remote->transport);
6ac3b707
CMN
996}
997
f0d2ddbb
CMN
998void git_remote_stop(git_remote *remote)
999{
613d5eb9
PK
1000 assert(remote);
1001
1002 if (remote->transport && remote->transport->cancel)
41fb1ca0 1003 remote->transport->cancel(remote->transport);
f0d2ddbb
CMN
1004}
1005
4cf01e9a
CMN
1006void git_remote_disconnect(git_remote *remote)
1007{
4bef3565
VM
1008 assert(remote);
1009
41fb1ca0
PK
1010 if (git_remote_connected(remote))
1011 remote->transport->close(remote->transport);
4cf01e9a
CMN
1012}
1013
9c82357b
CMN
1014void git_remote_free(git_remote *remote)
1015{
4330ab26 1016 git_refspec *spec;
4330ab26
CMN
1017 size_t i;
1018
2aae2188
CMN
1019 if (remote == NULL)
1020 return;
1021
42ea35c0
MS
1022 if (remote->transport != NULL) {
1023 git_remote_disconnect(remote);
1024
1025 remote->transport->free(remote->transport);
1026 remote->transport = NULL;
1027 }
1028
1029 git_vector_free(&remote->refs);
1030
4330ab26
CMN
1031 git_vector_foreach(&remote->refspecs, i, spec) {
1032 git_refspec__free(spec);
1033 git__free(spec);
1034 }
1035 git_vector_free(&remote->refspecs);
1036
3286c408 1037 git__free(remote->url);
3ed4b501 1038 git__free(remote->pushurl);
3286c408 1039 git__free(remote->name);
3286c408 1040 git__free(remote);
9c82357b 1041}
8171998f
CMN
1042
1043struct cb_data {
1044 git_vector *list;
1045 regex_t *preg;
1046};
1047
a1abe66a 1048static int remote_list_cb(const git_config_entry *entry, void *data_)
8171998f
CMN
1049{
1050 struct cb_data *data = (struct cb_data *)data_;
1051 size_t nmatch = 2;
1052 regmatch_t pmatch[2];
a1abe66a 1053 const char *name = entry->name;
8171998f
CMN
1054
1055 if (!regexec(data->preg, name, nmatch, pmatch, 0)) {
1056 char *remote_name = git__strndup(&name[pmatch[1].rm_so], pmatch[1].rm_eo - pmatch[1].rm_so);
4376f7f6 1057 GITERR_CHECK_ALLOC(remote_name);
8171998f 1058
4376f7f6
CMN
1059 if (git_vector_insert(data->list, remote_name) < 0)
1060 return -1;
8171998f
CMN
1061 }
1062
4376f7f6 1063 return 0;
8171998f
CMN
1064}
1065
1066int git_remote_list(git_strarray *remotes_list, git_repository *repo)
1067{
1068 git_config *cfg;
1069 git_vector list;
1070 regex_t preg;
1071 struct cb_data data;
1072 int error;
1073
4376f7f6
CMN
1074 if (git_repository_config__weakptr(&cfg, repo) < 0)
1075 return -1;
8171998f 1076
4376f7f6
CMN
1077 if (git_vector_init(&list, 4, NULL) < 0)
1078 return -1;
8171998f 1079
4376f7f6
CMN
1080 if (regcomp(&preg, "^remote\\.(.*)\\.url$", REG_EXTENDED) < 0) {
1081 giterr_set(GITERR_OS, "Remote catch regex failed to compile");
1082 return -1;
1083 }
8171998f
CMN
1084
1085 data.list = &list;
1086 data.preg = &preg;
1087 error = git_config_foreach(cfg, remote_list_cb, &data);
1088 regfree(&preg);
4376f7f6 1089 if (error < 0) {
8171998f
CMN
1090 size_t i;
1091 char *elem;
1092 git_vector_foreach(&list, i, elem) {
2bc8fa02 1093 git__free(elem);
8171998f
CMN
1094 }
1095
1096 git_vector_free(&list);
e4607392
RB
1097
1098 /* cb error is converted to GIT_EUSER by git_config_foreach */
1099 if (error == GIT_EUSER)
1100 error = -1;
1101
8171998f
CMN
1102 return error;
1103 }
1104
1105 remotes_list->strings = (char **)list.contents;
1106 remotes_list->count = list.length;
1107
4376f7f6 1108 return 0;
8171998f 1109}
a209a025 1110
250b95b2
CMN
1111void git_remote_check_cert(git_remote *remote, int check)
1112{
1113 assert(remote);
1114
1115 remote->check_cert = check;
1116}
b3aaa7a7 1117
9267ff58 1118int git_remote_set_callbacks(git_remote *remote, git_remote_callbacks *callbacks)
b3aaa7a7
CMN
1119{
1120 assert(remote && callbacks);
1121
c7231c45 1122 GITERR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
9267ff58 1123
b3aaa7a7 1124 memcpy(&remote->callbacks, callbacks, sizeof(git_remote_callbacks));
e03e71da 1125
41fb1ca0
PK
1126 if (remote->transport && remote->transport->set_callbacks)
1127 remote->transport->set_callbacks(remote->transport,
1128 remote->callbacks.progress,
1129 NULL,
df705148 1130 remote->callbacks.payload);
9267ff58
BS
1131
1132 return 0;
41fb1ca0
PK
1133}
1134
091361f5
PK
1135void git_remote_set_cred_acquire_cb(
1136 git_remote *remote,
59bccf33
BS
1137 git_cred_acquire_cb cred_acquire_cb,
1138 void *payload)
091361f5
PK
1139{
1140 assert(remote);
1141
1142 remote->cred_acquire_cb = cred_acquire_cb;
59bccf33 1143 remote->cred_acquire_payload = payload;
091361f5
PK
1144}
1145
41fb1ca0
PK
1146int git_remote_set_transport(git_remote *remote, git_transport *transport)
1147{
1148 assert(remote && transport);
1149
c7231c45 1150 GITERR_CHECK_VERSION(transport, GIT_TRANSPORT_VERSION, "git_transport");
10711769 1151
e03e71da 1152 if (remote->transport) {
41fb1ca0
PK
1153 giterr_set(GITERR_NET, "A transport is already bound to this remote");
1154 return -1;
e03e71da 1155 }
41fb1ca0
PK
1156
1157 remote->transport = transport;
1158 return 0;
b3aaa7a7 1159}
f70e466f 1160
67dad09b 1161const git_transfer_progress* git_remote_stats(git_remote *remote)
d57c47dc
BS
1162{
1163 assert(remote);
1164 return &remote->stats;
1165}
1166
f4a62c30 1167git_remote_autotag_option_t git_remote_autotag(git_remote *remote)
f70e466f
CMN
1168{
1169 return remote->download_tags;
1170}
1171
f4a62c30 1172void git_remote_set_autotag(git_remote *remote, git_remote_autotag_option_t value)
f70e466f
CMN
1173{
1174 remote->download_tags = value;
1175}
fcccf304 1176
fcccf304 1177static int rename_remote_config_section(
1178 git_repository *repo,
1179 const char *old_name,
1180 const char *new_name)
1181{
1182 git_buf old_section_name = GIT_BUF_INIT,
1183 new_section_name = GIT_BUF_INIT;
1184 int error = -1;
1185
1186 if (git_buf_printf(&old_section_name, "remote.%s", old_name) < 0)
1187 goto cleanup;
1188
1189 if (git_buf_printf(&new_section_name, "remote.%s", new_name) < 0)
1190 goto cleanup;
1191
1192 error = git_config_rename_section(
1193 repo,
1194 git_buf_cstr(&old_section_name),
1195 git_buf_cstr(&new_section_name));
1196
1197cleanup:
1198 git_buf_free(&old_section_name);
1199 git_buf_free(&new_section_name);
1200
1201 return error;
1202}
1203
1204struct update_data
1205{
1206 git_config *config;
1207 const char *old_remote_name;
1208 const char *new_remote_name;
1209};
1210
1211static int update_config_entries_cb(
1212 const git_config_entry *entry,
1213 void *payload)
1214{
1215 struct update_data *data = (struct update_data *)payload;
1216
1217 if (strcmp(entry->value, data->old_remote_name))
1218 return 0;
1219
1220 return git_config_set_string(
1221 data->config,
1222 entry->name,
1223 data->new_remote_name);
1224}
1225
1226static int update_branch_remote_config_entry(
1227 git_repository *repo,
1228 const char *old_name,
1229 const char *new_name)
1230{
1231 git_config *config;
1232 struct update_data data;
1233
1234 if (git_repository_config__weakptr(&config, repo) < 0)
1235 return -1;
1236
1237 data.config = config;
1238 data.old_remote_name = old_name;
1239 data.new_remote_name = new_name;
1240
1241 return git_config_foreach_match(
1242 config,
1243 "branch\\..+\\.remote",
1244 update_config_entries_cb, &data);
1245}
1246
1247static int rename_cb(const char *ref, void *data)
1248{
1249 if (git__prefixcmp(ref, GIT_REFS_REMOTES_DIR))
1250 return 0;
1251
1252 return git_vector_insert((git_vector *)data, git__strdup(ref));
1253}
1254
1255static int rename_one_remote_reference(
1256 git_repository *repo,
1257 const char *reference_name,
1258 const char *old_remote_name,
1259 const char *new_remote_name)
1260{
6cfbbf7e 1261 int error = -1;
fcccf304 1262 git_buf new_name = GIT_BUF_INIT;
1263 git_reference *reference = NULL;
d00d5464 1264 git_reference *newref = NULL;
fcccf304 1265
1266 if (git_buf_printf(
1267 &new_name,
1268 GIT_REFS_REMOTES_DIR "%s%s",
1269 new_remote_name,
1270 reference_name + strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name)) < 0)
1271 return -1;
1272
1273 if (git_reference_lookup(&reference, repo, reference_name) < 0)
1274 goto cleanup;
1275
d00d5464
ET
1276 error = git_reference_rename(&newref, reference, git_buf_cstr(&new_name), 0);
1277 git_reference_free(reference);
fcccf304 1278
1279cleanup:
d00d5464 1280 git_reference_free(newref);
fcccf304 1281 git_buf_free(&new_name);
1282 return error;
1283}
1284
1285static int rename_remote_references(
1286 git_repository *repo,
1287 const char *old_name,
1288 const char *new_name)
1289{
1290 git_vector refnames;
1291 int error = -1;
1292 unsigned int i;
1293 char *name;
1294
1295 if (git_vector_init(&refnames, 8, NULL) < 0)
1296 goto cleanup;
1297
1298 if (git_reference_foreach(
1299 repo,
1300 GIT_REF_LISTALL,
1301 rename_cb,
1302 &refnames) < 0)
1303 goto cleanup;
1304
1305 git_vector_foreach(&refnames, i, name) {
1306 if ((error = rename_one_remote_reference(repo, name, old_name, new_name)) < 0)
1307 goto cleanup;
1308 }
1309
1310 error = 0;
1311cleanup:
1312 git_vector_foreach(&refnames, i, name) {
1313 git__free(name);
1314 }
1315
1316 git_vector_free(&refnames);
1317 return error;
1318}
1319
1320static int rename_fetch_refspecs(
1321 git_remote *remote,
1322 const char *new_name,
1323 int (*callback)(const char *problematic_refspec, void *payload),
1324 void *payload)
1325{
1326 git_config *config;
4330ab26 1327 git_buf base = GIT_BUF_INIT, var = GIT_BUF_INIT, val = GIT_BUF_INIT;
1be680c4 1328 const git_refspec *spec;
4330ab26 1329 size_t i;
fcccf304 1330 int error = -1;
1331
4330ab26
CMN
1332 if (git_buf_printf(&base, "+refs/heads/*:refs/remotes/%s/*", remote->name) < 0)
1333 goto cleanup;
fcccf304 1334
1be680c4 1335 git_vector_foreach(&remote->refspecs, i, spec) {
4330ab26
CMN
1336 if (spec->push)
1337 continue;
fcccf304 1338
4330ab26
CMN
1339 /* Every refspec is a problem refspec for an in-memory remote */
1340 if (!remote->name) {
1be680c4 1341 if (callback(spec->string, payload) < 0) {
4330ab26
CMN
1342 error = GIT_EUSER;
1343 goto cleanup;
1344 }
fcccf304 1345
4330ab26
CMN
1346 continue;
1347 }
fcccf304 1348
4330ab26 1349 /* Does the dst part of the refspec follow the extected standard format? */
1be680c4
CMN
1350 if (strcmp(git_buf_cstr(&base), spec->string)) {
1351 if (callback(spec->string, payload) < 0) {
4330ab26
CMN
1352 error = GIT_EUSER;
1353 goto cleanup;
1354 }
fcccf304 1355
4330ab26
CMN
1356 continue;
1357 }
fcccf304 1358
4330ab26
CMN
1359 /* If we do want to move it to the new section */
1360 if (git_buf_printf(&val, "+refs/heads/*:refs/remotes/%s/*", new_name) < 0)
fcccf304 1361 goto cleanup;
1362
4330ab26
CMN
1363 if (git_buf_printf(&var, "remote.%s.fetch", new_name) < 0)
1364 goto cleanup;
fcccf304 1365
4330ab26
CMN
1366 if (git_repository_config__weakptr(&config, remote->repo) < 0)
1367 goto cleanup;
fcccf304 1368
4330ab26
CMN
1369 if (git_config_set_string(config, git_buf_cstr(&var), git_buf_cstr(&val)) < 0)
1370 goto cleanup;
1371 }
fcccf304 1372
4330ab26 1373 error = 0;
fcccf304 1374
1375cleanup:
4330ab26
CMN
1376 git_buf_free(&base);
1377 git_buf_free(&var);
1378 git_buf_free(&val);
fcccf304 1379 return error;
1380}
1381
1382int git_remote_rename(
1383 git_remote *remote,
1384 const char *new_name,
df705148 1385 git_remote_rename_problem_cb callback,
fcccf304 1386 void *payload)
1387{
1388 int error;
1389
1390 assert(remote && new_name);
1391
c07b52df 1392 if (!remote->name) {
79000951
BS
1393 giterr_set(GITERR_INVALID, "Can't rename an in-memory remote.");
1394 return GIT_EINVALIDSPEC;
1395 }
1396
fcccf304 1397 if ((error = ensure_remote_name_is_valid(new_name)) < 0)
1398 return error;
1399
a71c27cc
BS
1400 if (remote->repo) {
1401 if ((error = ensure_remote_doesnot_exist(remote->repo, new_name)) < 0)
fcccf304 1402 return error;
1403
a71c27cc
BS
1404 if (!remote->name) {
1405 if ((error = rename_fetch_refspecs(
1406 remote,
1407 new_name,
1408 callback,
1409 payload)) < 0)
1410 return error;
fcccf304 1411
a71c27cc 1412 remote->name = git__strdup(new_name);
fcccf304 1413
c07b52df 1414 if (!remote->name) return 0;
a71c27cc
BS
1415 return git_remote_save(remote);
1416 }
fcccf304 1417
a71c27cc
BS
1418 if ((error = rename_remote_config_section(
1419 remote->repo,
1420 remote->name,
1421 new_name)) < 0)
1422 return error;
fcccf304 1423
a71c27cc
BS
1424 if ((error = update_branch_remote_config_entry(
1425 remote->repo,
1426 remote->name,
1427 new_name)) < 0)
1428 return error;
fcccf304 1429
a71c27cc
BS
1430 if ((error = rename_remote_references(
1431 remote->repo,
1432 remote->name,
1433 new_name)) < 0)
1434 return error;
1435
1436 if ((error = rename_fetch_refspecs(
1437 remote,
1438 new_name,
1439 callback,
1440 payload)) < 0)
1441 return error;
1442 }
fcccf304 1443
1444 git__free(remote->name);
1445 remote->name = git__strdup(new_name);
1446
1447 return 0;
1448}
b0f6e45d
ET
1449
1450int git_remote_update_fetchhead(git_remote *remote)
1451{
1452 return remote->update_fetchhead;
1453}
1454
1455void git_remote_set_update_fetchhead(git_remote *remote, int value)
1456{
1457 remote->update_fetchhead = value;
1458}
2bca5b67 1459
1460int git_remote_is_valid_name(
1461 const char *remote_name)
1462{
1463 git_buf buf = GIT_BUF_INIT;
1464 git_refspec refspec;
1465 int error = -1;
1466
1467 if (!remote_name || *remote_name == '\0')
1468 return 0;
1469
1470 git_buf_printf(&buf, "refs/heads/test:refs/remotes/%s/test", remote_name);
1471 error = git_refspec__parse(&refspec, git_buf_cstr(&buf), true);
1472
1473 git_buf_free(&buf);
1474 git_refspec__free(&refspec);
1475
1476 giterr_clear();
1477 return error == 0;
1478}
4330ab26
CMN
1479
1480git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname)
1481{
1482 git_refspec *spec;
1483 size_t i;
1484
1485 git_vector_foreach(&remote->refspecs, i, spec) {
1486 if (spec->push)
1487 continue;
1488
1489 if (git_refspec_src_matches(spec, refname))
1490 return spec;
1491 }
1492
1493 return NULL;
1494}
1495
1496git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *refname)
1497{
1498 git_refspec *spec;
1499 size_t i;
1500
1501 git_vector_foreach(&remote->refspecs, i, spec) {
1502 if (spec->push)
1503 continue;
1504
1505 if (git_refspec_dst_matches(spec, refname))
1506 return spec;
1507 }
1508
1509 return NULL;
1510}
1511
1512void git_remote_clear_refspecs(git_remote *remote)
1513{
1514 git_refspec *spec;
4330ab26
CMN
1515 size_t i;
1516
1517 git_vector_foreach(&remote->refspecs, i, spec) {
1518 git_refspec__free(spec);
1be680c4 1519 git__free(spec);
4330ab26
CMN
1520 }
1521 git_vector_clear(&remote->refspecs);
4330ab26
CMN
1522}
1523
bc6374ea 1524int git_remote_add_fetch(git_remote *remote, const char *refspec)
4330ab26
CMN
1525{
1526 return add_refspec(remote, refspec, true);
1527}
1528
bc6374ea 1529int git_remote_add_push(git_remote *remote, const char *refspec)
4330ab26
CMN
1530{
1531 return add_refspec(remote, refspec, false);
1532}
bc6374ea
CMN
1533
1534static int copy_refspecs(git_strarray *array, git_remote *remote, int push)
1535{
1536 size_t i;
1537 git_vector refspecs;
1538 git_refspec *spec;
1539 char *dup;
1540
1541 if (git_vector_init(&refspecs, remote->refspecs.length, NULL) < 0)
1542 return -1;
1543
1544 git_vector_foreach(&remote->refspecs, i, spec) {
1545 if (spec->push != push)
1546 continue;
1547
1be680c4 1548 if ((dup = git__strdup(spec->string)) == NULL)
bc6374ea 1549 goto on_error;
bc6374ea
CMN
1550
1551 if (git_vector_insert(&refspecs, dup) < 0) {
1552 git__free(dup);
1553 goto on_error;
1554 }
1555 }
1556
1557 array->strings = (char **)refspecs.contents;
1558 array->count = refspecs.length;
1559
1560 return 0;
1561
1562on_error:
1563 git_vector_foreach(&refspecs, i, dup)
1564 git__free(dup);
1565 git_vector_free(&refspecs);
1566
1567 return -1;
1568}
1569
1570int git_remote_get_fetch_refspecs(git_strarray *array, git_remote *remote)
1571{
1572 return copy_refspecs(array, remote, false);
1573}
1574
1575int git_remote_get_push_refspecs(git_strarray *array, git_remote *remote)
1576{
1577 return copy_refspecs(array, remote, true);
1578}
1ffd0806
CMN
1579
1580size_t git_remote_refspec_count(git_remote *remote)
1581{
1582 return remote->refspecs.length;
1583}
1584
1585const git_refspec *git_remote_get_refspec(git_remote *remote, size_t n)
1586{
1587 return git_vector_get(&remote->refspecs, n);
1588}
1589
1590int git_remote_remove_refspec(git_remote *remote, size_t n)
1591{
1592 git_refspec *spec;
1593
1594 assert(remote);
1595
1596 spec = git_vector_get(&remote->refspecs, n);
1597 if (spec) {
1598 git_refspec__free(spec);
1599 git__free(spec);
1600 }
1601
1602 return git_vector_remove(&remote->refspecs, n);
1603}