Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions include/git2/refdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
*/
GIT_BEGIN_DECL

/** The type of the refdb as determined by "extensions.refStorage". */
typedef enum {
GIT_REFDB_FILES = 1 /**< Files backend using loose and packed refs. */
} git_refdb_t;

/**
* Create a new reference database with no backends.
*
Expand Down
7 changes: 7 additions & 0 deletions include/git2/repository.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "types.h"
#include "oid.h"
#include "odb.h"
#include "refdb.h"
#include "buffer.h"
#include "commit.h"

Expand Down Expand Up @@ -377,6 +378,12 @@ typedef struct {
*/
git_oid_t oid_type;
#endif

/**
* Type of the reference database to use for this repository, or 0 for
* default (currently "files").
*/
git_refdb_t refdb_type;
} git_repository_init_options;

/** Current version for the `git_repository_init_options` structure */
Expand Down
38 changes: 38 additions & 0 deletions include/git2/sys/refdb_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,48 @@ struct git_reference_iterator {
git_reference_iterator *iter);
};

typedef enum {
/**
* The refdb that is to be initialized is for a worktree.
*/
GIT_REFDB_BACKEND_INIT_IS_WORKTREE = (1u << 0),

/*
* Force-overwrite HEAD in case the refdb is already (partially)
* initialized.
*/
GIT_REFDB_BACKEND_INIT_FORCE_HEAD = (1u << 1)
} git_refdb_backend_init_flag_t;

/** An instance for a custom backend */
struct git_refdb_backend {
unsigned int version; /**< The backend API version */

/**
* Create a new refdb and initialize its structures.
*
* A refdb implementation may provide this function; if it is not
* provided, no data structures will be initialized for the refdb when
* a new repository is created.
*
* @param path The path of the Git directory that shall be initialized.
* @param initial_head The target that HEAD should point to. This value
* should only be applied when there isn't yet a HEAD
* reference, or when `GIT_REFDB_BACKEND_INIT_FORCE_HEAD`
* is passed. Optional, if unset the backend should not set
* up HEAD, either.
* @param mode The mode that shall be used to create files and
* directories. May be one of `git_repository_init_mode_t`
* or normal Unix permission bits.
* @param flags A combination of `git_refdb_backend_init_flag_t` flags.
* @return `0` on success, a negative error value code.
*/
int GIT_CALLBACK(init)(
git_refdb_backend *backend,
const char *head_target,
mode_t mode,
uint32_t flags);

/**
* Queries the refdb backend for the existence of a reference.
*
Expand Down
38 changes: 28 additions & 10 deletions src/libgit2/refdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,28 +39,36 @@ int git_refdb_new(git_refdb **out, git_repository *repo)

int git_refdb_open(git_refdb **out, git_repository *repo)
{
git_refdb_backend *backend;
git_refdb *db;
git_refdb_backend *dir;
int error;

GIT_ASSERT_ARG(out);
GIT_ASSERT_ARG(repo);

*out = NULL;

if (git_refdb_new(&db, repo) < 0)
return -1;
if ((error = git_refdb_new(&db, repo)) < 0)
goto out;

/* Add the default (filesystem) backend */
if (git_refdb_backend_fs(&dir, repo) < 0) {
git_refdb_free(db);
return -1;
switch (repo->refdb_type) {
case GIT_REFDB_FILES:
if ((error = git_refdb_backend_fs(&backend, repo)) < 0)
goto out;
break;
default:
git_error_set(GIT_ERROR_REFERENCE, "unknown reference storage format");
error = GIT_EINVALID;
goto out;
}

db->repo = repo;
db->backend = dir;

db->backend = backend;
*out = db;
return 0;
out:
if (error)
git_refdb_free(db);
return error;
}

static void refdb_free_backend(git_refdb *db)
Expand Down Expand Up @@ -114,6 +122,16 @@ void git_refdb_free(git_refdb *db)
GIT_REFCOUNT_DEC(db, git_refdb__free);
}

int git_refdb_init(git_refdb *refdb, const char *head_target, mode_t mode, uint32_t flags)
{
GIT_ASSERT_ARG(refdb);
GIT_ASSERT_ARG(refdb->backend);

if (!refdb->backend->init)
return 0;
return refdb->backend->init(refdb->backend, head_target, mode, flags);
}

