virtual

package
v0.0.0-...-ea22f37 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 1, 2024 License: Apache-2.0 Imports: 37 Imported by: 2

Documentation

Index

Constants

View Source
const (
	// ImplicitDirectoryLinkCount is the value that should be
	// assigned to fuse.attr.Nlink for directory nodes for which the
	// directory contents are not defined explicitly. These may be
	// directories that are lazy-loading, or have an infinite number
	// of children due to them being defined programmatically.
	//
	// It is important that we return a link count lower than two
	// for these directories. Tools like GNU find(1) rely on an
	// accurate link count to rule out the existence of child
	// directories. A link count below two instructs them to disable
	// such optimizations, forcing them to read directory listings.
	// See the "-noleaf" option in find(1)'s man page for details.
	//
	// File systems such as btrfs also set the link count of
	// directories to one.
	ImplicitDirectoryLinkCount uint32 = 1
	// EmptyDirectoryLinkCount is the value that should be assigned
	// to fuse.attr.Nlink for directory nodes that do not have any
	// child directories.
	EmptyDirectoryLinkCount uint32 = 2
)
View Source
const StatelessLeafLinkCount = 9999

StatelessLeafLinkCount is the value that should be assigned to fuse.Attr.Nlink for leaf nodes that don't track an explicit link count, such as files backed by the Content Addressable Storage (CAS).

The Linux kernel doesn't treat fuse.Attr.Nlink as an opaque value. Its value gets stored in the kernel inode structure's i_nlink field. This cached value may later be incremented and decremented inside fuse_link() and fuse_unlink(), meaning that it may reach zero. Once zero, the kernel thinks the file is unlinked, causing future link() calls to fail.

This means that the value of fuse.Attr.Nlink should ideally reflect the true number of paths under which these files are visible. For stateless files that is impossible to achieve, as they may appear in an arbitrary number of places that aren't known up front. Solve this by using a constant value that is sufficiently high for most use cases.

References: - https://github.com/torvalds/linux/blob/01c70267053d6718820ac0902d8823d5dd2a6adb/fs/fuse/inode.c#L161 - https://github.com/torvalds/linux/blob/01c70267053d6718820ac0902d8823d5dd2a6adb/fs/fuse/dir.c#L874 - https://github.com/torvalds/linux/blob/01c70267053d6718820ac0902d8823d5dd2a6adb/fs/fuse/dir.c#L726 - https://github.com/torvalds/linux/blob/01c70267053d6718820ac0902d8823d5dd2a6adb/fs/namei.c#L4066-L4067

Variables

This section is empty.

Functions

func BoundReadToFileSize

func BoundReadToFileSize(buf []byte, offset, size uint64) ([]byte, bool)

BoundReadToFileSize is a helper function for implementations of VirtualRead() to limit the read size to the actual file size.

func GetFileInfo

func GetFileInfo(name path.Component, node Node) filesystem.FileInfo

GetFileInfo extracts the attributes of a node and returns it in the form of a FileInfo object.

func ReadOnlyDirectoryOpenChildDoesntExist

func ReadOnlyDirectoryOpenChildDoesntExist(createAttributes *Attributes) (Leaf, AttributesMask, ChangeInfo, Status)

ReadOnlyDirectoryOpenChildDoesntExist is a helper function for implementing Directory.VirtualOpenChild() for read-only directories. It can be used to obtain return values in case the directory doesn't contains any file under a given name.

func ReadOnlyDirectoryOpenChildWrongFileType

func ReadOnlyDirectoryOpenChildWrongFileType(existingOptions *OpenExistingOptions, s Status) (Leaf, AttributesMask, ChangeInfo, Status)

ReadOnlyDirectoryOpenChildWrongFileType is a helper function for implementing Directory.VirtualOpenChild() for read-only directories. It can be used to obtain return values in case the directory already contains a file under a given name.

func Shuffle

func Shuffle(data sort.Interface)

Shuffle elements in a list using the Fisher-Yates algorithm.

Types

type Attributes

type Attributes struct {
	// contains filtered or unexported fields
}

Attributes of a file, normally requested through stat() or readdir(). A bitmask is used to track which attributes are set.

func (*Attributes) GetChangeID

func (a *Attributes) GetChangeID() uint64

GetChangeID returns the change ID, which clients can use to determine if file data, directory contents, or attributes of the node have changed.

func (*Attributes) GetDeviceNumber

func (a *Attributes) GetDeviceNumber() (filesystem.DeviceNumber, bool)

GetDeviceNumber returns the raw device number (st_rdev).

func (*Attributes) GetFileHandle

func (a *Attributes) GetFileHandle() []byte

GetFileHandle returns an identifier of the file that contains sufficient information to be able to resolve it at a later point in time.

func (*Attributes) GetFileType

func (a *Attributes) GetFileType() filesystem.FileType

GetFileType returns the file type (upper 4 bits of st_mode).

func (*Attributes) GetInodeNumber

func (a *Attributes) GetInodeNumber() uint64

GetInodeNumber returns the inode number (st_ino).

func (*Attributes) GetLastDataModificationTime

func (a *Attributes) GetLastDataModificationTime() (time.Time, bool)

GetLastDataModificationTime returns the last data modification time (st_mtim).

func (*Attributes) GetLinkCount

func (a *Attributes) GetLinkCount() uint32

GetLinkCount returns the link count (st_nlink).

func (*Attributes) GetPermissions

func (a *Attributes) GetPermissions() (Permissions, bool)

GetPermissions returns the mode (lowest 12 bits of st_mode).

func (*Attributes) GetSizeBytes

func (a *Attributes) GetSizeBytes() (uint64, bool)

GetSizeBytes returns the file size (st_size).

func (*Attributes) SetChangeID

func (a *Attributes) SetChangeID(changeID uint64) *Attributes

SetChangeID sets the change ID, which clients can use to determine if file data, directory contents, or attributes of the node have changed.

func (*Attributes) SetDeviceNumber

func (a *Attributes) SetDeviceNumber(deviceNumber filesystem.DeviceNumber) *Attributes

SetDeviceNumber sets the raw device number (st_rdev).

func (*Attributes) SetFileHandle

func (a *Attributes) SetFileHandle(fileHandle []byte) *Attributes

SetFileHandle sets an identifier of the file that contains sufficient information to be able to resolve it at a later point in time.

func (*Attributes) SetFileType

func (a *Attributes) SetFileType(fileType filesystem.FileType) *Attributes

SetFileType sets the file type (upper 4 bits of st_mode).

func (*Attributes) SetInodeNumber

func (a *Attributes) SetInodeNumber(inodeNumber uint64) *Attributes

SetInodeNumber sets the inode number (st_ino).

func (*Attributes) SetLastDataModificationTime

func (a *Attributes) SetLastDataModificationTime(lastDataModificationTime time.Time) *Attributes

SetLastDataModificationTime sets the last data modification time (st_mtim).

func (*Attributes) SetLinkCount

