summaryrefslogtreecommitdiff
path: root/refs/reftable-backend.c
diff options
context:
space:
mode:
Diffstat (limited to 'refs/reftable-backend.c')
-rw-r--r--refs/reftable-backend.c167
1 files changed, 126 insertions, 41 deletions
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index 4319a4eacb..fe74af73af 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -10,9 +10,10 @@
#include "../gettext.h"
#include "../hash.h"
#include "../hex.h"
-#include "../iterator.h"
#include "../ident.h"
+#include "../iterator.h"
#include "../object.h"
+#include "../parse.h"
#include "../path.h"
#include "../refs.h"
#include "../reftable/reftable-basics.h"
@@ -25,8 +26,8 @@
#include "../setup.h"
#include "../strmap.h"
#include "../trace2.h"
+#include "../worktree.h"
#include "../write-or-die.h"
-#include "parse.h"
#include "refs-internal.h"
/*
@@ -172,6 +173,37 @@ static struct reftable_ref_store *reftable_be_downcast(struct ref_store *ref_sto
return refs;
}
+static int backend_for_worktree(struct reftable_backend **out,
+ struct reftable_ref_store *store,
+ const char *worktree_name)
+{
+ struct strbuf worktree_dir = STRBUF_INIT;
+ int ret;
+
+ *out = strmap_get(&store->worktree_backends, worktree_name);
+ if (*out) {
+ ret = 0;
+ goto out;
+ }
+
+ strbuf_addf(&worktree_dir, "%s/worktrees/%s/reftable",
+ store->base.repo->commondir, worktree_name);
+
+ CALLOC_ARRAY(*out, 1);
+ store->err = ret = reftable_backend_init(*out, worktree_dir.buf,
+ &store->write_options);
+ if (ret < 0) {
+ free(*out);
+ goto out;
+ }
+
+ strmap_put(&store->worktree_backends, worktree_name, *out);
+
+out:
+ strbuf_release(&worktree_dir);
+ return ret;
+}
+
/*
* Some refs are global to the repository (refs/heads/{*}), while others are
* local to the worktree (eg. HEAD, refs/bisect/{*}). We solve this by having
@@ -191,19 +223,19 @@ static int backend_for(struct reftable_backend **out,
const char **rewritten_ref,
int reload)
{
- struct reftable_backend *be;
const char *wtname;
int wtname_len;
+ int ret;
if (!refname) {
- be = &store->main_backend;
+ *out = &store->main_backend;
+ ret = 0;
goto out;
}
switch (parse_worktree_ref(refname, &wtname, &wtname_len, rewritten_ref)) {
case REF_WORKTREE_OTHER: {
static struct strbuf wtname_buf = STRBUF_INIT;
- struct strbuf wt_dir = STRBUF_INIT;
/*
* We're using a static buffer here so that we don't need to
@@ -223,20 +255,8 @@ static int backend_for(struct reftable_backend **out,
* already and error out when trying to write a reference via
* both stacks.
*/
- be = strmap_get(&store->worktree_backends, wtname_buf.buf);
- if (!be) {
- strbuf_addf(&wt_dir, "%s/worktrees/%s/reftable",
- store->base.repo->commondir, wtname_buf.buf);
-
- CALLOC_ARRAY(be, 1);
- store->err = reftable_backend_init(be, wt_dir.buf,
- &store->write_options);
- assert(store->err != REFTABLE_API_ERROR);
-
- strmap_put(&store->worktree_backends, wtname_buf.buf, be);
- }
+ ret = backend_for_worktree(out, store, wtname_buf.buf);
- strbuf_release(&wt_dir);
goto out;
}
case REF_WORKTREE_CURRENT:
@@ -245,27 +265,24 @@ static int backend_for(struct reftable_backend **out,
* main worktree. We thus return the main stack in that case.
*/
if (!store->worktree_backend.stack)
- be = &store->main_backend;
+ *out = &store->main_backend;
else
- be = &store->worktree_backend;
+ *out = &store->worktree_backend;
+ ret = 0;
goto out;
case REF_WORKTREE_MAIN:
case REF_WORKTREE_SHARED:
- be = &store->main_backend;
+ *out = &store->main_backend;
+ ret = 0;
goto out;
default:
BUG("unhandled worktree reference type");
}
out:
- if (reload) {
- int ret = reftable_stack_reload(be->stack);
- if (ret)
- return ret;
- }
- *out = be;
-
- return 0;
+ if (reload && !ret)
+ ret = reftable_stack_reload((*out)->stack);
+ return ret;
}
static int should_write_log(struct reftable_ref_store *refs, const char *refname)
@@ -2746,24 +2763,92 @@ static int reftable_fsck_error_handler(struct reftable_fsck_info *info,
}
static int reftable_be_fsck(struct ref_store *ref_store, struct fsck_options *o,
- struct worktree *wt UNUSED)
+ struct worktree *wt)
{
- struct reftable_ref_store *refs;
- struct strmap_entry *entry;
- struct hashmap_iter iter;
- int ret = 0;
+ struct reftable_ref_store *refs =
+ reftable_be_downcast(ref_store, REF_STORE_READ, "fsck");
+ struct reftable_ref_iterator *iter = NULL;
+ struct reftable_ref_record ref = { 0 };
+ struct fsck_ref_report report = { 0 };
+ struct strbuf refname = STRBUF_INIT;
+ struct reftable_backend *backend;
+ int ret, errors = 0;
- refs = reftable_be_downcast(ref_store, REF_STORE_READ, "fsck");
+ if (is_main_worktree(wt)) {
+ backend = &refs->main_backend;
+ } else {
+ ret = backend_for_worktree(&backend, refs, wt->id);
+ if (ret < 0) {
+ ret = error(_("reftable stack for worktree '%s' is broken"),
+ wt->id);
+ goto out;
+ }
+ }
- ret |= reftable_fsck_check(refs->main_backend.stack, reftable_fsck_error_handler,
- reftable_fsck_verbose_handler, o);
+ errors |= reftable_fsck_check(backend->stack, reftable_fsck_error_handler,
+ reftable_fsck_verbose_handler, o);
- strmap_for_each_entry(&refs->worktree_backends, &iter, entry) {
- struct reftable_backend *b = (struct reftable_backend *)entry->value;
- ret |= reftable_fsck_check(b->stack, reftable_fsck_error_handler,
- reftable_fsck_verbose_handler, o);
+ iter = ref_iterator_for_stack(refs, backend->stack, "", NULL, 0);
+ if (!iter) {
+ ret = error(_("could not create iterator for worktree '%s'"), wt->id);
+ goto out;
}
+ while (1) {
+ ret = reftable_iterator_next_ref(&iter->iter, &ref);
+ if (ret > 0)
+ break;
+ if (ret < 0) {
+ ret = error(_("could not read record for worktree '%s'"), wt->id);
+ goto out;
+ }
+
+ strbuf_reset(&refname);
+ if (!is_main_worktree(wt))
+ strbuf_addf(&refname, "worktrees/%s/", wt->id);
+ strbuf_addstr(&refname, ref.refname);
+ report.path = refname.buf;
+
+ switch (ref.value_type) {
+ case REFTABLE_REF_VAL1:
+ case REFTABLE_REF_VAL2: {
+ struct object_id oid;
+ unsigned hash_id;
+
+ switch (reftable_stack_hash_id(backend->stack)) {
+ case REFTABLE_HASH_SHA1:
+ hash_id = GIT_HASH_SHA1;
+ break;
+ case REFTABLE_HASH_SHA256:
+ hash_id = GIT_HASH_SHA256;
+ break;
+ default:
+ BUG("unhandled hash ID %d",
+ reftable_stack_hash_id(backend->stack));
+ }
+
+ oidread(&oid, reftable_ref_record_val1(&ref),
+ &hash_algos[hash_id]);
+
+ errors |= refs_fsck_ref(ref_store, o, &report, ref.refname, &oid);
+ break;
+ }
+ case REFTABLE_REF_SYMREF:
+ errors |= refs_fsck_symref(ref_store, o, &report, ref.refname,
+ ref.value.symref);
+ break;
+ default:
+ BUG("unhandled reference value type %d", ref.value_type);
+ }
+ }
+
+ ret = errors ? -1 : 0;
+
+out:
+ if (iter)
+ ref_iterator_free(&iter->base);
+ reftable_ref_record_release(&ref);
+ strbuf_release(&refname);
return ret;
}