aboutsummaryrefslogtreecommitdiffstats
path: root/refs/files-backend.c
diff options
context:
space:
mode:
Diffstat (limited to 'refs/files-backend.c')
-rw-r--r--refs/files-backend.c410
1 files changed, 270 insertions, 140 deletions
diff --git a/refs/files-backend.c b/refs/files-backend.c
index a098d14ea0..11551de8f8 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "../git-compat-util.h"
#include "../copy.h"
#include "../environment.h"
@@ -89,9 +91,9 @@ static void clear_loose_ref_cache(struct files_ref_store *refs)
* Create a new submodule ref cache and add it to the internal
* set of caches.
*/
-static struct ref_store *files_ref_store_create(struct repository *repo,
- const char *gitdir,
- unsigned int flags)
+static struct ref_store *files_ref_store_init(struct repository *repo,
+ const char *gitdir,
+ unsigned int flags)
{
struct files_ref_store *refs = xcalloc(1, sizeof(*refs));
struct ref_store *ref_store = (struct ref_store *)refs;
@@ -102,7 +104,7 @@ static struct ref_store *files_ref_store_create(struct repository *repo,
get_common_dir_noenv(&sb, gitdir);
refs->gitcommondir = strbuf_detach(&sb, NULL);
refs->packed_ref_store =
- packed_ref_store_create(repo, refs->gitcommondir, flags);
+ packed_ref_store_init(repo, refs->gitcommondir, flags);
chdir_notify_reparent("files-backend $GIT_DIR", &refs->base.gitdir);
chdir_notify_reparent("files-backend $GIT_COMMONDIR",
@@ -149,6 +151,15 @@ static struct files_ref_store *files_downcast(struct ref_store *ref_store,
return refs;
}
+static void files_ref_store_release(struct ref_store *ref_store)
+{
+ struct files_ref_store *refs = files_downcast(ref_store, 0, "release");
+ free_ref_cache(refs->loose);
+ free(refs->gitcommondir);
+ ref_store_release(refs->packed_ref_store);
+ free(refs->packed_ref_store);
+}
+
static void files_reflog_path(struct files_ref_store *refs,
struct strbuf *sb,
const char *refname)
@@ -238,7 +249,7 @@ static void loose_fill_ref_dir_regular_file(struct files_ref_store *refs,
if (!refs_resolve_ref_unsafe(&refs->base, refname, RESOLVE_REF_READING,
&oid, &flag)) {
- oidclr(&oid);
+ oidclr(&oid, the_repository->hash_algo);
flag |= REF_ISBROKEN;
} else if (is_null_oid(&oid)) {
/*
@@ -255,7 +266,7 @@ static void loose_fill_ref_dir_regular_file(struct files_ref_store *refs,
if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
if (!refname_is_safe(refname))
die("loose refname is dangerous: %s", refname);
- oidclr(&oid);
+ oidclr(&oid, the_repository->hash_algo);
flag |= REF_BAD_NAME | REF_ISBROKEN;
}
add_entry_to_dir(dir, create_ref_entry(refname, &oid, flag));
@@ -315,19 +326,15 @@ static void loose_fill_ref_dir(struct ref_store *ref_store,
add_per_worktree_entries_to_dir(dir, dirname);
}
-/*
- * Add pseudorefs to the ref dir by parsing the directory for any files
- * which follow the pseudoref syntax.
- */
-static void add_pseudoref_and_head_entries(struct ref_store *ref_store,
- struct ref_dir *dir,
- const char *dirname)
+static int for_each_root_ref(struct files_ref_store *refs,
+ int (*cb)(const char *refname, void *cb_data),
+ void *cb_data)
{
- struct files_ref_store *refs =
- files_downcast(ref_store, REF_STORE_READ, "fill_ref_dir");
struct strbuf path = STRBUF_INIT, refname = STRBUF_INIT;
+ const char *dirname = refs->loose->root->name;
struct dirent *de;
size_t dirnamelen;
+ int ret;
DIR *d;
files_ref_path(refs, &path, dirname);
@@ -335,7 +342,7 @@ static void add_pseudoref_and_head_entries(struct ref_store *ref_store,
d = opendir(path.buf);
if (!d) {
strbuf_release(&path);
- return;
+ return -1;
}
strbuf_addstr(&refname, dirname);
@@ -351,15 +358,49 @@ static void add_pseudoref_and_head_entries(struct ref_store *ref_store,
strbuf_addstr(&refname, de->d_name);
dtype = get_dtype(de, &path, 1);
- if (dtype == DT_REG && (is_pseudoref(ref_store, de->d_name) ||
- is_headref(ref_store, de->d_name)))
- loose_fill_ref_dir_regular_file(refs, refname.buf, dir);
+ if (dtype == DT_REG && is_root_ref(de->d_name)) {
+ ret = cb(refname.buf, cb_data);
+ if (ret)
+ goto done;
+ }
strbuf_setlen(&refname, dirnamelen);
}
+
+ ret = 0;
+
+done:
strbuf_release(&refname);
strbuf_release(&path);
closedir(d);
+ return ret;
+}
+
+struct fill_root_ref_data {
+ struct files_ref_store *refs;
+ struct ref_dir *dir;
+};
+
+static int fill_root_ref(const char *refname, void *cb_data)
+{
+ struct fill_root_ref_data *data = cb_data;
+ loose_fill_ref_dir_regular_file(data->refs, refname, data->dir);
+ return 0;
+}
+
+/*
+ * Add root refs to the ref dir by parsing the directory for any files which
+ * follow the root ref syntax.
+ */
+static void add_root_refs(struct files_ref_store *refs,
+ struct ref_dir *dir)
+{
+ struct fill_root_ref_data data = {
+ .refs = refs,
+ .dir = dir,
+ };
+
+ for_each_root_ref(refs, fill_root_ref, &data);
}
static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs,
@@ -381,8 +422,7 @@ static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs,
dir = get_ref_dir(refs->loose->root);
if (flags & DO_FOR_EACH_INCLUDE_ROOT_REFS)
- add_pseudoref_and_head_entries(dir->cache->ref_store, dir,
- refs->loose->root->name);
+ add_root_refs(refs, dir);
/*
* Add an incomplete entry for "refs/" (to be filled
@@ -794,8 +834,10 @@ retry:
*/
if (refs_verify_refname_available(
refs->packed_ref_store, refname,
- extras, NULL, err))
+ extras, NULL, err)) {
+ ret = TRANSACTION_NAME_CONFLICT;
goto error_return;
+ }
}
ret = 0;
@@ -1111,7 +1153,7 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs,
if (!refs_resolve_ref_unsafe(&refs->base, lock->ref_name, 0,
&lock->old_oid, NULL))
- oidclr(&lock->old_oid);
+ oidclr(&lock->old_oid, the_repository->hash_algo);
goto out;
error_return:
@@ -1198,7 +1240,7 @@ static void prune_ref(struct files_ref_store *refs, struct ref_to_prune *r)
ref_transaction_add_update(
transaction, r->name,
REF_NO_DEREF | REF_HAVE_NEW | REF_HAVE_OLD | REF_IS_PRUNING,
- null_oid(), &r->oid, NULL);
+ null_oid(), &r->oid, NULL, NULL, NULL);
if (ref_transaction_commit(transaction, &err))
goto cleanup;
@@ -1229,7 +1271,8 @@ static void prune_refs(struct files_ref_store *refs, struct ref_to_prune **refs_
/*
* Return true if the specified reference should be packed.
*/
-static int should_pack_ref(const char *refname,
+static int should_pack_ref(struct files_ref_store *refs,
+ const char *refname,
const struct object_id *oid, unsigned int ref_flags,
struct pack_refs_opts *opts)
{
@@ -1245,7 +1288,7 @@ static int should_pack_ref(const char *refname,
return 0;
/* Do not pack broken refs: */
- if (!ref_resolves_to_object(refname, the_repository, oid, ref_flags))
+ if (!ref_resolves_to_object(refname, refs->base.repo, oid, ref_flags))
return 0;
if (ref_excluded(opts->exclusions, refname))
@@ -1277,14 +1320,14 @@ static int files_pack_refs(struct ref_store *ref_store,
packed_refs_lock(refs->packed_ref_store, LOCK_DIE_ON_ERROR, &err);
iter = cache_ref_iterator_begin(get_loose_ref_cache(refs, 0), NULL,
- the_repository, 0);
+ refs->base.repo, 0);
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
/*
* If the loose reference can be packed, add an entry
* in the packed ref cache. If the reference should be
* pruned, also add it to refs_to_prune.
*/
- if (!should_pack_ref(iter->refname, iter->oid, iter->flags, opts))
+ if (!should_pack_ref(refs, iter->refname, iter->oid, iter->flags, opts))
continue;
/*
@@ -1292,7 +1335,7 @@ static int files_pack_refs(struct ref_store *ref_store,
* packed-refs transaction:
*/
if (ref_transaction_update(transaction, iter->refname,
- iter->oid, NULL,
+ iter->oid, NULL, NULL, NULL,
REF_NO_DEREF, NULL, &err))
die("failure preparing to create packed reference %s: %s",
iter->refname, err.buf);
@@ -1381,7 +1424,8 @@ static int rename_tmp_log(struct files_ref_store *refs, const char *newrefname)
return ret;
}
-static int write_ref_to_lockfile(struct ref_lock *lock,
+static int write_ref_to_lockfile(struct files_ref_store *refs,
+ struct ref_lock *lock,
const struct object_id *oid,
int skip_oid_verification, struct strbuf *err);
static int commit_ref_update(struct files_ref_store *refs,
@@ -1529,7 +1573,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
}
oidcpy(&lock->old_oid, &orig_oid);
- if (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||
+ if (write_ref_to_lockfile(refs, lock, &orig_oid, 0, &err) ||
commit_ref_update(refs, lock, &orig_oid, logmsg, &err)) {
error("unable to write current sha1 into %s: %s", newrefname, err.buf);
strbuf_release(&err);
@@ -1549,7 +1593,7 @@ static int files_copy_or_rename_ref(struct ref_store *ref_store,
flag = log_all_ref_updates;
log_all_ref_updates = LOG_REFS_NONE;
- if (write_ref_to_lockfile(lock, &orig_oid, 0, &err) ||
+ if (write_ref_to_lockfile(refs, lock, &orig_oid, 0, &err) ||
commit_ref_update(refs, lock, &orig_oid, NULL, &err)) {
error("unable to write current sha1 into %s: %s", oldrefname, err.buf);
strbuf_release(&err);
@@ -1741,6 +1785,9 @@ static int files_log_ref_write(struct files_ref_store *refs,
{
int logfd, result;
+ if (flags & REF_SKIP_CREATE_REFLOG)
+ return 0;
+
if (log_all_ref_updates == LOG_REFS_UNSET)
log_all_ref_updates = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
@@ -1783,7 +1830,8 @@ static int files_log_ref_write(struct files_ref_store *refs,
* Write oid into the open lockfile, then close the lockfile. On
* errors, rollback the lockfile, fill in *err and return -1.
*/
-static int write_ref_to_lockfile(struct ref_lock *lock,
+static int write_ref_to_lockfile(struct files_ref_store *refs,
+ struct ref_lock *lock,
const struct object_id *oid,
int skip_oid_verification, struct strbuf *err)
{
@@ -1792,7 +1840,7 @@ static int write_ref_to_lockfile(struct ref_lock *lock,
int fd;
if (!skip_oid_verification) {
- o = parse_object(the_repository, oid);
+ o = parse_object(refs->base.repo, oid);
if (!o) {
strbuf_addf(
err,
@@ -1811,7 +1859,7 @@ static int write_ref_to_lockfile(struct ref_lock *lock,
}
}
fd = get_lock_file_fd(&lock->lk);
- if (write_in_full(fd, oid_to_hex(oid), the_hash_algo->hexsz) < 0 ||
+ if (write_in_full(fd, oid_to_hex(oid), refs->base.repo->hash_algo->hexsz) < 0 ||
write_in_full(fd, &term, 1) < 0 ||
fsync_component(FSYNC_COMPONENT_REFERENCE, get_lock_file_fd(&lock->lk)) < 0 ||
close_ref_gently(lock) < 0) {
@@ -1903,66 +1951,23 @@ static int create_ref_symlink(struct ref_lock *lock, const char *target)
return ret;
}
-static void update_symref_reflog(struct files_ref_store *refs,
- struct ref_lock *lock, const char *refname,
- const char *target, const char *logmsg)
-{
- struct strbuf err = STRBUF_INIT;
- struct object_id new_oid;
-
- if (logmsg &&
- refs_resolve_ref_unsafe(&refs->base, target,
- RESOLVE_REF_READING, &new_oid, NULL) &&
- files_log_ref_write(refs, refname, &lock->old_oid,
- &new_oid, logmsg, 0, &err)) {
- error("%s", err.buf);
- strbuf_release(&err);
- }
-}
-
-static int create_symref_locked(struct files_ref_store *refs,
- struct ref_lock *lock, const char *refname,
- const char *target, const char *logmsg)
+static int create_symref_lock(struct files_ref_store *refs,
+ struct ref_lock *lock, const char *refname,
+ const char *target, struct strbuf *err)
{
- if (prefer_symlink_refs && !create_ref_symlink(lock, target)) {
- update_symref_reflog(refs, lock, refname, target, logmsg);
- return 0;
+ if (!fdopen_lock_file(&lock->lk, "w")) {
+ strbuf_addf(err, "unable to fdopen %s: %s",
+ get_lock_file_path(&lock->lk), strerror(errno));
+ return -1;
}
- if (!fdopen_lock_file(&lock->lk, "w"))
- return error("unable to fdopen %s: %s",
+ if (fprintf(get_lock_file_fp(&lock->lk), "ref: %s\n", target) < 0) {
+ strbuf_addf(err, "unable to write to %s: %s",
get_lock_file_path(&lock->lk), strerror(errno));
-
- update_symref_reflog(refs, lock, refname, target, logmsg);
-
- /* no error check; commit_ref will check ferror */
- fprintf(get_lock_file_fp(&lock->lk), "ref: %s\n", target);
- if (commit_ref(lock) < 0)
- return error("unable to write symref for %s: %s", refname,
- strerror(errno));
- return 0;
-}
-
-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, REF_STORE_WRITE, "create_symref");
- struct strbuf err = STRBUF_INIT;
- struct ref_lock *lock;
- int ret;
-
- lock = lock_ref_oid_basic(refs, refname, &err);
- if (!lock) {
- error("%s", err.buf);
- strbuf_release(&err);
return -1;
}
- ret = create_symref_locked(refs, lock, refname, target, logmsg);
- unlock_ref(lock);
- return ret;
+ return 0;
}
static int files_reflog_exists(struct ref_store *ref_store,
@@ -2284,6 +2289,7 @@ static int split_head_update(struct ref_update *update,
struct ref_update *new_update;
if ((update->flags & REF_LOG_ONLY) ||
+ (update->flags & REF_SKIP_CREATE_REFLOG) ||
(update->flags & REF_IS_PRUNING) ||
(update->flags & REF_UPDATE_VIA_HEAD))
return 0;
@@ -2309,7 +2315,7 @@ static int split_head_update(struct ref_update *update,
transaction, "HEAD",
update->flags | REF_LOG_ONLY | REF_NO_DEREF,
&update->new_oid, &update->old_oid,
- update->msg);
+ NULL, NULL, update->msg);
/*
* Add "HEAD". This insertion is O(N) in the transaction
@@ -2371,8 +2377,9 @@ static int split_symref_update(struct ref_update *update,
new_update = ref_transaction_add_update(
transaction, referent, new_flags,
- &update->new_oid, &update->old_oid,
- update->msg);
+ update->new_target ? NULL : &update->new_oid,
+ update->old_target ? NULL : &update->old_oid,
+ update->new_target, update->old_target, update->msg);
new_update->parent_update = update;
@@ -2401,17 +2408,6 @@ static int split_symref_update(struct ref_update *update,
}
/*
- * Return the refname under which update was originally requested.
- */
-static const char *original_update_refname(struct ref_update *update)
-{
- while (update->parent_update)
- update = update->parent_update;
-
- return update->refname;
-}
-
-/*
* Check whether the REF_HAVE_OLD and old_oid values stored in update
* are consistent with oid, which is the reference's current value. If
* everything is OK, return 0; otherwise, write an error message to
@@ -2427,16 +2423,16 @@ static int check_old_oid(struct ref_update *update, struct object_id *oid,
if (is_null_oid(&update->old_oid))
strbuf_addf(err, "cannot lock ref '%s': "
"reference already exists",
- original_update_refname(update));
+ ref_update_original_update_refname(update));
else if (is_null_oid(oid))
strbuf_addf(err, "cannot lock ref '%s': "
"reference is missing but expected %s",
- original_update_refname(update),
+ ref_update_original_update_refname(update),
oid_to_hex(&update->old_oid));
else
strbuf_addf(err, "cannot lock ref '%s': "
"is at %s but expected %s",
- original_update_refname(update),
+ ref_update_original_update_refname(update),
oid_to_hex(oid),
oid_to_hex(&update->old_oid));
@@ -2464,14 +2460,13 @@ static int lock_ref_for_update(struct files_ref_store *refs,
struct strbuf *err)
{
struct strbuf referent = STRBUF_INIT;
- int mustexist = (update->flags & REF_HAVE_OLD) &&
- !is_null_oid(&update->old_oid);
+ int mustexist = ref_update_expects_existing_old_ref(update);
int ret = 0;
struct ref_lock *lock;
files_assert_main_repository(refs, "lock_ref_for_update");
- if ((update->flags & REF_HAVE_NEW) && is_null_oid(&update->new_oid))
+ if ((update->flags & REF_HAVE_NEW) && ref_update_has_null_new_value(update))
update->flags |= REF_DELETING;
if (head_ref) {
@@ -2490,7 +2485,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
reason = strbuf_detach(err, NULL);
strbuf_addf(err, "cannot lock ref '%s': %s",
- original_update_refname(update), reason);
+ ref_update_original_update_refname(update), reason);
free(reason);
goto out;
}
@@ -2510,11 +2505,18 @@ static int lock_ref_for_update(struct files_ref_store *refs,
if (update->flags & REF_HAVE_OLD) {
strbuf_addf(err, "cannot lock ref '%s': "
"error reading reference",
- original_update_refname(update));
+ ref_update_original_update_refname(update));
+ ret = TRANSACTION_GENERIC_ERROR;
+ goto out;
+ }
+ }
+
+ if (update->old_target) {
+ if (ref_update_check_old_target(referent.buf, update, err)) {
ret = TRANSACTION_GENERIC_ERROR;
goto out;
}
- } else if (check_old_oid(update, &lock->old_oid, err)) {
+ } else if (check_old_oid(update, &lock->old_oid, err)) {
ret = TRANSACTION_GENERIC_ERROR;
goto out;
}
@@ -2535,7 +2537,19 @@ static int lock_ref_for_update(struct files_ref_store *refs,
} else {
struct ref_update *parent_update;
- if (check_old_oid(update, &lock->old_oid, err)) {
+ /*
+ * Even if the ref is a regular ref, if `old_target` is set, we
+ * fail with an error.
+ */
+ if (update->old_target) {
+ strbuf_addf(err, _("cannot lock ref '%s': "
+ "expected symref with target '%s': "
+ "but is a regular ref"),
+ ref_update_original_update_refname(update),
+ update->old_target);
+ ret = TRANSACTION_GENERIC_ERROR;
+ goto out;
+ } else if (check_old_oid(update, &lock->old_oid, err)) {
ret = TRANSACTION_GENERIC_ERROR;
goto out;
}
@@ -2553,9 +2567,28 @@ static int lock_ref_for_update(struct files_ref_store *refs,
}
}
- if ((update->flags & REF_HAVE_NEW) &&
- !(update->flags & REF_DELETING) &&
- !(update->flags & REF_LOG_ONLY)) {
+ if (update->new_target && !(update->flags & REF_LOG_ONLY)) {
+ if (create_symref_lock(refs, lock, update->refname,
+ update->new_target, err)) {
+ ret = TRANSACTION_GENERIC_ERROR;
+ goto out;
+ }
+
+ if (close_ref_gently(lock)) {
+ strbuf_addf(err, "couldn't close '%s.lock'",
+ update->refname);
+ ret = TRANSACTION_GENERIC_ERROR;
+ goto out;
+ }
+
+ /*
+ * Once we have created the symref lock, the commit
+ * phase of the transaction only needs to commit the lock.
+ */
+ update->flags |= REF_NEEDS_COMMIT;
+ } else if ((update->flags & REF_HAVE_NEW) &&
+ !(update->flags & REF_DELETING) &&
+ !(update->flags & REF_LOG_ONLY)) {
if (!(update->type & REF_ISSYMREF) &&
oideq(&lock->old_oid, &update->new_oid)) {
/*
@@ -2563,7 +2596,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
* value, so we don't need to write it.
*/
} else if (write_ref_to_lockfile(
- lock, &update->new_oid,
+ refs, lock, &update->new_oid,
update->flags & REF_SKIP_OID_VERIFICATION,
err)) {
char *write_err = strbuf_detach(err, NULL);
@@ -2763,7 +2796,7 @@ static int files_transaction_prepare(struct ref_store *ref_store,
packed_transaction, update->refname,
REF_HAVE_NEW | REF_NO_DEREF,
&update->new_oid, NULL,
- NULL);
+ NULL, NULL, NULL);
}
}
@@ -2818,6 +2851,43 @@ cleanup:
return ret;
}
+static int parse_and_write_reflog(struct files_ref_store *refs,
+ struct ref_update *update,
+ struct ref_lock *lock,
+ struct strbuf *err)
+{
+ if (update->new_target) {
+ /*
+ * We want to get the resolved OID for the target, to ensure
+ * that the correct value is added to the reflog.
+ */
+ if (!refs_resolve_ref_unsafe(&refs->base, update->new_target,
+ RESOLVE_REF_READING,
+ &update->new_oid, NULL)) {
+ /*
+ * TODO: currently we skip creating reflogs for dangling
+ * symref updates. It would be nice to capture this as
+ * zero oid updates however.
+ */
+ return 0;
+ }
+ }
+
+ if (files_log_ref_write(refs, lock->ref_name, &lock->old_oid,
+ &update->new_oid, update->msg, update->flags, err)) {
+ char *old_msg = strbuf_detach(err, NULL);
+
+ strbuf_addf(err, "cannot update the ref '%s': %s",
+ lock->ref_name, old_msg);
+ free(old_msg);
+ unlock_ref(lock);
+ update->backend_data = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
static int files_transaction_finish(struct ref_store *ref_store,
struct ref_transaction *transaction,
struct strbuf *err)
@@ -2848,23 +2918,20 @@ static int files_transaction_finish(struct ref_store *ref_store,
if (update->flags & REF_NEEDS_COMMIT ||
update->flags & REF_LOG_ONLY) {
- if (files_log_ref_write(refs,
- lock->ref_name,
- &lock->old_oid,
- &update->new_oid,
- update->msg, update->flags,
- err)) {
- char *old_msg = strbuf_detach(err, NULL);
-
- strbuf_addf(err, "cannot update the ref '%s': %s",
- lock->ref_name, old_msg);
- free(old_msg);
- unlock_ref(lock);
- update->backend_data = NULL;
+ if (parse_and_write_reflog(refs, update, lock, err)) {
ret = TRANSACTION_GENERIC_ERROR;
goto cleanup;
}
}
+
+ /*
+ * We try creating a symlink, if that succeeds we continue to the
+ * next update. If not, we try and create a regular symref.
+ */
+ if (update->new_target && prefer_symlink_refs)
+ if (!create_ref_symlink(lock, update->new_target))
+ continue;
+
if (update->flags & REF_NEEDS_COMMIT) {
clear_loose_ref_cache(refs);
if (commit_ref(lock)) {
@@ -3048,7 +3115,7 @@ static int files_initial_transaction_commit(struct ref_store *ref_store,
ref_transaction_add_update(packed_transaction, update->refname,
update->flags & ~REF_HAVE_OLD,
&update->new_oid, &update->old_oid,
- NULL);
+ NULL, NULL, NULL);
}
if (packed_refs_lock(refs->packed_ref_store, 0, err)) {
@@ -3212,7 +3279,7 @@ static int files_reflog_expire(struct ref_store *ref_store,
rollback_lock_file(&reflog_lock);
} else if (update &&
(write_in_full(get_lock_file_fd(&lock->lk),
- oid_to_hex(&cb.last_kept_oid), the_hash_algo->hexsz) < 0 ||
+ oid_to_hex(&cb.last_kept_oid), refs->base.repo->hash_algo->hexsz) < 0 ||
write_str_in_full(get_lock_file_fd(&lock->lk), "\n") < 0 ||
close_ref_gently(lock) < 0)) {
status |= error("couldn't write %s",
@@ -3236,12 +3303,12 @@ static int files_reflog_expire(struct ref_store *ref_store,
return -1;
}
-static int files_init_db(struct ref_store *ref_store,
- int flags,
- struct strbuf *err UNUSED)
+static int files_ref_store_create_on_disk(struct ref_store *ref_store,
+ int flags,
+ struct strbuf *err UNUSED)
{
struct files_ref_store *refs =
- files_downcast(ref_store, REF_STORE_WRITE, "init_db");
+ files_downcast(ref_store, REF_STORE_WRITE, "create");
struct strbuf sb = STRBUF_INIT;
/*
@@ -3264,7 +3331,7 @@ static int files_init_db(struct ref_store *ref_store,
* There is no need to create directories for common refs when creating
* a worktree ref store.
*/
- if (!(flags & REFS_INIT_DB_IS_WORKTREE)) {
+ if (!(flags & REF_STORE_CREATE_ON_DISK_IS_WORKTREE)) {
/*
* Create .git/refs/{heads,tags}
*/
@@ -3281,17 +3348,80 @@ static int files_init_db(struct ref_store *ref_store,
return 0;
}
+struct remove_one_root_ref_data {
+ const char *gitdir;
+ struct strbuf *err;
+};
+
+static int remove_one_root_ref(const char *refname,
+ void *cb_data)
+{
+ struct remove_one_root_ref_data *data = cb_data;
+ struct strbuf buf = STRBUF_INIT;
+ int ret = 0;
+
+ strbuf_addf(&buf, "%s/%s", data->gitdir, refname);
+
+ ret = unlink(buf.buf);
+ if (ret < 0)
+ strbuf_addf(data->err, "could not delete %s: %s\n",
+ refname, strerror(errno));
+
+ strbuf_release(&buf);
+ return ret;
+}
+
+static int files_ref_store_remove_on_disk(struct ref_store *ref_store,
+ struct strbuf *err)
+{
+ struct files_ref_store *refs =
+ files_downcast(ref_store, REF_STORE_WRITE, "remove");
+ struct remove_one_root_ref_data data = {
+ .gitdir = refs->base.gitdir,
+ .err = err,
+ };
+ struct strbuf sb = STRBUF_INIT;
+ int ret = 0;
+
+ strbuf_addf(&sb, "%s/refs", refs->base.gitdir);
+ if (remove_dir_recursively(&sb, 0) < 0) {
+ strbuf_addf(err, "could not delete refs: %s",
+ strerror(errno));
+ ret = -1;
+ }
+ strbuf_reset(&sb);
+
+ strbuf_addf(&sb, "%s/logs", refs->base.gitdir);
+ if (remove_dir_recursively(&sb, 0) < 0) {
+ strbuf_addf(err, "could not delete logs: %s",
+ strerror(errno));
+ ret = -1;
+ }
+ strbuf_reset(&sb);
+
+ if (for_each_root_ref(refs, remove_one_root_ref, &data) < 0)
+ ret = -1;
+
+ if (ref_store_remove_on_disk(refs->packed_ref_store, err) < 0)
+ ret = -1;
+
+ strbuf_release(&sb);
+ return ret;
+}
+
struct ref_storage_be refs_be_files = {
.name = "files",
- .init = files_ref_store_create,
- .init_db = files_init_db,
+ .init = files_ref_store_init,
+ .release = files_ref_store_release,
+ .create_on_disk = files_ref_store_create_on_disk,
+ .remove_on_disk = files_ref_store_remove_on_disk,
+
.transaction_prepare = files_transaction_prepare,
.transaction_finish = files_transaction_finish,
.transaction_abort = files_transaction_abort,
.initial_transaction_commit = files_initial_transaction_commit,
.pack_refs = files_pack_refs,
- .create_symref = files_create_symref,
.rename_ref = files_rename_ref,
.copy_ref = files_copy_ref,