github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/p9/file.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package p9 16 17 import ( 18 "errors" 19 20 "golang.org/x/sys/unix" 21 "github.com/SagerNet/gvisor/pkg/fd" 22 ) 23 24 // Attacher is provided by the server. 25 type Attacher interface { 26 // Attach returns a new File. 27 // 28 // The client-side attach will be translate to a series of walks from 29 // the file returned by this Attach call. 30 Attach() (File, error) 31 } 32 33 // File is a set of operations corresponding to a single node. 34 // 35 // Note that on the server side, the server logic places constraints on 36 // concurrent operations to make things easier. This may reduce the need for 37 // complex, error-prone locking and logic in the backend. These are documented 38 // for each method. 39 // 40 // There are three different types of guarantees provided: 41 // 42 // none: There is no concurrency guarantee. The method may be invoked 43 // concurrently with any other method on any other file. 44 // 45 // read: The method is guaranteed to be exclusive of any write or global 46 // operation that is mutating the state of the directory tree starting at this 47 // node. For example, this means creating new files, symlinks, directories or 48 // renaming a directory entry (or renaming in to this target), but the method 49 // may be called concurrently with other read methods. 50 // 51 // write: The method is guaranteed to be exclusive of any read, write or global 52 // operation that is mutating the state of the directory tree starting at this 53 // node, as described in read above. There may however, be other write 54 // operations executing concurrently on other components in the directory tree. 55 // 56 // global: The method is guaranteed to be exclusive of any read, write or 57 // global operation. 58 type File interface { 59 // Walk walks to the path components given in names. 60 // 61 // Walk returns QIDs in the same order that the names were passed in. 62 // 63 // An empty list of arguments should return a copy of the current file. 64 // 65 // On the server, Walk has a read concurrency guarantee. 66 Walk(names []string) ([]QID, File, error) 67 68 // WalkGetAttr walks to the next file and returns its maximal set of 69 // attributes. 70 // 71 // Server-side p9.Files may return unix.ENOSYS to indicate that Walk 72 // and GetAttr should be used separately to satisfy this request. 73 // 74 // On the server, WalkGetAttr has a read concurrency guarantee. 75 WalkGetAttr([]string) ([]QID, File, AttrMask, Attr, error) 76 77 // MultiGetAttr batches up multiple calls to GetAttr(). names is a list of 78 // path components similar to Walk(). If the first component name is empty, 79 // the current file is stat'd and included in the results. If the walk reaches 80 // a file that doesn't exist or not a directory, MultiGetAttr returns the 81 // partial result with no error. 82 // 83 // On the server, MultiGetAttr has a read concurrency guarantee. 84 MultiGetAttr(names []string) ([]FullStat, error) 85 86 // StatFS returns information about the file system associated with 87 // this file. 88 // 89 // On the server, StatFS has no concurrency guarantee. 90 StatFS() (FSStat, error) 91 92 // GetAttr returns attributes of this node. 93 // 94 // On the server, GetAttr has a read concurrency guarantee. 95 GetAttr(req AttrMask) (QID, AttrMask, Attr, error) 96 97 // SetAttr sets attributes on this node. 98 // 99 // On the server, SetAttr has a write concurrency guarantee. 100 SetAttr(valid SetAttrMask, attr SetAttr) error 101 102 // GetXattr returns extended attributes of this node. 103 // 104 // Size indicates the size of the buffer that has been allocated to hold the 105 // attribute value. If the value is larger than size, implementations may 106 // return ERANGE to indicate that the buffer is too small, but they are also 107 // free to ignore the hint entirely (i.e. the value returned may be larger 108 // than size). All size checking is done independently at the syscall layer. 109 // 110 // On the server, GetXattr has a read concurrency guarantee. 111 GetXattr(name string, size uint64) (string, error) 112 113 // SetXattr sets extended attributes on this node. 114 // 115 // On the server, SetXattr has a write concurrency guarantee. 116 SetXattr(name, value string, flags uint32) error 117 118 // ListXattr lists the names of the extended attributes on this node. 119 // 120 // Size indicates the size of the buffer that has been allocated to hold the 121 // attribute list. If the list would be larger than size, implementations may 122 // return ERANGE to indicate that the buffer is too small, but they are also 123 // free to ignore the hint entirely (i.e. the value returned may be larger 124 // than size). All size checking is done independently at the syscall layer. 125 // 126 // On the server, ListXattr has a read concurrency guarantee. 127 ListXattr(size uint64) (map[string]struct{}, error) 128 129 // RemoveXattr removes extended attributes on this node. 130 // 131 // On the server, RemoveXattr has a write concurrency guarantee. 132 RemoveXattr(name string) error 133 134 // Allocate allows the caller to directly manipulate the allocated disk space 135 // for the file. See fallocate(2) for more details. 136 Allocate(mode AllocateMode, offset, length uint64) error 137 138 // Close is called when all references are dropped on the server side, 139 // and Close should be called by the client to drop all references. 140 // 141 // For server-side implementations of Close, the error is ignored. 142 // 143 // Close must be called even when Open has not been called. 144 // 145 // On the server, Close has no concurrency guarantee. 146 Close() error 147 148 // SetAttrClose is the equivalent of calling SetAttr() followed by Close(). 149 // This can be used to set file times before closing the file in a single 150 // operation. 151 // 152 // On the server, SetAttr has a write concurrency guarantee. 153 // On the server, Close has no concurrency guarantee. 154 SetAttrClose(valid SetAttrMask, attr SetAttr) error 155 156 // Open must be called prior to using Read, Write or Readdir. Once Open 157 // is called, some operations, such as Walk, will no longer work. 158 // 159 // On the client, Open should be called only once. The fd return is 160 // optional, and may be nil. 161 // 162 // On the server, Open has a read concurrency guarantee. If an *fd.FD 163 // is provided, ownership now belongs to the caller. Open is guaranteed 164 // to be called only once. 165 // 166 // N.B. The server must resolve any lazy paths when open is called. 167 // After this point, read and write may be called on files with no 168 // deletion check, so resolving in the data path is not viable. 169 Open(flags OpenFlags) (*fd.FD, QID, uint32, error) 170 171 // Read reads from this file. Open must be called first. 172 // 173 // This may return io.EOF in addition to unix.Errno values. 174 // 175 // On the server, ReadAt has a read concurrency guarantee. See Open for 176 // additional requirements regarding lazy path resolution. 177 ReadAt(p []byte, offset uint64) (int, error) 178 179 // Write writes to this file. Open must be called first. 180 // 181 // This may return io.EOF in addition to unix.Errno values. 182 // 183 // On the server, WriteAt has a read concurrency guarantee. See Open 184 // for additional requirements regarding lazy path resolution. 185 WriteAt(p []byte, offset uint64) (int, error) 186 187 // FSync syncs this node. Open must be called first. 188 // 189 // On the server, FSync has a read concurrency guarantee. 190 FSync() error 191 192 // Create creates a new regular file and opens it according to the 193 // flags given. This file is already Open. 194 // 195 // N.B. On the client, the returned file is a reference to the current 196 // file, which now represents the created file. This is not the case on 197 // the server. These semantics are very subtle and can easily lead to 198 // bugs, but are a consequence of the 9P create operation. 199 // 200 // See p9.File.Open for a description of *fd.FD. 201 // 202 // On the server, Create has a write concurrency guarantee. 203 Create(name string, flags OpenFlags, permissions FileMode, uid UID, gid GID) (*fd.FD, File, QID, uint32, error) 204 205 // Mkdir creates a subdirectory. 206 // 207 // On the server, Mkdir has a write concurrency guarantee. 208 Mkdir(name string, permissions FileMode, uid UID, gid GID) (QID, error) 209 210 // Symlink makes a new symbolic link. 211 // 212 // On the server, Symlink has a write concurrency guarantee. 213 Symlink(oldName string, newName string, uid UID, gid GID) (QID, error) 214 215 // Link makes a new hard link. 216 // 217 // On the server, Link has a write concurrency guarantee. 218 Link(target File, newName string) error 219 220 // Mknod makes a new device node. 221 // 222 // On the server, Mknod has a write concurrency guarantee. 223 Mknod(name string, mode FileMode, major uint32, minor uint32, uid UID, gid GID) (QID, error) 224 225 // Rename renames the file. 226 // 227 // Rename will never be called on the server, and RenameAt will always 228 // be used instead. 229 Rename(newDir File, newName string) error 230 231 // RenameAt renames a given file to a new name in a potentially new 232 // directory. 233 // 234 // oldName must be a name relative to this file, which must be a 235 // directory. newName is a name relative to newDir. 236 // 237 // On the server, RenameAt has a global concurrency guarantee. 238 RenameAt(oldName string, newDir File, newName string) error 239 240 // UnlinkAt the given named file. 241 // 242 // name must be a file relative to this directory. 243 // 244 // Flags are implementation-specific (e.g. O_DIRECTORY), but are 245 // generally Linux unlinkat(2) flags. 246 // 247 // On the server, UnlinkAt has a write concurrency guarantee. 248 UnlinkAt(name string, flags uint32) error 249 250 // Readdir reads directory entries. 251 // 252 // This may return io.EOF in addition to unix.Errno values. 253 // 254 // On the server, Readdir has a read concurrency guarantee. 255 Readdir(offset uint64, count uint32) ([]Dirent, error) 256 257 // Readlink reads the link target. 258 // 259 // On the server, Readlink has a read concurrency guarantee. 260 Readlink() (string, error) 261 262 // Flush is called prior to Close. 263 // 264 // Whereas Close drops all references to the file, Flush cleans up the 265 // file state. Behavior is implementation-specific. 266 // 267 // Flush is not related to flush(9p). Flush is an extension to 9P2000.L, 268 // see version.go. 269 // 270 // On the server, Flush has a read concurrency guarantee. 271 Flush() error 272 273 // Connect establishes a new host-socket backed connection with a 274 // socket. A File does not need to be opened before it can be connected 275 // and it can be connected to multiple times resulting in a unique 276 // *fd.FD each time. In addition, the lifetime of the *fd.FD is 277 // independent from the lifetime of the p9.File and must be managed by 278 // the caller. 279 // 280 // The returned FD must be non-blocking. 281 // 282 // Flags indicates the requested type of socket. 283 // 284 // On the server, Connect has a read concurrency guarantee. 285 Connect(flags ConnectFlags) (*fd.FD, error) 286 287 // Renamed is called when this node is renamed. 288 // 289 // This may not fail. The file will hold a reference to its parent 290 // within the p9 package, and is therefore safe to use for the lifetime 291 // of this File (until Close is called). 292 // 293 // This method should not be called by clients, who should use the 294 // relevant Rename methods. (Although the method will be a no-op.) 295 // 296 // On the server, Renamed has a global concurrency guarantee. 297 Renamed(newDir File, newName string) 298 } 299 300 // DefaultWalkGetAttr implements File.WalkGetAttr to return ENOSYS for server-side Files. 301 type DefaultWalkGetAttr struct{} 302 303 // WalkGetAttr implements File.WalkGetAttr. 304 func (DefaultWalkGetAttr) WalkGetAttr([]string) ([]QID, File, AttrMask, Attr, error) { 305 return nil, nil, AttrMask{}, Attr{}, unix.ENOSYS 306 } 307 308 // DisallowClientCalls panics if a client-only function is called. 309 type DisallowClientCalls struct{} 310 311 // SetAttrClose implements File.SetAttrClose. 312 func (DisallowClientCalls) SetAttrClose(SetAttrMask, SetAttr) error { 313 panic("SetAttrClose should not be called on the server") 314 } 315 316 // DisallowServerCalls panics if a server-only function is called. 317 type DisallowServerCalls struct{} 318 319 // Renamed implements File.Renamed. 320 func (*DisallowServerCalls) Renamed(File, string) { 321 panic("Renamed should not be called on the client") 322 } 323 324 // DefaultMultiGetAttr implements File.MultiGetAttr() on top of File. 325 func DefaultMultiGetAttr(start File, names []string) ([]FullStat, error) { 326 stats := make([]FullStat, 0, len(names)) 327 parent := start 328 mask := AttrMaskAll() 329 for i, name := range names { 330 if len(name) == 0 && i == 0 { 331 qid, valid, attr, err := parent.GetAttr(mask) 332 if err != nil { 333 return nil, err 334 } 335 stats = append(stats, FullStat{ 336 QID: qid, 337 Valid: valid, 338 Attr: attr, 339 }) 340 continue 341 } 342 qids, child, valid, attr, err := parent.WalkGetAttr([]string{name}) 343 if parent != start { 344 _ = parent.Close() 345 } 346 if err != nil { 347 if errors.Is(err, unix.ENOENT) { 348 return stats, nil 349 } 350 return nil, err 351 } 352 stats = append(stats, FullStat{ 353 QID: qids[0], 354 Valid: valid, 355 Attr: attr, 356 }) 357 if attr.Mode.FileType() != ModeDirectory { 358 // Doesn't need to continue if entry is not a dir. Including symlinks 359 // that cannot be followed. 360 _ = child.Close() 361 break 362 } 363 parent = child 364 } 365 if parent != start { 366 _ = parent.Close() 367 } 368 return stats, nil 369 }