1
0
mirror of https://github.com/golang/go synced 2024-11-19 05:34:40 -07:00
go/godoc/vfs/os.go
Michael Edwards 4ce273956a 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.

Fixes golang/go#15049

Change-Id: I34d17ca0027b0245f5ef434a000e5a3fe2af11cf
Reviewed-on: https://go-review.googlesource.com/45096
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-07-14 21:15:33 +00:00

94 lines
2.3 KiB
Go

// 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"
"log"
"os"
pathpkg "path"
"path/filepath"
"strings"
)
// 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(root)
}
type osFS string
func (root osFS) String() string { return "os(" + string(root) + ")" }
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(string(root), 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 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
}