func (a *Attributes) SetLinkCount(linkCount uint32) *Attributes

SetLinkCount sets the link count (st_nlink).

func (*Attributes) SetPermissions

func (a *Attributes) SetPermissions(permissions Permissions) *Attributes

SetPermissions sets the mode (lowest 12 bits of st_mode).

func (*Attributes) SetSizeBytes

func (a *Attributes) SetSizeBytes(sizeBytes uint64) *Attributes

SetSizeBytes sets the file size (st_size).

type AttributesMask

type AttributesMask uint32

AttributesMask is a bitmask of status attributes that need to be requested through Node.VirtualGetAttributes().

const (
	// AttributesMaskChangeID requests the change ID, which clients
	// can use to determine if file data, directory contents, or
	// attributes of the node have changed.
	AttributesMaskChangeID AttributesMask = 1 << iota
	// AttributesMaskDeviceNumber requests the raw device number
	// (st_rdev).
	AttributesMaskDeviceNumber
	// AttributesMaskFileHandle requests an identifier of the file
	// that contains sufficient information to be able to resolve it
	// at a later point in time.
	AttributesMaskFileHandle
	// AttributesMaskFileType requests the file type (upper 4 bits
	// of st_mode).
	AttributesMaskFileType
	// AttributesMaskInodeNumber requests the inode number (st_ino).
	AttributesMaskInodeNumber
	// AttributesMaskLastDataModificationTime requests the last data
	// modification time (st_mtim).
	AttributesMaskLastDataModificationTime
	// AttributesMaskLinkCount requests the link count (st_nlink).
	AttributesMaskLinkCount
	// AttributesMaskPermissions requests the permissions (lowest 12
	// bits of set_mode).
	AttributesMaskPermissions
	// AttributesMaskSizeBytes requests the file size (st_size).
	AttributesMaskSizeBytes
)

type ByteRangeLock

type ByteRangeLock[Owner comparable] struct {
	Start uint64
	End   uint64
	Owner Owner
	Type  ByteRangeLockType
}

ByteRangeLock holds information on a lock held on a non-empty range of bytes. Each lock has an owner associated with it. This field is only checked for equality, allowing it to merge adjacent or overlapping locks held by the same owner.

type ByteRangeLockSet

type ByteRangeLockSet[Owner comparable] struct {
	// contains filtered or unexported fields
}

ByteRangeLockSet is a set for ByteRangeLocks applied against the same file. The set is modeled as a linked list, where entries are sorted by starting address. All entries describe disjoint non-empty ranges of bytes, except for shared locks with distinct owners.

func (*ByteRangeLockSet[Owner]) Initialize

func (ls *ByteRangeLockSet[Owner]) Initialize()

Initialize the ByteRangeLockSet, so that it does not contain any locks.

func (*ByteRangeLockSet[Owner]) Set

func (ls *ByteRangeLockSet[Owner]) Set(lProvided *ByteRangeLock[Owner]) int

Set a byte range to a given lock. Calls to this method must generally be preceded by calls to Test(), as it is assumed the lock to be inserted does not conflict with the locks that are currently held.

This method returns the increase (positive) or decrease (negative) of the number of entries in the set. This can be used by the caller to determine when the owner of the lock can be released.

func (*ByteRangeLockSet[Owner]) Test

func (ls *ByteRangeLockSet[Owner]) Test(lTest *ByteRangeLock[Owner]) *ByteRangeLock[Owner]

Test whether a new lock to be inserted does not conflict with any of the other locks registered in the set.

type ByteRangeLockType

type ByteRangeLockType int

ByteRangeLockType is an enumeration that controls what kind of lock needs to be acquired.

const (
	// ByteRangeLockTypeUnlocked indicates that a byte range should
	// be unlocked. This value can only be provided to Set(); not
	// Test(). It is equivalent to POSIX's F_UNLCK.
	ByteRangeLockTypeUnlocked ByteRangeLockType = iota
	// ByteRangeLockTypeLockedExclusive indicates that a byte range
	// should be locked exclusively for writing. It is equivalent to
	// POSIX's F_WRLCK.
	ByteRangeLockTypeLockedExclusive
	// ByteRangeLockTypeLockedShared indicates that a byte range
	// should be locked shared for reading. It is equivalent to
	// F_RDLCK.
	ByteRangeLockTypeLockedShared
)

type ByteSliceID

type ByteSliceID []byte

ByteSliceID is a helper type for consumers of StatelessHandleAllocator and ResolvableHandleAllocator. It uses the contents of a byte slice as an object ID. The byte slice will be prefixed with its own length, so that no ambiguity exists if allocators are nested.

func (ByteSliceID) WriteTo

func (data ByteSliceID) WriteTo(w io.Writer) (nTotal int64, err error)

WriteTo writes the length of a byte slice and its contents to the Writer.

type CASFileFactory

type CASFileFactory interface {
	LookupFile(digest digest.Digest, isExecutable bool, readMonitor FileReadMonitor) NativeLeaf
}

CASFileFactory is a factory type for files whose contents correspond with an object stored in the Content Addressable Storage (CAS).

func NewBlobAccessCASFileFactory

func NewBlobAccessCASFileFactory(ctx context.Context, contentAddressableStorage blobstore.BlobAccess, errorLogger util.ErrorLogger) CASFileFactory

NewBlobAccessCASFileFactory creates a CASFileFactory that can be used to create FUSE files that are directly backed by BlobAccess. Files created by this factory are entirely immutable; it is only possible to read their contents.

func NewResolvableHandleAllocatingCASFileFactory

func NewResolvableHandleAllocatingCASFileFactory(base CASFileFactory, allocation StatelessHandleAllocation) CASFileFactory

NewResolvableHandleAllocatingCASFileFactory creates a decorator for CASFileFactory that creates read-only files for files stored in the Content Addressable Storage that have a stateless handle associated with them.

This decorator is intended to be used in places where CASFileFactory is used to hand out files with an indefinite lifetime, such as bb_clientd's "cas" directory. File handles will be larger, as the hash, size and executable bit of of the file will be stored in the file handle.

func NewStatelessHandleAllocatingCASFileFactory

func NewStatelessHandleAllocatingCASFileFactory(base CASFileFactory, allocation StatelessHandleAllocation) CASFileFactory

NewStatelessHandleAllocatingCASFileFactory creates a decorator for CASFileFactory that creates read-only files for files stored in the Content Addressable Storage that have a stateless handle associated with them.

This decorator is intended to be used in places where CASFileFactory is used to place files in mutable directories that properly track lifetimes of files. By making these files stateless, as opposed to resolvable, implementations of HandleAllocator may deduplicate multiple instances of the same file in the file system.

type ChangeInfo

type ChangeInfo struct {
	Before uint64
	After  uint64
}

ChangeInfo contains a pair of change IDs of a directory, before and after performing a directory mutating operation. This information needs to be returned by various NFSv4 operations.

type CharacterDeviceFactory

