godoc: don't try to follow all symlinks

Revert https://golang.org/cl/45096.

Original change description:
    godoc: follow symbolic links to folders in GOROOT

    Directory walking in godoc relies on ReadDir which returns the result
    of os.Lstat.

    Instead make the the OS VFS's ReadDir use os.Stat on symlinks before
    returning.

Updates golang/go#15049
Fixes golang/go#21061

Change-Id: Ieaa7923d85842f3da5696a7f46134d16407dae66
Reviewed-on: https://go-review.googlesource.com/53634
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/godoc/vfs/os.go b/godoc/vfs/os.go
index e107069..fa98142 100644
--- a/godoc/vfs/os.go
+++ b/godoc/vfs/os.go
@@ -7,11 +7,9 @@
 import (
 	"fmt"
 	"io/ioutil"
-	"log"
 	"os"
 	pathpkg "path"
 	"path/filepath"
-	"strings"
 )
 
 // OS returns an implementation of FileSystem reading from the
@@ -59,35 +57,9 @@
 }
 
 func (root osFS) Stat(path string) (os.FileInfo, error) {
-	return stat(root.resolve(path))
+	return os.Stat(root.resolve(path))
 }
 
-var readdir = ioutil.ReadDir // for testing
-var stat = os.Stat           // for testing
-
 func (root osFS) ReadDir(path string) ([]os.FileInfo, error) {
-	fis, err := readdir(root.resolve(path))
-	if err != nil {
-		return fis, err
-	}
-	ret := fis[:0]
-
-	// reread the files with os.Stat since they might be symbolic links
-	for _, fi := range fis {
-		if fi.Mode()&os.ModeSymlink != 0 {
-			baseName := fi.Name()
-			fi, err = root.Stat(pathpkg.Join(path, baseName))
-			if err != nil {
-				if os.IsNotExist(err) && strings.HasPrefix(baseName, ".") {
-					// Ignore editor spam files without log spam.
-					continue
-				}
-				log.Printf("ignoring symlink: %v", err)
-				continue
-			}
-		}
-		ret = append(ret, fi)
-	}
-
-	return ret, nil // is sorted
+	return ioutil.ReadDir(root.resolve(path)) // is sorted
 }
diff --git a/godoc/vfs/os_test.go b/godoc/vfs/os_test.go
deleted file mode 100644
index a22596f..0000000
--- a/godoc/vfs/os_test.go
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2017 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package vfs
-
-import (
-	"bytes"
-	"errors"
-	"fmt"
-	"os"
-	"path/filepath"
-	"testing"
-	"time"
-)
-
-type fakeFileInfo struct {
-	dir      bool
-	link     bool
-	basename string
-	modtime  time.Time
-	ents     []*fakeFileInfo
-	contents string
-	err      error
-}
-
-func (f *fakeFileInfo) Name() string       { return f.basename }
-func (f *fakeFileInfo) Sys() interface{}   { return nil }
-func (f *fakeFileInfo) ModTime() time.Time { return f.modtime }
-func (f *fakeFileInfo) IsDir() bool        { return f.dir }
-func (f *fakeFileInfo) Size() int64        { return int64(len(f.contents)) }
-func (f *fakeFileInfo) Mode() os.FileMode {
-	if f.dir {
-		return 0755 | os.ModeDir
-	}
-	if f.link {
-		return 0644 | os.ModeSymlink
-	}
-	return 0644
-}
-
-func TestOSReadDirFollowsSymLinks(t *testing.T) {
-	// Stat is called on ReadDir output by osFS
-	oldstat := stat
-	stat = func(path string) (os.FileInfo, error) {
-		if filepath.ToSlash(path) != "/tmp/subdir/is_link" {
-			t.Fatalf("stat called on unexpected path %q", path)
-		}
-		return &fakeFileInfo{
-			link:     false,
-			basename: "foo",
-		}, nil
-	}
-	defer func() { stat = oldstat }()
-
-	oldreaddir := readdir
-	readdir = func(path string) ([]os.FileInfo, error) {
-		return []os.FileInfo{
-			&fakeFileInfo{
-				link:     true,
-				basename: "is_link",
-			},
-			&fakeFileInfo{
-				link:     false,
-				basename: "not_link",
-			},
-		}, nil
-	}
-	defer func() { readdir = oldreaddir }()
-
-	fs := OS("/tmp")
-	result, err := fs.ReadDir("subdir")
-
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	var gotBuf bytes.Buffer
-	for i, fi := range result {
-		fmt.Fprintf(&gotBuf, "result[%d] = %v, %v\n", i, fi.Name(), fi.Mode())
-	}
-	got := gotBuf.String()
-	want := `result[0] = foo, -rw-r--r--
-result[1] = not_link, -rw-r--r--
-`
-	if got != want {
-		t.Errorf("ReadDir got:\n%s\n\nwant:\n%s\n", got, want)
-	}
-}
-
-func TestOSReadDirHandlesReadDirErrors(t *testing.T) {
-	oldreaddir := readdir
-	readdir = func(path string) ([]os.FileInfo, error) {
-		return []os.FileInfo{
-			&fakeFileInfo{
-				dir:      false,
-				basename: "foo",
-			},
-		}, errors.New("some arbitrary filesystem failure")
-	}
-	defer func() { readdir = oldreaddir }()
-
-	fs := OS("/tmp")
-	_, err := fs.ReadDir("subdir")
-
-	if got, want := fmt.Sprint(err), "some arbitrary filesystem failure"; got != want {
-		t.Errorf("ReadDir = %v; want %q", got, want)
-	}
-}