summaryrefslogtreecommitdiffstats
path: root/refs
diff options
context:
space:
mode:
authorshejialuo <shejialuo@gmail.com>2024-11-20 12:51:42 +0100
committerJunio C Hamano <gitster@pobox.com>2024-11-21 00:21:32 +0100
commit824aa541aae7a35f32f9dabc54f8a97861488013 (patch)
tree9327d43ff3df5f7b6535843724a19665d017f6a2 /refs
parentref: support multiple worktrees check for refs (diff)
downloadgit-824aa541aae7a35f32f9dabc54f8a97861488013.tar.xz
git-824aa541aae7a35f32f9dabc54f8a97861488013.zip
ref: port git-fsck(1) regular refs check for files backend
"git-fsck(1)" implicitly checks the ref content by passing the callback "fsck_handle_ref" to the "refs.c::refs_for_each_rawref". Then, it will check whether the ref content (eventually "oid") is valid. If not, it will report the following error to the user. error: refs/heads/main: invalid sha1 pointer 0000... And it will also report above errors when there are dangling symrefs in the repository wrongly. This does not align with the behavior of the "git symbolic-ref" command which allows users to create dangling symrefs. As we have already introduced the "git refs verify" command, we'd better check the ref content explicitly in the "git refs verify" command thus later we could remove these checks in "git-fsck(1)" and launch a subprocess to call "git refs verify" in "git-fsck(1)" to make the "git-fsck(1)" more clean. Following what "git-fsck(1)" does, add a similar check to "git refs verify". Then add a new fsck error message "badRefContent(ERROR)" to represent that a ref has an invalid content. 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>
Diffstat (limited to 'refs')
-rw-r--r--refs/files-backend.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 8bfdce64bc..9f300a7d3c 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -3505,6 +3505,52 @@ typedef int (*files_fsck_refs_fn)(struct ref_store *ref_store,
const char *refname,
struct dir_iterator *iter);
+static int files_fsck_refs_content(struct ref_store *ref_store,
+ struct fsck_options *o,
+ const char *target_name,
+ struct dir_iterator *iter)
+{
+ struct strbuf ref_content = STRBUF_INIT;
+ struct strbuf referent = STRBUF_INIT;
+ struct fsck_ref_report report = { 0 };
+ unsigned int type = 0;
+ int failure_errno = 0;
+ struct object_id oid;
+ int ret = 0;
+
+ report.path = target_name;
+
+ if (S_ISLNK(iter->st.st_mode))
+ goto cleanup;
+
+ if (strbuf_read_file(&ref_content, iter->path.buf, 0) < 0) {
+ /*
+ * Ref file could be removed by another concurrent process. We should
+ * ignore this error and continue to the next ref.
+ */
+ if (errno == ENOENT)
+ goto cleanup;
+
+ ret = error_errno(_("cannot read ref file '%s'"), iter->path.buf);
+ goto cleanup;
+ }
+
+ if (parse_loose_ref_contents(ref_store->repo->hash_algo,
+ ref_content.buf, &oid, &referent,
+ &type, &failure_errno)) {
+ strbuf_rtrim(&ref_content);
+ ret = fsck_report_ref(o, &report,
+ FSCK_MSG_BAD_REF_CONTENT,
+ "%s", ref_content.buf);
+ goto cleanup;
+ }
+
+cleanup:
+ strbuf_release(&ref_content);
+ strbuf_release(&referent);
+ return ret;
+}
+
static int files_fsck_refs_name(struct ref_store *ref_store UNUSED,
struct fsck_options *o,
const char *refname,
@@ -3600,6 +3646,7 @@ static int files_fsck_refs(struct ref_store *ref_store,
{
files_fsck_refs_fn fsck_refs_fn[]= {
files_fsck_refs_name,
+ files_fsck_refs_content,
NULL,
};