]> git.proxmox.com Git - libgit2.git/blame - src/remote.c
Include stacktrace summary in memory leak output.
[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 12
157cef10 13#include "common.h"
9c82357b
CMN
14#include "config.h"
15#include "repository.h"
16#include "remote.h"
e1d88030 17#include "fetch.h"
441f57c2 18#include "refs.h"
b0f6e45d
ET
19#include "refspec.h"
20#include "fetchhead.h"
fe794b2e 21#include "push.h"
9c82357b 22
22261344
CMN
23#define CONFIG_URL_FMT "remote.%s.url"
24#define CONFIG_PUSHURL_FMT "remote.%s.pushurl"
25#define CONFIG_FETCH_FMT "remote.%s.fetch"
77254990 26#define CONFIG_PUSH_FMT "remote.%s.push"
35a8a8c5 27#define CONFIG_TAGOPT_FMT "remote.%s.tagopt"
22261344 28
af613ecd 29static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs);
1ef3f0ce 30static int lookup_remote_prune_config(git_remote *remote, git_config *config, const char *name);
ec0c4c40 31char *apply_insteadof(git_config *config, const char *url, int direction);
af613ecd 32
3f894205 33static int add_refspec_to(git_vector *vector, const char *string, bool is_fetch)
9c82357b 34{
4330ab26 35 git_refspec *spec;
9c82357b 36
4330ab26
CMN
37 spec = git__calloc(1, sizeof(git_refspec));
38 GITERR_CHECK_ALLOC(spec);
39
1be680c4
CMN
40 if (git_refspec__parse(spec, string, is_fetch) < 0) {
41 git__free(spec);
42 return -1;
43 }
4330ab26
CMN
44
45 spec->push = !is_fetch;
3f894205 46 if (git_vector_insert(vector, spec) < 0) {
1be680c4
CMN
47 git_refspec__free(spec);
48 git__free(spec);
49 return -1;
50 }
9c82357b 51
4330ab26 52 return 0;
9c82357b
CMN
53}
54
3f894205
CMN
55static int add_refspec(git_remote *remote, const char *string, bool is_fetch)
56{
57 return add_refspec_to(&remote->refspecs, string, is_fetch);
58}
59
24f2f94e
CMN
60static int download_tags_value(git_remote *remote, git_config *cfg)
61{
9a97f49e 62 git_config_entry *ce;
24f2f94e
CMN
63 git_buf buf = GIT_BUF_INIT;
64 int error;
65
24f2f94e
CMN
66 if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
67 return -1;
68
9f77b3f6 69 error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false);
24f2f94e 70 git_buf_free(&buf);
24f2f94e 71
9f77b3f6
RB
72 if (!error && ce && ce->value) {
73 if (!strcmp(ce->value, "--no-tags"))
74 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
75 else if (!strcmp(ce->value, "--tags"))
76 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
bf6bebe2 77 }
24f2f94e 78
9a97f49e 79 git_config_entry_free(ce);
24f2f94e
CMN
80 return error;
81}
82
032ba9e4 83static int ensure_remote_name_is_valid(const char *name)
84{
2bca5b67 85 int error = 0;
032ba9e4 86
2bca5b67 87 if (!git_remote_is_valid_name(name)) {
032ba9e4 88 giterr_set(
89 GITERR_CONFIG,
183aa4f8 90 "'%s' is not a valid remote name.", name ? name : "(null)");
032ba9e4 91 error = GIT_EINVALIDSPEC;
92 }
93
94 return error;
95}
96
77254990
CMN
97static int write_add_refspec(git_repository *repo, const char *name, const char *refspec, bool fetch)
98{
99 git_config *cfg;
100 git_buf var = GIT_BUF_INIT;
c6e942fb 101 git_refspec spec;
77254990
CMN
102 const char *fmt;
103 int error;
104
105 if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
106 return error;
107
108 fmt = fetch ? CONFIG_FETCH_FMT : CONFIG_PUSH_FMT;
109
110 if ((error = ensure_remote_name_is_valid(name)) < 0)
111 return error;
112
c6e942fb
CMN
113 if ((error = git_refspec__parse(&spec, refspec, fetch)) < 0) {
114 if (giterr_last()->klass != GITERR_NOMEMORY)
115 error = GIT_EINVALIDSPEC;
116
117 return error;
118 }
119
120 git_refspec__free(&spec);
121
77254990
CMN
122 if ((error = git_buf_printf(&var, fmt, name)) < 0)
123 return error;
124
125 /*
126 * "$^" is a unmatcheable regexp: it will not match anything at all, so
127 * all values will be considered new and we will not replace any
128 * present value.
129 */
130 if ((error = git_config_set_multivar(cfg, var.ptr, "$^", refspec)) < 0) {
131 goto cleanup;
132 }
133
134cleanup:
135 git_buf_free(&var);
136 return 0;
137}
138
41698f22
CMN
139#if 0
140/* We could export this as a helper */
80fc7d6b 141static int get_check_cert(int *out, git_repository *repo)
af6dab7e
PK
142{
143 git_config *cfg;
144 const char *val;
80fc7d6b
ET
145 int error = 0;
146
147 assert(out && repo);
af6dab7e 148
80fc7d6b
ET
149 /* By default, we *DO* want to verify the certificate. */
150 *out = 1;
af6dab7e
PK
151
152 /* Go through the possible sources for SSL verification settings, from
153 * most specific to least specific. */
154
155 /* GIT_SSL_NO_VERIFY environment variable */
8f2a3d62 156 if ((val = getenv("GIT_SSL_NO_VERIFY")) != NULL)
80fc7d6b 157 return git_config_parse_bool(out, val);
af6dab7e
PK
158
159 /* http.sslVerify config setting */
80fc7d6b
ET
160 if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
161 return error;
af6dab7e 162
9f77b3f6 163 *out = git_config__get_bool_force(cfg, "http.sslverify", 1);
80fc7d6b 164 return 0;
af6dab7e 165}
41698f22 166#endif
af6dab7e 167
12f32d91
ET
168static int canonicalize_url(git_buf *out, const char *in)
169{
47a40d1d
CMN
170 if (in == NULL || strlen(in) == 0) {
171 giterr_set(GITERR_INVALID, "cannot set empty URL");
172 return GIT_EINVALIDSPEC;
173 }
12f32d91 174
47a40d1d 175#ifdef GIT_WIN32
12f32d91
ET
176 /* Given a UNC path like \\server\path, we need to convert this
177 * to //server/path for compatibility with core git.
178 */
179 if (in[0] == '\\' && in[1] == '\\' &&
180 (git__isalpha(in[2]) || git__isdigit(in[2]))) {
47a40d1d 181 const char *c;
12f32d91
ET
182 for (c = in; *c; c++)
183 git_buf_putc(out, *c == '\\' ? '/' : *c);
184
185 return git_buf_oom(out) ? -1 : 0;
186 }
187#endif
188
189 return git_buf_puts(out, in);
190}
191
874dcb25 192static int create_internal(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
778e1c73
CMN
193{
194 git_remote *remote;
a8846da7 195 git_config *config = NULL;
22261344
CMN
196 git_buf canonical_url = GIT_BUF_INIT;
197 git_buf var = GIT_BUF_INIT;
44f36f6e 198 int error = -1;
778e1c73 199
4bef3565 200 /* name is optional */
874dcb25 201 assert(out && repo && url);
617bfdf4 202
22261344
CMN
203 if ((error = git_repository_config__weakptr(&config, repo)) < 0)
204 return error;
205
59bccf33 206 remote = git__calloc(1, sizeof(git_remote));
4376f7f6 207 GITERR_CHECK_ALLOC(remote);
778e1c73 208
778e1c73 209 remote->repo = repo;
617bfdf4 210
12f32d91
ET
211 if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
212 canonicalize_url(&canonical_url, url) < 0)
44f36f6e 213 goto on_error;
d88d4311 214
ec0c4c40 215 remote->url = apply_insteadof(repo->_config, canonical_url.ptr, GIT_DIRECTION_FETCH);
778e1c73 216
617bfdf4
CMN
217 if (name != NULL) {
218 remote->name = git__strdup(name);
4376f7f6 219 GITERR_CHECK_ALLOC(remote->name);
22261344
CMN
220
221 if ((error = git_buf_printf(&var, CONFIG_URL_FMT, name)) < 0)
222 goto on_error;
223
ec0c4c40 224 if ((error = git_config_set_string(config, var.ptr, canonical_url.ptr)) < 0)
22261344 225 goto on_error;
617bfdf4
CMN
226 }
227
baaa8a44 228 if (fetch != NULL) {
77254990
CMN
229 if ((error = add_refspec(remote, fetch, true)) < 0)
230 goto on_error;
231
232 /* only write for non-anonymous remotes */
233 if (name && (error = write_add_refspec(repo, name, fetch, true)) < 0)
baaa8a44 234 goto on_error;
d3cd7da5 235
1ef3f0ce
DC
236 if ((error = git_repository_config_snapshot(&config, repo)) < 0)
237 goto on_error;
238
69f0032b 239 if ((error = lookup_remote_prune_config(remote, config, name)) < 0)
1ef3f0ce
DC
240 goto on_error;
241
d3cd7da5 242 /* Move the data over to where the matching functions can find them */
69f0032b 243 if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
d3cd7da5 244 goto on_error;
baaa8a44
CMN
245 }
246
35a8a8c5 247 /* A remote without a name doesn't download tags */
215af2cc 248 if (!name)
c648d4a8 249 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
35a8a8c5
CMN
250 else
251 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO;
252
c648d4a8 253
22261344
CMN
254 git_buf_free(&var);
255
778e1c73 256 *out = remote;
a8846da7 257 error = 0;
baaa8a44
CMN
258
259on_error:
a8846da7
ET
260 if (error)
261 git_remote_free(remote);
262
1ef3f0ce 263 git_config_free(config);
12f32d91 264 git_buf_free(&canonical_url);
22261344 265 git_buf_free(&var);
44f36f6e 266 return error;
778e1c73
CMN
267}
268
592f466c
BS
269static int ensure_remote_doesnot_exist(git_repository *repo, const char *name)
270{
271 int error;
272 git_remote *remote;
273
209425ce 274 error = git_remote_lookup(&remote, repo, name);
592f466c
BS
275
276 if (error == GIT_ENOTFOUND)
277 return 0;
278
279 if (error < 0)
280 return error;
281
282 git_remote_free(remote);
283
284 giterr_set(
285 GITERR_CONFIG,
286 "Remote '%s' already exists.", name);
287
288 return GIT_EEXISTS;
289}
290
f19304d2 291
874dcb25
BS
292int git_remote_create(git_remote **out, git_repository *repo, const char *name, const char *url)
293{
294 git_buf buf = GIT_BUF_INIT;
295 int error;
296
874dcb25
BS
297 if (git_buf_printf(&buf, "+refs/heads/*:refs/remotes/%s/*", name) < 0)
298 return -1;
299
a68e217f 300 error = git_remote_create_with_fetchspec(out, repo, name, url, git_buf_cstr(&buf));
874dcb25
BS
301 git_buf_free(&buf);
302
a68e217f 303 return error;
874dcb25
BS
304}
305
40b99d05
VG
306int git_remote_create_with_fetchspec(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
307{
40b99d05
VG
308 git_remote *remote = NULL;
309 int error;
310
311 if ((error = ensure_remote_name_is_valid(name)) < 0)
312 return error;
313
314 if ((error = ensure_remote_doesnot_exist(repo, name)) < 0)
315 return error;
874dcb25 316
0fe522d1 317 if (create_internal(&remote, repo, name, url, fetch) < 0)
874dcb25
BS
318 goto on_error;
319
c5193e3c 320 *out = remote;
321
874dcb25
BS
322 return 0;
323
324on_error:
c5193e3c 325 git_remote_free(remote);
874dcb25
BS
326 return -1;
327}
328
ae5b9362 329int git_remote_create_anonymous(git_remote **out, git_repository *repo, const char *url)
874dcb25 330{
ae5b9362 331 return create_internal(out, repo, NULL, url, NULL);
874dcb25
BS
332}
333
991b2840 334int git_remote_dup(git_remote **dest, git_remote *source)
40ef47dd 335{
70f7484d 336 size_t i;
991b2840 337 int error = 0;
70f7484d 338 git_refspec *spec;
40ef47dd
AS
339 git_remote *remote = git__calloc(1, sizeof(git_remote));
340 GITERR_CHECK_ALLOC(remote);
341
40ef47dd
AS
342 if (source->name != NULL) {
343 remote->name = git__strdup(source->name);
344 GITERR_CHECK_ALLOC(remote->name);
345 }
346
347 if (source->url != NULL) {
348 remote->url = git__strdup(source->url);
ec0c4c40 349 GITERR_CHECK_ALLOC(remote->url);
40ef47dd
AS
350 }
351
352 if (source->pushurl != NULL) {
353 remote->pushurl = git__strdup(source->pushurl);
1697cd6f 354 GITERR_CHECK_ALLOC(remote->pushurl);
40ef47dd
AS
355 }
356
357 remote->repo = source->repo;
40ef47dd 358 remote->download_tags = source->download_tags;
5f473947 359 remote->prune_refs = source->prune_refs;
40ef47dd 360
991b2840
AS
361 if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
362 git_vector_init(&remote->refspecs, 2, NULL) < 0 ||
363 git_vector_init(&remote->active_refspecs, 2, NULL) < 0) {
364 error = -1;
365 goto cleanup;
40ef47dd
AS
366 }
367
70f7484d
CMN
368 git_vector_foreach(&source->refspecs, i, spec) {
369 if ((error = add_refspec(remote, spec->string, !spec->push)) < 0)
370 goto cleanup;
371 }
991b2840 372
40ef47dd
AS
373 *dest = remote;
374
991b2840
AS
375cleanup:
376
991b2840
AS
377 if (error < 0)
378 git__free(remote);
379
380 return error;
40ef47dd
AS
381}
382
4330ab26
CMN
383struct refspec_cb_data {
384 git_remote *remote;
385 int fetch;
386};
387
388static int refspec_cb(const git_config_entry *entry, void *payload)
389{
96869a4e 390 struct refspec_cb_data *data = (struct refspec_cb_data *)payload;
25e0b157 391 return add_refspec(data->remote, entry->value, data->fetch);
4330ab26
CMN
392}
393
bf6bebe2 394static int get_optional_config(
c9ffa84b 395 bool *found, git_config *config, git_buf *buf,
396 git_config_foreach_cb cb, void *payload)
bf6bebe2
RB
397{
398 int error = 0;
399 const char *key = git_buf_cstr(buf);
400
401 if (git_buf_oom(buf))
402 return -1;
403
404 if (cb != NULL)
4efa3290 405 error = git_config_get_multivar_foreach(config, key, NULL, cb, payload);
bf6bebe2
RB
406 else
407 error = git_config_get_string(payload, config, key);
408
c9ffa84b 409 if (found)
410 *found = !error;
411
bf6bebe2
RB
412 if (error == GIT_ENOTFOUND) {
413 giterr_clear();
414 error = 0;
415 }
416
bf6bebe2
RB
417 return error;
418}
419
209425ce 420int git_remote_lookup(git_remote **out, git_repository *repo, const char *name)
9c82357b
CMN
421{
422 git_remote *remote;
f0f3a18a 423 git_buf buf = GIT_BUF_INIT;
9c82357b 424 const char *val;
4376f7f6 425 int error = 0;
9462c471 426 git_config *config;
96869a4e 427 struct refspec_cb_data data = { NULL };
c9ffa84b 428 bool optional_setting_found = false, found;
4330ab26 429
9462c471
VM
430 assert(out && repo && name);
431
032ba9e4 432 if ((error = ensure_remote_name_is_valid(name)) < 0)
433 return error;
434
ac99d86b 435 if ((error = git_repository_config_snapshot(&config, repo)) < 0)
29c4cb09 436 return error;
4bef3565 437
392702ee 438 remote = git__calloc(1, sizeof(git_remote));
4376f7f6 439 GITERR_CHECK_ALLOC(remote);
9c82357b 440
9c82357b 441 remote->name = git__strdup(name);
4376f7f6 442 GITERR_CHECK_ALLOC(remote->name);
9c82357b 443
25e0b157
RB
444 if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
445 git_vector_init(&remote->refspecs, 2, NULL) < 0 ||
2cdd5c57 446 git_vector_init(&remote->passive_refspecs, 2, NULL) < 0 ||
25e0b157 447 git_vector_init(&remote->active_refspecs, 2, NULL) < 0) {
2fb9d6de 448 error = -1;
449 goto cleanup;
450 }
d88d4311 451
25e0b157 452 if ((error = git_buf_printf(&buf, "remote.%s.url", name)) < 0)
2fb9d6de 453 goto cleanup;
9c82357b 454
c9ffa84b 455 if ((error = get_optional_config(&found, config, &buf, NULL, (void *)&val)) < 0)
9c82357b 456 goto cleanup;
bf6bebe2 457
c9ffa84b 458 optional_setting_found |= found;
459
9462c471 460 remote->repo = repo;
35a8a8c5 461 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO;
c9ffa84b 462
463 if (found && strlen(val) > 0) {
ec0c4c40 464 remote->url = apply_insteadof(config, val, GIT_DIRECTION_FETCH);
c9ffa84b 465 GITERR_CHECK_ALLOC(remote->url);
466 }
9c82357b 467
bf6bebe2 468 val = NULL;
3ed4b501 469 git_buf_clear(&buf);
bf6bebe2 470 git_buf_printf(&buf, "remote.%s.pushurl", name);
3ed4b501 471
c9ffa84b 472 if ((error = get_optional_config(&found, config, &buf, NULL, (void *)&val)) < 0)
3ed4b501 473 goto cleanup;
3ed4b501 474
c9ffa84b 475 optional_setting_found |= found;
476
477 if (!optional_setting_found) {
478 error = GIT_ENOTFOUND;
d723dbed 479 giterr_set(GITERR_CONFIG, "Remote '%s' does not exist.", name);
3ed4b501 480 goto cleanup;
c9ffa84b 481 }
3ed4b501 482
c9ffa84b 483 if (found && strlen(val) > 0) {
ec0c4c40 484 remote->pushurl = apply_insteadof(config, val, GIT_DIRECTION_PUSH);
3ed4b501
SC
485 GITERR_CHECK_ALLOC(remote->pushurl);
486 }
487
4330ab26
CMN
488 data.remote = remote;
489 data.fetch = true;
96869a4e 490
f0f3a18a 491 git_buf_clear(&buf);
bf6bebe2
RB
492 git_buf_printf(&buf, "remote.%s.fetch", name);
493
c9ffa84b 494 if ((error = get_optional_config(NULL, config, &buf, refspec_cb, &data)) < 0)
2fb9d6de 495 goto cleanup;
9c82357b 496
4330ab26 497 data.fetch = false;
bf6bebe2
RB
498 git_buf_clear(&buf);
499 git_buf_printf(&buf, "remote.%s.push", name);
9c82357b 500
c9ffa84b 501 if ((error = get_optional_config(NULL, config, &buf, refspec_cb, &data)) < 0)
9c82357b
CMN
502 goto cleanup;
503
24f2f94e
CMN
504 if (download_tags_value(remote, config) < 0)
505 goto cleanup;
506
1ef3f0ce
DC
507 if ((error = lookup_remote_prune_config(remote, config, name)) < 0)
508 goto cleanup;
509
510 /* Move the data over to where the matching functions can find them */
69f0032b 511 if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
1ef3f0ce
DC
512 goto cleanup;
513
514 *out = remote;
515
516cleanup:
517 git_config_free(config);
518 git_buf_free(&buf);
519
520 if (error < 0)
521 git_remote_free(remote);
522
523 return error;
524}
525
526static int lookup_remote_prune_config(git_remote *remote, git_config *config, const char *name)
527{
528 git_buf buf = GIT_BUF_INIT;
529 int error = 0;
530
5f473947
L
531 git_buf_printf(&buf, "remote.%s.prune", name);
532
533 if ((error = git_config_get_bool(&remote->prune_refs, config, git_buf_cstr(&buf))) < 0) {
534 if (error == GIT_ENOTFOUND) {
535 giterr_clear();
536
537 if ((error = git_config_get_bool(&remote->prune_refs, config, "fetch.prune")) < 0) {
538 if (error == GIT_ENOTFOUND) {
539 giterr_clear();
66b71ea5 540 error = 0;
5f473947
L
541 }
542 }
543 }
544 }
545
f0f3a18a 546 git_buf_free(&buf);
9c82357b
CMN
547 return error;
548}
549
4330ab26 550static int update_config_refspec(const git_remote *remote, git_config *config, int direction)
4fe5520a 551{
4330ab26 552 git_buf name = GIT_BUF_INIT;
66566516 553 unsigned int push;
4330ab26
CMN
554 const char *dir;
555 size_t i;
bf6bebe2 556 int error = 0;
3793fa9b 557 const char *cname;
4fe5520a 558
4330ab26
CMN
559 push = direction == GIT_DIRECTION_PUSH;
560 dir = push ? "push" : "fetch";
4fe5520a 561
4330ab26
CMN
562 if (git_buf_printf(&name, "remote.%s.%s", remote->name, dir) < 0)
563 return -1;
3793fa9b 564 cname = git_buf_cstr(&name);
4fe5520a 565
4330ab26 566 /* Clear out the existing config */
bf6bebe2 567 while (!error)
3793fa9b 568 error = git_config_delete_multivar(config, cname, ".*");
4fe5520a 569
4330ab26
CMN
570 if (error != GIT_ENOTFOUND)
571 return error;
572
1be680c4 573 for (i = 0; i < remote->refspecs.length; i++) {
4330ab26 574 git_refspec *spec = git_vector_get(&remote->refspecs, i);
4330ab26
CMN
575
576 if (spec->push != push)
577 continue;
578
376454d0
DRT
579 // "$^" is a unmatcheable regexp: it will not match anything at all, so
580 // all values will be considered new and we will not replace any
581 // present value.
bf6bebe2 582 if ((error = git_config_set_multivar(
376454d0 583 config, cname, "$^", spec->string)) < 0) {
4330ab26
CMN
584 goto cleanup;
585 }
586 }
587
588 giterr_clear();
589 error = 0;
4fe5520a 590
591cleanup:
592 git_buf_free(&name);
4fe5520a 593
594 return error;
595}
596
df705148 597const char *git_remote_name(const git_remote *remote)
9c82357b 598{
4bef3565 599 assert(remote);
9c82357b
CMN
600 return remote->name;
601}
602
85e1eded
ES
603git_repository *git_remote_owner(const git_remote *remote)
604{
605 assert(remote);
606 return remote->repo;
607}
608
df705148 609const char *git_remote_url(const git_remote *remote)
9c82357b 610{
4bef3565 611 assert(remote);
9c82357b
CMN
612 return remote->url;
613}
614
22261344 615static int set_url(git_repository *repo, const char *remote, const char *pattern, const char *url)
76501590 616{
22261344
CMN
617 git_config *cfg;
618 git_buf buf = GIT_BUF_INIT, canonical_url = GIT_BUF_INIT;
619 int error;
76501590 620
22261344 621 assert(repo && remote);
76501590 622
22261344
CMN
623 if ((error = ensure_remote_name_is_valid(remote)) < 0)
624 return error;
625
626 if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
627 return error;
628
629 if ((error = git_buf_printf(&buf, pattern, remote)) < 0)
630 return error;
631
632 if (url) {
633 if ((error = canonicalize_url(&canonical_url, url)) < 0)
634 goto cleanup;
635
636 error = git_config_set_string(cfg, buf.ptr, url);
637 } else {
638 error = git_config_delete_entry(cfg, buf.ptr);
639 }
640
641cleanup:
642 git_buf_free(&canonical_url);
643 git_buf_free(&buf);
644
645 return error;
646}
647
648int git_remote_set_url(git_repository *repo, const char *remote, const char *url)
649{
650 return set_url(repo, remote, CONFIG_URL_FMT, url);
76501590
SC
651}
652
df705148 653const char *git_remote_pushurl(const git_remote *remote)
76501590
SC
654{
655 assert(remote);
656 return remote->pushurl;
657}
658
22261344 659int git_remote_set_pushurl(git_repository *repo, const char *remote, const char* url)
76501590 660{
22261344 661 return set_url(repo, remote, CONFIG_PUSHURL_FMT, url);
76501590
SC
662}
663
eff5b499
SC
664const char* git_remote__urlfordirection(git_remote *remote, int direction)
665{
666 assert(remote);
667
b83c92dd 668 assert(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);
669
df705148 670 if (direction == GIT_DIRECTION_FETCH) {
eff5b499
SC
671 return remote->url;
672 }
673
df705148 674 if (direction == GIT_DIRECTION_PUSH) {
eff5b499
SC
675 return remote->pushurl ? remote->pushurl : remote->url;
676 }
677
678 return NULL;
679}
680
8f0104ec
CMN
681int set_transport_callbacks(git_transport *t, const git_remote_callbacks *cbs)
682{
683 if (!t->set_callbacks || !cbs)
684 return 0;
685
686 return t->set_callbacks(t, cbs->sideband_progress, NULL,
687 cbs->certificate_check, cbs->payload);
688}
689
690int git_remote_connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks)
9ba49bb5 691{
9ba49bb5 692 git_transport *t;
c0c39025 693 const char *url;
41fb1ca0 694 int flags = GIT_TRANSPORTFLAGS_NONE;
80fc7d6b 695 int error;
8f0104ec 696 void *payload = NULL;
058b753c
CMN
697 git_cred_acquire_cb credentials = NULL;
698 git_transport_cb transport = NULL;
9ba49bb5 699
4bef3565
VM
700 assert(remote);
701
8f0104ec
CMN
702 if (callbacks) {
703 GITERR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
704 credentials = callbacks->credentials;
058b753c 705 transport = callbacks->transport;
8f0104ec
CMN
706 payload = callbacks->payload;
707 }
708
41fb1ca0
PK
709 t = remote->transport;
710
c0c39025 711 url = git_remote__urlfordirection(remote, direction);
80fc7d6b 712 if (url == NULL) {
44bc0c6a 713 giterr_set(GITERR_INVALID,
714 "Malformed remote '%s' - missing URL", remote->name);
eff5b499 715 return -1;
44bc0c6a 716 }
eff5b499 717
1697cd6f
PK
718 /* If we don't have a transport object yet, and the caller specified a
719 * custom transport factory, use that */
058b753c
CMN
720 if (!t && transport &&
721 (error = transport(&t, remote, payload)) < 0)
1697cd6f
PK
722 return error;
723
724 /* If we still don't have a transport, then use the global
725 * transport registrations which map URI schemes to transport factories */
80fc7d6b
ET
726 if (!t && (error = git_transport_new(&t, remote, url)) < 0)
727 return error;
9ba49bb5 728
8f0104ec
CMN
729 if ((error = set_transport_callbacks(t, callbacks)) < 0 ||
730 (error = t->connect(t, url, credentials, payload, direction, flags)) != 0)
4376f7f6 731 goto on_error;
9ba49bb5
CMN
732
733 remote->transport = t;
734
4376f7f6 735 return 0;
9ba49bb5 736
4376f7f6
CMN
737on_error:
738 t->free(t);
613d5eb9
PK
739
740 if (t == remote->transport)
741 remote->transport = NULL;
742
80fc7d6b 743 return error;
9ba49bb5
CMN
744}
745
359dce72 746int git_remote_ls(const git_remote_head ***out, size_t *size, git_remote *remote)
9ba49bb5 747{
d88d4311
VM
748 assert(remote);
749
dc8adda4 750 if (!remote->transport) {
699dfcc3 751 giterr_set(GITERR_NET, "this remote has never connected");
dc8adda4
JG
752 return -1;
753 }
754
359dce72 755 return remote->transport->ls(out, size, remote->transport);
9ba49bb5
CMN
756}
757
613d5eb9
PK
758int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url)
759{
760 git_config *cfg;
9a97f49e 761 git_config_entry *ce = NULL;
9f77b3f6 762 const char *val = NULL;
80fc7d6b 763 int error;
613d5eb9
PK
764
765 assert(remote);
766
a71c27cc 767 if (!proxy_url || !remote->repo)
613d5eb9
PK
768 return -1;
769
770 *proxy_url = NULL;
771
80fc7d6b
ET
772 if ((error = git_repository_config__weakptr(&cfg, remote->repo)) < 0)
773 return error;
613d5eb9
PK
774
775 /* Go through the possible sources for proxy configuration, from most specific
776 * to least specific. */
777
778 /* remote.<name>.proxy config setting */
9f77b3f6 779 if (remote->name && remote->name[0]) {
613d5eb9
PK
780 git_buf buf = GIT_BUF_INIT;
781
80fc7d6b
ET
782 if ((error = git_buf_printf(&buf, "remote.%s.proxy", remote->name)) < 0)
783 return error;
613d5eb9 784
9f77b3f6
RB
785 error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false);
786 git_buf_free(&buf);
613d5eb9 787
9f77b3f6 788 if (error < 0)
80fc7d6b 789 return error;
613d5eb9 790
9f77b3f6
RB
791 if (ce && ce->value) {
792 val = ce->value;
793 goto found;
794 }
613d5eb9
PK
795 }
796
797 /* http.proxy config setting */
9f77b3f6 798 if ((error = git_config__lookup_entry(&ce, cfg, "http.proxy", false)) < 0)
80fc7d6b 799 return error;
9f77b3f6
RB
800 if (ce && ce->value) {
801 val = ce->value;
802 goto found;
803 }
613d5eb9
PK
804
805 /* HTTP_PROXY / HTTPS_PROXY environment variables */
806 val = use_ssl ? getenv("HTTPS_PROXY") : getenv("HTTP_PROXY");
807
9f77b3f6
RB
808found:
809 if (val && val[0]) {
613d5eb9
PK
810 *proxy_url = git__strdup(val);
811 GITERR_CHECK_ALLOC(*proxy_url);
613d5eb9 812 }
9a97f49e 813 git_config_entry_free(ce);
613d5eb9
PK
814
815 return 0;
816}
817
af613ecd
CMN
818/* DWIM `refspecs` based on `refs` and append the output to `out` */
819static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs)
d8488457 820{
af613ecd 821 size_t i;
d8488457 822 git_refspec *spec;
d8488457
CMN
823
824 git_vector_foreach(refspecs, i, spec) {
af613ecd
CMN
825 if (git_refspec__dwim_one(out, spec, refs) < 0)
826 return -1;
827 }
d8488457 828
af613ecd
CMN
829 return 0;
830}
d8488457 831
af613ecd
CMN
832static void free_refspecs(git_vector *vec)
833{
834 size_t i;
835 git_refspec *spec;
d8488457 836
af613ecd
CMN
837 git_vector_foreach(vec, i, spec) {
838 git_refspec__free(spec);
839 git__free(spec);
d8488457
CMN
840 }
841
af613ecd 842 git_vector_clear(vec);
d8488457
CMN
843}
844
845static int remote_head_cmp(const void *_a, const void *_b)
846{
847 const git_remote_head *a = (git_remote_head *) _a;
848 const git_remote_head *b = (git_remote_head *) _b;
849
850 return git__strcmp_cb(a->name, b->name);
851}
852
877cde76
CMN
853static int ls_to_vector(git_vector *out, git_remote *remote)
854{
855 git_remote_head **heads;
856 size_t heads_len, i;
857
858 if (git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote) < 0)
859 return -1;
860
861 if (git_vector_init(out, heads_len, remote_head_cmp) < 0)
862 return -1;
863
864 for (i = 0; i < heads_len; i++) {
865 if (git_vector_insert(out, heads[i]) < 0)
866 return -1;
867 }
868
869 return 0;
870}
871
8f0104ec 872int git_remote_download(git_remote *remote, const git_strarray *refspecs, const git_fetch_options *opts)
48a65a07 873{
eecc1772 874 int error = -1;
3f894205 875 size_t i;
2785544f 876 git_vector *to_active, specs = GIT_VECTOR_INIT, refs = GIT_VECTOR_INIT;
8f0104ec 877 const git_remote_callbacks *cbs = NULL;
95057b85 878
1e3b8ed5 879 assert(remote);
4bef3565 880
8f0104ec
CMN
881 if (opts) {
882 GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
883 cbs = &opts->callbacks;
884 }
885
886 if (!git_remote_connected(remote) &&
887 (error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs)) < 0)
888 goto on_error;
889
877cde76 890 if (ls_to_vector(&refs, remote) < 0)
d8488457 891 return -1;
d8488457 892
3f894205
CMN
893 if ((git_vector_init(&specs, 0, NULL)) < 0)
894 goto on_error;
895
c5837cad 896 remote->passed_refspecs = 0;
8e398e4c 897 if (!refspecs || !refspecs->count) {
3f894205
CMN
898 to_active = &remote->refspecs;
899 } else {
900 for (i = 0; i < refspecs->count; i++) {
901 if ((error = add_refspec_to(&specs, refspecs->strings[i], true)) < 0)
902 goto on_error;
903 }
904
905 to_active = &specs;
c5837cad 906 remote->passed_refspecs = 1;
3f894205
CMN
907 }
908
2cdd5c57
CMN
909 free_refspecs(&remote->passive_refspecs);
910 if ((error = dwim_refspecs(&remote->passive_refspecs, &remote->refspecs, &refs)) < 0)
911 goto on_error;
af613ecd 912
2cdd5c57 913 free_refspecs(&remote->active_refspecs);
3f894205 914 error = dwim_refspecs(&remote->active_refspecs, to_active, &refs);
2cdd5c57 915
877cde76 916 git_vector_free(&refs);
3f894205
CMN
917 free_refspecs(&specs);
918 git_vector_free(&specs);
877cde76
CMN
919
920 if (error < 0)
25e0b157 921 return error;
d8488457 922
c070ac64
POL
923 if (remote->push) {
924 git_push_free(remote->push);
925 remote->push = NULL;
926 }
927
35a8a8c5 928 if ((error = git_fetch_negotiate(remote, opts)) < 0)
4376f7f6 929 return error;
95057b85 930
8f0104ec 931 return git_fetch_download_pack(remote, cbs);
3f894205
CMN
932
933on_error:
934 git_vector_free(&refs);
935 free_refspecs(&specs);
936 git_vector_free(&specs);
937 return error;
48a65a07
CMN
938}
939
c3ab1e5a
BS
940int git_remote_fetch(
941 git_remote *remote,
3f894205 942 const git_strarray *refspecs,
8f0104ec 943 const git_fetch_options *opts,
c3ab1e5a 944 const char *reflog_message)
fe3a40a4 945{
3eff2a57 946 int error, update_fetchhead = 1;
35a8a8c5 947 git_remote_autotag_option_t tagopt = remote->download_tags;
6fb373a0 948 bool prune = false;
db55bb73 949 git_buf reflog_msg_buf = GIT_BUF_INIT;
8f0104ec
CMN
950 const git_remote_callbacks *cbs = NULL;
951
952 if (opts) {
953 GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
954 cbs = &opts->callbacks;
3eff2a57 955 update_fetchhead = opts->update_fetchhead;
35a8a8c5 956 tagopt = opts->download_tags;
8f0104ec 957 }
fe3a40a4
CMN
958
959 /* Connect and download everything */
8f0104ec 960 if ((error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs)) != 0)
fe3a40a4
CMN
961 return error;
962
8f0104ec 963 error = git_remote_download(remote, refspecs, opts);
fe3a40a4
CMN
964
965 /* We don't need to be connected anymore */
966 git_remote_disconnect(remote);
967
06a8f5c3
BL
968 /* If the download failed, return the error */
969 if (error != 0)
970 return error;
971
db55bb73
BS
972 /* Default reflog message */
973 if (reflog_message)
974 git_buf_sets(&reflog_msg_buf, reflog_message);
975 else {
976 git_buf_printf(&reflog_msg_buf, "fetch %s",
977 remote->name ? remote->name : remote->url);
978 }
979
fe3a40a4 980 /* Create "remote/foo" branches for all remote branches */
35a8a8c5 981 error = git_remote_update_tips(remote, cbs, update_fetchhead, tagopt, git_buf_cstr(&reflog_msg_buf));
db55bb73 982 git_buf_free(&reflog_msg_buf);
8c13eaed
CMN
983 if (error < 0)
984 return error;
985
6fb373a0
CMN
986 if (opts && opts->prune == GIT_FETCH_PRUNE)
987 prune = true;
c2418f46 988 else if (opts && opts->prune == GIT_FETCH_PRUNE_UNSPECIFIED && remote->prune_refs)
6fb373a0
CMN
989 prune = true;
990 else if (opts && opts->prune == GIT_FETCH_NO_PRUNE)
991 prune = false;
992 else
993 prune = remote->prune_refs;
994
995 if (prune)
8f0104ec 996 error = git_remote_prune(remote, cbs);
8c13eaed 997
db55bb73 998 return error;
fe3a40a4
CMN
999}
1000
b0f6e45d
ET
1001static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *update_heads, const char *fetchspec_src)
1002{
1003 unsigned int i;
1004 git_remote_head *remote_ref;
1005
1006 assert(update_heads && fetchspec_src);
1007
1008 *out = NULL;
7d4b65f6 1009
1010 git_vector_foreach(update_heads, i, remote_ref) {
1011 if (strcmp(remote_ref->name, fetchspec_src) == 0) {
1012 *out = remote_ref;
1013 break;
b0f6e45d
ET
1014 }
1015 }
1016
1017 return 0;
1018}
1019
2c9b9c8b
CMN
1020static int ref_to_update(int *update, git_buf *remote_name, git_remote *remote, git_refspec *spec, const char *ref_name)
1021{
1022 int error = 0;
1023 git_repository *repo;
1024 git_buf upstream_remote = GIT_BUF_INIT;
1025 git_buf upstream_name = GIT_BUF_INIT;
1026
1027 repo = git_remote_owner(remote);
1028
1029 if ((!git_reference__is_branch(ref_name)) ||
1030 !git_remote_name(remote) ||
1031 (error = git_branch_upstream_remote(&upstream_remote, repo, ref_name) < 0) ||
1032 git__strcmp(git_remote_name(remote), git_buf_cstr(&upstream_remote)) ||
1033 (error = git_branch_upstream_name(&upstream_name, repo, ref_name)) < 0 ||
1034 !git_refspec_dst_matches(spec, git_buf_cstr(&upstream_name)) ||
1035 (error = git_refspec_rtransform(remote_name, spec, upstream_name.ptr)) < 0) {
1036 /* Not an error if there is no upstream */
1037 if (error == GIT_ENOTFOUND) {
1038 giterr_clear();
1039 error = 0;
1040 }
1041
1042 *update = 0;
1043 } else {
1044 *update = 1;
1045 }
1046
1047 git_buf_free(&upstream_remote);
1048 git_buf_free(&upstream_name);
1049 return error;
1050}
1051
f49819aa 1052static int remote_head_for_ref(git_remote_head **out, git_remote *remote, git_refspec *spec, git_vector *update_heads, git_reference *ref)
b0f6e45d
ET
1053{
1054 git_reference *resolved_ref = NULL;
b0f6e45d 1055 git_buf remote_name = GIT_BUF_INIT;
f49819aa 1056 git_config *config = NULL;
e235db02 1057 const char *ref_name;
2c9b9c8b 1058 int error = 0, update;
b0f6e45d 1059
4330ab26 1060 assert(out && spec && ref);
b0f6e45d
ET
1061
1062 *out = NULL;
1063
67d4997a
CMN
1064 error = git_reference_resolve(&resolved_ref, ref);
1065
1066 /* If we're in an unborn branch, let's pretend nothing happened */
1067 if (error == GIT_ENOTFOUND && git_reference_type(ref) == GIT_REF_SYMBOLIC) {
1068 ref_name = git_reference_symbolic_target(ref);
1069 error = 0;
1070 } else {
1071 ref_name = git_reference_name(resolved_ref);
1072 }
1073
2c9b9c8b 1074 if ((error = ref_to_update(&update, &remote_name, remote, spec, ref_name)) < 0)
b0f6e45d 1075 goto cleanup;
b0f6e45d 1076
2c9b9c8b
CMN
1077 if (update)
1078 error = remote_head_for_fetchspec_src(out, update_heads, git_buf_cstr(&remote_name));
b0f6e45d
ET
1079
1080cleanup:
f7fcb18f 1081 git_buf_free(&remote_name);
b0f6e45d 1082 git_reference_free(resolved_ref);
f49819aa 1083 git_config_free(config);
b0f6e45d
ET
1084 return error;
1085}
1086
4330ab26 1087static int git_remote_write_fetchhead(git_remote *remote, git_refspec *spec, git_vector *update_heads)
b0f6e45d 1088{
b0f6e45d
ET
1089 git_reference *head_ref = NULL;
1090 git_fetchhead_ref *fetchhead_ref;
1091 git_remote_head *remote_ref, *merge_remote_ref;
1092 git_vector fetchhead_refs;
1093 bool include_all_fetchheads;
1094 unsigned int i = 0;
1095 int error = 0;
1096
1097 assert(remote);
1098
404eadb0
CMN
1099 /* no heads, nothing to do */
1100 if (update_heads->length == 0)
1101 return 0;
1102
b0f6e45d
ET
1103 if (git_vector_init(&fetchhead_refs, update_heads->length, git_fetchhead_ref_cmp) < 0)
1104 return -1;
1105
1106 /* Iff refspec is * (but not subdir slash star), include tags */
1107 include_all_fetchheads = (strcmp(GIT_REFS_HEADS_DIR "*", git_refspec_src(spec)) == 0);
1108
1109 /* Determine what to merge: if refspec was a wildcard, just use HEAD */
1110 if (git_refspec_is_wildcard(spec)) {
1111 if ((error = git_reference_lookup(&head_ref, remote->repo, GIT_HEAD_FILE)) < 0 ||
f49819aa 1112 (error = remote_head_for_ref(&merge_remote_ref, remote, spec, update_heads, head_ref)) < 0)
b0f6e45d
ET
1113 goto cleanup;
1114 } else {
1115 /* If we're fetching a single refspec, that's the only thing that should be in FETCH_HEAD. */
1116 if ((error = remote_head_for_fetchspec_src(&merge_remote_ref, update_heads, git_refspec_src(spec))) < 0)
1117 goto cleanup;
1118 }
1119
1120 /* Create the FETCH_HEAD file */
7d4b65f6 1121 git_vector_foreach(update_heads, i, remote_ref) {
b0f6e45d
ET
1122 int merge_this_fetchhead = (merge_remote_ref == remote_ref);
1123
1124 if (!include_all_fetchheads &&
1125 !git_refspec_src_matches(spec, remote_ref->name) &&
1126 !merge_this_fetchhead)
1127 continue;
1128
1129 if (git_fetchhead_ref_create(&fetchhead_ref,
1130 &remote_ref->oid,
1131 merge_this_fetchhead,
1132 remote_ref->name,
1133 git_remote_url(remote)) < 0)
1134 goto cleanup;
1135
1136 if (git_vector_insert(&fetchhead_refs, fetchhead_ref) < 0)
1137 goto cleanup;
1138 }
1139
1140 git_fetchhead_write(remote->repo, &fetchhead_refs);
1141
1142cleanup:
1143 for (i = 0; i < fetchhead_refs.length; ++i)
1144 git_fetchhead_ref_free(fetchhead_refs.contents[i]);
1145
1146 git_vector_free(&fetchhead_refs);
1147 git_reference_free(head_ref);
1148
1149 return error;
1150}
1151
59ff8b67
CMN
1152/**
1153 * Generate a list of candidates for pruning by getting a list of
1154 * references which match the rhs of an active refspec.
1155 */
1156static int prune_candidates(git_vector *candidates, git_remote *remote)
5f473947
L
1157{
1158 git_strarray arr = { 0 };
59ff8b67 1159 size_t i;
5f473947
L
1160 int error;
1161
1162 if ((error = git_reference_list(&arr, remote->repo)) < 0)
1163 return error;
1164
59ff8b67
CMN
1165 for (i = 0; i < arr.count; i++) {
1166 const char *refname = arr.strings[i];
1167 char *refname_dup;
1168
1169 if (!git_remote__matching_dst_refspec(remote, refname))
1170 continue;
1171
1172 refname_dup = git__strdup(refname);
1173 GITERR_CHECK_ALLOC(refname_dup);
1174
1175 if ((error = git_vector_insert(candidates, refname_dup)) < 0)
1176 goto out;
1177 }
1178
1179out:
1180 git_strarray_free(&arr);
1181 return error;
1182}
1183
1184static int find_head(const void *_a, const void *_b)
1185{
1186 git_remote_head *a = (git_remote_head *) _a;
1187 git_remote_head *b = (git_remote_head *) _b;
1188
1189 return strcmp(a->name, b->name);
1190}
1191
8f0104ec 1192int git_remote_prune(git_remote *remote, const git_remote_callbacks *callbacks)
59ff8b67
CMN
1193{
1194 size_t i, j;
1195 git_vector remote_refs = GIT_VECTOR_INIT;
1196 git_vector candidates = GIT_VECTOR_INIT;
1197 const git_refspec *spec;
1198 const char *refname;
1199 int error;
1200 git_oid zero_id = {{ 0 }};
1201
8f0104ec
CMN
1202 if (callbacks)
1203 GITERR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
1204
5f473947
L
1205 if ((error = ls_to_vector(&remote_refs, remote)) < 0)
1206 goto cleanup;
1207
59ff8b67 1208 git_vector_set_cmp(&remote_refs, find_head);
5f473947 1209
59ff8b67
CMN
1210 if ((error = prune_candidates(&candidates, remote)) < 0)
1211 goto cleanup;
5f473947 1212
59ff8b67
CMN
1213 /*
1214 * Remove those entries from the candidate list for which we
1215 * can find a remote reference in at least one refspec.
1216 */
1217 git_vector_foreach(&candidates, i, refname) {
1218 git_vector_foreach(&remote->active_refspecs, j, spec) {
1219 git_buf buf = GIT_BUF_INIT;
1220 size_t pos;
1221 char *src_name;
1222 git_remote_head key = {0};
1223
1224 if (!git_refspec_dst_matches(spec, refname))
5f473947
L
1225 continue;
1226
59ff8b67
CMN
1227 if ((error = git_refspec_rtransform(&buf, spec, refname)) < 0)
1228 goto cleanup;
5f473947 1229
59ff8b67
CMN
1230 key.name = (char *) git_buf_cstr(&buf);
1231 error = git_vector_search(&pos, &remote_refs, &key);
1232 git_buf_free(&buf);
5f473947 1233
59ff8b67
CMN
1234 if (error < 0 && error != GIT_ENOTFOUND)
1235 goto cleanup;
5f473947 1236
59ff8b67 1237 if (error == GIT_ENOTFOUND)
5f473947
L
1238 continue;
1239
59ff8b67
CMN
1240 /* if we did find a source, remove it from the candiates */
1241 if ((error = git_vector_set((void **) &src_name, &candidates, i, NULL)) < 0)
1242 goto cleanup;
1243
1244 git__free(src_name);
1245 break;
5f473947
L
1246 }
1247 }
1248
59ff8b67
CMN
1249 /*
1250 * For those candidates still left in the list, we need to
1251 * remove them. We do not remove symrefs, as those are for
1252 * stuff like origin/HEAD which will never match, but we do
1253 * not want to remove them.
1254 */
1255 git_vector_foreach(&candidates, i, refname) {
1256 git_reference *ref;
1257 git_oid id;
1258
1259 if (refname == NULL)
1260 continue;
1261
1262 error = git_reference_lookup(&ref, remote->repo, refname);
1263 /* as we want it gone, let's not consider this an error */
1264 if (error == GIT_ENOTFOUND)
1265 continue;
1266
1267 if (error < 0)
1268 goto cleanup;
1269
1270 if (git_reference_type(ref) == GIT_REF_SYMBOLIC) {
1271 git_reference_free(ref);
1272 continue;
1273 }
1274
1275 git_oid_cpy(&id, git_reference_target(ref));
1276 error = git_reference_delete(ref);
1277 git_reference_free(ref);
1278 if (error < 0)
1279 goto cleanup;
1280
8f0104ec
CMN
1281 if (callbacks && callbacks->update_tips)
1282 error = callbacks->update_tips(refname, &id, &zero_id, callbacks->payload);
59ff8b67
CMN
1283
1284 if (error < 0)
1285 goto cleanup;
1286 }
1287
5f473947 1288cleanup:
5f473947 1289 git_vector_free(&remote_refs);
59ff8b67 1290 git_vector_free_deep(&candidates);
5f473947
L
1291 return error;
1292}
1293
c3ab1e5a
BS
1294static int update_tips_for_spec(
1295 git_remote *remote,
8f0104ec 1296 const git_remote_callbacks *callbacks,
3eff2a57 1297 int update_fetchhead,
35a8a8c5 1298 git_remote_autotag_option_t tagopt,
c3ab1e5a
BS
1299 git_refspec *spec,
1300 git_vector *refs,
c3ab1e5a 1301 const char *log_message)
441f57c2 1302{
a37ddf7e 1303 int error = 0, autotag;
517bda19 1304 unsigned int i = 0;
97769280 1305 git_buf refname = GIT_BUF_INIT;
f184836b 1306 git_oid old;
a37ddf7e 1307 git_odb *odb;
441f57c2
CMN
1308 git_remote_head *head;
1309 git_reference *ref;
a37ddf7e 1310 git_refspec tagspec;
4330ab26 1311 git_vector update_heads;
441f57c2 1312
4bef3565
VM
1313 assert(remote);
1314
acd17006 1315 if (git_repository_odb__weakptr(&odb, remote->repo) < 0)
a37ddf7e
CMN
1316 return -1;
1317
3230a44f 1318 if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
a37ddf7e
CMN
1319 return -1;
1320
41fb1ca0 1321 /* Make a copy of the transport's refs */
4330ab26 1322 if (git_vector_init(&update_heads, 16, NULL) < 0)
41fb1ca0 1323 return -1;
585a2eb7 1324
4330ab26
CMN
1325 for (; i < refs->length; ++i) {
1326 head = git_vector_get(refs, i);
9063be1f 1327 autotag = 0;
517bda19 1328
a37ddf7e
CMN
1329 /* Ignore malformed ref names (which also saves us from tag^{} */
1330 if (!git_reference_is_valid_name(head->name))
1331 continue;
1332
e284c451 1333 if (git_refspec_src_matches(&tagspec, head->name)) {
35a8a8c5 1334 if (tagopt != GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
3230a44f 1335
35a8a8c5 1336 if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_AUTO)
e284c451 1337 autotag = 1;
a37ddf7e 1338
e284c451
POL
1339 git_buf_clear(&refname);
1340 if (git_buf_puts(&refname, head->name) < 0)
1341 goto on_error;
1342 } else {
a37ddf7e 1343 continue;
e284c451 1344 }
23aa7c90
CMN
1345 } else if (git_refspec_src_matches(spec, head->name)) {
1346 if (spec->dst) {
1347 if (git_refspec_transform(&refname, spec, head->name) < 0)
1348 goto on_error;
1349 } else {
1350 /*
1351 * no rhs mans store it in FETCH_HEAD, even if we don't
1352 update anything else.
1353 */
1354 if ((error = git_vector_insert(&update_heads, head)) < 0)
1355 goto on_error;
1356
1357 continue;
1358 }
a37ddf7e
CMN
1359 } else {
1360 continue;
1361 }
1362
e284c451 1363 /* In autotag mode, only create tags for objects already in db */
a37ddf7e
CMN
1364 if (autotag && !git_odb_exists(odb, &head->oid))
1365 continue;
f184836b 1366
d908351a 1367 if (!autotag && git_vector_insert(&update_heads, head) < 0)
b0f6e45d
ET
1368 goto on_error;
1369
2508cc66 1370 error = git_reference_name_to_id(&old, remote->repo, refname.ptr);
904b67e6 1371 if (error < 0 && error != GIT_ENOTFOUND)
f184836b
CMN
1372 goto on_error;
1373
d908351a 1374 if (error == GIT_ENOTFOUND) {
f184836b
CMN
1375 memset(&old, 0, GIT_OID_RAWSZ);
1376
d908351a
L
1377 if (autotag && git_vector_insert(&update_heads, head) < 0)
1378 goto on_error;
1379 }
1380
b7f167da 1381 if (!git_oid__cmp(&old, &head->oid))
f184836b 1382 continue;
441f57c2 1383
a37ddf7e 1384 /* In autotag mode, don't overwrite any locally-existing tags */
c3ab1e5a 1385 error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag,
659cf202 1386 log_message);
a37ddf7e 1387 if (error < 0 && error != GIT_EEXISTS)
944d250f 1388 goto on_error;
39157563
CMN
1389
1390 git_reference_free(ref);
f184836b 1391
8f0104ec
CMN
1392 if (callbacks && callbacks->update_tips != NULL) {
1393 if (callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload) < 0)
f184836b
CMN
1394 goto on_error;
1395 }
441f57c2
CMN
1396 }
1397
3eff2a57 1398 if (update_fetchhead &&
4330ab26 1399 (error = git_remote_write_fetchhead(remote, spec, &update_heads)) < 0)
b0f6e45d
ET
1400 goto on_error;
1401
b0f6e45d 1402 git_vector_free(&update_heads);
a37ddf7e 1403 git_refspec__free(&tagspec);
97769280 1404 git_buf_free(&refname);
f184836b
CMN
1405 return 0;
1406
1407on_error:
b0f6e45d 1408 git_vector_free(&update_heads);
a37ddf7e 1409 git_refspec__free(&tagspec);
f184836b
CMN
1410 git_buf_free(&refname);
1411 return -1;
97769280 1412
441f57c2
CMN
1413}
1414
c5837cad
CMN
1415/**
1416 * Iteration over the three vectors, with a pause whenever we find a match
1417 *
1418 * On each stop, we store the iteration stat in the inout i,j,k
1419 * parameters, and return the currently matching passive refspec as
1420 * well as the head which we matched.
1421 */
1422static int next_head(const git_remote *remote, git_vector *refs,
1423 git_refspec **out_spec, git_remote_head **out_head,
1424 size_t *out_i, size_t *out_j, size_t *out_k)
1425{
1426 const git_vector *active, *passive;
1427 git_remote_head *head;
1428 git_refspec *spec, *passive_spec;
1429 size_t i, j, k;
1430
1431 active = &remote->active_refspecs;
1432 passive = &remote->passive_refspecs;
1433
1434 i = *out_i;
1435 j = *out_j;
1436 k = *out_k;
1437
1438 for (; i < refs->length; i++) {
1439 head = git_vector_get(refs, i);
1440
1441 if (!git_reference_is_valid_name(head->name))
1442 continue;
1443
1444 for (; j < active->length; j++) {
1445 spec = git_vector_get(active, j);
1446
1447 if (!git_refspec_src_matches(spec, head->name))
1448 continue;
1449
1450 for (; k < passive->length; k++) {
1451 passive_spec = git_vector_get(passive, k);
1452
1453 if (!git_refspec_src_matches(passive_spec, head->name))
1454 continue;
1455
1456 *out_spec = passive_spec;
1457 *out_head = head;
1458 *out_i = i;
1459 *out_j = j;
1460 *out_k = k + 1;
1461 return 0;
1462
1463 }
1464 k = 0;
1465 }
1466 j = 0;
1467 }
1468
1469 return GIT_ITEROVER;
1470}
1471
9566ce43
CMN
1472static int opportunistic_updates(const git_remote *remote, const git_remote_callbacks *callbacks,
1473 git_vector *refs, const char *msg)
c5837cad
CMN
1474{
1475 size_t i, j, k;
1476 git_refspec *spec;
1477 git_remote_head *head;
1478 git_reference *ref;
1479 git_buf refname = GIT_BUF_INIT;
9566ce43 1480 int error = 0;
c5837cad
CMN
1481
1482 i = j = k = 0;
1483
1484 while ((error = next_head(remote, refs, &spec, &head, &i, &j, &k)) == 0) {
9566ce43 1485 git_oid old = {{ 0 }};
c5837cad
CMN
1486 /*
1487 * If we got here, there is a refspec which was used
1488 * for fetching which matches the source of one of the
1489 * passive refspecs, so we should update that
1490 * remote-tracking branch, but not add it to
1491 * FETCH_HEAD
1492 */
1493
9566ce43 1494 git_buf_clear(&refname);
c5837cad 1495 if ((error = git_refspec_transform(&refname, spec, head->name)) < 0)
9566ce43 1496 goto cleanup;
c5837cad 1497
9566ce43
CMN
1498 error = git_reference_name_to_id(&old, remote->repo, refname.ptr);
1499 if (error < 0 && error != GIT_ENOTFOUND)
1500 goto cleanup;
1501
1502 if (!git_oid_cmp(&old, &head->oid))
1503 continue;
c5837cad 1504
9566ce43
CMN
1505 /* If we did find a current reference, make sure we haven't lost a race */
1506 if (error)
1507 error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, true, msg);
1508 else
1509 error = git_reference_create_matching(&ref, remote->repo, refname.ptr, &head->oid, true, &old, msg);
1510 git_reference_free(ref);
c5837cad 1511 if (error < 0)
9566ce43
CMN
1512 goto cleanup;
1513
1514 if (callbacks && callbacks->update_tips != NULL) {
1515 if (callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload) < 0)
1516 goto cleanup;
1517 }
c5837cad
CMN
1518 }
1519
9566ce43
CMN
1520 if (error == GIT_ITEROVER)
1521 error = 0;
1522
1523cleanup:
1524 git_buf_free(&refname);
1525 return error;
c5837cad
CMN
1526}
1527
c3ab1e5a
BS
1528int git_remote_update_tips(
1529 git_remote *remote,
8f0104ec 1530 const git_remote_callbacks *callbacks,
3eff2a57 1531 int update_fetchhead,
35a8a8c5 1532 git_remote_autotag_option_t download_tags,
c3ab1e5a 1533 const char *reflog_message)
4330ab26 1534{
505b5d0c 1535 git_refspec *spec, tagspec;
cdedef40 1536 git_vector refs = GIT_VECTOR_INIT;
35a8a8c5 1537 git_remote_autotag_option_t tagopt;
505b5d0c 1538 int error;
4330ab26
CMN
1539 size_t i;
1540
fe794b2e
CMN
1541 /* push has its own logic hidden away in the push object */
1542 if (remote->push) {
8f0104ec 1543 return git_push_update_tips(remote->push, callbacks);
fe794b2e
CMN
1544 }
1545
505b5d0c
CMN
1546 if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
1547 return -1;
1548
877cde76
CMN
1549
1550 if ((error = ls_to_vector(&refs, remote)) < 0)
505b5d0c
CMN
1551 goto out;
1552
c2418f46 1553 if (download_tags == GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED)
35a8a8c5
CMN
1554 tagopt = remote->download_tags;
1555 else
1556 tagopt = download_tags;
1557
1558 if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
1559 if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, &tagspec, &refs, reflog_message)) < 0)
e284c451 1560 goto out;
505b5d0c 1561 }
4330ab26 1562
af613ecd 1563 git_vector_foreach(&remote->active_refspecs, i, spec) {
4330ab26
CMN
1564 if (spec->push)
1565 continue;
1566
35a8a8c5 1567 if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, spec, &refs, reflog_message)) < 0)
505b5d0c 1568 goto out;
4330ab26
CMN
1569 }
1570
c5837cad
CMN
1571 /* only try to do opportunisitic updates if the refpec lists differ */
1572 if (remote->passed_refspecs)
9566ce43 1573 error = opportunistic_updates(remote, callbacks, &refs, reflog_message);
c5837cad 1574
505b5d0c 1575out:
877cde76 1576 git_vector_free(&refs);
505b5d0c 1577 git_refspec__free(&tagspec);
505b5d0c 1578 return error;
4330ab26
CMN
1579}
1580
11f6ad5f 1581int git_remote_connected(const git_remote *remote)
6ac3b707 1582{
4bef3565 1583 assert(remote);
41fb1ca0
PK
1584
1585 if (!remote->transport || !remote->transport->is_connected)
1586 return 0;
1587
1588 /* Ask the transport if it's connected. */
613d5eb9 1589 return remote->transport->is_connected(remote->transport);
6ac3b707
CMN
1590}
1591
f0d2ddbb
CMN
1592void git_remote_stop(git_remote *remote)
1593{
613d5eb9
PK
1594 assert(remote);
1595
1596 if (remote->transport && remote->transport->cancel)
41fb1ca0 1597 remote->transport->cancel(remote->transport);
f0d2ddbb
CMN
1598}
1599
4cf01e9a
CMN
1600void git_remote_disconnect(git_remote *remote)
1601{
4bef3565
VM
1602 assert(remote);
1603
41fb1ca0
PK
1604 if (git_remote_connected(remote))
1605 remote->transport->close(remote->transport);
4cf01e9a
CMN
1606}
1607
9c82357b
CMN
1608void git_remote_free(git_remote *remote)
1609{
2aae2188
CMN
1610 if (remote == NULL)
1611 return;
1612
42ea35c0
MS
1613 if (remote->transport != NULL) {
1614 git_remote_disconnect(remote);
1615
1616 remote->transport->free(remote->transport);
1617 remote->transport = NULL;
1618 }
1619
1620 git_vector_free(&remote->refs);
1621
af613ecd 1622 free_refspecs(&remote->refspecs);
4330ab26
CMN
1623 git_vector_free(&remote->refspecs);
1624
af613ecd
CMN
1625 free_refspecs(&remote->active_refspecs);
1626 git_vector_free(&remote->active_refspecs);
1627
2cdd5c57
CMN
1628 free_refspecs(&remote->passive_refspecs);
1629 git_vector_free(&remote->passive_refspecs);
1630
fe794b2e 1631 git_push_free(remote->push);
3286c408 1632 git__free(remote->url);
3ed4b501 1633 git__free(remote->pushurl);
3286c408 1634 git__free(remote->name);
3286c408 1635 git__free(remote);
9c82357b 1636}
8171998f 1637
106c12f1 1638static int remote_list_cb(const git_config_entry *entry, void *payload)
8171998f 1639{
25e0b157 1640 git_vector *list = payload;
106c12f1
RB
1641 const char *name = entry->name + strlen("remote.");
1642 size_t namelen = strlen(name);
1643 char *remote_name;
8171998f 1644
106c12f1 1645 /* we know name matches "remote.<stuff>.(push)?url" */
8171998f 1646
106c12f1
RB
1647 if (!strcmp(&name[namelen - 4], ".url"))
1648 remote_name = git__strndup(name, namelen - 4); /* strip ".url" */
1649 else
1650 remote_name = git__strndup(name, namelen - 8); /* strip ".pushurl" */
25e0b157 1651 GITERR_CHECK_ALLOC(remote_name);
8171998f 1652
25e0b157 1653 return git_vector_insert(list, remote_name);
8171998f
CMN
1654}
1655
1656int git_remote_list(git_strarray *remotes_list, git_repository *repo)
1657{
8171998f 1658 int error;
96869a4e 1659 git_config *cfg;
25e0b157 1660 git_vector list = GIT_VECTOR_INIT;
8171998f 1661
96869a4e
RB
1662 if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
1663 return error;
8171998f 1664
25e0b157 1665 if ((error = git_vector_init(&list, 4, git__strcmp_cb)) < 0)
96869a4e 1666 return error;
8171998f 1667
106c12f1 1668 error = git_config_foreach_match(
25e0b157 1669 cfg, "^remote\\..*\\.(push)?url$", remote_list_cb, &list);
8171998f 1670
4376f7f6 1671 if (error < 0) {
9cfce273 1672 git_vector_free_deep(&list);
8171998f
CMN
1673 return error;
1674 }
1675
25e0b157 1676 git_vector_uniq(&list, git__free);
aec87f71 1677
25e0b157
RB
1678 remotes_list->strings =
1679 (char **)git_vector_detach(&remotes_list->count, NULL, &list);
8171998f 1680
4376f7f6 1681 return 0;
8171998f 1682}
a209a025 1683
67dad09b 1684const git_transfer_progress* git_remote_stats(git_remote *remote)
d57c47dc
BS
1685{
1686 assert(remote);
1687 return &remote->stats;
1688}
1689
11f6ad5f 1690git_remote_autotag_option_t git_remote_autotag(const git_remote *remote)
f70e466f
CMN
1691{
1692 return remote->download_tags;
1693}
1694
35a8a8c5 1695int git_remote_set_autotag(git_repository *repo, const char *remote, git_remote_autotag_option_t value)
f70e466f 1696{
35a8a8c5
CMN
1697 git_buf var = GIT_BUF_INIT;
1698 git_config *config;
1699 int error;
1700
1701 assert(repo && remote);
1702
1703 if ((error = ensure_remote_name_is_valid(remote)) < 0)
1704 return error;
1705
1706 if ((error = git_repository_config__weakptr(&config, repo)) < 0)
1707 return error;
1708
1709 if ((error = git_buf_printf(&var, CONFIG_TAGOPT_FMT, remote)))
1710 return error;
1711
1712 switch (value) {
1713 case GIT_REMOTE_DOWNLOAD_TAGS_NONE:
1714 error = git_config_set_string(config, var.ptr, "--no-tags");
1715 break;
1716 case GIT_REMOTE_DOWNLOAD_TAGS_ALL:
1717 error = git_config_set_string(config, var.ptr, "--tags");
1718 break;
1719 case GIT_REMOTE_DOWNLOAD_TAGS_AUTO:
1720 error = git_config_delete_entry(config, var.ptr);
1721 if (error == GIT_ENOTFOUND)
1722 error = 0;
1723 break;
1724 default:
1725 giterr_set(GITERR_INVALID, "Invalid value for the tagopt setting");
1726 error = -1;
1727 }
1728
1729 git_buf_free(&var);
1730 return error;
f70e466f 1731}
fcccf304 1732
5f473947
L
1733int git_remote_prune_refs(const git_remote *remote)
1734{
1735 return remote->prune_refs;
1736}
1737
fcccf304 1738static int rename_remote_config_section(
1739 git_repository *repo,
1740 const char *old_name,
1741 const char *new_name)
1742{
1743 git_buf old_section_name = GIT_BUF_INIT,
1744 new_section_name = GIT_BUF_INIT;
1745 int error = -1;
1746
1747 if (git_buf_printf(&old_section_name, "remote.%s", old_name) < 0)
1748 goto cleanup;
1749
40e48ea4 1750 if (new_name &&
1751 (git_buf_printf(&new_section_name, "remote.%s", new_name) < 0))
1752 goto cleanup;
fcccf304 1753
1754 error = git_config_rename_section(
1755 repo,
1756 git_buf_cstr(&old_section_name),
40e48ea4 1757 new_name ? git_buf_cstr(&new_section_name) : NULL);
fcccf304 1758
1759cleanup:
1760 git_buf_free(&old_section_name);
1761 git_buf_free(&new_section_name);
1762
1763 return error;
1764}
1765
96869a4e 1766struct update_data {
fcccf304 1767 git_config *config;
1768 const char *old_remote_name;
1769 const char *new_remote_name;
1770};
1771
1772static int update_config_entries_cb(
1773 const git_config_entry *entry,
1774 void *payload)
1775{
1776 struct update_data *data = (struct update_data *)payload;
1777
1778 if (strcmp(entry->value, data->old_remote_name))
1779 return 0;
1780
25e0b157
RB
1781 return git_config_set_string(
1782 data->config, entry->name, data->new_remote_name);
fcccf304 1783}
1784
1785static int update_branch_remote_config_entry(
1786 git_repository *repo,
1787 const char *old_name,
1788 const char *new_name)
1789{
96869a4e
RB
1790 int error;
1791 struct update_data data = { NULL };
fcccf304 1792
96869a4e
RB
1793 if ((error = git_repository_config__weakptr(&data.config, repo)) < 0)
1794 return error;
fcccf304 1795
fcccf304 1796 data.old_remote_name = old_name;
1797 data.new_remote_name = new_name;
1798
25e0b157 1799 return git_config_foreach_match(
96869a4e 1800 data.config, "branch\\..+\\.remote", update_config_entries_cb, &data);
fcccf304 1801}
1802
fcccf304 1803static int rename_one_remote_reference(
d1544564 1804 git_reference *reference_in,
fcccf304 1805 const char *old_remote_name,
1806 const char *new_remote_name)
1807{
96869a4e 1808 int error;
d1544564
CMN
1809 git_reference *ref = NULL, *dummy = NULL;
1810 git_buf namespace = GIT_BUF_INIT, old_namespace = GIT_BUF_INIT;
fcccf304 1811 git_buf new_name = GIT_BUF_INIT;
ccf6ce5c 1812 git_buf log_message = GIT_BUF_INIT;
d1544564
CMN
1813 size_t pfx_len;
1814 const char *target;
fcccf304 1815
d1544564
CMN
1816 if ((error = git_buf_printf(&namespace, GIT_REFS_REMOTES_DIR "%s/", new_remote_name)) < 0)
1817 return error;
1818
1819 pfx_len = strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name) + 1;
1820 git_buf_puts(&new_name, namespace.ptr);
1821 if ((error = git_buf_puts(&new_name, git_reference_name(reference_in) + pfx_len)) < 0)
ccf6ce5c 1822 goto cleanup;
fcccf304 1823
ccf6ce5c
BS
1824 if ((error = git_buf_printf(&log_message,
1825 "renamed remote %s to %s",
1826 old_remote_name, new_remote_name)) < 0)
1827 goto cleanup;
fcccf304 1828
d1544564 1829 if ((error = git_reference_rename(&ref, reference_in, git_buf_cstr(&new_name), 1,
659cf202 1830 git_buf_cstr(&log_message))) < 0)
d1544564
CMN
1831 goto cleanup;
1832
1833 if (git_reference_type(ref) != GIT_REF_SYMBOLIC)
1834 goto cleanup;
1835
1836 /* Handle refs like origin/HEAD -> origin/master */
1837 target = git_reference_symbolic_target(ref);
1838 if ((error = git_buf_printf(&old_namespace, GIT_REFS_REMOTES_DIR "%s/", old_remote_name)) < 0)
1839 goto cleanup;
1840
1841 if (git__prefixcmp(target, old_namespace.ptr))
1842 goto cleanup;
1843
1844 git_buf_clear(&new_name);
1845 git_buf_puts(&new_name, namespace.ptr);
1846 if ((error = git_buf_puts(&new_name, target + pfx_len)) < 0)
1847 goto cleanup;
1848
1849 error = git_reference_symbolic_set_target(&dummy, ref, git_buf_cstr(&new_name),
659cf202 1850 git_buf_cstr(&log_message));
d1544564
CMN
1851
1852 git_reference_free(dummy);
ccf6ce5c
BS
1853
1854cleanup:
d1544564
CMN
1855 git_reference_free(reference_in);
1856 git_reference_free(ref);
1857 git_buf_free(&namespace);
1858 git_buf_free(&old_namespace);
fcccf304 1859 git_buf_free(&new_name);
ccf6ce5c 1860 git_buf_free(&log_message);
fcccf304 1861 return error;
1862}
1863
1864static int rename_remote_references(
1865 git_repository *repo,
1866 const char *old_name,
1867 const char *new_name)
1868{
96869a4e 1869 int error;
a52ab4b8 1870 git_buf buf = GIT_BUF_INIT;
56960b83 1871 git_reference *ref;
9bd89d96 1872 git_reference_iterator *iter;
fcccf304 1873
a52ab4b8 1874 if ((error = git_buf_printf(&buf, GIT_REFS_REMOTES_DIR "%s/*", old_name)) < 0)
96869a4e 1875 return error;
fcccf304 1876
a52ab4b8
CMN
1877 error = git_reference_iterator_glob_new(&iter, repo, git_buf_cstr(&buf));
1878 git_buf_free(&buf);
9bd89d96 1879
a52ab4b8
CMN
1880 if (error < 0)
1881 return error;
1882
1883 while ((error = git_reference_next(&ref, iter)) == 0) {
96869a4e
RB
1884 if ((error = rename_one_remote_reference(ref, old_name, new_name)) < 0)
1885 break;
9bd89d96
CMN
1886 }
1887
1888 git_reference_iterator_free(iter);
fcccf304 1889
96869a4e 1890 return (error == GIT_ITEROVER) ? 0 : error;
fcccf304 1891}
1892
72bca13e 1893static int rename_fetch_refspecs(git_vector *problems, git_remote *remote, const char *new_name)
fcccf304 1894{
1895 git_config *config;
4330ab26 1896 git_buf base = GIT_BUF_INIT, var = GIT_BUF_INIT, val = GIT_BUF_INIT;
1be680c4 1897 const git_refspec *spec;
4330ab26 1898 size_t i;
25e0b157 1899 int error = 0;
fcccf304 1900
dab89f9b 1901 if ((error = git_repository_config__weakptr(&config, remote->repo)) < 0)
25e0b157
RB
1902 return error;
1903
72bca13e
CMN
1904 if ((error = git_vector_init(problems, 1, NULL)) < 0)
1905 return error;
1906
25e0b157
RB
1907 if ((error = git_buf_printf(
1908 &base, "+refs/heads/*:refs/remotes/%s/*", remote->name)) < 0)
1909 return error;
dab89f9b 1910
1be680c4 1911 git_vector_foreach(&remote->refspecs, i, spec) {
4330ab26
CMN
1912 if (spec->push)
1913 continue;
fcccf304 1914
dab89f9b 1915 /* Does the dst part of the refspec follow the expected format? */
5a49ff9f 1916 if (strcmp(git_buf_cstr(&base), spec->string)) {
72bca13e 1917 char *dup;
fcccf304 1918
72bca13e
CMN
1919 dup = git__strdup(spec->string);
1920 GITERR_CHECK_ALLOC(dup);
1921
1922 if ((error = git_vector_insert(problems, dup)) < 0)
25e0b157 1923 break;
c7b3e1b3 1924
4330ab26
CMN
1925 continue;
1926 }
fcccf304 1927
4330ab26 1928 /* If we do want to move it to the new section */
fcccf304 1929
dab89f9b
RB
1930 git_buf_clear(&val);
1931 git_buf_clear(&var);
fcccf304 1932
dab89f9b
RB
1933 if (git_buf_printf(
1934 &val, "+refs/heads/*:refs/remotes/%s/*", new_name) < 0 ||
1935 git_buf_printf(&var, "remote.%s.fetch", new_name) < 0)
1936 {
1937 error = -1;
25e0b157 1938 break;
dab89f9b 1939 }
fcccf304 1940
dab89f9b
RB
1941 if ((error = git_config_set_string(
1942 config, git_buf_cstr(&var), git_buf_cstr(&val))) < 0)
25e0b157 1943 break;
4330ab26 1944 }
fcccf304 1945
4330ab26
CMN
1946 git_buf_free(&base);
1947 git_buf_free(&var);
1948 git_buf_free(&val);
72bca13e
CMN
1949
1950 if (error < 0) {
1951 char *str;
1952 git_vector_foreach(problems, i, str)
1953 git__free(str);
1954
1955 git_vector_free(problems);
1956 }
1957
fcccf304 1958 return error;
1959}
1960
46c8f7f8 1961int git_remote_rename(git_strarray *out, git_repository *repo, const char *name, const char *new_name)
fcccf304 1962{
1963 int error;
46c8f7f8 1964 git_vector problem_refspecs = GIT_VECTOR_INIT;
64bcf567 1965 git_remote *remote = NULL;
fcccf304 1966
46c8f7f8 1967 assert(out && repo && name && new_name);
fcccf304 1968
209425ce 1969 if ((error = git_remote_lookup(&remote, repo, name)) < 0)
cce27d82 1970 return error;
79000951 1971
fcccf304 1972 if ((error = ensure_remote_name_is_valid(new_name)) < 0)
46c8f7f8 1973 goto cleanup;
fcccf304 1974
46c8f7f8
CMN
1975 if ((error = ensure_remote_doesnot_exist(repo, new_name)) < 0)
1976 goto cleanup;
fcccf304 1977
46c8f7f8
CMN
1978 if ((error = rename_remote_config_section(repo, name, new_name)) < 0)
1979 goto cleanup;
fcccf304 1980
46c8f7f8
CMN
1981 if ((error = update_branch_remote_config_entry(repo, name, new_name)) < 0)
1982 goto cleanup;
fcccf304 1983
46c8f7f8
CMN
1984 if ((error = rename_remote_references(repo, name, new_name)) < 0)
1985 goto cleanup;
fcccf304 1986
72bca13e 1987 if ((error = rename_fetch_refspecs(&problem_refspecs, remote, new_name)) < 0)
46c8f7f8 1988 goto cleanup;
fcccf304 1989
72bca13e
CMN
1990 out->count = problem_refspecs.length;
1991 out->strings = (char **) problem_refspecs.contents;
1992
46c8f7f8
CMN
1993cleanup:
1994 if (error < 0)
1995 git_vector_free(&problem_refspecs);
fcccf304 1996
46c8f7f8
CMN
1997 git_remote_free(remote);
1998 return error;
fcccf304 1999}
b0f6e45d 2000
2bca5b67 2001int git_remote_is_valid_name(
2002 const char *remote_name)
2003{
2004 git_buf buf = GIT_BUF_INIT;
2005 git_refspec refspec;
2006 int error = -1;
2007
2008 if (!remote_name || *remote_name == '\0')
2009 return 0;
2010
2011 git_buf_printf(&buf, "refs/heads/test:refs/remotes/%s/test", remote_name);
2012 error = git_refspec__parse(&refspec, git_buf_cstr(&buf), true);
2013
2014 git_buf_free(&buf);
2015 git_refspec__free(&refspec);
2016
2017 giterr_clear();
2018 return error == 0;
2019}
4330ab26
CMN
2020
2021git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname)
2022{
2023 git_refspec *spec;
2024 size_t i;
2025
af613ecd 2026 git_vector_foreach(&remote->active_refspecs, i, spec) {
4330ab26
CMN
2027 if (spec->push)
2028 continue;
2029
2030 if (git_refspec_src_matches(spec, refname))
2031 return spec;
2032 }
2033
2034 return NULL;
2035}
2036
2037git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *refname)
2038{
2039 git_refspec *spec;
2040 size_t i;
2041
af613ecd 2042 git_vector_foreach(&remote->active_refspecs, i, spec) {
4330ab26
CMN
2043 if (spec->push)
2044 continue;
2045
2046 if (git_refspec_dst_matches(spec, refname))
2047 return spec;
2048 }
2049
2050 return NULL;
2051}
2052
77254990 2053int git_remote_add_fetch(git_repository *repo, const char *remote, const char *refspec)
4330ab26 2054{
77254990 2055 return write_add_refspec(repo, remote, refspec, true);
4330ab26
CMN
2056}
2057
77254990 2058int git_remote_add_push(git_repository *repo, const char *remote, const char *refspec)
4330ab26 2059{
77254990 2060 return write_add_refspec(repo, remote, refspec, false);
266af6d8
CMN
2061}
2062
2063static int set_refspecs(git_remote *remote, git_strarray *array, int push)
2064{
2065 git_vector *vec = &remote->refspecs;
2066 git_refspec *spec;
2067 size_t i;
2068
2069 /* Start by removing any refspecs of the same type */
2070 for (i = 0; i < vec->length; i++) {
2071 spec = git_vector_get(vec, i);
2072 if (spec->push != push)
2073 continue;
2074
2075 git_refspec__free(spec);
2076 git__free(spec);
2077 git_vector_remove(vec, i);
2078 i--;
2079 }
2080
2081 /* And now we add the new ones */
2082
2083 for (i = 0; i < array->count; i++) {
2084 if (add_refspec(remote, array->strings[i], !push) < 0)
2085 return -1;
2086 }
2087
c300d84a 2088 return 0;
266af6d8
CMN
2089}
2090
11f6ad5f 2091static int copy_refspecs(git_strarray *array, const git_remote *remote, unsigned int push)
bc6374ea
CMN
2092{
2093 size_t i;
2094 git_vector refspecs;
2095 git_refspec *spec;
2096 char *dup;
2097
2098 if (git_vector_init(&refspecs, remote->refspecs.length, NULL) < 0)
2099 return -1;
2100
2101 git_vector_foreach(&remote->refspecs, i, spec) {
2102 if (spec->push != push)
2103 continue;
2104
1be680c4 2105 if ((dup = git__strdup(spec->string)) == NULL)
bc6374ea 2106 goto on_error;
bc6374ea
CMN
2107
2108 if (git_vector_insert(&refspecs, dup) < 0) {
2109 git__free(dup);
2110 goto on_error;
2111 }
2112 }
2113
2114 array->strings = (char **)refspecs.contents;
2115 array->count = refspecs.length;
2116
2117 return 0;
2118
2119on_error:
9cfce273 2120 git_vector_free_deep(&refspecs);
bc6374ea
CMN
2121
2122 return -1;
2123}
2124
11f6ad5f 2125int git_remote_get_fetch_refspecs(git_strarray *array, const git_remote *remote)
bc6374ea
CMN
2126{
2127 return copy_refspecs(array, remote, false);
2128}
2129
11f6ad5f 2130int git_remote_get_push_refspecs(git_strarray *array, const git_remote *remote)
bc6374ea
CMN
2131{
2132 return copy_refspecs(array, remote, true);
2133}
1ffd0806 2134
11f6ad5f 2135size_t git_remote_refspec_count(const git_remote *remote)
1ffd0806
CMN
2136{
2137 return remote->refspecs.length;
2138}
2139
11f6ad5f 2140const git_refspec *git_remote_get_refspec(const git_remote *remote, size_t n)
1ffd0806
CMN
2141{
2142 return git_vector_get(&remote->refspecs, n);
2143}
b9f81997 2144
bc91347b 2145int git_remote_init_callbacks(git_remote_callbacks *opts, unsigned int version)
b9f81997 2146{
bc91347b
RB
2147 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
2148 opts, version, git_remote_callbacks, GIT_REMOTE_CALLBACKS_INIT);
2149 return 0;
b9f81997 2150}
40e48ea4 2151
5cdac19c
CMN
2152/* asserts a branch.<foo>.remote format */
2153static const char *name_offset(size_t *len_out, const char *name)
40e48ea4 2154{
5cdac19c
CMN
2155 size_t prefix_len;
2156 const char *dot;
40e48ea4 2157
5cdac19c
CMN
2158 prefix_len = strlen("remote.");
2159 dot = strchr(name + prefix_len, '.');
40e48ea4 2160
5cdac19c 2161 assert(dot);
40e48ea4 2162
5cdac19c
CMN
2163 *len_out = dot - name - prefix_len;
2164 return name + prefix_len;
40e48ea4 2165}
2166
2167static int remove_branch_config_related_entries(
2168 git_repository *repo,
2169 const char *remote_name)
2170{
2171 int error;
2172 git_config *config;
5cdac19c
CMN
2173 git_config_entry *entry;
2174 git_config_iterator *iter;
2175 git_buf buf = GIT_BUF_INIT;
40e48ea4 2176
2177 if ((error = git_repository_config__weakptr(&config, repo)) < 0)
2178 return error;
2179
5cdac19c 2180 if ((error = git_config_iterator_glob_new(&iter, config, "branch\\..+\\.remote")) < 0)
40e48ea4 2181 return error;
2182
5cdac19c
CMN
2183 /* find any branches with us as upstream and remove that config */
2184 while ((error = git_config_next(&entry, iter)) == 0) {
2185 const char *branch;
2186 size_t branch_len;
40e48ea4 2187
5cdac19c
CMN
2188 if (strcmp(remote_name, entry->value))
2189 continue;
40e48ea4 2190
5cdac19c 2191 branch = name_offset(&branch_len, entry->name);
40e48ea4 2192
5cdac19c
CMN
2193 git_buf_clear(&buf);
2194 if (git_buf_printf(&buf, "branch.%.*s.merge", (int)branch_len, branch) < 0)
2195 break;
2196
2197 if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0)
2198 break;
2199
2200 git_buf_clear(&buf);
2201 if (git_buf_printf(&buf, "branch.%.*s.remote", (int)branch_len, branch) < 0)
2202 break;
2203
2204 if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0)
2205 break;
40e48ea4 2206 }
2207
5cdac19c
CMN
2208 if (error == GIT_ITEROVER)
2209 error = 0;
2210
2211 git_buf_free(&buf);
2212 git_config_iterator_free(iter);
40e48ea4 2213 return error;
2214}
2215
8a9419aa 2216static int remove_refs(git_repository *repo, const git_refspec *spec)
ec8a949a 2217{
8a9419aa
CMN
2218 git_reference_iterator *iter = NULL;
2219 git_vector refs;
ec8a949a 2220 const char *name;
8a9419aa 2221 char *dup;
ec8a949a 2222 int error;
8a9419aa 2223 size_t i;
ec8a949a 2224
8a9419aa 2225 if ((error = git_vector_init(&refs, 8, NULL)) < 0)
ec8a949a
CMN
2226 return error;
2227
8a9419aa
CMN
2228 if ((error = git_reference_iterator_new(&iter, repo)) < 0)
2229 goto cleanup;
2230
ec8a949a 2231 while ((error = git_reference_next_name(&name, iter)) == 0) {
8a9419aa
CMN
2232 if (!git_refspec_dst_matches(spec, name))
2233 continue;
2234
2235 dup = git__strdup(name);
2236 if (!dup) {
2237 error = -1;
2238 goto cleanup;
2239 }
ec8a949a 2240
8a9419aa
CMN
2241 if ((error = git_vector_insert(&refs, dup)) < 0)
2242 goto cleanup;
2243 }
ec8a949a
CMN
2244 if (error == GIT_ITEROVER)
2245 error = 0;
8a9419aa
CMN
2246 if (error < 0)
2247 goto cleanup;
2248
2249 git_vector_foreach(&refs, i, name) {
2250 if ((error = git_reference_remove(repo, name)) < 0)
2251 break;
2252 }
ec8a949a 2253
8a9419aa
CMN
2254cleanup:
2255 git_reference_iterator_free(iter);
2256 git_vector_foreach(&refs, i, dup) {
2257 git__free(dup);
2258 }
2259 git_vector_free(&refs);
ec8a949a
CMN
2260 return error;
2261}
2262
2263static int remove_remote_tracking(git_repository *repo, const char *remote_name)
2264{
2265 git_remote *remote;
2266 int error;
2267 size_t i, count;
2268
2269 /* we want to use what's on the config, regardless of changes to the instance in memory */
209425ce 2270 if ((error = git_remote_lookup(&remote, repo, remote_name)) < 0)
ec8a949a
CMN
2271 return error;
2272
2273 count = git_remote_refspec_count(remote);
2274 for (i = 0; i < count; i++) {
2275 const git_refspec *refspec = git_remote_get_refspec(remote, i);
2276
2277 /* shouldn't ever actually happen */
2278 if (refspec == NULL)
2279 continue;
2280
8a9419aa 2281 if ((error = remove_refs(repo, refspec)) < 0)
ec8a949a
CMN
2282 break;
2283 }
2284
2285 git_remote_free(remote);
2286 return error;
2287}
2288
262eec23 2289int git_remote_delete(git_repository *repo, const char *name)
40e48ea4 2290{
2291 int error;
40e48ea4 2292
262eec23 2293 assert(repo && name);
ec8a949a 2294
262eec23
CMN
2295 if ((error = remove_branch_config_related_entries(repo, name)) < 0 ||
2296 (error = remove_remote_tracking(repo, name)) < 0 ||
2297 (error = rename_remote_config_section(repo, name, NULL)) < 0)
ec8a949a
CMN
2298 return error;
2299
40e48ea4 2300 return 0;
2301}
d22db24f
CMN
2302
2303int git_remote_default_branch(git_buf *out, git_remote *remote)
2304{
2305 const git_remote_head **heads;
2306 const git_remote_head *guess = NULL;
2307 const git_oid *head_id;
2308 size_t heads_len, i;
2309 int error;
2310
dc8adda4
JG
2311 assert(out);
2312
d22db24f
CMN
2313 if ((error = git_remote_ls(&heads, &heads_len, remote)) < 0)
2314 return error;
2315
2316 if (heads_len == 0)
2317 return GIT_ENOTFOUND;
2318
0cdaa376
CMN
2319 if (strcmp(heads[0]->name, GIT_HEAD_FILE))
2320 return GIT_ENOTFOUND;
2321
d22db24f
CMN
2322 git_buf_sanitize(out);
2323 /* the first one must be HEAD so if that has the symref info, we're done */
2324 if (heads[0]->symref_target)
2325 return git_buf_puts(out, heads[0]->symref_target);
2326
2327 /*
2328 * If there's no symref information, we have to look over them
2329 * and guess. We return the first match unless the master
2330 * branch is a candidate. Then we return the master branch.
2331 */
2332 head_id = &heads[0]->oid;
2333
2334 for (i = 1; i < heads_len; i++) {
2335 if (git_oid_cmp(head_id, &heads[i]->oid))
2336 continue;
2337
38952604
CMN
2338 if (git__prefixcmp(heads[i]->name, GIT_REFS_HEADS_DIR))
2339 continue;
2340
d22db24f
CMN
2341 if (!guess) {
2342 guess = heads[i];
2343 continue;
2344 }
2345
2346 if (!git__strcmp(GIT_REFS_HEADS_MASTER_FILE, heads[i]->name)) {
2347 guess = heads[i];
2348 break;
2349 }
2350 }
2351
2352 if (!guess)
2353 return GIT_ENOTFOUND;
2354
2355 return git_buf_puts(out, guess->name);
2356}
3149547b 2357
fe794b2e 2358int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
3149547b 2359{
3149547b 2360 size_t i;
fe794b2e
CMN
2361 int error;
2362 git_push *push;
64e3e6d4 2363 git_refspec *spec;
8f0104ec 2364 const git_remote_callbacks *cbs = NULL;
3149547b 2365
fe794b2e 2366 assert(remote);
3149547b 2367
8f0104ec
CMN
2368 if (opts)
2369 cbs = &opts->callbacks;
2370
fe794b2e 2371 if (!git_remote_connected(remote) &&
8f0104ec 2372 (error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs)) < 0)
fe794b2e
CMN
2373 goto cleanup;
2374
1034f1b5 2375 free_refspecs(&remote->active_refspecs);
69f0032b 2376 if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
1034f1b5
POL
2377 goto cleanup;
2378
fe794b2e
CMN
2379 if (remote->push) {
2380 git_push_free(remote->push);
2381 remote->push = NULL;
2382 }
2383
2384 if ((error = git_push_new(&remote->push, remote)) < 0)
3149547b
CMN
2385 return error;
2386
fe794b2e 2387 push = remote->push;
3149547b
CMN
2388
2389 if (opts && (error = git_push_set_options(push, opts)) < 0)
2390 goto cleanup;
2391
64e3e6d4
CMN
2392 if (refspecs && refspecs->count > 0) {
2393 for (i = 0; i < refspecs->count; i++) {
2394 if ((error = git_push_add_refspec(push, refspecs->strings[i])) < 0)
2395 goto cleanup;
2396 }
2397 } else {
2398 git_vector_foreach(&remote->refspecs, i, spec) {
2399 if (!spec->push)
2400 continue;
2401 if ((error = git_push_add_refspec(push, spec->string)) < 0)
2402 goto cleanup;
2403 }
3149547b
CMN
2404 }
2405
8f0104ec 2406 if ((error = git_push_finish(push, cbs)) < 0)
3149547b
CMN
2407 goto cleanup;
2408
8f0104ec 2409 if (cbs && cbs->push_update_reference &&
52ee0e8e 2410 (error = git_push_status_foreach(push, cbs->push_update_reference, cbs->payload)) < 0)
3149547b
CMN
2411 goto cleanup;
2412
3149547b 2413cleanup:
fe794b2e
CMN
2414 return error;
2415}
2416
412a3808 2417int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
fe794b2e
CMN
2418{
2419 int error;
8f0104ec
CMN
2420 const git_remote_callbacks *cbs = NULL;
2421
2422 if (opts) {
2423 GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
2424 cbs = &opts->callbacks;
2425 }
fe794b2e
CMN
2426
2427 assert(remote && refspecs);
2428
8f0104ec 2429 if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs)) < 0)
fe794b2e
CMN
2430 return error;
2431
2432 if ((error = git_remote_upload(remote, refspecs, opts)) < 0)
2433 return error;
2434
35a8a8c5 2435 error = git_remote_update_tips(remote, cbs, 0, 0, NULL);
fe794b2e 2436
3149547b 2437 git_remote_disconnect(remote);
3149547b
CMN
2438 return error;
2439}
ec0c4c40
PS
2440
2441#define PREFIX "url"
2442#define SUFFIX_FETCH "insteadof"
2443#define SUFFIX_PUSH "pushinsteadof"
2444
2445char *apply_insteadof(git_config *config, const char *url, int direction)
2446{
2447 size_t match_length, prefix_length, suffix_length;
2448 char *replacement = NULL;
2449 const char *regexp;
2450
2451 git_buf result = GIT_BUF_INIT;
2452 git_config_entry *entry;
2453 git_config_iterator *iter;
2454
2455 assert(config);
2456 assert(url);
2457 assert(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);
2458
2459 /* Add 1 to prefix/suffix length due to the additional escaped dot */
2460 prefix_length = strlen(PREFIX) + 1;
2461 if (direction == GIT_DIRECTION_FETCH) {
2462 regexp = PREFIX "\\..*\\." SUFFIX_FETCH;
2463 suffix_length = strlen(SUFFIX_FETCH) + 1;
2464 } else {
2465 regexp = PREFIX "\\..*\\." SUFFIX_PUSH;
2466 suffix_length = strlen(SUFFIX_PUSH) + 1;
2467 }
2468
2785544f
CMN
2469 if (git_config_iterator_glob_new(&iter, config, regexp) < 0)
2470 return NULL;
ec0c4c40
PS
2471
2472 match_length = 0;
2473 while (git_config_next(&entry, iter) == 0) {
2474 size_t n, replacement_length;
2475
2476 /* Check if entry value is a prefix of URL */
2477 if (git__prefixcmp(url, entry->value))
2478 continue;
2479 /* Check if entry value is longer than previous
2480 * prefixes */
2481 if ((n = strlen(entry->value)) <= match_length)
2482 continue;
2483
2484 git__free(replacement);
2485 match_length = n;
2486
2487 /* Cut off prefix and suffix of the value */
2488 replacement_length =
2489 strlen(entry->name) - (prefix_length + suffix_length);
2490 replacement = git__strndup(entry->name + prefix_length,
2491 replacement_length);
2492 }
2493
2494 git_config_iterator_free(iter);
2495
2496 if (match_length == 0)
2497 return git__strdup(url);
2498
2499 git_buf_printf(&result, "%s%s", replacement, url + match_length);
2500
2501 git__free(replacement);
2502
2503 return result.ptr;
2504}