fskitbridge

package
v0.6.18 Latest Latest
Warning

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

Go to latest
Published: Aug 22, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package fskitbridge helps implement FSKit file systems in Go.

An FSKit file system extension exposes three Objective-C classes: a file system that subclasses FSUnaryFileSystem, a volume that subclasses FSVolume, and an item that subclasses FSItem. A Server registers this class set and implements its operation selectors on top of a Go UnaryFileSystem: implementations work with Go values and errors, and the Server handles FSKit object identity, reply blocks, set-attribute requests, directory packing, and errno reporting. A minimal volume implements Volume; optional interfaces such as MutableVolume and XattrVolume add the remaining FSKit operations.

The lower layer remains available for file systems that need direct control of the selector set. RegisterClasses registers a class set with method implementations written in Go. FSKit passes each operation a reply block that the implementation must invoke to deliver its result; ReplyBlocks invokes the common reply block shapes and reports a reply that could not be delivered. When typed C shim functions are linked into the process, NewReplyBlocksWithShims routes invocation through them; otherwise the block's invoke pointer is called directly.

ItemAttributesBuilder assembles the FSItemAttributes values returned by lookup, enumeration, and attribute operations, and POSIXError constructs the POSIX-domain NSError values that reply blocks accept.

An extension built as a c-archive and hosted by ExtensionFoundation wraps its Server in an Extension, which owns the lifecycle the host needs: lazy, retryable initialization, last-error reporting, a reply fallback for calls that arrive before the Server is ready, and panic recovery for the exported entry points.

Index

Constants

View Source
const ENOATTR = syscall.Errno(93)

ENOATTR is Darwin's "attribute not found" errno, which the syscall package does not name. File systems mapping a backend's missing-attribute error report it for extended attribute operations.

Variables

This section is empty.

Functions

func POSIXError

func POSIXError(errno syscall.Errno) objc.ID

POSIXError returns a new NSError in the POSIX error domain for errno, suitable for passing to a reply block.

Types

type AccessCheckVolume

type AccessCheckVolume interface {
	Volume

	// CheckAccess reports whether the requested access to item is allowed.
	CheckAccess(item Item, access fskit.FSAccessMask) (bool, error)
}

An AccessCheckVolume is a Volume that answers access checks itself. Without it the kernel checks access against the item mode bits.

type CapabilitiesVolume

type CapabilitiesVolume interface {
	Volume

	// SupportedCapabilities returns the volume's capabilities.
	SupportedCapabilities() fskit.FSVolumeSupportedCapabilities
}

A CapabilitiesVolume is a Volume that reports its own supported capabilities. Without it the Server reports 64-bit object IDs, hidden files, case sensitivity, and symbolic or hard link support according to the SymlinkVolume and LinkVolume interfaces.

type ClassConfig

type ClassConfig struct {
	FileSystemName      string
	VolumeName          string
	ItemName            string
	ExistingFileSystem  objc.Class
	FileSystemProtocols []string
	VolumeProtocols     []string
	FileSystemMethods   []objc.MethodDef
	VolumeMethods       []objc.MethodDef
	ItemMethods         []objc.MethodDef
}

ClassConfig describes the Objective-C classes and method implementations for an FSKit file system.

If ExistingFileSystem is nonzero it is used as the file system class as is and FileSystemMethods are not attached; this supports extensions whose file system class is provided by a host shim that routes operations to Go itself. If a class named VolumeName or ItemName is already registered, its methods are added or replaced instead of registering a new class, so registration can run again in the same process.

type ClassSet

type ClassSet struct {
	FileSystem objc.Class
	Volume     objc.Class
	Item       objc.Class
}

ClassSet is the set of Objective-C classes that implements an FSKit file system.

func RegisterClasses

func RegisterClasses(cfg ClassConfig) (ClassSet, error)

RegisterClasses registers or extends the Objective-C class set for an FSKit file system.

type DirEntry

type DirEntry struct {
	Name       string
	Type       fskit.FSItemType
	Attributes fskit.FSItemAttributes // must include the entry's file ID
}

A DirEntry is one entry of a directory listing.

type Extension

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

