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