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.
Этот коммит содержится в:
родитель
641a7e5cb9
коммит
98a6ed8059
2 изменённых файлов: 120 добавлений и 1 удалений
|
@ -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
|
||||
|
|
71
src/os/file_go_116_test.go
Обычный файл
71
src/os/file_go_116_test.go
Обычный файл
|
@ -0,0 +1,71 @@
|
|||
// Copyright 2009 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.
|
||||
|
||||
// +build go1.16,!baremetal,!js,!wasi
|
||||
|
||||
// DirFS tests copied verbatim from upstream os_test.go, and adjusted minimally to fit tinygo.
|
||||
|
||||
package os_test
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
. "os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
)
|
||||
|
||||
func TestDirFS(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Log("TODO: implement Readdir for Windows")
|
||||
return
|
||||
}
|
||||
if err := fstest.TestFS(DirFS("./testdata/dirfs"), "a", "b", "dir/x"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Test that Open does not accept backslash as separator.
|
||||
d := DirFS(".")
|
||||
_, err := d.Open(`testdata\dirfs`)
|
||||
if err == nil {
|
||||
t.Fatalf(`Open testdata\dirfs succeeded`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDirFSPathsValid(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Log("skipping on Windows")
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: switch back to t.TempDir once it's implemented
|
||||
d, err := MkdirTemp("", "TestDirFSPathsValid")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer Remove(d)
|
||||
if err := os.WriteFile(filepath.Join(d, "control.txt"), []byte(string("Hello, world!")), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer Remove(filepath.Join(d, "control.txt"))
|
||||
if err := os.WriteFile(filepath.Join(d, `e:xperi\ment.txt`), []byte(string("Hello, colon and backslash!")), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer Remove(filepath.Join(d, `e:xperi\ment.txt`))
|
||||
|
||||
fsys := os.DirFS(d)
|
||||
err = fs.WalkDir(fsys, ".", func(path string, e fs.DirEntry, err error) error {
|
||||
if fs.ValidPath(e.Name()) {
|
||||
t.Logf("%q ok", e.Name())
|
||||
} else {
|
||||
t.Errorf("%q INVALID", e.Name())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
Загрузка…
Создание таблицы
Сослаться в новой задаче