Files

285 lines
9.4 KiB
Go
Raw Permalink Normal View History

// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
// SPDX-License-Identifier: MIT
// The wire codecs of the NFSv4.2 operations, RFC 7862, with the shapes
// taken from the XDR of RFC 7863.
package nfs4
import (
"sourcedock.dev/petrbalvin/nfs/internal/xdr"
)
// Content types of the data_content4 enum, RFC 7862 section 8.2.
const (
ContentData = 0
ContentHole = 1
)
// Error codes the copy family answers with, RFC 7862 section 15.1.
const (
ErrOffloadDenied = 10091
ErrOffloadNoReqs = 10094
NfsSyncNothing = 0
NfsSyncDataSync = 1
NfsSyncFileSync = 2
OffloadNotReq = 0
OffloadSuccess = 1
OffloadDenied = 2
OffloadFatal = 3
OffloadNoFallback = 4
)
// AppendSeekArgs encodes the SEEK argop: the stateid, the offset and the
// content kind the client searches for.
func AppendSeekArgs(b []byte, st Stateid, offset uint64, what uint32) []byte {
b = xdr.AppendUint32(b, OpSeek)
b = st.Append(b)
b = xdr.AppendUint64(b, offset)
return xdr.AppendUint32(b, what)
}
// AppendSeekRes encodes a successful SEEK result: the end of file flag
// and the offset of the next content of the requested kind.
func AppendSeekRes(b []byte, eof bool, offset uint64) []byte {
b = xdr.AppendBool(b, eof)
return xdr.AppendUint64(b, offset)
}
// AppendAllocateArgs encodes the ALLOCATE argop: the reserved range.
func AppendAllocateArgs(b []byte, st Stateid, offset, length uint64) []byte {
b = xdr.AppendUint32(b, OpAllocate)
b = st.Append(b)
b = xdr.AppendUint64(b, offset)
return xdr.AppendUint64(b, length)
}
// AppendDeallocateArgs encodes the DEALLOCATE argop: the released range.
func AppendDeallocateArgs(b []byte, st Stateid, offset, length uint64) []byte {
b = xdr.AppendUint32(b, OpDeallocate)
b = st.Append(b)
b = xdr.AppendUint64(b, offset)
return xdr.AppendUint64(b, length)
}
// AppendIoAdviseArgs encodes the IO_ADVISE argop: the range and the hint
// bitmap.
func AppendIoAdviseArgs(b []byte, st Stateid, offset, length uint64, hints Bitmap) []byte {
b = xdr.AppendUint32(b, OpIoAdvise)
b = st.Append(b)
b = xdr.AppendUint64(b, offset)
b = xdr.AppendUint64(b, length)
return hints.AppendTo(b)
}
// AppendIoAdviseRes encodes a successful IO_ADVISE result: the hints the
// server accepted.
func AppendIoAdviseRes(b []byte, hints Bitmap) []byte {
return hints.AppendTo(b)
}
// A CopySourceServer is one netloc4 of the COPY argument list: the
// servers the source lives on.
type CopySourceServer struct {
Type uint32
Name string
Addr NetAddr
}
// AppendCopyArgs encodes the COPY argop: the source and destination
// stateids, the ranges and the source server list.
func AppendCopyArgs(b []byte, src, dst Stateid, srcOff, dstOff, count uint64, consecutive, synchronous bool, sources []CopySourceServer) []byte {
b = xdr.AppendUint32(b, OpCopy)
b = src.Append(b)
b = dst.Append(b)
b = xdr.AppendUint64(b, srcOff)
b = xdr.AppendUint64(b, dstOff)
b = xdr.AppendUint64(b, count)
b = xdr.AppendBool(b, consecutive)
b = xdr.AppendBool(b, synchronous)
b = xdr.AppendUint32(b, uint32(len(sources)))
for _, s := range sources {
b = xdr.AppendUint32(b, s.Type)
switch s.Type {
case 1, 2:
b = xdr.AppendString(b, s.Name)
case 3:
b = xdr.AppendString(b, s.Addr.Netid)
b = xdr.AppendString(b, s.Addr.Uaddr)
}
}
return b
}
// AppendWriteResponse encodes the write_response4 the copy family
// answers with.
func AppendWriteResponse(b []byte, callbackSt Stateid, callbackSet bool, count uint64, committed uint32, verifier [8]byte) []byte {
if callbackSet {
b = xdr.AppendUint32(b, 1)
b = callbackSt.Append(b)
} else {
b = xdr.AppendUint32(b, 0)
}
b = xdr.AppendUint64(b, count)
b = xdr.AppendUint32(b, committed)
return append(b, verifier[:]...)
}
// AppendCopyRes encodes a successful COPY result: the write response and
// the requirements the server met.
func AppendCopyRes(b []byte, callbackSt Stateid, callbackSet bool, count uint64, committed uint32, verifier [8]byte, consecutive, synchronous bool) []byte {
b = AppendWriteResponse(b, callbackSt, callbackSet, count, committed, verifier)
b = xdr.AppendBool(b, consecutive)
return xdr.AppendBool(b, synchronous)
}
// AppendCopyNotifyArgs encodes the COPY_NOTIFY argop: the source stateid
// and the destination the client copies to.
func AppendCopyNotifyArgs(b []byte, st Stateid, dstType uint32, dstName string, dstAddr NetAddr) []byte {
b = xdr.AppendUint32(b, OpCopyNotify)
b = st.Append(b)
b = xdr.AppendUint32(b, dstType)
switch dstType {
case 1, 2:
b = xdr.AppendString(b, dstName)
case 3:
b = xdr.AppendString(b, dstAddr.Netid)
b = xdr.AppendString(b, dstAddr.Uaddr)
}
return b
}
// AppendCopyNotifyRes encodes a successful COPY_NOTIFY result: the lease
// the authorization lives, the stateid naming it and the source servers.
func AppendCopyNotifyRes(b []byte, leaseSeconds int64, st Stateid, sources []CopySourceServer) []byte {
b = xdr.AppendInt64(b, leaseSeconds)
b = xdr.AppendUint32(b, 0)
b = st.Append(b)
b = xdr.AppendUint32(b, uint32(len(sources)))
for _, s := range sources {
b = xdr.AppendUint32(b, s.Type)
switch s.Type {
case 1, 2:
b = xdr.AppendString(b, s.Name)
case 3:
b = xdr.AppendString(b, s.Addr.Netid)
b = xdr.AppendString(b, s.Addr.Uaddr)
}
}
return b
}
// AppendOffloadCancelArgs encodes the OFFLOAD_CANCEL argop: the stateid
// of the copy to abandon.
func AppendOffloadCancelArgs(b []byte, st Stateid) []byte {
b = xdr.AppendUint32(b, OpOffloadCancel)
return st.Append(b)
}
// AppendOffloadStatusArgs encodes the OFFLOAD_STATUS argop: the stateid
// of the copy in flight.
func AppendOffloadStatusArgs(b []byte, st Stateid) []byte {
b = xdr.AppendUint32(b, OpOffloadStatus)
return st.Append(b)
}
// AppendOffloadStatusRes encodes a successful OFFLOAD_STATUS result: the
// bytes copied so far and the completion code.
func AppendOffloadStatusRes(b []byte, count uint64, complete uint32) []byte {
b = xdr.AppendUint64(b, count)
return xdr.AppendUint32(b, complete)
}
// AppendCloneArgs encodes the CLONE argop: the ranges of the clone. The
// saved file handle is the source, the current one the destination.
func AppendCloneArgs(b []byte, src, dst Stateid, srcOff, dstOff, count uint64) []byte {
b = xdr.AppendUint32(b, OpClone)
b = src.Append(b)
b = dst.Append(b)
b = xdr.AppendUint64(b, srcOff)
b = xdr.AppendUint64(b, dstOff)
return xdr.AppendUint64(b, count)
}
// AppendLayoutErrorArgs encodes the LAYOUTERROR argop: the failing range
// and one error per device.
func AppendLayoutErrorArgs(b []byte, offset, length uint64, st Stateid, device [16]byte, status, opnum uint32) []byte {
b = xdr.AppendUint32(b, OpLayoutError)
b = xdr.AppendUint64(b, offset)
b = xdr.AppendUint64(b, length)
b = st.Append(b)
b = xdr.AppendUint32(b, 1)
b = append(b, device[:]...)
b = xdr.AppendUint32(b, status)
return xdr.AppendUint32(b, opnum)
}
// AppendLayoutStatsArgs encodes the LAYOUTSTATS argop: the reported range
// and the IO counters of the data server.
func AppendLayoutStatsArgs(b []byte, offset, length uint64, st Stateid, readCount, readBytes, writeCount, writeBytes uint64, device [16]byte, updateType uint32, updateBody []byte) []byte {
b = xdr.AppendUint32(b, OpLayoutStats)
b = xdr.AppendUint64(b, offset)
b = xdr.AppendUint64(b, length)
b = st.Append(b)
b = xdr.AppendUint64(b, readCount)
b = xdr.AppendUint64(b, readBytes)
b = xdr.AppendUint64(b, writeCount)
b = xdr.AppendUint64(b, writeBytes)
b = append(b, device[:]...)
b = xdr.AppendUint32(b, updateType)
return xdr.AppendVarOpaque(b, updateBody)
}
// AppendReadPlusArgs encodes the READ_PLUS argop: the range to read.
func AppendReadPlusArgs(b []byte, st Stateid, offset uint64, count uint32) []byte {
b = xdr.AppendUint32(b, OpReadPlus)
b = st.Append(b)
b = xdr.AppendUint64(b, offset)
return xdr.AppendUint32(b, count)
}
// AppendReadPlusDataRes encodes a successful READ_PLUS result that
// carries one data segment.
func AppendReadPlusDataRes(b []byte, eof bool, offset uint64, data []byte) []byte {
b = xdr.AppendBool(b, eof)
b = xdr.AppendUint32(b, 1)
b = xdr.AppendUint32(b, ContentData)
b = xdr.AppendUint64(b, offset)
return xdr.AppendVarOpaque(b, data)
}
// AppendReadPlusHoleRes encodes a successful READ_PLUS result that
// reports a hole.
func AppendReadPlusHoleRes(b []byte, eof bool, offset, length uint64) []byte {
b = xdr.AppendBool(b, eof)
b = xdr.AppendUint32(b, 1)
b = xdr.AppendUint32(b, ContentHole)
b = xdr.AppendUint64(b, offset)
return xdr.AppendUint64(b, length)
}
// AppendWriteSameArgs encodes the WRITE_SAME argop: the stateid, the
// stability and the application data block to write. The block number
// is a count4 on the wire, RFC 7862 section 15.8.
func AppendWriteSameArgs(b []byte, st Stateid, stable uint32, offset, blockSize, blockCount, relOffBlocknum uint64, blockNum uint32, relOffPattern uint64, pattern []byte) []byte {
b = xdr.AppendUint32(b, OpWriteSame)
b = st.Append(b)
b = xdr.AppendUint32(b, stable)
b = xdr.AppendUint64(b, offset)
b = xdr.AppendUint64(b, blockSize)
b = xdr.AppendUint64(b, blockCount)
b = xdr.AppendUint64(b, relOffBlocknum)
b = xdr.AppendUint32(b, blockNum)
b = xdr.AppendUint64(b, relOffPattern)
return xdr.AppendVarOpaque(b, pattern)
}
// AppendWriteSameRes encodes a successful WRITE_SAME result: the write
// response alone.
func AppendWriteSameRes(b []byte, count uint64, committed uint32, verifier [8]byte) []byte {
b = xdr.AppendUint32(b, 0)
b = xdr.AppendUint64(b, count)
b = xdr.AppendUint32(b, committed)
return append(b, verifier[:]...)
}