aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2020-07-06 09:56:43 -0400
committerRuss Cox <rsc@golang.org>2020-10-20 02:32:46 +0000
commitfcb9d6b5d0ba6f5606c2b5dfc09f75e2dc5fc1e5 (patch)
treeb3098b5d3de2e8fa09662efb30f5d690db166ec4
parent9ad090c5fea60c9925b7eb30155ce01961c3537f (diff)
downloadgo-fcb9d6b5d0ba6f5606c2b5dfc09f75e2dc5fc1e5.tar.gz
go-fcb9d6b5d0ba6f5606c2b5dfc09f75e2dc5fc1e5.zip
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>
-rw-r--r--src/io/fs/fs.go112
-rw-r--r--src/io/fs/fs_test.go48
-rw-r--r--src/os/dir.go24
3 files changed, 163 insertions, 21 deletions
diff --git a/src/io/fs/fs.go b/src/io/fs/fs.go
index de5c465d9d..d9f89fc6ee 100644
--- a/src/io/fs/fs.go
+++ b/src/io/fs/fs.go
@@ -12,6 +12,118 @@ import (
"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.
// Errors returned by file systems can be tested against these errors
// using errors.Is.
diff --git a/src/io/fs/fs_test.go b/src/io/fs/fs_test.go
new file mode 100644
index 0000000000..8d395fc0db
--- /dev/null
+++ b/src/io/fs/fs_test.go
@@ -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)
+ }
+ }
+}
diff --git a/src/os/dir.go b/src/os/dir.go
index a312001704..b56d998459 100644
--- a/src/os/dir.go
+++ b/src/os/dir.go
@@ -4,6 +4,8 @@
package os
+import "io/fs"
+
type readdirMode int
const (
@@ -62,27 +64,7 @@ func (f *File) Readdirnames(n int) (names []string, err error) {
// A DirEntry is an entry read from a directory
// (using the ReadDir function or a File'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, 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)
-}
+type DirEntry = fs.DirEntry
// ReadDir reads the contents of the directory associated with the file f
// and returns a slice of DirEntry values in directory order.