mirror of https://github.com/golang/go.git
internal/fsys: follow root symlink in fsys.Walk
If fsys.Walk is called with a root directory that is a symlink, follow the symlink when doing the walk. This allows for users setting their current directory to a symlink to a module. Fixes #50807 Change-Id: Ie65a7cb804b87dea632ea6c758c20adcfa62fcd4 Reviewed-on: https://go-review.googlesource.com/c/go/+/448360 Reviewed-by: Bryan Mills <bcmills@google.com> Run-TryBot: Bryan Mills <bcmills@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
2f4d5c3b79
commit
4f13067f8a
|
|
@ -474,19 +474,23 @@ func IsDirWithGoFiles(dir string) (bool, error) {
|
|||
|
||||
// walk recursively descends path, calling walkFn. Copied, with some
|
||||
// modifications from path/filepath.walk.
|
||||
func walk(path string, info fs.FileInfo, walkFn filepath.WalkFunc) error {
|
||||
// Walk follows the root if it's a symlink, but reports the original paths,
|
||||
// so it calls walk with both the resolvedPath (which is the path with the root resolved)
|
||||
// and path (which is the path reported to the walkFn).
|
||||
func walk(path, resolvedPath string, info fs.FileInfo, walkFn filepath.WalkFunc) error {
|
||||
if err := walkFn(path, info, nil); err != nil || !info.IsDir() {
|
||||
return err
|
||||
}
|
||||
|
||||
fis, err := ReadDir(path)
|
||||
fis, err := ReadDir(resolvedPath)
|
||||
if err != nil {
|
||||
return walkFn(path, info, err)
|
||||
}
|
||||
|
||||
for _, fi := range fis {
|
||||
filename := filepath.Join(path, fi.Name())
|
||||
if err := walk(filename, fi, walkFn); err != nil {
|
||||
resolvedFilename := filepath.Join(resolvedPath, fi.Name())
|
||||
if err := walk(filename, resolvedFilename, fi, walkFn); err != nil {
|
||||
if !fi.IsDir() || err != filepath.SkipDir {
|
||||
return err
|
||||
}
|
||||
|
|
@ -503,7 +507,23 @@ func Walk(root string, walkFn filepath.WalkFunc) error {
|
|||
if err != nil {
|
||||
err = walkFn(root, nil, err)
|
||||
} else {
|
||||
err = walk(root, info, walkFn)
|
||||
resolved := root
|
||||
if info.Mode()&os.ModeSymlink != 0 {
|
||||
// Walk follows root if it's a symlink (but does not follow other symlinks).
|
||||
if op, ok := OverlayPath(root); ok {
|
||||
resolved = op
|
||||
}
|
||||
resolved, err = os.Readlink(resolved)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Re-stat to get the info for the resolved file.
|
||||
info, err = Lstat(resolved)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = walk(root, resolved, info, walkFn)
|
||||
}
|
||||
if err == filepath.SkipDir {
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -844,8 +844,8 @@ func TestWalkSymlink(t *testing.T) {
|
|||
{"control", "dir", []string{"dir", "dir" + string(filepath.Separator) + "file"}},
|
||||
// ensure Walk doesn't walk into the directory pointed to by the symlink
|
||||
// (because it's supposed to use Lstat instead of Stat).
|
||||
{"symlink_to_dir", "symlink", []string{"symlink"}},
|
||||
{"overlay_to_symlink_to_dir", "overlay_symlink", []string{"overlay_symlink"}},
|
||||
{"symlink_to_dir", "symlink", []string{"symlink", "symlink" + string(filepath.Separator) + "file"}},
|
||||
{"overlay_to_symlink_to_dir", "overlay_symlink", []string{"overlay_symlink", "overlay_symlink" + string(filepath.Separator) + "file"}},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
[!symlink] skip
|
||||
|
||||
symlink $WORK/gopath/src/sym -> $WORK/gopath/src/tree
|
||||
symlink $WORK/gopath/src/tree/squirrel -> $WORK/gopath/src/dir2 # this symlink should not be followed
|
||||
cd sym
|
||||
go list ./...
|
||||
cmp stdout $WORK/gopath/src/want_list.txt
|
||||
-- tree/go.mod --
|
||||
module example.com/tree
|
||||
|
||||
go 1.20
|
||||
-- tree/tree.go --
|
||||
package tree
|
||||
-- tree/branch/branch.go --
|
||||
package branch
|
||||
-- dir2/squirrel.go --
|
||||
package squirrel
|
||||
-- want_list.txt --
|
||||
example.com/tree
|
||||
example.com/tree/branch
|
||||
Loading…
Reference in New Issue