mirror of
https://github.com/hanzoai/visor.git
synced 2026-09-24 17:04:14 +00:00
664 lines
24 KiB
Go
664 lines
24 KiB
Go
// Copyright 2021 The gVisor Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package lisafs
|
|
|
|
import (
|
|
"golang.org/x/sys/unix"
|
|
"gvisor.dev/gvisor/pkg/abi/linux"
|
|
"gvisor.dev/gvisor/pkg/context"
|
|
"gvisor.dev/gvisor/pkg/refs"
|
|
"gvisor.dev/gvisor/pkg/sync"
|
|
)
|
|
|
|
// FDID (file descriptor identifier) is used to identify FDs on a connection.
|
|
// Each connection has its own FDID namespace.
|
|
//
|
|
// +marshal boundCheck slice:FDIDSlice
|
|
type FDID uint64
|
|
|
|
// InvalidFDID represents an invalid FDID.
|
|
const InvalidFDID FDID = 0
|
|
|
|
// Ok returns true if f is a valid FDID.
|
|
func (f FDID) Ok() bool {
|
|
return f != InvalidFDID
|
|
}
|
|
|
|
// genericFD can represent any type of FD.
|
|
type genericFD interface {
|
|
refs.RefCounter
|
|
}
|
|
|
|
// A ControlFD is the gateway to the backing filesystem tree node. It is an
|
|
// unusual concept. This exists to provide a safe way to do path-based
|
|
// operations on the file. It performs operations that can modify the
|
|
// filesystem tree and synchronizes these operations. See ControlFDImpl for
|
|
// supported operations.
|
|
//
|
|
// It is not an inode, because multiple control FDs are allowed to exist on the
|
|
// same file. It is not a file descriptor because it is not tied to any access
|
|
// mode, i.e. a control FD can change its access mode based on the operation
|
|
// being performed.
|
|
//
|
|
// Reference Model:
|
|
// - Each control FD holds a ref on its Node for its entire lifetime.
|
|
type ControlFD struct {
|
|
controlFDRefs
|
|
controlFDEntry
|
|
|
|
// node is the filesystem node this FD is immutably associated with.
|
|
node *Node
|
|
|
|
// openFDs is a linked list of all FDs opened on this FD. As per reference
|
|
// model, all open FDs hold a ref on this FD.
|
|
openFDsMu sync.RWMutex
|
|
openFDs openFDList
|
|
|
|
// All the following fields are immutable.
|
|
|
|
// id is the unique FD identifier which identifies this FD on its connection.
|
|
id FDID
|
|
|
|
// conn is the backing connection owning this FD.
|
|
conn *Connection
|
|
|
|
// ftype is the file type of the backing inode. ftype.FileType() == ftype.
|
|
ftype linux.FileMode
|
|
|
|
// impl is the control FD implementation which embeds this struct. It
|
|
// contains all the implementation specific details.
|
|
impl ControlFDImpl
|
|
}
|
|
|
|
var _ genericFD = (*ControlFD)(nil)
|
|
|
|
// DecRef implements refs.RefCounter.DecRef. Note that the context
|
|
// parameter should never be used. It exists solely to comply with the
|
|
// refs.RefCounter interface.
|
|
func (fd *ControlFD) DecRef(context.Context) {
|
|
fd.controlFDRefs.DecRef(func() {
|
|
fd.conn.server.renameMu.RLock()
|
|
defer fd.conn.server.renameMu.RUnlock()
|
|
fd.destroyLocked()
|
|
})
|
|
}
|
|
|
|
// decRefLocked is the same as DecRef except the added precondition.
|
|
//
|
|
// Precondition: server's rename mutex must be at least read locked.
|
|
func (fd *ControlFD) decRefLocked() {
|
|
fd.controlFDRefs.DecRef(func() {
|
|
fd.destroyLocked()
|
|
})
|
|
}
|
|
|
|
// Precondition: server's rename mutex must be at least read locked.
|
|
func (fd *ControlFD) destroyLocked() {
|
|
// Update node's control FD list.
|
|
fd.node.removeFD(fd)
|
|
|
|
// Drop ref on node.
|
|
fd.node.DecRef(nil)
|
|
|
|
// Let the FD implementation clean up.
|
|
fd.impl.Close()
|
|
}
|
|
|
|
// Init must be called before first use of fd. It inserts fd into the
|
|
// filesystem tree.
|
|
//
|
|
// Preconditions:
|
|
// - server's rename mutex must be at least read locked.
|
|
// - The caller must take a ref on node which is transferred to fd.
|
|
func (fd *ControlFD) Init(c *Connection, node *Node, mode linux.FileMode, impl ControlFDImpl) {
|
|
fd.conn = c
|
|
fd.node = node
|
|
fd.impl = impl
|
|
fd.ftype = mode.FileType()
|
|
// Initialize fd with 1 ref which is transferred to c via c.insertFD().
|
|
fd.controlFDRefs.InitRefs()
|
|
// Make fd reachable/discoverable.
|
|
fd.id = c.insertFD(fd)
|
|
node.insertFD(fd)
|
|
}
|
|
|
|
// Conn returns the fd's owning connection.
|
|
func (fd *ControlFD) Conn() *Connection {
|
|
return fd.conn
|
|
}
|
|
|
|
// FileType returns the file mode only containing the file type bits.
|
|
func (fd *ControlFD) FileType() linux.FileMode {
|
|
return fd.ftype
|
|
}
|
|
|
|
// IsDir indicates whether fd represents a directory.
|
|
func (fd *ControlFD) IsDir() bool {
|
|
return fd.ftype == unix.S_IFDIR
|
|
}
|
|
|
|
// IsRegular indicates whether fd represents a regular file.
|
|
func (fd *ControlFD) IsRegular() bool {
|
|
return fd.ftype == unix.S_IFREG
|
|
}
|
|
|
|
// IsSymlink indicates whether fd represents a symbolic link.
|
|
func (fd *ControlFD) IsSymlink() bool {
|
|
return fd.ftype == unix.S_IFLNK
|
|
}
|
|
|
|
// IsSocket indicates whether fd represents a socket.
|
|
func (fd *ControlFD) IsSocket() bool {
|
|
return fd.ftype == unix.S_IFSOCK
|
|
}
|
|
|
|
// Node returns the node this FD was opened on.
|
|
func (fd *ControlFD) Node() *Node {
|
|
return fd.node
|
|
}
|
|
|
|
// RemoveFromConn removes this control FD from its owning connection.
|
|
//
|
|
// Preconditions:
|
|
// - fd should not have been returned to the client. Otherwise the client can
|
|
// still refer to it.
|
|
// - server's rename mutex must at least be read locked.
|
|
func (fd *ControlFD) RemoveFromConn() {
|
|
fd.conn.removeControlFDLocked(fd.id)
|
|
}
|
|
|
|
// safelyRead executes the given operation with the local path node locked.
|
|
// This guarantees that fd's path will not change. fn may not any change paths.
|
|
func (fd *ControlFD) safelyRead(fn func() error) error {
|
|
fd.conn.server.renameMu.RLock()
|
|
defer fd.conn.server.renameMu.RUnlock()
|
|
fd.node.opMu.RLock()
|
|
defer fd.node.opMu.RUnlock()
|
|
return fn()
|
|
}
|
|
|
|
// safelyWrite executes the given operation with the local path node locked in
|
|
// a writable fashion. This guarantees that no other operation is executing on
|
|
// this path node. fn may change paths inside fd.node.
|
|
func (fd *ControlFD) safelyWrite(fn func() error) error {
|
|
fd.conn.server.renameMu.RLock()
|
|
defer fd.conn.server.renameMu.RUnlock()
|
|
fd.node.opMu.Lock()
|
|
defer fd.node.opMu.Unlock()
|
|
return fn()
|
|
}
|
|
|
|
// safelyGlobal executes the given operation with the global path lock held.
|
|
// This guarantees that no other operations is executing concurrently on this
|
|
// server. fn may change any path.
|
|
func (fd *ControlFD) safelyGlobal(fn func() error) (err error) {
|
|
fd.conn.server.renameMu.Lock()
|
|
defer fd.conn.server.renameMu.Unlock()
|
|
return fn()
|
|
}
|
|
|
|
// forEachOpenFD executes fn on each FD opened on fd.
|
|
func (fd *ControlFD) forEachOpenFD(fn func(ofd *OpenFD)) {
|
|
fd.openFDsMu.RLock()
|
|
defer fd.openFDsMu.RUnlock()
|
|
for ofd := fd.openFDs.Front(); ofd != nil; ofd = ofd.Next() {
|
|
fn(ofd)
|
|
}
|
|
}
|
|
|
|
// OpenFD represents an open file descriptor on the protocol. It resonates
|
|
// closely with a Linux file descriptor. Its operations are limited to the
|
|
// file. Its operations are not allowed to modify or traverse the filesystem
|
|
// tree. See OpenFDImpl for the supported operations.
|
|
//
|
|
// Reference Model:
|
|
// - An OpenFD takes a reference on the control FD it was opened on.
|
|
type OpenFD struct {
|
|
openFDRefs
|
|
openFDEntry
|
|
|
|
// All the following fields are immutable.
|
|
|
|
// controlFD is the ControlFD on which this FD was opened. OpenFD holds a ref
|
|
// on controlFD for its entire lifetime.
|
|
controlFD *ControlFD
|
|
|
|
// id is the unique FD identifier which identifies this FD on its connection.
|
|
id FDID
|
|
|
|
// Access mode for this FD.
|
|
readable bool
|
|
writable bool
|
|
|
|
// impl is the open FD implementation which embeds this struct. It
|
|
// contains all the implementation specific details.
|
|
impl OpenFDImpl
|
|
}
|
|
|
|
var _ genericFD = (*OpenFD)(nil)
|
|
|
|
// ControlFD returns the control FD on which this FD was opened.
|
|
func (fd *OpenFD) ControlFD() ControlFDImpl {
|
|
return fd.controlFD.impl
|
|
}
|
|
|
|
// DecRef implements refs.RefCounter.DecRef. Note that the context
|
|
// parameter should never be used. It exists solely to comply with the
|
|
// refs.RefCounter interface.
|
|
func (fd *OpenFD) DecRef(context.Context) {
|
|
fd.openFDRefs.DecRef(func() {
|
|
fd.controlFD.openFDsMu.Lock()
|
|
fd.controlFD.openFDs.Remove(fd)
|
|
fd.controlFD.openFDsMu.Unlock()
|
|
fd.controlFD.DecRef(nil) // Drop the ref on the control FD.
|
|
fd.impl.Close()
|
|
})
|
|
}
|
|
|
|
// Init must be called before first use of fd.
|
|
func (fd *OpenFD) Init(cfd *ControlFD, flags uint32, impl OpenFDImpl) {
|
|
// Initialize fd with 1 ref which is transferred to c via c.insertFD().
|
|
fd.openFDRefs.InitRefs()
|
|
fd.controlFD = cfd
|
|
fd.id = cfd.conn.insertFD(fd)
|
|
accessMode := flags & unix.O_ACCMODE
|
|
fd.readable = accessMode == unix.O_RDONLY || accessMode == unix.O_RDWR
|
|
fd.writable = accessMode == unix.O_WRONLY || accessMode == unix.O_RDWR
|
|
fd.impl = impl
|
|
cfd.IncRef() // Holds a ref on cfd for its lifetime.
|
|
cfd.openFDsMu.Lock()
|
|
cfd.openFDs.PushBack(fd)
|
|
cfd.openFDsMu.Unlock()
|
|
}
|
|
|
|
// BoundSocketFD represents a bound socket on the server.
|
|
//
|
|
// Reference Model:
|
|
// - A BoundSocketFD takes a reference on the control FD it is bound to.
|
|
type BoundSocketFD struct {
|
|
boundSocketFDRefs
|
|
|
|
// All the following fields are immutable.
|
|
|
|
// controlFD is the ControlFD on which this FD was bound. BoundSocketFD
|
|
// holds a ref on controlFD for its entire lifetime.
|
|
controlFD *ControlFD
|
|
|
|
// id is the unique FD identifier which identifies this FD on its connection.
|
|
id FDID
|
|
|
|
// impl is the socket FD implementation which embeds this struct. It
|
|
// contains all the implementation specific details.
|
|
impl BoundSocketFDImpl
|
|
}
|
|
|
|
var _ genericFD = (*BoundSocketFD)(nil)
|
|
|
|
// ControlFD returns the control FD on which this FD was bound.
|
|
func (fd *BoundSocketFD) ControlFD() ControlFDImpl {
|
|
return fd.controlFD.impl
|
|
}
|
|
|
|
// DecRef implements refs.RefCounter.DecRef. Note that the context
|
|
// parameter should never be used. It exists solely to comply with the
|
|
// refs.RefCounter interface.
|
|
func (fd *BoundSocketFD) DecRef(context.Context) {
|
|
fd.boundSocketFDRefs.DecRef(func() {
|
|
fd.controlFD.DecRef(nil) // Drop the ref on the control FD.
|
|
fd.impl.Close()
|
|
})
|
|
}
|
|
|
|
// Init must be called before first use of fd.
|
|
func (fd *BoundSocketFD) Init(cfd *ControlFD, impl BoundSocketFDImpl) {
|
|
// Initialize fd with 1 ref which is transferred to c via c.insertFD().
|
|
fd.boundSocketFDRefs.InitRefs()
|
|
fd.controlFD = cfd
|
|
fd.id = cfd.conn.insertFD(fd)
|
|
fd.impl = impl
|
|
cfd.IncRef() // Holds a ref on cfd for its lifetime.
|
|
}
|
|
|
|
// There are four different types of guarantees provided:
|
|
//
|
|
// none: There is no concurrency guarantee. The method may be invoked
|
|
// concurrently with any other method on any other FD.
|
|
//
|
|
// read: The method is guaranteed to be exclusive of any write or global
|
|
// operation that is mutating the state of the directory tree starting at this
|
|
// node. For example, this means creating new files, symlinks, directories or
|
|
// renaming a directory entry (or renaming in to this target), but the method
|
|
// may be called concurrently with other read methods.
|
|
//
|
|
// write: The method is guaranteed to be exclusive of any read, write or global
|
|
// operation that is mutating the state of the directory tree starting at this
|
|
// node, as described in read above. There may however, be other write
|
|
// operations executing concurrently on other components in the directory tree.
|
|
//
|
|
// global: The method is guaranteed to be exclusive of any read, write or
|
|
// global operation.
|
|
|
|
// ControlFDImpl contains implementation details for a ControlFD.
|
|
// Implementations of ControlFDImpl should contain their associated ControlFD
|
|
// by value as their first field.
|
|
//
|
|
// The operations that perform path traversal or any modification to the
|
|
// filesystem tree must synchronize those modifications with the server's
|
|
// rename mutex.
|
|
type ControlFDImpl interface {
|
|
// FD returns a pointer to the embedded ControlFD.
|
|
FD() *ControlFD
|
|
|
|
// Close should clean up resources used by the control FD implementation.
|
|
// Close is called after all references on the FD have been dropped and its
|
|
// FDID has been released.
|
|
//
|
|
// On the server, Close has no concurrency guarantee.
|
|
Close()
|
|
|
|
// Stat returns the stat(2) results for this FD.
|
|
//
|
|
// On the server, Stat has a read concurrency guarantee.
|
|
Stat() (Statx, error)
|
|
|
|
// SetStat sets file attributes on the backing file. This does not correspond
|
|
// to any one Linux syscall. On Linux, this operation is performed using
|
|
// multiple syscalls like fchmod(2), fchown(2), ftruncate(2), futimesat(2)
|
|
// and so on. The implementation must only set attributes for fields
|
|
// indicated by stat.Mask. Failure to set an attribute may or may not
|
|
// terminate the entire operation. SetStat must return a uint32 which is
|
|
// interpreted as a stat mask to indicate which attribute setting attempts
|
|
// failed. If multiple attribute setting attempts failed, the returned error
|
|
// may be from any one of them.
|
|
//
|
|
// On the server, SetStat has a write concurrency guarantee.
|
|
SetStat(stat SetStatReq) (uint32, error)
|
|
|
|
// Walk walks one path component from the directory represented by this FD.
|
|
// Walk must open a ControlFD on the walked file.
|
|
//
|
|
// On the server, Walk has a read concurrency guarantee.
|
|
Walk(name string) (*ControlFD, Statx, error)
|
|
|
|
// WalkStat is capable of walking multiple path components and returning the
|
|
// stat results for each path component walked via recordStat. Stat results
|
|
// must be returned in the order of walk.
|
|
//
|
|
// In case a symlink is encountered, the walk must terminate successfully on
|
|
// the symlink including its stat result.
|
|
//
|
|
// The first path component of path may be "" which indicates that the first
|
|
// stat result returned must be of this starting directory.
|
|
//
|
|
// On the server, WalkStat has a read concurrency guarantee.
|
|
WalkStat(path StringArray, recordStat func(Statx)) error
|
|
|
|
// Open opens the control FD with the flags passed. The flags should be
|
|
// interpreted as open(2) flags.
|
|
//
|
|
// Open may also optionally return a host FD for the opened file whose
|
|
// lifecycle is independent of the OpenFD. Returns -1 if not available.
|
|
//
|
|
// N.B. The server must resolve any lazy paths when open is called.
|
|
// After this point, read and write may be called on files with no
|
|
// deletion check, so resolving in the data path is not viable.
|
|
//
|
|
// On the server, Open has a read concurrency guarantee.
|
|
Open(flags uint32) (*OpenFD, int, error)
|
|
|
|
// OpenCreate creates a regular file inside the directory represented by this
|
|
// FD and then also opens the file. The created file has perms as specified
|
|
// by mode and owners as specified by uid and gid. The file is opened with
|
|
// the specified flags.
|
|
//
|
|
// OpenCreate may also optionally return a host FD for the opened file whose
|
|
// lifecycle is independent of the OpenFD. Returns -1 if not available.
|
|
//
|
|
// N.B. The server must resolve any lazy paths when open is called.
|
|
// After this point, read and write may be called on files with no
|
|
// deletion check, so resolving in the data path is not viable.
|
|
//
|
|
// On the server, OpenCreate has a write concurrency guarantee.
|
|
OpenCreate(mode linux.FileMode, uid UID, gid GID, name string, flags uint32) (*ControlFD, Statx, *OpenFD, int, error)
|
|
|
|
// Mkdir creates a directory inside the directory represented by this FD. The
|
|
// created directory has perms as specified by mode and owners as specified
|
|
// by uid and gid.
|
|
//
|
|
// On the server, Mkdir has a write concurrency guarantee.
|
|
Mkdir(mode linux.FileMode, uid UID, gid GID, name string) (*ControlFD, Statx, error)
|
|
|
|
// Mknod creates a file inside the directory represented by this FD. The file
|
|
// type and perms are specified by mode and owners are specified by uid and
|
|
// gid. If the newly created file is a character or block device, minor and
|
|
// major specify its device number.
|
|
//
|
|
// On the server, Mkdir has a write concurrency guarantee.
|
|
Mknod(mode linux.FileMode, uid UID, gid GID, name string, minor uint32, major uint32) (*ControlFD, Statx, error)
|
|
|
|
// Symlink creates a symlink inside the directory represented by this FD. The
|
|
// symlink has owners as specified by uid and gid and points to target.
|
|
//
|
|
// On the server, Symlink has a write concurrency guarantee.
|
|
Symlink(name string, target string, uid UID, gid GID) (*ControlFD, Statx, error)
|
|
|
|
// Link creates a hard link to the file represented by this FD. The hard link
|
|
// is created inside dir with the specified name.
|
|
//
|
|
// On the server, Link has a write concurrency guarantee for dir and read
|
|
// concurrency guarantee for this file.
|
|
Link(dir ControlFDImpl, name string) (*ControlFD, Statx, error)
|
|
|
|
// StatFS returns information about the file system associated with
|
|
// this file.
|
|
//
|
|
// On the server, StatFS has read concurrency guarantee.
|
|
StatFS() (StatFS, error)
|
|
|
|
// Readlink reads the symlink's target and writes the string into the buffer
|
|
// returned by getLinkBuf which can be used to request buffer for some size.
|
|
// It returns the number of bytes written into the buffer.
|
|
//
|
|
// On the server, Readlink has a read concurrency guarantee.
|
|
Readlink(getLinkBuf func(uint32) []byte) (uint16, error)
|
|
|
|
// Connect establishes a new host-socket backed connection with a unix domain
|
|
// socket. On success it returns a non-blocking host socket FD whose
|
|
// lifecycle is independent of this ControlFD.
|
|
//
|
|
// sockType indicates the requested type of socket and can be passed as type
|
|
// argument to socket(2).
|
|
//
|
|
// On the server, Connect has a read concurrency guarantee.
|
|
Connect(sockType uint32) (int, error)
|
|
|
|
// ConnectWithCreds is a wrapper around Connect but first changes the gofer's
|
|
// euid and egid to the given uid and gid before calling Connect. It restores
|
|
// the euid and egid after Connect.
|
|
//
|
|
// On the server, ConnectWithCreds has a read concurrency guarantee.
|
|
ConnectWithCreds(sockType uint32, uid UID, gid GID) (int, error)
|
|
|
|
// BindAt creates a host unix domain socket of type sockType, bound to
|
|
// the given namt of type sockType, bound to the given name. It returns
|
|
// a ControlFD that can be used for path operations on the socket, a
|
|
// BoundSocketFD that can be used to Accept/Listen on the socket, and a
|
|
// host FD that can be used for event notifications (like new
|
|
// connections).
|
|
//
|
|
// On the server, BindAt has a write concurrency guarantee.
|
|
BindAt(name string, sockType uint32, mode linux.FileMode, uid UID, gid GID) (*ControlFD, Statx, *BoundSocketFD, int, error)
|
|
|
|
// UnlinkAt the file identified by name in this directory.
|
|
//
|
|
// Flags are Linux unlinkat(2) flags.
|
|
//
|
|
// On the server, UnlinkAt has a write concurrency guarantee.
|
|
Unlink(name string, flags uint32) error
|
|
|
|
// RenameAt renames a given file to a new name in a potentially new directory.
|
|
//
|
|
// oldName must be a name relative to this file, which must be a directory.
|
|
// newName is a name relative to newDir.
|
|
//
|
|
// On the server, RenameAt has a global concurrency guarantee.
|
|
RenameAt(oldName string, newDir ControlFDImpl, newName string) error
|
|
|
|
// RenameAt2 renames a given file to a new name in a potentially new directory.
|
|
//
|
|
// oldName must be a name relative to this file, which must be a directory.
|
|
// newName is a name relative to newDir.
|
|
//
|
|
// On the server, RenameAt2 has a global concurrency guarantee.
|
|
RenameAt2(oldName string, newDir ControlFDImpl, newName string, flags uint32) error
|
|
|
|
// Renamed is called to notify the FD implementation that the file has been
|
|
// renamed. FD implementation may update its state accordingly.
|
|
//
|
|
// On the server, Renamed has a global concurrency guarantee.
|
|
Renamed()
|
|
|
|
// GetXattr returns extended attributes of this file. It returns the number
|
|
// of bytes written into the buffer returned by getValueBuf which can be used
|
|
// to request buffer for some size.
|
|
//
|
|
// If the value is larger than size, implementations may return ERANGE to
|
|
// indicate that the buffer is too small.
|
|
//
|
|
// N.B. size may be 0, in which can the implementation must first find out
|
|
// the attribute value size using getxattr(2) by passing size=0. Then request
|
|
// a buffer large enough using getValueBuf and write the value there.
|
|
//
|
|
// On the server, GetXattr has a read concurrency guarantee.
|
|
GetXattr(name string, size uint32, getValueBuf func(uint32) []byte) (uint16, error)
|
|
|
|
// SetXattr sets extended attributes on this file.
|
|
//
|
|
// On the server, SetXattr has a write concurrency guarantee.
|
|
SetXattr(name string, value string, flags uint32) error
|
|
|
|
// ListXattr lists the names of the extended attributes on this file.
|
|
//
|
|
// Size indicates the size of the buffer that has been allocated to hold the
|
|
// attribute list. If the list would be larger than size, implementations may
|
|
// return ERANGE to indicate that the buffer is too small, but they are also
|
|
// free to ignore the hint entirely (i.e. the value returned may be larger
|
|
// than size). All size checking is done independently at the syscall layer.
|
|
//
|
|
// On the server, ListXattr has a read concurrency guarantee.
|
|
ListXattr(size uint64) (StringArray, error)
|
|
|
|
// RemoveXattr removes extended attributes on this file.
|
|
//
|
|
// On the server, RemoveXattr has a write concurrency guarantee.
|
|
RemoveXattr(name string) error
|
|
}
|
|
|
|
// OpenFDImpl contains implementation details for a OpenFD. Implementations of
|
|
// OpenFDImpl should contain their associated OpenFD by value as their first
|
|
// field.
|
|
//
|
|
// Since these operations do not perform any path traversal or any modification
|
|
// to the filesystem tree, there is no need to synchronize with rename
|
|
// operations.
|
|
type OpenFDImpl interface {
|
|
// FD returns a pointer to the embedded OpenFD.
|
|
FD() *OpenFD
|
|
|
|
// Close should clean up resources used by the open FD implementation.
|
|
// Close is called after all references on the FD have been dropped and its
|
|
// FDID has been released.
|
|
//
|
|
// On the server, Close has no concurrency guarantee.
|
|
Close()
|
|
|
|
// Stat returns the stat(2) results for this FD.
|
|
//
|
|
// On the server, Stat has a read concurrency guarantee.
|
|
Stat() (Statx, error)
|
|
|
|
// Sync is similar to fsync(2).
|
|
//
|
|
// On the server, Sync has a read concurrency guarantee.
|
|
Sync() error
|
|
|
|
// Write writes buf at offset off to the backing file via this open FD. Write
|
|
// attempts to write len(buf) bytes and returns the number of bytes written.
|
|
//
|
|
// On the server, Write has a write concurrency guarantee. See Open for
|
|
// additional requirements regarding lazy path resolution.
|
|
Write(buf []byte, off uint64) (uint64, error)
|
|
|
|
// Read reads at offset off into buf from the backing file via this open FD.
|
|
// Read attempts to read len(buf) bytes and returns the number of bytes read.
|
|
//
|
|
// On the server, Read has a read concurrency guarantee. See Open for
|
|
// additional requirements regarding lazy path resolution.
|
|
Read(buf []byte, off uint64) (uint64, error)
|
|
|
|
// Allocate allows the caller to directly manipulate the allocated disk space
|
|
// for the file. See fallocate(2) for more details.
|
|
//
|
|
// On the server, Allocate has a write concurrency guarantee.
|
|
Allocate(mode, off, length uint64) error
|
|
|
|
// Flush can be used to clean up the file state. Behavior is
|
|
// implementation-specific.
|
|
//
|
|
// On the server, Flush has a read concurrency guarantee.
|
|
Flush() error
|
|
|
|
// Getdent64 fetches directory entries for this directory and calls
|
|
// recordDirent for each dirent read. If seek0 is true, then the directory FD
|
|
// is seeked to 0 and iteration starts from the beginning.
|
|
//
|
|
// On the server, Getdent64 has a read concurrency guarantee.
|
|
Getdent64(count uint32, seek0 bool, recordDirent func(Dirent64)) error
|
|
|
|
// Renamed is called to notify the FD implementation that the file has been
|
|
// renamed. FD implementation may update its state accordingly.
|
|
//
|
|
// On the server, Renamed has a global concurrency guarantee.
|
|
Renamed()
|
|
}
|
|
|
|
// BoundSocketFDImpl represents a socket on the host filesystem that has been
|
|
// created by the sandboxed application via Bind.
|
|
type BoundSocketFDImpl interface {
|
|
// FD returns a pointer to the embedded BoundSocketFD.
|
|
FD() *BoundSocketFD
|
|
|
|
// Listen marks the socket as accepting incoming connections.
|
|
//
|
|
// On the server, Listen has a read concurrency guarantee.
|
|
Listen(backlog int32) error
|
|
|
|
// Accept takes the first pending connection and creates a new socket
|
|
// for it. The new socket FD is returned along with the peer address of
|
|
// the connecting socket (which may be empty string).
|
|
//
|
|
// On the server, Accept has a read concurrency guarantee.
|
|
Accept() (int, string, error)
|
|
|
|
// Close should clean up resources used by the bound socket FD
|
|
// implementation.
|
|
//
|
|
// Close is called after all references on the FD have been dropped and its
|
|
// FDID has been released.
|
|
//
|
|
// On the server, Close has no concurrency guarantee.
|
|
Close()
|
|
}
|