fs.go 9.1 KB

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