]> git.ipfire.org Git - thirdparty/git.git/commitdiff
refs/reftable: add fsck check for checking the table name
authorKarthik Nayak <karthik.188@gmail.com>
Tue, 7 Oct 2025 12:11:31 +0000 (14:11 +0200)
committerJunio C Hamano <gitster@pobox.com>
Tue, 7 Oct 2025 16:22:58 +0000 (09:22 -0700)
Add glue code in 'refs/reftable-backend.c' which calls the reftable
library to perform the fsck checks. Here we also map the reftable errors
to Git' fsck errors.

Introduce a check to validate table names for a given reftable stack.
Also add 'badReftableTableName' as a corresponding error within Git. The
reftable specification mentions:

  It suggested to use
  ${min_update_index}-${max_update_index}-${random}.ref as a naming
  convention.

So treat non-conformant file names as warnings.

While adding the fsck header to 'refs/reftable-backend.c', modify the
list to maintain lexicographical ordering.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/fsck-msgids.adoc
fsck.h
refs/reftable-backend.c
t/meson.build
t/t0614-reftable-fsck.sh [new file with mode: 0755]

index 1c912615f99dc95826d3b3b837c9cc90e86da9b4..81f11ba125a22acd21bfb08961e4e943fd6452f4 100644 (file)
@@ -38,6 +38,9 @@
 `badReferentName`::
        (ERROR) The referent name of a symref is invalid.
 
+`badReftableTableName`::
+       (WARN) A reftable table has an invalid name.
+
 `badTagName`::
        (INFO) A tag has an invalid format.
 
diff --git a/fsck.h b/fsck.h
index 6b0db235e02bdade7702e8b4c3075abaabd0e035..759df97655605dfac0660ae08d09dc51c3ab2233 100644 (file)
--- a/fsck.h
+++ b/fsck.h
@@ -73,6 +73,7 @@ enum fsck_msg_type {
        FUNC(UNKNOWN_TYPE, ERROR) \
        FUNC(ZERO_PADDED_DATE, ERROR) \
        /* warnings */ \
+       FUNC(BAD_REFTABLE_TABLE_NAME, WARN) \
        FUNC(EMPTY_NAME, WARN) \
        FUNC(FULL_PATHNAME, WARN) \
        FUNC(HAS_DOT, WARN) \
index 67b7bc7958fcb15e87a0021c076be4131d6c92dd..d1c84f9f5ebb197ee9b5a54aa0d09f1c69e46c1b 100644 (file)
@@ -6,6 +6,7 @@
 #include "../config.h"
 #include "../dir.h"
 #include "../environment.h"
+#include "../fsck.h"
 #include "../gettext.h"
 #include "../hash.h"
 #include "../hex.h"
 #include "../path.h"
 #include "../refs.h"
 #include "../reftable/reftable-basics.h"
-#include "../reftable/reftable-stack.h"
-#include "../reftable/reftable-record.h"
 #include "../reftable/reftable-error.h"
+#include "../reftable/reftable-fsck.h"
 #include "../reftable/reftable-iterator.h"
+#include "../reftable/reftable-record.h"
+#include "../reftable/reftable-stack.h"
 #include "../repo-settings.h"
 #include "../setup.h"
 #include "../strmap.h"
@@ -2674,11 +2676,56 @@ done:
        return ret;
 }
 
