Skip to content

Commit ebb572d

Browse files
Bryan Millsgopherbot
Bryan Mills
authored andcommitted
Revert "internal/fsys: follow root symlink in fsys.Walk"
This reverts CL 448360 and adds a regression test for #57754. Reason for revert: broke 'go list' in Debian's distribution of the Go toolchain Fixes #57754. Updates #50807. Change-Id: I3e8b9126294c55f21572774b549fb28f29eded0f Reviewed-on: https://go-review.googlesource.com/c/go/+/461959 Reviewed-by: Russ Cox <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Auto-Submit: Bryan Mills <[email protected]> Run-TryBot: Bryan Mills <[email protected]>
1 parent 16cec4e commit ebb572d

File tree

5 files changed

+70
-46
lines changed

5 files changed

+70
-46
lines changed

src/cmd/go/internal/fsys/fsys.go

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -476,23 +476,19 @@ func IsDirWithGoFiles(dir string) (bool, error) {
476476

477477
// walk recursively descends path, calling walkFn. Copied, with some
478478
// modifications from path/filepath.walk.
479-
// Walk follows the root if it's a symlink, but reports the original paths,
480-
// so it calls walk with both the resolvedPath (which is the path with the root resolved)
481-
// and path (which is the path reported to the walkFn).
482-
func walk(path, resolvedPath string, info fs.FileInfo, walkFn filepath.WalkFunc) error {
479+
func walk(path string, info fs.FileInfo, walkFn filepath.WalkFunc) error {
483480
if err := walkFn(path, info, nil); err != nil || !info.IsDir() {
484481
return err
485482
}
486483

487-
fis, err := ReadDir(resolvedPath)
484+
fis, err := ReadDir(path)
488485
if err != nil {
489486
return walkFn(path, info, err)
490487
}
491488

492489
for _, fi := range fis {
493490
filename := filepath.Join(path, fi.Name())
494-
resolvedFilename := filepath.Join(resolvedPath, fi.Name())
495-
if err := walk(filename, resolvedFilename, fi, walkFn); err != nil {
491+
if err := walk(filename, fi, walkFn); err != nil {
496492
if !fi.IsDir() || err != filepath.SkipDir {
497493
return err
498494
}
@@ -509,23 +505,7 @@ func Walk(root string, walkFn filepath.WalkFunc) error {
509505
if err != nil {
510506
err = walkFn(root, nil, err)
511507
} else {
512-
resolved := root
513-
if info.Mode()&os.ModeSymlink != 0 {
514-
// Walk follows root if it's a symlink (but does not follow other symlinks).
515-
if op, ok := OverlayPath(root); ok {
516-
resolved = op
517-
}
518-
resolved, err = os.Readlink(resolved)
519-
if err != nil {
520-
return err
521-
}
522-
// Re-stat to get the info for the resolved file.
523-
info, err = Lstat(resolved)
524-
if err != nil {
525-
return err
526-
}
527-
}
528-
err = walk(root, resolved, info, walkFn)
508+
err = walk(root, info, walkFn)
529509
}
530510
if err == filepath.SkipDir {
531511
return nil

src/cmd/go/internal/fsys/fsys_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -844,8 +844,8 @@ func TestWalkSymlink(t *testing.T) {
844844
{"control", "dir", []string{"dir", "dir" + string(filepath.Separator) + "file"}},
845845
// ensure Walk doesn't walk into the directory pointed to by the symlink
846846
// (because it's supposed to use Lstat instead of Stat).
847-
{"symlink_to_dir", "symlink", []string{"symlink", "symlink" + string(filepath.Separator) + "file"}},
848-
{"overlay_to_symlink_to_dir", "overlay_symlink", []string{"overlay_symlink", "overlay_symlink" + string(filepath.Separator) + "file"}},
847+
{"symlink_to_dir", "symlink", []string{"symlink"}},
848+
{"overlay_to_symlink_to_dir", "overlay_symlink", []string{"overlay_symlink"}},
849849
}
850850

851851
for _, tc := range testCases {

src/cmd/go/script_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ func scriptEnv(srv *vcstest.Server, srvCertFile string) ([]string, error) {
211211
"GOROOT_FINAL=" + testGOROOT_FINAL, // causes spurious rebuilds and breaks the "stale" built-in if not propagated
212212
"GOTRACEBACK=system",
213213
"TESTGO_GOROOT=" + testGOROOT,
214+
"TESTGO_EXE=" + testGo,
214215
"TESTGO_VCSTEST_HOST=" + httpURL.Host,
215216
"TESTGO_VCSTEST_TLS_HOST=" + httpsURL.Host,
216217
"TESTGO_VCSTEST_CERT=" + srvCertFile,
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Regression test for https://go.dev/issue/57754: 'go list' failed if ../src
2+
# relative to the location of the go executable was a symlink to the real src
3+
# directory. (cmd/go expects that ../src is GOROOT/src, but it appears that the
4+
# Debian build of the Go toolchain is attempting to split GOROOT into binary and
5+
# source artifacts in different parent directories.)
6+
7+
[short] skip 'copies the cmd/go binary'
8+
[!symlink] skip 'tests symlink-specific behavior'
9+
10+
# Ensure that the relative path to $WORK/lib/goroot/src from $PWD is a different
11+
# number of ".." hops than the relative path to it from $WORK/share/goroot/src.
12+
13+
cd $WORK
14+
15+
# Construct a fake GOROOT in $WORK/lib/goroot whose src directory is a symlink
16+
# to a subdirectory of $WORK/share. This mimics the directory structure reported
17+
# in https://go.dev/issue/57754.
18+
#
19+
# Symlink everything else to the original $GOROOT to avoid needless copying work.
20+
21+
mkdir $WORK/lib/goroot
22+
mkdir $WORK/share/goroot
23+
symlink $WORK/share/goroot/src -> $GOROOT${/}src
24+
symlink $WORK/lib/goroot/src -> ../../share/goroot/src
25+
symlink $WORK/lib/goroot/pkg -> $GOROOT${/}pkg
26+
27+
# Verify that our symlink shenanigans don't prevent cmd/go from finding its
28+
# GOROOT using os.Executable.
29+
#
30+
# To do so, we copy the actual cmd/go executable — which is implemented as the
31+
# cmd/go test binary instead of the original $GOROOT/bin/go, which may be
32+
# arbitrarily stale — into the bin subdirectory of the fake GOROOT, causing
33+
# os.Executable to report a path in that directory.
34+
35+
mkdir $WORK/lib/goroot/bin
36+
cp $TESTGO_EXE $WORK/lib/goroot/bin/go$GOEXE
37+
38+
env GOROOT='' # Clear to force cmd/go to find GOROOT itself.
39+
exec $WORK/lib/goroot/bin/go env GOROOT
40+
stdout $WORK${/}lib${/}goroot
41+
42+
# Now verify that 'go list' can find standard-library packages in the symlinked
43+
# source tree, with paths matching the one reported by 'go env GOROOT'.
44+
45+
exec $WORK/lib/goroot/bin/go list -f '{{.ImportPath}}: {{.Dir}}' encoding/binary
46+
stdout '^encoding/binary: '$WORK${/}lib${/}goroot${/}src${/}encoding${/}binary'$'
47+
48+
# BUG(#50807): This doesn't work on Windows for some reason — perhaps
49+
# a bug in the Windows Lstat implementation with trailing separators?
50+
[!GOOS:windows] exec $WORK/lib/goroot/bin/go list -f '{{.ImportPath}}: {{.Dir}}' std
51+
[!GOOS:windows] stdout '^encoding/binary: '$WORK${/}lib${/}goroot${/}src${/}encoding${/}binary'$'
52+
53+
# Most path lookups in GOROOT are not sensitive to symlinks. However, patterns
54+
# involving '...' wildcards must use Walk to check the GOROOT tree, which makes
55+
# them more sensitive to symlinks (because Walk doesn't follow them).
56+
#
57+
# So we check such a pattern to confirm that it works and reports a path relative
58+
# to $GOROOT/src (and not the symlink target).
59+
60+
# BUG(#50807): This should report encoding/binary, not "matched no packages".
61+
exec $WORK/lib/goroot/bin/go list -f '{{.ImportPath}}: {{.Dir}}' .../binary
62+
! stdout .
63+
stderr '^go: warning: "\.\.\./binary" matched no packages$'

src/cmd/go/testdata/script/list_symlink_dotdotdot.txt

Lines changed: 0 additions & 20 deletions
This file was deleted.

0 commit comments

Comments
 (0)