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