internal/godoc: remove vfs

Change-Id: I508d92508553be76e42b4066e540c146e1c9ba53
Reviewed-on: https://go-review.googlesource.com/c/website/+/293490
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
diff --git a/internal/godoc/vfs/emptyvfs.go b/internal/godoc/vfs/emptyvfs.go
deleted file mode 100644
index 24954b1..0000000
--- a/internal/godoc/vfs/emptyvfs.go
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2016 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 (
-	"fmt"
-	"os"
-	"time"
-)
-
-// NewNameSpace returns a NameSpace pre-initialized with an empty
-// emulated directory mounted on the root mount point "/". This
-// allows directory traversal routines to work properly even if
-// a folder is not explicitly mounted at root by the user.
-func NewNameSpace() NameSpace {
-	ns := NameSpace{}
-	ns.Bind("/", &emptyVFS{}, "/", BindReplace)
-	return ns
-}
-
-// type emptyVFS emulates a FileSystem consisting of an empty directory
-type emptyVFS struct{}
-
-// Open implements Opener. Since emptyVFS is an empty directory, all
-// attempts to open a file should returns errors.
-func (e *emptyVFS) Open(path string) (ReadSeekCloser, error) {
-	if path == "/" {
-		return nil, fmt.Errorf("open: / is a directory")
-	}
-	return nil, os.ErrNotExist
-}
-
-// Stat returns os.FileInfo for an empty directory if the path is
-// is root "/" or error. os.FileInfo is implemented by emptyVFS
-func (e *emptyVFS) Stat(path string) (os.FileInfo, error) {
-	if path == "/" {
-		return e, nil
-	}
-	return nil, os.ErrNotExist
-}
-
-func (e *emptyVFS) Lstat(path string) (os.FileInfo, error) {
-	return e.Stat(path)
-}
-
-// ReadDir returns an empty os.FileInfo slice for "/", else error.
-func (e *emptyVFS) ReadDir(path string) ([]os.FileInfo, error) {
-	if path == "/" {
-		return []os.FileInfo{}, nil
-	}
-	return nil, os.ErrNotExist
-}
-
-func (e *emptyVFS) String() string {
-	return "emptyVFS(/)"
-}
-
-// These functions below implement os.FileInfo for the single
-// empty emulated directory.
-
-func (e *emptyVFS) Name() string {
-	return "/"
-}
-
-func (e *emptyVFS) Size() int64 {
-	return 0
-}
-
-func (e *emptyVFS) Mode() os.FileMode {
-	return os.ModeDir | os.ModePerm
-}
-
-func (e *emptyVFS) ModTime() time.Time {
-	return time.Time{}
-}
-
-func (e *emptyVFS) IsDir() bool {
-	return true
-}
-
-func (e *emptyVFS) Sys() interface{} {
-	return nil
-}
diff --git a/internal/godoc/vfs/fs.go b/internal/godoc/vfs/fs.go
deleted file mode 100644
index 2f122b9..0000000
--- a/internal/godoc/vfs/fs.go
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2021 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.
-
-//go:build go1.16
-// +build go1.16
-
-package vfs
-
-import (
-	"io/fs"
-	"os"
-	"path"
-	"strings"
-)
-
-// FromFS converts an fs.FS to the FileSystem interface.
-func FromFS(fsys fs.FS) FileSystem {
-	return &fsysToFileSystem{fsys}
-}
-
-type fsysToFileSystem struct {
-	fsys fs.FS
-}
-
-func (f *fsysToFileSystem) fsPath(name string) string {
-	name = path.Clean(name)
-	if name == "/" {
-		return "."
-	}
-	return strings.TrimPrefix(name, "/")
-}
-
-func (f *fsysToFileSystem) Open(name string) (ReadSeekCloser, error) {
-	file, err := f.fsys.Open(f.fsPath(name))
-	if err != nil {
-		return nil, err
-	}
-	if rsc, ok := file.(ReadSeekCloser); ok {
-		return rsc, nil
-	}
-	return &noSeekFile{f.fsPath(name), file}, nil
-}
-
-func (f *fsysToFileSystem) Lstat(name string) (os.FileInfo, error) {
-	return fs.Stat(f.fsys, f.fsPath(name))
-}
-
-func (f *fsysToFileSystem) Stat(name string) (os.FileInfo, error) {
-	return fs.Stat(f.fsys, f.fsPath(name))
-}
-
-func (f *fsysToFileSystem) ReadDir(name string) ([]os.FileInfo, error) {
-	dirs, err := fs.ReadDir(f.fsys, f.fsPath(name))
-	var infos []os.FileInfo
-	for _, d := range dirs {
-		info, err1 := d.Info()
-		if err1 != nil {
-			if err == nil {
-				err = err1
-			}
-			continue
-		}
-		infos = append(infos, info)
-	}
-	return infos, err
-}
-
-func (f *fsysToFileSystem) String() string { return "io/fs" }
-
-type noSeekFile struct {
-	path string
-	fs.File
-}
-
-func (f *noSeekFile) Seek(offset int64, whence int) (int64, error) {
-	return 0, &fs.PathError{Op: "seek", Path: f.path, Err: fs.ErrInvalid}
-}
diff --git a/internal/godoc/vfs/gatefs/gatefs.go b/internal/godoc/vfs/gatefs/gatefs.go
deleted file mode 100644
index 1c2d8fa..0000000
--- a/internal/godoc/vfs/gatefs/gatefs.go
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2013 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 gatefs provides an implementation of the FileSystem
-// interface that wraps another FileSystem and limits its concurrency.
-package gatefs // import "golang.org/x/website/internal/godoc/vfs/gatefs"
-
-import (
-	"fmt"
-	"os"
-
-	"golang.org/x/website/internal/godoc/vfs"
-)
-
-// New returns a new FileSystem that delegates to fs.
-// If gateCh is non-nil and buffered, it's used as a gate
-// to limit concurrency on calls to fs.
-func New(fs vfs.FileSystem, gateCh chan bool) vfs.FileSystem {
-	if cap(gateCh) == 0 {
-		return fs
-	}
-	return gatefs{fs, gate(gateCh)}
-}
-
-type gate chan bool
-
-func (g gate) enter() { g <- true }
-func (g gate) leave() { <-g }
-
-type gatefs struct {
-	fs vfs.FileSystem
-	gate
-}
-
-func (fs gatefs) String() string {
-	return fmt.Sprintf("gated(%s, %d)", fs.fs.String(), cap(fs.gate))
-}
-
-func (fs gatefs) Open(p string) (vfs.ReadSeekCloser, error) {
-	fs.enter()
-	defer fs.leave()
-	rsc, err := fs.fs.Open(p)
-	if err != nil {
-		return nil, err
-	}
-	return gatef{rsc, fs.gate}, nil
-}
-
-func (fs gatefs) Lstat(p string) (os.FileInfo, error) {
-	fs.enter()
-	defer fs.leave()
-	return fs.fs.Lstat(p)
-}
-
-func (fs gatefs) Stat(p string) (os.FileInfo, error) {
-	fs.enter()
-	defer fs.leave()
-	return fs.fs.Stat(p)
-}
-
-func (fs gatefs) ReadDir(p string) ([]os.FileInfo, error) {
-	fs.enter()
-	defer fs.leave()
-	return fs.fs.ReadDir(p)
-}
-
-type gatef struct {
-	rsc vfs.ReadSeekCloser
-	gate
-}
-
-func (f gatef) Read(p []byte) (n int, err error) {
-	f.enter()
-	defer f.leave()
-	return f.rsc.Read(p)
-}
-
-func (f gatef) Seek(offset int64, whence int) (ret int64, err error) {
-	f.enter()
-	defer f.leave()
-	return f.rsc.Seek(offset, whence)
-}
-
-func (f gatef) Close() error {
-	f.enter()
-	defer f.leave()
-	return f.rsc.Close()
-}
diff --git a/internal/godoc/vfs/httpfs/httpfs.go b/internal/godoc/vfs/httpfs/httpfs.go
deleted file mode 100644
index 292366a..0000000
--- a/internal/godoc/vfs/httpfs/httpfs.go
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2013 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 httpfs implements http.FileSystem using a godoc vfs.FileSystem.
-package httpfs // import "golang.org/x/website/internal/godoc/vfs/httpfs"
-
-import (
-	"fmt"
-	"io"
-	"net/http"
-	"os"
-
-	"golang.org/x/website/internal/godoc/vfs"
-)
-
-func New(fs vfs.FileSystem) http.FileSystem {
-	return &httpFS{fs}
-}
-
-type httpFS struct {
-	fs vfs.FileSystem
-}
-
-func (h *httpFS) Open(name string) (http.File, error) {
-	fi, err := h.fs.Stat(name)
-	if err != nil {
-		return nil, err
-	}
-	if fi.IsDir() {
-		return &httpDir{h.fs, name, nil}, nil
-	}
-	f, err := h.fs.Open(name)
-	if err != nil {
-		return nil, err
-	}
-	return &httpFile{h.fs, f, name}, nil
-}
-
-// httpDir implements http.File for a directory in a FileSystem.
-type httpDir struct {
-	fs      vfs.FileSystem
-	name    string
-	pending []os.FileInfo
-}
-
-func (h *httpDir) Close() error               { return nil }
-func (h *httpDir) Stat() (os.FileInfo, error) { return h.fs.Stat(h.name) }
-func (h *httpDir) Read([]byte) (int, error) {
-	return 0, fmt.Errorf("cannot Read from directory %s", h.name)
-}
-
-func (h *httpDir) Seek(offset int64, whence int) (int64, error) {
-	if offset == 0 && whence == 0 {
-		h.pending = nil
-		return 0, nil
-	}
-	return 0, fmt.Errorf("unsupported Seek in directory %s", h.name)
-}
-
-func (h *httpDir) Readdir(count int) ([]os.FileInfo, error) {
-	if h.pending == nil {
-		d, err := h.fs.ReadDir(h.name)
-		if err != nil {
-			return nil, err
-		}
-		if d == nil {
-			d = []os.FileInfo{} // not nil
-		}
-		h.pending = d
-	}
-
-	if len(h.pending) == 0 && count > 0 {
-		return nil, io.EOF
-	}
-	if count <= 0 || count > len(h.pending) {
-		count = len(h.pending)
-	}
-	d := h.pending[:count]
-	h.pending = h.pending[count:]
-	return d, nil
-}
-
-// httpFile implements http.File for a file (not directory) in a FileSystem.
-type httpFile struct {
-	fs vfs.FileSystem
-	vfs.ReadSeekCloser
-	name string
-}
-
-func (h *httpFile) Stat() (os.FileInfo, error) { return h.fs.Stat(h.name) }
-func (h *httpFile) Readdir(int) ([]os.FileInfo, error) {
-	return nil, fmt.Errorf("cannot Readdir from file %s", h.name)
-}
diff --git a/internal/godoc/vfs/mapfs/mapfs.go b/internal/godoc/vfs/mapfs/mapfs.go
deleted file mode 100644
index e0aebe3..0000000
--- a/internal/godoc/vfs/mapfs/mapfs.go
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright 2013 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 mapfs file provides an implementation of the FileSystem
-// interface based on the contents of a map[string]string.
-package mapfs // import "golang.org/x/website/internal/godoc/vfs/mapfs"
-
-import (
-	"fmt"
-	"io"
-	"os"
-	pathpkg "path"
-	"sort"
-	"strings"
-	"time"
-
-	"golang.org/x/website/internal/godoc/vfs"
-)
-
-// New returns a new FileSystem from the provided map.
-// Map keys must be forward slash-separated paths with
-// no leading slash, such as "file1.txt" or "dir/file2.txt".
-// New panics if any of the paths contain a leading slash.
-func New(m map[string]string) vfs.FileSystem {
-	// Verify all provided paths are relative before proceeding.
-	var pathsWithLeadingSlash []string
-	for p := range m {
-		if strings.HasPrefix(p, "/") {
-			pathsWithLeadingSlash = append(pathsWithLeadingSlash, p)
-		}
-	}
-	if len(pathsWithLeadingSlash) > 0 {
-		panic(fmt.Errorf("mapfs.New: invalid paths with a leading slash: %q", pathsWithLeadingSlash))
-	}
-
-	return mapFS(m)
-}
-
-// mapFS is the map based implementation of FileSystem
-type mapFS map[string]string
-
-func (fs mapFS) String() string { return "mapfs" }
-
-func (fs mapFS) Close() error { return nil }
-
-func filename(p string) string {
-	return strings.TrimPrefix(p, "/")
-}
-
-func (fs mapFS) Open(p string) (vfs.ReadSeekCloser, error) {
-	b, ok := fs[filename(p)]
-	if !ok {
-		return nil, os.ErrNotExist
-	}
-	return nopCloser{strings.NewReader(b)}, nil
-}
-
-func fileInfo(name, contents string) os.FileInfo {
-	return mapFI{name: pathpkg.Base(name), size: len(contents)}
-}
-
-func dirInfo(name string) os.FileInfo {
-	return mapFI{name: pathpkg.Base(name), dir: true}
-}
-
-func (fs mapFS) Lstat(p string) (os.FileInfo, error) {
-	b, ok := fs[filename(p)]
-	if ok {
-		return fileInfo(p, b), nil
-	}
-	ents, _ := fs.ReadDir(p)
-	if len(ents) > 0 {
-		return dirInfo(p), nil
-	}
-	return nil, os.ErrNotExist
-}
-
-func (fs mapFS) Stat(p string) (os.FileInfo, error) {
-	return fs.Lstat(p)
-}
-
-// slashdir returns path.Dir(p), but special-cases paths not beginning
-// with a slash to be in the root.
-func slashdir(p string) string {
-	d := pathpkg.Dir(p)
-	if d == "." {
-		return "/"
-	}
-	if strings.HasPrefix(p, "/") {
-		return d
-	}
-	return "/" + d
-}
-
-func (fs mapFS) ReadDir(p string) ([]os.FileInfo, error) {
-	p = pathpkg.Clean(p)
-	var ents []string
-	fim := make(map[string]os.FileInfo) // base -> fi
-	for fn, b := range fs {
-		dir := slashdir(fn)
-		isFile := true
-		var lastBase string
-		for {
-			if dir == p {
-				base := lastBase
-				if isFile {
-					base = pathpkg.Base(fn)
-				}
-				if fim[base] == nil {
-					var fi os.FileInfo
-					if isFile {
-						fi = fileInfo(fn, b)
-					} else {
-						fi = dirInfo(base)
-					}
-					ents = append(ents, base)
-					fim[base] = fi
-				}
-			}
-			if dir == "/" {
-				break
-			} else {
-				isFile = false
-				lastBase = pathpkg.Base(dir)
-				dir = pathpkg.Dir(dir)
-			}
-		}
-	}
-	if len(ents) == 0 {
-		return nil, os.ErrNotExist
-	}
-
-	sort.Strings(ents)
-	var list []os.FileInfo
-	for _, dir := range ents {
-		list = append(list, fim[dir])
-	}
-	return list, nil
-}
-
-// mapFI is the map-based implementation of FileInfo.
-type mapFI struct {
-	name string
-	size int
-	dir  bool
-}
-
-func (fi mapFI) IsDir() bool        { return fi.dir }
-func (fi mapFI) ModTime() time.Time { return time.Time{} }
-func (fi mapFI) Mode() os.FileMode {
-	if fi.IsDir() {
-		return 0755 | os.ModeDir
-	}
-	return 0444
-}
-func (fi mapFI) Name() string     { return pathpkg.Base(fi.name) }
-func (fi mapFI) Size() int64      { return int64(fi.size) }
-func (fi mapFI) Sys() interface{} { return nil }
-
-type nopCloser struct {
-	io.ReadSeeker
-}
-
-func (nc nopCloser) Close() error { return nil }
diff --git a/internal/godoc/vfs/mapfs/mapfs_test.go b/internal/godoc/vfs/mapfs/mapfs_test.go
deleted file mode 100644
index 6b7db29..0000000
--- a/internal/godoc/vfs/mapfs/mapfs_test.go
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2013 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 mapfs
-
-import (
-	"io/ioutil"
-	"os"
-	"reflect"
-	"testing"
-)
-
-func TestOpenRoot(t *testing.T) {
-	fs := New(map[string]string{
-		"foo/bar/three.txt": "a",
-		"foo/bar.txt":       "b",
-		"top.txt":           "c",
-		"other-top.txt":     "d",
-	})
-	tests := []struct {
-		path string
-		want string
-	}{
-		{"/foo/bar/three.txt", "a"},
-		{"foo/bar/three.txt", "a"},
-		{"foo/bar.txt", "b"},
-		{"top.txt", "c"},
-		{"/top.txt", "c"},
-		{"other-top.txt", "d"},
-		{"/other-top.txt", "d"},
-	}
-	for _, tt := range tests {
-		rsc, err := fs.Open(tt.path)
-		if err != nil {
-			t.Errorf("Open(%q) = %v", tt.path, err)
-			continue
-		}
-		slurp, err := ioutil.ReadAll(rsc)
-		if err != nil {
-			t.Error(err)
-		}
-		if string(slurp) != tt.want {
-			t.Errorf("Read(%q) = %q; want %q", tt.path, tt.want, slurp)
-		}
-		rsc.Close()
-	}
-
-	_, err := fs.Open("/xxxx")
-	if !os.IsNotExist(err) {
-		t.Errorf("ReadDir /xxxx = %v; want os.IsNotExist error", err)
-	}
-}
-
-func TestReaddir(t *testing.T) {
-	fs := New(map[string]string{
-		"foo/bar/three.txt": "333",
-		"foo/bar.txt":       "22",
-		"top.txt":           "top.txt file",
-		"other-top.txt":     "other-top.txt file",
-	})
-	tests := []struct {
-		dir  string
-		want []os.FileInfo
-	}{
-		{
-			dir: "/",
-			want: []os.FileInfo{
-				mapFI{name: "foo", dir: true},
-				mapFI{name: "other-top.txt", size: len("other-top.txt file")},
-				mapFI{name: "top.txt", size: len("top.txt file")},
-			},
-		},
-		{
-			dir: "/foo",
-			want: []os.FileInfo{
-				mapFI{name: "bar", dir: true},
-				mapFI{name: "bar.txt", size: 2},
-			},
-		},
-		{
-			dir: "/foo/",
-			want: []os.FileInfo{
-				mapFI{name: "bar", dir: true},
-				mapFI{name: "bar.txt", size: 2},
-			},
-		},
-		{
-			dir: "/foo/bar",
-			want: []os.FileInfo{
-				mapFI{name: "three.txt", size: 3},
-			},
-		},
-	}
-	for _, tt := range tests {
-		fis, err := fs.ReadDir(tt.dir)
-		if err != nil {
-			t.Errorf("ReadDir(%q) = %v", tt.dir, err)
-			continue
-		}
-		if !reflect.DeepEqual(fis, tt.want) {
-			t.Errorf("ReadDir(%q) = %#v; want %#v", tt.dir, fis, tt.want)
-			continue
-		}
-	}
-
-	_, err := fs.ReadDir("/xxxx")
-	if !os.IsNotExist(err) {
-		t.Errorf("ReadDir /xxxx = %v; want os.IsNotExist error", err)
-	}
-}
diff --git a/internal/godoc/vfs/namespace.go b/internal/godoc/vfs/namespace.go
deleted file mode 100644
index 38a6358..0000000
--- a/internal/godoc/vfs/namespace.go
+++ /dev/null
@@ -1,375 +0,0 @@
-// Copyright 2011 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 (
-	"fmt"
-	"io"
-	"os"
-	pathpkg "path"
-	"sort"
-	"strings"
-	"time"
-)
-
-// Setting debugNS = true will enable debugging prints about
-// name space translations.
-const debugNS = false
-
-// A NameSpace is a file system made up of other file systems
-// mounted at specific locations in the name space.
-//
-// The representation is a map from mount point locations
-// to the list of file systems mounted at that location.  A traditional
-// Unix mount table would use a single file system per mount point,
-// but we want to be able to mount multiple file systems on a single
-// mount point and have the system behave as if the union of those
-// file systems were present at the mount point.
-// For example, if the OS file system has a Go installation in
-// c:\Go and additional Go path trees in d:\Work1 and d:\Work2, then
-// this name space creates the view we want for the godoc server:
-//
-//	NameSpace{
-//		"/": {
-//			{old: "/", fs: OS(`c:\Go`), new: "/"},
-//		},
-//		"/src/pkg": {
-//			{old: "/src/pkg", fs: OS(`c:\Go`), new: "/src/pkg"},
-//			{old: "/src/pkg", fs: OS(`d:\Work1`), new: "/src"},
-//			{old: "/src/pkg", fs: OS(`d:\Work2`), new: "/src"},
-//		},
-//	}
-//
-// This is created by executing:
-//
-//	ns := NameSpace{}
-//	ns.Bind("/", OS(`c:\Go`), "/", BindReplace)
-//	ns.Bind("/src/pkg", OS(`d:\Work1`), "/src", BindAfter)
-//	ns.Bind("/src/pkg", OS(`d:\Work2`), "/src", BindAfter)
-//
-// A particular mount point entry is a triple (old, fs, new), meaning that to
-// operate on a path beginning with old, replace that prefix (old) with new
-// and then pass that path to the FileSystem implementation fs.
-//
-// If you do not explicitly mount a FileSystem at the root mountpoint "/" of the
-// NameSpace like above, Stat("/") will return a "not found" error which could
-// break typical directory traversal routines. In such cases, use NewNameSpace()
-// to get a NameSpace pre-initialized with an emulated empty directory at root.
-//
-// Given this name space, a ReadDir of /src/pkg/code will check each prefix
-// of the path for a mount point (first /src/pkg/code, then /src/pkg, then /src,
-// then /), stopping when it finds one.  For the above example, /src/pkg/code
-// will find the mount point at /src/pkg:
-//
-//	{old: "/src/pkg", fs: OS(`c:\Go`), new: "/src/pkg"},
-//	{old: "/src/pkg", fs: OS(`d:\Work1`), new: "/src"},
-//	{old: "/src/pkg", fs: OS(`d:\Work2`), new: "/src"},
-//
-// ReadDir will when execute these three calls and merge the results:
-//
-//	OS(`c:\Go`).ReadDir("/src/pkg/code")
-//	OS(`d:\Work1').ReadDir("/src/code")
-//	OS(`d:\Work2').ReadDir("/src/code")
-//
-// Note that the "/src/pkg" in "/src/pkg/code" has been replaced by
-// just "/src" in the final two calls.
-//
-// OS is itself an implementation of a file system: it implements
-// OS(`c:\Go`).ReadDir("/src/pkg/code") as ioutil.ReadDir(`c:\Go\src\pkg\code`).
-//
-// Because the new path is evaluated by fs (here OS(root)), another way
-// to read the mount table is to mentally combine fs+new, so that this table:
-//
-//	{old: "/src/pkg", fs: OS(`c:\Go`), new: "/src/pkg"},
-//	{old: "/src/pkg", fs: OS(`d:\Work1`), new: "/src"},
-//	{old: "/src/pkg", fs: OS(`d:\Work2`), new: "/src"},
-//
-// reads as:
-//
-//	"/src/pkg" -> c:\Go\src\pkg
-//	"/src/pkg" -> d:\Work1\src
-//	"/src/pkg" -> d:\Work2\src
-//
-// An invariant (a redundancy) of the name space representation is that
-// ns[mtpt][i].old is always equal to mtpt (in the example, ns["/src/pkg"]'s
-// mount table entries always have old == "/src/pkg").  The 'old' field is
-// useful to callers, because they receive just a []mountedFS and not any
-// other indication of which mount point was found.
-//
-type NameSpace map[string][]mountedFS
-
-// A mountedFS handles requests for path by replacing
-// a prefix 'old' with 'new' and then calling the fs methods.
-type mountedFS struct {
-	old string
-	fs  FileSystem
-	new string
-}
-
-// hasPathPrefix reports whether x == y or x == y + "/" + more.
-func hasPathPrefix(x, y string) bool {
-	return x == y || strings.HasPrefix(x, y) && (strings.HasSuffix(y, "/") || strings.HasPrefix(x[len(y):], "/"))
-}
-
-// translate translates path for use in m, replacing old with new.
-//
-// mountedFS{"/src/pkg", fs, "/src"}.translate("/src/pkg/code") == "/src/code".
-func (m mountedFS) translate(path string) string {
-	path = pathpkg.Clean("/" + path)
-	if !hasPathPrefix(path, m.old) {
-		panic("translate " + path + " but old=" + m.old)
-	}
-	return pathpkg.Join(m.new, path[len(m.old):])
-}
-
-func (NameSpace) String() string {
-	return "ns"
-}
-
-// Fprint writes a text representation of the name space to w.
-func (ns NameSpace) Fprint(w io.Writer) {
-	fmt.Fprint(w, "name space {\n")
-	var all []string
-	for mtpt := range ns {
-		all = append(all, mtpt)
-	}
-	sort.Strings(all)
-	for _, mtpt := range all {
-		fmt.Fprintf(w, "\t%s:\n", mtpt)
-		for _, m := range ns[mtpt] {
-			fmt.Fprintf(w, "\t\t%s %s\n", m.fs, m.new)
-		}
-	}
-	fmt.Fprint(w, "}\n")
-}
-
-// clean returns a cleaned, rooted path for evaluation.
-// It canonicalizes the path so that we can use string operations
-// to analyze it.
-func (NameSpace) clean(path string) string {
-	return pathpkg.Clean("/" + path)
-}
-
-type BindMode int
-
-const (
-	BindReplace BindMode = iota
-	BindBefore
-	BindAfter
-)
-
-// Bind causes references to old to redirect to the path new in newfs.
-// If mode is BindReplace, old redirections are discarded.
-// If mode is BindBefore, this redirection takes priority over existing ones,
-// but earlier ones are still consulted for paths that do not exist in newfs.
-// If mode is BindAfter, this redirection happens only after existing ones
-// have been tried and failed.
-func (ns NameSpace) Bind(old string, newfs FileSystem, new string, mode BindMode) {
-	old = ns.clean(old)
-	new = ns.clean(new)
-	m := mountedFS{old, newfs, new}
-	var mtpt []mountedFS
-	switch mode {
-	case BindReplace:
-		mtpt = append(mtpt, m)
-	case BindAfter:
-		mtpt = append(mtpt, ns.resolve(old)...)
-		mtpt = append(mtpt, m)
-	case BindBefore:
-		mtpt = append(mtpt, m)
-		mtpt = append(mtpt, ns.resolve(old)...)
-	}
-
-	// Extend m.old, m.new in inherited mount point entries.
-	for i := range mtpt {
-		m := &mtpt[i]
-		if m.old != old {
-			if !hasPathPrefix(old, m.old) {
-				// This should not happen.  If it does, panic so
-				// that we can see the call trace that led to it.
-				panic(fmt.Sprintf("invalid Bind: old=%q m={%q, %s, %q}", old, m.old, m.fs.String(), m.new))
-			}
-			suffix := old[len(m.old):]
-			m.old = pathpkg.Join(m.old, suffix)
-			m.new = pathpkg.Join(m.new, suffix)
-		}
-	}
-
-	ns[old] = mtpt
-}
-
-// resolve resolves a path to the list of mountedFS to use for path.
-func (ns NameSpace) resolve(path string) []mountedFS {
-	path = ns.clean(path)
-	for {
-		if m := ns[path]; m != nil {
-			if debugNS {
-				fmt.Printf("resolve %s: %v\n", path, m)
-			}
-			return m
-		}
-		if path == "/" {
-			break
-		}
-		path = pathpkg.Dir(path)
-	}
-	return nil
-}
-
-// Open implements the FileSystem Open method.
-func (ns NameSpace) Open(path string) (ReadSeekCloser, error) {
-	var err error
-	for _, m := range ns.resolve(path) {
-		if debugNS {
-			fmt.Printf("tx %s: %v\n", path, m.translate(path))
-		}
-		tp := m.translate(path)
-		r, err1 := m.fs.Open(tp)
-		if err1 == nil {
-			return r, nil
-		}
-		// IsNotExist errors in overlay FSes can mask real errors in
-		// the underlying FS, so ignore them if there is another error.
-		if err == nil || os.IsNotExist(err) {
-			err = err1
-		}
-	}
-	if err == nil {
-		err = &os.PathError{Op: "open", Path: path, Err: os.ErrNotExist}
-	}
-	return nil, err
-}
-
-// stat implements the FileSystem Stat and Lstat methods.
-func (ns NameSpace) stat(path string, f func(FileSystem, string) (os.FileInfo, error)) (os.FileInfo, error) {
-	var err error
-	for _, m := range ns.resolve(path) {
-		fi, err1 := f(m.fs, m.translate(path))
-		if err1 == nil {
-			return fi, nil
-		}
-		if err == nil {
-			err = err1
-		}
-	}
-	if err == nil {
-		err = &os.PathError{Op: "stat", Path: path, Err: os.ErrNotExist}
-	}
-	return nil, err
-}
-
-func (ns NameSpace) Stat(path string) (os.FileInfo, error) {
-	return ns.stat(path, FileSystem.Stat)
-}
-
-func (ns NameSpace) Lstat(path string) (os.FileInfo, error) {
-	return ns.stat(path, FileSystem.Lstat)
-}
-
-// dirInfo is a trivial implementation of os.FileInfo for a directory.
-type dirInfo string
-
-func (d dirInfo) Name() string       { return string(d) }
-func (d dirInfo) Size() int64        { return 0 }
-func (d dirInfo) Mode() os.FileMode  { return os.ModeDir | 0555 }
-func (d dirInfo) ModTime() time.Time { return startTime }
-func (d dirInfo) IsDir() bool        { return true }
-func (d dirInfo) Sys() interface{}   { return nil }
-
-var startTime = time.Now()
-
-// ReadDir implements the FileSystem ReadDir method.  It's where most of the magic is.
-// (The rest is in resolve.)
-//
-// Logically, ReadDir must return the union of all the directories that are named
-// by path.  In order to avoid misinterpreting Go packages, of all the directories
-// that contain Go source code, we only include the files from the first,
-// but we include subdirectories from all.
-//
-// ReadDir must also return directory entries needed to reach mount points.
-// If the name space looks like the example in the type NameSpace comment,
-// but c:\Go does not have a src/pkg subdirectory, we still want to be able
-// to find that subdirectory, because we've mounted d:\Work1 and d:\Work2
-// there.  So if we don't see "src" in the directory listing for c:\Go, we add an
-// entry for it before returning.
-//
-func (ns NameSpace) ReadDir(path string) ([]os.FileInfo, error) {
-	path = ns.clean(path)
-
-	// List matching directories and determine whether any of them contain
-	// Go files.
-	var (
-		dirs       [][]os.FileInfo
-		goDirIndex = -1
-		readDirErr error
-	)
-
-	for _, m := range ns.resolve(path) {
-		dir, err := m.fs.ReadDir(m.translate(path))
-		if err != nil {
-			if readDirErr == nil {
-				readDirErr = err
-			}
-			continue
-		}
-
-		dirs = append(dirs, dir)
-
-		if goDirIndex < 0 {
-			for _, f := range dir {
-				if !f.IsDir() && strings.HasSuffix(f.Name(), ".go") {
-					goDirIndex = len(dirs) - 1
-					break
-				}
-			}
-		}
-	}
-
-	// Build a list of files and subdirectories. If a directory contains Go files,
-	// only include files from that directory. Otherwise, include files from
-	// all directories. Include subdirectories from all directories regardless
-	// of whether Go files are present.
-	haveName := make(map[string]bool)
-	var all []os.FileInfo
-	for i, dir := range dirs {
-		for _, f := range dir {
-			name := f.Name()
-			if !haveName[name] && (f.IsDir() || goDirIndex < 0 || goDirIndex == i) {
-				all = append(all, f)
-				haveName[name] = true
-			}
-		}
-	}
-
-	// Add any missing directories needed to reach mount points.
-	for old := range ns {
-		if hasPathPrefix(old, path) && old != path {
-			// Find next element after path in old.
-			elem := old[len(path):]
-			elem = strings.TrimPrefix(elem, "/")
-			if i := strings.Index(elem, "/"); i >= 0 {
-				elem = elem[:i]
-			}
-			if !haveName[elem] {
-				haveName[elem] = true
-				all = append(all, dirInfo(elem))
-			}
-		}
-	}
-
-	if len(all) == 0 {
-		return nil, readDirErr
-	}
-
-	sort.Sort(byName(all))
-	return all, nil
-}
-
-// byName implements sort.Interface.
-type byName []os.FileInfo
-
-func (f byName) Len() int           { return len(f) }
-func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
-func (f byName) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }
diff --git a/internal/godoc/vfs/namespace_test.go b/internal/godoc/vfs/namespace_test.go
deleted file mode 100644
index 32b5e96..0000000
--- a/internal/godoc/vfs/namespace_test.go
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2016 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_test
-
-import (
-	"fmt"
-	"strings"
-	"testing"
-	"time"
-
-	"golang.org/x/website/internal/godoc/vfs"
-	"golang.org/x/website/internal/godoc/vfs/mapfs"
-)
-
-func TestNewNameSpace(t *testing.T) {
-
-	// We will mount this filesystem under /fs1
-	mount := mapfs.New(map[string]string{"fs1file": "abcdefgh"})
-
-	// Existing process. This should give error on Stat("/")
-	t1 := vfs.NameSpace{}
-	t1.Bind("/fs1", mount, "/", vfs.BindReplace)
-
-	// using NewNameSpace. This should work fine.
-	t2 := vfs.NewNameSpace()
-	t2.Bind("/fs1", mount, "/", vfs.BindReplace)
-
-	testcases := map[string][]bool{
-		"/":            {false, true},
-		"/fs1":         {true, true},
-		"/fs1/fs1file": {true, true},
-	}
-
-	fss := []vfs.FileSystem{t1, t2}
-
-	for j, fs := range fss {
-		for k, v := range testcases {
-			_, err := fs.Stat(k)
-			result := err == nil
-			if result != v[j] {
-				t.Errorf("fs: %d, testcase: %s, want: %v, got: %v, err: %s", j, k, v[j], result, err)
-			}
-		}
-	}
-
-	fi, err := t2.Stat("/")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if fi.Name() != "/" {
-		t.Errorf("t2.Name() : want:%s got:%s", "/", fi.Name())
-	}
-
-	if !fi.ModTime().IsZero() {
-		t.Errorf("t2.ModTime() : want:%v got:%v", time.Time{}, fi.ModTime())
-	}
-}
-
-func TestReadDirUnion(t *testing.T) {
-	for _, tc := range []struct {
-		desc       string
-		ns         vfs.NameSpace
-		path, want string
-	}{
-		{
-			desc: "no_go_files",
-			ns: func() vfs.NameSpace {
-				rootFs := mapfs.New(map[string]string{
-					"doc/a.txt":       "1",
-					"doc/b.txt":       "1",
-					"doc/dir1/d1.txt": "",
-				})
-				docFs := mapfs.New(map[string]string{
-					"doc/a.txt":       "22",
-					"doc/dir2/d2.txt": "",
-				})
-				ns := vfs.NameSpace{}
-				ns.Bind("/", rootFs, "/", vfs.BindReplace)
-				ns.Bind("/doc", docFs, "/doc", vfs.BindBefore)
-				return ns
-			}(),
-			path: "/doc",
-			want: "a.txt:2,b.txt:1,dir1:0,dir2:0",
-		}, {
-			desc: "have_go_files",
-			ns: func() vfs.NameSpace {
-				a := mapfs.New(map[string]string{
-					"src/x/a.txt":        "",
-					"src/x/suba/sub.txt": "",
-				})
-				b := mapfs.New(map[string]string{
-					"src/x/b.go":         "package b",
-					"src/x/subb/sub.txt": "",
-				})
-				c := mapfs.New(map[string]string{
-					"src/x/c.txt":        "",
-					"src/x/subc/sub.txt": "",
-				})
-				ns := vfs.NameSpace{}
-				ns.Bind("/", a, "/", vfs.BindReplace)
-				ns.Bind("/", b, "/", vfs.BindAfter)
-				ns.Bind("/", c, "/", vfs.BindAfter)
-				return ns
-			}(),
-			path: "/src/x",
-			want: "b.go:9,suba:0,subb:0,subc:0",
-		}, {
-			desc: "empty_mount",
-			ns: func() vfs.NameSpace {
-				ns := vfs.NameSpace{}
-				ns.Bind("/empty", mapfs.New(nil), "/empty", vfs.BindReplace)
-				return ns
-			}(),
-			path: "/",
-			want: "empty:0",
-		},
-	} {
-		t.Run(tc.desc, func(t *testing.T) {
-			fis, err := tc.ns.ReadDir(tc.path)
-			if err != nil {
-				t.Fatal(err)
-			}
-			buf := &strings.Builder{}
-			sep := ""
-			for _, fi := range fis {
-				fmt.Fprintf(buf, "%s%s:%d", sep, fi.Name(), fi.Size())
-				sep = ","
-			}
-			if got := buf.String(); got != tc.want {
-				t.Errorf("got %q; want %q", got, tc.want)
-			}
-		})
-	}
-}
diff --git a/internal/godoc/vfs/os.go b/internal/godoc/vfs/os.go
deleted file mode 100644
index 7b6025b..0000000
--- a/internal/godoc/vfs/os.go
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2013 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 (
-	"fmt"
-	"io/ioutil"
-	"os"
-	pathpkg "path"
-	"path/filepath"
-	"runtime"
-)
-
-// We expose a new variable because otherwise we need to copy the findGOROOT logic again
-// from cmd/godoc which is already copied twice from the standard library.
-
-// GOROOT is the GOROOT path under which the godoc binary is running.
-// It is needed to check whether a filesystem root is under GOROOT or not.
-// This is set from cmd/godoc/main.go.
-var GOROOT = runtime.GOROOT()
-
-// OS returns an implementation of FileSystem reading from the
-// tree rooted at root.  Recording a root is convenient everywhere
-// but necessary on Windows, because the slash-separated path
-// passed to Open has no way to specify a drive letter.  Using a root
-// lets code refer to OS(`c:\`), OS(`d:\`) and so on.
-func OS(root string) FileSystem {
-	return osFS{rootPath: root}
-}
-
-type osFS struct {
-	rootPath string
-}
-
-func (root osFS) String() string { return "os(" + root.rootPath + ")" }
-
-func (root osFS) resolve(path string) string {
-	// Clean the path so that it cannot possibly begin with ../.
-	// If it did, the result of filepath.Join would be outside the
-	// tree rooted at root.  We probably won't ever see a path
-	// with .. in it, but be safe anyway.
-	path = pathpkg.Clean("/" + path)
-
-	return filepath.Join(root.rootPath, path)
-}
-
-func (root osFS) Open(path string) (ReadSeekCloser, error) {
-	f, err := os.Open(root.resolve(path))
-	if err != nil {
-		return nil, err
-	}
-	fi, err := f.Stat()
-	if err != nil {
-		f.Close()
-		return nil, err
-	}
-	if fi.IsDir() {
-		f.Close()
-		return nil, fmt.Errorf("Open: %s is a directory", path)
-	}
-	return f, nil
-}
-
-func (root osFS) Lstat(path string) (os.FileInfo, error) {
-	return os.Lstat(root.resolve(path))
-}
-
-func (root osFS) Stat(path string) (os.FileInfo, error) {
-	return os.Stat(root.resolve(path))
-}
-
-func (root osFS) ReadDir(path string) ([]os.FileInfo, error) {
-	return ioutil.ReadDir(root.resolve(path)) // is sorted
-}
diff --git a/internal/godoc/vfs/vfs.go b/internal/godoc/vfs/vfs.go
deleted file mode 100644
index ecc54d0..0000000
--- a/internal/godoc/vfs/vfs.go
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2013 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 defines types for abstract file system access and provides an
-// implementation accessing the file system of the underlying OS.
-package vfs // import "golang.org/x/website/internal/godoc/vfs"
-
-import (
-	"io"
-	"io/ioutil"
-	"os"
-)
-
-// The FileSystem interface specifies the methods godoc is using
-// to access the file system for which it serves documentation.
-type FileSystem interface {
-	Opener
-	Lstat(path string) (os.FileInfo, error)
-	Stat(path string) (os.FileInfo, error)
-	ReadDir(path string) ([]os.FileInfo, error)
-	String() string
-}
-
-// Opener is a minimal virtual filesystem that can only open regular files.
-type Opener interface {
-	Open(name string) (ReadSeekCloser, error)
-}
-
-// A ReadSeekCloser can Read, Seek, and Close.
-type ReadSeekCloser interface {
-	io.Reader
-	io.Seeker
-	io.Closer
-}
-
-// ReadFile reads the file named by path from fs and returns the contents.
-func ReadFile(fs Opener, path string) ([]byte, error) {
-	rc, err := fs.Open(path)
-	if err != nil {
-		return nil, err
-	}
-	defer rc.Close()
-	return ioutil.ReadAll(rc)
-}