]> git.ipfire.org Git - thirdparty/git.git/commitdiff
packed-backend: check whether the "packed-refs" is regular file
authorshejialuo <shejialuo@gmail.com>
Thu, 27 Feb 2025 16:06:24 +0000 (00:06 +0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 27 Feb 2025 22:03:07 +0000 (14:03 -0800)
Although "git-fsck(1)" and "packed-backend.c" will check some
consistency and correctness of "packed-refs" file, they never check the
filetype of the "packed-refs". Let's verify that the "packed-refs" has
the expected filetype, confirming it is created by "git pack-refs"
command.

We could use "open_nofollow" wrapper to open the raw "packed-refs" file.
If the returned "fd" value is less than 0, we could check whether the
"errno" is "ELOOP" to report an error to the user. And then we use
"fstat" to check whether the "packed-refs" file is a regular file.

Reuse "FSCK_MSG_BAD_REF_FILETYPE" fsck message id to report the error to
the user if "packed-refs" is not a regular file.

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>
refs/packed-backend.c
t/t0602-reffiles-fsck.sh

index a7b6f74b6e35f897f619c540cbc600bbd888bc67..1fba804a2aad074b5c808f74e997ff36619bda0d 100644 (file)
@@ -4,6 +4,7 @@
 #include "../git-compat-util.h"
 #include "../config.h"
 #include "../dir.h"
+#include "../fsck.h"
 #include "../gettext.h"
 #include "../hash.h"
 #include "../hex.h"
@@ -1748,15 +1749,58 @@ static struct ref_iterator *packed_reflog_iterator_begin(struct ref_store *ref_s
        return empty_ref_iterator_begin();
 }
 
-static int packed_fsck(struct ref_store *ref_store UNUSED,
-                      struct fsck_options *o UNUSED,
+static int packed_fsck(struct ref_store *ref_store,
+                      struct fsck_options *o,
                       struct worktree *wt)
 {
+       struct packed_ref_store *refs = packed_downcast(ref_store,
+                                                       REF_STORE_READ, "fsck");
+       struct stat st;
+       int ret = 0;
+       int fd = -1;
 
        if (!is_main_worktree(wt))
-               return 0;
+               goto cleanup;
 
-       return 0;
+       if (o->verbose)
+               fprintf_ln(stderr, "Checking packed-refs file %s", refs->path);
+
+       fd = open_nofollow(refs->path, O_RDONLY);
+       if (fd < 0) {
+               /*
+                * If the packed-refs file doesn't exist, there's nothing
+                * to check.
+                */
+               if (errno == ENOENT)
+                       goto cleanup;
+
+               if (errno == ELOOP) {
+                       struct fsck_ref_report report = { 0 };
+                       report.path = "packed-refs";
+                       ret = fsck_report_ref(o, &report,
+                                             FSCK_MSG_BAD_REF_FILETYPE,
+                                             "not a regular file but a symlink");
+                       goto cleanup;
+               }
+
+               ret = error_errno(_("unable to open '%s'"), refs->path);
+               goto cleanup;
+       } else if (fstat(fd, &st) < 0) {
+               ret = error_errno(_("unable to stat '%s'"), refs->path);
+               goto cleanup;
+       } else if (!S_ISREG(st.st_mode)) {
+               struct fsck_ref_report report = { 0 };
+               report.path = "packed-refs";
+               ret = fsck_report_ref(o, &report,
+                                     FSCK_MSG_BAD_REF_FILETYPE,
+                                     "not a regular file");
+               goto cleanup;
+       }
+
+cleanup:
+       if (fd >= 0)
+               close(fd);
+       return ret;
 }
 
 struct ref_storage_be refs_be_packed = {
index cf7a202d0ded7c8343b74ee193f958b802c7abdf..68b7d4999e0b40ddc9a2be46330cabfa69233340 100755 (executable)
@@ -617,4 +617,34 @@ test_expect_success 'ref content checks should work with worktrees' '
        )
 '
 
+test_expect_success SYMLINKS 'the filetype of packed-refs should be checked' '
+       test_when_finished "rm -rf repo" &&
+       git init repo &&
+       (
+               cd repo &&
+               test_commit default &&
+               git branch branch-1 &&
+               git branch branch-2 &&
+               git branch branch-3 &&
+               git pack-refs --all &&
+
+               mv .git/packed-refs .git/packed-refs-back &&
+               ln -sf packed-refs-back .git/packed-refs &&
+               test_must_fail git refs verify 2>err &&
+               cat >expect <<-EOF &&
+               error: packed-refs: badRefFiletype: not a regular file but a symlink
+               EOF
+               rm .git/packed-refs &&
+               test_cmp expect err &&
+
+               mkdir .git/packed-refs &&
+               test_must_fail git refs verify 2>err &&
+               cat >expect <<-EOF &&
+               error: packed-refs: badRefFiletype: not a regular file
+               EOF
+               rm -r .git/packed-refs &&
+               test_cmp expect err
+       )
+'
+
 test_done