Files
Ayush Ranjan 84670a4fc6 gofer: Fix bug when casting auth.K{U/G}ID to int.
auth.K{U/G}ID has type uint32. When uid = auth.NoID = math.MaxUint32, which is
intended to represent -1, and it is casted to int, it becomes 4294967295 on
64-bit systems as int is 8 bytes in size. So the == -1 check fails.

Fixed the bug by explicitly setting syscall args to -1 when uid.Ok() == false.
Similarly, fix the bug in runsc/fsgofer.

PiperOrigin-RevId: 728258705
2025-02-18 10:16:08 -08:00

1874 lines
54 KiB
Go

// Copyright 2021 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package lisafs
import (
"fmt"
"math"
"os"
"strings"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/marshal/primitive"
)
// Messages have two parts:
// * A transport header used to decipher received messages.
// * A byte array referred to as "payload" which contains the actual message.
// "dataLen" refers to the size of both combined.
//
// All messages must implement the following functions:
// * marshal.Marshallable.SizeBytes
// * marshal.Marshallable.Marshal{Unsafe/Bytes}
// * marshal.CheckedMarshallable.CheckedUnmarshal
// * fmt.Stringer.String
//
// There is no explicit interface definition for this because that definition
// will not be used anywhere. If a concrete type is passed into a function
// which receives it as an interface, the struct is moved to the heap. This
// erodes memory performance. Message structs are be short lived - they are
// initialized, marshalled into a buffer and not used after that. So heap
// allocating these message structs is wasteful. Don't define Message interface
// so it's not used. Instead use function arguments. See Client.SndRcvMessage.
//
// Unmarshalling code should use the Checked variant of the Unmarshal functions
// because a malicious encoder could have manipulated payload bytes to make the
// unchecked unmarshal variants panic due to the lack of bound checking.
// Marshalling code does not need additional bound checking because the caller
// itself initializes the struct being marshalled, so it is trusted.
//
// String() implementations must ensure that the message struct doesn't escape.
// For instance, directly passing the struct to fmt.Sprintf() escapes it
// because of the implicit conversion to any.
type marshalFunc func([]byte) []byte
type unmarshalFunc func([]byte) ([]byte, bool)
type debugStringer func() string
// MID (message ID) is used to identify messages to parse from payload.
//
// +marshal slice:MIDSlice
type MID uint16
// These constants are used to identify their corresponding message types.
const (
// Error is only used in responses to pass errors to client.
Error MID = 0
// Mount is used to establish connection between the client and server mount
// point. lisafs requires that the client makes a successful Mount RPC before
// making other RPCs.
Mount MID = 1
// Channel requests to start a new communicational channel.
Channel MID = 2
// FStat requests the stat(2) results for a specified file.
FStat MID = 3
// SetStat requests to change file attributes. Note that there is no one
// corresponding Linux syscall. This is a conglomeration of fchmod(2),
// fchown(2), ftruncate(2) and futimesat(2).
SetStat MID = 4
// Walk requests to walk the specified path starting from the specified
// directory. Server-side path traversal is terminated preemptively on
// symlinks entries because they can cause non-linear traversal.
Walk MID = 5
// WalkStat is the same as Walk, except the following differences:
// * If the first path component is "", then it also returns stat results
// for the directory where the walk starts.
// * Does not return Inode, just the Stat results for each path component.
WalkStat MID = 6
// OpenAt is analogous to openat(2). It does not perform any walk. It merely
// duplicates the control FD with the open flags passed.
OpenAt MID = 7
// OpenCreateAt is analogous to openat(2) with O_CREAT|O_EXCL added to flags.
// It also returns the newly created file inode.
OpenCreateAt MID = 8
// Close is analogous to close(2) but can work on multiple FDs.
Close MID = 9
// FSync is analogous to fsync(2) but can work on multiple FDs.
FSync MID = 10
// PWrite is analogous to pwrite(2).
PWrite MID = 11
// PRead is analogous to pread(2).
PRead MID = 12
// MkdirAt is analogous to mkdirat(2).
MkdirAt MID = 13
// MknodAt is analogous to mknodat(2).
MknodAt MID = 14
// SymlinkAt is analogous to symlinkat(2).
SymlinkAt MID = 15
// LinkAt is analogous to linkat(2).
LinkAt MID = 16
// FStatFS is analogous to fstatfs(2).
FStatFS MID = 17
// FAllocate is analogous to fallocate(2).
FAllocate MID = 18
// ReadLinkAt is analogous to readlinkat(2).
ReadLinkAt MID = 19
// Flush cleans up the file state. Its behavior is implementation
// dependent and might not even be supported in server implementations.
Flush MID = 20
// Connect is loosely analogous to connect(2).
Connect MID = 21
// UnlinkAt is analogous to unlinkat(2).
UnlinkAt MID = 22
// RenameAt is loosely analogous to renameat(2).
RenameAt MID = 23
// Getdents64 is analogous to getdents64(2).
Getdents64 MID = 24
// FGetXattr is analogous to fgetxattr(2).
FGetXattr MID = 25
// FSetXattr is analogous to fsetxattr(2).
FSetXattr MID = 26
// FListXattr is analogous to flistxattr(2).
FListXattr MID = 27
// FRemoveXattr is analogous to fremovexattr(2).
FRemoveXattr MID = 28
// BindAt is analogous to bind(2).
BindAt MID = 29
// Listen is analogous to listen(2).
Listen MID = 30
// Accept is analogous to accept4(2).
Accept MID = 31
// ConnectWithCreds is analogous to connect(2) but it asks the server
// to connect with the provided effective uid/gid.
ConnectWithCreds MID = 32
)
const (
// NoUID is a sentinel used to indicate no valid UID. See auth.NoID.
NoUID UID = math.MaxUint32
// NoGID is a sentinel used to indicate no valid GID. See auth.NoID.
NoGID GID = math.MaxUint32
)
// MaxMessageSize is the recommended max message size that can be used by
// connections. Server implementations may choose to use other values.
func MaxMessageSize() uint32 {
// Return HugePageSize - PageSize so that when flipcall packet window is
// created with MaxMessageSize() + flipcall header size + channel header
// size, HugePageSize is allocated and can be backed by a single huge page
// if supported by the underlying memfd.
return uint32(hostarch.HugePageSize - os.Getpagesize())
}
// UID represents a user ID.
//
// +marshal
type UID uint32
// Ok returns true if uid is not NoUID.
func (uid UID) Ok() bool {
return uid != NoUID
}
// GID represents a group ID.
//
// +marshal
type GID uint32
// Ok returns true if gid is not NoGID.
func (gid GID) Ok() bool {
return gid != NoGID
}
// EmptyMessage is an empty message.
type EmptyMessage struct{}
// String implements fmt.Stringer.String.
func (*EmptyMessage) String() string {
return "EmptyMessage{}"
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (*EmptyMessage) SizeBytes() int {
return 0
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (*EmptyMessage) MarshalBytes(dst []byte) []byte { return dst }
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (*EmptyMessage) CheckedUnmarshal(src []byte) ([]byte, bool) { return src, true }
// SizedString represents a string in memory. The marshalled string bytes are
// preceded by a uint16 signifying the string length.
type SizedString string
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (s *SizedString) SizeBytes() int {
return (*primitive.Uint16)(nil).SizeBytes() + len(*s)
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (s *SizedString) MarshalBytes(dst []byte) []byte {
strLen := primitive.Uint16(len(*s))
dst = strLen.MarshalUnsafe(dst)
// Copy without any allocation.
return dst[copy(dst[:strLen], *s):]
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (s *SizedString) CheckedUnmarshal(src []byte) ([]byte, bool) {
var strLen primitive.Uint16
srcRemain, ok := strLen.CheckedUnmarshal(src)
if !ok || len(srcRemain) < int(strLen) {
return src, false
}
// Take the hit, this leads to an allocation + memcpy. No way around it.
*s = SizedString(srcRemain[:strLen])
return srcRemain[strLen:], true
}
// StringArray represents an array of SizedStrings in memory. The marshalled
// array data is preceded by a uint16 signifying the array length.
type StringArray []string
// String implements fmt.Stringer.String. This ensures that the string slice is
// not escaped so that callers that use a statically sized string array do not
// incur an unnecessary allocation.
func (s *StringArray) String() string {
var b strings.Builder
b.WriteString("[")
b.WriteString(strings.Join(*s, ", "))
b.WriteString("]")
return b.String()
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (s *StringArray) SizeBytes() int {
size := (*primitive.Uint16)(nil).SizeBytes()
for _, str := range *s {
sstr := SizedString(str)
size += sstr.SizeBytes()
}
return size
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (s *StringArray) MarshalBytes(dst []byte) []byte {
arrLen := primitive.Uint16(len(*s))
dst = arrLen.MarshalUnsafe(dst)
for _, str := range *s {
sstr := SizedString(str)
dst = sstr.MarshalBytes(dst)
}
return dst
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (s *StringArray) CheckedUnmarshal(src []byte) ([]byte, bool) {
var arrLen primitive.Uint16
srcRemain, ok := arrLen.CheckedUnmarshal(src)
if !ok {
return src, false
}
if cap(*s) < int(arrLen) {
*s = make([]string, arrLen)
} else {
*s = (*s)[:arrLen]
}
for i := primitive.Uint16(0); i < arrLen; i++ {
var sstr SizedString
srcRemain, ok = sstr.CheckedUnmarshal(srcRemain)
if !ok {
return src, false
}
(*s)[i] = string(sstr)
}
return srcRemain, true
}
// Inode represents an inode on the remote filesystem.
//
// +marshal slice:InodeSlice
type Inode struct {
ControlFD FDID
Stat linux.Statx
}
func (i *Inode) String() string {
return fmt.Sprintf("Inode{ControlFD: %d, Stat: %s}", i.ControlFD, i.Stat.String())
}
// MountReq is an empty request to Mount on the connection.
type MountReq struct{ EmptyMessage }
// String implements fmt.Stringer.String.
func (*MountReq) String() string {
return "MountReq{}"
}
// MountResp represents a Mount response.
type MountResp struct {
Root Inode
// MaxMessageSize is the maximum size of messages communicated between the
// client and server in bytes. This includes the communication header.
MaxMessageSize primitive.Uint32
// SupportedMs holds all the supported messages.
SupportedMs []MID
}
// String implements fmt.Stringer.String.
func (m *MountResp) String() string {
return fmt.Sprintf("MountResp{Root: %s, MaxMessageSize: %d, SupportedMs: %+v}", m.Root.String(), m.MaxMessageSize, m.SupportedMs)
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (m *MountResp) SizeBytes() int {
return m.Root.SizeBytes() +
m.MaxMessageSize.SizeBytes() +
(*primitive.Uint16)(nil).SizeBytes() +
(len(m.SupportedMs) * (*MID)(nil).SizeBytes())
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (m *MountResp) MarshalBytes(dst []byte) []byte {
dst = m.Root.MarshalUnsafe(dst)
dst = m.MaxMessageSize.MarshalUnsafe(dst)
numSupported := primitive.Uint16(len(m.SupportedMs))
dst = numSupported.MarshalBytes(dst)
return MarshalUnsafeMIDSlice(m.SupportedMs, dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (m *MountResp) CheckedUnmarshal(src []byte) ([]byte, bool) {
m.SupportedMs = m.SupportedMs[:0]
if m.SizeBytes() > len(src) {
return src, false
}
srcRemain := m.Root.UnmarshalUnsafe(src)
srcRemain = m.MaxMessageSize.UnmarshalUnsafe(srcRemain)
var numSupported primitive.Uint16
srcRemain = numSupported.UnmarshalBytes(srcRemain)
if int(numSupported)*(*MID)(nil).SizeBytes() > len(srcRemain) {
return src, false
}
if cap(m.SupportedMs) < int(numSupported) {
m.SupportedMs = make([]MID, numSupported)
} else {
m.SupportedMs = m.SupportedMs[:numSupported]
}
return UnmarshalUnsafeMIDSlice(m.SupportedMs, srcRemain), true
}
// ChannelReq is an empty requent to create a Channel.
type ChannelReq struct{ EmptyMessage }
// String implements fmt.Stringer.String.
func (*ChannelReq) String() string {
return "ChannelReq{}"
}
// ChannelResp is the response to the create channel request.
//
// +marshal boundCheck
type ChannelResp struct {
dataOffset int64
dataLength uint64
}
// String implements fmt.Stringer.String.
func (c *ChannelResp) String() string {
return fmt.Sprintf("ChannelResp{dataOffset: %d, dataLength: %d}", c.dataOffset, c.dataLength)
}
// ErrorResp is returned to represent an error while handling a request.
//
// +marshal
type ErrorResp struct {
errno uint32
}
// String implements fmt.Stringer.String.
func (e *ErrorResp) String() string {
return fmt.Sprintf("ErrorResp{errno: %d}", e.errno)
}
// StatReq requests the stat results for the specified FD.
//
// +marshal boundCheck
type StatReq struct {
FD FDID
}
// String implements fmt.Stringer.String.
func (s *StatReq) String() string {
return fmt.Sprintf("StatReq{FD: %d}", s.FD)
}
// SetStatReq is used to set attributeds on FDs.
//
// +marshal boundCheck
type SetStatReq struct {
FD FDID
Mask uint32
Mode uint32 // Only permissions part is settable.
UID UID
GID GID
Size uint64
Atime linux.Timespec
Mtime linux.Timespec
}
// String implements fmt.Stringer.String.
func (s *SetStatReq) String() string {
return fmt.Sprintf("SetStatReq{FD: %d, Mask: %#x, Mode: %d, UID: %d, GID: %d, Size: %d, Atime: %s, Mtime: %s}",
s.FD, s.Mask, s.Mode, s.UID, s.GID, s.Size, s.Atime.ToTime(), s.Mtime.ToTime())
}
// SetStatResp is used to communicate SetStat results. It contains a mask
// representing the failed changes. It also contains the errno of the failed
// set attribute operation. If multiple operations failed then any of those
// errnos can be returned.
//
// +marshal boundCheck
type SetStatResp struct {
FailureMask uint32
FailureErrNo uint32
}
// String implements fmt.Stringer.String.
func (s *SetStatResp) String() string {
return fmt.Sprintf("SetStatResp{FailureMask: %#x, FailureErrNo: %d}", s.FailureMask, s.FailureErrNo)
}
// WalkReq is used to request to walk multiple path components at once. This
// is used for both Walk and WalkStat.
type WalkReq struct {
DirFD FDID
Path StringArray
}
// String implements fmt.Stringer.String.
func (w *WalkReq) String() string {
return fmt.Sprintf("WalkReq{DirFD: %d, Path: %s}", w.DirFD, w.Path.String())
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (w *WalkReq) SizeBytes() int {
return w.DirFD.SizeBytes() + w.Path.SizeBytes()
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (w *WalkReq) MarshalBytes(dst []byte) []byte {
dst = w.DirFD.MarshalUnsafe(dst)
return w.Path.MarshalBytes(dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (w *WalkReq) CheckedUnmarshal(src []byte) ([]byte, bool) {
w.Path = w.Path[:0]
if w.SizeBytes() > len(src) {
return src, false
}
srcRemain := w.DirFD.UnmarshalUnsafe(src)
if srcRemain, ok := w.Path.CheckedUnmarshal(srcRemain); ok {
return srcRemain, true
}
return src, false
}
// WalkStatus is used to indicate the reason for partial/unsuccessful server
// side Walk operations. Please note that partial/unsuccessful walk operations
// do not necessarily fail the RPC. The RPC is successful with a failure hint
// which can be used by the client to infer server-side state.
type WalkStatus = primitive.Uint8
const (
// WalkSuccess indicates that all path components were successfully walked.
WalkSuccess WalkStatus = iota
// WalkComponentDoesNotExist indicates that the walk was prematurely
// terminated because an intermediate path component does not exist on
// server. The results of all previous existing path components is returned.
WalkComponentDoesNotExist
// WalkComponentSymlink indicates that the walk was prematurely
// terminated because an intermediate path component was a symlink. It is not
// safe to resolve symlinks remotely (unaware of mount points).
WalkComponentSymlink
)
func walkStatusToString(ws WalkStatus) string {
switch ws {
case WalkSuccess:
return "Success"
case WalkComponentDoesNotExist:
return "ComponentDoesNotExist"
case WalkComponentSymlink:
return "ComponentSymlink"
default:
panic(fmt.Sprintf("Unknown WalkStatus: %d", ws))
}
}
// WalkResp is used to communicate the inodes walked by the server. In memory,
// the inode array is preceded by a uint16 integer denoting array length.
type WalkResp struct {
Status WalkStatus
Inodes []Inode
}
// String implements fmt.Stringer.String. This ensures that the Inode slice is
// not escaped so that callers that use a statically sized Inode array do not
// incur an unnecessary allocation.
func (w *WalkResp) String() string {
var arrB strings.Builder
arrB.WriteString("[")
for i := range w.Inodes {
if i > 0 {
arrB.WriteString(", ")
}
arrB.WriteString(w.Inodes[i].String())
}
arrB.WriteString("]")
return fmt.Sprintf("WalkResp{Status: %s, Inodes: %s}", walkStatusToString(w.Status), arrB.String())
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (w *WalkResp) SizeBytes() int {
return w.Status.SizeBytes() +
(*primitive.Uint16)(nil).SizeBytes() + (len(w.Inodes) * (*Inode)(nil).SizeBytes())
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (w *WalkResp) MarshalBytes(dst []byte) []byte {
dst = w.Status.MarshalUnsafe(dst)
numInodes := primitive.Uint16(len(w.Inodes))
dst = numInodes.MarshalUnsafe(dst)
return MarshalUnsafeInodeSlice(w.Inodes, dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (w *WalkResp) CheckedUnmarshal(src []byte) ([]byte, bool) {
w.Inodes = w.Inodes[:0]
if w.SizeBytes() > len(src) {
return src, false
}
srcRemain := w.Status.UnmarshalUnsafe(src)
var numInodes primitive.Uint16
srcRemain = numInodes.UnmarshalUnsafe(srcRemain)
if int(numInodes)*(*Inode)(nil).SizeBytes() > len(srcRemain) {
return src, false
}
if cap(w.Inodes) < int(numInodes) {
w.Inodes = make([]Inode, numInodes)
} else {
w.Inodes = w.Inodes[:numInodes]
}
return UnmarshalUnsafeInodeSlice(w.Inodes, srcRemain), true
}
// WalkStatResp is used to communicate stat results for WalkStat. In memory,
// the array data is preceded by a uint16 denoting the array length.
type WalkStatResp struct {
Stats []linux.Statx
}
// String implements fmt.Stringer.String.
func (w *WalkStatResp) String() string {
var arrB strings.Builder
arrB.WriteString("[")
for i := range w.Stats {
if i > 0 {
arrB.WriteString(", ")
}
arrB.WriteString(w.Stats[i].String())
}
arrB.WriteString("]")
return fmt.Sprintf("WalkStatResp{Stats: %s}", arrB.String())
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (w *WalkStatResp) SizeBytes() int {
return (*primitive.Uint16)(nil).SizeBytes() + (len(w.Stats) * linux.SizeOfStatx)
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (w *WalkStatResp) MarshalBytes(dst []byte) []byte {
numStats := primitive.Uint16(len(w.Stats))
dst = numStats.MarshalUnsafe(dst)
return linux.MarshalUnsafeStatxSlice(w.Stats, dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (w *WalkStatResp) CheckedUnmarshal(src []byte) ([]byte, bool) {
w.Stats = w.Stats[:0]
if w.SizeBytes() > len(src) {
return src, false
}
var numStats primitive.Uint16
srcRemain := numStats.UnmarshalUnsafe(src)
if int(numStats)*linux.SizeOfStatx > len(srcRemain) {
return src, false
}
if cap(w.Stats) < int(numStats) {
w.Stats = make([]linux.Statx, numStats)
} else {
w.Stats = w.Stats[:numStats]
}
return linux.UnmarshalUnsafeStatxSlice(w.Stats, srcRemain), true
}
// OpenAtReq is used to open existing FDs with the specified flags.
//
// +marshal boundCheck
type OpenAtReq struct {
FD FDID
Flags uint32
_ uint32 // Need to make struct packed.
}
// String implements fmt.Stringer.String.
func (o *OpenAtReq) String() string {
return fmt.Sprintf("OpenAtReq{FD: %d, Flags: %#o}", o.FD, o.Flags)
}
// OpenAtResp is used to communicate the newly created FD.
//
// +marshal boundCheck
type OpenAtResp struct {
OpenFD FDID
}
// String implements fmt.Stringer.String.
func (o *OpenAtResp) String() string {
return fmt.Sprintf("OpenAtResp{OpenFD: %d}", o.OpenFD)
}
// +marshal
type createCommon struct {
DirFD FDID
UID UID
GID GID
Mode linux.FileMode
// The following are needed to make the struct packed.
_ uint16
_ uint32
}
// OpenCreateAtReq is used to make OpenCreateAt requests.
type OpenCreateAtReq struct {
createCommon
Flags primitive.Uint32
Name SizedString
}
// String implements fmt.Stringer.String.
func (o *OpenCreateAtReq) String() string {
return fmt.Sprintf("OpenCreateAtReq{DirFD: %d, Mode: %s, UID: %d, GID: %d, Flags: %#o, Name: %s}", o.DirFD, o.Mode, o.UID, o.GID, o.Flags, o.Name)
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (o *OpenCreateAtReq) SizeBytes() int {
return o.createCommon.SizeBytes() + o.Flags.SizeBytes() + o.Name.SizeBytes()
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (o *OpenCreateAtReq) MarshalBytes(dst []byte) []byte {
dst = o.createCommon.MarshalUnsafe(dst)
dst = o.Flags.MarshalUnsafe(dst)
return o.Name.MarshalBytes(dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (o *OpenCreateAtReq) CheckedUnmarshal(src []byte) ([]byte, bool) {
o.Name = ""
if o.SizeBytes() > len(src) {
return src, false
}
srcRemain := o.createCommon.UnmarshalUnsafe(src)
srcRemain = o.Flags.UnmarshalUnsafe(srcRemain)
if srcRemain, ok := o.Name.CheckedUnmarshal(srcRemain); ok {
return srcRemain, true
}
return src, false
}
// OpenCreateAtResp is used to communicate successful OpenCreateAt results.
//
// +marshal boundCheck
type OpenCreateAtResp struct {
Child Inode
NewFD FDID
}
// String implements fmt.Stringer.String.
func (o *OpenCreateAtResp) String() string {
return fmt.Sprintf("OpenCreateAtResp{Child: %s, NewFD: %d}", o.Child.String(), o.NewFD)
}
// FdArray is a utility struct which implements a marshallable type for
// communicating an array of FDIDs. In memory, the array data is preceded by a
// uint16 denoting the array length.
type FdArray []FDID
// String implements fmt.Stringer.String. This ensures that the FDID slice is
// not escaped so that callers that use a statically sized FDID array do not
// incur an unnecessary allocation.
func (f *FdArray) String() string {
var b strings.Builder
b.WriteString("[")
for i, fd := range *f {
if i > 0 {
b.WriteString(", ")
}
b.WriteString(fmt.Sprintf("%d", fd))
}
b.WriteString("]")
return b.String()
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (f *FdArray) SizeBytes() int {
return (*primitive.Uint16)(nil).SizeBytes() + (len(*f) * (*FDID)(nil).SizeBytes())
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (f *FdArray) MarshalBytes(dst []byte) []byte {
arrLen := primitive.Uint16(len(*f))
dst = arrLen.MarshalUnsafe(dst)
return MarshalUnsafeFDIDSlice(*f, dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (f *FdArray) CheckedUnmarshal(src []byte) ([]byte, bool) {
*f = (*f)[:0]
if f.SizeBytes() > len(src) {
return src, false
}
var arrLen primitive.Uint16
srcRemain := arrLen.UnmarshalUnsafe(src)
if int(arrLen)*(*FDID)(nil).SizeBytes() > len(srcRemain) {
return src, false
}
if cap(*f) < int(arrLen) {
*f = make(FdArray, arrLen)
} else {
*f = (*f)[:arrLen]
}
return UnmarshalUnsafeFDIDSlice(*f, srcRemain), true
}
// CloseReq is used to close(2) FDs.
type CloseReq struct {
FDs FdArray
}
// String implements fmt.Stringer.String.
func (c *CloseReq) String() string {
return fmt.Sprintf("CloseReq{FDs: %s}", c.FDs.String())
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (c *CloseReq) SizeBytes() int {
return c.FDs.SizeBytes()
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (c *CloseReq) MarshalBytes(dst []byte) []byte {
return c.FDs.MarshalBytes(dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (c *CloseReq) CheckedUnmarshal(src []byte) ([]byte, bool) {
return c.FDs.CheckedUnmarshal(src)
}
// CloseResp is an empty response to CloseReq.
type CloseResp struct{ EmptyMessage }
// String implements fmt.Stringer.String.
func (*CloseResp) String() string {
return "CloseResp{}"
}
// FsyncReq is used to fsync(2) FDs.
type FsyncReq struct {
FDs FdArray
}
// String implements fmt.Stringer.String.
func (f *FsyncReq) String() string {
return fmt.Sprintf("FsyncReq{FDs: %s}", f.FDs.String())
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (f *FsyncReq) SizeBytes() int {
return f.FDs.SizeBytes()
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (f *FsyncReq) MarshalBytes(dst []byte) []byte {
return f.FDs.MarshalBytes(dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (f *FsyncReq) CheckedUnmarshal(src []byte) ([]byte, bool) {
return f.FDs.CheckedUnmarshal(src)
}
// FsyncResp is an empty response to FsyncReq.
type FsyncResp struct{ EmptyMessage }
// String implements fmt.Stringer.String.
func (*FsyncResp) String() string {
return "FsyncResp{}"
}
// PReadReq is used to pread(2) on an FD.
//
// +marshal boundCheck
type PReadReq struct {
Offset uint64
FD FDID
Count uint32
_ uint32 // Need to make struct packed.
}
// String implements fmt.Stringer.String.
func (r *PReadReq) String() string {
return fmt.Sprintf("PReadReq{Offset: %d, FD: %d, Count: %d}", r.Offset, r.FD, r.Count)
}
// PReadResp is used to return the result of pread(2).
type PReadResp struct {
NumBytes primitive.Uint64
Buf []byte
}
// String implements fmt.Stringer.String.
func (r *PReadResp) String() string {
return fmt.Sprintf("PReadResp{NumBytes: %d, Buf: [...%d bytes...]}", r.NumBytes, len(r.Buf))
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (r *PReadResp) SizeBytes() int {
return r.NumBytes.SizeBytes() + int(r.NumBytes)
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (r *PReadResp) MarshalBytes(dst []byte) []byte {
dst = r.NumBytes.MarshalUnsafe(dst)
return dst[copy(dst[:r.NumBytes], r.Buf[:r.NumBytes]):]
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (r *PReadResp) CheckedUnmarshal(src []byte) ([]byte, bool) {
srcRemain, ok := r.NumBytes.CheckedUnmarshal(src)
if !ok || uint32(r.NumBytes) > uint32(len(srcRemain)) || uint32(r.NumBytes) > uint32(len(r.Buf)) {
return src, false
}
// We expect the client to have already allocated r.Buf. r.Buf probably
// (optimally) points to usermem. Directly copy into that.
r.Buf = r.Buf[:r.NumBytes]
return srcRemain[copy(r.Buf, srcRemain[:r.NumBytes]):], true
}
// PWriteReq is used to pwrite(2) on an FD.
type PWriteReq struct {
Offset primitive.Uint64
FD FDID
NumBytes primitive.Uint32
Buf []byte
}
// String implements fmt.Stringer.String.
func (w *PWriteReq) String() string {
return fmt.Sprintf("PWriteReq{Offset: %d, FD: %d, NumBytes: %d, Buf: [...%d bytes...]}", w.Offset, w.FD, w.NumBytes, len(w.Buf))
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (w *PWriteReq) SizeBytes() int {
return w.Offset.SizeBytes() + w.FD.SizeBytes() + w.NumBytes.SizeBytes() + int(w.NumBytes)
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (w *PWriteReq) MarshalBytes(dst []byte) []byte {
dst = w.Offset.MarshalUnsafe(dst)
dst = w.FD.MarshalUnsafe(dst)
dst = w.NumBytes.MarshalUnsafe(dst)
return dst[copy(dst[:w.NumBytes], w.Buf[:w.NumBytes]):]
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (w *PWriteReq) CheckedUnmarshal(src []byte) ([]byte, bool) {
w.NumBytes = 0
if w.SizeBytes() > len(src) {
return src, false
}
srcRemain := w.Offset.UnmarshalUnsafe(src)
srcRemain = w.FD.UnmarshalUnsafe(srcRemain)
srcRemain = w.NumBytes.UnmarshalUnsafe(srcRemain)
// This is an optimization. Assuming that the server is making this call, it
// is safe to just point to src rather than allocating and copying.
if uint32(w.NumBytes) > uint32(len(srcRemain)) {
return src, false
}
w.Buf = srcRemain[:w.NumBytes]
return srcRemain[w.NumBytes:], true
}
// PWriteResp is used to return the result of pwrite(2).
//
// +marshal boundCheck
type PWriteResp struct {
Count uint64
}
// String implements fmt.Stringer.String.
func (w *PWriteResp) String() string {
return fmt.Sprintf("PWriteResp{Count: %d}", w.Count)
}
// MkdirAtReq is used to make MkdirAt requests.
type MkdirAtReq struct {
createCommon
Name SizedString
}
// String implements fmt.Stringer.String.
func (m *MkdirAtReq) String() string {
return fmt.Sprintf("MkdirAtReq{DirFD: %d, Mode: %s, UID: %d, GID: %d, Name: %s}", m.DirFD, m.Mode, m.UID, m.GID, m.Name)
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (m *MkdirAtReq) SizeBytes() int {
return m.createCommon.SizeBytes() + m.Name.SizeBytes()
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (m *MkdirAtReq) MarshalBytes(dst []byte) []byte {
dst = m.createCommon.MarshalUnsafe(dst)
return m.Name.MarshalBytes(dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (m *MkdirAtReq) CheckedUnmarshal(src []byte) ([]byte, bool) {
m.Name = ""
if m.SizeBytes() > len(src) {
return src, false
}
srcRemain := m.createCommon.UnmarshalUnsafe(src)
if srcRemain, ok := m.Name.CheckedUnmarshal(srcRemain); ok {
return srcRemain, true
}
return src, false
}
// MkdirAtResp is the response to a successful MkdirAt request.
//
// +marshal boundCheck
type MkdirAtResp struct {
ChildDir Inode
}
// String implements fmt.Stringer.String.
func (m *MkdirAtResp) String() string {
return fmt.Sprintf("MkdirAtResp{ChildDir: %s}", m.ChildDir.String())
}
// MknodAtReq is used to make MknodAt requests.
type MknodAtReq struct {
createCommon
Minor primitive.Uint32
Major primitive.Uint32
Name SizedString
}
// String implements fmt.Stringer.String.
func (m *MknodAtReq) String() string {
return fmt.Sprintf("MknodAtReq{DirFD: %d, Mode: %s, UID: %d, GID: %d, Minor: %d, Major: %d, Name: %s}", m.DirFD, m.Mode, m.UID, m.GID, m.Minor, m.Major, m.Name)
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (m *MknodAtReq) SizeBytes() int {
return m.createCommon.SizeBytes() + m.Minor.SizeBytes() + m.Major.SizeBytes() + m.Name.SizeBytes()
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (m *MknodAtReq) MarshalBytes(dst []byte) []byte {
dst = m.createCommon.MarshalUnsafe(dst)
dst = m.Minor.MarshalUnsafe(dst)
dst = m.Major.MarshalUnsafe(dst)
return m.Name.MarshalBytes(dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (m *MknodAtReq) CheckedUnmarshal(src []byte) ([]byte, bool) {
m.Name = ""
if m.SizeBytes() > len(src) {
return src, false
}
srcRemain := m.createCommon.UnmarshalUnsafe(src)
srcRemain = m.Minor.UnmarshalUnsafe(srcRemain)
srcRemain = m.Major.UnmarshalUnsafe(srcRemain)
if srcRemain, ok := m.Name.CheckedUnmarshal(srcRemain); ok {
return srcRemain, true
}
return src, false
}
// MknodAtResp is the response to a successful MknodAt request.
//
// +marshal boundCheck
type MknodAtResp struct {
Child Inode
}
// String implements fmt.Stringer.String.
func (m *MknodAtResp) String() string {
return fmt.Sprintf("MknodAtResp{Child: %s}", m.Child.String())
}
// SymlinkAtReq is used to make SymlinkAt request.
type SymlinkAtReq struct {
DirFD FDID
UID UID
GID GID
Name SizedString
Target SizedString
}
// String implements fmt.Stringer.String.
func (s *SymlinkAtReq) String() string {
return fmt.Sprintf("SymlinkAtReq{DirFD: %d, UID: %d, GID: %d, Name: %s, Target: %s}", s.DirFD, s.UID, s.GID, s.Name, s.Target)
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (s *SymlinkAtReq) SizeBytes() int {
return s.DirFD.SizeBytes() + s.UID.SizeBytes() + s.GID.SizeBytes() + s.Name.SizeBytes() + s.Target.SizeBytes()
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (s *SymlinkAtReq) MarshalBytes(dst []byte) []byte {
dst = s.DirFD.MarshalUnsafe(dst)
dst = s.UID.MarshalUnsafe(dst)
dst = s.GID.MarshalUnsafe(dst)
dst = s.Name.MarshalBytes(dst)
return s.Target.MarshalBytes(dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (s *SymlinkAtReq) CheckedUnmarshal(src []byte) ([]byte, bool) {
s.Name = ""
s.Target = ""
if s.SizeBytes() > len(src) {
return src, false
}
srcRemain := s.DirFD.UnmarshalUnsafe(src)
srcRemain = s.UID.UnmarshalUnsafe(srcRemain)
srcRemain = s.GID.UnmarshalUnsafe(srcRemain)
var ok bool
if srcRemain, ok = s.Name.CheckedUnmarshal(srcRemain); !ok {
return src, false
}
if srcRemain, ok = s.Target.CheckedUnmarshal(srcRemain); !ok {
return src, false
}
return srcRemain, true
}
// SymlinkAtResp is the response to a successful SymlinkAt request.
//
// +marshal boundCheck
type SymlinkAtResp struct {
Symlink Inode
}
// String implements fmt.Stringer.String.
func (s *SymlinkAtResp) String() string {
return fmt.Sprintf("SymlinkAtResp{Symlink: %s}", s.Symlink.String())
}
// LinkAtReq is used to make LinkAt requests.
type LinkAtReq struct {
DirFD FDID
Target FDID
Name SizedString
}
// String implements fmt.Stringer.String.
func (l *LinkAtReq) String() string {
return fmt.Sprintf("LinkAtReq{DirFD: %d, Target: %d, Name: %s}", l.DirFD, l.Target, l.Name)
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (l *LinkAtReq) SizeBytes() int {
return l.DirFD.SizeBytes() + l.Target.SizeBytes() + l.Name.SizeBytes()
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (l *LinkAtReq) MarshalBytes(dst []byte) []byte {
dst = l.DirFD.MarshalUnsafe(dst)
dst = l.Target.MarshalUnsafe(dst)
return l.Name.MarshalBytes(dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (l *LinkAtReq) CheckedUnmarshal(src []byte) ([]byte, bool) {
l.Name = ""
if l.SizeBytes() > len(src) {
return src, false
}
srcRemain := l.DirFD.UnmarshalUnsafe(src)
srcRemain = l.Target.UnmarshalUnsafe(srcRemain)
if srcRemain, ok := l.Name.CheckedUnmarshal(srcRemain); ok {
return srcRemain, true
}
return src, false
}
// LinkAtResp is used to respond to a successful LinkAt request.
//
// +marshal boundCheck
type LinkAtResp struct {
Link Inode
}
// String implements fmt.Stringer.String.
func (l *LinkAtResp) String() string {
return fmt.Sprintf("LinkAtResp{Link: %s}", l.Link.String())
}
// FStatFSReq is used to request StatFS results for the specified FD.
//
// +marshal boundCheck
type FStatFSReq struct {
FD FDID
}
// String implements fmt.Stringer.String.
func (s *FStatFSReq) String() string {
return fmt.Sprintf("FStatFSReq{FD: %d}", s.FD)
}
// StatFS is responded to a successful FStatFS request.
//
// +marshal boundCheck
type StatFS struct {
Type uint64
BlockSize int64
Blocks uint64
BlocksFree uint64
BlocksAvailable uint64
Files uint64
FilesFree uint64
NameLength uint64
}
// String implements fmt.Stringer.String.
func (s *StatFS) String() string {
return fmt.Sprintf("StatFS{Type: %d, BlockSize: %d, Blocks: %d, BlocksFree: %d, BlocksAvailable: %d, Files: %d, FilesFree: %d, NameLength: %d}",
s.Type, s.BlockSize, s.Blocks, s.BlocksFree, s.BlocksAvailable, s.Files, s.FilesFree, s.NameLength)
}
// FAllocateReq is used to request to fallocate(2) an FD. This has no response.
//
// +marshal boundCheck
type FAllocateReq struct {
FD FDID
Mode uint64
Offset uint64
Length uint64
}
// String implements fmt.Stringer.String.
func (a *FAllocateReq) String() string {
return fmt.Sprintf("FAllocateReq{FD: %d, Mode: %d, Offset: %d, Length: %d}", a.FD, a.Mode, a.Offset, a.Length)
}
// FAllocateResp is an empty response to FAllocateReq.
type FAllocateResp struct{ EmptyMessage }
// String implements fmt.Stringer.String.
func (*FAllocateResp) String() string {
return "FAllocateResp{}"
}
// ReadLinkAtReq is used to readlinkat(2) at the specified FD.
//
// +marshal boundCheck
type ReadLinkAtReq struct {
FD FDID
}
// String implements fmt.Stringer.String.
func (r *ReadLinkAtReq) String() string {
return fmt.Sprintf("ReadLinkAtReq{FD: %d}", r.FD)
}
// ReadLinkAtResp is used to communicate ReadLinkAt results.
type ReadLinkAtResp struct {
Target SizedString
}
// String implements fmt.Stringer.String.
func (r *ReadLinkAtResp) String() string {
return fmt.Sprintf("ReadLinkAtResp{Target: %s}", r.Target)
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (r *ReadLinkAtResp) SizeBytes() int {
return r.Target.SizeBytes()
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (r *ReadLinkAtResp) MarshalBytes(dst []byte) []byte {
return r.Target.MarshalBytes(dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (r *ReadLinkAtResp) CheckedUnmarshal(src []byte) ([]byte, bool) {
return r.Target.CheckedUnmarshal(src)
}
// FlushReq is used to make Flush requests.
//
// +marshal boundCheck
type FlushReq struct {
FD FDID
}
// String implements fmt.Stringer.String.
func (f *FlushReq) String() string {
return fmt.Sprintf("FlushReq{FD: %d}", f.FD)
}
// FlushResp is an empty response to FlushReq.
type FlushResp struct{ EmptyMessage }
// String implements fmt.Stringer.String.
func (*FlushResp) String() string {
return "FlushResp{}"
}
// ConnectReq is used to make a Connect request.
//
// +marshal boundCheck
type ConnectReq struct {
FD FDID
// SockType is used to specify the socket type to connect to. As a special
// case, SockType = 0 means that the socket type does not matter and the
// requester will accept any socket type.
SockType uint32
_ uint32 // Need to make struct packed.
}
// String implements fmt.Stringer.String.
func (c *ConnectReq) String() string {
return fmt.Sprintf("ConnectReq{FD: %d, SockType: %d}", c.FD, c.SockType)
}
// ConnectResp is an empty response to ConnectReq.
type ConnectResp struct{ EmptyMessage }
// String implements fmt.Stringer.String.
func (*ConnectResp) String() string {
return "ConnectResp{}"
}
// ConnectWithCredsReq is used to make a ConnectWithCreds request. The response is also ConnectResp.
//
// +marshal boundCheck
type ConnectWithCredsReq struct {
ConnectReq
// UID and GID are used to specify the credentials to connect with.
UID UID
GID GID
}
// String implements fmt.Stringer.String.
func (c *ConnectWithCredsReq) String() string {
return fmt.Sprintf("ConnectWithCredsReq{FD: %d, SockType: %d, UID: %d, GID: %d}", c.FD, c.SockType, c.UID, c.GID)
}
// BindAtReq is used to make BindAt requests.
type BindAtReq struct {
createCommon
SockType primitive.Uint32
Name SizedString
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (b *BindAtReq) SizeBytes() int {
return b.createCommon.SizeBytes() + b.SockType.SizeBytes() + b.Name.SizeBytes()
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (b *BindAtReq) MarshalBytes(dst []byte) []byte {
dst = b.createCommon.MarshalUnsafe(dst)
dst = b.SockType.MarshalUnsafe(dst)
return b.Name.MarshalBytes(dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (b *BindAtReq) CheckedUnmarshal(src []byte) ([]byte, bool) {
b.Name = ""
if b.SizeBytes() > len(src) {
return src, false
}
srcRemain := b.createCommon.UnmarshalUnsafe(src)
srcRemain = b.SockType.UnmarshalUnsafe(srcRemain)
if srcRemain, ok := b.Name.CheckedUnmarshal(srcRemain); ok {
return srcRemain, ok
}
return src, false
}
// String implements fmt.Stringer.String.
func (b *BindAtReq) String() string {
return fmt.Sprintf("BindAtReq{DirFD: %d, Mode: %s, UID: %d, GID: %d, SockType: %d, Name: %q}", b.DirFD, b.Mode, b.UID, b.GID, b.SockType, b.Name)
}
// BindAtResp is used to communicate BindAt response.
//
// +marshal boundCheck
type BindAtResp struct {
Child Inode
BoundSocketFD FDID
}
// String implements fmt.Stringer.String.
func (b *BindAtResp) String() string {
return fmt.Sprintf("BindAtResp{Child: %s, BoundSocketFD: %d}", b.Child.String(), b.BoundSocketFD)
}
// ListenReq is used to make Listen requests.
//
// +marshal boundCheck
type ListenReq struct {
FD FDID
Backlog int32
_ uint32
}
// String implements fmt.Stringer.String.
func (l *ListenReq) String() string {
return fmt.Sprintf("ListenReq{FD: %v, Backlog: %d}", l.FD, l.Backlog)
}
// ListenResp is an empty response to ListenResp.
type ListenResp struct{ EmptyMessage }
// String implements fmt.Stringer.String.
func (*ListenResp) String() string {
return "ListenResp{}"
}
// AcceptReq is used to make AcceptRequests.
//
// +marshal boundCheck
type AcceptReq struct {
FD FDID
}
// String implements fmt.Stringer.String.
func (a *AcceptReq) String() string {
return fmt.Sprintf("AcceptReq{FD: %v}", a.FD)
}
// AcceptResp is an empty response to AcceptResp.
type AcceptResp struct {
PeerAddr SizedString
}
// String implements fmt.Stringer.String.
func (a *AcceptResp) String() string {
return fmt.Sprintf("AcceptResp{PeerAddr: %s}", a.PeerAddr)
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (a *AcceptResp) SizeBytes() int {
return a.PeerAddr.SizeBytes()
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (a *AcceptResp) MarshalBytes(dst []byte) []byte {
return a.PeerAddr.MarshalBytes(dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (a *AcceptResp) CheckedUnmarshal(src []byte) ([]byte, bool) {
return a.PeerAddr.CheckedUnmarshal(src)
}
// UnlinkAtReq is used to make UnlinkAt request.
type UnlinkAtReq struct {
DirFD FDID
Flags primitive.Uint32
Name SizedString
}
// String implements fmt.Stringer.String.
func (u *UnlinkAtReq) String() string {
return fmt.Sprintf("UnlinkAtReq{DirFD: %d, Flags: %#x, Name: %s}", u.DirFD, u.Flags, u.Name)
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (u *UnlinkAtReq) SizeBytes() int {
return u.DirFD.SizeBytes() + u.Flags.SizeBytes() + u.Name.SizeBytes()
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (u *UnlinkAtReq) MarshalBytes(dst []byte) []byte {
dst = u.DirFD.MarshalUnsafe(dst)
dst = u.Flags.MarshalUnsafe(dst)
return u.Name.MarshalBytes(dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (u *UnlinkAtReq) CheckedUnmarshal(src []byte) ([]byte, bool) {
u.Name = ""
if u.SizeBytes() > len(src) {
return src, false
}
srcRemain := u.DirFD.UnmarshalUnsafe(src)
srcRemain = u.Flags.UnmarshalUnsafe(srcRemain)
if srcRemain, ok := u.Name.CheckedUnmarshal(srcRemain); ok {
return srcRemain, true
}
return src, false
}
// UnlinkAtResp is an empty response to UnlinkAtReq.
type UnlinkAtResp struct{ EmptyMessage }
// String implements fmt.Stringer.String.
func (*UnlinkAtResp) String() string {
return "UnlinkAtResp{}"
}
// RenameAtReq is used to make RenameAt requests. Note that the request takes in
// the to-be-renamed file's FD instead of oldDir and oldName like renameat(2).
type RenameAtReq struct {
OldDir FDID
NewDir FDID
OldName SizedString
NewName SizedString
}
// String implements fmt.Stringer.String.
func (r *RenameAtReq) String() string {
return fmt.Sprintf("RenameAtReq{OldDir: %d, NewDir: %d, OldName: %s, NewName: %s}", r.OldDir, r.NewDir, r.OldName, r.NewName)
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (r *RenameAtReq) SizeBytes() int {
return r.OldDir.SizeBytes() + r.NewDir.SizeBytes() + r.OldName.SizeBytes() + r.NewName.SizeBytes()
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (r *RenameAtReq) MarshalBytes(dst []byte) []byte {
dst = r.OldDir.MarshalUnsafe(dst)
dst = r.NewDir.MarshalUnsafe(dst)
dst = r.OldName.MarshalBytes(dst)
return r.NewName.MarshalBytes(dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (r *RenameAtReq) CheckedUnmarshal(src []byte) ([]byte, bool) {
r.OldName = ""
r.NewName = ""
if r.SizeBytes() > len(src) {
return src, false
}
srcRemain := r.OldDir.UnmarshalUnsafe(src)
srcRemain = r.NewDir.UnmarshalUnsafe(srcRemain)
var ok bool
if srcRemain, ok = r.OldName.CheckedUnmarshal(srcRemain); !ok {
return src, false
}
if srcRemain, ok = r.NewName.CheckedUnmarshal(srcRemain); !ok {
return src, false
}
return srcRemain, true
}
// RenameAtResp is an empty response to RenameAtReq.
type RenameAtResp struct{ EmptyMessage }
// String implements fmt.Stringer.String.
func (*RenameAtResp) String() string {
return "RenameAtResp{}"
}
// Getdents64Req is used to make Getdents64 requests.
//
// +marshal boundCheck
type Getdents64Req struct {
DirFD FDID
// Count is the number of bytes to read. A negative value of Count is used to
// indicate that the implementation must lseek(0, SEEK_SET) before calling
// getdents64(2). Implementations must use the absolute value of Count to
// determine the number of bytes to read.
Count int32
_ uint32 // Need to make struct packed.
}
// String implements fmt.Stringer.String.
func (g *Getdents64Req) String() string {
return fmt.Sprintf("Getdents64Req{DirFD: %d, Count: %d}", g.DirFD, g.Count)
}
// Dirent64 is analogous to struct linux_dirent64.
type Dirent64 struct {
Ino primitive.Uint64
DevMinor primitive.Uint32
DevMajor primitive.Uint32
Off primitive.Uint64
Type primitive.Uint8
Name SizedString
}
// String implements fmt.Stringer.String.
func (d *Dirent64) String() string {
return fmt.Sprintf("Dirent64{Ino: %d, DevMinor: %d, DevMajor: %d, Off: %d, Type: %d, Name: %s}", d.Ino, d.DevMinor, d.DevMajor, d.Off, d.Type, d.Name)
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (d *Dirent64) SizeBytes() int {
return d.Ino.SizeBytes() + d.DevMinor.SizeBytes() + d.DevMajor.SizeBytes() + d.Off.SizeBytes() + d.Type.SizeBytes() + d.Name.SizeBytes()
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (d *Dirent64) MarshalBytes(dst []byte) []byte {
dst = d.Ino.MarshalUnsafe(dst)
dst = d.DevMinor.MarshalUnsafe(dst)
dst = d.DevMajor.MarshalUnsafe(dst)
dst = d.Off.MarshalUnsafe(dst)
dst = d.Type.MarshalUnsafe(dst)
return d.Name.MarshalBytes(dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (d *Dirent64) CheckedUnmarshal(src []byte) ([]byte, bool) {
d.Name = ""
if d.SizeBytes() > len(src) {
return src, false
}
srcRemain := d.Ino.UnmarshalUnsafe(src)
srcRemain = d.DevMinor.UnmarshalUnsafe(srcRemain)
srcRemain = d.DevMajor.UnmarshalUnsafe(srcRemain)
srcRemain = d.Off.UnmarshalUnsafe(srcRemain)
srcRemain = d.Type.UnmarshalUnsafe(srcRemain)
if srcRemain, ok := d.Name.CheckedUnmarshal(srcRemain); ok {
return srcRemain, true
}
return src, false
}
// Getdents64Resp is used to communicate getdents64 results. In memory, the
// dirents array is preceded by a uint16 integer denoting array length.
type Getdents64Resp struct {
Dirents []Dirent64
}
// String implements fmt.Stringer.String.
func (g *Getdents64Resp) String() string {
var b strings.Builder
b.WriteString("[")
for i, dirent := range g.Dirents {
if i > 0 {
b.WriteString(", ")
}
b.WriteString(dirent.String())
}
b.WriteString("]")
return fmt.Sprintf("Getdents64Resp{Dirents: %s}", b.String())
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (g *Getdents64Resp) SizeBytes() int {
ret := (*primitive.Uint16)(nil).SizeBytes()
for i := range g.Dirents {
ret += g.Dirents[i].SizeBytes()
}
return ret
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (g *Getdents64Resp) MarshalBytes(dst []byte) []byte {
numDirents := primitive.Uint16(len(g.Dirents))
dst = numDirents.MarshalUnsafe(dst)
for i := range g.Dirents {
dst = g.Dirents[i].MarshalBytes(dst)
}
return dst
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (g *Getdents64Resp) CheckedUnmarshal(src []byte) ([]byte, bool) {
g.Dirents = g.Dirents[:0]
if g.SizeBytes() > len(src) {
return src, false
}
var numDirents primitive.Uint16
srcRemain := numDirents.UnmarshalUnsafe(src)
if cap(g.Dirents) < int(numDirents) {
g.Dirents = make([]Dirent64, numDirents)
} else {
g.Dirents = g.Dirents[:numDirents]
}
var ok bool
for i := range g.Dirents {
if srcRemain, ok = g.Dirents[i].CheckedUnmarshal(srcRemain); !ok {
return src, false
}
}
return srcRemain, true
}
// FGetXattrReq is used to make FGetXattr requests. The response to this is
// just a SizedString containing the xattr value.
type FGetXattrReq struct {
FD FDID
BufSize primitive.Uint32
Name SizedString
}
// String implements fmt.Stringer.String.
func (g *FGetXattrReq) String() string {
return fmt.Sprintf("FGetXattrReq{FD: %d, BufSize: %d, Name: %s}", g.FD, g.BufSize, g.Name)
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (g *FGetXattrReq) SizeBytes() int {
return g.FD.SizeBytes() + g.BufSize.SizeBytes() + g.Name.SizeBytes()
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (g *FGetXattrReq) MarshalBytes(dst []byte) []byte {
dst = g.FD.MarshalUnsafe(dst)
dst = g.BufSize.MarshalUnsafe(dst)
return g.Name.MarshalBytes(dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (g *FGetXattrReq) CheckedUnmarshal(src []byte) ([]byte, bool) {
g.Name = ""
if g.SizeBytes() > len(src) {
return src, false
}
srcRemain := g.FD.UnmarshalUnsafe(src)
srcRemain = g.BufSize.UnmarshalUnsafe(srcRemain)
if srcRemain, ok := g.Name.CheckedUnmarshal(srcRemain); ok {
return srcRemain, true
}
return src, false
}
// FGetXattrResp is used to respond to FGetXattr request.
type FGetXattrResp struct {
Value SizedString
}
// String implements fmt.Stringer.String.
func (g *FGetXattrResp) String() string {
return fmt.Sprintf("FGetXattrResp{Value: %s}", g.Value)
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (g *FGetXattrResp) SizeBytes() int {
return g.Value.SizeBytes()
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (g *FGetXattrResp) MarshalBytes(dst []byte) []byte {
return g.Value.MarshalBytes(dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (g *FGetXattrResp) CheckedUnmarshal(src []byte) ([]byte, bool) {
return g.Value.CheckedUnmarshal(src)
}
// FSetXattrReq is used to make FSetXattr requests. It has no response.
type FSetXattrReq struct {
FD FDID
Flags primitive.Uint32
Name SizedString
Value SizedString
}
// String implements fmt.Stringer.String.
func (s *FSetXattrReq) String() string {
return fmt.Sprintf("FSetXattrReq{FD: %d, Flags: %#x, Name: %s, Value: %s}", s.FD, s.Flags, s.Name, s.Value)
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (s *FSetXattrReq) SizeBytes() int {
return s.FD.SizeBytes() + s.Flags.SizeBytes() + s.Name.SizeBytes() + s.Value.SizeBytes()
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (s *FSetXattrReq) MarshalBytes(dst []byte) []byte {
dst = s.FD.MarshalUnsafe(dst)
dst = s.Flags.MarshalUnsafe(dst)
dst = s.Name.MarshalBytes(dst)
return s.Value.MarshalBytes(dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (s *FSetXattrReq) CheckedUnmarshal(src []byte) ([]byte, bool) {
s.Name = ""
s.Value = ""
if s.SizeBytes() > len(src) {
return src, false
}
srcRemain := s.FD.UnmarshalUnsafe(src)
srcRemain = s.Flags.UnmarshalUnsafe(srcRemain)
var ok bool
if srcRemain, ok = s.Name.CheckedUnmarshal(srcRemain); !ok {
return src, false
}
if srcRemain, ok = s.Value.CheckedUnmarshal(srcRemain); !ok {
return src, false
}
return srcRemain, true
}
// FSetXattrResp is an empty response to FSetXattrReq.
type FSetXattrResp struct{ EmptyMessage }
// String implements fmt.Stringer.String.
func (*FSetXattrResp) String() string {
return "FSetXattrResp{}"
}
// FRemoveXattrReq is used to make FRemoveXattr requests. It has no response.
type FRemoveXattrReq struct {
FD FDID
Name SizedString
}
// String implements fmt.Stringer.String.
func (r *FRemoveXattrReq) String() string {
return fmt.Sprintf("FRemoveXattrReq{FD: %d, Name: %s}", r.FD, r.Name)
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (r *FRemoveXattrReq) SizeBytes() int {
return r.FD.SizeBytes() + r.Name.SizeBytes()
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (r *FRemoveXattrReq) MarshalBytes(dst []byte) []byte {
dst = r.FD.MarshalUnsafe(dst)
return r.Name.MarshalBytes(dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (r *FRemoveXattrReq) CheckedUnmarshal(src []byte) ([]byte, bool) {
r.Name = ""
if r.SizeBytes() > len(src) {
return src, false
}
srcRemain := r.FD.UnmarshalUnsafe(src)
if srcRemain, ok := r.Name.CheckedUnmarshal(srcRemain); ok {
return srcRemain, true
}
return src, false
}
// FRemoveXattrResp is an empty response to FRemoveXattrReq.
type FRemoveXattrResp struct{ EmptyMessage }
// String implements fmt.Stringer.String.
func (*FRemoveXattrResp) String() string {
return "FRemoveXattrResp{}"
}
// FListXattrReq is used to make FListXattr requests.
//
// +marshal boundCheck
type FListXattrReq struct {
FD FDID
Size uint64
}
// String implements fmt.Stringer.String.
func (l *FListXattrReq) String() string {
return fmt.Sprintf("FListXattrReq{FD: %d, Size: %d}", l.FD, l.Size)
}
// FListXattrResp is used to respond to FListXattr requests.
type FListXattrResp struct {
Xattrs StringArray
}
// String implements fmt.Stringer.String.
func (l *FListXattrResp) String() string {
return fmt.Sprintf("FListXattrResp{Xattrs: %s}", l.Xattrs.String())
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
func (l *FListXattrResp) SizeBytes() int {
return l.Xattrs.SizeBytes()
}
// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (l *FListXattrResp) MarshalBytes(dst []byte) []byte {
return l.Xattrs.MarshalBytes(dst)
}
// CheckedUnmarshal implements marshal.CheckedMarshallable.CheckedUnmarshal.
func (l *FListXattrResp) CheckedUnmarshal(src []byte) ([]byte, bool) {
return l.Xattrs.CheckedUnmarshal(src)
}