Skip to content

Commit 75371bd

Browse files
shejialuogitster
authored andcommitted
ref: add symlink ref content check for files backend
We have already introduced "files_fsck_symref_target". We should reuse this function to handle the symrefs which use legacy symbolic links. We should not check the trailing garbage for symbolic refs. Add a new parameter "symbolic_link" to disable some checks which should only be executed for textual symrefs. We firstly use the "strbuf_add_real_path" to resolve the symlink and get the absolute path "referent_path" which the symlink ref points to. Then we can get the absolute path "abs_gitdir" of the "gitdir". By combining "referent_path" and "abs_gitdir", we can extract the "referent". Thus, we can reuse "files_fsck_symref_target" function to seamlessly check the symlink refs. Because we consider deprecating writing the symbolic links and for reading, we may or may not deprecate. We first need to asses whether symbolic links may still be used. So, add a new fsck message "symlinkRef(INFO)" to let the user be aware of this information. 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 af7cb5f commit 75371bd

File tree

4 files changed

+154
-14
lines changed

4 files changed

+154
-14
lines changed

Documentation/fsck-msgids.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,11 @@
186186
(INFO) A ref does not end with newline. This will be
187187
considered an error in the future.
188188

189+
`symlinkRef`::
190+
(INFO) A symref uses the symbolic link. This kind of symref may
191+
be considered ERROR in the future when totally dropping the
192+
symlink support.
193+
189194
`trailingRefContent`::
190195
(INFO) A ref has trailing content. This will be
191196
considered an error in the future.