An Extension hosts a Server inside an ExtensionFoundation extension built as a c-archive. It owns the lifecycle a hosted extension needs around the Server: lazy, retryable initialization; last-error reporting; a reply fallback for calls that arrive before the Server is ready; and panic recovery for the exported entry points.

A c-archive cannot re-export Go functions defined in an imported package, so the file system's principal class invokes per-extension //export wrappers. Each wrapper is a one-line call into the matching Extension method, which keeps the lifecycle in one place rather than duplicated across extensions.

The zero Extension is not usable; create one with NewExtension.

func NewExtension

func NewExtension(shims ReplyBlockShims, newServer func() (*Server, error)) *Extension

NewExtension returns an Extension that builds its Server with newServer on first use. shims names the linked reply block shims so the fallback can answer calls that arrive before the Server is ready (see ReplyBlockShims).

func (*Extension) Init

func (e *Extension) Init() error

Init builds the Server if it is not already built and returns any error. A failure is not sticky: the next call retries, so an early call that races extension startup (before the principal class registers) does not poison the process.

func (*Extension) LastError

func (e *Extension) LastError() error

LastError returns the most recent initialization error, or nil.

func (*Extension) LoadResource

func (e *Extension) LoadResource(self, resource, options, reply objc.ID)

LoadResource routes loadResource:options:replyHandler: to the Server, replying with EINVAL through the fallback if the Server is not ready.

func (*Extension) NewFileSystem

func (e *Extension) NewFileSystem() objc.ID

NewFileSystem returns a new instance of the file system class, or 0 if the Server cannot be initialized.

func (*Extension) ProbeResource

func (e *Extension) ProbeResource(self, resource, reply objc.ID)

ProbeResource routes probeResource:replyHandler: to the Server, replying with EINVAL through the fallback if the Server is not ready.

func (*Extension) Server

func (e *Extension) Server() *Server

Server returns the built Server, or nil before Extension.Init succeeds.

func (*Extension) UnloadResource

func (e *Extension) UnloadResource(self, resource, options, reply objc.ID)

UnloadResource routes unloadResource:options:replyHandler: to the Server, replying with EINVAL through the fallback if the Server is not ready.

type Item

type Item any

An Item identifies a file system object. Implementations define their own item values; the Server associates each value with the FSItem object it hands to FSKit and passes the value back to later operations.

type ItemAttributesBuilder

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

ItemAttributesBuilder builds FSItemAttributes with the common fields used by FSKit file systems.

func NewItemAttributes

func NewItemAttributes() ItemAttributesBuilder

NewItemAttributes returns a builder for FSItemAttributes.

func (ItemAttributesBuilder) AccessTime

AccessTime sets the access time.

func (ItemAttributesBuilder) AllocSize

AllocSize sets the allocated size in bytes.

func (ItemAttributesBuilder) BirthTime

BirthTime sets the creation time.

func (ItemAttributesBuilder) Build

Build returns the assembled attributes.

func (ItemAttributesBuilder) ChangeTime

ChangeTime sets the attribute change time.

func (ItemAttributesBuilder) Flags

Flags sets the BSD file flags.

func (ItemAttributesBuilder) GID

GID sets the owning group ID.

func (ItemAttributesBuilder) ID

ID sets the file ID.

func (ItemAttributesBuilder) LinkCount

LinkCount sets the hard link count.

func (ItemAttributesBuilder) Mode

Mode sets the POSIX mode bits.

func (ItemAttributesBuilder) ModifyTime

ModifyTime sets the content modification time.

func (ItemAttributesBuilder) ParentID

ParentID sets the parent directory's file ID.

func (ItemAttributesBuilder) Size

Size sets the file size in bytes.

func (ItemAttributesBuilder) Type

Type sets the item type.

func (ItemAttributesBuilder) UID

UID sets the owning user ID.

type LinkVolume

type LinkVolume interface {
	Volume

	// Link links item under a new name in dir.
	Link(item Item, dir Item, name string) error
}

A LinkVolume is a Volume with hard links.

type MutableVolume