type CharacterDeviceFactory interface {
	LookupCharacterDevice(deviceNumber filesystem.DeviceNumber) NativeLeaf
}

CharacterDeviceFactory is a factory type for character devices. Character devices are immutable files; it is not possible to change the device after it has been created.

var BaseCharacterDeviceFactory CharacterDeviceFactory = baseCharacterDeviceFactory{}

BaseCharacterDeviceFactory can be used to create simple immutable character device nodes.

func NewHandleAllocatingCharacterDeviceFactory

func NewHandleAllocatingCharacterDeviceFactory(base CharacterDeviceFactory, allocation ResolvableHandleAllocation) CharacterDeviceFactory

NewHandleAllocatingCharacterDeviceFactory creates a decorator for CharacterDeviceFactory that creates character devices that have a handle associated with them.

Because device numbers are small, this implementation uses a resolvable handle allocator, meaning that the major and minor number of the device are stored in the file handle.

type Child

type Child[TDirectory any, TLeaf any, TNode any] struct {
	// contains filtered or unexported fields
}

Child is a variant type that either contains a directory or leaf object.

TODO: In principle it should be possible to eliminate the 'kind' field, if it weren't for the fact that we can't compare TDirectory and TLeaf against nil. There is no nullable constraint. https://github.com/golang/go/issues/53656

func (Child[TDirectory, TLeaf, TNode]) FromDirectory

func (Child[TDirectory, TLeaf, TNode]) FromDirectory(directory TDirectory) Child[TDirectory, TLeaf, TNode]

FromDirectory creates a Child that contains a directory.

func (Child[TDirectory, TLeaf, TNode]) FromLeaf

func (Child[TDirectory, TLeaf, TNode]) FromLeaf(leaf TLeaf) Child[TDirectory, TLeaf, TNode]

FromLeaf creates a Child that contains a leaf.

func (Child[TDirectory, TLeaf, TNode]) GetNode

func (c Child[TDirectory, TLeaf, TNode]) GetNode() TNode

GetNode returns the value of the child as a single object, making it possible to call into methods that are both provided by the directory and leaf types.

func (Child[TDirectory, TLeaf, TNode]) GetPair

func (c Child[TDirectory, TLeaf, TNode]) GetPair() (TDirectory, TLeaf)

GetPair returns the value of the child as a directory or leaf object, making it possible to call into directory/leaf specific methods.

func (Child[TDirectory, TLeaf, TNode]) IsSet

func (c Child[TDirectory, TLeaf, TNode]) IsSet() bool

IsSet returns true if the Child contains either a directory or leaf.

type ChildFilter

type ChildFilter func(node InitialNode, remove ChildRemover) bool

ChildFilter is a callback that is invoked by PrepopulatedDirectory.FilterChildren() for each of the children underneath the current directory hierarchy.

For each of the children, an InitialNode object is provided that describes the contents of that file or directory. In addition to that, a callback is provided that can remove the file or the contents of the directory. This callback may be invoked synchronously or asynchronously, potentially after FilterChildren() has completed.

The boolean return value of this function signals whether traversal should continue. When false, traversal will stop immediately.

type ChildRemover

type ChildRemover func() error

ChildRemover is a callback that is provided to ChildFilter to remove the provided file or contents of the provided directory.

type DigestHandleResolver

type DigestHandleResolver func(blobDigest digest.Digest, remainder io.ByteReader) (DirectoryChild, Status)

DigestHandleResolver is a handle resolver that needs to be implemented by users of ResolvableDigestHandleAllocator. This callback is responsible for looking up a file or directory that corresponds to a given REv2 digest that was reobtained from a file handle.

type Directory

type Directory interface {
	Node

	// VirtualOpenChild opens a regular file within the directory.
	//
	// When createAttributes is nil, this method will fail with
	// StatusErrNoEnt if the file does not exist. When not nil, a
	// file will be created.
	//
	// When existingOptions is nil, this method will fail with
	// StatusErrExist if the file already exists. When not nil, an
	// existing file will be opened.
	//
	// Either one or both of createAttributes and existingOptions
	// need to be provided.
	VirtualOpenChild(ctx context.Context, name path.Component, shareAccess ShareMask, createAttributes *Attributes, existingOptions *OpenExistingOptions, requested AttributesMask, openedFileAttributes *Attributes) (Leaf, AttributesMask, ChangeInfo, Status)
	// VirtualLink links an existing file into the directory.
	VirtualLink(ctx context.Context, name path.Component, leaf Leaf, requested AttributesMask, attributes *Attributes) (ChangeInfo, Status)
	// VirtualLookup obtains the inode corresponding with a child
	// stored within the directory.
	//
	// TODO: Can't use DirectoryChild in the return type here, due to
	// https://github.com/golang/go/issues/50259.
	VirtualLookup(ctx context.Context, name path.Component, requested AttributesMask, out *Attributes) (Child[Directory, Leaf, Node], Status)
	// VirtualMkdir creates an empty directory within the current
	// directory.
	VirtualMkdir(name path.Component, requested AttributesMask, attributes *Attributes) (Directory, ChangeInfo, Status)
	// VirtualMknod creates a character FIFO or UNIX domain socket
	// within the current directory.
	VirtualMknod(ctx context.Context, name path.Component, fileType filesystem.FileType, requested AttributesMask, attributes *Attributes) (Leaf, ChangeInfo, Status)
	// VirtualReadDir reports files and directories stored within
	// the directory.
	VirtualReadDir(ctx context.Context, firstCookie uint64, requested AttributesMask, reporter DirectoryEntryReporter) Status
	// VirtualRename renames a file stored in the current directory,
	// potentially moving it to another directory.
	VirtualRename(oldName path.Component, newDirectory Directory, newName path.Component) (ChangeInfo, ChangeInfo, Status)
	// VirtualRemove removes an empty directory or leaf node stored
	// within the current directory. Depending on the parameters,
	// this method behaves like rmdir(), unlink() or a mixture of
	// the two. The latter is needed by NFSv4.
	VirtualRemove(name path.Component, removeDirectory, removeLeaf bool) (ChangeInfo, Status)
	// VirtualSymlink creates a symbolic link within the current
	// directory.
	VirtualSymlink(ctx context.Context, pointedTo []byte, linkName path.Component, requested AttributesMask, attributes *Attributes) (Leaf, ChangeInfo, Status)
}

Directory node that is exposed through FUSE using SimpleRawFileSystem, or through NFSv4. The names of all of these operations are prefixed with 'Virtual' to ensure they don't collide with filesystem.Directory.

func NewStaticDirectory

func NewStaticDirectory(directories map[path.Component]DirectoryChild) Directory

NewStaticDirectory creates a Directory that contains a hardcoded list of child files or directories. The contents of this directory are immutable.

type DirectoryChild

type DirectoryChild = Child[Directory, Leaf, Node]

DirectoryChild is either a Directory or a Leaf, as returned by Directory.VirtualLookup().

type DirectoryEntryReporter