fsck.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ enum fsck_msg_type {
8989
FUNC(BAD_TAG_NAME, INFO) \
9090
FUNC(MISSING_TAGGER_ENTRY, INFO) \
9191
FUNC(REF_MISSING_NEWLINE, INFO) \
92+
FUNC(SYMLINK_REF, INFO) \
9293
FUNC(TRAILING_REF_CONTENT, INFO) \
9394
/* ignored (elevated when requested) */ \
9495
FUNC(EXTRA_HEADER_ENTRY, IGNORE)

refs/files-backend.c

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "../git-compat-util.h"
2+
#include "../abspath.h"
23
#include "../copy.h"
34
#include "../environment.h"
45
#include "../gettext.h"
@@ -1950,24 +1951,26 @@ static int commit_ref_update(struct files_ref_store *refs,
19501951
return 0;
19511952
}
19521953

1954+
#ifdef NO_SYMLINK_HEAD
1955+
#define create_ref_symlink(a, b) (-1)
1956+
#else
19531957
static int create_ref_symlink(struct ref_lock *lock, const char *target)
19541958
{
19551959
int ret = -1;
1956-
#ifndef NO_SYMLINK_HEAD
1960+
19571961
char *ref_path = get_locked_file_path(&lock->lk);
19581962
unlink(ref_path);
19591963
ret = symlink(target, ref_path);
19601964
free(ref_path);
19611965

19621966
if (ret)
19631967
fprintf(stderr, "no symlink - falling back to symbolic ref\n");
1964-
#endif
19651968
return ret;
19661969
}
1970+
#endif
19671971

1968-
static int create_symref_lock(struct files_ref_store *refs,
1969-
struct ref_lock *lock, const char *refname,
1970-
const char *target, struct strbuf *err)
1972+
static int create_symref_lock(struct ref_lock *lock, const char *target,
1973+
struct strbuf *err)
19711974
{
19721975
if (!fdopen_lock_file(&lock->lk, "w")) {
19731976
strbuf_addf(err, "unable to fdopen %s: %s",
@@ -2583,8 +2586,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
25832586
}
25842587

25852588
if (update->new_target && !(update->flags & REF_LOG_ONLY)) {
2586-
if (create_symref_lock(refs, lock, update->refname,
2587-
update->new_target, err)) {
2589+
if (create_symref_lock(lock, update->new_target, err)) {
25882590
ret = TRANSACTION_GENERIC_ERROR;
25892591
goto out;
25902592
}
@@ -3436,12 +3438,15 @@ typedef int (*files_fsck_refs_fn)(struct ref_store *ref_store,
34363438

34373439
/*
34383440
* Check the symref "referent" and "referent_path". For textual symref,
3439-
* "referent" would be the content after "refs:".
3441+
* "referent" would be the content after "refs:". For symlink ref,
3442+
* "referent" would be the relative path agaignst "gitdir" which should
3443+
* be the same as the textual symref literally.
34403444
*/
34413445
static int files_fsck_symref_target(struct fsck_options *o,
34423446
struct fsck_ref_report *report,
34433447
struct strbuf *referent,
3444-
struct strbuf *referent_path)
3448+
struct strbuf *referent_path,
3449+
unsigned int symbolic_link)
34453450
{
34463451
size_t len = referent->len - 1;
34473452
struct stat st;
@@ -3454,22 +3459,24 @@ static int files_fsck_symref_target(struct fsck_options *o,
34543459
goto out;
34553460
}
34563461

3457-
if (referent->buf[referent->len - 1] != '\n') {
3462+
if (!symbolic_link && referent->buf[referent->len - 1] != '\n') {
34583463
ret = fsck_report_ref(o, report,
34593464
FSCK_MSG_REF_MISSING_NEWLINE,
34603465
"missing newline");
34613466
len++;
34623467
}
34633468

3464-
strbuf_rtrim(referent);
3469+
if (!symbolic_link)
3470+
strbuf_rtrim(referent);
3471+
34653472
if (check_refname_format(referent->buf, 0)) {
34663473
ret = fsck_report_ref(o, report,
34673474
FSCK_MSG_BAD_REFERENT_NAME,
34683475
"points to refname with invalid format");
34693476
goto out;
34703477
}
34713478

3472-
if (len != referent->len) {
3479+
if (!symbolic_link && len != referent->len) {
34733480
ret = fsck_report_ref(o, report,
34743481
FSCK_MSG_TRAILING_REF_CONTENT,
34753482
"trailing garbage in ref");
@@ -3509,6 +3516,7 @@ static int files_fsck_refs_content(struct ref_store *ref_store,
35093516
{
35103517
struct strbuf referent_path = STRBUF_INIT;
35113518
struct strbuf ref_content = STRBUF_INIT;
3519+
struct strbuf abs_gitdir = STRBUF_INIT;
35123520
struct strbuf referent = STRBUF_INIT;
35133521
struct strbuf refname = STRBUF_INIT;
35143522
struct fsck_ref_report report = {0};
@@ -3521,8 +3529,35 @@ static int files_fsck_refs_content(struct ref_store *ref_store,
35213529
strbuf_addf(&refname, "%s/%s", refs_check_dir, iter->relative_path);
35223530
report.path = refname.buf;
35233531

3524-
if (S_ISLNK(iter->st.st_mode))
3532+
if (S_ISLNK(iter->st.st_mode)) {
3533+
const char* relative_referent_path;
3534+
3535+
ret = fsck_report_ref(o, &report,
3536+
FSCK_MSG_SYMLINK_REF,
3537+
"use deprecated symbolic link for symref");
3538+
3539+
strbuf_add_absolute_path(&abs_gitdir, ref_store->gitdir);
3540+
strbuf_normalize_path(&abs_gitdir);
3541+
if (!is_dir_sep(abs_gitdir.buf[abs_gitdir.len - 1]))
3542+
strbuf_addch(&abs_gitdir, '/');
3543+
3544+
strbuf_add_real_path(&referent_path, iter->path.buf);
3545+
3546+
if (!skip_prefix(referent_path.buf,
3547+
abs_gitdir.buf,
3548+
&relative_referent_path)) {
3549+
ret = fsck_report_ref(o, &report,
3550+
FSCK_MSG_ESCAPE_REFERENT,
3551+
"point to target outside gitdir");
3552+
goto cleanup;
3553+
}
3554+
3555+
strbuf_addstr(&referent, relative_referent_path);
3556+
ret = files_fsck_symref_target(o, &report,
3557+
&referent, &referent_path, 1);
3558+
35253559
goto cleanup;
3560+
}
35263561

35273562
if (strbuf_read_file(&ref_content, iter->path.buf, 0) < 0) {
35283563
ret = error_errno(_("unable to read ref '%s/%s'"),
@@ -3563,14 +3598,16 @@ static int files_fsck_refs_content(struct ref_store *ref_store,
35633598
strbuf_rtrim(&referent_path);
35643599
ret = files_fsck_symref_target(o, &report,
35653600
&referent,
3566-
&referent_path);
3601+
&referent_path,
3602+
0);
35673603
}
35683604

35693605
cleanup:
35703606
strbuf_release(&refname);
35713607
strbuf_release(&ref_content);
35723608
strbuf_release(&referent);
35733609
strbuf_release(&referent_path);
3610+
strbuf_release(&abs_gitdir);
35743611
return ret;
35753612
}
35763613

t/t0602-reffiles-fsck.sh

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,4 +326,101 @@ test_expect_success 'textual symref content should be checked (aggregate)' '
326326
test_cmp expect sorted_err
327327
'
328328

329+
test_expect_success SYMLINKS 'symlink symref content should be checked (individual)' '
330+
test_when_finished "rm -rf repo" &&
331+
git init repo &&
332+
branch_dir_prefix=.git/refs/heads &&
333+
tag_dir_prefix=.git/refs/tags &&
334+
cd repo &&
335+
test_commit default &&
336+
mkdir -p "$branch_dir_prefix/a/b" &&
337+
338+
ln -sf ./main $branch_dir_prefix/branch-symbolic-good &&
339+
git refs verify 2>err &&
340+
cat >expect <<-EOF &&
341+
warning: refs/heads/branch-symbolic-good: symlinkRef: use deprecated symbolic link for symref
342+
EOF
343+
rm $branch_dir_prefix/branch-symbolic-good &&
344+
test_cmp expect err &&
345+
346+
ln -sf ../../../../branch $branch_dir_prefix/branch-symbolic-1 &&
347+
test_must_fail git refs verify 2>err &&
348+
cat >expect <<-EOF &&
349+
warning: refs/heads/branch-symbolic-1: symlinkRef: use deprecated symbolic link for symref
350+
error: refs/heads/branch-symbolic-1: escapeReferent: point to target outside gitdir
351+
EOF
352+
rm $branch_dir_prefix/branch-symbolic-1 &&
353+
test_cmp expect err &&
354+
355+
ln -sf ../../logs/branch-bad $branch_dir_prefix/branch-symbolic-2 &&
356+
test_must_fail git refs verify 2>err &&
357+
cat >expect <<-EOF &&
358+
warning: refs/heads/branch-symbolic-2: symlinkRef: use deprecated symbolic link for symref
359+
error: refs/heads/branch-symbolic-2: escapeReferent: points to ref outside the refs directory
360+
EOF
361+
rm $branch_dir_prefix/branch-symbolic-2 &&
362+
test_cmp expect err &&
363+
364+
ln -sf ./"branch space" $branch_dir_prefix/branch-symbolic-3 &&
365+
test_must_fail git refs verify 2>err &&
366+
cat >expect <<-EOF &&
367+
warning: refs/heads/branch-symbolic-3: symlinkRef: use deprecated symbolic link for symref
368+
error: refs/heads/branch-symbolic-3: badReferentName: points to refname with invalid format
369+
EOF
370+
rm $branch_dir_prefix/branch-symbolic-3 &&
371+
test_cmp expect err &&
372+
373+
ln -sf ./".tag" $tag_dir_prefix/tag-symbolic-1 &&
374+
test_must_fail git refs verify 2>err &&
375+
cat >expect <<-EOF &&
376+
warning: refs/tags/tag-symbolic-1: symlinkRef: use deprecated symbolic link for symref
377+
error: refs/tags/tag-symbolic-1: badReferentName: points to refname with invalid format
378+
EOF
379+
rm $tag_dir_prefix/tag-symbolic-1 &&
380+
test_cmp expect err &&
381+
382+
ln -sf ./ $tag_dir_prefix/tag-symbolic-2 &&
383+
test_must_fail git refs verify 2>err &&
384+
cat >expect <<-EOF &&
385+
warning: refs/tags/tag-symbolic-2: symlinkRef: use deprecated symbolic link for symref
386+
error: refs/tags/tag-symbolic-2: badReferentFiletype: points to the directory
387+
EOF
388+
rm $tag_dir_prefix/tag-symbolic-2 &&
389+
test_cmp expect err
390+
'
391+
392+
test_expect_success SYMLINKS 'symlink symref content should be checked (aggregate)' '
393+
test_when_finished "rm -rf repo" &&
394+
git init repo &&
395+
branch_dir_prefix=.git/refs/heads &&
396+
tag_dir_prefix=.git/refs/tags &&
397+
cd repo &&
398+
test_commit default &&
399+
mkdir -p "$branch_dir_prefix/a/b" &&
400+
401+
ln -sf ./main $branch_dir_prefix/branch-symbolic-good &&
402+
ln -sf ../../../../branch $branch_dir_prefix/branch-symbolic-1 &&
403+
ln -sf ../../logs/branch-bad $branch_dir_prefix/branch-symbolic-2 &&
404+
ln -sf ./"branch space" $branch_dir_prefix/branch-symbolic-3 &&
405+
ln -sf ./".tag" $tag_dir_prefix/tag-symbolic-1 &&
406+
ln -sf ./ $tag_dir_prefix/tag-symbolic-2 &&
407+
408+
test_must_fail git refs verify 2>err &&
409+
cat >expect <<-EOF &&
410+
error: refs/heads/branch-symbolic-1: escapeReferent: point to target outside gitdir
411+
error: refs/heads/branch-symbolic-2: escapeReferent: points to ref outside the refs directory
412+
error: refs/heads/branch-symbolic-3: badReferentName: points to refname with invalid format
413+
error: refs/tags/tag-symbolic-1: badReferentName: points to refname with invalid format
414+
error: refs/tags/tag-symbolic-2: badReferentFiletype: points to the directory
415+
warning: refs/heads/branch-symbolic-1: symlinkRef: use deprecated symbolic link for symref
416+
warning: refs/heads/branch-symbolic-2: symlinkRef: use deprecated symbolic link for symref
417+
warning: refs/heads/branch-symbolic-3: symlinkRef: use deprecated symbolic link for symref
418+
warning: refs/heads/branch-symbolic-good: symlinkRef: use deprecated symbolic link for symref
419+
warning: refs/tags/tag-symbolic-1: symlinkRef: use deprecated symbolic link for symref
420+
warning: refs/tags/tag-symbolic-2: symlinkRef: use deprecated symbolic link for symref
421+
EOF
422+
sort err >sorted_err &&
423+
test_cmp expect sorted_err
424+
'
425+
329426
test_done

0 commit comments

Comments
 (0)