type MutableVolume interface {
	Volume

	// Create creates a file (FSItemTypeFile) or directory
	// (FSItemTypeDirectory) named name in dir.
	Create(dir Item, name string, typ fskit.FSItemType, mode uint32) (Item, error)

	// Remove removes the item named name from dir.
	Remove(dir Item, name string, item Item) error

	// Rename moves item, named srcName in srcDir, to dstName in dstDir.
	// If over is non-nil the destination exists and is replaced; the
	// Server reclaims over after a successful rename.
	Rename(item Item, srcDir Item, srcName string, dstDir Item, dstName string, over Item) error

	// SetAttributes applies the requested attribute changes to item and
	// returns the subset it actually applied, as the fields left non-nil.
	// A Volume that applied everything returns set unchanged.
	//
	// The Server reports the returned subset to FSKit as the consumed
	// attributes, and FSKit takes an unconsumed attribute as one the file
	// system does not support: that is how a caller learns a chown did not
	// happen instead of believing a silent success. Returning the applied
	// set rather than clearing an in-out parameter keeps the mistake of
	// forgetting to report cheap -- the zero value claims nothing, so an
	// implementer who gets it wrong under-claims.
	SetAttributes(item Item, set SetAttributes) (applied SetAttributes, err error)

	// Write writes data to file at offset, returning the number of bytes
	// written.
	Write(file Item, offset int64, data []byte) (int, error)
}

A MutableVolume is a Volume that supports mutation. Without it the Server reports EROFS for all mutating operations.

type OpenCloseVolume

type OpenCloseVolume interface {
	Volume

	// Open notes that item was opened with the given modes.
	Open(item Item, modes fskit.FSVolumeOpenModes) error

	// Close notes that item was closed, keeping the given modes.
	Close(item Item, modes fskit.FSVolumeOpenModes) error
}

An OpenCloseVolume is a Volume that tracks open and close of its items.

type PathConf

type PathConf struct {
	MaximumLinkCount          int
	MaximumNameLength         int
	MaximumFileSize           uint64
	MaximumXattrSize          int
	RestrictsOwnershipChanges bool
	TruncatesLongNames        bool

	// OpenUnlinkEmulation asks FSKit to emulate open-unlink semantics,
	// for volumes that cannot keep unlinked-but-open files alive.
	OpenUnlinkEmulation bool
}

PathConf holds the path configuration limits and behavior the Server reports to FSKit. The Server reports the values as given; most implementations start from DefaultPathConf.

func DefaultPathConf

func DefaultPathConf() PathConf

DefaultPathConf returns the path configuration the Server reports for volumes that do not implement PathConfVolume: no hard links, 255-byte names, 63-bit file sizes, 64 KiB extended attributes, and open-unlink emulation.

type PathConfVolume

type PathConfVolume interface {
	Volume

	// PathConf returns the volume's path configuration limits.
	PathConf() PathConf
}

A PathConfVolume is a Volume that reports its own path configuration limits. Without it the Server reports DefaultPathConf.

type PreallocateVolume

type PreallocateVolume interface {
	Volume

	// Preallocate reserves length bytes at offset in file, returning the
	// number of bytes reserved.
	Preallocate(file Item, offset int64, length uint64) (uint64, error)
}

A PreallocateVolume is a Volume that supports preallocating space.

type ProbeResult

type ProbeResult struct {
	Name string
}

A ProbeResult names a successfully probed resource.

type ReplyBlockShims

type ReplyBlockShims struct {
	Error    string
	Object   string
	ItemName string
	Verifier string
	Bool     string
	Size     string
}

ReplyBlockShims names optional linked functions used for typed FSKit reply block invocation. Each field names a C function that invokes a block of the corresponding shape; an empty name means no shim is linked for that shape.

type ReplyBlocks

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

ReplyBlocks invokes FSKit reply blocks.

func NewReplyBlocks

func NewReplyBlocks() *ReplyBlocks

NewReplyBlocks returns a reply block invoker with no linked shim names.

func NewReplyBlocksWithShims

func NewReplyBlocksWithShims(shims ReplyBlockShims) *ReplyBlocks

NewReplyBlocksWithShims returns a reply block invoker that prefers linked typed shims when they are present.

