// 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 (
	"math"
	"os"

	"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.

// 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
)

const (
	// NoUID is a sentinel used to indicate no valid UID.
	NoUID UID = math.MaxUint32

	// NoGID is a sentinel used to indicate no valid GID.
	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())
}

// TODO(gvisor.dev/issue/6450): Once this is resolved:
// * Update manual implementations and function signatures.
// * Update RPC handlers and appropriate callers to handle errors correctly.
// * Update manual implementations to get rid of buffer shifting.

// 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
}

// NoopMarshal is a noop implementation of marshal.Marshallable.MarshalBytes.
func NoopMarshal([]byte) {}

// NoopUnmarshal is a noop implementation of marshal.Marshallable.UnmarshalBytes.
func NoopUnmarshal([]byte) {}

// SizedString represents a string in memory. The marshalled string bytes are
// preceded by a uint32 signifying the string length.
type SizedString string

// SizeBytes implements marshal.Marshallable.SizeBytes.
func (s *SizedString) SizeBytes() int {
	return (*primitive.Uint32)(nil).SizeBytes() + len(*s)
}

// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (s *SizedString) MarshalBytes(dst []byte) {
	strLen := primitive.Uint32(len(*s))
	strLen.MarshalUnsafe(dst)
	dst = dst[strLen.SizeBytes():]
	// Copy without any allocation.
	copy(dst[:strLen], *s)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (s *SizedString) UnmarshalBytes(src []byte) {
	var strLen primitive.Uint32
	strLen.UnmarshalUnsafe(src)
	src = src[strLen.SizeBytes():]
	// Take the hit, this leads to an allocation + memcpy. No way around it.
	*s = SizedString(src[:strLen])
}

// StringArray represents an array of SizedStrings in memory. The marshalled
// array data is preceded by a uint32 signifying the array length.
type StringArray []string

