Introduce a fsck check for the reftable backend, which checks if the 'tables.list' contains a newline. The reftable backend writes a trailing newline when writing the 'tables.list', but it doesn't check for it when reading the file. A missing newline however indicates that the file was manually tampered with, so let's raise this as an error to the user. Signed-off-by: Karthik Nayak <karthik.188@xxxxxxxxx> --- Documentation/fsck-msgids.adoc | 3 +++ fsck.h | 1 + refs/reftable-backend.c | 3 +++ reftable/fsck.c | 36 ++++++++++++++++++++++++++++++++++++ reftable/reftable-fsck.h | 2 ++ t/t0614-reftable-fsck.sh | 21 +++++++++++++++++++++ 6 files changed, 66 insertions(+) diff --git a/Documentation/fsck-msgids.adoc b/Documentation/fsck-msgids.adoc index 707e2fc50a..1432b1de06 100644 --- a/Documentation/fsck-msgids.adoc +++ b/Documentation/fsck-msgids.adoc @@ -41,6 +41,9 @@ `badReftableStackCount`:: (ERROR) Mismatch in number of tables. +`badReftableStackListNewline`:: + (ERROR) Reftable stack list missing trailing newline. + `badReftableTableName`:: (ERROR) A reftable table has an invalid name. diff --git a/fsck.h b/fsck.h index 256effc4f8..33432bae79 100644 --- a/fsck.h +++ b/fsck.h @@ -35,6 +35,7 @@ enum fsck_msg_type { FUNC(BAD_PARENT_SHA1, ERROR) \ FUNC(BAD_REFERENT_NAME, ERROR) \ FUNC(BAD_REFTABLE_STACK_COUNT, ERROR) \ + FUNC(BAD_REFTABLE_STACK_LIST_NEWLINE, ERROR) \ FUNC(BAD_REFTABLE_TABLE_NAME, ERROR) \ FUNC(BAD_REF_CONTENT, ERROR) \ FUNC(BAD_REF_FILETYPE, ERROR) \ diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c index 616f4ee0f3..0087afa3ac 100644 --- a/refs/reftable-backend.c +++ b/refs/reftable-backend.c @@ -2698,6 +2698,9 @@ static int reftable_fsck_error_handler(struct reftable_fsck_info info, case REFTABLE_FSCK_ERROR_STACK_COUNT: msg_id = FSCK_MSG_BAD_REFTABLE_STACK_COUNT; break; + case REFTABLE_FSCK_ERROR_STACK_LIST_MISSING_NEWLINE: + msg_id = FSCK_MSG_BAD_REFTABLE_STACK_LIST_NEWLINE; + break; default: BUG("unknown fsck error: %d", info.error); } diff --git a/reftable/fsck.c b/reftable/fsck.c index e92a630276..b4898fd2cd 100644 --- a/reftable/fsck.c +++ b/reftable/fsck.c @@ -1,7 +1,31 @@ #include "basics.h" +#include "reftable-error.h" #include "reftable-fsck.h" #include "stack.h" +static int reftable_fsck_stack_contains_newline(const char *list_file) +{ + FILE *f = fopen(list_file, "r"); + int c = 0; + + if (f == NULL) { + if (errno == ENOENT) + return 0; + return REFTABLE_IO_ERROR; + } + + if (fseek(f, 0, SEEK_END) == 0) { + long size = ftell(f); + if (size <= 0) + return REFTABLE_IO_ERROR; + fseek(f, -1, SEEK_END); + c = fgetc(f); + } + fclose(f); + + return c == '\n'; +} + static int reftable_fsck_valid_stack_count(struct reftable_stack *st) { DIR *dir = opendir(st->reftable_dir); @@ -66,6 +90,18 @@ int reftable_fsck_check(struct reftable_stack *stack, } } + verbose_fn("Checking trailing newline in stack list", cb_data); + + if (!reftable_fsck_stack_contains_newline(stack->list_file)) { + struct reftable_fsck_info info = { + .error = REFTABLE_FSCK_ERROR_STACK_LIST_MISSING_NEWLINE, + .path = stack->list_file, + .msg = "trailing newline missing in stack list" + }; + + err = report_fn(info, cb_data); + } + verbose_fn("Checking reftable tables count", cb_data); if (!reftable_fsck_valid_stack_count(stack)) { diff --git a/reftable/reftable-fsck.h b/reftable/reftable-fsck.h index 888c3968b7..8e6cb6c7d2 100644 --- a/reftable/reftable-fsck.h +++ b/reftable/reftable-fsck.h @@ -8,6 +8,8 @@ enum reftable_fsck_error { REFTABLE_FSCK_ERROR_TABLE_NAME = -1, /* Incorrect number of tables present */ REFTABLE_FSCK_ERROR_STACK_COUNT = -2, + /* Newline missing at the end of the stack list */ + REFTABLE_FSCK_ERROR_STACK_LIST_MISSING_NEWLINE = -3, }; /* Represents an individual error encounctered during the FSCK checks. */ diff --git a/t/t0614-reftable-fsck.sh b/t/t0614-reftable-fsck.sh index a351fed562..937c5dd37a 100755 --- a/t/t0614-reftable-fsck.sh +++ b/t/t0614-reftable-fsck.sh @@ -52,4 +52,25 @@ test_expect_success 'table count should be checked' ' ) ' +test_expect_success 'stack list must contain trailing newline' ' + 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 && + + printf "%s" "$(cat .git/reftable/tables.list)" >.git/reftable/tables.list.tmp && + mv .git/reftable/tables.list.tmp .git/reftable/tables.list && + + test_must_fail git refs verify 2>err && + cat >expect <<-EOF && + error: $(pwd)/.git/reftable/tables.list: badReftableStackListNewline: trailing newline missing in stack list + EOF + test_cmp expect err + ) +' + test_done -- 2.50.1