func (*ReplyBlocks) BoolError

func (r *ReplyBlocks) BoolError(block objc.ID, value bool, err objc.ID) error

BoolError invokes a reply block that takes a boolean and an NSError.

func (*ReplyBlocks) Error

func (r *ReplyBlocks) Error(block objc.ID, err objc.ID) error

Error invokes a reply block that takes an NSError.

func (*ReplyBlocks) ItemNameError

func (r *ReplyBlocks) ItemNameError(block objc.ID, item objc.ID, name objc.ID, err objc.ID) error

ItemNameError invokes a reply block that takes an FSItem, an FSFileName, and an NSError.

func (*ReplyBlocks) ObjectError

func (r *ReplyBlocks) ObjectError(block objc.ID, object objc.ID, err objc.ID) error

ObjectError invokes a reply block that takes an object and an NSError.

func (*ReplyBlocks) SizeError

func (r *ReplyBlocks) SizeError(block objc.ID, size uintptr, err objc.ID) error

SizeError invokes a reply block that takes a byte count and an NSError.

func (*ReplyBlocks) VerifierError

func (r *ReplyBlocks) VerifierError(block objc.ID, verifier uint64, err objc.ID) error

VerifierError invokes a reply block that takes a directory verifier and an NSError.

func (*ReplyBlocks) Void

func (r *ReplyBlocks) Void(block objc.ID) error

Void invokes a reply block that takes no arguments.

type Server

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

A Server adapts a UnaryFileSystem to FSKit. It registers the Objective-C class set, implements the FSKit operation selectors, tracks the FSItem and FSVolume objects it hands to FSKit, and reports operation errors as POSIX-domain NSErrors.

The Server declares the FSKit volume operation protocols and answers each protocol's inhibited query according to the optional interfaces the loaded Volume implements. Volume renaming is always inhibited.

Register a class set once per process: a second Server with the same class names takes over that class set's operations.

func NewServer

func NewServer(cfg ServerConfig) (*Server, error)

NewServer registers the class set for cfg and returns its Server.

func (*Server) Classes

func (s *Server) Classes() ClassSet

Classes returns the registered class set.

func (*Server) LoadResource

func (s *Server) LoadResource(self, resource, options, reply objc.ID)

LoadResource loads a resource, replies with its FSVolume, and marks the container ready. It is the implementation of loadResource:options:replyHandler:, exported for host shims that route the selector to Go themselves.

func (*Server) NewFileSystem

func (s *Server) NewFileSystem() objc.ID

NewFileSystem returns a new instance of the file system class.

func (*Server) NewVolume

func (s *Server) NewVolume(v Volume) (objc.ID, error)

NewVolume returns a new instance of the volume class serving v, with its root item already resolved.

func (*Server) ProbeResource

func (s *Server) ProbeResource(self, resource, reply objc.ID)

ProbeResource probes a resource and replies with an FSProbeResult. It is the implementation of probeResource:replyHandler:, exported for host shims that route the selector to Go themselves.

func (*Server) UnloadResource

func (s *Server) UnloadResource(self, resource, options, reply objc.ID)

UnloadResource unloads the resource and replies. It is the implementation of unloadResource:options:replyHandler:, exported for host shims that route the selector to Go themselves.

type ServerConfig

type ServerConfig struct {
	// FileSystemName, VolumeName, and ItemName name the Objective-C
	// classes the Server registers.
	FileSystemName string
	VolumeName     string
	ItemName       string

	// ExistingFileSystem, if nonzero, is used as the file system class
	// instead of registering one; see [ClassConfig]. The host shim then
	// routes operations to the Server through [Server.ProbeResource],
	// [Server.LoadResource], and [Server.UnloadResource].
	ExistingFileSystem objc.Class

	// Shims names linked reply block shims; see [ReplyBlockShims].
	Shims ReplyBlockShims

	// FileSystem is the file system implementation.
	FileSystem UnaryFileSystem

	// Logf, if non-nil, receives diagnostic messages. If nil, failures
	// to deliver a reply are reported through the log package and other
	// diagnostics are dropped.
	Logf func(format string, args ...any)
}

ServerConfig configures a Server.

