Documentation ¶
Overview ¶
Package fuse provides APIs to implement filesystems in userspace in terms of raw FUSE protocol.
A filesystem is implemented by implementing its server that provides a RawFileSystem interface. Typically the server embeds NewDefaultRawFileSystem() and implements only subset of filesystem methods:
type MyFS struct { fuse.RawFileSystem ... } func NewMyFS() *MyFS { return &MyFS{ RawFileSystem: fuse.NewDefaultRawFileSystem(), ... } } // Mkdir implements "mkdir" request handler. // // For other requests - not explicitly implemented by MyFS - ENOSYS // will be typically returned to client. func (fs *MyFS) Mkdir(...) { ... }
Then the filesystem can be mounted and served to a client (typically OS kernel) by creating Server:
fs := NewMyFS() // implements RawFileSystem fssrv, err := fuse.NewServer(fs, mountpoint, &fuse.MountOptions{...}) if err != nil { ... }
and letting the server do its work:
// either synchronously - .Serve() blocks until the filesystem is unmounted. fssrv.Serve() // or in the background - .Serve() is spawned in another goroutine, but // before interacting with fssrv from current context we have to wait // until the filesystem mounting is complete. go fssrv.Serve() err = fssrv.WaitMount() if err != nil { ... }
The server will serve clients by dispatching their requests to the filesystem implementation and conveying responses back. For example "mkdir" FUSE request dispatches to call
fs.Mkdir(*MkdirIn, ..., *EntryOut)
"stat" to call
fs.GetAttr(*GetAttrIn, *AttrOut)
etc. Please refer to RawFileSystem documentation for details.
Typically, each call of the API happens in its own goroutine, so take care to make the file system thread-safe.
Be careful when you access the FUSE mount from the same process. An access can tie up two OS threads (one on the request side and one on the FUSE server side). This can deadlock if there is no free thread to handle the FUSE server side. Run your program with GOMAXPROCS=1 to make the problem easier to reproduce, see https://github.com/hanwen/go-fuse/issues/261 for an example of that problem.
Higher level interfaces ¶
As said above this packages provides way to implement filesystems in terms of raw FUSE protocol.
Package github.com/hanwen/go-fuse/v2/fs provides way to implement filesystems in terms of paths and/or inodes.
Mount styles ¶
The NewServer() handles mounting the filesystem, which involves opening `/dev/fuse` and calling the `mount(2)` syscall. The latter needs root permissions. This is handled in one of three ways:
1) go-fuse opens `/dev/fuse` and executes the `fusermount` setuid-root helper to call `mount(2)` for us. This is the default. Does not need root permissions but needs `fusermount` installed.
2) If `MountOptions.DirectMount` is set, go-fuse calls `mount(2)` itself. Needs root permissions, but works without `fusermount`.
3) If `mountPoint` has the magic `/dev/fd/N` syntax, it means that that a privileged parent process:
* Opened /dev/fuse
* Called mount(2) on a real mountpoint directory that we don't know about
* Inherited the fd to /dev/fuse to us
* Informs us about the fd number via /dev/fd/N
This magic syntax originates from libfuse [1] and allows the FUSE server to run without any privileges and without needing `fusermount`, as the parent process performs all privileged operations.
The "privileged parent" is usually a container manager like Singularity [2], but for testing, it can also be the `mount.fuse3` helper with the `drop_privileges,setuid=$USER` flags. Example below for gocryptfs:
$ sudo mount.fuse3 "/usr/local/bin/gocryptfs#/tmp/cipher" /tmp/mnt -o drop_privileges,setuid=$USER
[1] https://github.com/libfuse/libfuse/commit/64e11073b9347fcf9c6d1eea143763ba9e946f70
[2] https://sylabs.io/guides/3.7/user-guide/bind_paths_and_mounts.html#fuse-mounts
Index ¶
- Constants
- func NewContext(ctx context.Context, caller *Caller) context.Context
- func Print(obj interface{}) string
- func ToStatT(f os.FileInfo) *syscall.Stat_t
- func UtimeToTimespec(t *time.Time) (ts syscall.Timespec)deprecated
- type AccessIn
- type Attr
- func (a *Attr) AccessTime() time.Time
- func (a *Attr) ChangeTime() time.Time
- func (a *Attr) FromStat(s *syscall.Stat_t)
- func (a *Attr) IsBlock() bool
- func (a *Attr) IsChar() bool
- func (a *Attr) IsDir() bool
- func (a *Attr) IsFifo() bool
- func (a *Attr) IsRegular() bool
- func (a *Attr) IsSocket() bool
- func (a *Attr) IsSymlink() bool
- func (a *Attr) ModTime() time.Time
- func (a *Attr) SetTimes(access *time.Time, mod *time.Time, chstatus *time.Time)
- func (a *Attr) String() string
- type AttrOut
- type Caller
- type Context
- type CopyFileRangeIn
- type CreateIn
- type CreateOut
- type DirEntry
- type DirEntryList
- type EntryOut
- type FallocateIn
- type FileLock
- type FlushIn
- type ForgetIn
- type FsyncIn
- type GetAttrIn
- type GetXAttrIn
- type GetXAttrOut
- type InHeader
- type InitIn
- type InitOut
- type InterruptIn
- type LatencyMap
- type LinkIn
- type LkIn
- type LkOut
- type LseekIn
- type LseekOut
- type MkdirIn
- type MknodIn
- type MountOptions
- type NotifyInvalDeleteOut
- type NotifyInvalEntryOut
- type NotifyInvalInodeOut
- type NotifyRetrieveIn
- type NotifyRetrieveOut
- type NotifyStoreOut
- type OpenIn
- type OpenOut
- type OutHeader
- type Owner
- type RawFileSystem
- type ReadIn
- type ReadResult
- type ReleaseIn
- type Rename1In
- type RenameIn
- type Server
- func (ms *Server) DebugData() string
- func (ms *Server) DeleteNotify(parent uint64, child uint64, name string) Status
- func (ms *Server) EntryNotify(parent uint64, name string) Status
- func (ms *Server) InodeNotify(node uint64, off int64, length int64) Status
- func (ms *Server) InodeNotifyStoreCache(node uint64, offset int64, data []byte) Status
- func (ms *Server) InodeRetrieveCache(node uint64, offset int64, dest []byte) (n int, st Status)
- func (ms *Server) KernelSettings() *InitIn
- func (ms *Server) RecordLatencies(l LatencyMap)
- func (ms *Server) Serve()
- func (ms *Server) SetDebug(dbg bool)
- func (ms *Server) Unmount() (err error)
- func (ms *Server) Wait()
- func (ms *Server) WaitMount() error
- type SetAttrIn
- type SetAttrInCommon
- func (s *SetAttrInCommon) GetATime() (time.Time, bool)
- func (s *SetAttrInCommon) GetCTime() (time.Time, bool)
- func (s *SetAttrInCommon) GetFh() (uint64, bool)
- func (s *SetAttrInCommon) GetGID() (uint32, bool)
- func (s *SetAttrInCommon) GetMTime() (time.Time, bool)
- func (s *SetAttrInCommon) GetMode() (uint32, bool)
- func (s *SetAttrInCommon) GetSize() (uint64, bool)
- func (s *SetAttrInCommon) GetUID() (uint32, bool)
- type SetXAttrIn
- type StatfsOut
- type Status
- type WriteIn
- type WriteOut
Constants ¶
const ( FUSE_ROOT_ID = 1 FUSE_UNKNOWN_INO = 0xffffffff CUSE_UNRESTRICTED_IOCTL = (1 << 0) FUSE_LK_FLOCK = (1 << 0) FUSE_RELEASE_FLUSH = (1 << 0) FUSE_RELEASE_FLOCK_UNLOCK = (1 << 1) FUSE_IOCTL_MAX_IOV = 256 FUSE_POLL_SCHEDULE_NOTIFY = (1 << 0) CUSE_INIT_INFO_MAX = 4096 S_IFDIR = syscall.S_IFDIR S_IFREG = syscall.S_IFREG S_IFLNK = syscall.S_IFLNK S_IFIFO = syscall.S_IFIFO CUSE_INIT = 4096 O_ANYWRITE = uint32(os.O_WRONLY | os.O_RDWR | os.O_APPEND | os.O_CREATE | os.O_TRUNC) )
const ( OK = Status(0) // EACCESS Permission denied EACCES = Status(syscall.EACCES) // EBUSY Device or resource busy EBUSY = Status(syscall.EBUSY) // EAGAIN Resource temporarily unavailable EAGAIN = Status(syscall.EAGAIN) // EINTR Call was interrupted EINTR = Status(syscall.EINTR) // EINVAL Invalid argument EINVAL = Status(syscall.EINVAL) // EIO I/O error EIO = Status(syscall.EIO) // ENOENT No such file or directory ENOENT = Status(syscall.ENOENT) // ENOSYS Function not implemented ENOSYS = Status(syscall.ENOSYS) // ENOTDIR Not a directory ENOTDIR = Status(syscall.ENOTDIR) // ENOTSUP Not supported ENOTSUP = Status(syscall.ENOTSUP) // EISDIR Is a directory EISDIR = Status(syscall.EISDIR) // EPERM Operation not permitted EPERM = Status(syscall.EPERM) // ERANGE Math result not representable ERANGE = Status(syscall.ERANGE) // EXDEV Cross-device link EXDEV = Status(syscall.EXDEV) // EBADF Bad file number EBADF = Status(syscall.EBADF) // ENODEV No such device ENODEV = Status(syscall.ENODEV) // EROFS Read-only file system EROFS = Status(syscall.EROFS) )
const ( FATTR_MODE = (1 << 0) FATTR_UID = (1 << 1) FATTR_GID = (1 << 2) FATTR_SIZE = (1 << 3) FATTR_ATIME = (1 << 4) FATTR_MTIME = (1 << 5) FATTR_FH = (1 << 6) FATTR_ATIME_NOW = (1 << 7) FATTR_MTIME_NOW = (1 << 8) FATTR_LOCKOWNER = (1 << 9) FATTR_CTIME = (1 << 10) FATTR_KILL_SUIDGID = (1 << 11) )
const ( // OpenOut.Flags FOPEN_DIRECT_IO = (1 << 0) FOPEN_KEEP_CACHE = (1 << 1) FOPEN_NONSEEKABLE = (1 << 2) FOPEN_CACHE_DIR = (1 << 3) FOPEN_STREAM = (1 << 4) FOPEN_NOFLUSH = (1 << 5) FOPEN_PARALLEL_DIRECT_WRITES = (1 << 6) )
const ( CAP_ASYNC_READ = (1 << 0) CAP_POSIX_LOCKS = (1 << 1) CAP_FILE_OPS = (1 << 2) CAP_ATOMIC_O_TRUNC = (1 << 3) CAP_EXPORT_SUPPORT = (1 << 4) CAP_BIG_WRITES = (1 << 5) CAP_DONT_MASK = (1 << 6) CAP_SPLICE_WRITE = (1 << 7) CAP_SPLICE_MOVE = (1 << 8) CAP_SPLICE_READ = (1 << 9) CAP_FLOCK_LOCKS = (1 << 10) CAP_IOCTL_DIR = (1 << 11) CAP_AUTO_INVAL_DATA = (1 << 12) CAP_READDIRPLUS = (1 << 13) CAP_READDIRPLUS_AUTO = (1 << 14) CAP_ASYNC_DIO = (1 << 15) CAP_WRITEBACK_CACHE = (1 << 16) CAP_NO_OPEN_SUPPORT = (1 << 17) CAP_PARALLEL_DIROPS = (1 << 18) CAP_HANDLE_KILLPRIV = (1 << 19) CAP_POSIX_ACL = (1 << 20) CAP_ABORT_ERROR = (1 << 21) CAP_MAX_PAGES = (1 << 22) CAP_CACHE_SYMLINKS = (1 << 23) /* bits 32..63 get shifted down 32 bits into the Flags2 field */ CAP_SECURITY_CTX = (1 << 32) CAP_HAS_INODE_DAX = (1 << 33) CAP_CREATE_SUPP_GROUP = (1 << 34) CAP_HAS_EXPIRE_ONLY = (1 << 35) CAP_DIRECT_IO_RELAX = (1 << 36) )
To be set in InitIn/InitOut.Flags.
Keep in sync with either of * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/fuse.h * https://github.com/libfuse/libfuse/blob/master/include/fuse_kernel.h but NOT with * https://github.com/libfuse/libfuse/blob/master/include/fuse_common.h This file has CAP_HANDLE_KILLPRIV and CAP_POSIX_ACL reversed!
const ( FUSE_IOCTL_COMPAT = (1 << 0) FUSE_IOCTL_UNRESTRICTED = (1 << 1) FUSE_IOCTL_RETRY = (1 << 2) )
const ( X_OK = 1 W_OK = 2 R_OK = 4 F_OK = 0 )
For AccessIn.Mask.
const ( // NOTIFY_POLL = -1 // notify kernel that a poll waiting for IO on a file handle should wake up NOTIFY_INVAL_INODE = -2 // notify kernel that an inode should be invalidated NOTIFY_INVAL_ENTRY = -3 // notify kernel that a directory entry should be invalidated NOTIFY_STORE_CACHE = -4 // store data into kernel cache of an inode NOTIFY_RETRIEVE_CACHE = -5 // retrieve data from kernel cache of an inode NOTIFY_DELETE = -6 // notify kernel that a directory entry has been deleted )
const ( WRITE_CACHE = (1 << 0) WRITE_LOCKOWNER = (1 << 1) WRITE_KILL_SUIDGID = (1 << 2) )
const ( ENODATA = Status(syscall.ENODATA) ENOATTR = Status(syscall.ENODATA) // On Linux, ENOATTR is an alias for ENODATA. // EREMOTEIO Remote I/O error EREMOTEIO = Status(syscall.EREMOTEIO) )
const ( CAP_NO_OPENDIR_SUPPORT = (1 << 24) CAP_EXPLICIT_INVAL_DATA = (1 << 25) CAP_MAP_ALIGNMENT = (1 << 26) CAP_SUBMOUNTS = (1 << 27) CAP_HANDLE_KILLPRIV_V2 = (1 << 28) CAP_SETXATTR_EXT = (1 << 29) CAP_INIT_EXT = (1 << 30) CAP_INIT_RESERVED = (1 << 31) // CAP_RENAME_SWAP only exists on OSX. CAP_RENAME_SWAP = 0x0 )
To be set in InitIn/InitOut.Flags.
This flags conflict with https://github.com/macfuse/library/blob/master/include/fuse_common.h and should be used only on Linux.
const (
// Mask for GetAttrIn.Flags. If set, GetAttrIn has a file handle set.
FUSE_GETATTR_FH = (1 << 0)
)
const (
// Linux v4.20+ caps requests at 1 MiB. Older kernels at 128 kiB.
MAX_KERNEL_WRITE = 1024 * 1024
)
const (
READ_LOCKOWNER = (1 << 1)
)
const RELEASE_FLUSH = (1 << 0)
Variables ¶
This section is empty.
Functions ¶
func Print ¶
func Print(obj interface{}) string
Print pretty prints FUSE data types for kernel communication
func UtimeToTimespec
deprecated
UtimeToTimespec converts a "Time" pointer as passed to Utimens to a "Timespec" that can be passed to the utimensat syscall. A nil pointer is converted to the special UTIME_OMIT value.
Deprecated: use unix.TimeToTimespec from the x/sys/unix package instead.
Types ¶
type Attr ¶
type Attr struct { Ino uint64 Size uint64 // Blocks is the number of 512-byte blocks that the file occupies on disk. Blocks uint64 Atime uint64 Mtime uint64 Ctime uint64 Atimensec uint32 Mtimensec uint32 Ctimensec uint32 Mode uint32 Nlink uint32 Owner Rdev uint32 // Blksize is the preferred size for file system operations. Blksize uint32 Padding uint32 }
func (*Attr) AccessTime ¶
func (*Attr) ChangeTime ¶
type AttrOut ¶
func (*AttrOut) SetTimeout ¶
type Caller ¶
Caller has data on the process making the FS call.
The UID and GID are effective UID/GID, except for the ACCESS opcode, where UID and GID are the real UIDs
type Context ¶
type Context struct { Caller Cancel <-chan struct{} }
Context passes along cancelation signal and request data (PID, GID, UID). The name of this class predates the standard "context" package from Go, but it does implement the context.Context interface.
When a FUSE request is canceled, the API routine should respond by returning the EINTR status code.
type CopyFileRangeIn ¶
type DirEntry ¶
type DirEntry struct { // Mode is the file's mode. Only the high bits (eg. S_IFDIR) // are considered. Mode uint32 // Name is the basename of the file in the directory. Name string // Ino is the inode number. Ino uint64 }
DirEntry is a type for PathFileSystem and NodeFileSystem to return directory contents in.
type DirEntryList ¶
type DirEntryList struct {
// contains filtered or unexported fields
}
DirEntryList holds the return value for READDIR and READDIRPLUS opcodes.
func NewDirEntryList ¶
func NewDirEntryList(data []byte, off uint64) *DirEntryList
NewDirEntryList creates a DirEntryList with the given data buffer and offset.
func (*DirEntryList) AddDirEntry ¶
func (l *DirEntryList) AddDirEntry(e DirEntry) bool
AddDirEntry tries to add an entry, and reports whether it succeeded.
func (*DirEntryList) AddDirLookupEntry ¶
func (l *DirEntryList) AddDirLookupEntry(e DirEntry) *EntryOut
AddDirLookupEntry is used for ReadDirPlus. If reserves and zeroizes space for an EntryOut struct and serializes a DirEntry. On success, it returns pointers to both structs. If not enough space was left, it returns two nil pointers.
The resulting READDIRPLUS output buffer looks like this in memory: 1) EntryOut{} 2) _Dirent{} 3) Name (null-terminated) 4) Padding to align to 8 bytes [repeat]
func (*DirEntryList) FixMode ¶
func (l *DirEntryList) FixMode(mode uint32)
FixMode overrides the file mode of the last direntry that was added. This can be needed when a directory changes while READDIRPLUS is running. Only the file type bits of mode are considered, the rest is masked out.
type EntryOut ¶
type EntryOut struct { NodeId uint64 Generation uint64 EntryValid uint64 AttrValid uint64 EntryValidNsec uint32 AttrValidNsec uint32 Attr }
EntryOut holds the result of a (directory,name) lookup. It has two TTLs, one for the (directory, name) lookup itself, and one for the attributes (eg. size, mode). The entry TTL also applies if the lookup result is ENOENT ("negative entry lookup")
func (*EntryOut) AttrTimeout ¶
func (*EntryOut) EntryTimeout ¶
EntryTimeout returns entry timeout currently
func (*EntryOut) SetAttrTimeout ¶
func (*EntryOut) SetEntryTimeout ¶
type FallocateIn ¶
type FileLock ¶
func (*FileLock) FromFlockT ¶
type GetAttrIn ¶
type GetXAttrIn ¶
type GetXAttrOut ¶
type InitIn ¶
type InitIn struct { InHeader Major uint32 Minor uint32 MaxReadAhead uint32 Flags uint32 Flags2 uint32 Unused [11]uint32 }
func (*InitIn) SupportsNotify ¶
SupportsNotify returns whether a certain notification type is supported. Pass any of the NOTIFY_* types as argument.
func (*InitIn) SupportsVersion ¶
SupportsVersion returns true if the kernel supports the given protocol version or newer.
type InterruptIn ¶
type LatencyMap ¶
This type may be provided for recording latencies of each FUSE operation.
type MountOptions ¶
type MountOptions struct { AllowOther bool // Options are passed as -o string to fusermount. Options []string // Default is _DEFAULT_BACKGROUND_TASKS, 12. This numbers // controls the allowed number of requests that relate to // async I/O. Concurrency for synchronous I/O is not limited. MaxBackground int // MaxWrite is the max size for read and write requests. If 0, use // go-fuse default (currently 64 kiB). // This number is internally capped at MAX_KERNEL_WRITE (higher values don't make // sense). // // Non-direct-io reads are mostly served via kernel readahead, which is // additionally subject to the MaxReadAhead limit. // // Implementation notes: // // There's four values the Linux kernel looks at when deciding the request size: // * MaxWrite, passed via InitOut.MaxWrite. Limits the WRITE size. // * max_read, passed via a string mount option. Limits the READ size. // go-fuse sets max_read equal to MaxWrite. // You can see the current max_read value in /proc/self/mounts . // * MaxPages, passed via InitOut.MaxPages. In Linux 4.20 and later, the value // can go up to 1 MiB and go-fuse calculates the MaxPages value acc. // to MaxWrite, rounding up. // On older kernels, the value is fixed at 128 kiB and the // passed value is ignored. No request can be larger than MaxPages, so // READ and WRITE are effectively capped at MaxPages. // * MaxReadAhead, passed via InitOut.MaxReadAhead. MaxWrite int // MaxReadAhead is the max read ahead size to use. It controls how much data the // kernel reads in advance to satisfy future read requests from applications. // How much exactly is subject to clever heuristics in the kernel // (see https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/mm/readahead.c?h=v6.2-rc5#n375 // if you are brave) and hence also depends on the kernel version. // // If 0, use kernel default. This number is capped at the kernel maximum // (128 kiB on Linux) and cannot be larger than MaxWrite. // // MaxReadAhead only affects buffered reads (=non-direct-io), but even then, the // kernel can and does send larger reads to satisfy read reqests from applications // (up to MaxWrite or VM_READAHEAD_PAGES=128 kiB, whichever is less). MaxReadAhead int // If IgnoreSecurityLabels is set, all security related xattr // requests will return NO_DATA without passing through the // user defined filesystem. You should only set this if you // file system implements extended attributes, and you are not // interested in security labels. IgnoreSecurityLabels bool // ignoring labels should be provided as a fusermount mount option. // If RememberInodes is set, we will never forget inodes. // This may be useful for NFS. RememberInodes bool // Values shown in "df -T" and friends // First column, "Filesystem" FsName string // Second column, "Type", will be shown as "fuse." + Name Name string // If set, wrap the file system in a single-threaded locking wrapper. SingleThreaded bool // If set, return ENOSYS for Getxattr calls, so the kernel does not issue any // Xattr operations at all. DisableXAttrs bool // If set, print debugging information. Debug bool // If set, sink for debug statements. Logger *log.Logger // If set, ask kernel to forward file locks to FUSE. If using, // you must implement the GetLk/SetLk/SetLkw methods. EnableLocks bool // If set, the kernel caches all Readlink return values. The // filesystem must use content notification to force the // kernel to issue a new Readlink call. EnableSymlinkCaching bool // If set, ask kernel not to do automatic data cache invalidation. // The filesystem is fully responsible for invalidating data cache. ExplicitDataCacheControl bool // SyncRead is off by default, which means that go-fuse enable the // FUSE_CAP_ASYNC_READ capability. // The kernel then submits multiple concurrent reads to service // userspace requests and kernel readahead. // // Setting SyncRead disables the FUSE_CAP_ASYNC_READ capability. // The kernel then only sends one read request per file handle at a time, // and orders the requests by offset. // // This is useful if reading out of order or concurrently is expensive for // (example: Amazon Cloud Drive). // // See the comment to FUSE_CAP_ASYNC_READ in // https://github.com/libfuse/libfuse/blob/master/include/fuse_common.h // for more details. SyncRead bool // If set, fuse will first attempt to use syscall.Mount instead of // fusermount to mount the filesystem. This will not update /etc/mtab // but might be needed if fusermount is not available. // Also, Server.Unmount will attempt syscall.Unmount before calling // fusermount. DirectMount bool // DirectMountStrict is like DirectMount but no fallback to fusermount is // performed. If both DirectMount and DirectMountStrict are set, // DirectMountStrict wins. DirectMountStrict bool // DirectMountFlags are the mountflags passed to syscall.Mount. If zero, the // default value used by fusermount are used: syscall.MS_NOSUID|syscall.MS_NODEV. // // If you actually *want* zero flags, pass syscall.MS_MGC_VAL, which is ignored // by the kernel. See `man 2 mount` for details about MS_MGC_VAL. DirectMountFlags uintptr // EnableAcls enables kernel ACL support. // // See the comments to FUSE_CAP_POSIX_ACL // in https://github.com/libfuse/libfuse/blob/master/include/fuse_common.h // for details. EnableAcl bool // Disable ReadDirPlus capability so ReadDir is used instead. Simple // directory queries (i.e. 'ls' without '-l') can be faster with // ReadDir, as no per-file stat calls are needed DisableReadDirPlus bool }
type NotifyInvalDeleteOut ¶
type NotifyInvalEntryOut ¶
type NotifyInvalInodeOut ¶
type NotifyRetrieveIn ¶
type NotifyRetrieveOut ¶
type NotifyStoreOut ¶
type Owner ¶
func CurrentOwner ¶
func CurrentOwner() *Owner
type RawFileSystem ¶
type RawFileSystem interface { String() string // If called, provide debug output through the log package. SetDebug(debug bool) // Lookup is called by the kernel when the VFS wants to know // about a file inside a directory. Many lookup calls can // occur in parallel, but only one call happens for each (dir, // name) pair. Lookup(cancel <-chan struct{}, header *InHeader, name string, out *EntryOut) (status Status) // Forget is called when the kernel discards entries from its // dentry cache. This happens on unmount, and when the kernel // is short on memory. Since it is not guaranteed to occur at // any moment, and since there is no return value, Forget // should not do I/O, as there is no channel to report back // I/O errors. Forget(nodeid, nlookup uint64) // Attributes. GetAttr(cancel <-chan struct{}, input *GetAttrIn, out *AttrOut) (code Status) SetAttr(cancel <-chan struct{}, input *SetAttrIn, out *AttrOut) (code Status) // Modifying structure. Mknod(cancel <-chan struct{}, input *MknodIn, name string, out *EntryOut) (code Status) Mkdir(cancel <-chan struct{}, input *MkdirIn, name string, out *EntryOut) (code Status) Unlink(cancel <-chan struct{}, header *InHeader, name string) (code Status) Rmdir(cancel <-chan struct{}, header *InHeader, name string) (code Status) Rename(cancel <-chan struct{}, input *RenameIn, oldName string, newName string) (code Status) Link(cancel <-chan struct{}, input *LinkIn, filename string, out *EntryOut) (code Status) Symlink(cancel <-chan struct{}, header *InHeader, pointedTo string, linkName string, out *EntryOut) (code Status) Readlink(cancel <-chan struct{}, header *InHeader) (out []byte, code Status) Access(cancel <-chan struct{}, input *AccessIn) (code Status) // GetXAttr reads an extended attribute, and should return the // number of bytes. If the buffer is too small, return ERANGE, // with the required buffer size. GetXAttr(cancel <-chan struct{}, header *InHeader, attr string, dest []byte) (sz uint32, code Status) // ListXAttr lists extended attributes as '\0' delimited byte // slice, and return the number of bytes. If the buffer is too // small, return ERANGE, with the required buffer size. ListXAttr(cancel <-chan struct{}, header *InHeader, dest []byte) (uint32, Status) // SetAttr writes an extended attribute. SetXAttr(cancel <-chan struct{}, input *SetXAttrIn, attr string, data []byte) Status // RemoveXAttr removes an extended attribute. RemoveXAttr(cancel <-chan struct{}, header *InHeader, attr string) (code Status) // File handling. Create(cancel <-chan struct{}, input *CreateIn, name string, out *CreateOut) (code Status) Open(cancel <-chan struct{}, input *OpenIn, out *OpenOut) (status Status) Read(cancel <-chan struct{}, input *ReadIn, buf []byte) (ReadResult, Status) Lseek(cancel <-chan struct{}, in *LseekIn, out *LseekOut) Status // File locking GetLk(cancel <-chan struct{}, input *LkIn, out *LkOut) (code Status) SetLk(cancel <-chan struct{}, input *LkIn) (code Status) SetLkw(cancel <-chan struct{}, input *LkIn) (code Status) Release(cancel <-chan struct{}, input *ReleaseIn) Write(cancel <-chan struct{}, input *WriteIn, data []byte) (written uint32, code Status) CopyFileRange(cancel <-chan struct{}, input *CopyFileRangeIn) (written uint32, code Status) Flush(cancel <-chan struct{}, input *FlushIn) Status Fsync(cancel <-chan struct{}, input *FsyncIn) (code Status) Fallocate(cancel <-chan struct{}, input *FallocateIn) (code Status) // Directory handling OpenDir(cancel <-chan struct{}, input *OpenIn, out *OpenOut) (status Status) ReadDir(cancel <-chan struct{}, input *ReadIn, out *DirEntryList) Status ReadDirPlus(cancel <-chan struct{}, input *ReadIn, out *DirEntryList) Status ReleaseDir(input *ReleaseIn) FsyncDir(cancel <-chan struct{}, input *FsyncIn) (code Status) StatFs(cancel <-chan struct{}, input *InHeader, out *StatfsOut) (code Status) // This is called on processing the first request. The // filesystem implementation can use the server argument to // talk back to the kernel (through notify methods). Init(*Server) }
RawFileSystem is an interface close to the FUSE wire protocol.
Unless you really know what you are doing, you should not implement this, but rather the nodefs.Node or pathfs.FileSystem interfaces; the details of getting interactions with open files, renames, and threading right etc. are somewhat tricky and not very interesting.
Each FUSE request results in a corresponding method called by Server. Several calls may be made simultaneously, because the server typically calls each method in separate goroutine.
A null implementation is provided by NewDefaultRawFileSystem.
After a successful FUSE API call returns, you may not read input or write output data: for performance reasons, memory is reused for following requests, and reading/writing the request data will lead to race conditions. If you spawn a background routine from a FUSE API call, any incoming request data it wants to reference should be copied over.
If a FUSE API call is canceled (which is signaled by closing the `cancel` channel), the API call should return EINTR. In this case, the outstanding request data is not reused, so the API call may return EINTR without ensuring that child contexts have successfully completed.
func NewDefaultRawFileSystem ¶
func NewDefaultRawFileSystem() RawFileSystem
NewDefaultRawFileSystem returns ENOSYS (not implemented) for all operations.
type ReadResult ¶
type ReadResult interface { // Returns the raw bytes for the read, possibly using the // passed buffer. The buffer should be larger than the return // value from Size. Bytes(buf []byte) ([]byte, Status) // Size returns how many bytes this return value takes at most. Size() int // Done() is called after sending the data to the kernel. Done() }
The result of Read is an array of bytes, but for performance reasons, we can also return data as a file-descriptor/offset/size tuple. If the backing store for a file is another filesystem, this reduces the amount of copying between the kernel and the FUSE server. The ReadResult interface captures both cases.
func ReadResultData ¶
func ReadResultData(b []byte) ReadResult
func ReadResultFd ¶
func ReadResultFd(fd uintptr, off int64, sz int) ReadResult
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server contains the logic for reading from the FUSE device and translating it to RawFileSystem interface calls.
func NewServer ¶
func NewServer(fs RawFileSystem, mountPoint string, opts *MountOptions) (*Server, error)
NewServer creates a FUSE server and attaches ("mounts") it to the `mountPoint` directory.
See the "Mount styles" section in the package documentation if you want to know about the inner workings of the mount process. Usually you do not.
func (*Server) DeleteNotify ¶
DeleteNotify notifies the kernel that an entry is removed from a directory. In many cases, this is equivalent to EntryNotify, except when the directory is in use, eg. as working directory of some process. You should not hold any FUSE filesystem locks, as that can lead to deadlock.
func (*Server) EntryNotify ¶
EntryNotify should be used if the existence status of an entry within a directory changes. You should not hold any FUSE filesystem locks, as that can lead to deadlock.
func (*Server) InodeNotify ¶
InodeNotify invalidates the information associated with the inode (ie. data cache, attributes, etc.)
func (*Server) InodeNotifyStoreCache ¶
InodeNotifyStoreCache tells kernel to store data into inode's cache.
This call is similar to InodeNotify, but instead of only invalidating a data region, it gives updated data directly to the kernel.
func (*Server) InodeRetrieveCache ¶
InodeRetrieveCache retrieves data from kernel's inode cache.
InodeRetrieveCache asks kernel to return data from its cache for inode at [offset:offset+len(dest)) and waits for corresponding reply. If kernel cache has fewer consecutive data starting at offset, that fewer amount is returned. In particular if inode data at offset is not cached (0, OK) is returned.
The kernel returns ENOENT if it does not currently have entry for this inode in its dentry cache.
func (*Server) KernelSettings ¶
KernelSettings returns the Init message from the kernel, so filesystems can adapt to availability of features of the kernel driver. The message should not be altered.
func (*Server) RecordLatencies ¶
func (ms *Server) RecordLatencies(l LatencyMap)
RecordLatencies switches on collection of timing for each request coming from the kernel.P assing a nil argument switches off the
func (*Server) Serve ¶
func (ms *Server) Serve()
Serve initiates the FUSE loop. Normally, callers should run Serve() and wait for it to exit, but tests will want to run this in a goroutine.
Each filesystem operation executes in a separate goroutine.
func (*Server) Unmount ¶
Unmount calls fusermount -u on the mount. This has the effect of shutting down the filesystem. After the Server is unmounted, it should be discarded. This function is idempotent.
Does not work when we were mounted with the magic /dev/fd/N mountpoint syntax, as we do not know the real mountpoint. Unmount using
fusermount -u /path/to/real/mountpoint
in this case.
type SetAttrIn ¶
type SetAttrIn struct {
SetAttrInCommon
}
type SetAttrInCommon ¶
type SetAttrInCommon struct { InHeader Valid uint32 Padding uint32 Fh uint64 Size uint64 LockOwner uint64 Atime uint64 Mtime uint64 Ctime uint64 Atimensec uint32 Mtimensec uint32 Ctimensec uint32 Mode uint32 Unused4 uint32 Owner Unused5 uint32 }
func (*SetAttrInCommon) GetFh ¶
func (s *SetAttrInCommon) GetFh() (uint64, bool)
GetFh returns the file handle if available, or 0 if undefined.
func (*SetAttrInCommon) GetGID ¶
func (s *SetAttrInCommon) GetGID() (uint32, bool)
func (*SetAttrInCommon) GetMode ¶
func (s *SetAttrInCommon) GetMode() (uint32, bool)
func (*SetAttrInCommon) GetSize ¶
func (s *SetAttrInCommon) GetSize() (uint64, bool)
func (*SetAttrInCommon) GetUID ¶
func (s *SetAttrInCommon) GetUID() (uint32, bool)
type SetXAttrIn ¶
type StatfsOut ¶
type StatfsOut struct { Blocks uint64 Bfree uint64 Bavail uint64 Files uint64 Ffree uint64 Bsize uint32 NameLen uint32 Frsize uint32 Padding uint32 Spare [6]uint32 }
func (*StatfsOut) FromStatfsT ¶
type Status ¶
type Status int32
Status is the errno number that a FUSE call returns to the kernel.
Source Files ¶
- api.go
- attr.go
- attr_linux.go
- bufferpool.go
- constants.go
- constants_linux.go
- context.go
- defaultraw.go
- direntry.go
- misc.go
- misc_unix.go
- mount.go
- mount_linux.go
- opcode.go
- poll.go
- poll_unix.go
- print.go
- print_linux.go
- print_unix.go
- read.go
- request.go
- request_linux.go
- server.go
- server_linux.go
- splice_linux.go
- syscall_linux.go
- typeprint.go
- types.go
- types_linux.go
- types_unix.go
Directories ¶
Path | Synopsis |
---|---|
This package is deprecated.
|
This package is deprecated. |
This package is deprecated.
|
This package is deprecated. |
Package test holds the tests for Go-FUSE and is not for end-user consumption.
|
Package test holds the tests for Go-FUSE and is not for end-user consumption. |