type DirectoryEntryReporter interface {
	// TODO: Can't use DirectoryChild in the arguments here, due to
	// https://github.com/golang/go/issues/50259.
	ReportEntry(nextCookie uint64, name path.Component, child Child[Directory, Leaf, Node], attributes *Attributes) bool
}

DirectoryEntryReporter is used by VirtualReadDir() to report individual directory entries. These methods may be called while locks on the underlying directory are held. This means that it's not safe to call methods of the child directory, as that could cause deadlocks.

type DirectoryPrepopulatedDirEntry

type DirectoryPrepopulatedDirEntry struct {
	Child PrepopulatedDirectory
	Name  path.Component
}

DirectoryPrepopulatedDirEntry contains information about a directory node that is stored in a PrepopulatedDirectory.

type FUSERemovalNotifier

type FUSERemovalNotifier func(parent uint64, name path.Component)

FUSERemovalNotifier is a callback method that can be registered to report the removal of files from stateful directories.

type FUSERemovalNotifierRegistrar

type FUSERemovalNotifierRegistrar func(removalNotifier FUSERemovalNotifier)

FUSERemovalNotifierRegistrar has the same signature as FUSEStatefulHandleAllocator.RegisterRemovalNotifier(). It has been added to aid testing.

type FUSEStatefulHandleAllocator

type FUSEStatefulHandleAllocator struct {
	// contains filtered or unexported fields
}

FUSEStatefulHandleAllocator creates a handle allocator for the purpose of exposing the virtual file system through FUSE. It is responsible for decorating all files in the file system, so that they have inode numbers and link counts. Inode numbers are unique for stateful (mutable) files, while they are identical for stateless files that share the same identifiers, meaning they can be deduplicated by the kernel.

The FUSE protocol is stateful, in the sense that the kernel and the userspace service share state on which nodes in the file system have been resolved. The kernel will never issue requests against objects that have not been resolved yet, or for which the kernel has issued a FORGET operation. This means that this handle allocator does not need to provide any mechanism for resolving arbitrary files present in the file system, making its implementation simple. There is thus no distinction between stateless and resolvable files.

func NewFUSEHandleAllocator

func NewFUSEHandleAllocator(randomNumberGenerator random.ThreadSafeGenerator) *FUSEStatefulHandleAllocator

NewFUSEHandleAllocator creates a new FUSEStatefulHandleAllocator.

func (*FUSEStatefulHandleAllocator) New

New creates a new stateful handle allocation.

func (*FUSEStatefulHandleAllocator) RegisterRemovalNotifier

func (hr *FUSEStatefulHandleAllocator) RegisterRemovalNotifier(removalNotifier FUSERemovalNotifier)

RegisterRemovalNotifier adds a new file removal notifier to the handle allocator. Any future calls to Release() against DirectoryHandles returned by this handle allocator will call into the FUSERemovalNotifier, providing it the inode number of the parent directory.

This method is used by the FUSE server to register a callback that sends "entry notify" events to the kernel, causing the directory entry to be removed from the kernel's cache.

type FileAllocator

type FileAllocator interface {
	NewFile(isExecutable bool, size uint64, shareAccess ShareMask) (NativeLeaf, Status)
}

FileAllocator is called into by InMemoryPrepopulatedDirectory to create new files within the file system. Such files could either be stored in memory, on disk, remotely, etc.

Files returned by this interface should have a link count of 1, and are opened using the provided share access mask.

func NewHandleAllocatingFileAllocator

func NewHandleAllocatingFileAllocator(base FileAllocator, allocator StatefulHandleAllocator) FileAllocator

NewHandleAllocatingFileAllocator creates a decorator for FileAllocator that creates mutable files that have a stateful handle associated with them. This gives ever mutable file its own inode number and link count.

func NewPoolBackedFileAllocator

func NewPoolBackedFileAllocator(pool re_filesystem.FilePool, errorLogger util.ErrorLogger) FileAllocator

NewPoolBackedFileAllocator creates an allocator for a leaf node that may be stored in an PrepopulatedDirectory, representing a mutable regular file. All operations to mutate file contents (reads, writes and truncations) are forwarded to a file obtained from a FilePool.

When the file becomes unreachable (i.e., both its link count and open file descriptor count reach zero), Close() is called on the underlying backing file descriptor. This may be used to request deletion from underlying storage.

type FileReadMonitor

type FileReadMonitor func()

FileReadMonitor is used by the regular files created through the InitialContentsFetcher to indicate that one or more calls against VirtualRead() have occurred. This is used by AccessMonitoringInitialContentsFetcher to monitor file access.

type FileReadMonitorFactory

type FileReadMonitorFactory func(name path.Component) FileReadMonitor

FileReadMonitorFactory is a factory type for FileReadMonitor that is provided to the InitialContentsFetcher, so that the InitialContentsFetcher can attach the resulting monitors to any files that are returned.

If this function returns nil, no monitor is attached to the file.

type HandleResolver

type HandleResolver func(r io.ByteReader) (DirectoryChild, Status)

HandleResolver is a method that is used by ResolvableHandleAllocator to reconstruct files based on the identifiers provided to New().

TODO: Implementations of this method must currently make sure that directories and leaves that are returned are decorated with a handle allocation. Can't we let implementations of ResolvableHandleAllocator do this? That way resolvers may remain simple.

type InitialContentsFetcher

type InitialContentsFetcher interface {
	FetchContents(fileReadMonitorFactory FileReadMonitorFactory) (map[path.Component]InitialNode, error)

	// GetContainingDigests() returns a set of digests of objects in
	// the Content Addressable Storage that back the directories and
	// leaf nodes yielded by this InitialContentsFetcher.
	//
	// The set returned by this function may be passed to
	// ContentAddressableStorage.FindMissingBlobs() to check whether
	// the all files underneath this directory still exist, and to
	// prevent them from being removed in the nearby future.
	//
	// This API assumes that the resulting set is small enough to
	// fit in memory. For hierarchies backed by Tree objects, this
	// will generally hold. It may not be safe to call this method
	// on InitialContentsFetchers that expand to infinitely big
	// hierarchies.
	GetContainingDigests(ctx context.Context) (digest.Set, error)
}

InitialContentsFetcher is called into by PrepopulatedDirectory when a directory whose contents need to be instantiated lazily is accessed. The results returned by FetchContents() are used to populate the directory.

FetchContents() should be called until it succeeds at most once. It may be possible FetchContents() is never called. This may happen if the directory in question is never accessed.

var EmptyInitialContentsFetcher InitialContentsFetcher = emptyInitialContentsFetcher{}

EmptyInitialContentsFetcher is an instance of InitialContentsFetcher that yields no children. It can be used in case an empty directory needs to be created.

func NewAccessMonitoringInitialContentsFetcher

func NewAccessMonitoringInitialContentsFetcher(base InitialContentsFetcher, rootDirectoryMonitor access.UnreadDirectoryMonitor) InitialContentsFetcher