type SetAttributes

type SetAttributes struct {
	Mode       *uint32
	UID        *uint32
	GID        *uint32
	Flags      *uint32
	Size       *uint64
	AccessTime *syscall.Timespec
	ModifyTime *syscall.Timespec
}

SetAttributes holds the attributes of a set-attributes request. A nil field was not requested.

The Server reports back to FSKit only the fields a Volume returns from SetAttributes, so a Volume that cannot change ownership should omit UID and GID from what it returns rather than failing the whole request.

type StatisticsVolume

type StatisticsVolume interface {
	Volume

	// Statistics returns the volume's statfs statistics.
	Statistics() fskit.FSStatFSResult
}

A StatisticsVolume is a Volume that reports its own statfs statistics. Without it the Server reports single-block placeholder statistics under the volume name.

type SymlinkVolume

type SymlinkVolume interface {
	Volume

	// Readlink returns the target of the symbolic link item.
	Readlink(item Item) (string, error)

	// Symlink creates a symbolic link named name to target in dir.
	Symlink(dir Item, name, target string) (Item, error)
}

A SymlinkVolume is a Volume with symbolic links.

type UnaryFileSystem

type UnaryFileSystem interface {
	// Probe inspects a resource and names the file system that would
	// mount it.
	Probe(resource fskit.FSResource) (ProbeResult, error)

	// Load prepares the resource and returns its volume.
	Load(resource fskit.FSResource) (Volume, error)

	// Unload releases the resource. It may be called more than once.
	Unload() error
}

A UnaryFileSystem implements an FSKit unary file system: a file system that manages a single resource as a single volume. The Server adapts it to the FSUnaryFileSystemOperations protocol.

Errors report errnos to FSKit as described for Volume.

type Volume

type Volume interface {
	// VolumeName returns the volume's display name.
	VolumeName() string

	// Root returns the item for the root directory.
	Root() (Item, error)

	// Lookup resolves name within the directory dir.
	Lookup(dir Item, name string) (Item, error)

	// Reclaim releases any state held for item. The system is done with
	// the item; it may be reclaimed more than once.
	Reclaim(item Item)

	// Attributes returns the item's attributes, including its file ID.
	Attributes(item Item) (fskit.FSItemAttributes, error)

	// ReadDir lists the directory dir.
	ReadDir(dir Item) ([]DirEntry, error)

	// Read reads from file at offset into buf, returning the number of
	// bytes read. Reading past the end of the file returns 0, and io.EOF
	// is not an error.
	Read(file Item, offset int64, buf []byte) (int, error)
}

A Volume implements the core, read-only operations of an FSKit volume. The Server adapts a Volume to the FSVolumeOperations protocol and answers the mutating operations with EROFS unless the Volume also implements MutableVolume.

Optional interfaces extend a Volume with additional FSKit operations: MutableVolume, SymlinkVolume, LinkVolume, XattrVolume, PreallocateVolume, OpenCloseVolume, AccessCheckVolume, CapabilitiesVolume, StatisticsVolume, and PathConfVolume.

Operations report failure by returning an error. An error that is or wraps a syscall.Errno reports that errno to FSKit; fs.ErrNotExist, fs.ErrExist, fs.ErrPermission, fs.ErrInvalid, and errors.ErrUnsupported report ENOENT, EEXIST, EACCES, EINVAL, and ENOTSUP; any other error reports EIO. In xattr operations fs.ErrNotExist reports ENOATTR.

type XattrVolume

type XattrVolume interface {
	Volume

	// GetXattr returns the value of the extended attribute name on item.
	GetXattr(item Item, name string) ([]byte, error)

	// SetXattr sets the extended attribute name on item to data.
	SetXattr(item Item, name string, data []byte) error

	// RemoveXattr removes the extended attribute name from item.
	RemoveXattr(item Item, name string) error

	// ListXattr lists the extended attribute names on item.
	ListXattr(item Item) ([]string, error)
}

An XattrVolume is a Volume with extended attributes. The Server implements the FSKit set-xattr policies (must-create, must-replace, delete) in terms of these methods.

Jump to

Keyboard shortcuts

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