mirror of
https://github.com/golang/go
synced 2024-11-17 08:34:43 -07:00
io/fs: add FS, File, ReadDirFile; move DirEntry from os
These are the core interfaces for the io/fs design. See #41190 and https://golang.org/s/draft-iofs-design for details. DirEntry was left behind in the previous move from os but is needed for ReadDirFile, so it moves in this commit. Also apply a couple comment changes suggested in the review of CL 261540. For #41190. Change-Id: I087741545139ed30b9ba5db728a0bad71129500b Reviewed-on: https://go-review.googlesource.com/c/go/+/243908 Trust: Russ Cox <rsc@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com> Reviewed-by: Rob Pike <r@golang.org> TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
parent
9ad090c5fe
commit
fcb9d6b5d0
112
src/io/fs/fs.go
112
src/io/fs/fs.go
@ -12,6 +12,118 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// An FS provides access to a hierarchical file system.
|
||||||
|
//
|
||||||
|
// The FS interface is the minimum implementation required of the file system.
|
||||||
|
// A file system may implement additional interfaces,
|
||||||
|
// such as fsutil.ReadFileFS, to provide additional or optimized functionality.
|
||||||
|
// See io/fsutil for details.
|
||||||
|
type FS interface {
|
||||||
|
// Open opens the named file.
|
||||||
|
//
|
||||||
|
// When Open returns an error, it should be of type *PathError
|
||||||
|
// with the Op field set to "open", the Path field set to name,
|
||||||
|
// and the Err field describing the problem.
|
||||||
|
//
|
||||||
|
// Open should reject attempts to open names that do not satisfy
|
||||||
|
// ValidPath(name), returning a *PathError with Err set to
|
||||||
|
// ErrInvalid or ErrNotExist.
|
||||||
|
Open(name string) (File, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidPath reports whether the given path name
|
||||||
|
// is valid for use in a call to Open.
|
||||||
|
// Path names passed to open are unrooted, slash-separated
|
||||||
|
// sequences of path elements, like “x/y/z”.
|
||||||
|
// Path names must not contain a “.” or “..” or empty element,
|
||||||
|
// except for the special case that the root directory is named “.”.
|
||||||
|
//
|
||||||
|
// Paths are slash-separated on all systems, even Windows.
|
||||||
|
// Backslashes must not appear in path names.
|
||||||
|
func ValidPath(name string) bool {
|
||||||
|
if name == "." {
|
||||||
|
// special case
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over elements in name, checking each.
|
||||||
|
for {
|
||||||
|
i := 0
|
||||||
|
for i < len(name) && name[i] != '/' {
|
||||||
|
if name[i] == '\\' {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
elem := name[:i]
|
||||||
|
if elem == "" || elem == "." || elem == ".." {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if i == len(name) {
|
||||||
|
return true // reached clean ending
|
||||||
|
}
|
||||||
|
name = name[i+1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A File provides access to a single file.
|
||||||
|
// The File interface is the minimum implementation required of the file.
|
||||||
|
// A file may implement additional interfaces, such as
|
||||||
|
// ReadDirFile, ReaderAt, or Seeker, to provide additional or optimized functionality.
|
||||||
|
type File interface {
|
||||||
|
Stat() (FileInfo, error)
|
||||||
|
Read([]byte) (int, error)
|
||||||
|
Close() error
|
||||||
|
}
|
||||||
|
|
||||||
|
// A DirEntry is an entry read from a directory
|
||||||
|
// (using the ReadDir function or a ReadDirFile's ReadDir method).
|
||||||
|
type DirEntry interface {
|
||||||
|
// Name returns the name of the file (or subdirectory) described by the entry.
|
||||||
|
// This name is only the final element of the path (the base name), not the entire path.
|
||||||
|
// For example, Name would return "hello.go" not "/home/gopher/hello.go".
|
||||||
|
Name() string
|
||||||
|
|
||||||
|
// IsDir reports whether the entry describes a directory.
|
||||||
|
IsDir() bool
|
||||||
|
|
||||||
|
// Type returns the type bits for the entry.
|
||||||
|
// The type bits are a subset of the usual FileMode bits, those returned by the FileMode.Type method.
|
||||||
|
Type() FileMode
|
||||||
|
|
||||||
|
// Info returns the FileInfo for the file or subdirectory described by the entry.
|
||||||
|
// The returned FileInfo may be from the time of the original directory read
|
||||||
|
// or from the time of the call to Info. If the file has been removed or renamed
|
||||||
|
// since the directory read, Info may return an error satisfying errors.Is(err, ErrNotExist).
|
||||||
|
// If the entry denotes a symbolic link, Info reports the information about the link itself,
|
||||||
|
// not the link's target.
|
||||||
|
Info() (FileInfo, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A ReadDirFile is a directory file whose entries can be read with the ReadDir method.
|
||||||
|
// Every directory file should implement this interface.
|
||||||
|
// (It is permissible for any file to implement this interface,
|
||||||
|
// but if so ReadDir should return an error for non-directories.)
|
||||||
|
type ReadDirFile interface {
|
||||||
|
File
|
||||||
|
|
||||||
|
// ReadDir reads the contents of the directory and returns
|
||||||
|
// a slice of up to n DirEntry values in directory order.
|
||||||
|
// Subsequent calls on the same file will yield further DirEntry values.
|
||||||
|
//
|
||||||
|
// If n > 0, ReadDir returns at most n DirEntry structures.
|
||||||
|
// In this case, if ReadDir returns an empty slice, it will return
|
||||||
|
// a non-nil error explaining why.
|
||||||
|
// At the end of a directory, the error is io.EOF.
|
||||||
|
//
|
||||||
|
// If n <= 0, ReadDir returns all the DirEntry values from the directory
|
||||||
|
// in a single slice. In this case, if ReadDir succeeds (reads all the way
|
||||||
|
// to the end of the directory), it returns the slice and a nil error.
|
||||||
|
// If it encounters an error before the end of the directory,
|
||||||
|
// ReadDir returns the DirEntry list read until that point and a non-nil error.
|
||||||
|
ReadDir(n int) ([]DirEntry, error)
|
||||||
|
}
|
||||||
|
|
||||||
// Generic file system errors.
|
// Generic file system errors.
|
||||||
// Errors returned by file systems can be tested against these errors
|
// Errors returned by file systems can be tested against these errors
|
||||||
// using errors.Is.
|
// using errors.Is.
|
||||||
|
48
src/io/fs/fs_test.go
Normal file
48
src/io/fs/fs_test.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// Copyright 2020 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 fs_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "io/fs"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var isValidPathTests = []struct {
|
||||||
|
name string
|
||||||
|
ok bool
|
||||||
|
}{
|
||||||
|
{".", true},
|
||||||
|
{"x", true},
|
||||||
|
{"x/y", true},
|
||||||
|
|
||||||
|
{"", false},
|
||||||
|
{"..", false},
|
||||||
|
{"/", false},
|
||||||
|
{"x/", false},
|
||||||
|
{"/x", false},
|
||||||
|
{"x/y/", false},
|
||||||
|
{"/x/y", false},
|
||||||
|
{"./", false},
|
||||||
|
{"./x", false},
|
||||||
|
{"x/.", false},
|
||||||
|
{"x/./y", false},
|
||||||
|
{"../", false},
|
||||||
|
{"../x", false},
|
||||||
|
{"x/..", false},
|
||||||
|
{"x/../y", false},
|
||||||
|
{"x//y", false},
|
||||||
|
{`x\`, false},
|
||||||
|
{`x\y`, false},
|
||||||
|
{`\x`, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidPath(t *testing.T) {
|
||||||
|
for _, tt := range isValidPathTests {
|
||||||
|
ok := ValidPath(tt.name)
|
||||||
|
if ok != tt.ok {
|
||||||
|
t.Errorf("ValidPath(%q) = %v, want %v", tt.name, ok, tt.ok)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
package os
|
package os
|
||||||
|
|
||||||
|
import "io/fs"
|
||||||
|
|
||||||
type readdirMode int
|
type readdirMode int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -62,27 +64,7 @@ func (f *File) Readdirnames(n int) (names []string, err error) {
|
|||||||
|
|
||||||
// A DirEntry is an entry read from a directory
|
// A DirEntry is an entry read from a directory
|
||||||
// (using the ReadDir function or a File's ReadDir method).
|
// (using the ReadDir function or a File's ReadDir method).
|
||||||
type DirEntry interface {
|
type DirEntry = fs.DirEntry
|
||||||
// Name returns the name of the file (or subdirectory) described by the entry.
|
|
||||||
// This name is only the final element of the path, not the entire path.
|
|
||||||
// For example, Name would return "hello.go" not "/home/gopher/hello.go".
|
|
||||||
Name() string
|
|
||||||
|
|
||||||
// IsDir reports whether the entry describes a subdirectory.
|
|
||||||
IsDir() bool
|
|
||||||
|
|
||||||
// Type returns the type bits for the entry.
|
|
||||||
// The type bits are a subset of the usual FileMode bits, those returned by the FileMode.Type method.
|
|
||||||
Type() FileMode
|
|
||||||
|
|
||||||
// Info returns the FileInfo for the file or subdirectory described by the entry.
|
|
||||||
// The returned FileInfo may be from the time of the original directory read
|
|
||||||
// or from the time of the call to Info. If the file has been removed or renamed
|
|
||||||
// since the directory read, Info may return an error satisfying errors.Is(err, ErrNotExist).
|
|
||||||
// If the entry denotes a symbolic link, Info reports the information about the link itself,
|
|
||||||
// not the link's target.
|
|
||||||
Info() (FileInfo, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadDir reads the contents of the directory associated with the file f
|
// ReadDir reads the contents of the directory associated with the file f
|
||||||
// and returns a slice of DirEntry values in directory order.
|
// and returns a slice of DirEntry values in directory order.
|
||||||
|
Loading…
Reference in New Issue
Block a user