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