123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- // 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 defines basic interfaces to a file system.
- // A file system can be provided by the host operating system
- // but also by other packages.
- package fs
- import (
- "internal/oserror"
- "time"
- "unicode/utf8"
- )
- // 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 ReadFileFS, to provide additional or optimized functionality.
- 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 UTF-8-encoded,
- // unrooted, slash-separated sequences of path elements, like “x/y/z”.
- // Path names must not contain an element that is “.” or “..” or the empty string,
- // except for the special case that the root directory is named “.”.
- // Paths must not start or end with a slash: “/x” and “x/” are invalid.
- //
- // Note that paths are slash-separated on all systems, even Windows.
- // Paths containing other characters such as backslash and colon
- // are accepted as valid, but those characters must never be
- // interpreted by an FS implementation as path element separators.
- func ValidPath(name string) bool {
- if !utf8.ValidString(name) {
- return false
- }
- if name == "." {
- // special case
- return true
- }
- // Iterate over elements in name, checking each.
- for {
- i := 0
- for i < len(name) && name[i] != '/' {
- 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.
- // Directory files should also implement ReadDirFile.
- // A file may implement io.ReaderAt or io.Seeker as optimizations.
- 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.
- var (
- ErrInvalid = errInvalid() // "invalid argument"
- ErrPermission = errPermission() // "permission denied"
- ErrExist = errExist() // "file already exists"
- ErrNotExist = errNotExist() // "file does not exist"
- ErrClosed = errClosed() // "file already closed"
- )
- func errInvalid() error { return oserror.ErrInvalid }
- func errPermission() error { return oserror.ErrPermission }
- func errExist() error { return oserror.ErrExist }
- func errNotExist() error { return oserror.ErrNotExist }
- func errClosed() error { return oserror.ErrClosed }
- // A FileInfo describes a file and is returned by Stat.
- type FileInfo interface {
- Name() string // base name of the file
- Size() int64 // length in bytes for regular files; system-dependent for others
- Mode() FileMode // file mode bits
- ModTime() time.Time // modification time
- IsDir() bool // abbreviation for Mode().IsDir()
- Sys() any // underlying data source (can return nil)
- }
- // A FileMode represents a file's mode and permission bits.
- // The bits have the same definition on all systems, so that
- // information about files can be moved from one system
- // to another portably. Not all bits apply to all systems.
- // The only required bit is ModeDir for directories.
- type FileMode uint32
- // The defined file mode bits are the most significant bits of the FileMode.
- // The nine least-significant bits are the standard Unix rwxrwxrwx permissions.
- // The values of these bits should be considered part of the public API and
- // may be used in wire protocols or disk representations: they must not be
- // changed, although new bits might be added.
- const (
- // The single letters are the abbreviations
- // used by the String method's formatting.
- ModeDir FileMode = 1 << (32 - 1 - iota) // d: is a directory
- ModeAppend // a: append-only
- ModeExclusive // l: exclusive use
- ModeTemporary // T: temporary file; Plan 9 only
- ModeSymlink // L: symbolic link
- ModeDevice // D: device file
- ModeNamedPipe // p: named pipe (FIFO)
- ModeSocket // S: Unix domain socket
- ModeSetuid // u: setuid
- ModeSetgid // g: setgid
- ModeCharDevice // c: Unix character device, when ModeDevice is set
- ModeSticky // t: sticky
- ModeIrregular // ?: non-regular file; nothing else is known about this file
- // Mask for the type bits. For regular files, none will be set.
- ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice | ModeCharDevice | ModeIrregular
- ModePerm FileMode = 0777 // Unix permission bits
- )
- func (m FileMode) String() string {
- const str = "dalTLDpSugct?"
- var buf [32]byte // Mode is uint32.
- w := 0
- for i, c := range str {
- if m&(1<<uint(32-1-i)) != 0 {
- buf[w] = byte(c)
- w++
- }
- }
- if w == 0 {
- buf[w] = '-'
- w++
- }
- const rwx = "rwxrwxrwx"
- for i, c := range rwx {
- if m&(1<<uint(9-1-i)) != 0 {
- buf[w] = byte(c)
- } else {
- buf[w] = '-'
- }
- w++
- }
- return string(buf[:w])
- }
- // IsDir reports whether m describes a directory.
- // That is, it tests for the ModeDir bit being set in m.
- func (m FileMode) IsDir() bool {
- return m&ModeDir != 0
- }
- // IsRegular reports whether m describes a regular file.
- // That is, it tests that no mode type bits are set.
- func (m FileMode) IsRegular() bool {
- return m&ModeType == 0
- }
- // Perm returns the Unix permission bits in m (m & ModePerm).
- func (m FileMode) Perm() FileMode {
- return m & ModePerm
- }
- // Type returns type bits in m (m & ModeType).
- func (m FileMode) Type() FileMode {
- return m & ModeType
- }
- // PathError records an error and the operation and file path that caused it.
- type PathError struct {
- Op string
- Path string
- Err error
- }
- func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() }
- func (e *PathError) Unwrap() error { return e.Err }
- // Timeout reports whether this error represents a timeout.
- func (e *PathError) Timeout() bool {
- t, ok := e.Err.(interface{ Timeout() bool })
- return ok && t.Timeout()
- }
|