Skip to content

Commit 1c0e2a0

Browse files
shejialuogitster
authored andcommitted
ref: add more strict checks for regular refs
We have already used "parse_loose_ref_contents" function to check whether the ref content is valid in files backend. However, by using "parse_loose_ref_contents", we allow the ref's content to end with garbage or without a newline. Even though we never create such loose refs ourselves, we have accepted such loose refs. So, it is entirely possible that some third-party tools may rely on such loose refs being valid. We should not report an error fsck message at current. We should notify the users about such "curiously formatted" loose refs so that adequate care is taken before we decide to tighten the rules in the future. And it's not suitable either to report a warn fsck message to the user. We don't yet want the "--strict" flag that controls this bit to end up generating errors for such weirdly-formatted reference contents, as we first want to assess whether this retroactive tightening will cause issues for any tools out there. It may cause compatibility issues which may break the repository. So, we add the following two fsck infos to represent the situation where the ref content ends without newline or has trailing garbages: 1. refMissingNewline(INFO): A loose ref that does not end with newline(LF). 2. trailingRefContent(INFO): A loose ref has trailing content. It might appear that we can't provide the user with any warnings by using FSCK_INFO. However, in "fsck.c::fsck_vreport", we will convert FSCK_INFO to FSCK_WARN and we can still warn the user about these situations when using "git refs verify" without introducing compatibility issues. Mentored-by: Patrick Steinhardt <[email protected]> Mentored-by: Karthik Nayak <[email protected]> Signed-off-by: shejialuo <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 824aa54 commit 1c0e2a0

File tree

6 files changed

+96
-7
lines changed

6 files changed

+96
-7
lines changed

Documentation/fsck-msgids.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,20 @@
173173
`nullSha1`::
174174
(WARN) Tree contains entries pointing to a null sha1.
175175

176+
`refMissingNewline`::
177+
(INFO) A loose ref that does not end with newline(LF). As
178+
valid implementations of Git never created such a loose ref
179+
file, it may become an error in the future. Report to the
180+
[email protected] mailing list if you see this error, as
181+
we need to know what tools created such a file.
182+
183+
`trailingRefContent`::
184+
(INFO) A loose ref has trailing content. As valid implementations
185+
of Git never created such a loose ref file, it may become an
186+
error in the future. Report to the [email protected] mailing
187+
list if you see this error, as we need to know what tools
188+
created such a file.
189+
176190
`treeNotSorted`::
177191
(ERROR) A tree is not properly sorted.
178192

fsck.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ enum fsck_msg_type {
8585
FUNC(MAILMAP_SYMLINK, INFO) \
8686
FUNC(BAD_TAG_NAME, INFO) \
8787
FUNC(MISSING_TAGGER_ENTRY, INFO) \
88+
FUNC(REF_MISSING_NEWLINE, INFO) \
89+
FUNC(TRAILING_REF_CONTENT, INFO) \
8890
/* ignored (elevated when requested) */ \
8991
FUNC(EXTRA_HEADER_ENTRY, IGNORE)
9092

refs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1789,7 +1789,7 @@ static int refs_read_special_head(struct ref_store *ref_store,
17891789
}
17901790

17911791
result = parse_loose_ref_contents(ref_store->repo->hash_algo, content.buf,
1792-
oid, referent, type, failure_errno);
1792+
oid, referent, type, NULL, failure_errno);
17931793

17941794
done:
17951795
strbuf_release(&full_path);

refs/files-backend.c

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ static int read_ref_internal(struct ref_store *ref_store, const char *refname,
569569
buf = sb_contents.buf;
570570

571571
ret = parse_loose_ref_contents(ref_store->repo->hash_algo, buf,
572-
oid, referent, type, &myerr);
572+
oid, referent, type, NULL, &myerr);
573573

