github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/io/fs/fs.go (about)

     1  // Copyright 2020 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package fs defines basic interfaces to a file system.
     6  // A file system can be provided by the host operating system
     7  // but also by other packages.
     8  package fs
     9  
    10  import (
    11  	"internal/oserror"
    12  	"time"
    13  )
    14  
    15  // An FS provides access to a hierarchical file system.
    16  //
    17  // The FS interface is the minimum implementation required of the file system.
    18  // A file system may implement additional interfaces,
    19  // such as ReadFileFS, to provide additional or optimized functionality.
    20  type FS interface {
    21  	// Open opens the named file.
    22  	//
    23  	// When Open returns an error, it should be of type *PathError
    24  	// with the Op field set to "open", the Path field set to name,
    25  	// and the Err field describing the problem.
    26  	//
    27  	// Open should reject attempts to open names that do not satisfy
    28  	// ValidPath(name), returning a *PathError with Err set to
    29  	// ErrInvalid or ErrNotExist.
    30  	Open(name string) (File, error)
    31  }
    32  
    33  // ValidPath reports whether the given path name
    34  // is valid for use in a call to Open.
    35  // Path names passed to open are unrooted, slash-separated
    36  // sequences of path elements, like “x/y/z”.
    37  // Path names must not contain a “.” or “..” or empty element,
    38  // except for the special case that the root directory is named “.”.
    39  //
    40  // Paths are slash-separated on all systems, even Windows.
    41  // Backslashes must not appear in path names.
    42  func ValidPath(name string) bool {
    43  	if name == "." {
    44  		// special case
    45  		return true
    46  	}
    47  
    48  	// Iterate over elements in name, checking each.
    49  	for {
    50  		i := 0
    51  		for i < len(name) && name[i] != '/' {
    52  			if name[i] == '\\' {
    53  				return false
    54  			}
    55  			i++
    56  		}
    57  		elem := name[:i]
    58  		if elem == "" || elem == "." || elem == ".." {
    59  			return false
    60  		}
    61  		if i == len(name) {
    62  			return true // reached clean ending
    63  		}
    64  		name = name[i+1:]
    65  	}
    66  }
    67  
    68  // A File provides access to a single file.
    69  // The File interface is the minimum implementation required of the file.
    70  // A file may implement additional interfaces, such as
    71  // ReadDirFile, ReaderAt, or Seeker, to provide additional or optimized functionality.
    72  type File interface {
    73  	Stat() (FileInfo, error)
    74  	Read([]byte) (int, error)
    75  	Close() error
    76  }
    77  
    78  // A DirEntry is an entry read from a directory
    79  // (using the ReadDir function or a ReadDirFile's ReadDir method).
    80  type DirEntry interface {
    81  	// Name returns the name of the file (or subdirectory) described by the entry.
    82  	// This name is only the final element of the path (the base name), not the entire path.
    83  	// For example, Name would return "hello.go" not "/home/gopher/hello.go".
    84  	Name() string
    85  
    86  	// IsDir reports whether the entry describes a directory.
    87  	IsDir() bool
    88  
    89  	// Type returns the type bits for the entry.
    90  	// The type bits are a subset of the usual FileMode bits, those returned by the FileMode.Type method.
    91  	Type() FileMode
    92  
    93  	// Info returns the FileInfo for the file or subdirectory described by the entry.
    94  	// The returned FileInfo may be from the time of the original directory read
    95  	// or from the time of the call to Info. If the file has been removed or renamed
    96  	// since the directory read, Info may return an error satisfying errors.Is(err, ErrNotExist).
    97  	// If the entry denotes a symbolic link, Info reports the information about the link itself,
    98  	// not the link's target.
    99  	Info() (FileInfo, error)
   100  }
   101  
   102  // A ReadDirFile is a directory file whose entries can be read with the ReadDir method.
   103  // Every directory file should implement this interface.
   104  // (It is permissible for any file to implement this interface,
   105  // but if so ReadDir should return an error for non-directories.)
   106  type ReadDirFile interface {
   107  	File
   108  
   109  	// ReadDir reads the contents of the directory and returns
   110  	// a slice of up to n DirEntry values in directory order.
   111  	// Subsequent calls on the same file will yield further DirEntry values.
   112  	//
   113  	// If n > 0, ReadDir returns at most n DirEntry structures.
   114  	// In this case, if ReadDir returns an empty slice, it will return
   115  	// a non-nil error explaining why.
   116  	// At the end of a directory, the error is io.EOF.
   117  	//
   118  	// If n <= 0, ReadDir returns all the DirEntry values from the directory
   119  	// in a single slice. In this case, if ReadDir succeeds (reads all the way
   120  	// to the end of the directory), it returns the slice and a nil error.
   121  	// If it encounters an error before the end of the directory,
   122  	// ReadDir returns the DirEntry list read until that point and a non-nil error.
   123  	ReadDir(n int) ([]DirEntry, error)
   124  }
   125  
   126  // Generic file system errors.
   127  // Errors returned by file systems can be tested against these errors
   128  // using errors.Is.
   129  var (
   130  	ErrInvalid    = errInvalid()    // "invalid argument"
   131  	ErrPermission = errPermission() // "permission denied"
   132  	ErrExist      = errExist()      // "file already exists"
   133  	ErrNotExist   = errNotExist()   // "file does not exist"
   134  	ErrClosed     = errClosed()     // "file already closed"
   135  )
   136  
   137  func errInvalid() error    { return oserror.ErrInvalid }
   138  func errPermission() error { return oserror.ErrPermission }
   139  func errExist() error      { return oserror.ErrExist }
   140  func errNotExist() error   { return oserror.ErrNotExist }
   141  func errClosed() error     { return oserror.ErrClosed }
   142  
   143  // A FileInfo describes a file and is returned by Stat.
   144  type FileInfo interface {
   145  	Name() string       // base name of the file
   146  	Size() int64        // length in bytes for regular files; system-dependent for others
   147  	Mode() FileMode     // file mode bits
   148  	ModTime() time.Time // modification time
   149  	IsDir() bool        // abbreviation for Mode().IsDir()
   150  	Sys() interface{}   // underlying data source (can return nil)
   151  }
   152  
   153  // A FileMode represents a file's mode and permission bits.
   154  // The bits have the same definition on all systems, so that
   155  // information about files can be moved from one system
   156  // to another portably. Not all bits apply to all systems.
   157  // The only required bit is ModeDir for directories.
   158  type FileMode uint32
   159  
   160  // The defined file mode bits are the most significant bits of the FileMode.
   161  // The nine least-significant bits are the standard Unix rwxrwxrwx permissions.
   162  // The values of these bits should be considered part of the public API and
   163  // may be used in wire protocols or disk representations: they must not be
   164  // changed, although new bits might be added.
   165  const (
   166  	// The single letters are the abbreviations
   167  	// used by the String method's formatting.
   168  	ModeDir        FileMode = 1 << (32 - 1 - iota) // d: is a directory
   169  	ModeAppend                                     // a: append-only
   170  	ModeExclusive                                  // l: exclusive use
   171  	ModeTemporary                                  // T: temporary file; Plan 9 only
   172  	ModeSymlink                                    // L: symbolic link
   173  	ModeDevice                                     // D: device file
   174  	ModeNamedPipe                                  // p: named pipe (FIFO)
   175  	ModeSocket                                     // S: Unix domain socket
   176  	ModeSetuid                                     // u: setuid
   177  	ModeSetgid                                     // g: setgid
   178  	ModeCharDevice                                 // c: Unix character device, when ModeDevice is set
   179  	ModeSticky                                     // t: sticky
   180  	ModeIrregular                                  // ?: non-regular file; nothing else is known about this file
   181  
   182  	// Mask for the type bits. For regular files, none will be set.
   183  	ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice | ModeCharDevice | ModeIrregular
   184  
   185  	ModePerm FileMode = 0777 // Unix permission bits
   186  )
   187  
   188  func (m FileMode) String() string {
   189  	const str = "dalTLDpSugct?"
   190  	var buf [32]byte // Mode is uint32.
   191  	w := 0
   192  	for i, c := range str {
   193  		if m&(1<<uint(32-1-i)) != 0 {
   194  			buf[w] = byte(c)
   195  			w++
   196  		}
   197  	}
   198  	if w == 0 {
   199  		buf[w] = '-'
   200  		w++
   201  	}
   202  	const rwx = "rwxrwxrwx"
   203  	for i, c := range rwx {
   204  		if m&(1<<uint(9-1-i)) != 0 {
   205  			buf[w] = byte(c)
   206  		} else {
   207  			buf[w] = '-'
   208  		}
   209  		w++
   210  	}
   211  	return string(buf[:w])
   212  }
   213  
   214  // IsDir reports whether m describes a directory.
   215  // That is, it tests for the ModeDir bit being set in m.
   216  func (m FileMode) IsDir() bool {
   217  	return m&ModeDir != 0
   218  }
   219  
   220  // IsRegular reports whether m describes a regular file.
   221  // That is, it tests that no mode type bits are set.
   222  func (m FileMode) IsRegular() bool {
   223  	return m&ModeType == 0
   224  }
   225  
   226  // Perm returns the Unix permission bits in m (m & ModePerm).
   227  func (m FileMode) Perm() FileMode {
   228  	return m & ModePerm
   229  }
   230  
   231  // Type returns type bits in m (m & ModeType).
   232  func (m FileMode) Type() FileMode {
   233  	return m & ModeType
   234  }
   235  
   236  // PathError records an error and the operation and file path that caused it.
   237  type PathError struct {
   238  	Op   string
   239  	Path string
   240  	Err  error
   241  }
   242  
   243  func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() }
   244  
   245  func (e *PathError) Unwrap() error { return e.Err }
   246  
   247  // Timeout reports whether this error represents a timeout.
   248  func (e *PathError) Timeout() bool {
   249  	t, ok := e.Err.(interface{ Timeout() bool })
   250  	return ok && t.Timeout()
   251  }