github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/lisafs/fd.go (about)

     1  // Copyright 2021 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 lisafs
    16  
    17  import (
    18  	"golang.org/x/sys/unix"
    19  	"github.com/metacubex/gvisor/pkg/abi/linux"
    20  	"github.com/metacubex/gvisor/pkg/context"
    21  	"github.com/metacubex/gvisor/pkg/refs"
    22  	"github.com/metacubex/gvisor/pkg/sync"
    23  )
    24  
    25  // FDID (file descriptor identifier) is used to identify FDs on a connection.
    26  // Each connection has its own FDID namespace.
    27  //
    28  // +marshal boundCheck slice:FDIDSlice
    29  type FDID uint64
    30  
    31  // InvalidFDID represents an invalid FDID.
    32  const InvalidFDID FDID = 0
    33  
    34  // Ok returns true if f is a valid FDID.
    35  func (f FDID) Ok() bool {
    36  	return f != InvalidFDID
    37  }
    38  
    39  // genericFD can represent any type of FD.
    40  type genericFD interface {
    41  	refs.RefCounter
    42  }
    43  
    44  // A ControlFD is the gateway to the backing filesystem tree node. It is an
    45  // unusual concept. This exists to provide a safe way to do path-based
    46  // operations on the file. It performs operations that can modify the
    47  // filesystem tree and synchronizes these operations. See ControlFDImpl for
    48  // supported operations.
    49  //
    50  // It is not an inode, because multiple control FDs are allowed to exist on the
    51  // same file. It is not a file descriptor because it is not tied to any access
    52  // mode, i.e. a control FD can change its access mode based on the operation
    53  // being performed.
    54  //
    55  // Reference Model:
    56  //   - Each control FD holds a ref on its Node for its entire lifetime.
    57  type ControlFD struct {
    58  	controlFDRefs
    59  	controlFDEntry
    60  
    61  	// node is the filesystem node this FD is immutably associated with.
    62  	node *Node
    63  
    64  	// openFDs is a linked list of all FDs opened on this FD. As per reference
    65  	// model, all open FDs hold a ref on this FD.
    66  	openFDsMu sync.RWMutex
    67  	openFDs   openFDList
    68  
    69  	// All the following fields are immutable.
    70  
    71  	// id is the unique FD identifier which identifies this FD on its connection.
    72  	id FDID
    73  
    74  	// conn is the backing connection owning this FD.
    75  	conn *Connection
    76  
    77  	// ftype is the file type of the backing inode. ftype.FileType() == ftype.
    78  	ftype linux.FileMode
    79  
    80  	// impl is the control FD implementation which embeds this struct. It
    81  	// contains all the implementation specific details.
    82  	impl ControlFDImpl
    83  }
    84  
    85  var _ genericFD = (*ControlFD)(nil)
    86  
    87  // DecRef implements refs.RefCounter.DecRef. Note that the context
    88  // parameter should never be used. It exists solely to comply with the
    89  // refs.RefCounter interface.
    90  func (fd *ControlFD) DecRef(context.Context) {
    91  	fd.controlFDRefs.DecRef(func() {
    92  		fd.conn.server.renameMu.RLock()
    93  		defer fd.conn.server.renameMu.RUnlock()
    94  		fd.destroyLocked()
    95  	})
    96  }
    97  
    98  // decRefLocked is the same as DecRef except the added precondition.
    99  //
   100  // Precondition: server's rename mutex must be at least read locked.
   101  func (fd *ControlFD) decRefLocked() {
   102  	fd.controlFDRefs.DecRef(func() {
   103  		fd.destroyLocked()
   104  	})
   105  }
   106  
   107  // Precondition: server's rename mutex must be at least read locked.
   108  func (fd *ControlFD) destroyLocked() {
   109  	// Update node's control FD list.
   110  	fd.node.removeFD(fd)
   111  
   112  	// Drop ref on node.
   113  	fd.node.DecRef(nil)
   114  
   115  	// Let the FD implementation clean up.
   116  	fd.impl.Close()
   117  }
   118  
   119  // Init must be called before first use of fd. It inserts fd into the
   120  // filesystem tree.
   121  //
   122  // Preconditions:
   123  //   - server's rename mutex must be at least read locked.
   124  //   - The caller must take a ref on node which is transferred to fd.
   125  func (fd *ControlFD) Init(c *Connection, node *Node, mode linux.FileMode, impl ControlFDImpl) {
   126  	fd.conn = c
   127  	fd.node = node
   128  	fd.impl = impl
   129  	fd.ftype = mode.FileType()
   130  	// Initialize fd with 1 ref which is transferred to c via c.insertFD().
   131  	fd.controlFDRefs.InitRefs()
   132  	// Make fd reachable/discoverable.
   133  	fd.id = c.insertFD(fd)
   134  	node.insertFD(fd)
   135  }
   136  
   137  // Conn returns the fd's owning connection.
   138  func (fd *ControlFD) Conn() *Connection {
   139  	return fd.conn
   140  }
   141  
   142  // FileType returns the file mode only containing the file type bits.
   143  func (fd *ControlFD) FileType() linux.FileMode {
   144  	return fd.ftype
   145  }
   146  
   147  // IsDir indicates whether fd represents a directory.
   148  func (fd *ControlFD) IsDir() bool {
   149  	return fd.ftype == unix.S_IFDIR
   150  }
   151  
   152  // IsRegular indicates whether fd represents a regular file.
   153  func (fd *ControlFD) IsRegular() bool {
   154  	return fd.ftype == unix.S_IFREG
   155  }
   156  
   157  // IsSymlink indicates whether fd represents a symbolic link.
   158  func (fd *ControlFD) IsSymlink() bool {
   159  	return fd.ftype == unix.S_IFLNK
   160  }
   161  
   162  // IsSocket indicates whether fd represents a socket.
   163  func (fd *ControlFD) IsSocket() bool {
   164  	return fd.ftype == unix.S_IFSOCK
   165  }
   166  
   167  // Node returns the node this FD was opened on.
   168  func (fd *ControlFD) Node() *Node {
   169  	return fd.node
   170  }
   171  
   172  // RemoveFromConn removes this control FD from its owning connection.
   173  //
   174  // Preconditions:
   175  //   - fd should not have been returned to the client. Otherwise the client can
   176  //     still refer to it.
   177  //   - server's rename mutex must at least be read locked.
   178  func (fd *ControlFD) RemoveFromConn() {
   179  	fd.conn.removeControlFDLocked(fd.id)
   180  }
   181  
   182  // safelyRead executes the given operation with the local path node locked.
   183  // This guarantees that fd's path will not change. fn may not any change paths.
   184  func (fd *ControlFD) safelyRead(fn func() error) error {
   185  	fd.conn.server.renameMu.RLock()
   186  	defer fd.conn.server.renameMu.RUnlock()
   187  	fd.node.opMu.RLock()
   188  	defer fd.node.opMu.RUnlock()
   189  	return fn()
   190  }
   191  
   192  // safelyWrite executes the given operation with the local path node locked in
   193  // a writable fashion. This guarantees that no other operation is executing on
   194  // this path node. fn may change paths inside fd.node.
   195  func (fd *ControlFD) safelyWrite(fn func() error) error {
   196  	fd.conn.server.renameMu.RLock()
   197  	defer fd.conn.server.renameMu.RUnlock()
   198  	fd.node.opMu.Lock()
   199  	defer fd.node.opMu.Unlock()
   200  	return fn()
   201  }
   202  
   203  // safelyGlobal executes the given operation with the global path lock held.
   204  // This guarantees that no other operations is executing concurrently on this
   205  // server. fn may change any path.
   206  func (fd *ControlFD) safelyGlobal(fn func() error) (err error) {
   207  	fd.conn.server.renameMu.Lock()
   208  	defer fd.conn.server.renameMu.Unlock()
   209  	return fn()
   210  }
   211  
   212  // forEachOpenFD executes fn on each FD opened on fd.
   213  func (fd *ControlFD) forEachOpenFD(fn func(ofd *OpenFD)) {
   214  	fd.openFDsMu.RLock()
   215  	defer fd.openFDsMu.RUnlock()
   216  	for ofd := fd.openFDs.Front(); ofd != nil; ofd = ofd.Next() {
   217  		fn(ofd)
   218  	}
   219  }
   220  
   221  // OpenFD represents an open file descriptor on the protocol. It resonates
   222  // closely with a Linux file descriptor. Its operations are limited to the
   223  // file. Its operations are not allowed to modify or traverse the filesystem
   224  // tree. See OpenFDImpl for the supported operations.
   225  //
   226  // Reference Model:
   227  //   - An OpenFD takes a reference on the control FD it was opened on.
   228  type OpenFD struct {
   229  	openFDRefs
   230  	openFDEntry
   231  
   232  	// All the following fields are immutable.
   233  
   234  	// controlFD is the ControlFD on which this FD was opened. OpenFD holds a ref
   235  	// on controlFD for its entire lifetime.
   236  	controlFD *ControlFD
   237  
   238  	// id is the unique FD identifier which identifies this FD on its connection.
   239  	id FDID
   240  
   241  	// Access mode for this FD.
   242  	readable bool
   243  	writable bool
   244  
   245  	// impl is the open FD implementation which embeds this struct. It
   246  	// contains all the implementation specific details.
   247  	impl OpenFDImpl
   248  }
   249  
   250  var _ genericFD = (*OpenFD)(nil)
   251  
   252  // ControlFD returns the control FD on which this FD was opened.
   253  func (fd *OpenFD) ControlFD() ControlFDImpl {
   254  	return fd.controlFD.impl
   255  }
   256  
   257  // DecRef implements refs.RefCounter.DecRef. Note that the context
   258  // parameter should never be used. It exists solely to comply with the
   259  // refs.RefCounter interface.
   260  func (fd *OpenFD) DecRef(context.Context) {
   261  	fd.openFDRefs.DecRef(func() {
   262  		fd.controlFD.openFDsMu.Lock()
   263  		fd.controlFD.openFDs.Remove(fd)
   264  		fd.controlFD.openFDsMu.Unlock()
   265  		fd.controlFD.DecRef(nil) // Drop the ref on the control FD.
   266  		fd.impl.Close()
   267  	})
   268  }
   269  
   270  // Init must be called before first use of fd.
   271  func (fd *OpenFD) Init(cfd *ControlFD, flags uint32, impl OpenFDImpl) {
   272  	// Initialize fd with 1 ref which is transferred to c via c.insertFD().
   273  	fd.openFDRefs.InitRefs()
   274  	fd.controlFD = cfd
   275  	fd.id = cfd.conn.insertFD(fd)
   276  	accessMode := flags & unix.O_ACCMODE
   277  	fd.readable = accessMode == unix.O_RDONLY || accessMode == unix.O_RDWR
   278  	fd.writable = accessMode == unix.O_WRONLY || accessMode == unix.O_RDWR
   279  	fd.impl = impl
   280  	cfd.IncRef() // Holds a ref on cfd for its lifetime.
   281  	cfd.openFDsMu.Lock()
   282  	cfd.openFDs.PushBack(fd)
   283  	cfd.openFDsMu.Unlock()
   284  }
   285  
   286  // BoundSocketFD represents a bound socket on the server.
   287  //
   288  // Reference Model:
   289  //   - A BoundSocketFD takes a reference on the control FD it is bound to.
   290  type BoundSocketFD struct {
   291  	boundSocketFDRefs
   292  
   293  	// All the following fields are immutable.
   294  
   295  	// controlFD is the ControlFD on which this FD was bound. BoundSocketFD
   296  	// holds a ref on controlFD for its entire lifetime.
   297  	controlFD *ControlFD
   298  
   299  	// id is the unique FD identifier which identifies this FD on its connection.
   300  	id FDID
   301  
   302  	// impl is the socket FD implementation which embeds this struct. It
   303  	// contains all the implementation specific details.
   304  	impl BoundSocketFDImpl
   305  }
   306  
   307  var _ genericFD = (*BoundSocketFD)(nil)
   308  
   309  // ControlFD returns the control FD on which this FD was bound.
   310  func (fd *BoundSocketFD) ControlFD() ControlFDImpl {
   311  	return fd.controlFD.impl
   312  }
   313  
   314  // DecRef implements refs.RefCounter.DecRef. Note that the context
   315  // parameter should never be used. It exists solely to comply with the
   316  // refs.RefCounter interface.
   317  func (fd *BoundSocketFD) DecRef(context.Context) {
   318  	fd.boundSocketFDRefs.DecRef(func() {
   319  		fd.controlFD.DecRef(nil) // Drop the ref on the control FD.
   320  		fd.impl.Close()
   321  	})
   322  }
   323  
   324  // Init must be called before first use of fd.
   325  func (fd *BoundSocketFD) Init(cfd *ControlFD, impl BoundSocketFDImpl) {
   326  	// Initialize fd with 1 ref which is transferred to c via c.insertFD().
   327  	fd.boundSocketFDRefs.InitRefs()
   328  	fd.controlFD = cfd
   329  	fd.id = cfd.conn.insertFD(fd)
   330  	fd.impl = impl
   331  	cfd.IncRef() // Holds a ref on cfd for its lifetime.
   332  }
   333  
   334  // There are four different types of guarantees provided:
   335  //
   336  // none: There is no concurrency guarantee. The method may be invoked
   337  // concurrently with any other method on any other FD.
   338  //
   339  // read: The method is guaranteed to be exclusive of any write or global
   340  // operation that is mutating the state of the directory tree starting at this
   341  // node. For example, this means creating new files, symlinks, directories or
   342  // renaming a directory entry (or renaming in to this target), but the method
   343  // may be called concurrently with other read methods.
   344  //
   345  // write: The method is guaranteed to be exclusive of any read, write or global
   346  // operation that is mutating the state of the directory tree starting at this
   347  // node, as described in read above. There may however, be other write
   348  // operations executing concurrently on other components in the directory tree.
   349  //
   350  // global: The method is guaranteed to be exclusive of any read, write or
   351  // global operation.
   352  
   353  // ControlFDImpl contains implementation details for a ControlFD.
   354  // Implementations of ControlFDImpl should contain their associated ControlFD
   355  // by value as their first field.
   356  //
   357  // The operations that perform path traversal or any modification to the
   358  // filesystem tree must synchronize those modifications with the server's
   359  // rename mutex.
   360  type ControlFDImpl interface {
   361  	// FD returns a pointer to the embedded ControlFD.
   362  	FD() *ControlFD
   363  
   364  	// Close should clean up resources used by the control FD implementation.
   365  	// Close is called after all references on the FD have been dropped and its
   366  	// FDID has been released.
   367  	//
   368  	// On the server, Close has no concurrency guarantee.
   369  	Close()
   370  
   371  	// Stat returns the stat(2) results for this FD.
   372  	//
   373  	// On the server, Stat has a read concurrency guarantee.
   374  	Stat() (linux.Statx, error)
   375  
   376  	// SetStat sets file attributes on the backing file. This does not correspond
   377  	// to any one Linux syscall. On Linux, this operation is performed using
   378  	// multiple syscalls like fchmod(2), fchown(2), ftruncate(2), futimesat(2)
   379  	// and so on. The implementation must only set attributes for fields
   380  	// indicated by stat.Mask. Failure to set an attribute may or may not
   381  	// terminate the entire operation. SetStat must return a uint32 which is
   382  	// interpreted as a stat mask to indicate which attribute setting attempts
   383  	// failed. If multiple attribute setting attempts failed, the returned error
   384  	// may be from any one of them.
   385  	//
   386  	// On the server, SetStat has a write concurrency guarantee.
   387  	SetStat(stat SetStatReq) (uint32, error)
   388  
   389  	// Walk walks one path component from the directory represented by this FD.
   390  	// Walk must open a ControlFD on the walked file.
   391  	//
   392  	// On the server, Walk has a read concurrency guarantee.
   393  	Walk(name string) (*ControlFD, linux.Statx, error)
   394  
   395  	// WalkStat is capable of walking multiple path components and returning the
   396  	// stat results for each path component walked via recordStat. Stat results
   397  	// must be returned in the order of walk.
   398  	//
   399  	// In case a symlink is encountered, the walk must terminate successfully on
   400  	// the symlink including its stat result.
   401  	//
   402  	// The first path component of path may be "" which indicates that the first
   403  	// stat result returned must be of this starting directory.
   404  	//
   405  	// On the server, WalkStat has a read concurrency guarantee.
   406  	WalkStat(path StringArray, recordStat func(linux.Statx)) error
   407  
   408  	// Open opens the control FD with the flags passed. The flags should be
   409  	// interpreted as open(2) flags.
   410  	//
   411  	// Open may also optionally return a host FD for the opened file whose
   412  	// lifecycle is independent of the OpenFD. Returns -1 if not available.
   413  	//
   414  	// N.B. The server must resolve any lazy paths when open is called.
   415  	// After this point, read and write may be called on files with no
   416  	// deletion check, so resolving in the data path is not viable.
   417  	//
   418  	// On the server, Open has a read concurrency guarantee.
   419  	Open(flags uint32) (*OpenFD, int, error)
   420  
   421  	// OpenCreate creates a regular file inside the directory represented by this
   422  	// FD and then also opens the file. The created file has perms as specified
   423  	// by mode and owners as specified by uid and gid. The file is opened with
   424  	// the specified flags.
   425  	//
   426  	// OpenCreate may also optionally return a host FD for the opened file whose
   427  	// lifecycle is independent of the OpenFD. Returns -1 if not available.
   428  	//
   429  	// N.B. The server must resolve any lazy paths when open is called.
   430  	// After this point, read and write may be called on files with no
   431  	// deletion check, so resolving in the data path is not viable.
   432  	//
   433  	// On the server, OpenCreate has a write concurrency guarantee.
   434  	OpenCreate(mode linux.FileMode, uid UID, gid GID, name string, flags uint32) (*ControlFD, linux.Statx, *OpenFD, int, error)
   435  
   436  	// Mkdir creates a directory inside the directory represented by this FD. The
   437  	// created directory has perms as specified by mode and owners as specified
   438  	// by uid and gid.
   439  	//
   440  	// On the server, Mkdir has a write concurrency guarantee.
   441  	Mkdir(mode linux.FileMode, uid UID, gid GID, name string) (*ControlFD, linux.Statx, error)
   442  
   443  	// Mknod creates a file inside the directory represented by this FD. The file
   444  	// type and perms are specified by mode and owners are specified by uid and
   445  	// gid. If the newly created file is a character or block device, minor and
   446  	// major specify its device number.
   447  	//
   448  	// On the server, Mkdir has a write concurrency guarantee.
   449  	Mknod(mode linux.FileMode, uid UID, gid GID, name string, minor uint32, major uint32) (*ControlFD, linux.Statx, error)
   450  
   451  	// Symlink creates a symlink inside the directory represented by this FD. The
   452  	// symlink has owners as specified by uid and gid and points to target.
   453  	//
   454  	// On the server, Symlink has a write concurrency guarantee.
   455  	Symlink(name string, target string, uid UID, gid GID) (*ControlFD, linux.Statx, error)
   456  
   457  	// Link creates a hard link to the file represented by this FD. The hard link
   458  	// is created inside dir with the specified name.
   459  	//
   460  	// On the server, Link has a write concurrency guarantee for dir and read
   461  	// concurrency guarantee for this file.
   462  	Link(dir ControlFDImpl, name string) (*ControlFD, linux.Statx, error)
   463  
   464  	// StatFS returns information about the file system associated with
   465  	// this file.
   466  	//
   467  	// On the server, StatFS has read concurrency guarantee.
   468  	StatFS() (StatFS, error)
   469  
   470  	// Readlink reads the symlink's target and writes the string into the buffer
   471  	// returned by getLinkBuf which can be used to request buffer for some size.
   472  	// It returns the number of bytes written into the buffer.
   473  	//
   474  	// On the server, Readlink has a read concurrency guarantee.
   475  	Readlink(getLinkBuf func(uint32) []byte) (uint16, error)
   476  
   477  	// Connect establishes a new host-socket backed connection with a unix domain
   478  	// socket. On success it returns a non-blocking host socket FD whose
   479  	// lifecycle is independent of this ControlFD.
   480  	//
   481  	// sockType indicates the requested type of socket and can be passed as type
   482  	// argument to socket(2).
   483  	//
   484  	// On the server, Connect has a read concurrency guarantee.
   485  	Connect(sockType uint32) (int, error)
   486  
   487  	// BindAt creates a host unix domain socket of type sockType, bound to
   488  	// the given namt of type sockType, bound to the given name. It returns
   489  	// a ControlFD that can be used for path operations on the socket, a
   490  	// BoundSocketFD that can be used to Accept/Listen on the socket, and a
   491  	// host FD that can be used for event notifications (like new
   492  	// connections).
   493  	//
   494  	// On the server, BindAt has a write concurrency guarantee.
   495  	BindAt(name string, sockType uint32, mode linux.FileMode, uid UID, gid GID) (*ControlFD, linux.Statx, *BoundSocketFD, int, error)
   496  
   497  	// UnlinkAt the file identified by name in this directory.
   498  	//
   499  	// Flags are Linux unlinkat(2) flags.
   500  	//
   501  	// On the server, UnlinkAt has a write concurrency guarantee.
   502  	Unlink(name string, flags uint32) error
   503  
   504  	// RenameAt renames a given file to a new name in a potentially new directory.
   505  	//
   506  	// oldName must be a name relative to this file, which must be a directory.
   507  	// newName is a name relative to newDir.
   508  	//
   509  	// On the server, RenameAt has a global concurrency guarantee.
   510  	RenameAt(oldName string, newDir ControlFDImpl, newName string) error
   511  
   512  	// Renamed is called to notify the FD implementation that the file has been
   513  	// renamed. FD implementation may update its state accordingly.
   514  	//
   515  	// On the server, Renamed has a global concurrency guarantee.
   516  	Renamed()
   517  
   518  	// GetXattr returns extended attributes of this file. It returns the number
   519  	// of bytes written into the buffer returned by getValueBuf which can be used
   520  	// to request buffer for some size.
   521  	//
   522  	// If the value is larger than size, implementations may return ERANGE to
   523  	// indicate that the buffer is too small.
   524  	//
   525  	// N.B. size may be 0, in which can the implementation must first find out
   526  	// the attribute value size using getxattr(2) by passing size=0. Then request
   527  	// a buffer large enough using getValueBuf and write the value there.
   528  	//
   529  	// On the server, GetXattr has a read concurrency guarantee.
   530  	GetXattr(name string, size uint32, getValueBuf func(uint32) []byte) (uint16, error)
   531  
   532  	// SetXattr sets extended attributes on this file.
   533  	//
   534  	// On the server, SetXattr has a write concurrency guarantee.
   535  	SetXattr(name string, value string, flags uint32) error
   536  
   537  	// ListXattr lists the names of the extended attributes on this file.
   538  	//
   539  	// Size indicates the size of the buffer that has been allocated to hold the
   540  	// attribute list. If the list would be larger than size, implementations may
   541  	// return ERANGE to indicate that the buffer is too small, but they are also
   542  	// free to ignore the hint entirely (i.e. the value returned may be larger
   543  	// than size). All size checking is done independently at the syscall layer.
   544  	//
   545  	// On the server, ListXattr has a read concurrency guarantee.
   546  	ListXattr(size uint64) (StringArray, error)
   547  
   548  	// RemoveXattr removes extended attributes on this file.
   549  	//
   550  	// On the server, RemoveXattr has a write concurrency guarantee.
   551  	RemoveXattr(name string) error
   552  }
   553  
   554  // OpenFDImpl contains implementation details for a OpenFD. Implementations of
   555  // OpenFDImpl should contain their associated OpenFD by value as their first
   556  // field.
   557  //
   558  // Since these operations do not perform any path traversal or any modification
   559  // to the filesystem tree, there is no need to synchronize with rename
   560  // operations.
   561  type OpenFDImpl interface {
   562  	// FD returns a pointer to the embedded OpenFD.
   563  	FD() *OpenFD
   564  
   565  	// Close should clean up resources used by the open FD implementation.
   566  	// Close is called after all references on the FD have been dropped and its
   567  	// FDID has been released.
   568  	//
   569  	// On the server, Close has no concurrency guarantee.
   570  	Close()
   571  
   572  	// Stat returns the stat(2) results for this FD.
   573  	//
   574  	// On the server, Stat has a read concurrency guarantee.
   575  	Stat() (linux.Statx, error)
   576  
   577  	// Sync is similar to fsync(2).
   578  	//
   579  	// On the server, Sync has a read concurrency guarantee.
   580  	Sync() error
   581  
   582  	// Write writes buf at offset off to the backing file via this open FD. Write
   583  	// attempts to write len(buf) bytes and returns the number of bytes written.
   584  	//
   585  	// On the server, Write has a write concurrency guarantee. See Open for
   586  	// additional requirements regarding lazy path resolution.
   587  	Write(buf []byte, off uint64) (uint64, error)
   588  
   589  	// Read reads at offset off into buf from the backing file via this open FD.
   590  	// Read attempts to read len(buf) bytes and returns the number of bytes read.
   591  	//
   592  	// On the server, Read has a read concurrency guarantee. See Open for
   593  	// additional requirements regarding lazy path resolution.
   594  	Read(buf []byte, off uint64) (uint64, error)
   595  
   596  	// Allocate allows the caller to directly manipulate the allocated disk space
   597  	// for the file. See fallocate(2) for more details.
   598  	//
   599  	// On the server, Allocate has a write concurrency guarantee.
   600  	Allocate(mode, off, length uint64) error
   601  
   602  	// Flush can be used to clean up the file state. Behavior is
   603  	// implementation-specific.
   604  	//
   605  	// On the server, Flush has a read concurrency guarantee.
   606  	Flush() error
   607  
   608  	// Getdent64 fetches directory entries for this directory and calls
   609  	// recordDirent for each dirent read. If seek0 is true, then the directory FD
   610  	// is seeked to 0 and iteration starts from the beginning.
   611  	//
   612  	// On the server, Getdent64 has a read concurrency guarantee.
   613  	Getdent64(count uint32, seek0 bool, recordDirent func(Dirent64)) error
   614  
   615  	// Renamed is called to notify the FD implementation that the file has been
   616  	// renamed. FD implementation may update its state accordingly.
   617  	//
   618  	// On the server, Renamed has a global concurrency guarantee.
   619  	Renamed()
   620  }
   621  
   622  // BoundSocketFDImpl represents a socket on the host filesystem that has been
   623  // created by the sandboxed application via Bind.
   624  type BoundSocketFDImpl interface {
   625  	// FD returns a pointer to the embedded BoundSocketFD.
   626  	FD() *BoundSocketFD
   627  
   628  	// Listen marks the socket as accepting incoming connections.
   629  	//
   630  	// On the server, Listen has a read concurrency guarantee.
   631  	Listen(backlog int32) error
   632  
   633  	// Accept takes the first pending connection and creates a new socket
   634  	// for it. The new socket FD is returned along with the peer address of
   635  	// the connecting socket (which may be empty string).
   636  	//
   637  	// On the server, Accept has a read concurrency guarantee.
   638  	Accept() (int, string, error)
   639  
   640  	// Close should clean up resources used by the bound socket FD
   641  	// implementation.
   642  	//
   643  	// Close is called after all references on the FD have been dropped and its
   644  	// FDID has been released.
   645  	//
   646  	// On the server, Close has no concurrency guarantee.
   647  	Close()
   648  }