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