574574
out:
575575
if (ret && !myerr)
@@ -606,7 +606,7 @@ static int files_read_symbolic_ref(struct ref_store *ref_store, const char *refn
606606
int parse_loose_ref_contents(const struct git_hash_algo *algop,
607607
const char *buf, struct object_id *oid,
608608
struct strbuf *referent, unsigned int *type,
609-
int *failure_errno)
609+
const char **trailing, int *failure_errno)
610610
{
611611
const char *p;
612612
if (skip_prefix(buf, "ref:", &buf)) {
@@ -628,6 +628,10 @@ int parse_loose_ref_contents(const struct git_hash_algo *algop,
628628
*failure_errno = EINVAL;
629629
return -1;
630630
}
631+
632+
if (trailing)
633+
*trailing = p;
634+
631635
return 0;
632636
}
633637

@@ -3513,6 +3517,7 @@ static int files_fsck_refs_content(struct ref_store *ref_store,
35133517
struct strbuf ref_content = STRBUF_INIT;
35143518
struct strbuf referent = STRBUF_INIT;
35153519
struct fsck_ref_report report = { 0 };
3520+
const char *trailing = NULL;
35163521
unsigned int type = 0;
35173522
int failure_errno = 0;
35183523
struct object_id oid;
@@ -3537,14 +3542,29 @@ static int files_fsck_refs_content(struct ref_store *ref_store,
35373542

35383543
if (parse_loose_ref_contents(ref_store->repo->hash_algo,
35393544
ref_content.buf, &oid, &referent,
3540-
&type, &failure_errno)) {
3545+
&type, &trailing, &failure_errno)) {
35413546
strbuf_rtrim(&ref_content);
35423547
ret = fsck_report_ref(o, &report,
35433548
FSCK_MSG_BAD_REF_CONTENT,
35443549
"%s", ref_content.buf);
35453550
goto cleanup;
35463551
}
35473552

3553+
if (!(type & REF_ISSYMREF)) {
3554+
if (!*trailing) {
3555+
ret = fsck_report_ref(o, &report,
3556+
FSCK_MSG_REF_MISSING_NEWLINE,
3557+
"misses LF at the end");
3558+
goto cleanup;
3559+
}
3560+
if (*trailing != '\n' || *(trailing + 1)) {
3561+
ret = fsck_report_ref(o, &report,
3562+
FSCK_MSG_TRAILING_REF_CONTENT,
3563+
"has trailing garbage: '%s'", trailing);
3564+
goto cleanup;
3565+
}
3566+
}
3567+
35483568
cleanup:
35493569
strbuf_release(&ref_content);
35503570
strbuf_release(&referent);

refs/refs-internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,7 @@ struct ref_store {
716716
int parse_loose_ref_contents(const struct git_hash_algo *algop,
717717
const char *buf, struct object_id *oid,
718718
struct strbuf *referent, unsigned int *type,
719-
int *failure_errno);
719+
const char **trailing, int *failure_errno);
720720

721721
/*
722722
* Fill in the generic part of refs and add it to our collection of

t/t0602-reffiles-fsck.sh

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,48 @@ test_expect_success 'regular ref content should be checked (individual)' '
189189
EOF
190190
rm $branch_dir_prefix/a/b/branch-bad &&
191191
test_cmp expect err || return 1
192-
done
192+
done &&
193+
194+
printf "%s" "$(git rev-parse main)" >$branch_dir_prefix/branch-no-newline &&
195+
git refs verify 2>err &&
196+
cat >expect <<-EOF &&
197+
warning: refs/heads/branch-no-newline: refMissingNewline: misses LF at the end
198+
EOF
199+
rm $branch_dir_prefix/branch-no-newline &&
200+
test_cmp expect err &&
201+
202+
for trailing_content in " garbage" " more garbage"
203+
do
204+
printf "%s" "$(git rev-parse main)$trailing_content" >$branch_dir_prefix/branch-garbage &&
205+
git refs verify 2>err &&
206+
cat >expect <<-EOF &&
207+
warning: refs/heads/branch-garbage: trailingRefContent: has trailing garbage: '\''$trailing_content'\''
208+
EOF
209+
rm $branch_dir_prefix/branch-garbage &&
210+
test_cmp expect err || return 1
211+
done &&
212+
213+
printf "%s\n\n\n" "$(git rev-parse main)" >$branch_dir_prefix/branch-garbage-special &&
214+
git refs verify 2>err &&
215+
cat >expect <<-EOF &&
216+
warning: refs/heads/branch-garbage-special: trailingRefContent: has trailing garbage: '\''
217+
218+
219+
'\''
220+
EOF
221+
rm $branch_dir_prefix/branch-garbage-special &&
222+
test_cmp expect err &&
223+
224+
printf "%s\n\n\n garbage" "$(git rev-parse main)" >$branch_dir_prefix/branch-garbage-special &&
225+
git refs verify 2>err &&
226+
cat >expect <<-EOF &&
227+
warning: refs/heads/branch-garbage-special: trailingRefContent: has trailing garbage: '\''
228+
229+
230+
garbage'\''
231+
EOF
232+
rm $branch_dir_prefix/branch-garbage-special &&
233+
test_cmp expect err
193234
'
194235

195236
test_expect_success 'regular ref content should be checked (aggregate)' '
@@ -207,12 +248,16 @@ test_expect_success 'regular ref content should be checked (aggregate)' '
207248
printf "%s" $bad_content_1 >$tag_dir_prefix/tag-bad-1 &&
208249
printf "%s" $bad_content_2 >$tag_dir_prefix/tag-bad-2 &&
209250
printf "%s" $bad_content_3 >$branch_dir_prefix/a/b/branch-bad &&
251+
printf "%s" "$(git rev-parse main)" >$branch_dir_prefix/branch-no-newline &&
252+
printf "%s garbage" "$(git rev-parse main)" >$branch_dir_prefix/branch-garbage &&
210253
211254
test_must_fail git refs verify 2>err &&
212255
cat >expect <<-EOF &&
213256
error: refs/heads/a/b/branch-bad: badRefContent: $bad_content_3
214257
error: refs/tags/tag-bad-1: badRefContent: $bad_content_1
215258
error: refs/tags/tag-bad-2: badRefContent: $bad_content_2
259+
warning: refs/heads/branch-garbage: trailingRefContent: has trailing garbage: '\'' garbage'\''
260+
warning: refs/heads/branch-no-newline: refMissingNewline: misses LF at the end
216261
EOF
217262
sort err >sorted_err &&
218263
test_cmp expect sorted_err
@@ -260,7 +305,15 @@ test_expect_success 'ref content checks should work with worktrees' '
260305
EOF
261306
rm $worktree2_refdir_prefix/bad-branch-2 &&
262307
test_cmp expect err || return 1
263-
done
308+
done &&
309+
310+
printf "%s" "$(git rev-parse HEAD)" >$worktree1_refdir_prefix/branch-no-newline &&
311+
git refs verify 2>err &&
312+
cat >expect <<-EOF &&
313+
warning: worktrees/worktree-1/refs/worktree/branch-no-newline: refMissingNewline: misses LF at the end
314+
EOF
315+
rm $worktree1_refdir_prefix/branch-no-newline &&
316+
test_cmp expect err
264317
'
265318

266319
test_done

0 commit comments

Comments
 (0)