File Coverage

deps/libgit2/src/refs.c
Criterion Covered Total %
statement 483 650 74.3
branch 272 496 54.8
condition n/a
subroutine n/a
pod n/a
total 755 1146 65.8


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