Blame src/refs.c

Packit Service 20376f
/*
Packit Service 20376f
 * Copyright (C) the libgit2 contributors. All rights reserved.
Packit Service 20376f
 *
Packit Service 20376f
 * This file is part of libgit2, distributed under the GNU GPL v2 with
Packit Service 20376f
 * a Linking Exception. For full terms see the included COPYING file.
Packit Service 20376f
 */
Packit Service 20376f
Packit Service 20376f
#include "refs.h"
Packit Service 20376f
#include "hash.h"
Packit Service 20376f
#include "repository.h"
Packit Service 20376f
#include "fileops.h"
Packit Service 20376f
#include "filebuf.h"
Packit Service 20376f
#include "pack.h"
Packit Service 20376f
#include "reflog.h"
Packit Service 20376f
#include "refdb.h"
Packit Service 20376f
Packit Service 20376f
#include <git2/tag.h>
Packit Service 20376f
#include <git2/object.h>
Packit Service 20376f
#include <git2/oid.h>
Packit Service 20376f
#include <git2/branch.h>
Packit Service 20376f
#include <git2/refs.h>
Packit Service 20376f
#include <git2/refdb.h>
Packit Service 20376f
#include <git2/sys/refs.h>
Packit Service 20376f
#include <git2/signature.h>
Packit Service 20376f
#include <git2/commit.h>
Packit Service 20376f
Packit Service 20376f
bool git_reference__enable_symbolic_ref_target_validation = true;
Packit Service 20376f
Packit Service 20376f
#define DEFAULT_NESTING_LEVEL	5
Packit Service 20376f
#define MAX_NESTING_LEVEL		10
Packit Service 20376f
Packit Service 20376f
enum {
Packit Service 20376f
	GIT_PACKREF_HAS_PEEL = 1,
Packit Service 20376f
	GIT_PACKREF_WAS_LOOSE = 2
Packit Service 20376f
};
Packit Service 20376f
Packit Service 20376f
static git_reference *alloc_ref(const char *name)
Packit Service 20376f
{
Packit Service 20376f
	git_reference *ref = NULL;
Packit Service 20376f
	size_t namelen = strlen(name), reflen;
Packit Service 20376f
Packit Service 20376f
	if (!GIT_ADD_SIZET_OVERFLOW(&reflen, sizeof(git_reference), namelen) &&
Packit Service 20376f
		!GIT_ADD_SIZET_OVERFLOW(&reflen, reflen, 1) &&
Packit Service 20376f
		(ref = git__calloc(1, reflen)) != NULL)
Packit Service 20376f
		memcpy(ref->name, name, namelen + 1);
Packit Service 20376f
Packit Service 20376f
	return ref;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
git_reference *git_reference__alloc_symbolic(
Packit Service 20376f
	const char *name, const char *target)
Packit Service 20376f
{
Packit Service 20376f
	git_reference *ref;
Packit Service 20376f
Packit Service 20376f
	assert(name && target);
Packit Service 20376f
Packit Service 20376f
	ref = alloc_ref(name);
Packit Service 20376f
	if (!ref)
Packit Service 20376f
		return NULL;
Packit Service 20376f
Packit Service 20376f
	ref->type = GIT_REF_SYMBOLIC;
Packit Service 20376f
Packit Service 20376f
	if ((ref->target.symbolic = git__strdup(target)) == NULL) {
Packit Service 20376f
		git__free(ref);
Packit Service 20376f
		return NULL;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	return ref;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
git_reference *git_reference__alloc(
Packit Service 20376f
	const char *name,
Packit Service 20376f
	const git_oid *oid,
Packit Service 20376f
	const git_oid *peel)
Packit Service 20376f
{
Packit Service 20376f
	git_reference *ref;
Packit Service 20376f
Packit Service 20376f
	assert(name && oid);
Packit Service 20376f
Packit Service 20376f
	ref = alloc_ref(name);
Packit Service 20376f
	if (!ref)
Packit Service 20376f
		return NULL;
Packit Service 20376f
Packit Service 20376f
	ref->type = GIT_REF_OID;
Packit Service 20376f
	git_oid_cpy(&ref->target.oid, oid);
Packit Service 20376f
Packit Service 20376f
	if (peel != NULL)
Packit Service 20376f
		git_oid_cpy(&ref->peel, peel);
Packit Service 20376f
Packit Service 20376f
	return ref;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
git_reference *git_reference__set_name(
Packit Service 20376f
	git_reference *ref, const char *name)
Packit Service 20376f
{
Packit Service 20376f
	size_t namelen = strlen(name);
Packit Service 20376f
	size_t reflen;
Packit Service 20376f
	git_reference *rewrite = NULL;
Packit Service 20376f
Packit Service 20376f
	if (!GIT_ADD_SIZET_OVERFLOW(&reflen, sizeof(git_reference), namelen) &&
Packit Service 20376f
		!GIT_ADD_SIZET_OVERFLOW(&reflen, reflen, 1) &&
Packit Service 20376f
		(rewrite = git__realloc(ref, reflen)) != NULL)
Packit Service 20376f
		memcpy(rewrite->name, name, namelen + 1);
Packit Service 20376f
Packit Service 20376f
	return rewrite;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_dup(git_reference **dest, git_reference *source)
Packit Service 20376f
{
Packit Service 20376f
	if (source->type == GIT_REF_SYMBOLIC)
Packit Service 20376f
		*dest = git_reference__alloc_symbolic(source->name, source->target.symbolic);
Packit Service 20376f
	else
Packit Service 20376f
		*dest = git_reference__alloc(source->name, &source->target.oid, &source->peel);
Packit Service 20376f
Packit Service 20376f
	GITERR_CHECK_ALLOC(*dest);
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void git_reference_free(git_reference *reference)
Packit Service 20376f
{
Packit Service 20376f
	if (reference == NULL)
Packit Service 20376f
		return;
Packit Service 20376f
Packit Service 20376f
	if (reference->type == GIT_REF_SYMBOLIC)
Packit Service 20376f
		git__free(reference->target.symbolic);
Packit Service 20376f
Packit Service 20376f
	if (reference->db)
Packit Service 20376f
		GIT_REFCOUNT_DEC(reference->db, git_refdb__free);
Packit Service 20376f
Packit Service 20376f
	git__free(reference);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_delete(git_reference *ref)
Packit Service 20376f
{
Packit Service 20376f
	const git_oid *old_id = NULL;
Packit Service 20376f
	const char *old_target = NULL;
Packit Service 20376f
Packit Service 20376f
	if (ref->type == GIT_REF_OID)
Packit Service 20376f
		old_id = &ref->target.oid;
Packit Service 20376f
	else
Packit Service 20376f
		old_target = ref->target.symbolic;
Packit Service 20376f
Packit Service 20376f
	return git_refdb_delete(ref->db, ref->name, old_id, old_target);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_remove(git_repository *repo, const char *name)
Packit Service 20376f
{
Packit Service 20376f
	git_refdb *db;
Packit Service 20376f
	int error;
Packit Service 20376f
Packit Service 20376f
	if ((error = git_repository_refdb__weakptr(&db, repo)) < 0)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	return git_refdb_delete(db, name, NULL, NULL);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_lookup(git_reference **ref_out,
Packit Service 20376f
	git_repository *repo, const char *name)
Packit Service 20376f
{
Packit Service 20376f
	return git_reference_lookup_resolved(ref_out, repo, name, 0);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_name_to_id(
Packit Service 20376f
	git_oid *out, git_repository *repo, const char *name)
Packit Service 20376f
{
Packit Service 20376f
	int error;
Packit Service 20376f
	git_reference *ref;
Packit Service 20376f
Packit Service 20376f
	if ((error = git_reference_lookup_resolved(&ref, repo, name, -1)) < 0)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	git_oid_cpy(out, git_reference_target(ref));
Packit Service 20376f
	git_reference_free(ref);
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int reference_normalize_for_repo(
Packit Service 20376f
	git_refname_t out,
Packit Service 20376f
	git_repository *repo,
Packit Service 20376f
	const char *name,
Packit Service 20376f
	bool validate)
Packit Service 20376f
{
Packit Service 20376f
	int precompose;
Packit Service 20376f
	unsigned int flags = GIT_REF_FORMAT_ALLOW_ONELEVEL;
Packit Service 20376f
Packit Service 20376f
	if (!git_repository__cvar(&precompose, repo, GIT_CVAR_PRECOMPOSE) &&
Packit Service 20376f
		precompose)
Packit Service 20376f
		flags |= GIT_REF_FORMAT__PRECOMPOSE_UNICODE;
Packit Service 20376f
Packit Service 20376f
	if (!validate)
Packit Service 20376f
		flags |= GIT_REF_FORMAT__VALIDATION_DISABLE;
Packit Service 20376f
Packit Service 20376f
	return git_reference_normalize_name(out, GIT_REFNAME_MAX, name, flags);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_lookup_resolved(
Packit Service 20376f
	git_reference **ref_out,
Packit Service 20376f
	git_repository *repo,
Packit Service 20376f
	const char *name,
Packit Service 20376f
	int max_nesting)
Packit Service 20376f
{
Packit Service 20376f
	git_refname_t scan_name;
Packit Service 20376f
	git_ref_t scan_type;
Packit Service 20376f
	int error = 0, nesting;
Packit Service 20376f
	git_reference *ref = NULL;
Packit Service 20376f
	git_refdb *refdb;
Packit Service 20376f
Packit Service 20376f
	assert(ref_out && repo && name);
Packit Service 20376f
Packit Service 20376f
	*ref_out = NULL;
Packit Service 20376f
Packit Service 20376f
	if (max_nesting > MAX_NESTING_LEVEL)
Packit Service 20376f
		max_nesting = MAX_NESTING_LEVEL;
Packit Service 20376f
	else if (max_nesting < 0)
Packit Service 20376f
		max_nesting = DEFAULT_NESTING_LEVEL;
Packit Service 20376f
Packit Service 20376f
	scan_type = GIT_REF_SYMBOLIC;
Packit Service 20376f
Packit Service 20376f
	if ((error = reference_normalize_for_repo(scan_name, repo, name, true)) < 0)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	for (nesting = max_nesting;
Packit Service 20376f
		 nesting >= 0 && scan_type == GIT_REF_SYMBOLIC;
Packit Service 20376f
		 nesting--)
Packit Service 20376f
	{
Packit Service 20376f
		if (nesting != max_nesting) {
Packit Service 20376f
			strncpy(scan_name, ref->target.symbolic, sizeof(scan_name));
Packit Service 20376f
			git_reference_free(ref);
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		if ((error = git_refdb_lookup(&ref, refdb, scan_name)) < 0)
Packit Service 20376f
			return error;
Packit Service 20376f
Packit Service 20376f
		scan_type = ref->type;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (scan_type != GIT_REF_OID && max_nesting != 0) {
Packit Service 20376f
		giterr_set(GITERR_REFERENCE,
Packit Service 20376f
			"cannot resolve reference (>%u levels deep)", max_nesting);
Packit Service 20376f
		git_reference_free(ref);
Packit Service 20376f
		return -1;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	*ref_out = ref;
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference__read_head(
Packit Service 20376f
	git_reference **out,
Packit Service 20376f
	git_repository *repo,
Packit Service 20376f
	const char *path)
Packit Service 20376f
{
Packit Service 20376f
	git_buf reference = GIT_BUF_INIT;
Packit Service 20376f
	char *name = NULL;
Packit Service 20376f
	int error;
Packit Service 20376f
Packit Service 20376f
	if ((error = git_futils_readbuffer(&reference, path)) < 0)
Packit Service 20376f
		goto out;
Packit Service 20376f
	git_buf_rtrim(&reference);
Packit Service 20376f
Packit Service 20376f
	if (git__strncmp(reference.ptr, GIT_SYMREF, strlen(GIT_SYMREF)) == 0) {
Packit Service 20376f
		git_buf_consume(&reference, reference.ptr + strlen(GIT_SYMREF));
Packit Service 20376f
Packit Service 20376f
		name = git_path_basename(path);
Packit Service 20376f
Packit Service 20376f
		if ((*out = git_reference__alloc_symbolic(name, reference.ptr)) == NULL) {
Packit Service 20376f
			error = -1;
Packit Service 20376f
			goto out;
Packit Service 20376f
		}
Packit Service 20376f
	} else {
Packit Service 20376f
		if ((error = git_reference_lookup(out, repo, reference.ptr)) < 0)
Packit Service 20376f
			goto out;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
out:
Packit Service 20376f
	git__free(name);
Packit Service 20376f
	git_buf_free(&reference);
Packit Service 20376f
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_dwim(git_reference **out, git_repository *repo, const char *refname)
Packit Service 20376f
{
Packit Service 20376f
	int error = 0, i;
Packit Service 20376f
	bool fallbackmode = true, foundvalid = false;
Packit Service 20376f
	git_reference *ref;
Packit Service 20376f
	git_buf refnamebuf = GIT_BUF_INIT, name = GIT_BUF_INIT;
Packit Service 20376f
Packit Service 20376f
	static const char* formatters[] = {
Packit Service 20376f
		"%s",
Packit Service 20376f
		GIT_REFS_DIR "%s",
Packit Service 20376f
		GIT_REFS_TAGS_DIR "%s",
Packit Service 20376f
		GIT_REFS_HEADS_DIR "%s",
Packit Service 20376f
		GIT_REFS_REMOTES_DIR "%s",
Packit Service 20376f
		GIT_REFS_REMOTES_DIR "%s/" GIT_HEAD_FILE,
Packit Service 20376f
		NULL
Packit Service 20376f
	};
Packit Service 20376f
Packit Service 20376f
	if (*refname)
Packit Service 20376f
		git_buf_puts(&name, refname);
Packit Service 20376f
	else {
Packit Service 20376f
		git_buf_puts(&name, GIT_HEAD_FILE);
Packit Service 20376f
		fallbackmode = false;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	for (i = 0; formatters[i] && (fallbackmode || i == 0); i++) {
Packit Service 20376f
Packit Service 20376f
		git_buf_clear(&refnamebuf);
Packit Service 20376f
Packit Service 20376f
		if ((error = git_buf_printf(&refnamebuf, formatters[i], git_buf_cstr(&name))) < 0)
Packit Service 20376f
			goto cleanup;
Packit Service 20376f
Packit Service 20376f
		if (!git_reference_is_valid_name(git_buf_cstr(&refnamebuf))) {
Packit Service 20376f
			error = GIT_EINVALIDSPEC;
Packit Service 20376f
			continue;
Packit Service 20376f
		}
Packit Service 20376f
		foundvalid = true;
Packit Service 20376f
Packit Service 20376f
		error = git_reference_lookup_resolved(&ref, repo, git_buf_cstr(&refnamebuf), -1);
Packit Service 20376f
Packit Service 20376f
		if (!error) {
Packit Service 20376f
			*out = ref;
Packit Service 20376f
			error = 0;
Packit Service 20376f
			goto cleanup;
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		if (error != GIT_ENOTFOUND)
Packit Service 20376f
			goto cleanup;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
cleanup:
Packit Service 20376f
	if (error && !foundvalid) {
Packit Service 20376f
		/* never found a valid reference name */
Packit Service 20376f
		giterr_set(GITERR_REFERENCE,
Packit Service 20376f
			"could not use '%s' as valid reference name", git_buf_cstr(&name));
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (error == GIT_ENOTFOUND)
Packit Service 20376f
		giterr_set(GITERR_REFERENCE, "no reference found for shorthand '%s'", refname);
Packit Service 20376f
Packit Service 20376f
	git_buf_free(&name);
Packit Service 20376f
	git_buf_free(&refnamebuf);
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/**
Packit Service 20376f
 * Getters
Packit Service 20376f
 */
Packit Service 20376f
git_ref_t git_reference_type(const git_reference *ref)
Packit Service 20376f
{
Packit Service 20376f
	assert(ref);
Packit Service 20376f
	return ref->type;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
const char *git_reference_name(const git_reference *ref)
Packit Service 20376f
{
Packit Service 20376f
	assert(ref);
Packit Service 20376f
	return ref->name;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
git_repository *git_reference_owner(const git_reference *ref)
Packit Service 20376f
{
Packit Service 20376f
	assert(ref);
Packit Service 20376f
	return ref->db->repo;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
const git_oid *git_reference_target(const git_reference *ref)
Packit Service 20376f
{
Packit Service 20376f
	assert(ref);
Packit Service 20376f
Packit Service 20376f
	if (ref->type != GIT_REF_OID)
Packit Service 20376f
		return NULL;
Packit Service 20376f
Packit Service 20376f
	return &ref->target.oid;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
const git_oid *git_reference_target_peel(const git_reference *ref)
Packit Service 20376f
{
Packit Service 20376f
	assert(ref);
Packit Service 20376f
Packit Service 20376f
	if (ref->type != GIT_REF_OID || git_oid_iszero(&ref->peel))
Packit Service 20376f
		return NULL;
Packit Service 20376f
Packit Service 20376f
	return &ref->peel;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
const char *git_reference_symbolic_target(const git_reference *ref)
Packit Service 20376f
{
Packit Service 20376f
	assert(ref);
Packit Service 20376f
Packit Service 20376f
	if (ref->type != GIT_REF_SYMBOLIC)
Packit Service 20376f
		return NULL;
Packit Service 20376f
Packit Service 20376f
	return ref->target.symbolic;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int reference__create(
Packit Service 20376f
	git_reference **ref_out,
Packit Service 20376f
	git_repository *repo,
Packit Service 20376f
	const char *name,
Packit Service 20376f
	const git_oid *oid,
Packit Service 20376f
	const char *symbolic,
Packit Service 20376f
	int force,
Packit Service 20376f
	const git_signature *signature,
Packit Service 20376f
	const char *log_message,
Packit Service 20376f
	const git_oid *old_id,
Packit Service 20376f
	const char *old_target)
Packit Service 20376f
{
Packit Service 20376f
	git_refname_t normalized;
Packit Service 20376f
	git_refdb *refdb;
Packit Service 20376f
	git_reference *ref = NULL;
Packit Service 20376f
	int error = 0;
Packit Service 20376f
Packit Service 20376f
	assert(repo && name);
Packit Service 20376f
	assert(symbolic || signature);
Packit Service 20376f
Packit Service 20376f
	if (ref_out)
Packit Service 20376f
		*ref_out = NULL;
Packit Service 20376f
Packit Service 20376f
	error = reference_normalize_for_repo(normalized, repo, name, true);
Packit Service 20376f
	if (error < 0)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	error = git_repository_refdb__weakptr(&refdb, repo);
Packit Service 20376f
	if (error < 0)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	if (oid != NULL) {
Packit Service 20376f
		assert(symbolic == NULL);
Packit Service 20376f
Packit Service 20376f
		if (!git_object__is_valid(repo, oid, GIT_OBJ_ANY)) {
Packit Service 20376f
			giterr_set(GITERR_REFERENCE,
Packit Service 20376f
				"target OID for the reference doesn't exist on the repository");
Packit Service 20376f
			return -1;
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		ref = git_reference__alloc(normalized, oid, NULL);
Packit Service 20376f
	} else {
Packit Service 20376f
		git_refname_t normalized_target;
Packit Service 20376f
Packit Service 20376f
		error = reference_normalize_for_repo(normalized_target, repo,
Packit Service 20376f
			symbolic, git_reference__enable_symbolic_ref_target_validation);
Packit Service 20376f
Packit Service 20376f
		if (error < 0)
Packit Service 20376f
			return error;
Packit Service 20376f
Packit Service 20376f
		ref = git_reference__alloc_symbolic(normalized, normalized_target);
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	GITERR_CHECK_ALLOC(ref);
Packit Service 20376f
Packit Service 20376f
	if ((error = git_refdb_write(refdb, ref, force, signature, log_message, old_id, old_target)) < 0) {
Packit Service 20376f
		git_reference_free(ref);
Packit Service 20376f
		return error;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (ref_out == NULL)
Packit Service 20376f
		git_reference_free(ref);
Packit Service 20376f
	else
Packit Service 20376f
		*ref_out = ref;
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int configured_ident(git_signature **out, const git_repository *repo)
Packit Service 20376f
{
Packit Service 20376f
	if (repo->ident_name && repo->ident_email)
Packit Service 20376f
		return git_signature_now(out, repo->ident_name, repo->ident_email);
Packit Service 20376f
Packit Service 20376f
	/* if not configured let us fall-through to the next method  */
Packit Service 20376f
	return -1;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference__log_signature(git_signature **out, git_repository *repo)
Packit Service 20376f
{
Packit Service 20376f
	int error;
Packit Service 20376f
	git_signature *who;
Packit Service 20376f
Packit Service 20376f
	if(((error = configured_ident(&who, repo)) < 0) &&
Packit Service 20376f
	   ((error = git_signature_default(&who, repo)) < 0) &&
Packit Service 20376f
	   ((error = git_signature_now(&who, "unknown", "unknown")) < 0))
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	*out = who;
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_create_matching(
Packit Service 20376f
	git_reference **ref_out,
Packit Service 20376f
	git_repository *repo,
Packit Service 20376f
	const char *name,
Packit Service 20376f
	const git_oid *id,
Packit Service 20376f
	int force,
Packit Service 20376f
	const git_oid *old_id,
Packit Service 20376f
	const char *log_message)
Packit Service 20376f
Packit Service 20376f
{
Packit Service 20376f
	int error;
Packit Service 20376f
	git_signature *who = NULL;
Packit Service 20376f
Packit Service 20376f
	assert(id);
Packit Service 20376f
Packit Service 20376f
	if ((error = git_reference__log_signature(&who, repo)) < 0)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	error = reference__create(
Packit Service 20376f
		ref_out, repo, name, id, NULL, force, who, log_message, old_id, NULL);
Packit Service 20376f
Packit Service 20376f
	git_signature_free(who);
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_create(
Packit Service 20376f
	git_reference **ref_out,
Packit Service 20376f
	git_repository *repo,
Packit Service 20376f
	const char *name,
Packit Service 20376f
	const git_oid *id,
Packit Service 20376f
	int force,
Packit Service 20376f
	const char *log_message)
Packit Service 20376f
{
Packit Service 20376f
        return git_reference_create_matching(ref_out, repo, name, id, force, NULL, log_message);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_symbolic_create_matching(
Packit Service 20376f
	git_reference **ref_out,
Packit Service 20376f
	git_repository *repo,
Packit Service 20376f
	const char *name,
Packit Service 20376f
	const char *target,
Packit Service 20376f
	int force,
Packit Service 20376f
	const char *old_target,
Packit Service 20376f
	const char *log_message)
Packit Service 20376f
{
Packit Service 20376f
	int error;
Packit Service 20376f
	git_signature *who = NULL;
Packit Service 20376f
Packit Service 20376f
	assert(target);
Packit Service 20376f
Packit Service 20376f
	if ((error = git_reference__log_signature(&who, repo)) < 0)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	error = reference__create(
Packit Service 20376f
		ref_out, repo, name, NULL, target, force, who, log_message, NULL, old_target);
Packit Service 20376f
Packit Service 20376f
	git_signature_free(who);
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_symbolic_create(
Packit Service 20376f
	git_reference **ref_out,
Packit Service 20376f
	git_repository *repo,
Packit Service 20376f
	const char *name,
Packit Service 20376f
	const char *target,
Packit Service 20376f
	int force,
Packit Service 20376f
	const char *log_message)
Packit Service 20376f
{
Packit Service 20376f
	return git_reference_symbolic_create_matching(ref_out, repo, name, target, force, NULL, log_message);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int ensure_is_an_updatable_direct_reference(git_reference *ref)
Packit Service 20376f
{
Packit Service 20376f
	if (ref->type == GIT_REF_OID)
Packit Service 20376f
		return 0;
Packit Service 20376f
Packit Service 20376f
	giterr_set(GITERR_REFERENCE, "cannot set OID on symbolic reference");
Packit Service 20376f
	return -1;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_set_target(
Packit Service 20376f
	git_reference **out,
Packit Service 20376f
	git_reference *ref,
Packit Service 20376f
	const git_oid *id,
Packit Service 20376f
	const char *log_message)
Packit Service 20376f
{
Packit Service 20376f
	int error;
Packit Service 20376f
	git_repository *repo;
Packit Service 20376f
Packit Service 20376f
	assert(out && ref && id);
Packit Service 20376f
Packit Service 20376f
	repo = ref->db->repo;
Packit Service 20376f
Packit Service 20376f
	if ((error = ensure_is_an_updatable_direct_reference(ref)) < 0)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	return git_reference_create_matching(out, repo, ref->name, id, 1, &ref->target.oid, log_message);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int ensure_is_an_updatable_symbolic_reference(git_reference *ref)
Packit Service 20376f
{
Packit Service 20376f
	if (ref->type == GIT_REF_SYMBOLIC)
Packit Service 20376f
		return 0;
Packit Service 20376f
Packit Service 20376f
	giterr_set(GITERR_REFERENCE, "cannot set symbolic target on a direct reference");
Packit Service 20376f
	return -1;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_symbolic_set_target(
Packit Service 20376f
	git_reference **out,
Packit Service 20376f
	git_reference *ref,
Packit Service 20376f
	const char *target,
Packit Service 20376f
	const char *log_message)
Packit Service 20376f
{
Packit Service 20376f
	int error;
Packit Service 20376f
Packit Service 20376f
	assert(out && ref && target);
Packit Service 20376f
Packit Service 20376f
	if ((error = ensure_is_an_updatable_symbolic_reference(ref)) < 0)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	return git_reference_symbolic_create_matching(
Packit Service 20376f
		out, ref->db->repo, ref->name, target, 1, ref->target.symbolic, log_message);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
typedef struct {
Packit Service 20376f
    const char *old_name;
Packit Service 20376f
    git_refname_t new_name;
Packit Service 20376f
} rename_cb_data;
Packit Service 20376f
Packit Service 20376f
static int update_wt_heads(git_repository *repo, const char *path, void *payload)
Packit Service 20376f
{
Packit Service 20376f
	rename_cb_data *data = (rename_cb_data *) payload;
Packit Service 20376f
	git_reference *head = NULL;
Packit Service 20376f
	char *gitdir = NULL;
Packit Service 20376f
	int error;
Packit Service 20376f
Packit Service 20376f
	if ((error = git_reference__read_head(&head, repo, path)) < 0) {
Packit Service 20376f
		giterr_set(GITERR_REFERENCE, "could not read HEAD when renaming references");
Packit Service 20376f
		goto out;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if ((gitdir = git_path_dirname(path)) == NULL) {
Packit Service 20376f
		error = -1;
Packit Service 20376f
		goto out;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (git_reference_type(head) != GIT_REF_SYMBOLIC ||
Packit Service 20376f
	    git__strcmp(head->target.symbolic, data->old_name) != 0) {
Packit Service 20376f
		error = 0;
Packit Service 20376f
		goto out;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	/* Update HEAD it was pointing to the reference being renamed */
Packit Service 20376f
	if ((error = git_repository_create_head(gitdir, data->new_name)) < 0) {
Packit Service 20376f
		giterr_set(GITERR_REFERENCE, "failed to update HEAD after renaming reference");
Packit Service 20376f
		goto out;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
out:
Packit Service 20376f
	git_reference_free(head);
Packit Service 20376f
	git__free(gitdir);
Packit Service 20376f
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int reference__rename(git_reference **out, git_reference *ref, const char *new_name, int force,
Packit Service 20376f
				 const git_signature *signature, const char *message)
Packit Service 20376f
{
Packit Service 20376f
	git_repository *repo;
Packit Service 20376f
	git_refname_t normalized;
Packit Service 20376f
	bool should_head_be_updated = false;
Packit Service 20376f
	int error = 0;
Packit Service 20376f
Packit Service 20376f
	assert(ref && new_name && signature);
Packit Service 20376f
Packit Service 20376f
	repo = git_reference_owner(ref);
Packit Service 20376f
Packit Service 20376f
	if ((error = reference_normalize_for_repo(
Packit Service 20376f
		normalized, repo, new_name, true)) < 0)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	/* Check if we have to update HEAD. */
Packit Service 20376f
	if ((error = git_branch_is_head(ref)) < 0)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	should_head_be_updated = (error > 0);
Packit Service 20376f
Packit Service 20376f
	if ((error = git_refdb_rename(out, ref->db, ref->name, normalized, force, signature, message)) < 0)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	/* Update HEAD if it was pointing to the reference being renamed */
Packit Service 20376f
	if (should_head_be_updated) {
Packit Service 20376f
		error = git_repository_set_head(ref->db->repo, normalized);
Packit Service 20376f
	} else {
Packit Service 20376f
		rename_cb_data payload;
Packit Service 20376f
		payload.old_name = ref->name;
Packit Service 20376f
		memcpy(&payload.new_name, &normalized, sizeof(normalized));
Packit Service 20376f
Packit Service 20376f
		error = git_repository_foreach_head(repo, update_wt_heads, &payload);
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
Packit Service 20376f
int git_reference_rename(
Packit Service 20376f
	git_reference **out,
Packit Service 20376f
	git_reference *ref,
Packit Service 20376f
	const char *new_name,
Packit Service 20376f
	int force,
Packit Service 20376f
	const char *log_message)
Packit Service 20376f
{
Packit Service 20376f
	git_signature *who;
Packit Service 20376f
	int error;
Packit Service 20376f
Packit Service 20376f
	if ((error = git_reference__log_signature(&who, ref->db->repo)) < 0)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	error = reference__rename(out, ref, new_name, force, who, log_message);
Packit Service 20376f
	git_signature_free(who);
Packit Service 20376f
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_resolve(git_reference **ref_out, const git_reference *ref)
Packit Service 20376f
{
Packit Service 20376f
	switch (git_reference_type(ref)) {
Packit Service 20376f
	case GIT_REF_OID:
Packit Service 20376f
		return git_reference_lookup(ref_out, ref->db->repo, ref->name);
Packit Service 20376f
Packit Service 20376f
	case GIT_REF_SYMBOLIC:
Packit Service 20376f
		return git_reference_lookup_resolved(ref_out, ref->db->repo, ref->target.symbolic, -1);
Packit Service 20376f
Packit Service 20376f
	default:
Packit Service 20376f
		giterr_set(GITERR_REFERENCE, "invalid reference");
Packit Service 20376f
		return -1;
Packit Service 20376f
	}
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_foreach(
Packit Service 20376f
	git_repository *repo,
Packit Service 20376f
	git_reference_foreach_cb callback,
Packit Service 20376f
	void *payload)
Packit Service 20376f
{
Packit Service 20376f
	git_reference_iterator *iter;
Packit Service 20376f
	git_reference *ref;
Packit Service 20376f
	int error;
Packit Service 20376f
Packit Service 20376f
	if ((error = git_reference_iterator_new(&iter, repo)) < 0)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	while (!(error = git_reference_next(&ref, iter))) {
Packit Service 20376f
		if ((error = callback(ref, payload)) != 0) {
Packit Service 20376f
			giterr_set_after_callback(error);
Packit Service 20376f
			break;
Packit Service 20376f
		}
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (error == GIT_ITEROVER)
Packit Service 20376f
		error = 0;
Packit Service 20376f
Packit Service 20376f
	git_reference_iterator_free(iter);
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_foreach_name(
Packit Service 20376f
	git_repository *repo,
Packit Service 20376f
	git_reference_foreach_name_cb callback,
Packit Service 20376f
	void *payload)
Packit Service 20376f
{
Packit Service 20376f
	git_reference_iterator *iter;
Packit Service 20376f
	const char *refname;
Packit Service 20376f
	int error;
Packit Service 20376f
Packit Service 20376f
	if ((error = git_reference_iterator_new(&iter, repo)) < 0)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	while (!(error = git_reference_next_name(&refname, iter))) {
Packit Service 20376f
		if ((error = callback(refname, payload)) != 0) {
Packit Service 20376f
			giterr_set_after_callback(error);
Packit Service 20376f
			break;
Packit Service 20376f
		}
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (error == GIT_ITEROVER)
Packit Service 20376f
		error = 0;
Packit Service 20376f
Packit Service 20376f
	git_reference_iterator_free(iter);
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_foreach_glob(
Packit Service 20376f
	git_repository *repo,
Packit Service 20376f
	const char *glob,
Packit Service 20376f
	git_reference_foreach_name_cb callback,
Packit Service 20376f
	void *payload)
Packit Service 20376f
{
Packit Service 20376f
	git_reference_iterator *iter;
Packit Service 20376f
	const char *refname;
Packit Service 20376f
	int error;
Packit Service 20376f
Packit Service 20376f
	if ((error = git_reference_iterator_glob_new(&iter, repo, glob)) < 0)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	while (!(error = git_reference_next_name(&refname, iter))) {
Packit Service 20376f
		if ((error = callback(refname, payload)) != 0) {
Packit Service 20376f
			giterr_set_after_callback(error);
Packit Service 20376f
			break;
Packit Service 20376f
		}
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (error == GIT_ITEROVER)
Packit Service 20376f
		error = 0;
Packit Service 20376f
Packit Service 20376f
	git_reference_iterator_free(iter);
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_iterator_new(git_reference_iterator **out, git_repository *repo)
Packit Service 20376f
{
Packit Service 20376f
	git_refdb *refdb;
Packit Service 20376f
Packit Service 20376f
	if (git_repository_refdb__weakptr(&refdb, repo) < 0)
Packit Service 20376f
		return -1;
Packit Service 20376f
Packit Service 20376f
	return git_refdb_iterator(out, refdb, NULL);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_iterator_glob_new(
Packit Service 20376f
	git_reference_iterator **out, git_repository *repo, const char *glob)
Packit Service 20376f
{
Packit Service 20376f
	git_refdb *refdb;
Packit Service 20376f
Packit Service 20376f
	if (git_repository_refdb__weakptr(&refdb, repo) < 0)
Packit Service 20376f
		return -1;
Packit Service 20376f
Packit Service 20376f
	return git_refdb_iterator(out, refdb, glob);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_next(git_reference **out, git_reference_iterator *iter)
Packit Service 20376f
{
Packit Service 20376f
	return git_refdb_iterator_next(out, iter);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_next_name(const char **out, git_reference_iterator *iter)
Packit Service 20376f
{
Packit Service 20376f
	return git_refdb_iterator_next_name(out, iter);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void git_reference_iterator_free(git_reference_iterator *iter)
Packit Service 20376f
{
Packit Service 20376f
	if (iter == NULL)
Packit Service 20376f
		return;
Packit Service 20376f
Packit Service 20376f
	git_refdb_iterator_free(iter);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int cb__reflist_add(const char *ref, void *data)
Packit Service 20376f
{
Packit Service 20376f
	char *name = git__strdup(ref);
Packit Service 20376f
	GITERR_CHECK_ALLOC(name);
Packit Service 20376f
	return git_vector_insert((git_vector *)data, name);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_list(
Packit Service 20376f
	git_strarray *array,
Packit Service 20376f
	git_repository *repo)
Packit Service 20376f
{
Packit Service 20376f
	git_vector ref_list;
Packit Service 20376f
Packit Service 20376f
	assert(array && repo);
Packit Service 20376f
Packit Service 20376f
	array->strings = NULL;
Packit Service 20376f
	array->count = 0;
Packit Service 20376f
Packit Service 20376f
	if (git_vector_init(&ref_list, 8, NULL) < 0)
Packit Service 20376f
		return -1;
Packit Service 20376f
Packit Service 20376f
	if (git_reference_foreach_name(
Packit Service 20376f
			repo, &cb__reflist_add, (void *)&ref_list) < 0) {
Packit Service 20376f
		git_vector_free(&ref_list);
Packit Service 20376f
		return -1;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	array->strings = (char **)git_vector_detach(&array->count, NULL, &ref_list);
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int is_valid_ref_char(char ch)
Packit Service 20376f
{
Packit Service 20376f
	if ((unsigned) ch <= ' ')
Packit Service 20376f
		return 0;
Packit Service 20376f
Packit Service 20376f
	switch (ch) {
Packit Service 20376f
	case '~':
Packit Service 20376f
	case '^':
Packit Service 20376f
	case ':':
Packit Service 20376f
	case '\\':
Packit Service 20376f
	case '?':
Packit Service 20376f
	case '[':
Packit Service 20376f
	case '*':
Packit Service 20376f
		return 0;
Packit Service 20376f
	default:
Packit Service 20376f
		return 1;
Packit Service 20376f
	}
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int ensure_segment_validity(const char *name)
Packit Service 20376f
{
Packit Service 20376f
	const char *current = name;
Packit Service 20376f
	char prev = '\0';
Packit Service 20376f
	const int lock_len = (int)strlen(GIT_FILELOCK_EXTENSION);
Packit Service 20376f
	int segment_len;
Packit Service 20376f
Packit Service 20376f
	if (*current == '.')
Packit Service 20376f
		return -1; /* Refname starts with "." */
Packit Service 20376f
Packit Service 20376f
	for (current = name; ; current++) {
Packit Service 20376f
		if (*current == '\0' || *current == '/')
Packit Service 20376f
			break;
Packit Service 20376f
Packit Service 20376f
		if (!is_valid_ref_char(*current))
Packit Service 20376f
			return -1; /* Illegal character in refname */
Packit Service 20376f
Packit Service 20376f
		if (prev == '.' && *current == '.')
Packit Service 20376f
			return -1; /* Refname contains ".." */
Packit Service 20376f
Packit Service 20376f
		if (prev == '@' && *current == '{')
Packit Service 20376f
			return -1; /* Refname contains "@{" */
Packit Service 20376f
Packit Service 20376f
		prev = *current;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	segment_len = (int)(current - name);
Packit Service 20376f
Packit Service 20376f
	/* A refname component can not end with ".lock" */
Packit Service 20376f
	if (segment_len >= lock_len &&
Packit Service 20376f
		!memcmp(current - lock_len, GIT_FILELOCK_EXTENSION, lock_len))
Packit Service 20376f
			return -1;
Packit Service 20376f
Packit Service 20376f
	return segment_len;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static bool is_all_caps_and_underscore(const char *name, size_t len)
Packit Service 20376f
{
Packit Service 20376f
	size_t i;
Packit Service 20376f
	char c;
Packit Service 20376f
Packit Service 20376f
	assert(name && len > 0);
Packit Service 20376f
Packit Service 20376f
	for (i = 0; i < len; i++)
Packit Service 20376f
	{
Packit Service 20376f
		c = name[i];
Packit Service 20376f
		if ((c < 'A' || c > 'Z') && c != '_')
Packit Service 20376f
			return false;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (*name == '_' || name[len - 1] == '_')
Packit Service 20376f
		return false;
Packit Service 20376f
Packit Service 20376f
	return true;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* Inspired from https://github.com/git/git/blob/f06d47e7e0d9db709ee204ed13a8a7486149f494/refs.c#L36-100 */
Packit Service 20376f
int git_reference__normalize_name(
Packit Service 20376f
	git_buf *buf,
Packit Service 20376f
	const char *name,
Packit Service 20376f
	unsigned int flags)
Packit Service 20376f
{
Packit Service 20376f
	const char *current;
Packit Service 20376f
	int segment_len, segments_count = 0, error = GIT_EINVALIDSPEC;
Packit Service 20376f
	unsigned int process_flags;
Packit Service 20376f
	bool normalize = (buf != NULL);
Packit Service 20376f
	bool validate = (flags & GIT_REF_FORMAT__VALIDATION_DISABLE) == 0;
Packit Service 20376f
Packit Service 20376f
#ifdef GIT_USE_ICONV
Packit Service 20376f
	git_path_iconv_t ic = GIT_PATH_ICONV_INIT;
Packit Service 20376f
#endif
Packit Service 20376f
Packit Service 20376f
	assert(name);
Packit Service 20376f
Packit Service 20376f
	process_flags = flags;
Packit Service 20376f
	current = (char *)name;
Packit Service 20376f
Packit Service 20376f
	if (validate && *current == '/')
Packit Service 20376f
		goto cleanup;
Packit Service 20376f
Packit Service 20376f
	if (normalize)
Packit Service 20376f
		git_buf_clear(buf);
Packit Service 20376f
Packit Service 20376f
#ifdef GIT_USE_ICONV
Packit Service 20376f
	if ((flags & GIT_REF_FORMAT__PRECOMPOSE_UNICODE) != 0) {
Packit Service 20376f
		size_t namelen = strlen(current);
Packit Service 20376f
		if ((error = git_path_iconv_init_precompose(&ic)) < 0 ||
Packit Service 20376f
			(error = git_path_iconv(&ic, &current, &namelen)) < 0)
Packit Service 20376f
			goto cleanup;
Packit Service 20376f
		error = GIT_EINVALIDSPEC;
Packit Service 20376f
	}
Packit Service 20376f
#endif
Packit Service 20376f
Packit Service 20376f
	if (!validate) {
Packit Service 20376f
		git_buf_sets(buf, current);
Packit Service 20376f
Packit Service 20376f
		error = git_buf_oom(buf) ? -1 : 0;
Packit Service 20376f
		goto cleanup;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	while (true) {
Packit Service 20376f
		segment_len = ensure_segment_validity(current);
Packit Service 20376f
		if (segment_len < 0) {
Packit Service 20376f
			if ((process_flags & GIT_REF_FORMAT_REFSPEC_PATTERN) &&
Packit Service 20376f
					current[0] == '*' &&
Packit Service 20376f
					(current[1] == '\0' || current[1] == '/')) {
Packit Service 20376f
				/* Accept one wildcard as a full refname component. */
Packit Service 20376f
				process_flags &= ~GIT_REF_FORMAT_REFSPEC_PATTERN;
Packit Service 20376f
				segment_len = 1;
Packit Service 20376f
			} else
Packit Service 20376f
				goto cleanup;
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		if (segment_len > 0) {
Packit Service 20376f
			if (normalize) {
Packit Service 20376f
				size_t cur_len = git_buf_len(buf);
Packit Service 20376f
Packit Service 20376f
				git_buf_joinpath(buf, git_buf_cstr(buf), current);
Packit Service 20376f
				git_buf_truncate(buf,
Packit Service 20376f
					cur_len + segment_len + (segments_count ? 1 : 0));
Packit Service 20376f
Packit Service 20376f
				if (git_buf_oom(buf)) {
Packit Service 20376f
					error = -1;
Packit Service 20376f
					goto cleanup;
Packit Service 20376f
				}
Packit Service 20376f
			}
Packit Service 20376f
Packit Service 20376f
			segments_count++;
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		/* No empty segment is allowed when not normalizing */
Packit Service 20376f
		if (segment_len == 0 && !normalize)
Packit Service 20376f
			goto cleanup;
Packit Service 20376f
Packit Service 20376f
		if (current[segment_len] == '\0')
Packit Service 20376f
			break;
Packit Service 20376f
Packit Service 20376f
		current += segment_len + 1;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	/* A refname can not be empty */
Packit Service 20376f
	if (segment_len == 0 && segments_count == 0)
Packit Service 20376f
		goto cleanup;
Packit Service 20376f
Packit Service 20376f
	/* A refname can not end with "." */
Packit Service 20376f
	if (current[segment_len - 1] == '.')
Packit Service 20376f
		goto cleanup;
Packit Service 20376f
Packit Service 20376f
	/* A refname can not end with "/" */
Packit Service 20376f
	if (current[segment_len - 1] == '/')
Packit Service 20376f
		goto cleanup;
Packit Service 20376f
Packit Service 20376f
	if ((segments_count == 1 ) && !(flags & GIT_REF_FORMAT_ALLOW_ONELEVEL))
Packit Service 20376f
		goto cleanup;
Packit Service 20376f
Packit Service 20376f
	if ((segments_count == 1 ) &&
Packit Service 20376f
	    !(flags & GIT_REF_FORMAT_REFSPEC_SHORTHAND) &&
Packit Service 20376f
		!(is_all_caps_and_underscore(name, (size_t)segment_len) ||
Packit Service 20376f
			((flags & GIT_REF_FORMAT_REFSPEC_PATTERN) && !strcmp("*", name))))
Packit Service 20376f
			goto cleanup;
Packit Service 20376f
Packit Service 20376f
	if ((segments_count > 1)
Packit Service 20376f
		&& (is_all_caps_and_underscore(name, strchr(name, '/') - name)))
Packit Service 20376f
			goto cleanup;
Packit Service 20376f
Packit Service 20376f
	error = 0;
Packit Service 20376f
Packit Service 20376f
cleanup:
Packit Service 20376f
	if (error == GIT_EINVALIDSPEC)
Packit Service 20376f
		giterr_set(
Packit Service 20376f
			GITERR_REFERENCE,
Packit Service 20376f
			"the given reference name '%s' is not valid", name);
Packit Service 20376f
Packit Service 20376f
	if (error && normalize)
Packit Service 20376f
		git_buf_free(buf);
Packit Service 20376f
Packit Service 20376f
#ifdef GIT_USE_ICONV
Packit Service 20376f
	git_path_iconv_clear(&ic);
Packit Service 20376f
#endif
Packit Service 20376f
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_normalize_name(
Packit Service 20376f
	char *buffer_out,
Packit Service 20376f
	size_t buffer_size,
Packit Service 20376f
	const char *name,
Packit Service 20376f
	unsigned int flags)
Packit Service 20376f
{
Packit Service 20376f
	git_buf buf = GIT_BUF_INIT;
Packit Service 20376f
	int error;
Packit Service 20376f
Packit Service 20376f
	if ((error = git_reference__normalize_name(&buf, name, flags)) < 0)
Packit Service 20376f
		goto cleanup;
Packit Service 20376f
Packit Service 20376f
	if (git_buf_len(&buf) > buffer_size - 1) {
Packit Service 20376f
		giterr_set(
Packit Service 20376f
		GITERR_REFERENCE,
Packit Service 20376f
		"the provided buffer is too short to hold the normalization of '%s'", name);
Packit Service 20376f
		error = GIT_EBUFS;
Packit Service 20376f
		goto cleanup;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	git_buf_copy_cstr(buffer_out, buffer_size, &buf;;
Packit Service 20376f
Packit Service 20376f
	error = 0;
Packit Service 20376f
Packit Service 20376f
cleanup:
Packit Service 20376f
	git_buf_free(&buf;;
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
#define GIT_REF_TYPEMASK (GIT_REF_OID | GIT_REF_SYMBOLIC)
Packit Service 20376f
Packit Service 20376f
int git_reference_cmp(
Packit Service 20376f
	const git_reference *ref1,
Packit Service 20376f
	const git_reference *ref2)
Packit Service 20376f
{
Packit Service 20376f
	git_ref_t type1, type2;
Packit Service 20376f
	assert(ref1 && ref2);
Packit Service 20376f
Packit Service 20376f
	type1 = git_reference_type(ref1);
Packit Service 20376f
	type2 = git_reference_type(ref2);
Packit Service 20376f
Packit Service 20376f
	/* let's put symbolic refs before OIDs */
Packit Service 20376f
	if (type1 != type2)
Packit Service 20376f
		return (type1 == GIT_REF_SYMBOLIC) ? -1 : 1;
Packit Service 20376f
Packit Service 20376f
	if (type1 == GIT_REF_SYMBOLIC)
Packit Service 20376f
		return strcmp(ref1->target.symbolic, ref2->target.symbolic);
Packit Service 20376f
Packit Service 20376f
	return git_oid__cmp(&ref1->target.oid, &ref2->target.oid);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/**
Packit Service 20376f
 * Get the end of a chain of references. If the final one is not
Packit Service 20376f
 * found, we return the reference just before that.
Packit Service 20376f
 */
Packit Service 20376f
static int get_terminal(git_reference **out, git_repository *repo, const char *ref_name, int nesting)
Packit Service 20376f
{
Packit Service 20376f
	git_reference *ref;
Packit Service 20376f
	int error = 0;
Packit Service 20376f
Packit Service 20376f
	if (nesting > MAX_NESTING_LEVEL) {
Packit Service 20376f
		giterr_set(GITERR_REFERENCE, "reference chain too deep (%d)", nesting);
Packit Service 20376f
		return GIT_ENOTFOUND;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	/* set to NULL to let the caller know that they're at the end of the chain */
Packit Service 20376f
	if ((error = git_reference_lookup(&ref, repo, ref_name)) < 0) {
Packit Service 20376f
		*out = NULL;
Packit Service 20376f
		return error;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (git_reference_type(ref) == GIT_REF_OID) {
Packit Service 20376f
		*out = ref;
Packit Service 20376f
		error = 0;
Packit Service 20376f
	} else {
Packit Service 20376f
		error = get_terminal(out, repo, git_reference_symbolic_target(ref), nesting + 1);
Packit Service 20376f
		if (error == GIT_ENOTFOUND && !*out)
Packit Service 20376f
			*out = ref;
Packit Service 20376f
		else
Packit Service 20376f
			git_reference_free(ref);
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/*
Packit Service 20376f
 * Starting with the reference given by `ref_name`, follows symbolic
Packit Service 20376f
 * references until a direct reference is found and updated the OID
Packit Service 20376f
 * on that direct reference to `oid`.
Packit Service 20376f
 */
Packit Service 20376f
int git_reference__update_terminal(
Packit Service 20376f
	git_repository *repo,
Packit Service 20376f
	const char *ref_name,
Packit Service 20376f
	const git_oid *oid,
Packit Service 20376f
	const git_signature *sig,
Packit Service 20376f
	const char *log_message)
Packit Service 20376f
{
Packit Service 20376f
	git_reference *ref = NULL, *ref2 = NULL;
Packit Service 20376f
	git_signature *who = NULL;
Packit Service 20376f
	const git_signature *to_use;
Packit Service 20376f
	int error = 0;
Packit Service 20376f
Packit Service 20376f
	if (!sig && (error = git_reference__log_signature(&who, repo)) < 0)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	to_use = sig ? sig : who;
Packit Service 20376f
	error = get_terminal(&ref, repo, ref_name, 0);
Packit Service 20376f
Packit Service 20376f
	/* found a dangling symref */
Packit Service 20376f
	if (error == GIT_ENOTFOUND && ref) {
Packit Service 20376f
		assert(git_reference_type(ref) == GIT_REF_SYMBOLIC);
Packit Service 20376f
		giterr_clear();
Packit Service 20376f
		error = reference__create(&ref2, repo, ref->target.symbolic, oid, NULL, 0, to_use,
Packit Service 20376f
					  log_message, NULL, NULL);
Packit Service 20376f
	} else if (error == GIT_ENOTFOUND) {
Packit Service 20376f
		giterr_clear();
Packit Service 20376f
		error = reference__create(&ref2, repo, ref_name, oid, NULL, 0, to_use,
Packit Service 20376f
					  log_message, NULL, NULL);
Packit Service 20376f
	}  else if (error == 0) {
Packit Service 20376f
		assert(git_reference_type(ref) == GIT_REF_OID);
Packit Service 20376f
		error = reference__create(&ref2, repo, ref->name, oid, NULL, 1, to_use,
Packit Service 20376f
					  log_message, &ref->target.oid, NULL);
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	git_reference_free(ref2);
Packit Service 20376f
	git_reference_free(ref);
Packit Service 20376f
	git_signature_free(who);
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static const char *commit_type(const git_commit *commit)
Packit Service 20376f
{
Packit Service 20376f
	unsigned int count = git_commit_parentcount(commit);
Packit Service 20376f
Packit Service 20376f
	if (count >= 2)
Packit Service 20376f
		return " (merge)";
Packit Service 20376f
	else if (count == 0)
Packit Service 20376f
		return " (initial)";
Packit Service 20376f
	else
Packit Service 20376f
		return "";
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference__update_for_commit(
Packit Service 20376f
	git_repository *repo,
Packit Service 20376f
	git_reference *ref,
Packit Service 20376f
	const char *ref_name,
Packit Service 20376f
	const git_oid *id,
Packit Service 20376f
	const char *operation)
Packit Service 20376f
{
Packit Service 20376f
	git_reference *ref_new = NULL;
Packit Service 20376f
	git_commit *commit = NULL;
Packit Service 20376f
	git_buf reflog_msg = GIT_BUF_INIT;
Packit Service 20376f
	const git_signature *who;
Packit Service 20376f
	int error;
Packit Service 20376f
Packit Service 20376f
	if ((error = git_commit_lookup(&commit, repo, id)) < 0 ||
Packit Service 20376f
		(error = git_buf_printf(&reflog_msg, "%s%s: %s",
Packit Service 20376f
			operation ? operation : "commit",
Packit Service 20376f
			commit_type(commit),
Packit Service 20376f
			git_commit_summary(commit))) < 0)
Packit Service 20376f
		goto done;
Packit Service 20376f
Packit Service 20376f
	who = git_commit_committer(commit);
Packit Service 20376f
Packit Service 20376f
	if (ref) {
Packit Service 20376f
		if ((error = ensure_is_an_updatable_direct_reference(ref)) < 0)
Packit Service 20376f
			return error;
Packit Service 20376f
Packit Service 20376f
		error = reference__create(&ref_new, repo, ref->name, id, NULL, 1, who,
Packit Service 20376f
					  git_buf_cstr(&reflog_msg), &ref->target.oid, NULL);
Packit Service 20376f
	}
Packit Service 20376f
	else
Packit Service 20376f
		error = git_reference__update_terminal(
Packit Service 20376f
			repo, ref_name, id, who, git_buf_cstr(&reflog_msg));
Packit Service 20376f
Packit Service 20376f
done:
Packit Service 20376f
	git_reference_free(ref_new);
Packit Service 20376f
	git_buf_free(&reflog_msg);
Packit Service 20376f
	git_commit_free(commit);
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_has_log(git_repository *repo, const char *refname)
Packit Service 20376f
{
Packit Service 20376f
	int error;
Packit Service 20376f
	git_refdb *refdb;
Packit Service 20376f
Packit Service 20376f
	assert(repo && refname);
Packit Service 20376f
Packit Service 20376f
	if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	return git_refdb_has_log(refdb, refname);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_ensure_log(git_repository *repo, const char *refname)
Packit Service 20376f
{
Packit Service 20376f
	int error;
Packit Service 20376f
	git_refdb *refdb;
Packit Service 20376f
Packit Service 20376f
	assert(repo && refname);
Packit Service 20376f
Packit Service 20376f
	if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	return git_refdb_ensure_log(refdb, refname);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference__is_branch(const char *ref_name)
Packit Service 20376f
{
Packit Service 20376f
	return git__prefixcmp(ref_name, GIT_REFS_HEADS_DIR) == 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_is_branch(const git_reference *ref)
Packit Service 20376f
{
Packit Service 20376f
	assert(ref);
Packit Service 20376f
	return git_reference__is_branch(ref->name);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference__is_remote(const char *ref_name)
Packit Service 20376f
{
Packit Service 20376f
	return git__prefixcmp(ref_name, GIT_REFS_REMOTES_DIR) == 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_is_remote(const git_reference *ref)
Packit Service 20376f
{
Packit Service 20376f
	assert(ref);
Packit Service 20376f
	return git_reference__is_remote(ref->name);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference__is_tag(const char *ref_name)
Packit Service 20376f
{
Packit Service 20376f
	return git__prefixcmp(ref_name, GIT_REFS_TAGS_DIR) == 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_is_tag(const git_reference *ref)
Packit Service 20376f
{
Packit Service 20376f
	assert(ref);
Packit Service 20376f
	return git_reference__is_tag(ref->name);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference__is_note(const char *ref_name)
Packit Service 20376f
{
Packit Service 20376f
	return git__prefixcmp(ref_name, GIT_REFS_NOTES_DIR) == 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_is_note(const git_reference *ref)
Packit Service 20376f
{
Packit Service 20376f
	assert(ref);
Packit Service 20376f
	return git_reference__is_note(ref->name);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int peel_error(int error, git_reference *ref, const char* msg)
Packit Service 20376f
{
Packit Service 20376f
	giterr_set(
Packit Service 20376f
		GITERR_INVALID,
Packit Service 20376f
		"the reference '%s' cannot be peeled - %s", git_reference_name(ref), msg);
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_peel(
Packit Service 20376f
	git_object **peeled,
Packit Service 20376f
	git_reference *ref,
Packit Service 20376f
	git_otype target_type)
Packit Service 20376f
{
Packit Service 20376f
	git_reference *resolved = NULL;
Packit Service 20376f
	git_object *target = NULL;
Packit Service 20376f
	int error;
Packit Service 20376f
Packit Service 20376f
	assert(ref);
Packit Service 20376f
Packit Service 20376f
	if (ref->type == GIT_REF_OID) {
Packit Service 20376f
		resolved = ref;
Packit Service 20376f
	} else {
Packit Service 20376f
		if ((error = git_reference_resolve(&resolved, ref)) < 0)
Packit Service 20376f
			return peel_error(error, ref, "Cannot resolve reference");
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	/*
Packit Service 20376f
	 * If we try to peel an object to a tag, we cannot use
Packit Service 20376f
	 * the fully peeled object, as that will always resolve
Packit Service 20376f
	 * to a commit. So we only want to use the peeled value
Packit Service 20376f
	 * if it is not zero and the target is not a tag.
Packit Service 20376f
	 */
Packit Service 20376f
	if (target_type != GIT_OBJ_TAG && !git_oid_iszero(&resolved->peel)) {
Packit Service 20376f
		error = git_object_lookup(&target,
Packit Service 20376f
			git_reference_owner(ref), &resolved->peel, GIT_OBJ_ANY);
Packit Service 20376f
	} else {
Packit Service 20376f
		error = git_object_lookup(&target,
Packit Service 20376f
			git_reference_owner(ref), &resolved->target.oid, GIT_OBJ_ANY);
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (error < 0) {
Packit Service 20376f
		peel_error(error, ref, "Cannot retrieve reference target");
Packit Service 20376f
		goto cleanup;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (target_type == GIT_OBJ_ANY && git_object_type(target) != GIT_OBJ_TAG)
Packit Service 20376f
		error = git_object_dup(peeled, target);
Packit Service 20376f
	else
Packit Service 20376f
		error = git_object_peel(peeled, target, target_type);
Packit Service 20376f
Packit Service 20376f
cleanup:
Packit Service 20376f
	git_object_free(target);
Packit Service 20376f
Packit Service 20376f
	if (resolved != ref)
Packit Service 20376f
		git_reference_free(resolved);
Packit Service 20376f
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference__is_valid_name(const char *refname, unsigned int flags)
Packit Service 20376f
{
Packit Service 20376f
	if (git_reference__normalize_name(NULL, refname, flags) < 0) {
Packit Service 20376f
		giterr_clear();
Packit Service 20376f
		return false;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	return true;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_reference_is_valid_name(const char *refname)
Packit Service 20376f
{
Packit Service 20376f
	return git_reference__is_valid_name(refname, GIT_REF_FORMAT_ALLOW_ONELEVEL);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
const char *git_reference__shorthand(const char *name)
Packit Service 20376f
{
Packit Service 20376f
	if (!git__prefixcmp(name, GIT_REFS_HEADS_DIR))
Packit Service 20376f
		return name + strlen(GIT_REFS_HEADS_DIR);
Packit Service 20376f
	else if (!git__prefixcmp(name, GIT_REFS_TAGS_DIR))
Packit Service 20376f
		return name + strlen(GIT_REFS_TAGS_DIR);
Packit Service 20376f
	else if (!git__prefixcmp(name, GIT_REFS_REMOTES_DIR))
Packit Service 20376f
		return name + strlen(GIT_REFS_REMOTES_DIR);
Packit Service 20376f
	else if (!git__prefixcmp(name, GIT_REFS_DIR))
Packit Service 20376f
		return name + strlen(GIT_REFS_DIR);
Packit Service 20376f
Packit Service 20376f
	/* No shorthands are avaiable, so just return the name */
Packit Service 20376f
	return name;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
const char *git_reference_shorthand(const git_reference *ref)
Packit Service 20376f
{
Packit Service 20376f
	return git_reference__shorthand(ref->name);
Packit Service 20376f
}