1
0
mirror of https://github.com/git/git.git synced 2024-09-29 16:41:53 +02:00

Merge branch 'mh/ref-store'

The ref-store abstraction was introduced to the refs API so that we
can plug in different backends to store references.

* mh/ref-store: (38 commits)
  refs: implement iteration over only per-worktree refs
  refs: make lock generic
  refs: add method to rename refs
  refs: add methods to init refs db
  refs: make delete_refs() virtual
  refs: add method for initial ref transaction commit
  refs: add methods for reflog
  refs: add method iterator_begin
  files_ref_iterator_begin(): take a ref_store argument
  split_symref_update(): add a files_ref_store argument
  lock_ref_sha1_basic(): add a files_ref_store argument
  lock_ref_for_update(): add a files_ref_store argument
  commit_ref_update(): add a files_ref_store argument
  lock_raw_ref(): add a files_ref_store argument
  repack_without_refs(): add a files_ref_store argument
  refs: make peel_ref() virtual
  refs: make create_symref() virtual
  refs: make pack_refs() virtual
  refs: make verify_refname_available() virtual
  refs: make read_raw_ref() virtual
  ...
This commit is contained in:
Junio C Hamano 2016-09-19 13:47:19 -07:00
commit 4322f3848a
5 changed files with 812 additions and 317 deletions

@ -180,13 +180,7 @@ static int create_default_files(const char *template_path)
char junk[2];
int reinit;
int filemode;
/*
* Create .git/refs/{heads,tags}
*/
safe_create_dir(git_path_buf(&buf, "refs"), 1);
safe_create_dir(git_path_buf(&buf, "refs/heads"), 1);
safe_create_dir(git_path_buf(&buf, "refs/tags"), 1);
struct strbuf err = STRBUF_INIT;
/* Just look for `init.templatedir` */
git_config(git_init_db_config, NULL);
@ -210,11 +204,18 @@ static int create_default_files(const char *template_path)
*/
if (get_shared_repository()) {
adjust_shared_perm(get_git_dir());
adjust_shared_perm(git_path_buf(&buf, "refs"));
adjust_shared_perm(git_path_buf(&buf, "refs/heads"));
adjust_shared_perm(git_path_buf(&buf, "refs/tags"));
}
/*
* We need to create a "refs" dir in any case so that older
* versions of git can tell that this is a repository.
*/
safe_create_dir(git_path("refs"), 1);
adjust_shared_perm(git_path("refs"));
if (refs_init_db(&err))
die("failed to set up refs db: %s", err.buf);
/*
* Create the default symlink from ".git/HEAD" to the "master"
* branch, if it does not exist yet.

309
refs.c

@ -9,6 +9,25 @@
#include "object.h"
#include "tag.h"
/*
* List of all available backends
*/
static struct ref_storage_be *refs_backends = &refs_be_files;
static struct ref_storage_be *find_ref_storage_backend(const char *name)
{
struct ref_storage_be *be;
for (be = refs_backends; be; be = be->next)
if (!strcmp(be->name, name))
return be;
return NULL;
}
int ref_storage_backend_exists(const char *name)
{
return find_ref_storage_backend(name) != NULL;
}
/*
* How to handle various characters in refnames:
* 0: An acceptable character for refs
@ -1081,20 +1100,20 @@ const char *find_descendant_ref(const char *dirname,
return NULL;
}
int rename_ref_available(const char *oldname, const char *newname)
int rename_ref_available(const char *old_refname, const char *new_refname)
{
struct string_list skip = STRING_LIST_INIT_NODUP;
struct strbuf err = STRBUF_INIT;
int ret;
int ok;
string_list_insert(&skip, oldname);
ret = !verify_refname_available(newname, NULL, &skip, &err);
if (!ret)
string_list_insert(&skip, old_refname);
ok = !verify_refname_available(new_refname, NULL, &skip, &err);
if (!ok)
error("%s", err.buf);
string_list_clear(&skip, 0);
strbuf_release(&err);
return ret;
return ok;
}
int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)
@ -1132,9 +1151,13 @@ int head_ref(each_ref_fn fn, void *cb_data)
static int do_for_each_ref(const char *submodule, const char *prefix,
each_ref_fn fn, int trim, int flags, void *cb_data)
{
struct ref_store *refs = get_ref_store(submodule);
struct ref_iterator *iter;
iter = files_ref_iterator_begin(submodule, prefix, flags);
if (!refs)
return 0;
iter = refs->be->iterator_begin(refs, prefix, flags);
iter = prefix_ref_iterator_begin(iter, prefix, trim);
return do_for_each_ref_iterator(iter, fn, cb_data);
@ -1193,8 +1216,10 @@ int for_each_rawref(each_ref_fn fn, void *cb_data)
}
/* This function needs to return a meaningful errno on failure */
const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
unsigned char *sha1, int *flags)
static const char *resolve_ref_recursively(struct ref_store *refs,
const char *refname,
int resolve_flags,
unsigned char *sha1, int *flags)
{
static struct strbuf sb_refname = STRBUF_INIT;
int unused_flags;
@ -1226,7 +1251,8 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
for (symref_count = 0; symref_count < SYMREF_MAXDEPTH; symref_count++) {
unsigned int read_flags = 0;
if (read_raw_ref(refname, sha1, &sb_refname, &read_flags)) {
if (refs->be->read_raw_ref(refs, refname,
sha1, &sb_refname, &read_flags)) {
*flags |= read_flags;
if (errno != ENOENT || (resolve_flags & RESOLVE_REF_READING))
return NULL;
@ -1265,3 +1291,266 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
errno = ELOOP;
return NULL;
}
/* backend functions */
int refs_init_db(struct strbuf *err)
{
struct ref_store *refs = get_ref_store(NULL);
return refs->be->init_db(refs, err);
}
const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
unsigned char *sha1, int *flags)
{
return resolve_ref_recursively(get_ref_store(NULL), refname,
resolve_flags, sha1, flags);
}
int resolve_gitlink_ref(const char *submodule, const char *refname,
unsigned char *sha1)
{
size_t len = strlen(submodule);
struct ref_store *refs;
int flags;
while (len && submodule[len - 1] == '/')
len--;
if (!len)
return -1;
if (submodule[len]) {
/* We need to strip off one or more trailing slashes */
char *stripped = xmemdupz(submodule, len);
refs = get_ref_store(stripped);
free(stripped);
} else {
refs = get_ref_store(submodule);
}
if (!refs)
return -1;
if (!resolve_ref_recursively(refs, refname, 0, sha1, &flags) ||
is_null_sha1(sha1))
return -1;
return 0;
}
/* A pointer to the ref_store for the main repository: */
static struct ref_store *main_ref_store;
/* A linked list of ref_stores for submodules: */
static struct ref_store *submodule_ref_stores;
void base_ref_store_init(struct ref_store *refs,
const struct ref_storage_be *be,
const char *submodule)
{
refs->be = be;
if (!submodule) {
if (main_ref_store)
die("BUG: main_ref_store initialized twice");
refs->submodule = "";
refs->next = NULL;
main_ref_store = refs;
} else {
if (lookup_ref_store(submodule))
die("BUG: ref_store for submodule '%s' initialized twice",
submodule);
refs->submodule = xstrdup(submodule);
refs->next = submodule_ref_stores;
submodule_ref_stores = refs;
}
}
struct ref_store *ref_store_init(const char *submodule)
{
const char *be_name = "files";
struct ref_storage_be *be = find_ref_storage_backend(be_name);
if (!be)
die("BUG: reference backend %s is unknown", be_name);
if (!submodule || !*submodule)
return be->init(NULL);
else
return be->init(submodule);
}
struct ref_store *lookup_ref_store(const char *submodule)
{
struct ref_store *refs;
if (!submodule || !*submodule)
return main_ref_store;
for (refs = submodule_ref_stores; refs; refs = refs->next) {
if (!strcmp(submodule, refs->submodule))
return refs;
}
return NULL;
}
struct ref_store *get_ref_store(const char *submodule)
{
struct ref_store *refs;
if (!submodule || !*submodule) {
refs = lookup_ref_store(NULL);
if (!refs)
refs = ref_store_init(NULL);
} else {
refs = lookup_ref_store(submodule);
if (!refs) {
struct strbuf submodule_sb = STRBUF_INIT;
strbuf_addstr(&submodule_sb, submodule);
if (is_nonbare_repository_dir(&submodule_sb))
refs = ref_store_init(submodule);
strbuf_release(&submodule_sb);
}
}
return refs;
}
void assert_main_repository(struct ref_store *refs, const char *caller)
{
if (*refs->submodule)
die("BUG: %s called for a submodule", caller);
}
/* backend functions */
int pack_refs(unsigned int flags)
{
struct ref_store *refs = get_ref_store(NULL);
return refs->be->pack_refs(refs, flags);
}
int peel_ref(const char *refname, unsigned char *sha1)
{
struct ref_store *refs = get_ref_store(NULL);
return refs->be->peel_ref(refs, refname, sha1);
}
int create_symref(const char *ref_target, const char *refs_heads_master,
const char *logmsg)
{
struct ref_store *refs = get_ref_store(NULL);
return refs->be->create_symref(refs, ref_target, refs_heads_master,
logmsg);
}
int ref_transaction_commit(struct ref_transaction *transaction,
struct strbuf *err)
{
struct ref_store *refs = get_ref_store(NULL);
return refs->be->transaction_commit(refs, transaction, err);
}
int verify_refname_available(const char *refname,
const struct string_list *extra,
const struct string_list *skip,
struct strbuf *err)
{
struct ref_store *refs = get_ref_store(NULL);
return refs->be->verify_refname_available(refs, refname, extra, skip, err);
}
int for_each_reflog(each_ref_fn fn, void *cb_data)
{
struct ref_store *refs = get_ref_store(NULL);
struct ref_iterator *iter;
iter = refs->be->reflog_iterator_begin(refs);
return do_for_each_ref_iterator(iter, fn, cb_data);
}
int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn,
void *cb_data)
{
struct ref_store *refs = get_ref_store(NULL);
return refs->be->for_each_reflog_ent_reverse(refs, refname,
fn, cb_data);
}
int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn,
void *cb_data)
{
struct ref_store *refs = get_ref_store(NULL);
return refs->be->for_each_reflog_ent(refs, refname, fn, cb_data);
}
int reflog_exists(const char *refname)
{
struct ref_store *refs = get_ref_store(NULL);
return refs->be->reflog_exists(refs, refname);
}
int safe_create_reflog(const char *refname, int force_create,
struct strbuf *err)
{
struct ref_store *refs = get_ref_store(NULL);
return refs->be->create_reflog(refs, refname, force_create, err);
}
int delete_reflog(const char *refname)
{
struct ref_store *refs = get_ref_store(NULL);
return refs->be->delete_reflog(refs, refname);
}
int reflog_expire(const char *refname, const unsigned char *sha1,
unsigned int flags,
reflog_expiry_prepare_fn prepare_fn,
reflog_expiry_should_prune_fn should_prune_fn,
reflog_expiry_cleanup_fn cleanup_fn,
void *policy_cb_data)
{
struct ref_store *refs = get_ref_store(NULL);
return refs->be->reflog_expire(refs, refname, sha1, flags,
prepare_fn, should_prune_fn,
cleanup_fn, policy_cb_data);
}
int initial_ref_transaction_commit(struct ref_transaction *transaction,
struct strbuf *err)
{
struct ref_store *refs = get_ref_store(NULL);
return refs->be->initial_transaction_commit(refs, transaction, err);
}
int delete_refs(struct string_list *refnames, unsigned int flags)
{
struct ref_store *refs = get_ref_store(NULL);
return refs->be->delete_refs(refs, refnames, flags);
}
int rename_ref(const char *oldref, const char *newref, const char *logmsg)
{
struct ref_store *refs = get_ref_store(NULL);
return refs->be->rename_ref(refs, oldref, newref, logmsg);
}

