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