int git_refdb_exists(int *exists, git_refdb *refdb, const char *ref_name)
{
GIT_ASSERT_ARG(exists);
Expand Down
24 changes: 24 additions & 0 deletions src/libgit2/refdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "git2/refdb.h"
#include "repository.h"

#define GIT_INVALID_HEAD "refs/heads/.invalid"

struct git_refdb {
git_refcount rc;
git_repository *repo;
Expand All @@ -20,6 +22,11 @@ struct git_refdb {

void git_refdb__free(git_refdb *db);

int git_refdb_init(git_refdb *refdb,
const char *head_target,
mode_t mode,
uint32_t flags);

int git_refdb_exists(
int *exists,
git_refdb *refdb,
Expand Down Expand Up @@ -125,4 +132,21 @@ int git_refdb_ensure_log(git_refdb *refdb, const char *refname);
int git_refdb_lock(void **payload, git_refdb *db, const char *refname);
int git_refdb_unlock(git_refdb *db, void *payload, int success, int update_reflog, const git_reference *ref, const git_signature *sig, const char *message);

GIT_INLINE(const char *) git_refdb_type_name(git_refdb_t type)
{
switch (type) {
case GIT_REFDB_FILES:
return "files";
default:
return "unknown";
}
}

GIT_INLINE(git_refdb_t) git_refdb_type_fromstr(const char *name)
{
if (strcmp(name, "files") == 0)
return GIT_REFDB_FILES;
return 0;
}

#endif
55 changes: 55 additions & 0 deletions src/libgit2/refdb_fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,60 @@ static int packed_loadloose(refdb_fs_backend *backend)
return error;
}

static int refdb_fs_backend__init(struct git_refdb_backend *_backend,
const char *head_target,
mode_t mode,
uint32_t flags)
{
refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
git_str path = GIT_STR_INIT, content = GIT_STR_INIT;
int error;

/*
* As most references are per repository and not per worktree we don't
* want to set up the typical "refs/" hierarchy in worktrees.
*/
if ((flags & GIT_REFDB_BACKEND_INIT_IS_WORKTREE) == 0) {
mode_t dmode;

if (mode == GIT_REPOSITORY_INIT_SHARED_UMASK)
dmode = 0777;
else if (mode == GIT_REPOSITORY_INIT_SHARED_GROUP)
dmode = (0775 | S_ISGID);
else if (mode == GIT_REPOSITORY_INIT_SHARED_ALL)
dmode = (0777 | S_ISGID);
else
dmode = mode;

if ((error = git_str_joinpath(&path, backend->gitpath, GIT_REFS_HEADS_DIR)) < 0 ||
(error = git_futils_mkdir(path.ptr, dmode, 0) < 0) ||
(error = git_str_joinpath(&path, backend->gitpath, GIT_REFS_TAGS_DIR)) < 0 ||
(error = git_futils_mkdir(path.ptr, dmode, 0) < 0))
goto out;
}

if (head_target) {
if ((error = git_str_joinpath(&path, backend->gitpath, GIT_HEAD_FILE)) < 0)
goto out;

if ((flags & GIT_REFDB_BACKEND_INIT_FORCE_HEAD) == 0 &&
git_fs_path_exists(path.ptr))
goto out;

if ((error = git_str_printf(&content, GIT_SYMREF "%s\n", head_target)) < 0 ||
(error = git_futils_writebuffer(&content, path.ptr, 0, mode)) < 0)
goto out;
}

error = 0;

out:
git_str_dispose(&content);
git_str_dispose(&path);

return error;
}

static int refdb_fs_backend__exists(
int *exists,
git_refdb_backend *_backend,
Expand Down Expand Up @@ -2545,6 +2599,7 @@ int git_refdb_backend_fs(
backend->fsync = 1;
backend->iterator_flags |= GIT_ITERATOR_DESCEND_SYMLINKS;

backend->parent.init = &refdb_fs_backend__init;
backend->parent.exists = &refdb_fs_backend__exists;
backend->parent.lookup = &refdb_fs_backend__lookup;
backend->parent.iterator = &refdb_fs_backend__iterator;
Expand Down
2 changes: 0 additions & 2 deletions src/libgit2/repo_template.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@ typedef struct {
static repo_template_item repo_template[] = {
{ GIT_OBJECTS_INFO_DIR, GIT_OBJECT_DIR_MODE, NULL }, /* '/objects/info/' */
{ GIT_OBJECTS_PACK_DIR, GIT_OBJECT_DIR_MODE, NULL }, /* '/objects/pack/' */
{ GIT_REFS_HEADS_DIR, GIT_REFS_DIR_MODE, NULL }, /* '/refs/heads/' */
{ GIT_REFS_TAGS_DIR, GIT_REFS_DIR_MODE, NULL }, /* '/refs/tags/' */
{ GIT_HOOKS_DIR, GIT_HOOKS_DIR_MODE, NULL }, /* '/hooks/' */
{ GIT_INFO_DIR, GIT_INFO_DIR_MODE, NULL }, /* '/info/' */
{ GIT_DESC_FILE, GIT_DESC_MODE, GIT_DESC_CONTENT },
Expand Down
Loading
Loading