-static int reftable_be_fsck(struct ref_store *ref_store UNUSED,
-                           struct fsck_options *o UNUSED,
+static void reftable_fsck_verbose_handler(const char *msg, void *cb_data)
+{
+       struct fsck_options *o = cb_data;
+
+       if (o->verbose)
+               fprintf_ln(stderr, "%s", msg);
+}
+
+static const enum fsck_msg_id fsck_msg_id_map[] = {
+       [REFTABLE_FSCK_ERROR_TABLE_NAME] = FSCK_MSG_BAD_REFTABLE_TABLE_NAME,
+};
+
+static int reftable_fsck_error_handler(struct reftable_fsck_info *info,
+                                      void *cb_data)
+{
+       struct fsck_ref_report report = { .path = info->path };
+       struct fsck_options *o = cb_data;
+       enum fsck_msg_id msg_id;
+
+       if (info->error < 0 || info->error >= REFTABLE_FSCK_MAX_VALUE)
+               BUG("unknown fsck error: %d", (int)info->error);
+
+       msg_id = fsck_msg_id_map[info->error];
+
+       if (!msg_id)
+               BUG("fsck_msg_id value missing for reftable error: %d", (int)info->error);
+
+       return fsck_report_ref(o, &report, msg_id, "%s", info->msg);
+}
+
+static int reftable_be_fsck(struct ref_store *ref_store, struct fsck_options *o,
                            struct worktree *wt UNUSED)
 {
-       return 0;
+       struct reftable_ref_store *refs;
+       struct strmap_entry *entry;
+       struct hashmap_iter iter;
+       int ret = 0;
+
+       refs = reftable_be_downcast(ref_store, REF_STORE_READ, "fsck");
+
+       ret |= reftable_fsck_check(refs->main_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);
+       }
+
+       return ret;
 }
 
 struct ref_storage_be refs_be_reftable = {
index bbeba1a8d50e1bb2174e9548656a8f10f5c1fd9d..834e0f1b0a63bb3cb414c2dd310d5423ef685a68 100644 (file)
@@ -145,6 +145,7 @@ integration_tests = [
   't0611-reftable-httpd.sh',
   't0612-reftable-jgit-compatibility.sh',
   't0613-reftable-write-options.sh',
+  't0614-reftable-fsck.sh',
   't1000-read-tree-m-3way.sh',
   't1001-read-tree-m-2way.sh',
   't1002-read-tree-m-u-2way.sh',
diff --git a/t/t0614-reftable-fsck.sh b/t/t0614-reftable-fsck.sh
new file mode 100755 (executable)
index 0000000..85cc47d
--- /dev/null
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+test_description='Test reftable backend consistency check'
+
+GIT_TEST_DEFAULT_REF_FORMAT=reftable
+export GIT_TEST_DEFAULT_REF_FORMAT
+
+. ./test-lib.sh
+
+test_expect_success "no errors reported on a well formed repository" '
+       test_when_finished "rm -rf repo" &&
+       git init repo &&
+       (
+               cd repo &&
+               git commit --allow-empty -m initial &&
+
+               for i in $(test_seq 20)
+               do
+                       git update-ref refs/heads/branch-$i HEAD || return 1
+               done &&
+
+               # The repository should end up with multiple tables.
+               test_line_count ">" 1 .git/reftable/tables.list &&
+
+               git refs verify 2>err &&
+               test_must_be_empty err
+       )
+'
+
+for TABLE_NAME in "foo-bar-e4d12d59.ref" \
+       "0x00000000zzzz-0x00000000zzzz-e4d12d59.ref" \
+       "0x000000000001-0x000000000002-e4d12d59.abc" \
+       "0x000000000001-0x000000000002-e4d12d59.refabc"; do
+       test_expect_success "table name $TABLE_NAME should be checked" '
+               test_when_finished "rm -rf repo" &&
+               git init repo &&
+               (
+                       cd repo &&
+                       git commit --allow-empty -m initial &&
+
+                       git refs verify 2>err &&
+                       test_must_be_empty err &&
+
+                       EXISTING_TABLE=$(head -n1 .git/reftable/tables.list) &&
+                       mv ".git/reftable/$EXISTING_TABLE" ".git/reftable/$TABLE_NAME" &&
+                       sed "s/${EXISTING_TABLE}/${TABLE_NAME}/g" .git/reftable/tables.list > tables.list &&
+                       mv tables.list .git/reftable/tables.list &&
+
+                       git refs verify 2>err &&
+                       cat >expect <<-EOF &&
+                       warning: ${TABLE_NAME}: badReftableTableName: invalid reftable table name
+                       EOF
+                       test_cmp expect err
+               )
+       '
+done
+
+test_done