os: add DirFS, which is used by many programs to access readdir.

It's wafer-thin :-)

Includes smoke test from upstream.

TODO: once t.TempDir is implemented, add io/fs to the list of standard library tests to run; that's a better test.
This commit is contained in:
Dan Kegel
2022-01-23 12:56:09 -08:00
committed by Ron Evans
parent 641a7e5cb9
commit 98a6ed8059
2 changed files with 120 additions and 1 deletions
+49 -1
View File
@@ -5,6 +5,7 @@ package os
import (
"io"
"io/fs"
"runtime"
)
type (
@@ -12,9 +13,56 @@ type (
FileInfo = fs.FileInfo
)
// The followings are copied from Go 1.16 official implementation:
// The followings are copied from Go 1.16 or 1.17 official implementation:
// https://github.com/golang/go/blob/go1.16/src/os/file.go
// DirFS returns a file system (an fs.FS) for the tree of files rooted at the directory dir.
//
// Note that DirFS("/prefix") only guarantees that the Open calls it makes to the
// operating system will begin with "/prefix": DirFS("/prefix").Open("file") is the
// same as os.Open("/prefix/file"). So if /prefix/file is a symbolic link pointing outside
// the /prefix tree, then using DirFS does not stop the access any more than using
// os.Open does. DirFS is therefore not a general substitute for a chroot-style security
// mechanism when the directory tree contains arbitrary content.
func DirFS(dir string) fs.FS {
return dirFS(dir)
}
func containsAny(s, chars string) bool {
for i := 0; i < len(s); i++ {
for j := 0; j < len(chars); j++ {
if s[i] == chars[j] {
return true
}
}
}
return false
}
type dirFS string
func (dir dirFS) Open(name string) (fs.File, error) {
if !fs.ValidPath(name) || runtime.GOOS == "windows" && containsAny(name, `\:`) {
return nil, &PathError{Op: "open", Path: name, Err: ErrInvalid}
}
f, err := Open(string(dir) + "/" + name)
if err != nil {
return nil, err // nil fs.File
}
return f, nil
}
func (dir dirFS) Stat(name string) (fs.FileInfo, error) {
if !fs.ValidPath(name) || runtime.GOOS == "windows" && containsAny(name, `\:`) {
return nil, &PathError{Op: "stat", Path: name, Err: ErrInvalid}
}
f, err := Stat(string(dir) + "/" + name)
if err != nil {
return nil, err
}
return f, nil
}
// ReadFile reads the named file and returns the contents.
// A successful call returns err == nil, not err == EOF.
// Because ReadFile reads the whole file, it does not treat an EOF from Read