files-backend: add unified interface for refs scanning

For refs and reflogs, we need to scan its corresponding directories to check every regular file or symbolic link which shares the same pattern. Introduce a unified interface for scanning directories for files-backend. Mentored-by: Patrick Steinhardt <ps@pks.im> Mentored-by: Karthik Nayak <karthik.188@gmail.com> Signed-off-by: shejialuo <shejialuo@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

shejialuo committed Aug 8, 2024 at 19:31 UTC a7600b8481b533d77a2cc5f03acdbed12b996fcd
3 files changed +76 -1
Documentation/fsck-msgids.txt
+3
@@ -19,6 +19,9 @@
19 `badParentSha1`::
20 (ERROR) A commit object has a bad parent sha1.
21
22 +`badRefFiletype`::
23 + (ERROR) A ref has a bad file type.
24 +
25 `badTagName`::
26 (INFO) A tag has an invalid format.
27
fsck.h
+1
@@ -31,6 +31,7 @@ enum fsck_msg_type {
31 FUNC(BAD_NAME, ERROR) \
32 FUNC(BAD_OBJECT_SHA1, ERROR) \
33 FUNC(BAD_PARENT_SHA1, ERROR) \
34 + FUNC(BAD_REF_FILETYPE, ERROR) \
35 FUNC(BAD_TIMEZONE, ERROR) \
36 FUNC(BAD_TREE, ERROR) \
37 FUNC(BAD_TREE_SHA1, ERROR) \
refs/files-backend.c
+72 -1
@@ -6,6 +6,7 @@
6 #include "../gettext.h"
7 #include "../hash.h"
8 #include "../hex.h"
9 +#include "../fsck.h"
10 #include "../refs.h"
11 #include "refs-internal.h"
12 #include "ref-cache.h"
@@ -3408,13 +3409,83 @@ static int files_ref_store_remove_on_disk(struct ref_store *ref_store,
3409 return ret;
3410 }
3411
3412 +/*
3413 + * For refs and reflogs, they share a unified interface when scanning
3414 + * the whole directory. This function is used as the callback for each
3415 + * regular file or symlink in the directory.
3416 + */
3417 +typedef int (*files_fsck_refs_fn)(struct ref_store *ref_store,
3418 + struct fsck_options *o,
3419 + const char *refs_check_dir,
3420 + struct dir_iterator *iter);
3421 +
3422 +static int files_fsck_refs_dir(struct ref_store *ref_store,
3423 + struct fsck_options *o,
3424 + const char *refs_check_dir,
3425 + files_fsck_refs_fn *fsck_refs_fn)
3426 +{
3427 + struct strbuf sb = STRBUF_INIT;
3428 + struct dir_iterator *iter;
3429 + int iter_status;
3430 + int ret = 0;
3431 +
3432 + strbuf_addf(&sb, "%s/%s", ref_store->gitdir, refs_check_dir);
3433 +
3434 + iter = dir_iterator_begin(sb.buf, 0);
3435 + if (!iter) {
3436 + ret = error_errno(_("cannot open directory %s"), sb.buf);
3437 + goto out;
3438 + }
3439 +
3440 + while ((iter_status = dir_iterator_advance(iter)) == ITER_OK) {
3441 + if (S_ISDIR(iter->st.st_mode)) {
3442 + continue;
3443 + } else if (S_ISREG(iter->st.st_mode) ||
3444 + S_ISLNK(iter->st.st_mode)) {
3445 + if (o->verbose)
3446 + fprintf_ln(stderr, "Checking %s/%s",
3447 + refs_check_dir, iter->relative_path);
3448 + for (size_t i = 0; fsck_refs_fn[i]; i++) {
3449 + if (fsck_refs_fn[i](ref_store, o, refs_check_dir, iter))
3450 + ret = -1;
3451 + }
3452 + } else {
3453 + struct fsck_ref_report report = { .path = iter->basename };
3454 + if (fsck_report_ref(o, &report,
3455 + FSCK_MSG_BAD_REF_FILETYPE,
3456 + "unexpected file type"))
3457 + ret = -1;
3458 + }
3459 + }
3460 +
3461 + if (iter_status != ITER_DONE)
3462 + ret = error(_("failed to iterate over '%s'"), sb.buf);
3463 +
3464 +out:
3465 + strbuf_release(&sb);
3466 + return ret;
3467 +}
3468 +
3469 +static int files_fsck_refs(struct ref_store *ref_store,
3470 + struct fsck_options *o)
3471 +{
3472 + files_fsck_refs_fn fsck_refs_fn[]= {
3473 + NULL,
3474 + };
3475 +
3476 + if (o->verbose)
3477 + fprintf_ln(stderr, _("Checking references consistency"));
3478 + return files_fsck_refs_dir(ref_store, o, "refs", fsck_refs_fn);
3479 +}
3480 +
3481 static int files_fsck(struct ref_store *ref_store,
3482 struct fsck_options *o)
3483 {
3484 struct files_ref_store *refs =
3485 files_downcast(ref_store, REF_STORE_READ, "fsck");
3486
3417 - return refs->packed_ref_store->be->fsck(refs->packed_ref_store, o);
3487 + return files_fsck_refs(ref_store, o) |
3488 + refs->packed_ref_store->be->fsck(refs->packed_ref_store, o);
3489 }
3490
3491 struct ref_storage_be refs_be_files = {