NewAccessMonitoringInitialContentsFetcher decorates an InitialContentsFetcher, so that any read access to files and directories is reported to an UnreadDirectoryMonitor. This can be used to create file system access profiles of build actions.

func NewCASInitialContentsFetcher

func NewCASInitialContentsFetcher(ctx context.Context, directoryWalker cas.DirectoryWalker, casFileFactory CASFileFactory, symlinkFactory SymlinkFactory, digestFunction digest.Function) InitialContentsFetcher

NewCASInitialContentsFetcher creates an InitialContentsFetcher that lazily instantiates a full directory hierarchy based on directory objects stored in the Content Addressable Storage (CAS).

Upon request, it loads the root directory of the tree and converts all of the children to either additional InitialContentFetchers (directories), FileBackedFiles (regular files) or Symlinks (symbolic links).

type InitialNode

type InitialNode = Child[InitialContentsFetcher, NativeLeaf, any]

InitialNode is the value type of the map of directory entries returned by InitialContentsFetcher.FetchContents(). Either Directory or Leaf is set, but not both.

type Leaf

type Leaf interface {
	Node

	VirtualAllocate(off, size uint64) Status
	VirtualSeek(offset uint64, regionType filesystem.RegionType) (*uint64, Status)
	VirtualOpenSelf(ctx context.Context, shareAccess ShareMask, options *OpenExistingOptions, requested AttributesMask, attributes *Attributes) Status
	VirtualRead(buf []byte, offset uint64) (n int, eof bool, s Status)
	VirtualReadlink(ctx context.Context) ([]byte, Status)
	VirtualClose(shareAccess ShareMask)
	VirtualWrite(buf []byte, offset uint64) (int, Status)
}

Leaf node that is exposed through FUSE using SimpleRawFileSystem, or through NFSv4. Examples of leaf nodes are regular files, sockets, FIFOs, symbolic links and devices.

TODO: Should all methods take an instance of Context?

type LeafPrepopulatedDirEntry

type LeafPrepopulatedDirEntry struct {
	Child NativeLeaf
	Name  path.Component
}

LeafPrepopulatedDirEntry contains information about a leaf node that is stored in a PrepopulatedDirectory.

type NFSStatefulHandleAllocator

type NFSStatefulHandleAllocator struct {
	// contains filtered or unexported fields
}

NFSStatefulHandleAllocator creates a handle allocator for the purpose of exposing the virtual file system through NFS. It is responsible for decorating all files in the file system, so that they have file handles, inode numbers and link counts. File handles and inode numbers are unique for stateful (mutable) files, while they are identical for stateless files that share the same identifiers, meaning they can be deduplicated by the kernel.

The NFS protocol is stateless, in the sense that the client and server share no state on which nodes in the file system have been resolved. The client does not inform the server that it has released files from its cache. This means that the server needs to be able to resolve all file handles that are either still present in the file system or are still opened by the client. This handle allocator is capable of only doing the former. The latter can be supported at a higher level.

