diff mbox series

[v6,3/9] packed-backend: check whether the "packed-refs" is regular file

Message ID Z73D3PdEFk_nciH7@ArchLinux (mailing list archive)
State Superseded
Headers show
Series add more ref consistency checks | expand

Commit Message

shejialuo Feb. 25, 2025, 1:21 p.m. UTC
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.

Use "lstat" to check the file mode. If we cannot check the file status
due to there is no such file this is OK because there is a possibility
that there is no "packed-refs" in the repo.

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>
---
 refs/packed-backend.c    | 37 +++++++++++++++++++++++++++++++++----
 t/t0602-reffiles-fsck.sh | 22 ++++++++++++++++++++++
 2 files changed, 55 insertions(+), 4 deletions(-)

Comments

Junio C Hamano Feb. 25, 2025, 5:44 p.m. UTC | #1
shejialuo <shejialuo@gmail.com> writes:

> 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.
>
> Use "lstat" to check the file mode. If we cannot check the file status
> due to there is no such file this is OK because there is a possibility
> that there is no "packed-refs" in the repo.

Can this be done _after_ the open_nofollow() check you had in the
previous round noticed a problem?  Even though we are trying to
notice and find problems in the given repository, it is generally
a good idea to optimize for the more common case (i.e. the file is a
regular one and not a symbolic link or directory or anything funny).
Something along the lines of

	fd = open_nofollow(...);
	if (fd < 0) {
		lstat() to inspect the details
	} else if (fstat(fd, &st) < 0) {
		... cannot tell what we opened ...
	} else if (!S_ISREG(st.st_mode)) {
		... we opened something funny ...
	} else {
		... the thing is a regular file as expected ...
	}

perhaps?
shejialuo Feb. 26, 2025, 12:05 p.m. UTC | #2
On Tue, Feb 25, 2025 at 09:44:12AM -0800, Junio C Hamano wrote:
> shejialuo <shejialuo@gmail.com> writes:
> 
> > 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.
> >
> > Use "lstat" to check the file mode. If we cannot check the file status
> > due to there is no such file this is OK because there is a possibility
> > that there is no "packed-refs" in the repo.
> 
> Can this be done _after_ the open_nofollow() check you had in the
> previous round noticed a problem?  Even though we are trying to
> notice and find problems in the given repository, it is generally
> a good idea to optimize for the more common case (i.e. the file is a
> regular one and not a symbolic link or directory or anything funny).
> Something along the lines of
> 
> 	fd = open_nofollow(...);
> 	if (fd < 0) {
> 		lstat() to inspect the details
> 	} else if (fstat(fd, &st) < 0) {
> 		... cannot tell what we opened ...
> 	} else if (!S_ISREG(st.st_mode)) {
> 		... we opened something funny ...
> 	} else {
> 		... the thing is a regular file as expected ...
> 	}
> 

Good idea, by using this way, the code would be more clean. I will
improve this in the next version.

> perhaps?
diff mbox series

Patch

diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index a7b6f74b6e..6c118119a0 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -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,43 @@  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;
 
 	if (!is_main_worktree(wt))
-		return 0;
+		goto cleanup;
 
-	return 0;
+	if (o->verbose)
+		fprintf_ln(stderr, "Checking packed-refs file %s", refs->path);
+
+	if (lstat(refs->path, &st) < 0) {
+		/*
+		 * If the packed-refs file doesn't exist, there's nothing
+		 * to check.
+		 */
+		if (errno == ENOENT)
+			goto cleanup;
+		ret = error_errno(_("unable to stat '%s'"), refs->path);
+		goto cleanup;
+	}
+
+	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:
+	return ret;
 }
 
 struct ref_storage_be refs_be_packed = {
diff --git a/t/t0602-reffiles-fsck.sh b/t/t0602-reffiles-fsck.sh
index cf7a202d0d..e65ca341cd 100755
--- a/t/t0602-reffiles-fsck.sh
+++ b/t/t0602-reffiles-fsck.sh
@@ -617,4 +617,26 @@  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
+		EOF
+		rm .git/packed-refs &&
+		test_cmp expect err
+	)
+'
+
 test_done