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
--- /dev/null
+#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;
+}
--- /dev/null
+#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 */