gvisor-lx/pkg/abi/linux/fuse.go
Leadaxe 117243aa02 snapshot: sagernet/gvisor v0.0.0-20260727.0-sing-box-mod.1 + SPEC 048 guard
Обновление снапшота с v0.0.0-20250811.0 на пин, которого требует
sing-box после мержа 235 коммитов (upstream d620bbbf2 "Update gvisor to
20260727.0"). Прежний снапшот был взят 2026-08-04 ровно с той версии,
на которой тогда стоял апстрим; разрыв возник 2026-08-05 вместе с его
бампом.

За год апстрим-gvisor изменил ~14 000 строк в 292 файлах. Значимое для
нас — сетевой стек: tcp/connect.go (PMTU-discovery + исправление
начального RTT/RTO: раньше задержка ACK внутри стека завышала стартовый
таймаут на несколько RTT), tcp/snd.go, tcp/rcv.go, stack/conntrack.go,
stack/packet_buffer.go. Всего 30 файлов в TCP и 37 в stack.

Баг SPEC 048 апстрим НЕ исправил — проверено по коду новой версии:
handleConnecting по-прежнему проверяет состояние endpoint'а, но не ep.h,
а performHandshake так же зануляет h и отпускает мьютекс до Close().
Поэтому guard перенесён (12 строк) вместе со своим тестом (45 строк).

Red/green проверен на новой базе: без guard'а тест падает с той же
nil-паникой, что в полевом крашдампе; с ним зелёный.
2026-08-05 14:53:31 +03:00

1267 lines
32 KiB
Go

// Copyright 2020 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package linux
import (
"structs"
"time"
"github.com/sagernet/gvisor/pkg/marshal/primitive"
)
// FUSEOpcode is a FUSE operation code.
//
// +marshal
type FUSEOpcode uint32
// FUSEOpID is a FUSE operation ID.
//
// +marshal
type FUSEOpID uint64
// FUSE_ROOT_ID is the id of root inode.
const FUSE_ROOT_ID = 1
// Opcodes for FUSE operations.
//
// Analogous to the opcodes in include/linux/fuse.h.
const (
FUSE_LOOKUP FUSEOpcode = 1
FUSE_FORGET = 2 /* no reply */
FUSE_GETATTR = 3
FUSE_SETATTR = 4
FUSE_READLINK = 5
FUSE_SYMLINK = 6
_
FUSE_MKNOD = 8
FUSE_MKDIR = 9
FUSE_UNLINK = 10
FUSE_RMDIR = 11
FUSE_RENAME = 12
FUSE_LINK = 13
FUSE_OPEN = 14
FUSE_READ = 15
FUSE_WRITE = 16
FUSE_STATFS = 17
FUSE_RELEASE = 18
_
FUSE_FSYNC = 20
FUSE_SETXATTR = 21
FUSE_GETXATTR = 22
FUSE_LISTXATTR = 23
FUSE_REMOVEXATTR = 24
FUSE_FLUSH = 25
FUSE_INIT = 26
FUSE_OPENDIR = 27
FUSE_READDIR = 28
FUSE_RELEASEDIR = 29
FUSE_FSYNCDIR = 30
FUSE_GETLK = 31
FUSE_SETLK = 32
FUSE_SETLKW = 33
FUSE_ACCESS = 34
FUSE_CREATE = 35
FUSE_INTERRUPT = 36
FUSE_BMAP = 37
FUSE_DESTROY = 38
FUSE_IOCTL = 39
FUSE_POLL = 40
FUSE_NOTIFY_REPLY = 41
FUSE_BATCH_FORGET = 42
FUSE_FALLOCATE = 43
)
const (
// FUSE_MIN_READ_BUFFER is the minimum size the read can be for any FUSE filesystem.
// This is the minimum size Linux supports. See linux.fuse.h.
FUSE_MIN_READ_BUFFER uint32 = 8192
)
// FUSEHeaderIn is the header read by the daemon with each request.
//
// +marshal
// +stateify savable
type FUSEHeaderIn struct {
_ structs.HostLayout
// Len specifies the total length of the data, including this header.
Len uint32
// Opcode specifies the kind of operation of the request.
Opcode FUSEOpcode
// Unique specifies the unique identifier for this request.
Unique FUSEOpID
// NodeID is the ID of the filesystem object being operated on.
NodeID uint64
// UID is the UID of the requesting process.
UID uint32
// GID is the GID of the requesting process.
GID uint32
// PID is the PID of the requesting process.
PID uint32
_ uint32
}
// SizeOfFUSEHeaderIn is the size of the FUSEHeaderIn struct.
var SizeOfFUSEHeaderIn = uint32((*FUSEHeaderIn)(nil).SizeBytes())
// FUSEHeaderOut is the header written by the daemon when it processes
// a request and wants to send a reply (almost all operations require a
// reply; if they do not, this will be explicitly documented).
//
// +marshal
// +stateify savable
type FUSEHeaderOut struct {
_ structs.HostLayout
// Len specifies the total length of the data, including this header.
Len uint32
// Error specifies the error that occurred (0 if none).
Error int32
// Unique specifies the unique identifier of the corresponding request.
Unique FUSEOpID
}
// SizeOfFUSEHeaderOut is the size of the FUSEHeaderOut struct.
var SizeOfFUSEHeaderOut = uint32((*FUSEHeaderOut)(nil).SizeBytes())
// FUSE_INIT flags, consistent with the ones in include/uapi/linux/fuse.h.
// Our target version is 7.23 but we have few implemented in advance.
const (
FUSE_ASYNC_READ = 1 << 0
FUSE_POSIX_LOCKS = 1 << 1
FUSE_FILE_OPS = 1 << 2
FUSE_ATOMIC_O_TRUNC = 1 << 3
FUSE_EXPORT_SUPPORT = 1 << 4
FUSE_BIG_WRITES = 1 << 5
FUSE_DONT_MASK = 1 << 6
FUSE_SPLICE_WRITE = 1 << 7
FUSE_SPLICE_MOVE = 1 << 8
FUSE_SPLICE_READ = 1 << 9
FUSE_FLOCK_LOCKS = 1 << 10
FUSE_HAS_IOCTL_DIR = 1 << 11
FUSE_AUTO_INVAL_DATA = 1 << 12
FUSE_DO_READDIRPLUS = 1 << 13
FUSE_READDIRPLUS_AUTO = 1 << 14
FUSE_ASYNC_DIO = 1 << 15
FUSE_WRITEBACK_CACHE = 1 << 16
FUSE_NO_OPEN_SUPPORT = 1 << 17
FUSE_MAX_PAGES = 1 << 22 // From FUSE 7.28
)
// currently supported FUSE protocol version numbers.
const (
FUSE_KERNEL_VERSION = 7
FUSE_KERNEL_MINOR_VERSION = 31
)
// Constants relevant to FUSE operations.
const (
FUSE_NAME_MAX = 1024
FUSE_PAGE_SIZE = 4096
FUSE_DIRENT_ALIGN = 8
FUSE_FSYNC_FDATASYNC = 1 << 0
)
// FUSEInitIn is the request sent by the kernel to the daemon,
// to negotiate the version and flags.
//
// +marshal
type FUSEInitIn struct {
_ structs.HostLayout
// Major version supported by kernel.
Major uint32
// Minor version supported by the kernel.
Minor uint32
// MaxReadahead is the maximum number of bytes to read-ahead
// decided by the kernel.
MaxReadahead uint32
// Flags of this init request.
Flags uint32
}
// FUSEInitOut is the reply sent by the daemon to the kernel
// for FUSEInitIn. We target FUSE 7.23; this struct supports 7.28.
//
// +marshal
type FUSEInitOut struct {
_ structs.HostLayout
// Major version supported by daemon.
Major uint32
// Minor version supported by daemon.
Minor uint32
// MaxReadahead is the maximum number of bytes to read-ahead.
// Decided by the daemon, after receiving the value from kernel.
MaxReadahead uint32
// Flags of this init reply.
Flags uint32
// MaxBackground is the maximum number of pending background requests
// that the daemon wants.
MaxBackground uint16
// CongestionThreshold is the daemon-decided threshold for
// the number of the pending background requests.
CongestionThreshold uint16
// MaxWrite is the daemon's maximum size of a write buffer.
// Kernel adjusts it to the minimum (fuse/init.go:fuseMinMaxWrite).
// if the value from daemon is too small.
MaxWrite uint32
// TimeGran is the daemon's time granularity for mtime and ctime metadata.
// The unit is nanosecond.
// Value should be power of 10.
// 1 indicates full nanosecond granularity support.
TimeGran uint32
// MaxPages is the daemon's maximum number of pages for one write operation.
// Kernel adjusts it to the maximum (fuse/init.go:FUSE_MAX_MAX_PAGES).
// if the value from daemon is too large.
MaxPages uint16
_ uint16
_ [8]uint32
}
// FUSEStatfsOut is the reply sent by the daemon to the kernel
// for FUSE_STATFS.
// from https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/fuse.h#L252
//
// +marshal
type FUSEStatfsOut struct {
_ structs.HostLayout
// Blocks is the maximum number of data blocks the filesystem may store, in
// units of BlockSize.
Blocks uint64
// BlocksFree is the number of free data blocks, in units of BlockSize.
BlocksFree uint64
// BlocksAvailable is the number of data blocks free for use by
// unprivileged users, in units of BlockSize.
BlocksAvailable uint64
// Files is the number of used file nodes on the filesystem.
Files uint64
// FileFress is the number of free file nodes on the filesystem.
FilesFree uint64
// BlockSize is the optimal transfer block size in bytes.
BlockSize uint32
// NameLength is the maximum file name length.
NameLength uint32
// FragmentSize is equivalent to BlockSize.
FragmentSize uint32
_ uint32
Spare [6]uint32
}
// FUSE_GETATTR_FH is currently the only flag of FUSEGetAttrIn.GetAttrFlags.
// If it is set, the file handle (FUSEGetAttrIn.Fh) is used to indicate the
// object instead of the node id attribute in the request header.
const FUSE_GETATTR_FH = (1 << 0)
// FUSEGetAttrIn is the request sent by the kernel to the daemon,
// to get the attribute of a inode.
//
// +marshal
type FUSEGetAttrIn struct {
_ structs.HostLayout
// GetAttrFlags specifies whether getattr request is sent with a nodeid or
// with a file handle.
GetAttrFlags uint32
_ uint32
// Fh is the file handler when GetAttrFlags has FUSE_GETATTR_FH bit. If
// used, the operation is analogous to fstat(2).
Fh uint64
}
// FUSEAttr is the struct used in the response FUSEGetAttrOut.
//
// +marshal
type FUSEAttr struct {
_ structs.HostLayout
// Ino is the inode number of this file.
Ino uint64
// Size is the size of this file.
Size uint64
// Blocks is the number of the 512B blocks allocated by this file.
Blocks uint64
// Atime is the time of last access.
Atime uint64
// Mtime is the time of last modification.
Mtime uint64
// Ctime is the time of last status change.
Ctime uint64
// AtimeNsec is the nano second part of Atime.
AtimeNsec uint32
// MtimeNsec is the nano second part of Mtime.
MtimeNsec uint32
// CtimeNsec is the nano second part of Ctime.
CtimeNsec uint32
// Mode contains the file type and mode.
Mode uint32
// Nlink is the number of the hard links.
Nlink uint32
// UID is user ID of the owner.
UID uint32
// GID is group ID of the owner.
GID uint32
// Rdev is the device ID if this is a special file.
Rdev uint32
// BlkSize is the block size for filesystem I/O.
BlkSize uint32
_ uint32
}
// ATimeNsec returns the last access time as the total time since the unix epoch
// in nanoseconds.
func (a FUSEAttr) ATimeNsec() int64 {
return int64(a.Atime)*time.Second.Nanoseconds() + int64(a.AtimeNsec)
}
// MTimeNsec returns the last modification time as the total time since the unix
// epoch in nanoseconds.
func (a FUSEAttr) MTimeNsec() int64 {
return int64(a.Mtime)*time.Second.Nanoseconds() + int64(a.MtimeNsec)
}
// CTimeNsec returns the last change time as the total time since the unix epoch
// in nanoseconds.
func (a FUSEAttr) CTimeNsec() int64 {
return int64(a.Ctime)*time.Second.Nanoseconds() + int64(a.CtimeNsec)
}
// FUSEAttrOut is the reply sent by the daemon to the kernel
// for FUSEGetAttrIn and FUSESetAttrIn.
//
// +marshal
type FUSEAttrOut struct {
_ structs.HostLayout
// AttrValid and AttrValidNsec describe the attribute cache duration
AttrValid uint64
// AttrValidNsec is the nanosecond part of the attribute cache duration
AttrValidNsec uint32
_ uint32
// Attr contains the metadata returned from the FUSE server
Attr FUSEAttr
}
// FUSEEntryOut is the reply sent by the daemon to the kernel
// for FUSE_MKNOD, FUSE_MKDIR, FUSE_SYMLINK, FUSE_LINK and
// FUSE_LOOKUP.
//
// +marshal
type FUSEEntryOut struct {
_ structs.HostLayout
// NodeID is the ID for current inode.
NodeID uint64
// Generation is the generation number of inode.
// Used to identify an inode that have different ID at different time.
Generation uint64
// EntryValid indicates timeout for an entry.
EntryValid uint64
// AttrValid indicates timeout for an entry's attributes.
AttrValid uint64
// EntryValidNsec indicates timeout for an entry in nanosecond.
EntryValidNSec uint32
// AttrValidNsec indicates timeout for an entry's attributes in nanosecond.
AttrValidNSec uint32
// Attr contains the attributes of an entry.
Attr FUSEAttr
}
// CString represents a null terminated string which can be marshalled.
//
// +marshal dynamic
type CString string
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (s *CString) MarshalBytes(buf []byte) []byte {
copy(buf, *s)
buf[len(*s)] = 0 // null char
return buf[s.SizeBytes():]
}
// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (s *CString) UnmarshalBytes(buf []byte) []byte {
panic("Unimplemented, CString is never unmarshalled")
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (s *CString) SizeBytes() int {
// 1 extra byte for null-terminated string.
return len(*s) + 1
}
// FUSELookupIn is the request sent by the kernel to the daemon
// to look up a file name.
//
// +marshal dynamic
type FUSELookupIn struct {
_ structs.HostLayout
// Name is a file name to be looked up.
Name CString
}
// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (r *FUSELookupIn) UnmarshalBytes(buf []byte) []byte {
panic("Unimplemented, FUSELookupIn is never unmarshalled")
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (r *FUSELookupIn) MarshalBytes(buf []byte) []byte {
return r.Name.MarshalBytes(buf)
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (r *FUSELookupIn) SizeBytes() int {
return r.Name.SizeBytes()
}
// MAX_NON_LFS indicates the maximum offset without large file support.
const MAX_NON_LFS = ((1 << 31) - 1)
// flags returned by OPEN request.
const (
// FOPEN_DIRECT_IO indicates bypassing page cache for this opened file.
FOPEN_DIRECT_IO = 1 << 0
// FOPEN_KEEP_CACHE avoids invalidating the data cache on open.
FOPEN_KEEP_CACHE = 1 << 1
// FOPEN_NONSEEKABLE indicates the file cannot be seeked.
FOPEN_NONSEEKABLE = 1 << 2
// FOPEN_CACHE_DIR indicated to allow caching this directory
FOPEN_CACHE_DIR = 1 << 3
// FOPEN_STREAM indicates the file is stream-like (no file position at all)
FOPEN_STREAM = 1 << 4
// FOPEN_NOFLUSH indicates the file does not need to be flushed on close.
FOPEN_NOFLUSH = 1 << 5
)
// FUSEOpenIn is the request sent by the kernel to the daemon,
// to negotiate flags and get file handle.
//
// +marshal
type FUSEOpenIn struct {
_ structs.HostLayout
// Flags of this open request.
Flags uint32
_ uint32
}
// FUSEOpenOut is the reply sent by the daemon to the kernel
// for FUSEOpenIn.
//
// +marshal
type FUSEOpenOut struct {
_ structs.HostLayout
// Fh is the file handler for opened files.
Fh uint64
// OpenFlag for the opened files.
OpenFlag uint32
_ uint32
}
// FUSECreateOut is the reply sent by the daemon to the kernel
// for FUSECreateMeta.
//
// +marshal
type FUSECreateOut struct {
_ structs.HostLayout
FUSEEntryOut
FUSEOpenOut
}
// FUSE_READ flags, consistent with the ones in include/uapi/linux/fuse.h.
const (
FUSE_READ_LOCKOWNER = 1 << 1
)
// FUSEReadIn is the request sent by the kernel to the daemon
// for FUSE_READ.
//
// +marshal
type FUSEReadIn struct {
_ structs.HostLayout
// Fh is the file handle in userspace.
Fh uint64
// Offset is the read offset.
Offset uint64
// Size is the number of bytes to read.
Size uint32
// ReadFlags for this FUSE_READ request.
// Currently only contains FUSE_READ_LOCKOWNER.
ReadFlags uint32
// LockOwner is the id of the lock owner if there is one.
LockOwner uint64
// Flags for the underlying file.
Flags uint32
_ uint32
}
// FUSEWriteIn is the first part of the payload of the
// request sent by the kernel to the daemon
// for FUSE_WRITE (struct for FUSE version >= 7.9).
//
// The second part of the payload is the
// binary bytes of the data to be written.
// See FUSEWritePayloadIn that combines header & payload.
//
// +marshal
type FUSEWriteIn struct {
_ structs.HostLayout
// Fh is the file handle in userspace.
Fh uint64
// Offset is the write offset.
Offset uint64
// Size is the number of bytes to write.
Size uint32
// ReadFlags for this FUSE_WRITE request.
WriteFlags uint32
// LockOwner is the id of the lock owner if there is one.
LockOwner uint64
// Flags for the underlying file.
Flags uint32
_ uint32
}
// SizeOfFUSEWriteIn is the size of the FUSEWriteIn struct.
var SizeOfFUSEWriteIn = uint32((*FUSEWriteIn)(nil).SizeBytes())
// FUSEWritePayloadIn combines header - FUSEWriteIn and payload
// in a single marshallable struct when sending request by the
// kernel to the daemon
//
// +marshal dynamic
type FUSEWritePayloadIn struct {
_ structs.HostLayout
Header FUSEWriteIn
Payload primitive.ByteSlice `hostlayout:"ignore"`
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (r *FUSEWritePayloadIn) SizeBytes() int {
if r == nil {
return (*FUSEWriteIn)(nil).SizeBytes()
}
return r.Header.SizeBytes() + r.Payload.SizeBytes()
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (r *FUSEWritePayloadIn) MarshalBytes(dst []byte) []byte {
dst = r.Header.MarshalUnsafe(dst)
dst = r.Payload.MarshalUnsafe(dst)
return dst
}
// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (r *FUSEWritePayloadIn) UnmarshalBytes(src []byte) []byte {
panic("Unimplemented, FUSEWritePayloadIn is never unmarshalled")
}
// FUSEWriteOut is the payload of the reply sent by the daemon to the kernel
// for a FUSE_WRITE request.
//
// +marshal
type FUSEWriteOut struct {
_ structs.HostLayout
// Size is the number of bytes written.
Size uint32
_ uint32
}
// FUSEReleaseIn is the request sent by the kernel to the daemon
// when there is no more reference to a file.
//
// +marshal
type FUSEReleaseIn struct {
_ structs.HostLayout
// Fh is the file handler for the file to be released.
Fh uint64
// Flags of the file.
Flags uint32
// ReleaseFlags of this release request.
ReleaseFlags uint32
// LockOwner is the id of the lock owner if there is one.
LockOwner uint64
}
// FUSECreateMeta contains all the static fields of FUSECreateIn,
// which is used for FUSE_CREATE.
//
// +marshal
type FUSECreateMeta struct {
_ structs.HostLayout
// Flags of the creating file.
Flags uint32
// Mode is the mode of the creating file.
Mode uint32
// Umask is the current file mode creation mask.
Umask uint32
_ uint32
}
// FUSERenameIn sent by the kernel for FUSE_RENAME
//
// +marshal dynamic
type FUSERenameIn struct {
_ structs.HostLayout
Newdir primitive.Uint64
Oldname CString
Newname CString
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (r *FUSERenameIn) MarshalBytes(dst []byte) []byte {
dst = r.Newdir.MarshalBytes(dst)
dst = r.Oldname.MarshalBytes(dst)
return r.Newname.MarshalBytes(dst)
}
// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (r *FUSERenameIn) UnmarshalBytes(buf []byte) []byte {
panic("Unimplemented, FUSERmDirIn is never unmarshalled")
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (r *FUSERenameIn) SizeBytes() int {
return r.Newdir.SizeBytes() + r.Oldname.SizeBytes() + r.Newname.SizeBytes()
}
// FUSECreateIn contains all the arguments sent by the kernel to the daemon, to
// atomically create and open a new regular file.
//
// +marshal dynamic
type FUSECreateIn struct {
_ structs.HostLayout
// CreateMeta contains mode, rdev and umash fields for FUSE_MKNODS.
CreateMeta FUSECreateMeta
// Name is the name of the node to create.
Name CString
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (r *FUSECreateIn) MarshalBytes(buf []byte) []byte {
buf = r.CreateMeta.MarshalBytes(buf)
return r.Name.MarshalBytes(buf)
}
// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (r *FUSECreateIn) UnmarshalBytes(buf []byte) []byte {
panic("Unimplemented, FUSECreateIn is never unmarshalled")
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (r *FUSECreateIn) SizeBytes() int {
return r.CreateMeta.SizeBytes() + r.Name.SizeBytes()
}
// FUSEMknodMeta contains all the static fields of FUSEMknodIn,
// which is used for FUSE_MKNOD.
//
// +marshal
type FUSEMknodMeta struct {
_ structs.HostLayout
// Mode of the inode to create.
Mode uint32
// Rdev encodes device major and minor information.
Rdev uint32
// Umask is the current file mode creation mask.
Umask uint32
_ uint32
}
// FUSEMknodIn contains all the arguments sent by the kernel
// to the daemon, to create a new file node.
//
// +marshal dynamic
type FUSEMknodIn struct {
_ structs.HostLayout
// MknodMeta contains mode, rdev and umash fields for FUSE_MKNODS.
MknodMeta FUSEMknodMeta
// Name is the name of the node to create.
Name CString
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (r *FUSEMknodIn) MarshalBytes(buf []byte) []byte {
buf = r.MknodMeta.MarshalBytes(buf)
return r.Name.MarshalBytes(buf)
}
// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (r *FUSEMknodIn) UnmarshalBytes(buf []byte) []byte {
panic("Unimplemented, FUSEMknodIn is never unmarshalled")
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (r *FUSEMknodIn) SizeBytes() int {
return r.MknodMeta.SizeBytes() + r.Name.SizeBytes()
}
// FUSESymlinkIn is the request sent by the kernel to the daemon,
// to create a symbolic link.
//
// +marshal dynamic
type FUSESymlinkIn struct {
_ structs.HostLayout
// Name of symlink to create.
Name CString
// Target of the symlink.
Target CString
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (r *FUSESymlinkIn) MarshalBytes(buf []byte) []byte {
buf = r.Name.MarshalBytes(buf)
return r.Target.MarshalBytes(buf)
}
// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (r *FUSESymlinkIn) UnmarshalBytes(buf []byte) []byte {
panic("Unimplemented, FUSEMknodIn is never unmarshalled")
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (r *FUSESymlinkIn) SizeBytes() int {
return r.Name.SizeBytes() + r.Target.SizeBytes()
}
// FUSELinkIn is the request sent by the kernel to create a hard link.
//
// +marshal dynamic
type FUSELinkIn struct {
_ structs.HostLayout
// OldNodeID is the ID of the inode that is being linked to.
OldNodeID primitive.Uint64
// Name of the new hard link to create.
Name CString
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (r *FUSELinkIn) MarshalBytes(buf []byte) []byte {
buf = r.OldNodeID.MarshalBytes(buf)
return r.Name.MarshalBytes(buf)
}
// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (r *FUSELinkIn) UnmarshalBytes(buf []byte) []byte {
panic("Unimplemented, FUSELinkIn is never unmarshalled")
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (r *FUSELinkIn) SizeBytes() int {
return r.OldNodeID.SizeBytes() + r.Name.SizeBytes()
}
// FUSEEmptyIn is used by operations without request body.
//
// +marshal dynamic
type FUSEEmptyIn struct {
_ structs.HostLayout
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (r *FUSEEmptyIn) MarshalBytes(buf []byte) []byte {
return buf
}
// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (r *FUSEEmptyIn) UnmarshalBytes(buf []byte) []byte {
panic("Unimplemented, FUSEEmptyIn is never unmarshalled")
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (r *FUSEEmptyIn) SizeBytes() int {
return 0
}
// FUSEMkdirMeta contains all the static fields of FUSEMkdirIn,
// which is used for FUSE_MKDIR.
//
// +marshal
type FUSEMkdirMeta struct {
_ structs.HostLayout
// Mode of the directory of create.
Mode uint32
// Umask is the user file creation mask.
Umask uint32
}
// FUSEMkdirIn contains all the arguments sent by the kernel
// to the daemon, to create a new directory.
//
// +marshal dynamic
type FUSEMkdirIn struct {
_ structs.HostLayout
// MkdirMeta contains Mode and Umask of the directory to create.
MkdirMeta FUSEMkdirMeta
// Name of the directory to create.
Name CString
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (r *FUSEMkdirIn) MarshalBytes(buf []byte) []byte {
buf = r.MkdirMeta.MarshalBytes(buf)
return r.Name.MarshalBytes(buf)
}
// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (r *FUSEMkdirIn) UnmarshalBytes(buf []byte) []byte {
panic("Unimplemented, FUSEMkdirIn is never unmarshalled")
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (r *FUSEMkdirIn) SizeBytes() int {
return r.MkdirMeta.SizeBytes() + r.Name.SizeBytes()
}
// FUSERmDirIn is the request sent by the kernel to the daemon
// when trying to remove a directory.
//
// +marshal dynamic
type FUSERmDirIn struct {
_ structs.HostLayout
// Name is a directory name to be removed.
Name CString
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (r *FUSERmDirIn) MarshalBytes(buf []byte) []byte {
return r.Name.MarshalBytes(buf)
}
// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (r *FUSERmDirIn) UnmarshalBytes(buf []byte) []byte {
panic("Unimplemented, FUSERmDirIn is never unmarshalled")
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (r *FUSERmDirIn) SizeBytes() int {
return r.Name.SizeBytes()
}
// FUSEGetXattrHdr contains the static fields of FUSEGetXattrIn.
//
// +marshal
type FUSEGetXattrHdr struct {
_ structs.HostLayout
Size uint32
_ uint32
}
// FUSEGetXattrIn contains the arguments for FUSE_GETXATTR.
//
// +marshal dynamic
type FUSEGetXattrIn struct {
_ structs.HostLayout
Hdr FUSEGetXattrHdr
Name CString
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (r *FUSEGetXattrIn) MarshalBytes(buf []byte) []byte {
buf = r.Hdr.MarshalBytes(buf)
return r.Name.MarshalBytes(buf)
}
// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (r *FUSEGetXattrIn) UnmarshalBytes(buf []byte) []byte {
panic("Unimplemented, FUSEGetXattrIn is never unmarshalled")
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (r *FUSEGetXattrIn) SizeBytes() int {
return r.Hdr.SizeBytes() + r.Name.SizeBytes()
}
// FUSEGetXattrOut is the reply sent by the daemon to the kernel
// for FUSE_GETXATTR and FUSE_LISTXATTR when the input size was 0.
//
// +marshal
type FUSEGetXattrOut struct {
_ structs.HostLayout
Size uint32
_ uint32
}
// FUSESetXattrHdr contains the static fields of FUSESetXattrIn.
//
// +marshal
type FUSESetXattrHdr struct {
_ structs.HostLayout
Size uint32
Flags uint32
}
// FUSESetXattrIn contains the arguments for FUSE_SETXATTR.
//
// +marshal dynamic
type FUSESetXattrIn struct {
_ structs.HostLayout
Hdr FUSESetXattrHdr
Name CString
Value []byte `hostlayout:"ignore"`
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (r *FUSESetXattrIn) MarshalBytes(buf []byte) []byte {
buf = r.Hdr.MarshalBytes(buf)
buf = r.Name.MarshalBytes(buf)
copy(buf, r.Value)
return buf[len(r.Value):]
}
// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (r *FUSESetXattrIn) UnmarshalBytes(buf []byte) []byte {
panic("Unimplemented, FUSESetXattrIn is never unmarshalled")
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (r *FUSESetXattrIn) SizeBytes() int {
return r.Hdr.SizeBytes() + r.Name.SizeBytes() + len(r.Value)
}
// FUSEDirents is a list of Dirents received from the FUSE daemon server.
// It is used for FUSE_READDIR.
//
// +marshal dynamic
type FUSEDirents struct {
_ structs.HostLayout
Dirents []*FUSEDirent `hostlayout:"ignore"`
}
// FUSEDirent is a Dirent received from the FUSE daemon server.
// It is used for FUSE_READDIR.
//
// +marshal dynamic
type FUSEDirent struct {
_ structs.HostLayout
// Meta contains all the static fields of FUSEDirent.
Meta FUSEDirentMeta
// Name is the filename of the dirent.
Name string `hostlayout:"ignore"`
}
// FUSEDirentMeta contains all the static fields of FUSEDirent.
// It is used for FUSE_READDIR.
//
// +marshal
type FUSEDirentMeta struct {
_ structs.HostLayout
// Inode of the dirent.
Ino uint64
// Offset of the dirent.
Off uint64
// NameLen is the length of the dirent name.
NameLen uint32
// Type of the dirent.
Type uint32
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (r *FUSEDirents) SizeBytes() int {
var sizeBytes int
for _, dirent := range r.Dirents {
sizeBytes += dirent.SizeBytes()
}
return sizeBytes
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (r *FUSEDirents) MarshalBytes(buf []byte) []byte {
panic("Unimplemented, FUSEDirents is never marshalled")
}
// UnmarshalBytes deserializes FUSEDirents from the src buffer.
func (r *FUSEDirents) UnmarshalBytes(src []byte) []byte {
for len(src) >= (*FUSEDirentMeta)(nil).SizeBytes() {
var dirent FUSEDirent
rem := dirent.UnmarshalBytes(src)
if len(rem) == len(src) || len(dirent.Name) == 0 {
break
}
if r.Dirents == nil {
r.Dirents = make([]*FUSEDirent, 0)
}
r.Dirents = append(r.Dirents, &dirent)
src = rem
}
return src
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (r *FUSEDirent) SizeBytes() int {
dataSize := r.Meta.SizeBytes() + len(r.Name)
// Each Dirent must be padded such that its size is a multiple
// of FUSE_DIRENT_ALIGN. Similar to the fuse dirent alignment
// in linux/fuse.h.
return (dataSize + (FUSE_DIRENT_ALIGN - 1)) & ^(FUSE_DIRENT_ALIGN - 1)
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (r *FUSEDirent) MarshalBytes(buf []byte) []byte {
panic("Unimplemented, FUSEDirent is never marshalled")
}
// shiftNextDirent advances buf to the start of the next dirent, per
// FUSE ABI. buf should begin at the start of a dirent.
func (r *FUSEDirent) shiftNextDirent(buf []byte) []byte {
nextOff := r.SizeBytes()
if nextOff > len(buf) { // Handle overflow.
return buf[len(buf):]
}
return buf[nextOff:]
}
// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (r *FUSEDirent) UnmarshalBytes(src []byte) []byte {
if len(src) < (*FUSEDirentMeta)(nil).SizeBytes() {
return src
}
srcP := r.Meta.UnmarshalBytes(src)
// Calculate the 8-byte aligned size of this directory entry record.
recLen := (r.Meta.SizeBytes() + int(r.Meta.NameLen) + (FUSE_DIRENT_ALIGN - 1)) & ^(FUSE_DIRENT_ALIGN - 1)
// If the name is invalid or if the record straddles the end of the source
// buffer (making it incomplete), return the buffer unconsumed. This leaves
// the offset at the start of this entry so it can be re-fetched whole.
if r.Meta.NameLen == 0 || r.Meta.NameLen > FUSE_NAME_MAX || recLen > len(src) {
return src
}
buf := make([]byte, r.Meta.NameLen)
name := primitive.ByteSlice(buf)
name.UnmarshalBytes(srcP[:r.Meta.NameLen])
r.Name = string(name)
return r.shiftNextDirent(src)
}
// FATTR_* consts are the attribute flags defined in include/uapi/linux/fuse.h.
// These should be or-ed together for setattr to know what has been changed.
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)
)
// FUSESetAttrIn is the request sent by the kernel to the daemon,
// to set the attribute(s) of a file.
//
// +marshal
type FUSESetAttrIn struct {
_ structs.HostLayout
// Valid indicates which attributes are modified by this request.
Valid uint32
_ uint32
// Fh is used to identify the file if FATTR_FH is set in Valid.
Fh uint64
// Size is the size that the request wants to change to.
Size uint64
// LockOwner is the owner of the lock that the request wants to change to.
LockOwner uint64
// Atime is the access time that the request wants to change to.
Atime uint64
// Mtime is the modification time that the request wants to change to.
Mtime uint64
// Ctime is the status change time that the request wants to change to.
Ctime uint64
// AtimeNsec is the nano second part of Atime.
AtimeNsec uint32
// MtimeNsec is the nano second part of Mtime.
MtimeNsec uint32
// CtimeNsec is the nano second part of Ctime.
CtimeNsec uint32
// Mode is the file mode that the request wants to change to.
Mode uint32
_ uint32
// UID is the user ID of the owner that the request wants to change to.
UID uint32
// GID is the group ID of the owner that the request wants to change to.
GID uint32
_ uint32
}
// FUSEUnlinkIn is the request sent by the kernel to the daemon
// when trying to unlink a node.
//
// +marshal dynamic
type FUSEUnlinkIn struct {
_ structs.HostLayout
// Name of the node to unlink.
Name CString
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (r *FUSEUnlinkIn) MarshalBytes(buf []byte) []byte {
return r.Name.MarshalBytes(buf)
}
// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (r *FUSEUnlinkIn) UnmarshalBytes(buf []byte) []byte {
panic("Unimplemented, FUSEUnlinkIn is never unmarshalled")
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (r *FUSEUnlinkIn) SizeBytes() int {
return r.Name.SizeBytes()
}
// FUSEFsyncIn is the request sent by the kernel to the daemon
// when trying to fsync a file.
//
// +marshal
type FUSEFsyncIn struct {
_ structs.HostLayout
Fh uint64
FsyncFlags uint32
// padding
_ uint32
}
// FUSEAccessIn is the request sent by the kernel to the daemon when checking
// permissions on a file.
//
// +marshal
type FUSEAccessIn struct {
_ structs.HostLayout
Mask uint32
// padding
_ uint32
}
// FUSEFallocateIn is the request sent by the kernel to the daemon to perform
// a fallocate operation.
//
// +marshal
type FUSEFallocateIn struct {
_ structs.HostLayout
Fh uint64
Offset uint64
Length uint64
Mode uint32
// padding
_ uint32
}
// FUSEFlushIn is the request sent by the kernel to the daemon after a file is
// closed.
//
// +marshal
type FUSEFlushIn struct {
_ structs.HostLayout
Fh uint64
_ uint32 // unused
_ uint32 // padding
LockOwner uint64
}