]> git.proxmox.com Git - libgit2.git/blob - src/refs.c
alloc doesn't take a refdb; git_refdb_free nicely in the tests
[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 #include "hash.h"
10 #include "repository.h"
11 #include "fileops.h"
12 #include "pack.h"
13 #include "reflog.h"
14 #include "refdb.h"
15
16 #include <git2/tag.h>
17 #include <git2/object.h>
18 #include <git2/oid.h>
19 #include <git2/branch.h>
20 #include <git2/refs.h>
21 #include <git2/refdb.h>
22 #include <git2/refdb_backend.h>
23
24 GIT__USE_STRMAP;
25
26 #define DEFAULT_NESTING_LEVEL 5
27 #define MAX_NESTING_LEVEL 10
28
29 enum {
30 GIT_PACKREF_HAS_PEEL = 1,
31 GIT_PACKREF_WAS_LOOSE = 2
32 };
33
34 static git_reference *alloc_ref(const char *name)
35 {
36 git_reference *ref;
37 size_t namelen = strlen(name);
38
39 if ((ref = git__calloc(1, sizeof(git_reference) + namelen + 1)) == NULL)
40 return NULL;
41
42 memcpy(ref->name, name, namelen + 1);
43
44 return ref;
45 }
46
47 git_reference *git_reference__alloc_symbolic(
48 const char *name,
49 const char *target)
50 {
51 git_reference *ref;
52
53 assert(name && target);
54
55 ref = alloc_ref(name);
56 if (!ref)
57 return NULL;
58
59 ref->type = GIT_REF_SYMBOLIC;
60
61 if ((ref->target.symbolic = git__strdup(target)) == NULL) {
62 git__free(ref);
63 return NULL;
64 }
65
66 return ref;
67 }
68
69 git_reference *git_reference__alloc(
70 const char *name,
71 const git_oid *oid,
72 const git_oid *peel)
73 {
74 git_reference *ref;
75
76 assert(name && oid);
77
78 ref = alloc_ref(name);
79 if (!ref)
80 return NULL;
81
82 ref->type = GIT_REF_OID;
83 git_oid_cpy(&ref->target.oid, oid);
84
85 if (peel != NULL)
86 git_oid_cpy(&ref->peel, peel);
87
88 return ref;
89 }
90
91 void git_reference_free(git_reference *reference)
92 {
93 if (reference == NULL)
94 return;
95
96 if (reference->type == GIT_REF_SYMBOLIC)
97 git__free(reference->target.symbolic);
98
99 git__free(reference);
100 }
101
102 struct reference_available_t {
103 const char *new_ref;
104 const char *old_ref;
105 int available;
106 };
107
108 static int _reference_available_cb(const char *ref, void *data)
109 {
110 struct reference_available_t *d;
111
112 assert(ref && data);
113 d = (struct reference_available_t *)data;
114
115 if (!d->old_ref || strcmp(d->old_ref, ref)) {
116 size_t reflen = strlen(ref);
117 size_t newlen = strlen(d->new_ref);
118 size_t cmplen = reflen < newlen ? reflen : newlen;
119 const char *lead = reflen < newlen ? d->new_ref : ref;
120
121 if (!strncmp(d->new_ref, ref, cmplen) && lead[cmplen] == '/') {
122 d->available = 0;
123 return -1;
124 }
125 }
126
127 return 0;
128 }
129
130 static int reference_path_available(
131 git_repository *repo,
132 const char *ref,
133 const char* old_ref)
134 {
135 int error;
136 struct reference_available_t data;
137
138 data.new_ref = ref;
139 data.old_ref = old_ref;
140 data.available = 1;
141
142 error = git_reference_foreach(
143 repo, GIT_REF_LISTALL, _reference_available_cb, (void *)&data);
144 if (error < 0)
145 return error;
146
147 if (!data.available) {
148 giterr_set(GITERR_REFERENCE,
149 "The path to reference '%s' collides with an existing one", ref);
150 return -1;
151 }
152
153 return 0;
154 }
155
156 /*
157 * Check if a reference could be written to disk, based on:
158 *
159 * - Whether a reference with the same name already exists,
160 * and we are allowing or disallowing overwrites
161 *
162 * - Whether the name of the reference would collide with
163 * an existing path
164 */
165 static int reference_can_write(
166 git_repository *repo,
167 const char *refname,
168 const char *previous_name,
169 int force)
170 {
171 git_refdb *refdb;
172
173 if (git_repository_refdb__weakptr(&refdb, repo) < 0)
174 return -1;
175
176 /* see if the reference shares a path with an existing reference;
177 * if a path is shared, we cannot create the reference, even when forcing */
178 if (reference_path_available(repo, refname, previous_name) < 0)
179 return -1;
180
181 /* check if the reference actually exists, but only if we are not forcing
182 * the rename. If we are forcing, it's OK to overwrite */
183 if (!force) {
184 int exists;
185
186 if (git_refdb_exists(&exists, refdb, refname) < 0)
187 return -1;
188
189 /* We cannot proceed if the reference already exists and we're not forcing
190 * the rename; the existing one would be overwritten */
191 if (exists) {
192 giterr_set(GITERR_REFERENCE,
193 "A reference with that name (%s) already exists", refname);
194 return GIT_EEXISTS;
195 }
196 }
197
198 /* FIXME: if the reference exists and we are forcing, do we really need to
199 * remove the reference first?
200 *
201 * Two cases:
202 *
203 * - the reference already exists and is loose: not a problem, the file
204 * gets overwritten on disk
205 *
206 * - the reference already exists and is packed: we write a new one as
207 * loose, which by all means renders the packed one useless
208 */
209
210 return 0;
211 }
212
213 int git_reference_delete(git_reference *ref)
214 {
215 return git_refdb_delete(ref->db, ref);
216 }
217
218 int git_reference_lookup(git_reference **ref_out,
219 git_repository *repo, const char *name)
220 {
221 return git_reference_lookup_resolved(ref_out, repo, name, 0);
222 }
223
224 int git_reference_name_to_id(
225 git_oid *out, git_repository *repo, const char *name)
226 {
227 int error;
228 git_reference *ref;
229
230 if ((error = git_reference_lookup_resolved(&ref, repo, name, -1)) < 0)
231 return error;
232
233 git_oid_cpy(out, git_reference_target(ref));
234 git_reference_free(ref);
235 return 0;
236 }
237
238 int git_reference_lookup_resolved(
239 git_reference **ref_out,
240 git_repository *repo,
241 const char *name,
242 int max_nesting)
243 {
244 char scan_name[GIT_REFNAME_MAX];
245 git_ref_t scan_type;
246 int error = 0, nesting;
247 git_reference *ref = NULL;
248 git_refdb *refdb;
249
250 assert(ref_out && repo && name);
251
252 *ref_out = NULL;
253
254 if (max_nesting > MAX_NESTING_LEVEL)
255 max_nesting = MAX_NESTING_LEVEL;
256 else if (max_nesting < 0)
257 max_nesting = DEFAULT_NESTING_LEVEL;
258
259 strncpy(scan_name, name, GIT_REFNAME_MAX);
260 scan_type = GIT_REF_SYMBOLIC;
261
262 if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
263 return -1;
264
265 if ((error = git_reference__normalize_name_lax(scan_name, GIT_REFNAME_MAX, name)) < 0)
266 return error;
267
268 for (nesting = max_nesting;
269 nesting >= 0 && scan_type == GIT_REF_SYMBOLIC;
270 nesting--)
271 {
272 if (nesting != max_nesting) {
273 strncpy(scan_name, ref->target.symbolic, GIT_REFNAME_MAX);
274 git_reference_free(ref);
275 }
276
277 if ((error = git_refdb_lookup(&ref, refdb, scan_name)) < 0)
278 return error;
279
280 scan_type = ref->type;
281 }
282
283 if (scan_type != GIT_REF_OID && max_nesting != 0) {
284 giterr_set(GITERR_REFERENCE,
285 "Cannot resolve reference (>%u levels deep)", max_nesting);
286 git_reference_free(ref);
287 return -1;
288 }
289
290 *ref_out = ref;
291 return 0;
292 }
293
294 /**
295 * Getters
296 */
297 git_ref_t git_reference_type(const git_reference *ref)
298 {
299 assert(ref);
300 return ref->type;
301 }
302
303 const char *git_reference_name(const git_reference *ref)
304 {
305 assert(ref);
306 return ref->name;
307 }
308
309 git_repository *git_reference_owner(const git_reference *ref)
310 {
311 assert(ref);
312 return ref->db->repo;
313 }
314
315 const git_oid *git_reference_target(const git_reference *ref)
316 {
317 assert(ref);
318
319 if (ref->type != GIT_REF_OID)
320 return NULL;
321
322 return &ref->target.oid;
323 }
324
325 const git_oid *git_reference_target_peel(const git_reference *ref)
326 {
327 assert(ref);
328
329 if (ref->type != GIT_REF_OID || git_oid_iszero(&ref->peel))
330 return NULL;
331
332 return &ref->peel;
333 }
334
335 const char *git_reference_symbolic_target(const git_reference *ref)
336 {
337 assert(ref);
338
339 if (ref->type != GIT_REF_SYMBOLIC)
340 return NULL;
341
342 return ref->target.symbolic;
343 }
344
345 static int reference__create(
346 git_reference **ref_out,
347 git_repository *repo,
348 const char *name,
349 const git_oid *oid,
350 const char *symbolic,
351 int force)
352 {
353 char normalized[GIT_REFNAME_MAX];
354 git_refdb *refdb;
355 git_reference *ref = NULL;
356 int error = 0;
357
358 if (ref_out)
359 *ref_out = NULL;
360
361 if ((error = git_reference__normalize_name_lax(normalized, sizeof(normalized), name)) < 0 ||
362 (error = reference_can_write(repo, normalized, NULL, force)) < 0 ||
363 (error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
364 return error;
365
366 if (oid != NULL) {
367 assert(symbolic == NULL);
368 ref = git_reference__alloc(name, oid, NULL);
369 } else {
370 ref = git_reference__alloc_symbolic(name, symbolic);
371 }
372
373 GITERR_CHECK_ALLOC(ref);
374 ref->db = refdb;
375
376 if ((error = git_refdb_write(refdb, ref)) < 0) {
377 git_reference_free(ref);
378 return error;
379 }
380
381 if (ref_out == NULL)
382 git_reference_free(ref);
383 else
384 *ref_out = ref;
385
386 return 0;
387 }
388
389 int git_reference_create(
390 git_reference **ref_out,
391 git_repository *repo,
392 const char *name,
393 const git_oid *oid,
394 int force)
395 {
396 git_odb *odb;
397 int error = 0;
398
399 assert(repo && name && oid);
400
401 /* Sanity check the reference being created - target must exist. */
402 if ((error = git_repository_odb__weakptr(&odb, repo)) < 0)
403 return error;
404
405 if (!git_odb_exists(odb, oid)) {
406 giterr_set(GITERR_REFERENCE,
407 "Target OID for the reference doesn't exist on the repository");
408 return -1;
409 }
410
411 return reference__create(ref_out, repo, name, oid, NULL, force);
412 }
413
414 int git_reference_symbolic_create(
415 git_reference **ref_out,
416 git_repository *repo,
417 const char *name,
418 const char *target,
419 int force)
420 {
421 char normalized[GIT_REFNAME_MAX];
422 int error = 0;
423
424 assert(repo && name && target);
425
426 if ((error = git_reference__normalize_name_lax(
427 normalized, sizeof(normalized), target)) < 0)
428 return error;
429
430 return reference__create(ref_out, repo, name, NULL, normalized, force);
431 }
432
433 int git_reference_set_target(
434 git_reference **out,
435 git_reference *ref,
436 const git_oid *id)
437 {
438 assert(out && ref && id);
439
440 if (ref->type != GIT_REF_OID) {
441 giterr_set(GITERR_REFERENCE, "Cannot set OID on symbolic reference");
442 return -1;
443 }
444
445 return git_reference_create(out, ref->db->repo, ref->name, id, 1);
446 }
447
448 int git_reference_symbolic_set_target(
449 git_reference **out,
450 git_reference *ref,
451 const char *target)
452 {
453 assert(out && ref && target);
454
455 if (ref->type != GIT_REF_SYMBOLIC) {
456 giterr_set(GITERR_REFERENCE,
457 "Cannot set symbolic target on a direct reference");
458 return -1;
459 }
460
461 return git_reference_symbolic_create(out, ref->db->repo, ref->name, target, 1);
462 }
463
464 int git_reference_rename(
465 git_reference **out,
466 git_reference *ref,
467 const char *new_name,
468 int force)
469 {
470 unsigned int normalization_flags;
471 char normalized[GIT_REFNAME_MAX];
472 bool should_head_be_updated = false;
473 git_reference *result = NULL;
474 int error = 0;
475 int reference_has_log;
476
477 *out = NULL;
478
479 normalization_flags = ref->type == GIT_REF_SYMBOLIC ?
480 GIT_REF_FORMAT_ALLOW_ONELEVEL : GIT_REF_FORMAT_NORMAL;
481
482 if ((error = git_reference_normalize_name(
483 normalized, sizeof(normalized), new_name, normalization_flags)) < 0 ||
484 (error = reference_can_write(ref->db->repo, normalized, ref->name, force)) < 0)
485 return error;
486
487 /*
488 * Create the new reference.
489 */
490 if (ref->type == GIT_REF_OID) {
491 result = git_reference__alloc(new_name, &ref->target.oid, &ref->peel);
492 } else if (ref->type == GIT_REF_SYMBOLIC) {
493 result = git_reference__alloc_symbolic(new_name, ref->target.symbolic);
494 } else {
495 assert(0);
496 }
497
498 if (result == NULL)
499 return -1;
500
501 result->db = ref->db;
502
503 /* Check if we have to update HEAD. */
504 if ((error = git_branch_is_head(ref)) < 0)
505 goto on_error;
506
507 should_head_be_updated = (error > 0);
508
509 /* Now delete the old ref and save the new one. */
510 if ((error = git_refdb_delete(ref->db, ref)) < 0)
511 goto on_error;
512
513 /* Save the new reference. */
514 if ((error = git_refdb_write(ref->db, result)) < 0)
515 goto rollback;
516
517 /* Update HEAD it was poiting to the reference being renamed. */
518 if (should_head_be_updated && (error = git_repository_set_head(ref->db->repo, new_name)) < 0) {
519 giterr_set(GITERR_REFERENCE, "Failed to update HEAD after renaming reference");
520 goto on_error;
521 }
522
523 /* Rename the reflog file, if it exists. */
524 reference_has_log = git_reference_has_log(ref);
525 if (reference_has_log < 0) {
526 error = reference_has_log;
527 goto on_error;
528 }
529 if (reference_has_log && (error = git_reflog_rename(ref, new_name)) < 0)
530 goto on_error;
531
532 *out = result;
533
534 return error;
535
536 rollback:
537 git_refdb_write(ref->db, ref);
538
539 on_error:
540 git_reference_free(result);
541
542 return error;
543 }
544
545 int git_reference_resolve(git_reference **ref_out, const git_reference *ref)
546 {
547 switch (git_reference_type(ref)) {
548 case GIT_REF_OID:
549 return git_reference_lookup(ref_out, ref->db->repo, ref->name);
550
551 case GIT_REF_SYMBOLIC:
552 return git_reference_lookup_resolved(ref_out, ref->db->repo, ref->target.symbolic, -1);
553
554 default:
555 giterr_set(GITERR_REFERENCE, "Invalid reference");
556 return -1;
557 }
558 }
559
560 int git_reference_foreach(
561 git_repository *repo,
562 unsigned int list_flags,
563 git_reference_foreach_cb callback,
564 void *payload)
565 {
566 git_refdb *refdb;
567 git_repository_refdb__weakptr(&refdb, repo);
568
569 return git_refdb_foreach(refdb, list_flags, callback, payload);
570 }
571
572 static int cb__reflist_add(const char *ref, void *data)
573 {
574 return git_vector_insert((git_vector *)data, git__strdup(ref));
575 }
576
577 int git_reference_list(
578 git_strarray *array,
579 git_repository *repo,
580 unsigned int list_flags)
581 {
582 git_vector ref_list;
583
584 assert(array && repo);
585
586 array->strings = NULL;
587 array->count = 0;
588
589 if (git_vector_init(&ref_list, 8, NULL) < 0)
590 return -1;
591
592 if (git_reference_foreach(
593 repo, list_flags, &cb__reflist_add, (void *)&ref_list) < 0) {
594 git_vector_free(&ref_list);
595 return -1;
596 }
597
598 array->strings = (char **)ref_list.contents;
599 array->count = ref_list.length;
600 return 0;
601 }
602
603 static int is_valid_ref_char(char ch)
604 {
605 if ((unsigned) ch <= ' ')
606 return 0;
607
608 switch (ch) {
609 case '~':
610 case '^':
611 case ':':
612 case '\\':
613 case '?':
614 case '[':
615 case '*':
616 return 0;
617 default:
618 return 1;
619 }
620 }
621
622 static int ensure_segment_validity(const char *name)
623 {
624 const char *current = name;
625 char prev = '\0';
626 const int lock_len = (int)strlen(GIT_FILELOCK_EXTENSION);
627 int segment_len;
628
629 if (*current == '.')
630 return -1; /* Refname starts with "." */
631
632 for (current = name; ; current++) {
633 if (*current == '\0' || *current == '/')
634 break;
635
636 if (!is_valid_ref_char(*current))
637 return -1; /* Illegal character in refname */
638
639 if (prev == '.' && *current == '.')
640 return -1; /* Refname contains ".." */
641
642 if (prev == '@' && *current == '{')
643 return -1; /* Refname contains "@{" */
644
645 prev = *current;
646 }
647
648 segment_len = (int)(current - name);
649
650 /* A refname component can not end with ".lock" */
651 if (segment_len >= lock_len &&
652 !memcmp(current - lock_len, GIT_FILELOCK_EXTENSION, lock_len))
653 return -1;
654
655 return segment_len;
656 }
657
658 static bool is_all_caps_and_underscore(const char *name, size_t len)
659 {
660 size_t i;
661 char c;
662
663 assert(name && len > 0);
664
665 for (i = 0; i < len; i++)
666 {
667 c = name[i];
668 if ((c < 'A' || c > 'Z') && c != '_')
669 return false;
670 }
671
672 if (*name == '_' || name[len - 1] == '_')
673 return false;
674
675 return true;
676 }
677
678 int git_reference__normalize_name(
679 git_buf *buf,
680 const char *name,
681 unsigned int flags)
682 {
683 // Inspired from https://github.com/git/git/blob/f06d47e7e0d9db709ee204ed13a8a7486149f494/refs.c#L36-100
684
685 char *current;
686 int segment_len, segments_count = 0, error = GIT_EINVALIDSPEC;
687 unsigned int process_flags;
688 bool normalize = (buf != NULL);
689 assert(name);
690
691 process_flags = flags;
692 current = (char *)name;
693
694 if (*current == '/')
695 goto cleanup;
696
697 if (normalize)
698 git_buf_clear(buf);
699
700 while (true) {
701 segment_len = ensure_segment_validity(current);
702 if (segment_len < 0) {
703 if ((process_flags & GIT_REF_FORMAT_REFSPEC_PATTERN) &&
704 current[0] == '*' &&
705 (current[1] == '\0' || current[1] == '/')) {
706 /* Accept one wildcard as a full refname component. */
707 process_flags &= ~GIT_REF_FORMAT_REFSPEC_PATTERN;
708 segment_len = 1;
709 } else
710 goto cleanup;
711 }
712
713 if (segment_len > 0) {
714 if (normalize) {
715 size_t cur_len = git_buf_len(buf);
716
717 git_buf_joinpath(buf, git_buf_cstr(buf), current);
718 git_buf_truncate(buf,
719 cur_len + segment_len + (segments_count ? 1 : 0));
720
721 if (git_buf_oom(buf)) {
722 error = -1;
723 goto cleanup;
724 }
725 }
726
727 segments_count++;
728 }
729
730 /* No empty segment is allowed when not normalizing */
731 if (segment_len == 0 && !normalize)
732 goto cleanup;
733
734 if (current[segment_len] == '\0')
735 break;
736
737 current += segment_len + 1;
738 }
739
740 /* A refname can not be empty */
741 if (segment_len == 0 && segments_count == 0)
742 goto cleanup;
743
744 /* A refname can not end with "." */
745 if (current[segment_len - 1] == '.')
746 goto cleanup;
747
748 /* A refname can not end with "/" */
749 if (current[segment_len - 1] == '/')
750 goto cleanup;
751
752 if ((segments_count == 1 ) && !(flags & GIT_REF_FORMAT_ALLOW_ONELEVEL))
753 goto cleanup;
754
755 if ((segments_count == 1 ) &&
756 !(is_all_caps_and_underscore(name, (size_t)segment_len) ||
757 ((flags & GIT_REF_FORMAT_REFSPEC_PATTERN) && !strcmp("*", name))))
758 goto cleanup;
759
760 if ((segments_count > 1)
761 && (is_all_caps_and_underscore(name, strchr(name, '/') - name)))
762 goto cleanup;
763
764 error = 0;
765
766 cleanup:
767 if (error == GIT_EINVALIDSPEC)
768 giterr_set(
769 GITERR_REFERENCE,
770 "The given reference name '%s' is not valid", name);
771
772 if (error && normalize)
773 git_buf_free(buf);
774
775 return error;
776 }
777
778 int git_reference_normalize_name(
779 char *buffer_out,
780 size_t buffer_size,
781 const char *name,
782 unsigned int flags)
783 {
784 git_buf buf = GIT_BUF_INIT;
785 int error;
786
787 if ((error = git_reference__normalize_name(&buf, name, flags)) < 0)
788 goto cleanup;
789
790 if (git_buf_len(&buf) > buffer_size - 1) {
791 giterr_set(
792 GITERR_REFERENCE,
793 "The provided buffer is too short to hold the normalization of '%s'", name);
794 error = GIT_EBUFS;
795 goto cleanup;
796 }
797
798 git_buf_copy_cstr(buffer_out, buffer_size, &buf);
799
800 error = 0;
801
802 cleanup:
803 git_buf_free(&buf);
804 return error;
805 }
806
807 int git_reference__normalize_name_lax(
808 char *buffer_out,
809 size_t out_size,
810 const char *name)
811 {
812 return git_reference_normalize_name(
813 buffer_out,
814 out_size,
815 name,
816 GIT_REF_FORMAT_ALLOW_ONELEVEL);
817 }
818 #define GIT_REF_TYPEMASK (GIT_REF_OID | GIT_REF_SYMBOLIC)
819
820 int git_reference_cmp(git_reference *ref1, git_reference *ref2)
821 {
822 git_ref_t type1, type2;
823 assert(ref1 && ref2);
824
825 type1 = git_reference_type(ref1);
826 type2 = git_reference_type(ref2);
827
828 /* let's put symbolic refs before OIDs */
829 if (type1 != type2)
830 return (type1 == GIT_REF_SYMBOLIC) ? -1 : 1;
831
832 if (type1 == GIT_REF_SYMBOLIC)
833 return strcmp(ref1->target.symbolic, ref2->target.symbolic);
834
835 return git_oid_cmp(&ref1->target.oid, &ref2->target.oid);
836 }
837
838 static int reference__update_terminal(
839 git_repository *repo,
840 const char *ref_name,
841 const git_oid *oid,
842 int nesting)
843 {
844 git_reference *ref;
845 int error = 0;
846
847 if (nesting > MAX_NESTING_LEVEL)
848 return GIT_ENOTFOUND;
849
850 error = git_reference_lookup(&ref, repo, ref_name);
851
852 /* If we haven't found the reference at all, create a new reference. */
853 if (error == GIT_ENOTFOUND) {
854 giterr_clear();
855 return git_reference_create(NULL, repo, ref_name, oid, 0);
856 }
857
858 if (error < 0)
859 return error;
860
861 /* If the ref is a symbolic reference, follow its target. */
862 if (git_reference_type(ref) == GIT_REF_SYMBOLIC) {
863 error = reference__update_terminal(repo, git_reference_symbolic_target(ref), oid,
864 nesting+1);
865 git_reference_free(ref);
866 } else {
867 git_reference_free(ref);
868 error = git_reference_create(NULL, repo, ref_name, oid, 1);
869 }
870
871 return error;
872 }
873
874 /*
875 * Starting with the reference given by `ref_name`, follows symbolic
876 * references until a direct reference is found and updated the OID
877 * on that direct reference to `oid`.
878 */
879 int git_reference__update_terminal(
880 git_repository *repo,
881 const char *ref_name,
882 const git_oid *oid)
883 {
884 return reference__update_terminal(repo, ref_name, oid, 0);
885 }
886
887 int git_reference_foreach_glob(
888 git_repository *repo,
889 const char *glob,
890 unsigned int list_flags,
891 int (*callback)(
892 const char *reference_name,
893 void *payload),
894 void *payload)
895 {
896 git_refdb *refdb;
897
898 assert(repo && glob && callback);
899
900 git_repository_refdb__weakptr(&refdb, repo);
901
902 return git_refdb_foreach_glob(refdb, glob, list_flags, callback, payload);
903 }
904
905 int git_reference_has_log(
906 git_reference *ref)
907 {
908 git_buf path = GIT_BUF_INIT;
909 int result;
910
911 assert(ref);
912
913 if (git_buf_join_n(&path, '/', 3, ref->db->repo->path_repository,
914 GIT_REFLOG_DIR, ref->name) < 0)
915 return -1;
916
917 result = git_path_isfile(git_buf_cstr(&path));
918 git_buf_free(&path);
919
920 return result;
921 }
922
923 int git_reference__is_branch(const char *ref_name)
924 {
925 return git__prefixcmp(ref_name, GIT_REFS_HEADS_DIR) == 0;
926 }
927
928 int git_reference_is_branch(git_reference *ref)
929 {
930 assert(ref);
931 return git_reference__is_branch(ref->name);
932 }
933
934 int git_reference__is_remote(const char *ref_name)
935 {
936 return git__prefixcmp(ref_name, GIT_REFS_REMOTES_DIR) == 0;
937 }
938
939 int git_reference_is_remote(git_reference *ref)
940 {
941 assert(ref);
942 return git_reference__is_remote(ref->name);
943 }
944
945 static int peel_error(int error, git_reference *ref, const char* msg)
946 {
947 giterr_set(
948 GITERR_INVALID,
949 "The reference '%s' cannot be peeled - %s", git_reference_name(ref), msg);
950 return error;
951 }
952
953 int git_reference_peel(
954 git_object **peeled,
955 git_reference *ref,
956 git_otype target_type)
957 {
958 git_reference *resolved = NULL;
959 git_object *target = NULL;
960 int error;
961
962 assert(ref);
963
964 if (ref->type == GIT_REF_OID) {
965 resolved = ref;
966 } else {
967 if ((error = git_reference_resolve(&resolved, ref)) < 0)
968 return peel_error(error, ref, "Cannot resolve reference");
969 }
970
971 if (!git_oid_iszero(&resolved->peel)) {
972 error = git_object_lookup(&target,
973 git_reference_owner(ref), &resolved->peel, GIT_OBJ_ANY);
974 } else {
975 error = git_object_lookup(&target,
976 git_reference_owner(ref), &resolved->target.oid, GIT_OBJ_ANY);
977 }
978
979 if (error < 0) {
980 peel_error(error, ref, "Cannot retrieve reference target");
981 goto cleanup;
982 }
983
984 if (target_type == GIT_OBJ_ANY && git_object_type(target) != GIT_OBJ_TAG)
985 error = git_object_dup(peeled, target);
986 else
987 error = git_object_peel(peeled, target, target_type);
988
989 cleanup:
990 git_object_free(target);
991
992 if (resolved != ref)
993 git_reference_free(resolved);
994
995 return error;
996 }
997
998 int git_reference__is_valid_name(
999 const char *refname,
1000 unsigned int flags)
1001 {
1002 int error;
1003
1004 error = git_reference__normalize_name(NULL, refname, flags) == 0;
1005 giterr_clear();
1006
1007 return error;
1008 }
1009
1010 int git_reference_is_valid_name(
1011 const char *refname)
1012 {
1013 return git_reference__is_valid_name(
1014 refname,
1015 GIT_REF_FORMAT_ALLOW_ONELEVEL);
1016 }