summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--meson.build1
-rw-r--r--reftable/fsck.c100
-rw-r--r--reftable/reftable-fsck.h40
4 files changed, 143 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index e11340c1ae..0867ab5179 100644
--- a/Makefile
+++ b/Makefile
@@ -2729,9 +2729,10 @@ XDIFF_OBJS += xdiff/xutils.o
xdiff-objs: $(XDIFF_OBJS)
REFTABLE_OBJS += reftable/basics.o
-REFTABLE_OBJS += reftable/error.o
REFTABLE_OBJS += reftable/block.o
REFTABLE_OBJS += reftable/blocksource.o
+REFTABLE_OBJS += reftable/error.o
+REFTABLE_OBJS += reftable/fsck.o
REFTABLE_OBJS += reftable/iter.o
REFTABLE_OBJS += reftable/merged.o
REFTABLE_OBJS += reftable/pq.o
diff --git a/meson.build b/meson.build
index 5dd299b496..82879fbfaa 100644
--- a/meson.build
+++ b/meson.build
@@ -452,6 +452,7 @@ libgit_sources = [
'reftable/error.c',
'reftable/block.c',
'reftable/blocksource.c',
+ 'reftable/fsck.c',
'reftable/iter.c',
'reftable/merged.c',
'reftable/pq.c',
diff --git a/reftable/fsck.c b/reftable/fsck.c
new file mode 100644
index 0000000000..26b9115b14
--- /dev/null
+++ b/reftable/fsck.c
@@ -0,0 +1,100 @@
+#include "basics.h"
+#include "reftable-fsck.h"
+#include "reftable-table.h"
+#include "stack.h"
+
+static bool table_has_valid_name(const char *name)
+{
+ const char *ptr = name;
+ char *endptr;
+
+ /* strtoull doesn't set errno on success */
+ errno = 0;
+
+ strtoull(ptr, &endptr, 16);
+ if (errno)
+ return false;
+ ptr = endptr;
+
+ if (*ptr != '-')
+ return false;
+ ptr++;
+
+ strtoull(ptr, &endptr, 16);
+ if (errno)
+ return false;
+ ptr = endptr;
+
+ if (*ptr != '-')
+ return false;
+ ptr++;
+
+ strtoul(ptr, &endptr, 16);
+ if (errno)
+ return false;
+ ptr = endptr;
+
+ if (strcmp(ptr, ".ref") && strcmp(ptr, ".log"))
+ return false;
+
+ return true;
+}
+
+typedef int (*table_check_fn)(struct reftable_table *table,
+ reftable_fsck_report_fn report_fn,
+ void *cb_data);
+
+static int table_check_name(struct reftable_table *table,
+ reftable_fsck_report_fn report_fn,
+ void *cb_data)
+{
+ if (!table_has_valid_name(table->name)) {
+ struct reftable_fsck_info info;
+
+ info.error = REFTABLE_FSCK_ERROR_TABLE_NAME;
+ info.msg = "invalid reftable table name";
+ info.path = table->name;
+
+ return report_fn(&info, cb_data);
+ }
+
+ return 0;
+}
+
+static int table_checks(struct reftable_table *table,
+ reftable_fsck_report_fn report_fn,
+ reftable_fsck_verbose_fn verbose_fn UNUSED,
+ void *cb_data)
+{
+ table_check_fn table_check_fns[] = {
+ table_check_name,
+ NULL,
+ };
+ int err = 0;
+
+ for (size_t i = 0; table_check_fns[i]; i++)
+ err |= table_check_fns[i](table, report_fn, cb_data);
+
+ return err;
+}
+
+int reftable_fsck_check(struct reftable_stack *stack,
+ reftable_fsck_report_fn report_fn,
+ reftable_fsck_verbose_fn verbose_fn,
+ void *cb_data)
+{
+ struct reftable_buf msg = REFTABLE_BUF_INIT;
+ int err = 0;
+
+ for (size_t i = 0; i < stack->tables_len; i++) {
+ reftable_buf_reset(&msg);
+ reftable_buf_addstr(&msg, "Checking table: ");
+ reftable_buf_addstr(&msg, stack->tables[i]->name);
+ verbose_fn(msg.buf, cb_data);
+
+ err |= table_checks(stack->tables[i], report_fn, verbose_fn, cb_data);
+ }
+
+ reftable_buf_release(&msg);
+ return err;
+}
diff --git a/reftable/reftable-fsck.h b/reftable/reftable-fsck.h
new file mode 100644
index 0000000000..007a392cf9
--- /dev/null
+++ b/reftable/reftable-fsck.h
@@ -0,0 +1,40 @@
+#ifndef REFTABLE_FSCK_H
+#define REFTABLE_FSCK_H
+
+#include "reftable-stack.h"
+
+enum reftable_fsck_error {
+ /* Invalid table name */
+ REFTABLE_FSCK_ERROR_TABLE_NAME = 0,
+ /* Used for bounds checking, must be last */
+ REFTABLE_FSCK_MAX_VALUE,
+};
+
+/* Represents an individual error encountered during the FSCK checks. */
+struct reftable_fsck_info {
+ enum reftable_fsck_error error;
+ const char *msg;
+ const char *path;
+};
+
+typedef int reftable_fsck_report_fn(struct reftable_fsck_info *info,
+ void *cb_data);
+typedef void reftable_fsck_verbose_fn(const char *msg, void *cb_data);
+
+/*
+ * Given a reftable stack, perform consistency checks on the stack.
+ *
+ * If an issue is encountered, the issue is reported to the callee via the
+ * provided 'report_fn'. If the issue is non-recoverable the flow will not
+ * continue. If it is recoverable, the flow will continue and further issues
+ * will be reported as identified.
+ *
+ * The 'verbose_fn' will be invoked to provide verbose information about
+ * the progress and state of the consistency checks.
+ */
+int reftable_fsck_check(struct reftable_stack *stack,
+ reftable_fsck_report_fn report_fn,
+ reftable_fsck_verbose_fn verbose_fn,
+ void *cb_data);
+
+#endif /* REFTABLE_FSCK_H */