13
refs.h

@ -66,6 +66,8 @@ int ref_exists(const char *refname);
int is_branch(const char *refname);
extern int refs_init_db(struct strbuf *err);
/*
* If refname is a non-symbolic reference that refers to a tag object,
* and the tag can be (recursively) dereferenced to a non-tag object,
@ -77,11 +79,12 @@ int is_branch(const char *refname);
int peel_ref(const char *refname, unsigned char *sha1);
/**
* Resolve refname in the nested "gitlink" repository that is located
* at path. If the resolution is successful, return 0 and set sha1 to
* the name of the object; otherwise, return a non-zero value.
* Resolve refname in the nested "gitlink" repository in the specified
* submodule (which must be non-NULL). If the resolution is
* successful, return 0 and set sha1 to the name of the object;
* otherwise, return a non-zero value.
*/
int resolve_gitlink_ref(const char *path, const char *refname,
int resolve_gitlink_ref(const char *submodule, const char *refname,
unsigned char *sha1);
/*
@ -544,4 +547,6 @@ int reflog_expire(const char *refname, const unsigned char *sha1,
reflog_expiry_cleanup_fn cleanup_fn,
void *policy_cb_data);
int ref_storage_backend_exists(const char *name);
#endif /* REFS_H */

@ -39,7 +39,7 @@ struct ref_value {
struct object_id peeled;
};
struct ref_cache;
struct files_ref_store;
/*
* Information used (along with the information in ref_entry) to
@ -78,8 +78,8 @@ struct ref_dir {
*/
int sorted;
/* A pointer to the ref_cache that contains this ref_dir. */
struct ref_cache *ref_cache;
/* A pointer to the files_ref_store that contains this ref_dir. */
struct files_ref_store *ref_store;
struct ref_entry **entries;
};
@ -161,7 +161,7 @@ struct ref_entry {
static void read_loose_refs(const char *dirname, struct ref_dir *dir);
static int search_ref_dir(struct ref_dir *dir, const char *refname, size_t len);
static struct ref_entry *create_dir_entry(struct ref_cache *ref_cache,
static struct ref_entry *create_dir_entry(struct files_ref_store *ref_store,
const char *dirname, size_t len,
int incomplete);
static void add_entry_to_dir(struct ref_dir *dir, struct ref_entry *entry);
@ -183,7 +183,7 @@ static struct ref_dir *get_ref_dir(struct ref_entry *entry)
int pos = search_ref_dir(dir, "refs/bisect/", 12);
if (pos < 0) {
struct ref_entry *child_entry;
child_entry = create_dir_entry(dir->ref_cache,
child_entry = create_dir_entry(dir->ref_store,
"refs/bisect/",
12, 1);
add_entry_to_dir(dir, child_entry);
@ -261,13 +261,13 @@ static void clear_ref_dir(struct ref_dir *dir)
* dirname is the name of the directory with a trailing slash (e.g.,
* "refs/heads/") or "" for the top-level directory.
*/
static struct ref_entry *create_dir_entry(struct ref_cache *ref_cache,
static struct ref_entry *create_dir_entry(struct files_ref_store *ref_store,
const char *dirname, size_t len,
int incomplete)
{
struct ref_entry *direntry;
FLEX_ALLOC_MEM(direntry, name, dirname, len);
direntry->u.subdir.ref_cache = ref_cache;
direntry->u.subdir.ref_store = ref_store;
direntry->flag = REF_DIR | (incomplete ? REF_INCOMPLETE : 0);
return direntry;
}
@ -343,7 +343,7 @@ static struct ref_dir *search_for_subdir(struct ref_dir *dir,
* therefore, create an empty record for it but mark
* the record complete.
*/
entry = create_dir_entry(dir->ref_cache, subdirname, len, 0);
entry = create_dir_entry(dir->ref_store, subdirname, len, 0);
add_entry_to_dir(dir, entry);
} else {
entry = dir->entries[entry_index];
@ -887,9 +887,9 @@ struct packed_ref_cache {
/*
* Count of references to the data structure in this instance,
* including the pointer from ref_cache::packed if any. The
* data will not be freed as long as the reference count is
* nonzero.
* including the pointer from files_ref_store::packed if any.
* The data will not be freed as long as the reference count
* is nonzero.
*/
unsigned int referrers;
@ -910,17 +910,11 @@ struct packed_ref_cache {
* Future: need to be in "struct repository"
* when doing a full libification.
*/
static struct ref_cache {
struct ref_cache *next;
struct files_ref_store {
struct ref_store base;
struct ref_entry *loose;
struct packed_ref_cache *packed;
/*
* The submodule name, or "" for the main repo. We allocate
* length 1 rather than FLEX_ARRAY so that the main ref_cache
* is initialized correctly.
*/
char name[1];
} ref_cache, *submodule_ref_caches;
};
/* Lock used for the main packed-refs file: */
static struct lock_file packlock;
@ -949,7 +943,7 @@ static int release_packed_ref_cache(struct packed_ref_cache *packed_refs)
}
}
static void clear_packed_ref_cache(struct ref_cache *refs)
static void clear_packed_ref_cache(struct files_ref_store *refs)
{
if (refs->packed) {
struct packed_ref_cache *packed_refs = refs->packed;
@ -961,7 +955,7 @@ static void clear_packed_ref_cache(struct ref_cache *refs)
}
}
static void clear_loose_ref_cache(struct ref_cache *refs)
static void clear_loose_ref_cache(struct files_ref_store *refs)
{
if (refs->loose) {
free_ref_entry(refs->loose);
@ -973,53 +967,34 @@ static void clear_loose_ref_cache(struct ref_cache *refs)
* Create a new submodule ref cache and add it to the internal
* set of caches.
*/
static struct ref_cache *create_ref_cache(const char *submodule)
static struct ref_store *files_ref_store_create(const char *submodule)
{
struct ref_cache *refs;
if (!submodule)
submodule = "";
FLEX_ALLOC_STR(refs, name, submodule);
refs->next = submodule_ref_caches;
submodule_ref_caches = refs;
return refs;
}
struct files_ref_store *refs = xcalloc(1, sizeof(*refs));
struct ref_store *ref_store = (struct ref_store *)refs;
static struct ref_cache *lookup_ref_cache(const char *submodule)
{
struct ref_cache *refs;
base_ref_store_init(ref_store, &refs_be_files, submodule);
if (!submodule || !*submodule)
return &ref_cache;
for (refs = submodule_ref_caches; refs; refs = refs->next)
if (!strcmp(submodule, refs->name))
return refs;
return NULL;
return ref_store;
}
/*
* Return a pointer to a ref_cache for the specified submodule. For
* the main repository, use submodule==NULL; such a call cannot fail.
* For a submodule, the submodule must exist and be a nonbare
* repository, otherwise return NULL.
*
* The returned structure will be allocated and initialized but not
* necessarily populated; it should not be freed.
* Downcast ref_store to files_ref_store. Die if ref_store is not a
* files_ref_store. If submodule_allowed is not true, then also die if
* files_ref_store is for a submodule (i.e., not for the main
* repository). caller is used in any necessary error messages.
*/
static struct ref_cache *get_ref_cache(const char *submodule)
static struct files_ref_store *files_downcast(
struct ref_store *ref_store, int submodule_allowed,
const char *caller)
{
struct ref_cache *refs = lookup_ref_cache(submodule);
if (ref_store->be != &refs_be_files)
die("BUG: ref_store is type \"%s\" not \"files\" in %s",
ref_store->be->name, caller);
if (!refs) {
struct strbuf submodule_sb = STRBUF_INIT;
if (!submodule_allowed)
assert_main_repository(ref_store, caller);
strbuf_addstr(&submodule_sb, submodule);
if (is_nonbare_repository_dir(&submodule_sb))
refs = create_ref_cache(submodule);
strbuf_release(&submodule_sb);
}
return refs;
return (struct files_ref_store *)ref_store;
}
/* The length of a peeled reference line in packed-refs, including EOL: */
@ -1151,15 +1126,16 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir)
}
/*
* Get the packed_ref_cache for the specified ref_cache, creating it
* if necessary.
* Get the packed_ref_cache for the specified files_ref_store,
* creating it if necessary.
*/
static struct packed_ref_cache *get_packed_ref_cache(struct ref_cache *refs)
static struct packed_ref_cache *get_packed_ref_cache(struct files_ref_store *refs)
{
char *packed_refs_file;
if (*refs->name)
packed_refs_file = git_pathdup_submodule(refs->name, "packed-refs");
if (*refs->base.submodule)
packed_refs_file = git_pathdup_submodule(refs->base.submodule,
"packed-refs");
else
packed_refs_file = git_pathdup("packed-refs");
@ -1189,7 +1165,7 @@ static struct ref_dir *get_packed_ref_dir(struct packed_ref_cache *packed_ref_ca
return get_ref_dir(packed_ref_cache->root);
}
static struct ref_dir *get_packed_refs(struct ref_cache *refs)
static struct ref_dir *get_packed_refs(struct files_ref_store *refs)
{
return get_packed_ref_dir(get_packed_ref_cache(refs));
}
@ -1200,10 +1176,10 @@ static struct ref_dir *get_packed_refs(struct ref_cache *refs)
* lock_packed_refs()). To actually write the packed-refs file, call
* commit_packed_refs().
*/
static void add_packed_ref(const char *refname, const unsigned char *sha1)
static void add_packed_ref(struct files_ref_store *refs,
const char *refname, const unsigned char *sha1)
{
struct packed_ref_cache *packed_ref_cache =
get_packed_ref_cache(&ref_cache);
struct packed_ref_cache *packed_ref_cache = get_packed_ref_cache(refs);
if (!packed_ref_cache->lock)
die("internal error: packed refs not locked");
@ -1218,7 +1194,7 @@ static void add_packed_ref(const char *refname, const unsigned char *sha1)
*/
static void read_loose_refs(const char *dirname, struct ref_dir *dir)
{
struct ref_cache *refs = dir->ref_cache;
struct files_ref_store *refs = dir->ref_store;
DIR *d;
struct dirent *de;
int dirnamelen = strlen(dirname);
@ -1227,8 +1203,8 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
size_t path_baselen;
int err = 0;
if (*refs->name)
err = strbuf_git_path_submodule(&path, refs->name, "%s", dirname);
if (*refs->base.submodule)
err = strbuf_git_path_submodule(&path, refs->base.submodule, "%s", dirname);
else
strbuf_git_path(&path, "%s", dirname);
path_baselen = path.len;
@ -1268,10 +1244,10 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
} else {
int read_ok;
if (*refs->name) {
if (*refs->base.submodule) {
hashclr(sha1);
flag = 0;
read_ok = !resolve_gitlink_ref(refs->name,
read_ok = !resolve_gitlink_ref(refs->base.submodule,
refname.buf, sha1);
} else {
read_ok = !read_ref_full(refname.buf,
@ -1312,7 +1288,7 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
closedir(d);
}
static struct ref_dir *get_loose_refs(struct ref_cache *refs)
static struct ref_dir *get_loose_refs(struct files_ref_store *refs)
{
if (!refs->loose) {
/*
@ -1330,105 +1306,22 @@ static struct ref_dir *get_loose_refs(struct ref_cache *refs)
return get_ref_dir(refs->loose);
}
#define MAXREFLEN (1024)
/*
* Called by resolve_gitlink_ref_recursive() after it failed to read
* from the loose refs in ref_cache refs. Find <refname> in the
* packed-refs file for the submodule.
*/
static int resolve_gitlink_packed_ref(struct ref_cache *refs,
const char *refname, unsigned char *sha1)
{
struct ref_entry *ref;
struct ref_dir *dir = get_packed_refs(refs);
ref = find_ref(dir, refname);
if (ref == NULL)
return -1;
hashcpy(sha1, ref->u.value.oid.hash);
return 0;
}
static int resolve_gitlink_ref_recursive(struct ref_cache *refs,
const char *refname, unsigned char *sha1,
int recursion)
{
int fd, len;
char buffer[128], *p;
char *path;
if (recursion > SYMREF_MAXDEPTH || strlen(refname) > MAXREFLEN)
return -1;
path = *refs->name
? git_pathdup_submodule(refs->name, "%s", refname)
: git_pathdup("%s", refname);
fd = open(path, O_RDONLY);
free(path);
if (fd < 0)
return resolve_gitlink_packed_ref(refs, refname, sha1);
len = read(fd, buffer, sizeof(buffer)-1);
close(fd);
if (len < 0)
return -1;
while (len && isspace(buffer[len-1]))
len--;
buffer[len] = 0;
/* Was it a detached head or an old-fashioned symlink? */
if (!get_sha1_hex(buffer, sha1))
return 0;
/* Symref? */
if (strncmp(buffer, "ref:", 4))
return -1;
p = buffer + 4;
while (isspace(*p))
p++;
return resolve_gitlink_ref_recursive(refs, p, sha1, recursion+1);
}
int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1)
{
int len = strlen(path), retval;
struct strbuf submodule = STRBUF_INIT;
struct ref_cache *refs;
while (len && path[len-1] == '/')
len--;
if (!len)
return -1;
strbuf_add(&submodule, path, len);
refs = get_ref_cache(submodule.buf);
if (!refs) {
strbuf_release(&submodule);
return -1;
}
strbuf_release(&submodule);
retval = resolve_gitlink_ref_recursive(refs, refname, sha1, 0);
return retval;
}
/*
* Return the ref_entry for the given refname from the packed
* references. If it does not exist, return NULL.
*/
static struct ref_entry *get_packed_ref(const char *refname)
static struct ref_entry *get_packed_ref(struct files_ref_store *refs,
const char *refname)
{
return find_ref(get_packed_refs(&ref_cache), refname);
return find_ref(get_packed_refs(refs), refname);
}
/*
* A loose ref file doesn't exist; check for a packed ref.
*/
static int resolve_missing_loose_ref(const char *refname,
unsigned char *sha1,
unsigned int *flags)
static int resolve_packed_ref(struct files_ref_store *refs,
const char *refname,
unsigned char *sha1, unsigned int *flags)
{
struct ref_entry *entry;
@ -1436,7 +1329,7 @@ static int resolve_missing_loose_ref(const char *refname,
* The loose reference file does not exist; check for a packed
* reference.
*/
entry = get_packed_ref(refname);
entry = get_packed_ref(refs, refname);
if (entry) {
hashcpy(sha1, entry->u.value.oid.hash);
*flags |= REF_ISPACKED;
@ -1446,9 +1339,12 @@ static int resolve_missing_loose_ref(const char *refname,
return -1;
}
int read_raw_ref(const char *refname, unsigned char *sha1,
struct strbuf *referent, unsigned int *type)
static int files_read_raw_ref(struct ref_store *ref_store,
const char *refname, unsigned char *sha1,
struct strbuf *referent, unsigned int *type)
{
struct files_ref_store *refs =
files_downcast(ref_store, 1, "read_raw_ref");
struct strbuf sb_contents = STRBUF_INIT;
struct strbuf sb_path = STRBUF_INIT;
const char *path;
@ -1460,7 +1356,12 @@ int read_raw_ref(const char *refname, unsigned char *sha1,
*type = 0;
strbuf_reset(&sb_path);
strbuf_git_path(&sb_path, "%s", refname);
if (*refs->base.submodule)
strbuf_git_path_submodule(&sb_path, refs->base.submodule, "%s", refname);
else
strbuf_git_path(&sb_path, "%s", refname);
path = sb_path.buf;
stat_ref:
@ -1477,7 +1378,7 @@ stat_ref:
if (lstat(path, &st) < 0) {
if (errno != ENOENT)
goto out;
if (resolve_missing_loose_ref(refname, sha1, type)) {
if (resolve_packed_ref(refs, refname, sha1, type)) {
errno = ENOENT;
goto out;
}
@ -1511,7 +1412,7 @@ stat_ref:
* ref is supposed to be, there could still be a
* packed ref:
*/
if (resolve_missing_loose_ref(refname, sha1, type)) {
if (resolve_packed_ref(refs, refname, sha1, type)) {
errno = EISDIR;
goto out;
}
@ -1612,7 +1513,8 @@ static void unlock_ref(struct ref_lock *lock)
* avoided, namely if we were successfully able to read the ref
* - Generate informative error messages in the case of failure
*/
static int lock_raw_ref(const char *refname, int mustexist,
static int lock_raw_ref(struct files_ref_store *refs,
const char *refname, int mustexist,
const struct string_list *extras,
const struct string_list *skip,
struct ref_lock **lock_p,
@ -1626,6 +1528,8 @@ static int lock_raw_ref(const char *refname, int mustexist,
int ret = TRANSACTION_GENERIC_ERROR;
assert(err);
assert_main_repository(&refs->base, "lock_raw_ref");
*type = 0;
/* First lock the file so it can't change out from under us. */
@ -1709,7 +1613,8 @@ retry:
* fear that its value will change.
*/
if (read_raw_ref(refname, lock->old_oid.hash, referent, type)) {
if (files_read_raw_ref(&refs->base, refname,
lock->old_oid.hash, referent, type)) {
if (errno == ENOENT) {
if (mustexist) {
/* Garden variety missing reference. */
@ -1752,7 +1657,7 @@ retry:
REMOVE_DIR_EMPTY_ONLY)) {
if (verify_refname_available_dir(
refname, extras, skip,
get_loose_refs(&ref_cache),
get_loose_refs(refs),
err)) {
/*
* The error message set by
@ -1791,7 +1696,7 @@ retry:
*/
if (verify_refname_available_dir(
refname, extras, skip,
get_packed_refs(&ref_cache),
get_packed_refs(refs),
err)) {
goto error_return;
}
@ -1844,8 +1749,10 @@ static enum peel_status peel_entry(struct ref_entry *entry, int repeel)
return status;
}
int peel_ref(const char *refname, unsigned char *sha1)
static int files_peel_ref(struct ref_store *ref_store,
const char *refname, unsigned char *sha1)
{
struct files_ref_store *refs = files_downcast(ref_store, 0, "peel_ref");
int flag;
unsigned char base[20];
@ -1870,7 +1777,7 @@ int peel_ref(const char *refname, unsigned char *sha1)
* have REF_KNOWS_PEELED.
*/
if (flag & REF_ISPACKED) {
struct ref_entry *r = get_packed_ref(refname);
struct ref_entry *r = get_packed_ref(refs, refname);
if (r) {
if (peel_entry(r, 0))
return -1;
@ -1897,6 +1804,10 @@ static int files_ref_iterator_advance(struct ref_iterator *ref_iterator)
int ok;
while ((ok = ref_iterator_advance(iter->iter0)) == ITER_OK) {
if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
ref_type(iter->iter0->refname) != REF_TYPE_PER_WORKTREE)
continue;
if (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
!ref_resolves_to_object(iter->iter0->refname,
iter->iter0->oid,
@ -1945,11 +1856,12 @@ static struct ref_iterator_vtable files_ref_iterator_vtable = {
files_ref_iterator_abort
};
struct ref_iterator *files_ref_iterator_begin(
const char *submodule,
static struct ref_iterator *files_ref_iterator_begin(
struct ref_store *ref_store,
const char *prefix, unsigned int flags)
{
struct ref_cache *refs = get_ref_cache(submodule);
struct files_ref_store *refs =
files_downcast(ref_store, 1, "ref_iterator_begin");
struct ref_dir *loose_dir, *packed_dir;
struct ref_iterator *loose_iter, *packed_iter;
struct files_ref_iterator *iter;
@ -2065,7 +1977,8 @@ static int remove_empty_directories(struct strbuf *path)
* Locks a ref returning the lock on success and NULL on failure.
* On failure errno is set to something meaningful.
*/
static struct ref_lock *lock_ref_sha1_basic(const char *refname,
static struct ref_lock *lock_ref_sha1_basic(struct files_ref_store *refs,
const char *refname,
const unsigned char *old_sha1,
const struct string_list *extras,
const struct string_list *skip,
@ -2081,6 +1994,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
int attempts_remaining = 3;
int resolved;
assert_main_repository(&refs->base, "lock_ref_sha1_basic");
assert(err);
lock = xcalloc(1, sizeof(struct ref_lock));
@ -2102,8 +2016,9 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
*/
if (remove_empty_directories(&ref_file)) {
last_errno = errno;
if (!verify_refname_available_dir(refname, extras, skip,
get_loose_refs(&ref_cache), err))
if (!verify_refname_available_dir(
refname, extras, skip,
get_loose_refs(refs), err))
strbuf_addf(err, "there are still refs under '%s'",
refname);
goto error_return;
@ -2114,8 +2029,9 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
if (!resolved) {
last_errno = errno;
if (last_errno != ENOTDIR ||
!verify_refname_available_dir(refname, extras, skip,
get_loose_refs(&ref_cache), err))
!verify_refname_available_dir(
refname, extras, skip,
get_loose_refs(refs), err))
strbuf_addf(err, "unable to resolve reference '%s': %s",
refname, strerror(last_errno));
@ -2130,7 +2046,8 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
*/
if (is_null_oid(&lock->old_oid) &&
verify_refname_available_dir(refname, extras, skip,
get_packed_refs(&ref_cache), err)) {
get_packed_refs(refs),
err)) {
last_errno = ENOTDIR;
goto error_return;
}
@ -2217,13 +2134,14 @@ static int write_packed_entry_fn(struct ref_entry *entry, void *cb_data)
* hold_lock_file_for_update(). Return 0 on success. On errors, set
* errno appropriately and return a nonzero value.
*/
static int lock_packed_refs(int flags)
static int lock_packed_refs(struct files_ref_store *refs, int flags)
{
static int timeout_configured = 0;
static int timeout_value = 1000;
struct packed_ref_cache *packed_ref_cache;
assert_main_repository(&refs->base, "lock_packed_refs");
if (!timeout_configured) {
git_config_get_int("core.packedrefstimeout", &timeout_value);
timeout_configured = 1;
@ -2239,7 +2157,7 @@ static int lock_packed_refs(int flags)
* this will automatically invalidate the cache and re-read
* the packed-refs file.
*/
packed_ref_cache = get_packed_ref_cache(&ref_cache);
packed_ref_cache = get_packed_ref_cache(refs);
packed_ref_cache->lock = &packlock;
/* Increment the reference count to prevent it from being freed: */
acquire_packed_ref_cache(packed_ref_cache);
@ -2252,14 +2170,16 @@ static int lock_packed_refs(int flags)
* lock_packed_refs()). Return zero on success. On errors, set errno
* and return a nonzero value
*/
static int commit_packed_refs(void)
static int commit_packed_refs(struct files_ref_store *refs)
{
struct packed_ref_cache *packed_ref_cache =
get_packed_ref_cache(&ref_cache);
get_packed_ref_cache(refs);
int error = 0;
int save_errno = 0;
FILE *out;
assert_main_repository(&refs->base, "commit_packed_refs");
if (!packed_ref_cache->lock)
die("internal error: packed-refs not locked");
@ -2286,17 +2206,19 @@ static int commit_packed_refs(void)
* in-memory packed reference cache. (The packed-refs file will be
* read anew if it is needed again after this function is called.)
*/
static void rollback_packed_refs(void)
static void rollback_packed_refs(struct files_ref_store *refs)
{
struct packed_ref_cache *packed_ref_cache =
get_packed_ref_cache(&ref_cache);
get_packed_ref_cache(refs);
assert_main_repository(&refs->base, "rollback_packed_refs");
if (!packed_ref_cache->lock)
die("internal error: packed-refs not locked");
rollback_lock_file(packed_ref_cache->lock);
packed_ref_cache->lock = NULL;
release_packed_ref_cache(packed_ref_cache);
clear_packed_ref_cache(&ref_cache);
clear_packed_ref_cache(refs);
}
struct ref_to_prune {
@ -2427,20 +2349,22 @@ static void prune_refs(struct ref_to_prune *r)
}
}
int pack_refs(unsigned int flags)
static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
{
struct files_ref_store *refs =
files_downcast(ref_store, 0, "pack_refs");
struct pack_refs_cb_data cbdata;
memset(&cbdata, 0, sizeof(cbdata));
cbdata.flags = flags;
lock_packed_refs(LOCK_DIE_ON_ERROR);
cbdata.packed_refs = get_packed_refs(&ref_cache);
lock_packed_refs(refs, LOCK_DIE_ON_ERROR);
cbdata.packed_refs = get_packed_refs(refs);
do_for_each_entry_in_dir(get_loose_refs(&ref_cache), 0,
do_for_each_entry_in_dir(get_loose_refs(refs), 0,
pack_if_possible_fn, &cbdata);
if (commit_packed_refs())
if (commit_packed_refs(refs))
die_errno("unable to overwrite old ref-pack file");
prune_refs(cbdata.ref_to_prune);
@ -2454,17 +2378,19 @@ int pack_refs(unsigned int flags)
*
* The refs in 'refnames' needn't be sorted. `err` must not be NULL.
*/
static int repack_without_refs(struct string_list *refnames, struct strbuf *err)
static int repack_without_refs(struct files_ref_store *refs,
struct string_list *refnames, struct strbuf *err)
{
struct ref_dir *packed;
struct string_list_item *refname;
int ret, needs_repacking = 0, removed = 0;
assert_main_repository(&refs->base, "repack_without_refs");
assert(err);
/* Look for a packed ref */
for_each_string_list_item(refname, refnames) {
if (get_packed_ref(refname->string)) {
if (get_packed_ref(refs, refname->string)) {
needs_repacking = 1;
break;
}
@ -2474,11 +2400,11 @@ static int repack_without_refs(struct string_list *refnames, struct strbuf *err)
if (!needs_repacking)
return 0; /* no refname exists in packed refs */
if (lock_packed_refs(0)) {
if (lock_packed_refs(refs, 0)) {
unable_to_lock_message(git_path("packed-refs"), errno, err);
return -1;
}
packed = get_packed_refs(&ref_cache);
packed = get_packed_refs(refs);
/* Remove refnames from the cache */
for_each_string_list_item(refname, refnames)
@ -2489,12 +2415,12 @@ static int repack_without_refs(struct string_list *refnames, struct strbuf *err)
* All packed entries disappeared while we were
* acquiring the lock.
*/
rollback_packed_refs();
rollback_packed_refs(refs);
return 0;
}
/* Write what remains */
ret = commit_packed_refs();
ret = commit_packed_refs(refs);
if (ret)
strbuf_addf(err, "unable to overwrite old ref-pack file: %s",
strerror(errno));
@ -2519,15 +2445,18 @@ static int delete_ref_loose(struct ref_lock *lock, int flag, struct strbuf *err)
return 0;
}
int delete_refs(struct string_list *refnames, unsigned int flags)
static int files_delete_refs(struct ref_store *ref_store,
struct string_list *refnames, unsigned int flags)
{
struct files_ref_store *refs =
files_downcast(ref_store, 0, "delete_refs");
struct strbuf err = STRBUF_INIT;
int i, result = 0;
if (!refnames->nr)
return 0;
result = repack_without_refs(refnames, &err);
result = repack_without_refs(refs, refnames, &err);
if (result) {
/*
* If we failed to rewrite the packed-refs file, then
@ -2618,13 +2547,16 @@ out:
return ret;
}
int verify_refname_available(const char *newname,
const struct string_list *extras,
const struct string_list *skip,
struct strbuf *err)
static int files_verify_refname_available(struct ref_store *ref_store,
const char *newname,
const struct string_list *extras,
const struct string_list *skip,
struct strbuf *err)
{
struct ref_dir *packed_refs = get_packed_refs(&ref_cache);
struct ref_dir *loose_refs = get_loose_refs(&ref_cache);
struct files_ref_store *refs =
files_downcast(ref_store, 1, "verify_refname_available");
struct ref_dir *packed_refs = get_packed_refs(refs);
struct ref_dir *loose_refs = get_loose_refs(refs);
if (verify_refname_available_dir(newname, extras, skip,
packed_refs, err) ||
@ -2637,12 +2569,17 @@ int verify_refname_available(const char *newname,
static int write_ref_to_lockfile(struct ref_lock *lock,
const unsigned char *sha1, struct strbuf *err);
static int commit_ref_update(struct ref_lock *lock,
static int commit_ref_update(struct files_ref_store *refs,
struct ref_lock *lock,
const unsigned char *sha1, const char *logmsg,
struct strbuf *err);
int rename_ref(const char *oldrefname, const char *newrefname, const char *logmsg)
static int files_rename_ref(struct ref_store *ref_store,
const char *oldrefname, const char *newrefname,
const char *logmsg)
{
struct files_ref_store *refs =
files_downcast(ref_store, 0, "rename_ref");
unsigned char sha1[20], orig_sha1[20];
int flag = 0, logmoved = 0;
struct ref_lock *lock;
@ -2705,8 +2642,8 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
logmoved = log;
lock = lock_ref_sha1_basic(newrefname, NULL, NULL, NULL, REF_NODEREF,
NULL, &err);
lock = lock_ref_sha1_basic(refs, newrefname, NULL, NULL, NULL,
REF_NODEREF, NULL, &err);
if (!lock) {
error("unable to rename '%s' to '%s': %s", oldrefname, newrefname, err.buf);
strbuf_release(&err);
@ -2715,7 +2652,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
hashcpy(lock->old_oid.hash, orig_sha1);
if (write_ref_to_lockfile(lock, orig_sha1, &err) ||
commit_ref_update(lock, orig_sha1, logmsg, &err)) {
commit_ref_update(refs, lock, orig_sha1, logmsg, &err)) {
error("unable to write current sha1 into %s: %s", newrefname, err.buf);
strbuf_release(&err);
goto rollback;
@ -2724,8 +2661,8 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
return 0;
rollback:
lock = lock_ref_sha1_basic(oldrefname, NULL, NULL, NULL, REF_NODEREF,
NULL, &err);
lock = lock_ref_sha1_basic(refs, oldrefname, NULL, NULL, NULL,
REF_NODEREF, NULL, &err);
if (!lock) {
error("unable to lock %s for rollback: %s", oldrefname, err.buf);
strbuf_release(&err);
@ -2735,7 +2672,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
flag = log_all_ref_updates;
log_all_ref_updates = 0;
if (write_ref_to_lockfile(lock, orig_sha1, &err) ||
commit_ref_update(lock, orig_sha1, NULL, &err)) {
commit_ref_update(refs, lock, orig_sha1, NULL, &err)) {
error("unable to write current sha1 into %s: %s", oldrefname, err.buf);
strbuf_release(&err);
}
@ -2838,11 +2775,16 @@ static int log_ref_setup(const char *refname, struct strbuf *logfile, struct str
}
int safe_create_reflog(const char *refname, int force_create, struct strbuf *err)
static int files_create_reflog(struct ref_store *ref_store,
const char *refname, int force_create,
struct strbuf *err)
{
int ret;
struct strbuf sb = STRBUF_INIT;
/* Check validity (but we don't need the result): */
files_downcast(ref_store, 0, "create_reflog");
ret = log_ref_setup(refname, &sb, err, force_create);
strbuf_release(&sb);
return ret;
@ -2971,11 +2913,14 @@ static int write_ref_to_lockfile(struct ref_lock *lock,
* to the loose reference lockfile. Also update the reflogs if
* necessary, using the specified lockmsg (which can be NULL).
*/
static int commit_ref_update(struct ref_lock *lock,
static int commit_ref_update(struct files_ref_store *refs,
struct ref_lock *lock,
const unsigned char *sha1, const char *logmsg,
struct strbuf *err)
{
clear_loose_ref_cache(&ref_cache);
assert_main_repository(&refs->base, "commit_ref_update");
clear_loose_ref_cache(refs);
if (log_ref_write(lock->ref_name, lock->old_oid.hash, sha1, logmsg, 0, err)) {
char *old_msg = strbuf_detach(err, NULL);
strbuf_addf(err, "cannot update the ref '%s': %s",
@ -3074,13 +3019,18 @@ static int create_symref_locked(struct ref_lock *lock, const char *refname,
return 0;
}
int create_symref(const char *refname, const char *target, const char *logmsg)
static int files_create_symref(struct ref_store *ref_store,
const char *refname, const char *target,
const char *logmsg)
{
struct files_ref_store *refs =
files_downcast(ref_store, 0, "create_symref");
struct strbuf err = STRBUF_INIT;
struct ref_lock *lock;
int ret;
lock = lock_ref_sha1_basic(refname, NULL, NULL, NULL, REF_NODEREF, NULL,
lock = lock_ref_sha1_basic(refs, refname, NULL,
NULL, NULL, REF_NODEREF, NULL,
&err);
if (!lock) {
error("%s", err.buf);
@ -3128,16 +3078,24 @@ int set_worktree_head_symref(const char *gitdir, const char *target)
return ret;
}
int reflog_exists(const char *refname)
static int files_reflog_exists(struct ref_store *ref_store,
const char *refname)
{
struct stat st;
/* Check validity (but we don't need the result): */
files_downcast(ref_store, 0, "reflog_exists");
return !lstat(git_path("logs/%s", refname), &st) &&
S_ISREG(st.st_mode);
}
int delete_reflog(const char *refname)
static int files_delete_reflog(struct ref_store *ref_store,
const char *refname)
{
/* Check validity (but we don't need the result): */
files_downcast(ref_store, 0, "delete_reflog");
return remove_path(git_path("logs/%s", refname));
}
@ -3180,13 +3138,19 @@ static char *find_beginning_of_line(char *bob, char *scan)
return scan;
}
int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn, void *cb_data)
static int files_for_each_reflog_ent_reverse(struct ref_store *ref_store,
const char *refname,
each_reflog_ent_fn fn,
void *cb_data)
{
struct strbuf sb = STRBUF_INIT;
FILE *logfp;
long pos;
int ret = 0, at_tail = 1;
/* Check validity (but we don't need the result): */
files_downcast(ref_store, 0, "for_each_reflog_ent_reverse");
logfp = fopen(git_path("logs/%s", refname), "r");
if (!logfp)
return -1;
@ -3282,12 +3246,17 @@ int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn, void
return ret;
}
int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn, void *cb_data)
static int files_for_each_reflog_ent(struct ref_store *ref_store,
const char *refname,
each_reflog_ent_fn fn, void *cb_data)
{
FILE *logfp;
struct strbuf sb = STRBUF_INIT;
int ret = 0;
/* Check validity (but we don't need the result): */
files_downcast(ref_store, 0, "for_each_reflog_ent");
logfp = fopen(git_path("logs/%s", refname), "r");
if (!logfp)
return -1;
@ -3366,22 +3335,19 @@ static struct ref_iterator_vtable files_reflog_iterator_vtable = {
files_reflog_iterator_abort
};
struct ref_iterator *files_reflog_iterator_begin(void)
static struct ref_iterator *files_reflog_iterator_begin(struct ref_store *ref_store)
{
struct files_reflog_iterator *iter = xcalloc(1, sizeof(*iter));
struct ref_iterator *ref_iterator = &iter->base;
/* Check validity (but we don't need the result): */
files_downcast(ref_store, 0, "reflog_iterator_begin");
base_ref_iterator_init(ref_iterator, &files_reflog_iterator_vtable);
iter->dir_iterator = dir_iterator_begin(git_path("logs"));
return ref_iterator;
}
int for_each_reflog(each_ref_fn fn, void *cb_data)
{
return do_for_each_ref_iterator(files_reflog_iterator_begin(),
fn, cb_data);
}
static int ref_update_reject_duplicates(struct string_list *refnames,
struct strbuf *err)
{
@ -3454,7 +3420,8 @@ static int split_head_update(struct ref_update *update,
* Note that the new update will itself be subject to splitting when
* the iteration gets to it.
*/
static int split_symref_update(struct ref_update *update,
static int split_symref_update(struct files_ref_store *refs,
struct ref_update *update,
const char *referent,
struct ref_transaction *transaction,
struct string_list *affected_refnames,
@ -3568,7 +3535,8 @@ static int check_old_oid(struct ref_update *update, struct object_id *oid,
* - If it is an update of head_ref, add a corresponding REF_LOG_ONLY
* update of HEAD.
*/
static int lock_ref_for_update(struct ref_update *update,
static int lock_ref_for_update(struct files_ref_store *refs,
struct ref_update *update,
struct ref_transaction *transaction,
const char *head_ref,
struct string_list *affected_refnames,
@ -3580,6 +3548,8 @@ static int lock_ref_for_update(struct ref_update *update,
int ret;
struct ref_lock *lock;
assert_main_repository(&refs->base, "lock_ref_for_update");
if ((update->flags & REF_HAVE_NEW) && is_null_sha1(update->new_sha1))
update->flags |= REF_DELETING;
@ -3590,11 +3560,10 @@ static int lock_ref_for_update(struct ref_update *update,
return ret;
}
ret = lock_raw_ref(update->refname, mustexist,
ret = lock_raw_ref(refs, update->refname, mustexist,
affected_refnames, NULL,
&update->lock, &referent,
&lock, &referent,
&update->type, err);
if (ret) {
char *reason;
@ -3605,7 +3574,7 @@ static int lock_ref_for_update(struct ref_update *update,
return ret;
}
lock = update->lock;
update->backend_data = lock;
if (update->type & REF_ISSYMREF) {
if (update->flags & REF_NODEREF) {
@ -3633,7 +3602,8 @@ static int lock_ref_for_update(struct ref_update *update,
* of processing the split-off update, so we
* don't have to do it here.
*/
ret = split_symref_update(update, referent.buf, transaction,
ret = split_symref_update(refs, update,
referent.buf, transaction,
affected_refnames, err);
if (ret)
return ret;
@ -3652,7 +3622,8 @@ static int lock_ref_for_update(struct ref_update *update,
for (parent_update = update->parent_update;
parent_update;
parent_update = parent_update->parent_update) {
oidcpy(&parent_update->lock->old_oid, &lock->old_oid);
struct ref_lock *parent_lock = parent_update->backend_data;
oidcpy(&parent_lock->old_oid, &lock->old_oid);
}
}
@ -3673,7 +3644,7 @@ static int lock_ref_for_update(struct ref_update *update,
* The lock was freed upon failure of
* write_ref_to_lockfile():
*/
update->lock = NULL;
update->backend_data = NULL;
strbuf_addf(err,
"cannot update ref '%s': %s",
update->refname, write_err);
@ -3698,9 +3669,12 @@ static int lock_ref_for_update(struct ref_update *update,
return 0;
}
int ref_transaction_commit(struct ref_transaction *transaction,
struct strbuf *err)
static int files_transaction_commit(struct ref_store *ref_store,
struct ref_transaction *transaction,
struct strbuf *err)
{
struct files_ref_store *refs =
files_downcast(ref_store, 0, "ref_transaction_commit");
int ret = 0, i;
struct string_list refs_to_delete = STRING_LIST_INIT_NODUP;
struct string_list_item *ref_to_delete;
@ -3779,8 +3753,8 @@ int ref_transaction_commit(struct ref_transaction *transaction,
for (i = 0; i < transaction->nr; i++) {
struct ref_update *update = transaction->updates[i];
ret = lock_ref_for_update(update, transaction, head_ref,
&affected_refnames, err);
ret = lock_ref_for_update(refs, update, transaction,
head_ref, &affected_refnames, err);
if (ret)
goto cleanup;
}
@ -3788,7 +3762,7 @@ int ref_transaction_commit(struct ref_transaction *transaction,
/* Perform updates first so live commits remain referenced */
for (i = 0; i < transaction->nr; i++) {
struct ref_update *update = transaction->updates[i];
struct ref_lock *lock = update->lock;
struct ref_lock *lock = update->backend_data;
if (update->flags & REF_NEEDS_COMMIT ||
update->flags & REF_LOG_ONLY) {
@ -3801,17 +3775,17 @@ int ref_transaction_commit(struct ref_transaction *transaction,
lock->ref_name, old_msg);
free(old_msg);
unlock_ref(lock);
update->lock = NULL;
update->backend_data = NULL;
ret = TRANSACTION_GENERIC_ERROR;
goto cleanup;
}
}
if (update->flags & REF_NEEDS_COMMIT) {
clear_loose_ref_cache(&ref_cache);
clear_loose_ref_cache(refs);
if (commit_ref(lock)) {
strbuf_addf(err, "couldn't set '%s'", lock->ref_name);
unlock_ref(lock);
update->lock = NULL;
update->backend_data = NULL;
ret = TRANSACTION_GENERIC_ERROR;
goto cleanup;
}
@ -3820,34 +3794,35 @@ int ref_transaction_commit(struct ref_transaction *transaction,
/* Perform deletes now that updates are safely completed */
for (i = 0; i < transaction->nr; i++) {
struct ref_update *update = transaction->updates[i];
struct ref_lock *lock = update->backend_data;
if (update->flags & REF_DELETING &&
!(update->flags & REF_LOG_ONLY)) {
if (delete_ref_loose(update->lock, update->type, err)) {
if (delete_ref_loose(lock, update->type, err)) {
ret = TRANSACTION_GENERIC_ERROR;
goto cleanup;
}
if (!(update->flags & REF_ISPRUNING))
string_list_append(&refs_to_delete,
update->lock->ref_name);
lock->ref_name);
}
}
if (repack_without_refs(&refs_to_delete, err)) {
if (repack_without_refs(refs, &refs_to_delete, err)) {
ret = TRANSACTION_GENERIC_ERROR;
goto cleanup;
}
for_each_string_list_item(ref_to_delete, &refs_to_delete)
unlink_or_warn(git_path("logs/%s", ref_to_delete->string));
clear_loose_ref_cache(&ref_cache);
clear_loose_ref_cache(refs);
cleanup:
transaction->state = REF_TRANSACTION_CLOSED;
for (i = 0; i < transaction->nr; i++)
if (transaction->updates[i]->lock)
unlock_ref(transaction->updates[i]->lock);
if (transaction->updates[i]->backend_data)
unlock_ref(transaction->updates[i]->backend_data);
string_list_clear(&refs_to_delete, 0);
free(head_ref);
string_list_clear(&affected_refnames, 0);
@ -3863,9 +3838,12 @@ static int ref_present(const char *refname,
return string_list_has_string(affected_refnames, refname);
}
int initial_ref_transaction_commit(struct ref_transaction *transaction,
struct strbuf *err)
static int files_initial_transaction_commit(struct ref_store *ref_store,
struct ref_transaction *transaction,
struct strbuf *err)
{
struct files_ref_store *refs =
files_downcast(ref_store, 0, "initial_ref_transaction_commit");
int ret = 0, i;
struct string_list affected_refnames = STRING_LIST_INIT_NODUP;
@ -3913,7 +3891,7 @@ int initial_ref_transaction_commit(struct ref_transaction *transaction,
}
}
if (lock_packed_refs(0)) {
if (lock_packed_refs(refs, 0)) {
strbuf_addf(err, "unable to lock packed-refs file: %s",
strerror(errno));
ret = TRANSACTION_GENERIC_ERROR;
@ -3925,10 +3903,10 @@ int initial_ref_transaction_commit(struct ref_transaction *transaction,
if ((update->flags & REF_HAVE_NEW) &&
!is_null_sha1(update->new_sha1))
add_packed_ref(update->refname, update->new_sha1);
add_packed_ref(refs, update->refname, update->new_sha1);
}
if (commit_packed_refs()) {
if (commit_packed_refs(refs)) {
strbuf_addf(err, "unable to commit packed-refs file: %s",
strerror(errno));
ret = TRANSACTION_GENERIC_ERROR;
@ -3978,13 +3956,16 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
return 0;
}
int reflog_expire(const char *refname, const unsigned char *sha1,
unsigned int flags,
reflog_expiry_prepare_fn prepare_fn,
reflog_expiry_should_prune_fn should_prune_fn,
reflog_expiry_cleanup_fn cleanup_fn,
void *policy_cb_data)
static int files_reflog_expire(struct ref_store *ref_store,
const char *refname, const unsigned char *sha1,
unsigned int flags,
reflog_expiry_prepare_fn prepare_fn,
reflog_expiry_should_prune_fn should_prune_fn,
reflog_expiry_cleanup_fn cleanup_fn,
void *policy_cb_data)
{
struct files_ref_store *refs =
files_downcast(ref_store, 0, "reflog_expire");
static struct lock_file reflog_lock;
struct expire_reflog_cb cb;
struct ref_lock *lock;
@ -4003,7 +3984,8 @@ int reflog_expire(const char *refname, const unsigned char *sha1,
* reference itself, plus we might need to update the
* reference if --updateref was specified:
*/
lock = lock_ref_sha1_basic(refname, sha1, NULL, NULL, REF_NODEREF,
lock = lock_ref_sha1_basic(refs, refname, sha1,
NULL, NULL, REF_NODEREF,
&type, &err);
if (!lock) {
error("cannot lock ref '%s': %s", refname, err.buf);
@ -4083,3 +4065,47 @@ int reflog_expire(const char *refname, const unsigned char *sha1,
unlock_ref(lock);
return -1;
}
static int files_init_db(struct ref_store *ref_store, struct strbuf *err)
{
/* Check validity (but we don't need the result): */
files_downcast(ref_store, 0, "init_db");
/*
* Create .git/refs/{heads,tags}
*/
safe_create_dir(git_path("refs/heads"), 1);
safe_create_dir(git_path("refs/tags"), 1);
if (get_shared_repository()) {
adjust_shared_perm(git_path("refs/heads"));
adjust_shared_perm(git_path("refs/tags"));
}
return 0;
}
struct ref_storage_be refs_be_files = {
NULL,
"files",
files_ref_store_create,
files_init_db,
files_transaction_commit,
files_initial_transaction_commit,
files_pack_refs,
files_peel_ref,
files_create_symref,
files_delete_refs,
files_rename_ref,
files_ref_iterator_begin,
files_read_raw_ref,
files_verify_refname_available,
files_reflog_iterator_begin,
files_for_each_reflog_ent,
files_for_each_reflog_ent_reverse,
files_reflog_exists,
files_create_reflog,
files_delete_reflog,
files_reflog_expire
};

@ -162,7 +162,7 @@ struct ref_update {
*/
unsigned int flags;
struct ref_lock *lock;
void *backend_data;
unsigned int type;
char *msg;
@ -240,7 +240,17 @@ const char *find_descendant_ref(const char *dirname,
const struct string_list *extras,
const struct string_list *skip);
int rename_ref_available(const char *oldname, const char *newname);
/*
* Check whether an attempt to rename old_refname to new_refname would
* cause a D/F conflict with any existing reference (other than
* possibly old_refname). If there would be a conflict, emit an error
* message and return false; otherwise, return true.
*
* Note that this function is not safe against all races with other
* processes (though rename_ref() catches some races that might get by
* this check).
*/
int rename_ref_available(const char *old_refname, const char *new_refname);
/* We allow "recursive" symbolic refs. Only within reason, though */
#define SYMREF_MAXDEPTH 5
@ -394,23 +404,6 @@ struct ref_iterator *prefix_ref_iterator_begin(struct ref_iterator *iter0,
const char *prefix,
int trim);
/*
* Iterate over the packed and loose references in the specified
* submodule that are within find_containing_dir(prefix). If prefix is
* NULL or the empty string, iterate over all references in the
* submodule.
*/
struct ref_iterator *files_ref_iterator_begin(const char *submodule,
const char *prefix,
unsigned int flags);
/*
* Iterate over the references in the main ref_store that have a
* reflog. The paths within a directory are iterated over in arbitrary
* order.
*/
struct ref_iterator *files_reflog_iterator_begin(void);
/* Internal implementation of reference iteration: */
/*
@ -475,8 +468,85 @@ int do_for_each_ref_iterator(struct ref_iterator *iter,
each_ref_fn fn, void *cb_data);
/*
* Read the specified reference from the filesystem or packed refs
* file, non-recursively. Set type to describe the reference, and:
* Only include per-worktree refs in a do_for_each_ref*() iteration.
* Normally this will be used with a files ref_store, since that's
* where all reference backends will presumably store their
* per-worktree refs.
*/
#define DO_FOR_EACH_PER_WORKTREE_ONLY 0x02
struct ref_store;
/* refs backends */
/*
* Initialize the ref_store for the specified submodule, or for the
* main repository if submodule == NULL. These functions should call
* base_ref_store_init() to initialize the shared part of the
* ref_store and to record the ref_store for later lookup.
*/
typedef struct ref_store *ref_store_init_fn(const char *submodule);
typedef int ref_init_db_fn(struct ref_store *refs, struct strbuf *err);
typedef int ref_transaction_commit_fn(struct ref_store *refs,
struct ref_transaction *transaction,
struct strbuf *err);
typedef int pack_refs_fn(struct ref_store *ref_store, unsigned int flags);
typedef int peel_ref_fn(struct ref_store *ref_store,
const char *refname, unsigned char *sha1);
typedef int create_symref_fn(struct ref_store *ref_store,
const char *ref_target,
const char *refs_heads_master,
const char *logmsg);
typedef int delete_refs_fn(struct ref_store *ref_store,
struct string_list *refnames, unsigned int flags);
typedef int rename_ref_fn(struct ref_store *ref_store,
const char *oldref, const char *newref,
const char *logmsg);
/*
* Iterate over the references in the specified ref_store that are
* within find_containing_dir(prefix). If prefix is NULL or the empty
* string, iterate over all references in the submodule.
*/
typedef struct ref_iterator *ref_iterator_begin_fn(
struct ref_store *ref_store,
const char *prefix, unsigned int flags);
/* reflog functions */
/*
* Iterate over the references in the specified ref_store that have a
* reflog. The refs are iterated over in arbitrary order.
*/
typedef struct ref_iterator *reflog_iterator_begin_fn(
struct ref_store *ref_store);
typedef int for_each_reflog_ent_fn(struct ref_store *ref_store,
const char *refname,
each_reflog_ent_fn fn,
void *cb_data);
typedef int for_each_reflog_ent_reverse_fn(struct ref_store *ref_store,
const char *refname,
each_reflog_ent_fn fn,
void *cb_data);
typedef int reflog_exists_fn(struct ref_store *ref_store, const char *refname);
typedef int create_reflog_fn(struct ref_store *ref_store, const char *refname,
int force_create, struct strbuf *err);
typedef int delete_reflog_fn(struct ref_store *ref_store, const char *refname);
typedef int reflog_expire_fn(struct ref_store *ref_store,
const char *refname, const unsigned char *sha1,
unsigned int flags,
reflog_expiry_prepare_fn prepare_fn,
reflog_expiry_should_prune_fn should_prune_fn,
reflog_expiry_cleanup_fn cleanup_fn,
void *policy_cb_data);
/*
* Read a reference from the specified reference store, non-recursively.
* Set type to describe the reference, and:
*
* - If refname is the name of a normal reference, fill in sha1
* (leaving referent unchanged).
@ -512,7 +582,111 @@ int do_for_each_ref_iterator(struct ref_iterator *iter,
* - in all other cases, referent will be untouched, and therefore
* refname will still be valid and unchanged.
*/
int read_raw_ref(const char *refname, unsigned char *sha1,
struct strbuf *referent, unsigned int *type);
typedef int read_raw_ref_fn(struct ref_store *ref_store,
const char *refname, unsigned char *sha1,
struct strbuf *referent, unsigned int *type);
typedef int verify_refname_available_fn(struct ref_store *ref_store,
const char *newname,
const struct string_list *extras,
const struct string_list *skip,
struct strbuf *err);
struct ref_storage_be {
struct ref_storage_be *next;
const char *name;
ref_store_init_fn *init;
ref_init_db_fn *init_db;
ref_transaction_commit_fn *transaction_commit;
ref_transaction_commit_fn *initial_transaction_commit;
pack_refs_fn *pack_refs;
peel_ref_fn *peel_ref;
create_symref_fn *create_symref;
delete_refs_fn *delete_refs;
rename_ref_fn *rename_ref;
ref_iterator_begin_fn *iterator_begin;
read_raw_ref_fn *read_raw_ref;
verify_refname_available_fn *verify_refname_available;
reflog_iterator_begin_fn *reflog_iterator_begin;
for_each_reflog_ent_fn *for_each_reflog_ent;
for_each_reflog_ent_reverse_fn *for_each_reflog_ent_reverse;
reflog_exists_fn *reflog_exists;
create_reflog_fn *create_reflog;
delete_reflog_fn *delete_reflog;
reflog_expire_fn *reflog_expire;
};
extern struct ref_storage_be refs_be_files;
/*
* A representation of the reference store for the main repository or
* a submodule. The ref_store instances for submodules are kept in a
* linked list.
*/
struct ref_store {
/* The backend describing this ref_store's storage scheme: */
const struct ref_storage_be *be;
/*
* The name of the submodule represented by this object, or
* the empty string if it represents the main repository's
* reference store:
*/
const char *submodule;
/*
* Submodule reference store instances are stored in a linked
* list using this pointer.
*/
struct ref_store *next;
};
/*
* Fill in the generic part of refs for the specified submodule and
* add it to our collection of reference stores.
*/
void base_ref_store_init(struct ref_store *refs,
const struct ref_storage_be *be,
const char *submodule);
/*
* Create, record, and return a ref_store instance for the specified
* submodule (or the main repository if submodule is NULL).
*
* For backwards compatibility, submodule=="" is treated the same as
* submodule==NULL.
*/
struct ref_store *ref_store_init(const char *submodule);
/*
* Return the ref_store instance for the specified submodule (or the
* main repository if submodule is NULL). If that ref_store hasn't
* been initialized yet, return NULL.
*
* For backwards compatibility, submodule=="" is treated the same as
* submodule==NULL.
*/
struct ref_store *lookup_ref_store(const char *submodule);
/*
* Return the ref_store instance for the specified submodule. For the
* main repository, use submodule==NULL; such a call cannot fail. For
* a submodule, the submodule must exist and be a nonbare repository,
* otherwise return NULL. If the requested reference store has not yet
* been initialized, initialize it first.
*
* For backwards compatibility, submodule=="" is treated the same as
* submodule==NULL.
*/
struct ref_store *get_ref_store(const char *submodule);
/*
* Die if refs is for a submodule (i.e., not for the main repository).
* caller is used in any necessary error messages.
*/
void assert_main_repository(struct ref_store *refs, const char *caller);
#endif /* REFS_REFS_INTERNAL_H */