To work well with infinitely big directory structures (e.g., bb_clientd's "cas" directory), this implementation makes use of the handle resolver function provided to AsResolvableAllocator(). Instead of tracking these nodes explicitly, it generates longer file handles that have the value provided to ResolvableHandleAllocator.New() as a suffix, making it possible to regenerate these nodes on the fly.

func NewNFSHandleAllocator

func NewNFSHandleAllocator(randomNumberGenerator random.SingleThreadedGenerator) *NFSStatefulHandleAllocator

NewNFSHandleAllocator creates a new NFSStatefulHandleAllocator that does not have any resolvable objects.

func (*NFSStatefulHandleAllocator) New

New creates a new stateful handle allocation.

func (*NFSStatefulHandleAllocator) ResolveHandle

ResolveHandle resolves a directory or leaf object that corresponds with a file handle previously returned by Attributes.GetFileHandle().

Only files that are linked into the file system are guaranteed to be resolvable. Files that have been unlinked, but are still opened have to be tracked at a higher level.

type NativeLeaf

type NativeLeaf interface {
	Leaf

	// Operations called into by implementations of
	// PrepopulatedDirectory. The Link() operation may fail, for the
	// reason that Directory.VirtualLink() may be called on leaf
	// nodes that have been removed concurrently.
	Link() Status
	Unlink()

	// Additional operations that are used by consumers of
	// PrepopulatedDirectory.
	//
	// TODO: Remove these once Go supports generics. We could turn
	// PrepopulatedDirectory and InitialContentsFetcher into
	// parameterized types, where the leaves could be any type
	// that's based on NativeLeaf.
	Readlink() (path.Parser, error)
	UploadFile(ctx context.Context, contentAddressableStorage blobstore.BlobAccess, digestFunction digest.Function, writableFileUploadDelay <-chan struct{}) (digest.Digest, error)
	// GetContainingDigests() returns a set of digests of objects in
	// the Content Addressable Storage that back the contents of
	// this file.
	//
	// The set returned by this function may be passed to
	// ContentAddressableStorage.FindMissingBlobs() to check whether
	// the file still exists in its entirety, and to prevent that
	// the file is removed in the nearby future.
	GetContainingDigests() digest.Set
	// GetBazelOutputServiceStat() returns the status of the leaf
	// node in the form of a Status message that is used by the
	// Bazel Output Service protocol.
	GetBazelOutputServiceStat(digestFunction *digest.Function) (*bazeloutputservice.BatchStatResponse_Stat, error)
	// AppendOutputPathPersistencyDirectoryNode() appends a FileNode
	// or SymlinkNode entry to a Directory message that is used to
	// persist the state of a Bazel Output Service output path to
	// disk.
	AppendOutputPathPersistencyDirectoryNode(directory *outputpathpersistency.Directory, name path.Component)
}

NativeLeaf objects are non-directory nodes that can be placed in a PrepopulatedDirectory.

func NewSpecialFile

func NewSpecialFile(fileType filesystem.FileType, deviceNumber *filesystem.DeviceNumber) NativeLeaf

NewSpecialFile creates a node that may be used as a character device, block device, FIFO or UNIX domain socket. Nodes of these types are mere placeholders. The kernel is responsible for capturing calls to open() and connect().

type Node

type Node interface {
	VirtualGetAttributes(ctx context.Context, requested AttributesMask, attributes *Attributes)
	VirtualSetAttributes(ctx context.Context, in *Attributes, requested AttributesMask, attributes *Attributes) Status
}

Node is the intersection between Directory and Leaf. These are the operations that can be applied to both kinds of objects.

type OpenExistingOptions

type OpenExistingOptions struct {
	Truncate bool
}

OpenExistingOptions contains options that describe what should happen with a file when opened. The Truncate option corresponds to open()'s O_TRUNC option. This option has no effect on freshly created files, as those are always empty.

func (*OpenExistingOptions) ToAttributesMask

func (o *OpenExistingOptions) ToAttributesMask() (m AttributesMask)

ToAttributesMask converts open options to an AttributeMask, indicating which file attributes were affected by the operation.

type Permissions

type Permissions uint8

Permissions of a file. Unlike regular UNIX file system, no distinction is made between owner, group and all permissions. This is because the virtual file system is effectively single user.

const (
	// PermissionsRead indicates that file contents may be read, or
	// that files in a directory may be listed.
	PermissionsRead Permissions = 1 << iota
	// PermissionsWrite indicates that file contents may be written
	// to, or that files in a directory may be added, removed or
	// renamed.
	PermissionsWrite
	// PermissionsExecute indicates that a file is executable, or
	// that files in a directory may be looked up.
	PermissionsExecute
)

func NewPermissionsFromMode

func NewPermissionsFromMode(m uint32) (p Permissions)

NewPermissionsFromMode creates a set of permissions from a traditional UNIX style mode.

func (Permissions) ToMode

func (p Permissions) ToMode() (m uint32)

ToMode converts a set of permissions to a traditional UNIX style mode. The permissions for the owner, group and all will be identical.

type PrepopulatedDirectory

type PrepopulatedDirectory interface {
	Directory

	// LookupChild() looks up a file or directory contained in a
	// PrepopulatedDirectory. This method is similar to
	// VirtualLookup(), except that it returns the native types
	// managed by PrepopulatedDirectory.
	//
	// TODO: Can't use PrepopulatedDirectoryChild in the return type
	// here, due to https://github.com/golang/go/issues/50259.
	LookupChild(name path.Component) (Child[PrepopulatedDirectory, NativeLeaf, Node], error)
	// LookupAllChildren() looks up all files and directories
	// contained in a PrepopulatedDirectory. This method is similar
	// to VirtualReadDir(), except that it returns the native types
	// managed by PrepopulatedDirectory. Entries are returned in
	// alphabetical order.
	LookupAllChildren() ([]DirectoryPrepopulatedDirEntry, []LeafPrepopulatedDirEntry, error)
	// CreateChildren() creates one or more files or directories in
	// the current directory.
	//
	// If the overwrite flag is set, existing files and directories
	// will be replaced. If the overwrite flag is not set, the call
	// will fail if one or more entries already exist. No changes
	// will be made to the directory in that case.
	CreateChildren(children map[path.Component]InitialNode, overwrite bool) error
	// CreateAndEnterPrepopulatedDirectory() is similar to
	// LookupChild(), except that it creates the specified directory
	// if it does not yet exist. If a file already exists, it will
	// be removed.
	CreateAndEnterPrepopulatedDirectory(name path.Component) (PrepopulatedDirectory, error)
	// RemoveAllChildren() removes all files and directories
	// contained in the current directory.
	//
	// This method is identical to the one filesystem.Directory,
	// except that the forbidNewChildren flag may be set to
	// permanently mark the directory in such a way that no further
	// files may be added. When called on the root directory, all
	// resources associated with the directory hierarchy will be
	// released.
	RemoveAllChildren(forbidNewChildren bool) error
	// InstallHooks sets up hooks for creating files and logging
	// errors that occur under the directory subtree.
	//
	// This function is identical to BuildDirectory.InstallHooks(),
	// except that it uses the FUSE specific FileAllocator instead
	// of FilePool.
	InstallHooks(fileAllocator FileAllocator, errorLogger util.ErrorLogger)
	// FilterChildren() can be used to traverse over all of the
	// InitialContentsFetcher and NativeLeaf objects stored in this
	// directory hierarchy. For each of the objects, a callback is
	// provided that can be used to remove the file or the contents
	// of the directory associated with this object.
	//
	// This function can be used by bb_clientd to purge files or
	// directories that are no longer present in the Content
	// Addressable Storage at the start of the build.
	FilterChildren(childFilter ChildFilter) error

	// Functions inherited from filesystem.Directory.
	ReadDir() ([]filesystem.FileInfo, error)
	RemoveAll(name path.Component) error
	Remove(name path.Component) error
}

PrepopulatedDirectory is a Directory that is writable and can contain files of type NativeLeaf.

By making use of InitialContentsFetcher, it is possible to create subdirectories that are prepopulated with files and directories. These will be instantiated only when accessed. This feature is used by bb_worker to lazily load the input root while a build action is being executed. Similarly, it is used by bb_clientd to lazily instantiate the contents of a Tree object.

func NewInMemoryPrepopulatedDirectory

func NewInMemoryPrepopulatedDirectory(fileAllocator FileAllocator, symlinkFactory SymlinkFactory, errorLogger util.ErrorLogger, handleAllocator StatefulHandleAllocator, initialContentsSorter Sorter, hiddenFilesMatcher StringMatcher, clock clock.Clock) PrepopulatedDirectory

NewInMemoryPrepopulatedDirectory creates a new PrepopulatedDirectory that keeps all directory metadata stored in memory. As the filesystem API does not allow traversing the hierarchy upwards, this directory can be considered the root directory of the hierarchy.

type PrepopulatedDirectoryChild

type PrepopulatedDirectoryChild = Child[PrepopulatedDirectory, NativeLeaf, Node]

PrepopulatedDirectoryChild is either a PrepopulatedDirectory or a NativeLeaf, as returned by PrepopulatedDirectory.LookupChild().

type ReadOnlyDirectory

type ReadOnlyDirectory struct{}

ReadOnlyDirectory can be embedded into a Directory to disable all operations that mutate the directory contents.

func (ReadOnlyDirectory) VirtualLink(ctx context.Context, name path.Component, leaf Leaf, requested AttributesMask, out *Attributes) (ChangeInfo, Status)

VirtualLink is an implementation of the link() system call that treats the target directory as being read-only.

func (ReadOnlyDirectory) VirtualMkdir

func (ReadOnlyDirectory) VirtualMkdir(name path.Component, requested AttributesMask, out *Attributes) (Directory, ChangeInfo, Status)

VirtualMkdir is an implementation of the mkdir() system call that treats the target directory as being read-only.

func (ReadOnlyDirectory) VirtualMknod

func (ReadOnlyDirectory) VirtualMknod(ctx context.Context, name path.Component, fileType filesystem.FileType, requested AttributesMask, out *Attributes) (Leaf, ChangeInfo, Status)

VirtualMknod is an implementation of the mknod() system call that treats the target directory as being read-only.

func (ReadOnlyDirectory) VirtualRemove

func (ReadOnlyDirectory) VirtualRemove(name path.Component, removeDirectory, removeLeaf bool) (ChangeInfo, Status)

VirtualRemove is an implementation of the unlink() and rmdir() system calls that treats the target directory as being read-only.

func (ReadOnlyDirectory) VirtualRename

func (ReadOnlyDirectory) VirtualRename(oldName path.Component, newDirectory Directory, newName path.Component) (ChangeInfo, ChangeInfo, Status)

VirtualRename is an implementation of the rename() system call that treats the target directory as being read-only.

func (ReadOnlyDirectory) VirtualSetAttributes

func (ReadOnlyDirectory) VirtualSetAttributes(ctx context.Context, in *Attributes, requested AttributesMask, out *Attributes) Status

VirtualSetAttributes is an implementation of the chmod(), utimensat(), etc. system calls that treats the target directory as being read-only.

func (ReadOnlyDirectory) VirtualSymlink(ctx context.Context, pointedTo []byte, linkName path.Component, requested AttributesMask, out *Attributes) (Leaf, ChangeInfo, Status)

VirtualSymlink is an implementation of the symlink() system call that treats the target directory as being read-only.

type ResolvableDigestHandleAllocator

type ResolvableDigestHandleAllocator struct {
	// contains filtered or unexported fields
}

ResolvableDigestHandleAllocator is a convenience type for the handle allocator API, used for identifying objects by REv2 digest. It is used by bb_clientd's "cas" directory to give unique file handles to objects stored in the Content Addressable Storage.

Because REv2 objects that include their instance name are too long to fit in NFS file handles, this type uses a stateless allocator for the instance name part. It uses a resolvable allocator only for the object hash and size, as those are generally small enough to fit in the file handle.

This means that every time a new instance name is used, a resolver gets leaked. This is acceptable for most use cases, as the instance names in use tend to be limited.

func NewResolvableDigestHandleAllocator

func NewResolvableDigestHandleAllocator(allocation StatelessHandleAllocation, resolver DigestHandleResolver) *ResolvableDigestHandleAllocator

NewResolvableDigestHandleAllocator creates a new NewResolvableDigestHandleAllocator.

func (*ResolvableDigestHandleAllocator) New

New creates a new handle allocation for an object with a given digest.

type ResolvableHandleAllocation

type ResolvableHandleAllocation interface {
	AsResolvableAllocator(resolver HandleResolver) ResolvableHandleAllocator
	AsStatelessDirectory(directory Directory) Directory
	AsNativeLeaf(leaf NativeLeaf) NativeLeaf
	AsLeaf(leaf Leaf) Leaf
}

ResolvableHandleAllocation corresponds to an allocation of a file handle that is not only stateless, but can also be trivially reconstructed based on a small, bounded of information.

TODO: ResolvableHandleAllocators can be nested. The resolver provided to AsResolvableAllocator() is only used for the first level. We could eliminate the argument, but that makes composition harder.

type ResolvableHandleAllocator

type ResolvableHandleAllocator interface {
	New(id io.WriterTo) ResolvableHandleAllocation
}

ResolvableHandleAllocator is responsible for allocating file handles that are not only stateless, but can also be trivially reconstructed based on a small, bounded amount of information.

This kind of allocator is generally used by bb_clientd's cas/ subdirectory. This directory allows for the exploration of arbitrary objects stored in the Content Addressable Storage (CAS). This allocator can be used to store the digest of such objects in the file handle, meaning bb_clientd doesn't need to track state for each of the files individually.

The exact amount of space that can be stored in a file handle is protocol specific. NFSv3 and NFSv4 use file handles that are 64 and 128 bytes in size, respectively.

type ShareMask

type ShareMask uint32

ShareMask is a bitmask of operations that are permitted against a Leaf that has been opened.

const (
	// ShareMaskRead permits calls to VirtualRead().
	ShareMaskRead ShareMask = 1 << iota
	// ShareMaskWrite permits calls to VirtualWrite().
	ShareMaskWrite
)

func (ShareMask) Count

func (sm ShareMask) Count() uint

Count the number of permitted operations.

type Sorter

type Sorter func(data sort.Interface)

Sorter is a function type for a sorting algorithm. Its signature is identical to the sort.Sort() function.

This type is used by InMemoryPrepopulatedDirectory to make the policy for sorting the results of VirtualReadDir() configurable. Depending on the use case, it is desirable to use a deterministic algorithm (e.g., alphabetic sorting) or an undeterministic one (e.g., random shuffling).

type StatefulDirectoryHandle

type StatefulDirectoryHandle interface {
	GetAttributes(requested AttributesMask, attributes *Attributes)
	NotifyRemoval(name path.Component)
	Release()
}

StatefulDirectoryHandle is a handle that needs to be embedded into stateful directories. It can be used to report mutations to the directory through NotifyRemoval(), or report deletion through Release().

The directory type that embeds the handle must call GetAttributes() as part of Directory.VirtualGetAttributes() to augment the attributes with an inode number and/or file handle.

type StatefulHandleAllocation

type StatefulHandleAllocation interface {
	StatelessHandleAllocation

	AsStatefulDirectory(directory Directory) StatefulDirectoryHandle
}

StatefulHandleAllocation corresponds to an allocation of a file handle that is unique, meaning it can be used to identify stateful, mutable files or directories.

Exactly one call to one of the methods on this interface needs to be performed to convert the allocation to an actual use of the file handle.

type StatefulHandleAllocator

type StatefulHandleAllocator interface {
	New() StatefulHandleAllocation
}

StatefulHandleAllocator is responsible for allocating new file handles, giving files and directories stored in the file system their own identity and lifetime. The exact meaning of identity is implementation specific. In the case of FUSE it can be an inode number/node ID, while in the case of NFSv4 it corresponds to the value of a 128-byte nfs_fh4.

type StatelessHandleAllocation

type StatelessHandleAllocation interface {
	ResolvableHandleAllocation

	AsStatelessAllocator() StatelessHandleAllocator
}

StatelessHandleAllocation corresponds to an allocation of a file handle that is stateless, meaning it can be used to identify stateless files or directories.

type StatelessHandleAllocator

type StatelessHandleAllocator interface {
	New(id io.WriterTo) StatelessHandleAllocation
}

StatelessHandleAllocator is responsible for allocating file handles of files that are stateless, immutable files.

For every handle that is allocated, an identifier needs to be provided in the form of an io.WriterTo. This may be used to give files with the same identifier the same underlying file handle or inode number.

NOTE: Care must be taken that the provided identifier is properly terminated or is prefixed with its own length. Stateless handle allocators may be nested, causing their identifiers to be concatenated. This could cause ambiguity if this rule is not followed.

type Status

type Status int

Status response of operations applied against Node objects.

const (
	// StatusOK indicates that the operation succeeded.
	StatusOK Status = iota
	// StatusErrAccess indicates that the operation failed due to
	// permission being denied.
	StatusErrAccess
	// StatusErrBadHandle indicates that the provided file handle
	// failed internal consistency checks.
	StatusErrBadHandle
	// StatusErrExist indicates that a file system object of the
	// specified target name (when creating, renaming or linking)
	// already exists.
	StatusErrExist
	// StatusErrInval indicates that the arguments for this
	// operation are not valid.
	StatusErrInval
	// StatusErrIO indicates that the operation failed due to an I/O
	// error.
	StatusErrIO
	// StatusErrIsDir indicates that a request is made against a
	// directory when the current operation does not allow a
	// directory as a target.
	StatusErrIsDir
	// StatusErrNoEnt indicate sthat the operation failed due to a
	// file not existing.
	StatusErrNoEnt
	// StatusErrNotDir indicates that a request is made against a
	// leaf when the current operation does not allow a leaf as a
	// target.
	StatusErrNotDir
	// StatusErrNotEmpty indicates that attempt was made to remove a
	// directory that was not empty.
	StatusErrNotEmpty
	// StatusErrNXIO indicates that a request is made beyond the
	// limits of the file or device.
	StatusErrNXIO
	// StatusErrPerm indicates that the operation was not allowed
	// because the caller is neither a privileged user (root) nor
	// the owner of the target of the operation.
	StatusErrPerm
	// StatusErrROFS indicates that a modifying operation was
	// attempted on a read-only file system.
	StatusErrROFS
	// StatusErrStale indicates that the file system object referred
	// to by the file handle no longer exists, or access to it has
	// been revoked.
	StatusErrStale
	// StatusErrSymlink indicates that a request is made against a
	// symbolic link when the current operation does not allow a
	// symbolic link as a target.
	StatusErrSymlink
	// StatusErrWrongType that a request is made against an object
	// that is of an invalid type for the current operation, and
	// there is no more specific error (such as StatusErrIsDir or
	// StatusErrSymlink) that applies.
	StatusErrWrongType
	// StatusErrXDev indicates an attempt to do an operation, such
	// as linking, that inappropriately crosses a boundary.
	StatusErrXDev
)

type StringMatcher

type StringMatcher func(s string) bool

StringMatcher is a function type that has the same signature as regexp.Regexp's MatchString() method. It is used by InMemoryPrepopulatedDirectory to determine which files should be hidden from directory listings.

type SymlinkFactory

type SymlinkFactory interface {
	LookupSymlink(target []byte) NativeLeaf
}

SymlinkFactory is a factory type for symbolic links. Symbolic links are immutable files; the target to which they point can only be altered by replacing the node entirely (e.g., by first unlinking it from the directory).

var BaseSymlinkFactory SymlinkFactory = symlinkFactory{}

BaseSymlinkFactory can be used to create simple immutable symlink nodes.

func NewHandleAllocatingSymlinkFactory

func NewHandleAllocatingSymlinkFactory(base SymlinkFactory, allocation StatelessHandleAllocation) SymlinkFactory

NewHandleAllocatingSymlinkFactory is a decorator for SymlinkFactory that creates symbolic link nodes that have a stateless handle associated with them.

Because symbolic link contents can be long, it is not possible to use a resolvable allocator here, as that would cause the full contents of the symbolic link to become part of the file handle, which is undesirable. In the case of NFS we want these nodes to be explicitly tracked, using an invisible link count.

type UserSettableSymlink struct {
	// contains filtered or unexported fields
}

UserSettableSymlink is an implementation of a symbolic link, whose target can be modified using the TemporaryDirectoryInstaller gRPC API.

Instead of just pointing to a single target, this type is capable of storing one target per user. Both when reading and adjusting the symbolic link's target, the public authentication metadata is used to identify the user.

func NewUserSettableSymlink(buildDirectory *path.Builder) *UserSettableSymlink

NewUserSettableSymlink creates a UserSettableSymlink that doesn't have any targets configured.

func (*UserSettableSymlink) AppendOutputPathPersistencyDirectoryNode

func (f *UserSettableSymlink) AppendOutputPathPersistencyDirectoryNode(directory *outputpathpersistency.Directory, name path.Component)

AppendOutputPathPersistencyDirectoryNode returns the status of the symbolic link, so that it may be persisted on disk. This method is a no-op, as this type is not used as part of build output paths.

func (*UserSettableSymlink) CheckReadiness

func (f *UserSettableSymlink) CheckReadiness(ctx context.Context, request *emptypb.Empty) (*emptypb.Empty, error)

CheckReadiness returns whether the target of the symbolic link is capable of being mutated.

func (*UserSettableSymlink) GetBazelOutputServiceStat

func (f *UserSettableSymlink) GetBazelOutputServiceStat(digestFunction *digest.Function) (*bazeloutputservice.BatchStatResponse_Stat, error)

GetBazelOutputServiceStat returns the status of the symbolic link, so that it may be reported through the Bazel Output Service. This method is a no-op, as this type is not used in combination with the Bazel Output Service.

func (UserSettableSymlink) GetContainingDigests

func (UserSettableSymlink) GetContainingDigests() digest.Set

func (*UserSettableSymlink) InstallTemporaryDirectory

func (f *UserSettableSymlink) InstallTemporaryDirectory(ctx context.Context, request *tmp_installer.InstallTemporaryDirectoryRequest) (*emptypb.Empty, error)

InstallTemporaryDirectory sets the target of the symbolic link for the user stored in the authentication metadata.

func (UserSettableSymlink) Link() Status
func (f *UserSettableSymlink) Readlink() (path.Parser, error)

Readlink returns the target of the symbolic link. This method always fails, as it's called in places where no Context is available.

func (UserSettableSymlink) Unlink()

func (UserSettableSymlink) UploadFile

func (UserSettableSymlink) UploadFile(ctx context.Context, contentAddressableStorage blobstore.BlobAccess, digestFunction digest.Function, writableFileUploadDelay <-chan struct{}) (digest.Digest, error)

func (UserSettableSymlink) VirtualAllocate

func (UserSettableSymlink) VirtualAllocate(off, size uint64) Status

func (UserSettableSymlink) VirtualClose

func (UserSettableSymlink) VirtualClose(shareAccess ShareMask)

func (*UserSettableSymlink) VirtualGetAttributes

func (f *UserSettableSymlink) VirtualGetAttributes(ctx context.Context, requested AttributesMask, attributes *Attributes)

VirtualGetAttributes returns the file system attributes of the symbolic link.

func (UserSettableSymlink) VirtualOpenSelf

func (UserSettableSymlink) VirtualOpenSelf(ctx context.Context, shareAccess ShareMask, options *OpenExistingOptions, requested AttributesMask, attributes *Attributes) Status

func (UserSettableSymlink) VirtualRead

func (UserSettableSymlink) VirtualRead(buf []byte, offset uint64) (int, bool, Status)
func (f *UserSettableSymlink) VirtualReadlink(ctx context.Context) ([]byte, Status)

VirtualReadlink returns the target of the symbolic link for the calling user.

func (UserSettableSymlink) VirtualSeek

func (UserSettableSymlink) VirtualSeek(offset uint64, regionType filesystem.RegionType) (*uint64, Status)

func (*UserSettableSymlink) VirtualSetAttributes

func (f *UserSettableSymlink) VirtualSetAttributes(ctx context.Context, in *Attributes, requested AttributesMask, out *Attributes) Status

VirtualSetAttributes adjusts the attributes of the symbolic link.

func (UserSettableSymlink) VirtualWrite

func (UserSettableSymlink) VirtualWrite(buf []byte, off uint64) (int, Status)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL