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