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