// SizeBytes implements marshal.Marshallable.SizeBytes.
func (s *StringArray) SizeBytes() int {
	size := (*primitive.Uint32)(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) {
	arrLen := primitive.Uint32(len(*s))
	arrLen.MarshalUnsafe(dst)
	dst = dst[arrLen.SizeBytes():]
	for _, str := range *s {
		sstr := SizedString(str)
		sstr.MarshalBytes(dst)
		dst = dst[sstr.SizeBytes():]
	}
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (s *StringArray) UnmarshalBytes(src []byte) {
	var arrLen primitive.Uint32
	arrLen.UnmarshalUnsafe(src)
	src = src[arrLen.SizeBytes():]

	if cap(*s) < int(arrLen) {
		*s = make([]string, arrLen)
	} else {
		*s = (*s)[:arrLen]
	}

	for i := primitive.Uint32(0); i < arrLen; i++ {
		var sstr SizedString
		sstr.UnmarshalBytes(src)
		src = src[sstr.SizeBytes():]
		(*s)[i] = string(sstr)
	}
}

// Inode represents an inode on the remote filesystem.
//
// +marshal slice:InodeSlice
type Inode struct {
	ControlFD FDID
	_         uint32 // Need to make struct packed.
	Stat      linux.Statx
}

// MountReq represents a Mount request.
type MountReq struct {
	MountPath SizedString
}

// SizeBytes implements marshal.Marshallable.SizeBytes.
func (m *MountReq) SizeBytes() int {
	return m.MountPath.SizeBytes()
}

// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (m *MountReq) MarshalBytes(dst []byte) {
	m.MountPath.MarshalBytes(dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (m *MountReq) UnmarshalBytes(src []byte) {
	m.MountPath.UnmarshalBytes(src)
}

// 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
}

// 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) {
	m.Root.MarshalUnsafe(dst)
	dst = dst[m.Root.SizeBytes():]
	m.MaxMessageSize.MarshalUnsafe(dst)
	dst = dst[m.MaxMessageSize.SizeBytes():]
	numSupported := primitive.Uint16(len(m.SupportedMs))
	numSupported.MarshalBytes(dst)
	dst = dst[numSupported.SizeBytes():]
	MarshalUnsafeMIDSlice(m.SupportedMs, dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (m *MountResp) UnmarshalBytes(src []byte) {
	m.Root.UnmarshalUnsafe(src)
	src = src[m.Root.SizeBytes():]
	m.MaxMessageSize.UnmarshalUnsafe(src)
	src = src[m.MaxMessageSize.SizeBytes():]
	var numSupported primitive.Uint16
	numSupported.UnmarshalBytes(src)
	src = src[numSupported.SizeBytes():]
	m.SupportedMs = make([]MID, numSupported)
	UnmarshalUnsafeMIDSlice(m.SupportedMs, src)
}

// ChannelResp is the response to the create channel request.
//
// +marshal
type ChannelResp struct {
	dataOffset int64
	dataLength uint64
}

// ErrorResp is returned to represent an error while handling a request.
//
// +marshal
type ErrorResp struct {
	errno uint32
}

// StatReq requests the stat results for the specified FD.
//
// +marshal
type StatReq struct {
	FD FDID
}

// SetStatReq is used to set attributeds on FDs.
//
// +marshal
type SetStatReq struct {
	FD    FDID
	_     uint32
	Mask  uint32
	Mode  uint32 // Only permissions part is settable.
	UID   UID
	GID   GID
	Size  uint64
	Atime linux.Timespec
	Mtime linux.Timespec
}

// 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
type SetStatResp struct {
	FailureMask  uint32
	FailureErrNo uint32
}

// 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
}

// 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) {
	w.DirFD.MarshalUnsafe(dst)
	dst = dst[w.DirFD.SizeBytes():]
	w.Path.MarshalBytes(dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (w *WalkReq) UnmarshalBytes(src []byte) {
	w.DirFD.UnmarshalUnsafe(src)
	src = src[w.DirFD.SizeBytes():]
	w.Path.UnmarshalBytes(src)
}

// 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
)

// WalkResp is used to communicate the inodes walked by the server.
type WalkResp struct {
	Status WalkStatus
	Inodes []Inode
}

// SizeBytes implements marshal.Marshallable.SizeBytes.
func (w *WalkResp) SizeBytes() int {
	return w.Status.SizeBytes() +
		(*primitive.Uint32)(nil).SizeBytes() + (len(w.Inodes) * (*Inode)(nil).SizeBytes())
}

// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (w *WalkResp) MarshalBytes(dst []byte) {
	w.Status.MarshalUnsafe(dst)
	dst = dst[w.Status.SizeBytes():]

	numInodes := primitive.Uint32(len(w.Inodes))
	numInodes.MarshalUnsafe(dst)
	dst = dst[numInodes.SizeBytes():]

	MarshalUnsafeInodeSlice(w.Inodes, dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (w *WalkResp) UnmarshalBytes(src []byte) {
	w.Status.UnmarshalUnsafe(src)
	src = src[w.Status.SizeBytes():]

	var numInodes primitive.Uint32
	numInodes.UnmarshalUnsafe(src)
	src = src[numInodes.SizeBytes():]

	if cap(w.Inodes) < int(numInodes) {
		w.Inodes = make([]Inode, numInodes)
	} else {
		w.Inodes = w.Inodes[:numInodes]
	}
	UnmarshalUnsafeInodeSlice(w.Inodes, src)
}

// WalkStatResp is used to communicate stat results for WalkStat.
type WalkStatResp struct {
	Stats []linux.Statx
}

// SizeBytes implements marshal.Marshallable.SizeBytes.
func (w *WalkStatResp) SizeBytes() int {
	return (*primitive.Uint32)(nil).SizeBytes() + (len(w.Stats) * linux.SizeOfStatx)
}

// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (w *WalkStatResp) MarshalBytes(dst []byte) {
	numStats := primitive.Uint32(len(w.Stats))
	numStats.MarshalUnsafe(dst)
	dst = dst[numStats.SizeBytes():]

	linux.MarshalUnsafeStatxSlice(w.Stats, dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (w *WalkStatResp) UnmarshalBytes(src []byte) {
	var numStats primitive.Uint32
	numStats.UnmarshalUnsafe(src)
	src = src[numStats.SizeBytes():]

	if cap(w.Stats) < int(numStats) {
		w.Stats = make([]linux.Statx, numStats)
	} else {
		w.Stats = w.Stats[:numStats]
	}
	linux.UnmarshalUnsafeStatxSlice(w.Stats, src)
}

// OpenAtReq is used to open existing FDs with the specified flags.
//
// +marshal
type OpenAtReq struct {
	FD    FDID
	Flags uint32
}

// OpenAtResp is used to communicate the newly created FD.
//
// +marshal
type OpenAtResp struct {
	NewFD FDID
}

// +marshal
type createCommon struct {
	DirFD FDID
	Mode  linux.FileMode
	_     uint16 // Need to make struct packed.
	UID   UID
	GID   GID
}

// OpenCreateAtReq is used to make OpenCreateAt requests.
type OpenCreateAtReq struct {
	createCommon
	Name  SizedString
	Flags primitive.Uint32
}

// SizeBytes implements marshal.Marshallable.SizeBytes.
func (o *OpenCreateAtReq) SizeBytes() int {
	return o.createCommon.SizeBytes() + o.Name.SizeBytes() + o.Flags.SizeBytes()
}

// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (o *OpenCreateAtReq) MarshalBytes(dst []byte) {
	o.createCommon.MarshalUnsafe(dst)
	dst = dst[o.createCommon.SizeBytes():]
	o.Name.MarshalBytes(dst)
	dst = dst[o.Name.SizeBytes():]
	o.Flags.MarshalUnsafe(dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (o *OpenCreateAtReq) UnmarshalBytes(src []byte) {
	o.createCommon.UnmarshalUnsafe(src)
	src = src[o.createCommon.SizeBytes():]
	o.Name.UnmarshalBytes(src)
	src = src[o.Name.SizeBytes():]
	o.Flags.UnmarshalUnsafe(src)
}

// OpenCreateAtResp is used to communicate successful OpenCreateAt results.
//
// +marshal
type OpenCreateAtResp struct {
	Child Inode
	NewFD FDID
	_     uint32 // Need to make struct packed.
}

// 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
// uint32 denoting the array length.
type FdArray []FDID

// SizeBytes implements marshal.Marshallable.SizeBytes.
func (f *FdArray) SizeBytes() int {
	return (*primitive.Uint32)(nil).SizeBytes() + (len(*f) * (*FDID)(nil).SizeBytes())
}

// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (f *FdArray) MarshalBytes(dst []byte) {
	arrLen := primitive.Uint32(len(*f))
	arrLen.MarshalUnsafe(dst)
	dst = dst[arrLen.SizeBytes():]
	MarshalUnsafeFDIDSlice(*f, dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (f *FdArray) UnmarshalBytes(src []byte) {
	var arrLen primitive.Uint32
	arrLen.UnmarshalUnsafe(src)
	src = src[arrLen.SizeBytes():]
	if cap(*f) < int(arrLen) {
		*f = make(FdArray, arrLen)
	} else {
		*f = (*f)[:arrLen]
	}
	UnmarshalUnsafeFDIDSlice(*f, src)
}

// CloseReq is used to close(2) FDs.
type CloseReq struct {
	FDs FdArray
}

// 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) {
	c.FDs.MarshalBytes(dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (c *CloseReq) UnmarshalBytes(src []byte) {
	c.FDs.UnmarshalBytes(src)
}

// FsyncReq is used to fsync(2) FDs.
type FsyncReq struct {
	FDs FdArray
}

// 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) {
	f.FDs.MarshalBytes(dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (f *FsyncReq) UnmarshalBytes(src []byte) {
	f.FDs.UnmarshalBytes(src)
}

// PReadReq is used to pread(2) on an FD.
//
// +marshal
type PReadReq struct {
	Offset uint64
	FD     FDID
	Count  uint32
}

// PReadResp is used to return the result of pread(2).
type PReadResp struct {
	NumBytes primitive.Uint32
	Buf      []byte
}

// 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) {
	r.NumBytes.MarshalUnsafe(dst)
	dst = dst[r.NumBytes.SizeBytes():]
	copy(dst[:r.NumBytes], r.Buf[:r.NumBytes])
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (r *PReadResp) UnmarshalBytes(src []byte) {
	r.NumBytes.UnmarshalUnsafe(src)
	src = src[r.NumBytes.SizeBytes():]

	// We expect the client to have already allocated r.Buf. r.Buf probably
	// (optimally) points to usermem. Directly copy into that.
	copy(r.Buf[:r.NumBytes], src[:r.NumBytes])
}

// PWriteReq is used to pwrite(2) on an FD.
type PWriteReq struct {
	Offset   primitive.Uint64
	FD       FDID
	NumBytes primitive.Uint32
	Buf      []byte
}

// 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) {
	w.Offset.MarshalUnsafe(dst)
	dst = dst[w.Offset.SizeBytes():]
	w.FD.MarshalUnsafe(dst)
	dst = dst[w.FD.SizeBytes():]
	w.NumBytes.MarshalUnsafe(dst)
	dst = dst[w.NumBytes.SizeBytes():]
	copy(dst[:w.NumBytes], w.Buf[:w.NumBytes])
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (w *PWriteReq) UnmarshalBytes(src []byte) {
	w.Offset.UnmarshalUnsafe(src)
	src = src[w.Offset.SizeBytes():]
	w.FD.UnmarshalUnsafe(src)
	src = src[w.FD.SizeBytes():]
	w.NumBytes.UnmarshalUnsafe(src)
	src = src[w.NumBytes.SizeBytes():]

	// 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.
	w.Buf = src[:w.NumBytes]
}

// PWriteResp is used to return the result of pwrite(2).
//
// +marshal
type PWriteResp struct {
	Count uint64
}

// MkdirAtReq is used to make MkdirAt requests.
type MkdirAtReq struct {
	createCommon
	Name SizedString
}

// 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) {
	m.createCommon.MarshalUnsafe(dst)
	dst = dst[m.createCommon.SizeBytes():]
	m.Name.MarshalBytes(dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (m *MkdirAtReq) UnmarshalBytes(src []byte) {
	m.createCommon.UnmarshalUnsafe(src)
	src = src[m.createCommon.SizeBytes():]
	m.Name.UnmarshalBytes(src)
}

// MkdirAtResp is the response to a successful MkdirAt request.
//
// +marshal
type MkdirAtResp struct {
	ChildDir Inode
}

// MknodAtReq is used to make MknodAt requests.
type MknodAtReq struct {
	createCommon
	Name  SizedString
	Minor primitive.Uint32
	Major primitive.Uint32
}

// SizeBytes implements marshal.Marshallable.SizeBytes.
func (m *MknodAtReq) SizeBytes() int {
	return m.createCommon.SizeBytes() + m.Name.SizeBytes() + m.Minor.SizeBytes() + m.Major.SizeBytes()
}

// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (m *MknodAtReq) MarshalBytes(dst []byte) {
	m.createCommon.MarshalUnsafe(dst)
	dst = dst[m.createCommon.SizeBytes():]
	m.Name.MarshalBytes(dst)
	dst = dst[m.Name.SizeBytes():]
	m.Minor.MarshalUnsafe(dst)
	dst = dst[m.Minor.SizeBytes():]
	m.Major.MarshalUnsafe(dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (m *MknodAtReq) UnmarshalBytes(src []byte) {
	m.createCommon.UnmarshalUnsafe(src)
	src = src[m.createCommon.SizeBytes():]
	m.Name.UnmarshalBytes(src)
	src = src[m.Name.SizeBytes():]
	m.Minor.UnmarshalUnsafe(src)
	src = src[m.Minor.SizeBytes():]
	m.Major.UnmarshalUnsafe(src)
}

// MknodAtResp is the response to a successful MknodAt request.
//
// +marshal
type MknodAtResp struct {
	Child Inode
}

// SymlinkAtReq is used to make SymlinkAt request.
type SymlinkAtReq struct {
	DirFD  FDID
	Name   SizedString
	Target SizedString
	UID    UID
	GID    GID
}

// SizeBytes implements marshal.Marshallable.SizeBytes.
func (s *SymlinkAtReq) SizeBytes() int {
	return s.DirFD.SizeBytes() + s.Name.SizeBytes() + s.Target.SizeBytes() + s.UID.SizeBytes() + s.GID.SizeBytes()
}

// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (s *SymlinkAtReq) MarshalBytes(dst []byte) {
	s.DirFD.MarshalUnsafe(dst)
	dst = dst[s.DirFD.SizeBytes():]
	s.Name.MarshalBytes(dst)
	dst = dst[s.Name.SizeBytes():]
	s.Target.MarshalBytes(dst)
	dst = dst[s.Target.SizeBytes():]
	s.UID.MarshalUnsafe(dst)
	dst = dst[s.UID.SizeBytes():]
	s.GID.MarshalUnsafe(dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (s *SymlinkAtReq) UnmarshalBytes(src []byte) {
	s.DirFD.UnmarshalUnsafe(src)
	src = src[s.DirFD.SizeBytes():]
	s.Name.UnmarshalBytes(src)
	src = src[s.Name.SizeBytes():]
	s.Target.UnmarshalBytes(src)
	src = src[s.Target.SizeBytes():]
	s.UID.UnmarshalUnsafe(src)
	src = src[s.UID.SizeBytes():]
	s.GID.UnmarshalUnsafe(src)
}

// SymlinkAtResp is the response to a successful SymlinkAt request.
//
// +marshal
type SymlinkAtResp struct {
	Symlink Inode
}

// LinkAtReq is used to make LinkAt requests.
type LinkAtReq struct {
	DirFD  FDID
	Target FDID
	Name   SizedString
}

// 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) {
	l.DirFD.MarshalUnsafe(dst)
	dst = dst[l.DirFD.SizeBytes():]
	l.Target.MarshalUnsafe(dst)
	dst = dst[l.Target.SizeBytes():]
	l.Name.MarshalBytes(dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (l *LinkAtReq) UnmarshalBytes(src []byte) {
	l.DirFD.UnmarshalUnsafe(src)
	src = src[l.DirFD.SizeBytes():]
	l.Target.UnmarshalUnsafe(src)
	src = src[l.Target.SizeBytes():]
	l.Name.UnmarshalBytes(src)
}

// LinkAtResp is used to respond to a successful LinkAt request.
//
// +marshal
type LinkAtResp struct {
	Link Inode
}

// FStatFSReq is used to request StatFS results for the specified FD.
//
// +marshal
type FStatFSReq struct {
	FD FDID
}

// StatFS is responded to a successful FStatFS request.
//
// +marshal
type StatFS struct {
	Type            uint64
	BlockSize       int64
	Blocks          uint64
	BlocksFree      uint64
	BlocksAvailable uint64
	Files           uint64
	FilesFree       uint64
	NameLength      uint64
}

// FAllocateReq is used to request to fallocate(2) an FD. This has no response.
//
// +marshal
type FAllocateReq struct {
	FD     FDID
	_      uint32
	Mode   uint64
	Offset uint64
	Length uint64
}

// ReadLinkAtReq is used to readlinkat(2) at the specified FD.
//
// +marshal
type ReadLinkAtReq struct {
	FD FDID
}

// ReadLinkAtResp is used to communicate ReadLinkAt results.
type ReadLinkAtResp struct {
	Target SizedString
}

// 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) {
	r.Target.MarshalBytes(dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (r *ReadLinkAtResp) UnmarshalBytes(src []byte) {
	r.Target.UnmarshalBytes(src)
}

// FlushReq is used to make Flush requests.
//
// +marshal
type FlushReq struct {
	FD FDID
}

// ConnectReq is used to make a Connect request.
//
// +marshal
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
}

// UnlinkAtReq is used to make UnlinkAt request.
type UnlinkAtReq struct {
	DirFD FDID
	Name  SizedString
	Flags primitive.Uint32
}

// SizeBytes implements marshal.Marshallable.SizeBytes.
func (u *UnlinkAtReq) SizeBytes() int {
	return u.DirFD.SizeBytes() + u.Name.SizeBytes() + u.Flags.SizeBytes()
}

// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (u *UnlinkAtReq) MarshalBytes(dst []byte) {
	u.DirFD.MarshalUnsafe(dst)
	dst = dst[u.DirFD.SizeBytes():]
	u.Name.MarshalBytes(dst)
	dst = dst[u.Name.SizeBytes():]
	u.Flags.MarshalUnsafe(dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (u *UnlinkAtReq) UnmarshalBytes(src []byte) {
	u.DirFD.UnmarshalUnsafe(src)
	src = src[u.DirFD.SizeBytes():]
	u.Name.UnmarshalBytes(src)
	src = src[u.Name.SizeBytes():]
	u.Flags.UnmarshalUnsafe(src)
}

// RenameAtReq is used to make Rename 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 {
	Renamed FDID
	NewDir  FDID
	NewName SizedString
}

// SizeBytes implements marshal.Marshallable.SizeBytes.
func (r *RenameAtReq) SizeBytes() int {
	return r.Renamed.SizeBytes() + r.NewDir.SizeBytes() + r.NewName.SizeBytes()
}

// MarshalBytes implements marshal.Marshallable.MarshalBytes.
func (r *RenameAtReq) MarshalBytes(dst []byte) {
	r.Renamed.MarshalUnsafe(dst)
	dst = dst[r.Renamed.SizeBytes():]
	r.NewDir.MarshalUnsafe(dst)
	dst = dst[r.NewDir.SizeBytes():]
	r.NewName.MarshalBytes(dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (r *RenameAtReq) UnmarshalBytes(src []byte) {
	r.Renamed.UnmarshalUnsafe(src)
	src = src[r.Renamed.SizeBytes():]
	r.NewDir.UnmarshalUnsafe(src)
	src = src[r.NewDir.SizeBytes():]
	r.NewName.UnmarshalBytes(src)
}

// Getdents64Req is used to make Getdents64 requests.
//
// +marshal
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
}

// 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
}

// 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) {
	d.Ino.MarshalUnsafe(dst)
	dst = dst[d.Ino.SizeBytes():]
	d.DevMinor.MarshalUnsafe(dst)
	dst = dst[d.DevMinor.SizeBytes():]
	d.DevMajor.MarshalUnsafe(dst)
	dst = dst[d.DevMajor.SizeBytes():]
	d.Off.MarshalUnsafe(dst)
	dst = dst[d.Off.SizeBytes():]
	d.Type.MarshalUnsafe(dst)
	dst = dst[d.Type.SizeBytes():]
	d.Name.MarshalBytes(dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (d *Dirent64) UnmarshalBytes(src []byte) {
	d.Ino.UnmarshalUnsafe(src)
	src = src[d.Ino.SizeBytes():]
	d.DevMinor.UnmarshalUnsafe(src)
	src = src[d.DevMinor.SizeBytes():]
	d.DevMajor.UnmarshalUnsafe(src)
	src = src[d.DevMajor.SizeBytes():]
	d.Off.UnmarshalUnsafe(src)
	src = src[d.Off.SizeBytes():]
	d.Type.UnmarshalUnsafe(src)
	src = src[d.Type.SizeBytes():]
	d.Name.UnmarshalBytes(src)
}

// Getdents64Resp is used to communicate getdents64 results.
type Getdents64Resp struct {
	Dirents []Dirent64
}

// SizeBytes implements marshal.Marshallable.SizeBytes.
func (g *Getdents64Resp) SizeBytes() int {
	ret := (*primitive.Uint32)(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) {
	numDirents := primitive.Uint32(len(g.Dirents))
	numDirents.MarshalUnsafe(dst)
	dst = dst[numDirents.SizeBytes():]
	for i := range g.Dirents {
		g.Dirents[i].MarshalBytes(dst)
		dst = dst[g.Dirents[i].SizeBytes():]
	}
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (g *Getdents64Resp) UnmarshalBytes(src []byte) {
	var numDirents primitive.Uint32
	numDirents.UnmarshalUnsafe(src)
	if cap(g.Dirents) < int(numDirents) {
		g.Dirents = make([]Dirent64, numDirents)
	} else {
		g.Dirents = g.Dirents[:numDirents]
	}

	src = src[numDirents.SizeBytes():]
	for i := range g.Dirents {
		g.Dirents[i].UnmarshalBytes(src)
		src = src[g.Dirents[i].SizeBytes():]
	}
}

// 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
}

// 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) {
	g.FD.MarshalUnsafe(dst)
	dst = dst[g.FD.SizeBytes():]
	g.BufSize.MarshalUnsafe(dst)
	dst = dst[g.BufSize.SizeBytes():]
	g.Name.MarshalBytes(dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (g *FGetXattrReq) UnmarshalBytes(src []byte) {
	g.FD.UnmarshalUnsafe(src)
	src = src[g.FD.SizeBytes():]
	g.BufSize.UnmarshalUnsafe(src)
	src = src[g.BufSize.SizeBytes():]
	g.Name.UnmarshalBytes(src)
}

// FGetXattrResp is used to respond to FGetXattr request.
type FGetXattrResp struct {
	Value SizedString
}

// 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) {
	g.Value.MarshalBytes(dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (g *FGetXattrResp) UnmarshalBytes(src []byte) {
	g.Value.UnmarshalBytes(src)
}

// FSetXattrReq is used to make FSetXattr requests. It has no response.
type FSetXattrReq struct {
	FD    FDID
	Flags primitive.Uint32
	Name  SizedString
	Value SizedString
}

// 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) {
	s.FD.MarshalUnsafe(dst)
	dst = dst[s.FD.SizeBytes():]
	s.Flags.MarshalUnsafe(dst)
	dst = dst[s.Flags.SizeBytes():]
	s.Name.MarshalBytes(dst)
	dst = dst[s.Name.SizeBytes():]
	s.Value.MarshalBytes(dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (s *FSetXattrReq) UnmarshalBytes(src []byte) {
	s.FD.UnmarshalUnsafe(src)
	src = src[s.FD.SizeBytes():]
	s.Flags.UnmarshalUnsafe(src)
	src = src[s.Flags.SizeBytes():]
	s.Name.UnmarshalBytes(src)
	src = src[s.Name.SizeBytes():]
	s.Value.UnmarshalBytes(src)
}

// FRemoveXattrReq is used to make FRemoveXattr requests. It has no response.
type FRemoveXattrReq struct {
	FD   FDID
	Name SizedString
}

// 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) {
	r.FD.MarshalUnsafe(dst)
	dst = dst[r.FD.SizeBytes():]
	r.Name.MarshalBytes(dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (r *FRemoveXattrReq) UnmarshalBytes(src []byte) {
	r.FD.UnmarshalUnsafe(src)
	src = src[r.FD.SizeBytes():]
	r.Name.UnmarshalBytes(src)
}

// FListXattrReq is used to make FListXattr requests.
//
// +marshal
type FListXattrReq struct {
	FD   FDID
	_    uint32
	Size uint64
}

// FListXattrResp is used to respond to FListXattr requests.
type FListXattrResp struct {
	Xattrs StringArray
}

// 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) {
	l.Xattrs.MarshalBytes(dst)
}

// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
func (l *FListXattrResp) UnmarshalBytes(src []byte) {
	l.Xattrs.UnmarshalBytes(src)
}