]> git.proxmox.com Git - libgit2.git/blob - src/refs.c
Merge branch 'debian/experimental' into debian/sid
[libgit2.git] / src / refs.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 "refs.h"
9
10 #include "hash.h"
11 #include "repository.h"
12 #include "futils.h"
13 #include "filebuf.h"
14 #include "pack.h"
15 #include "reflog.h"
16 #include "refdb.h"
17
18 #include <git2/tag.h>
19 #include <git2/object.h>
20 #include <git2/oid.h>
21 #include <git2/branch.h>
22 #include <git2/refs.h>
23 #include <git2/refdb.h>
24 #include <git2/sys/refs.h>
25 #include <git2/signature.h>
26 #include <git2/commit.h>
27
28 bool git_reference__enable_symbolic_ref_target_validation = true;
29
30 #define DEFAULT_NESTING_LEVEL 5
31 #define MAX_NESTING_LEVEL 10
32
33 enum {
34 GIT_PACKREF_HAS_PEEL = 1,
35 GIT_PACKREF_WAS_LOOSE = 2
36 };
37
38 static git_reference *alloc_ref(const char *name)
39 {
40 git_reference *ref = NULL;
41 size_t namelen = strlen(name), reflen;
42
43 if (!GIT_ADD_SIZET_OVERFLOW(&reflen, sizeof(git_reference), namelen) &&
44 !GIT_ADD_SIZET_OVERFLOW(&reflen, reflen, 1) &&
45 (ref = git__calloc(1, reflen)) != NULL)
46 memcpy(ref->name, name, namelen + 1);
47
48 return ref;
49 }
50
51 git_reference *git_reference__alloc_symbolic(
52 const char *name, const char *target)
53 {
54 git_reference *ref;
55
56 assert(name && target);
57
58 ref = alloc_ref(name);
59 if (!ref)
60 return NULL;
61
62 ref->type = GIT_REFERENCE_SYMBOLIC;
63
64 if ((ref->target.symbolic = git__strdup(target)) == NULL) {
65 git__free(ref);
66 return NULL;
67 }
68
69 return ref;
70 }
71
72 git_reference *git_reference__alloc(
73 const char *name,
74 const git_oid *oid,
75 const git_oid *peel)
76 {
77 git_reference *ref;
78
79 assert(name && oid);
80
81 ref = alloc_ref(name);
82 if (!ref)
83 return NULL;
84
85 ref->type = GIT_REFERENCE_DIRECT;
86 git_oid_cpy(&ref->target.oid, oid);
87
88 if (peel != NULL)
89 git_oid_cpy(&ref->peel, peel);
90
91 return ref;
92 }
93
94 git_reference *git_reference__realloc(
95 git_reference **ptr_to_ref, const char *name)
96 {
97 size_t namelen, reflen;
98 git_reference *rewrite = NULL;
99
100 assert(ptr_to_ref && name);
101
102 namelen = strlen(name);
103
104 if (!GIT_ADD_SIZET_OVERFLOW(&reflen, sizeof(git_reference), namelen) &&
105 !GIT_ADD_SIZET_OVERFLOW(&reflen, reflen, 1) &&
106 (rewrite = git__realloc(*ptr_to_ref, reflen)) != NULL)
107 memcpy(rewrite->name, name, namelen + 1);
108
109 *ptr_to_ref = NULL;
110
111 return rewrite;
112 }
113
114 int git_reference_dup(git_reference **dest, git_reference *source)
115 {
116 if (source->type == GIT_REFERENCE_SYMBOLIC)
117 *dest = git_reference__alloc_symbolic(source->name, source->target.symbolic);
118 else
119 *dest = git_reference__alloc(source->name, &source->target.oid, &source->peel);
120
121 GIT_ERROR_CHECK_ALLOC(*dest);
122
123 (*dest)->db = source->db;
124 GIT_REFCOUNT_INC((*dest)->db);
125
126 return 0;
127 }
128
129 void git_reference_free(git_reference *reference)
130 {
131 if (reference == NULL)
132 return;
133
134 if (reference->type == GIT_REFERENCE_SYMBOLIC)
135 git__free(reference->target.symbolic);
136
137 if (reference->db)
138 GIT_REFCOUNT_DEC(reference->db, git_refdb__free);
139
140 git__free(reference);
141 }
142
143 int git_reference_delete(git_reference *ref)
144 {
145 const git_oid *old_id = NULL;
146 const char *old_target = NULL;
147
148 if (!strcmp(ref->name, "HEAD")) {
149 git_error_set(GIT_ERROR_REFERENCE, "cannot delete HEAD");
150 return GIT_ERROR;
151 }
152
153 if (ref->type == GIT_REFERENCE_DIRECT)
154 old_id = &ref->target.oid;
155 else
156 old_target = ref->target.symbolic;
157
158 return git_refdb_delete(ref->db, ref->name, old_id, old_target);
159 }
160
161 int git_reference_remove(git_repository *repo, const char *name)
162 {
163 git_refdb *db;
164 int error;
165
166 if ((error = git_repository_refdb__weakptr(&db, repo)) < 0)
167 return error;
168
169 return git_refdb_delete(db, name, NULL, NULL);
170 }
171
172 int git_reference_lookup(git_reference **ref_out,
173 git_repository *repo, const char *name)
174 {
175 return git_reference_lookup_resolved(ref_out, repo, name, 0);
176 }
177
178 int git_reference_name_to_id(
179 git_oid *out, git_repository *repo, const char *name)
180 {
181 int error;
182 git_reference *ref;
183
184 if ((error = git_reference_lookup_resolved(&ref, repo, name, -1)) < 0)
185 return error;
186
187 git_oid_cpy(out, git_reference_target(ref));
188 git_reference_free(ref);
189 return 0;
190 }
191
192 static int reference_normalize_for_repo(
193 git_refname_t out,
194 git_repository *repo,
195 const char *name,
196 bool validate)
197 {
198 int precompose;
199 unsigned int flags = GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL;
200
201 if (!git_repository__configmap_lookup(&precompose, repo, GIT_CONFIGMAP_PRECOMPOSE) &&
202 precompose)
203 flags |= GIT_REFERENCE_FORMAT__PRECOMPOSE_UNICODE;
204
205 if (!validate)
206 flags |= GIT_REFERENCE_FORMAT__VALIDATION_DISABLE;
207
208 return git_reference_normalize_name(out, GIT_REFNAME_MAX, name, flags);
209 }
210
211 int git_reference_lookup_resolved(
212 git_reference **ref_out,
213 git_repository *repo,
214 const char *name,
215 int max_nesting)
216 {
217 git_refname_t scan_name;
218 git_reference_t scan_type;
219 int error = 0, nesting;
220 git_reference *ref = NULL;
221 git_refdb *refdb;
222
223 assert(ref_out && repo && name);
224
225 *ref_out = NULL;
226
227 if (max_nesting > MAX_NESTING_LEVEL)
228 max_nesting = MAX_NESTING_LEVEL;
229 else if (max_nesting < 0)
230 max_nesting = DEFAULT_NESTING_LEVEL;
231
232 scan_type = GIT_REFERENCE_SYMBOLIC;
233
234 if ((error = reference_normalize_for_repo(scan_name, repo, name, true)) < 0)
235 return error;
236
237 if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
238 return error;
239
240 for (nesting = max_nesting;
241 nesting >= 0 && scan_type == GIT_REFERENCE_SYMBOLIC;
242 nesting--)
243 {
244 if (nesting != max_nesting) {
245 strncpy(scan_name, ref->target.symbolic, sizeof(scan_name));
246 git_reference_free(ref);
247 }
248
249 if ((error = git_refdb_lookup(&ref, refdb, scan_name)) < 0)
250 return error;
251
252 scan_type = ref->type;
253 }
254
255 if (scan_type != GIT_REFERENCE_DIRECT && max_nesting != 0) {
256 git_error_set(GIT_ERROR_REFERENCE,
257 "cannot resolve reference (>%u levels deep)", max_nesting);
258 git_reference_free(ref);
259 return -1;
260 }
261
262 *ref_out = ref;
263 return 0;
264 }
265
266 int git_reference__read_head(
267 git_reference **out,
268 git_repository *repo,
269 const char *path)
270 {
271 git_buf reference = GIT_BUF_INIT;
272 char *name = NULL;
273 int error;
274
275 if ((error = git_futils_readbuffer(&reference, path)) < 0)
276 goto out;
277 git_buf_rtrim(&reference);
278
279 if (git__strncmp(reference.ptr, GIT_SYMREF, strlen(GIT_SYMREF)) == 0) {
280 git_buf_consume(&reference, reference.ptr + strlen(GIT_SYMREF));
281
282 name = git_path_basename(path);
283
284 if ((*out = git_reference__alloc_symbolic(name, reference.ptr)) == NULL) {
285 error = -1;
286 goto out;
287 }
288 } else {
289 if ((error = git_reference_lookup(out, repo, reference.ptr)) < 0)
290 goto out;
291 }
292
293 out:
294 git__free(name);
295 git_buf_dispose(&reference);
296
297 return error;
298 }
299
300 int git_reference_dwim(git_reference **out, git_repository *repo, const char *refname)
301 {
302 int error = 0, i;
303 bool fallbackmode = true, foundvalid = false;
304 git_reference *ref;
305 git_buf refnamebuf = GIT_BUF_INIT, name = GIT_BUF_INIT;
306
307 static const char* formatters[] = {
308 "%s",
309 GIT_REFS_DIR "%s",
310 GIT_REFS_TAGS_DIR "%s",
311 GIT_REFS_HEADS_DIR "%s",
312 GIT_REFS_REMOTES_DIR "%s",
313 GIT_REFS_REMOTES_DIR "%s/" GIT_HEAD_FILE,
314 NULL
315 };
316
317 if (*refname)
318 git_buf_puts(&name, refname);
319 else {
320 git_buf_puts(&name, GIT_HEAD_FILE);
321 fallbackmode = false;
322 }
323
324 for (i = 0; formatters[i] && (fallbackmode || i == 0); i++) {
325
326 git_buf_clear(&refnamebuf);
327
328 if ((error = git_buf_printf(&refnamebuf, formatters[i], git_buf_cstr(&name))) < 0)
329 goto cleanup;
330
331 if (!git_reference_is_valid_name(git_buf_cstr(&refnamebuf))) {
332 error = GIT_EINVALIDSPEC;
333 continue;
334 }
335 foundvalid = true;
336
337 error = git_reference_lookup_resolved(&ref, repo, git_buf_cstr(&refnamebuf), -1);
338
339 if (!error) {
340 *out = ref;
341 error = 0;
342 goto cleanup;
343 }
344
345 if (error != GIT_ENOTFOUND)
346 goto cleanup;
347 }
348
349 cleanup:
350 if (error && !foundvalid) {
351 /* never found a valid reference name */
352 git_error_set(GIT_ERROR_REFERENCE,
353 "could not use '%s' as valid reference name", git_buf_cstr(&name));
354 }
355
356 if (error == GIT_ENOTFOUND)
357 git_error_set(GIT_ERROR_REFERENCE, "no reference found for shorthand '%s'", refname);
358
359 git_buf_dispose(&name);
360 git_buf_dispose(&refnamebuf);
361 return error;
362 }
363
364 /**
365 * Getters
366 */
367 git_reference_t git_reference_type(const git_reference *ref)
368 {
369 assert(ref);
370 return ref->type;
371 }
372
373 const char *git_reference_name(const git_reference *ref)
374 {
375 assert(ref);
376 return ref->name;
377 }
378
379 git_repository *git_reference_owner(const git_reference *ref)
380 {
381 assert(ref);
382 return ref->db->repo;
383 }
384
385 const git_oid *git_reference_target(const git_reference *ref)
386 {
387 assert(ref);
388
389 if (ref->type != GIT_REFERENCE_DIRECT)
390 return NULL;
391
392 return &ref->target.oid;
393 }
394
395 const git_oid *git_reference_target_peel(const git_reference *ref)
396 {
397 assert(ref);
398
399 if (ref->type != GIT_REFERENCE_DIRECT || git_oid_is_zero(&ref->peel))
400 return NULL;
401
402 return &ref->peel;
403 }
404
405 const char *git_reference_symbolic_target(const git_reference *ref)
406 {
407 assert(ref);
408
409 if (ref->type != GIT_REFERENCE_SYMBOLIC)
410 return NULL;
411
412 return ref->target.symbolic;
413 }
414
415 static int reference__create(
416 git_reference **ref_out,
417 git_repository *repo,
418 const char *name,
419 const git_oid *oid,
420 const char *symbolic,
421 int force,
422 const git_signature *signature,
423 const char *log_message,
424 const git_oid *old_id,
425 const char *old_target)
426 {
427 git_refname_t normalized;
428 git_refdb *refdb;
429 git_reference *ref = NULL;
430 int error = 0;
431
432 assert(repo && name);
433 assert(symbolic || signature);
434
435 if (ref_out)
436 *ref_out = NULL;
437
438 error = reference_normalize_for_repo(normalized, repo, name, true);
439 if (error < 0)
440 return error;
441
442 error = git_repository_refdb__weakptr(&refdb, repo);
443 if (error < 0)
444 return error;
445
446 if (oid != NULL) {
447 assert(symbolic == NULL);
448
449 if (!git_object__is_valid(repo, oid, GIT_OBJECT_ANY)) {
450 git_error_set(GIT_ERROR_REFERENCE,
451 "target OID for the reference doesn't exist on the repository");
452 return -1;
453 }
454
455 ref = git_reference__alloc(normalized, oid, NULL);
456 } else {
457 git_refname_t normalized_target;
458
459 error = reference_normalize_for_repo(normalized_target, repo,
460 symbolic, git_reference__enable_symbolic_ref_target_validation);
461
462 if (error < 0)
463 return error;
464
465 ref = git_reference__alloc_symbolic(normalized, normalized_target);
466 }
467
468 GIT_ERROR_CHECK_ALLOC(ref);
469
470 if ((error = git_refdb_write(refdb, ref, force, signature, log_message, old_id, old_target)) < 0) {
471 git_reference_free(ref);
472 return error;
473 }
474
475 if (ref_out == NULL)
476 git_reference_free(ref);
477 else
478 *ref_out = ref;
479
480 return 0;
481 }
482
483 int configured_ident(git_signature **out, const git_repository *repo)
484 {
485 if (repo->ident_name && repo->ident_email)
486 return git_signature_now(out, repo->ident_name, repo->ident_email);
487
488 /* if not configured let us fall-through to the next method */
489 return -1;
490 }
491
492 int git_reference__log_signature(git_signature **out, git_repository *repo)
493 {
494 int error;
495 git_signature *who;
496
497 if(((error = configured_ident(&who, repo)) < 0) &&
498 ((error = git_signature_default(&who, repo)) < 0) &&
499 ((error = git_signature_now(&who, "unknown", "unknown")) < 0))
500 return error;
501
502 *out = who;
503 return 0;
504 }
505
506 int git_reference_create_matching(
507 git_reference **ref_out,
508 git_repository *repo,
509 const char *name,
510 const git_oid *id,
511 int force,
512 const git_oid *old_id,
513 const char *log_message)
514
515 {
516 int error;
517 git_signature *who = NULL;
518
519 assert(id);
520
521 if ((error = git_reference__log_signature(&who, repo)) < 0)
522 return error;
523
524 error = reference__create(
525 ref_out, repo, name, id, NULL, force, who, log_message, old_id, NULL);
526
527 git_signature_free(who);
528 return error;
529 }
530
531 int git_reference_create(
532 git_reference **ref_out,
533 git_repository *repo,
534 const char *name,
535 const git_oid *id,
536 int force,
537 const char *log_message)
538 {
539 return git_reference_create_matching(ref_out, repo, name, id, force, NULL, log_message);
540 }
541
542 int git_reference_symbolic_create_matching(
543 git_reference **ref_out,
544 git_repository *repo,
545 const char *name,
546 const char *target,
547 int force,
548 const char *old_target,
549 const char *log_message)
550 {
551 int error;
552 git_signature *who = NULL;
553
554 assert(target);
555
556 if ((error = git_reference__log_signature(&who, repo)) < 0)
557 return error;
558
559 error = reference__create(
560 ref_out, repo, name, NULL, target, force, who, log_message, NULL, old_target);
561
562 git_signature_free(who);
563 return error;
564 }
565
566 int git_reference_symbolic_create(
567 git_reference **ref_out,
568 git_repository *repo,
569 const char *name,
570 const char *target,
571 int force,
572 const char *log_message)
573 {
574 return git_reference_symbolic_create_matching(ref_out, repo, name, target, force, NULL, log_message);
575 }
576
577 static int ensure_is_an_updatable_direct_reference(git_reference *ref)
578 {
579 if (ref->type == GIT_REFERENCE_DIRECT)
580 return 0;
581
582 git_error_set(GIT_ERROR_REFERENCE, "cannot set OID on symbolic reference");
583 return -1;
584 }
585
586 int git_reference_set_target(
587 git_reference **out,
588 git_reference *ref,
589 const git_oid *id,
590 const char *log_message)
591 {
592 int error;
593 git_repository *repo;
594
595 assert(out && ref && id);
596
597 repo = ref->db->repo;
598
599 if ((error = ensure_is_an_updatable_direct_reference(ref)) < 0)
600 return error;
601
602 return git_reference_create_matching(out, repo, ref->name, id, 1, &ref->target.oid, log_message);
603 }
604
605 static int ensure_is_an_updatable_symbolic_reference(git_reference *ref)
606 {
607 if (ref->type == GIT_REFERENCE_SYMBOLIC)
608 return 0;
609
610 git_error_set(GIT_ERROR_REFERENCE, "cannot set symbolic target on a direct reference");
611 return -1;
612 }
613
614 int git_reference_symbolic_set_target(
615 git_reference **out,
616 git_reference *ref,
617 const char *target,
618 const char *log_message)
619 {
620 int error;
621
622 assert(out && ref && target);
623
624 if ((error = ensure_is_an_updatable_symbolic_reference(ref)) < 0)
625 return error;
626
627 return git_reference_symbolic_create_matching(
628 out, ref->db->repo, ref->name, target, 1, ref->target.symbolic, log_message);
629 }
630
631 typedef struct {
632 const char *old_name;
633 git_refname_t new_name;
634 } rename_cb_data;
635
636 static int update_wt_heads(git_repository *repo, const char *path, void *payload)
637 {
638 rename_cb_data *data = (rename_cb_data *) payload;
639 git_reference *head = NULL;
640 char *gitdir = NULL;
641 int error;
642
643 if ((error = git_reference__read_head(&head, repo, path)) < 0) {
644 git_error_set(GIT_ERROR_REFERENCE, "could not read HEAD when renaming references");
645 goto out;
646 }
647
648 if ((gitdir = git_path_dirname(path)) == NULL) {
649 error = -1;
650 goto out;
651 }
652
653 if (git_reference_type(head) != GIT_REFERENCE_SYMBOLIC ||
654 git__strcmp(head->target.symbolic, data->old_name) != 0) {
655 error = 0;
656 goto out;
657 }
658
659 /* Update HEAD it was pointing to the reference being renamed */
660 if ((error = git_repository_create_head(gitdir, data->new_name)) < 0) {
661 git_error_set(GIT_ERROR_REFERENCE, "failed to update HEAD after renaming reference");
662 goto out;
663 }
664
665 out:
666 git_reference_free(head);
667 git__free(gitdir);
668
669 return error;
670 }
671
672 static int reference__rename(git_reference **out, git_reference *ref, const char *new_name, int force,
673 const git_signature *signature, const char *message)
674 {
675 git_repository *repo;
676 git_refname_t normalized;
677 bool should_head_be_updated = false;
678 int error = 0;
679
680 assert(ref && new_name && signature);
681
682 repo = git_reference_owner(ref);
683
684 if ((error = reference_normalize_for_repo(
685 normalized, repo, new_name, true)) < 0)
686 return error;
687
688 /* Check if we have to update HEAD. */
689 if ((error = git_branch_is_head(ref)) < 0)
690 return error;
691
692 should_head_be_updated = (error > 0);
693
694 if ((error = git_refdb_rename(out, ref->db, ref->name, normalized, force, signature, message)) < 0)
695 return error;
696
697 /* Update HEAD if it was pointing to the reference being renamed */
698 if (should_head_be_updated) {
699 error = git_repository_set_head(ref->db->repo, normalized);
700 } else {
701 rename_cb_data payload;
702 payload.old_name = ref->name;
703 memcpy(&payload.new_name, &normalized, sizeof(normalized));
704
705 error = git_repository_foreach_head(repo, update_wt_heads, 0, &payload);
706 }
707
708 return error;
709 }
710
711
712 int git_reference_rename(
713 git_reference **out,
714 git_reference *ref,
715 const char *new_name,
716 int force,
717 const char *log_message)
718 {
719 git_signature *who;
720 int error;
721
722 assert(out && ref);
723
724 if ((error = git_reference__log_signature(&who, ref->db->repo)) < 0)
725 return error;
726
727 error = reference__rename(out, ref, new_name, force, who, log_message);
728 git_signature_free(who);
729
730 return error;
731 }
732
733 int git_reference_resolve(git_reference **ref_out, const git_reference *ref)
734 {
735 switch (git_reference_type(ref)) {
736 case GIT_REFERENCE_DIRECT:
737 return git_reference_lookup(ref_out, ref->db->repo, ref->name);
738
739 case GIT_REFERENCE_SYMBOLIC:
740 return git_reference_lookup_resolved(ref_out, ref->db->repo, ref->target.symbolic, -1);
741
742 default:
743 git_error_set(GIT_ERROR_REFERENCE, "invalid reference");
744 return -1;
745 }
746 }
747
748 int git_reference_foreach(
749 git_repository *repo,
750 git_reference_foreach_cb callback,
751 void *payload)
752 {
753 git_reference_iterator *iter;
754 git_reference *ref;
755 int error;
756
757 if ((error = git_reference_iterator_new(&iter, repo)) < 0)
758 return error;
759
760 while (!(error = git_reference_next(&ref, iter))) {
761 if ((error = callback(ref, payload)) != 0) {
762 git_error_set_after_callback(error);
763 break;
764 }
765 }
766
767 if (error == GIT_ITEROVER)
768 error = 0;
769
770 git_reference_iterator_free(iter);
771 return error;
772 }
773
774 int git_reference_foreach_name(
775 git_repository *repo,
776 git_reference_foreach_name_cb callback,
777 void *payload)
778 {
779 git_reference_iterator *iter;
780 const char *refname;
781 int error;
782
783 if ((error = git_reference_iterator_new(&iter, repo)) < 0)
784 return error;
785
786 while (!(error = git_reference_next_name(&refname, iter))) {
787 if ((error = callback(refname, payload)) != 0) {
788 git_error_set_after_callback(error);
789 break;
790 }
791 }
792
793 if (error == GIT_ITEROVER)
794 error = 0;
795
796 git_reference_iterator_free(iter);
797 return error;
798 }
799
800 int git_reference_foreach_glob(
801 git_repository *repo,
802 const char *glob,
803 git_reference_foreach_name_cb callback,
804 void *payload)
805 {
806 git_reference_iterator *iter;
807 const char *refname;
808 int error;
809
810 if ((error = git_reference_iterator_glob_new(&iter, repo, glob)) < 0)
811 return error;
812
813 while (!(error = git_reference_next_name(&refname, iter))) {
814 if ((error = callback(refname, payload)) != 0) {
815 git_error_set_after_callback(error);
816 break;
817 }
818 }
819
820 if (error == GIT_ITEROVER)
821 error = 0;
822
823 git_reference_iterator_free(iter);
824 return error;
825 }
826
827 int git_reference_iterator_new(git_reference_iterator **out, git_repository *repo)
828 {
829 git_refdb *refdb;
830
831 if (git_repository_refdb__weakptr(&refdb, repo) < 0)
832 return -1;
833
834 return git_refdb_iterator(out, refdb, NULL);
835 }
836
837 int git_reference_iterator_glob_new(
838 git_reference_iterator **out, git_repository *repo, const char *glob)
839 {
840 git_refdb *refdb;
841
842 if (git_repository_refdb__weakptr(&refdb, repo) < 0)
843 return -1;
844
845 return git_refdb_iterator(out, refdb, glob);
846 }
847
848 int git_reference_next(git_reference **out, git_reference_iterator *iter)
849 {
850 return git_refdb_iterator_next(out, iter);
851 }
852
853 int git_reference_next_name(const char **out, git_reference_iterator *iter)
854 {
855 return git_refdb_iterator_next_name(out, iter);
856 }
857
858 void git_reference_iterator_free(git_reference_iterator *iter)
859 {
860 if (iter == NULL)
861 return;
862
863 git_refdb_iterator_free(iter);
864 }
865
866 static int cb__reflist_add(const char *ref, void *data)
867 {
868 char *name = git__strdup(ref);
869 GIT_ERROR_CHECK_ALLOC(name);
870 return git_vector_insert((git_vector *)data, name);
871 }
872
873 int git_reference_list(
874 git_strarray *array,
875 git_repository *repo)
876 {
877 git_vector ref_list;
878
879 assert(array && repo);
880
881 array->strings = NULL;
882 array->count = 0;
883
884 if (git_vector_init(&ref_list, 8, NULL) < 0)
885 return -1;
886
887 if (git_reference_foreach_name(
888 repo, &cb__reflist_add, (void *)&ref_list) < 0) {
889 git_vector_free(&ref_list);
890 return -1;
891 }
892
893 array->strings = (char **)git_vector_detach(&array->count, NULL, &ref_list);
894
895 return 0;
896 }
897
898 static int is_valid_ref_char(char ch)
899 {
900 if ((unsigned) ch <= ' ')
901 return 0;
902
903 switch (ch) {
904 case '~':
905 case '^':
906 case ':':
907 case '\\':
908 case '?':
909 case '[':
910 return 0;
911 default:
912 return 1;
913 }
914 }
915
916 static int ensure_segment_validity(const char *name, char may_contain_glob)
917 {
918 const char *current = name;
919 char prev = '\0';
920 const int lock_len = (int)strlen(GIT_FILELOCK_EXTENSION);
921 int segment_len;
922
923 if (*current == '.')
924 return -1; /* Refname starts with "." */
925
926 for (current = name; ; current++) {
927 if (*current == '\0' || *current == '/')
928 break;
929
930 if (!is_valid_ref_char(*current))
931 return -1; /* Illegal character in refname */
932
933 if (prev == '.' && *current == '.')
934 return -1; /* Refname contains ".." */
935
936 if (prev == '@' && *current == '{')
937 return -1; /* Refname contains "@{" */
938
939 if (*current == '*') {
940 if (!may_contain_glob)
941 return -1;
942 may_contain_glob = 0;
943 }
944
945 prev = *current;
946 }
947
948 segment_len = (int)(current - name);
949
950 /* A refname component can not end with ".lock" */
951 if (segment_len >= lock_len &&
952 !memcmp(current - lock_len, GIT_FILELOCK_EXTENSION, lock_len))
953 return -1;
954
955 return segment_len;
956 }
957
958 static bool is_all_caps_and_underscore(const char *name, size_t len)
959 {
960 size_t i;
961 char c;
962
963 assert(name && len > 0);
964
965 for (i = 0; i < len; i++)
966 {
967 c = name[i];
968 if ((c < 'A' || c > 'Z') && c != '_')
969 return false;
970 }
971
972 if (*name == '_' || name[len - 1] == '_')
973 return false;
974
975 return true;
976 }
977
978 /* Inspired from https://github.com/git/git/blob/f06d47e7e0d9db709ee204ed13a8a7486149f494/refs.c#L36-100 */
979 int git_reference__normalize_name(
980 git_buf *buf,
981 const char *name,
982 unsigned int flags)
983 {
984 const char *current;
985 int segment_len, segments_count = 0, error = GIT_EINVALIDSPEC;
986 unsigned int process_flags;
987 bool normalize = (buf != NULL);
988 bool validate = (flags & GIT_REFERENCE_FORMAT__VALIDATION_DISABLE) == 0;
989
990 #ifdef GIT_USE_ICONV
991 git_path_iconv_t ic = GIT_PATH_ICONV_INIT;
992 #endif
993
994 assert(name);
995
996 process_flags = flags;
997 current = (char *)name;
998
999 if (validate && *current == '/')
1000 goto cleanup;
1001
1002 if (normalize)
1003 git_buf_clear(buf);
1004
1005 #ifdef GIT_USE_ICONV
1006 if ((flags & GIT_REFERENCE_FORMAT__PRECOMPOSE_UNICODE) != 0) {
1007 size_t namelen = strlen(current);
1008 if ((error = git_path_iconv_init_precompose(&ic)) < 0 ||
1009 (error = git_path_iconv(&ic, &current, &namelen)) < 0)
1010 goto cleanup;
1011 error = GIT_EINVALIDSPEC;
1012 }
1013 #endif
1014
1015 if (!validate) {
1016 git_buf_sets(buf, current);
1017
1018 error = git_buf_oom(buf) ? -1 : 0;
1019 goto cleanup;
1020 }
1021
1022 while (true) {
1023 char may_contain_glob = process_flags & GIT_REFERENCE_FORMAT_REFSPEC_PATTERN;
1024
1025 segment_len = ensure_segment_validity(current, may_contain_glob);
1026 if (segment_len < 0)
1027 goto cleanup;
1028
1029 if (segment_len > 0) {
1030 /*
1031 * There may only be one glob in a pattern, thus we reset
1032 * the pattern-flag in case the current segment has one.
1033 */
1034 if (memchr(current, '*', segment_len))
1035 process_flags &= ~GIT_REFERENCE_FORMAT_REFSPEC_PATTERN;
1036
1037 if (normalize) {
1038 size_t cur_len = git_buf_len(buf);
1039
1040 git_buf_joinpath(buf, git_buf_cstr(buf), current);
1041 git_buf_truncate(buf,
1042 cur_len + segment_len + (segments_count ? 1 : 0));
1043
1044 if (git_buf_oom(buf)) {
1045 error = -1;
1046 goto cleanup;
1047 }
1048 }
1049
1050 segments_count++;
1051 }
1052
1053 /* No empty segment is allowed when not normalizing */
1054 if (segment_len == 0 && !normalize)
1055 goto cleanup;
1056
1057 if (current[segment_len] == '\0')
1058 break;
1059
1060 current += segment_len + 1;
1061 }
1062
1063 /* A refname can not be empty */
1064 if (segment_len == 0 && segments_count == 0)
1065 goto cleanup;
1066
1067 /* A refname can not end with "." */
1068 if (current[segment_len - 1] == '.')
1069 goto cleanup;
1070
1071 /* A refname can not end with "/" */
1072 if (current[segment_len - 1] == '/')
1073 goto cleanup;
1074
1075 if ((segments_count == 1 ) && !(flags & GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL))
1076 goto cleanup;
1077
1078 if ((segments_count == 1 ) &&
1079 !(flags & GIT_REFERENCE_FORMAT_REFSPEC_SHORTHAND) &&
1080 !(is_all_caps_and_underscore(name, (size_t)segment_len) ||
1081 ((flags & GIT_REFERENCE_FORMAT_REFSPEC_PATTERN) && !strcmp("*", name))))
1082 goto cleanup;
1083
1084 if ((segments_count > 1)
1085 && (is_all_caps_and_underscore(name, strchr(name, '/') - name)))
1086 goto cleanup;
1087
1088 error = 0;
1089
1090 cleanup:
1091 if (error == GIT_EINVALIDSPEC)
1092 git_error_set(
1093 GIT_ERROR_REFERENCE,
1094 "the given reference name '%s' is not valid", name);
1095
1096 if (error && normalize)
1097 git_buf_dispose(buf);
1098
1099 #ifdef GIT_USE_ICONV
1100 git_path_iconv_clear(&ic);
1101 #endif
1102
1103 return error;
1104 }
1105
1106 int git_reference_normalize_name(
1107 char *buffer_out,
1108 size_t buffer_size,
1109 const char *name,
1110 unsigned int flags)
1111 {
1112 git_buf buf = GIT_BUF_INIT;
1113 int error;
1114
1115 if ((error = git_reference__normalize_name(&buf, name, flags)) < 0)
1116 goto cleanup;
1117
1118 if (git_buf_len(&buf) > buffer_size - 1) {
1119 git_error_set(
1120 GIT_ERROR_REFERENCE,
1121 "the provided buffer is too short to hold the normalization of '%s'", name);
1122 error = GIT_EBUFS;
1123 goto cleanup;
1124 }
1125
1126 git_buf_copy_cstr(buffer_out, buffer_size, &buf);
1127
1128 error = 0;
1129
1130 cleanup:
1131 git_buf_dispose(&buf);
1132 return error;
1133 }
1134
1135 #define GIT_REFERENCE_TYPEMASK (GIT_REFERENCE_DIRECT | GIT_REFERENCE_SYMBOLIC)
1136
1137 int git_reference_cmp(
1138 const git_reference *ref1,
1139 const git_reference *ref2)
1140 {
1141 git_reference_t type1, type2;
1142 assert(ref1 && ref2);
1143
1144 type1 = git_reference_type(ref1);
1145 type2 = git_reference_type(ref2);
1146
1147 /* let's put symbolic refs before OIDs */
1148 if (type1 != type2)
1149 return (type1 == GIT_REFERENCE_SYMBOLIC) ? -1 : 1;
1150
1151 if (type1 == GIT_REFERENCE_SYMBOLIC)
1152 return strcmp(ref1->target.symbolic, ref2->target.symbolic);
1153
1154 return git_oid__cmp(&ref1->target.oid, &ref2->target.oid);
1155 }
1156
1157 /**
1158 * Get the end of a chain of references. If the final one is not
1159 * found, we return the reference just before that.
1160 */
1161 static int get_terminal(git_reference **out, git_repository *repo, const char *ref_name, int nesting)
1162 {
1163 git_reference *ref;
1164 int error = 0;
1165
1166 if (nesting > MAX_NESTING_LEVEL) {
1167 git_error_set(GIT_ERROR_REFERENCE, "reference chain too deep (%d)", nesting);
1168 return GIT_ENOTFOUND;
1169 }
1170
1171 /* set to NULL to let the caller know that they're at the end of the chain */
1172 if ((error = git_reference_lookup(&ref, repo, ref_name)) < 0) {
1173 *out = NULL;
1174 return error;
1175 }
1176
1177 if (git_reference_type(ref) == GIT_REFERENCE_DIRECT) {
1178 *out = ref;
1179 error = 0;
1180 } else {
1181 error = get_terminal(out, repo, git_reference_symbolic_target(ref), nesting + 1);
1182 if (error == GIT_ENOTFOUND && !*out)
1183 *out = ref;
1184 else
1185 git_reference_free(ref);
1186 }
1187
1188 return error;
1189 }
1190
1191 /*
1192 * Starting with the reference given by `ref_name`, follows symbolic
1193 * references until a direct reference is found and updated the OID
1194 * on that direct reference to `oid`.
1195 */
1196 int git_reference__update_terminal(
1197 git_repository *repo,
1198 const char *ref_name,
1199 const git_oid *oid,
1200 const git_signature *sig,
1201 const char *log_message)
1202 {
1203 git_reference *ref = NULL, *ref2 = NULL;
1204 git_signature *who = NULL;
1205 const git_signature *to_use;
1206 int error = 0;
1207
1208 if (!sig && (error = git_reference__log_signature(&who, repo)) < 0)
1209 return error;
1210
1211 to_use = sig ? sig : who;
1212 error = get_terminal(&ref, repo, ref_name, 0);
1213
1214 /* found a dangling symref */
1215 if (error == GIT_ENOTFOUND && ref) {
1216 assert(git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC);
1217 git_error_clear();
1218 error = reference__create(&ref2, repo, ref->target.symbolic, oid, NULL, 0, to_use,
1219 log_message, NULL, NULL);
1220 } else if (error == GIT_ENOTFOUND) {
1221 git_error_clear();
1222 error = reference__create(&ref2, repo, ref_name, oid, NULL, 0, to_use,
1223 log_message, NULL, NULL);
1224 } else if (error == 0) {
1225 assert(git_reference_type(ref) == GIT_REFERENCE_DIRECT);
1226 error = reference__create(&ref2, repo, ref->name, oid, NULL, 1, to_use,
1227 log_message, &ref->target.oid, NULL);
1228 }
1229
1230 git_reference_free(ref2);
1231 git_reference_free(ref);
1232 git_signature_free(who);
1233 return error;
1234 }
1235
1236 static const char *commit_type(const git_commit *commit)
1237 {
1238 unsigned int count = git_commit_parentcount(commit);
1239
1240 if (count >= 2)
1241 return " (merge)";
1242 else if (count == 0)
1243 return " (initial)";
1244 else
1245 return "";
1246 }
1247
1248 int git_reference__update_for_commit(
1249 git_repository *repo,
1250 git_reference *ref,
1251 const char *ref_name,
1252 const git_oid *id,
1253 const char *operation)
1254 {
1255 git_reference *ref_new = NULL;
1256 git_commit *commit = NULL;
1257 git_buf reflog_msg = GIT_BUF_INIT;
1258 const git_signature *who;
1259 int error;
1260
1261 if ((error = git_commit_lookup(&commit, repo, id)) < 0 ||
1262 (error = git_buf_printf(&reflog_msg, "%s%s: %s",
1263 operation ? operation : "commit",
1264 commit_type(commit),
1265 git_commit_summary(commit))) < 0)
1266 goto done;
1267
1268 who = git_commit_committer(commit);
1269
1270 if (ref) {
1271 if ((error = ensure_is_an_updatable_direct_reference(ref)) < 0)
1272 return error;
1273
1274 error = reference__create(&ref_new, repo, ref->name, id, NULL, 1, who,
1275 git_buf_cstr(&reflog_msg), &ref->target.oid, NULL);
1276 }
1277 else
1278 error = git_reference__update_terminal(
1279 repo, ref_name, id, who, git_buf_cstr(&reflog_msg));
1280
1281 done:
1282 git_reference_free(ref_new);
1283 git_buf_dispose(&reflog_msg);
1284 git_commit_free(commit);
1285 return error;
1286 }
1287
1288 int git_reference_has_log(git_repository *repo, const char *refname)
1289 {
1290 int error;
1291 git_refdb *refdb;
1292
1293 assert(repo && refname);
1294
1295 if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
1296 return error;
1297
1298 return git_refdb_has_log(refdb, refname);
1299 }
1300
1301 int git_reference_ensure_log(git_repository *repo, const char *refname)
1302 {
1303 int error;
1304 git_refdb *refdb;
1305
1306 assert(repo && refname);
1307
1308 if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
1309 return error;
1310
1311 return git_refdb_ensure_log(refdb, refname);
1312 }
1313
1314 int git_reference__is_branch(const char *ref_name)
1315 {
1316 return git__prefixcmp(ref_name, GIT_REFS_HEADS_DIR) == 0;
1317 }
1318
1319 int git_reference_is_branch(const git_reference *ref)
1320 {
1321 assert(ref);
1322 return git_reference__is_branch(ref->name);
1323 }
1324
1325 int git_reference__is_remote(const char *ref_name)
1326 {
1327 return git__prefixcmp(ref_name, GIT_REFS_REMOTES_DIR) == 0;
1328 }
1329
1330 int git_reference_is_remote(const git_reference *ref)
1331 {
1332 assert(ref);
1333 return git_reference__is_remote(ref->name);
1334 }
1335
1336 int git_reference__is_tag(const char *ref_name)
1337 {
1338 return git__prefixcmp(ref_name, GIT_REFS_TAGS_DIR) == 0;
1339 }
1340
1341 int git_reference_is_tag(const git_reference *ref)
1342 {
1343 assert(ref);
1344 return git_reference__is_tag(ref->name);
1345 }
1346
1347 int git_reference__is_note(const char *ref_name)
1348 {
1349 return git__prefixcmp(ref_name, GIT_REFS_NOTES_DIR) == 0;
1350 }
1351
1352 int git_reference_is_note(const git_reference *ref)
1353 {
1354 assert(ref);
1355 return git_reference__is_note(ref->name);
1356 }
1357
1358 static int peel_error(int error, const git_reference *ref, const char* msg)
1359 {
1360 git_error_set(
1361 GIT_ERROR_INVALID,
1362 "the reference '%s' cannot be peeled - %s", git_reference_name(ref), msg);
1363 return error;
1364 }
1365
1366 int git_reference_peel(
1367 git_object **peeled,
1368 const git_reference *ref,
1369 git_object_t target_type)
1370 {
1371 const git_reference *resolved = NULL;
1372 git_reference *allocated = NULL;
1373 git_object *target = NULL;
1374 int error;
1375
1376 assert(ref);
1377
1378 if (ref->type == GIT_REFERENCE_DIRECT) {
1379 resolved = ref;
1380 } else {
1381 if ((error = git_reference_resolve(&allocated, ref)) < 0)
1382 return peel_error(error, ref, "Cannot resolve reference");
1383
1384 resolved = allocated;
1385 }
1386
1387 /*
1388 * If we try to peel an object to a tag, we cannot use
1389 * the fully peeled object, as that will always resolve
1390 * to a commit. So we only want to use the peeled value
1391 * if it is not zero and the target is not a tag.
1392 */
1393 if (target_type != GIT_OBJECT_TAG && !git_oid_is_zero(&resolved->peel)) {
1394 error = git_object_lookup(&target,
1395 git_reference_owner(ref), &resolved->peel, GIT_OBJECT_ANY);
1396 } else {
1397 error = git_object_lookup(&target,
1398 git_reference_owner(ref), &resolved->target.oid, GIT_OBJECT_ANY);
1399 }
1400
1401 if (error < 0) {
1402 peel_error(error, ref, "Cannot retrieve reference target");
1403 goto cleanup;
1404 }
1405
1406 if (target_type == GIT_OBJECT_ANY && git_object_type(target) != GIT_OBJECT_TAG)
1407 error = git_object_dup(peeled, target);
1408 else
1409 error = git_object_peel(peeled, target, target_type);
1410
1411 cleanup:
1412 git_object_free(target);
1413 git_reference_free(allocated);
1414
1415 return error;
1416 }
1417
1418 int git_reference__is_valid_name(const char *refname, unsigned int flags)
1419 {
1420 if (git_reference__normalize_name(NULL, refname, flags) < 0) {
1421 git_error_clear();
1422 return false;
1423 }
1424
1425 return true;
1426 }
1427
1428 int git_reference_is_valid_name(const char *refname)
1429 {
1430 return git_reference__is_valid_name(refname, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL);
1431 }
1432
1433 const char *git_reference__shorthand(const char *name)
1434 {
1435 if (!git__prefixcmp(name, GIT_REFS_HEADS_DIR))
1436 return name + strlen(GIT_REFS_HEADS_DIR);
1437 else if (!git__prefixcmp(name, GIT_REFS_TAGS_DIR))
1438 return name + strlen(GIT_REFS_TAGS_DIR);
1439 else if (!git__prefixcmp(name, GIT_REFS_REMOTES_DIR))
1440 return name + strlen(GIT_REFS_REMOTES_DIR);
1441 else if (!git__prefixcmp(name, GIT_REFS_DIR))
1442 return name + strlen(GIT_REFS_DIR);
1443
1444 /* No shorthands are avaiable, so just return the name */
1445 return name;
1446 }
1447
1448 const char *git_reference_shorthand(const git_reference *ref)
1449 {
1450 return git_reference__shorthand(ref->name);
1451 }
1452
1453 int git_reference__is_unborn_head(bool *unborn, const git_reference *ref, git_repository *repo)
1454 {
1455 int error;
1456 git_reference *tmp_ref;
1457 assert(unborn && ref && repo);
1458
1459 if (ref->type == GIT_REFERENCE_DIRECT) {
1460 *unborn = 0;
1461 return 0;
1462 }
1463
1464 error = git_reference_lookup_resolved(&tmp_ref, repo, ref->name, -1);
1465 git_reference_free(tmp_ref);
1466
1467 if (error != 0 && error != GIT_ENOTFOUND)
1468 return error;
1469 else if (error == GIT_ENOTFOUND && git__strcmp(ref->name, GIT_HEAD_FILE) == 0)
1470 *unborn = true;
1471 else
1472 *unborn = false;
1473
1474 return 0;
1475 }