feat: full NFSv4.2 server and client in pure Go
Test / test (push) Successful in 2m4s
Release / gates (push) Successful in 2m5s
Release / build (amd64, freebsd) (push) Successful in 1m27s
Release / build (amd64, linux) (push) Successful in 1m22s
Release / build (amd64, netbsd) (push) Successful in 1m19s
Release / build (amd64, openbsd) (push) Successful in 1m20s
Release / build (arm64, darwin) (push) Successful in 1m21s
Release / build (arm64, freebsd) (push) Successful in 1m26s
Release / build (arm64, linux) (push) Successful in 1m25s
Release / build (arm64, netbsd) (push) Successful in 1m31s
Release / build (arm64, openbsd) (push) Successful in 1m27s
Release / build (loong64, linux) (push) Successful in 1m37s
Release / build (riscv64, linux) (push) Successful in 1m21s
Release / release (push) Successful in 40s

Assisted-by: GLM 5.3 Flash
This commit is contained in:
2026-09-21 18:51:17 +02:00
commit a9b8039ef7
153 changed files with 34403 additions and 0 deletions
+118
View File
@@ -0,0 +1,118 @@
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
// SPDX-License-Identifier: MIT
// The codecs of the remaining NFSv4.1 operations: the parent lookups, the
// attribute comparisons, the lock owner release and the session binding
// family.
package nfs4
import (
"sourcedock.dev/petrbalvin/nfs/internal/xdr"
)
// Connection direction and binding values of the CREATE_SESSION and
// BIND_CONN_TO_SESSION channel directory, RFC 8881 section 2.10.1.
const (
Cdfc4Fore = 1
Cdfc4Back = 2
Cdfc4ForeOrBoth = 3
Cdfc4BackOrBoth = 7
Cdfs4Fore = 1
Cdfs4Back = 2
Cdfs4Both = 3
Cdfs4Arrow = 4
)
// AppendLookupp appends the LOOKUPP argop, which carries no arguments.
func AppendLookupp(b []byte) []byte {
return xdr.AppendUint32(b, OpLookupp)
}
// AppendPutPubfh appends the PUTPUBFH argop, which carries no arguments.
func AppendPutPubfh(b []byte) []byte {
return xdr.AppendUint32(b, OpPutPubfh)
}
// AppendVerifyArgs appends the VERIFY argop: the attributes the file must
// carry for the compound to proceed. NVERIFY shares the shape and demands
// the opposite.
func AppendVerifyArgs(b []byte, request Bitmap, a Attrs) []byte {
b = xdr.AppendUint32(b, OpVerify)
return AppendFattr(b, request, a)
}
// AppendNverifyArgs appends the NVERIFY argop: the attributes the file
// must not carry.
func AppendNverifyArgs(b []byte, request Bitmap, a Attrs) []byte {
b = xdr.AppendUint32(b, OpNverify)
return AppendFattr(b, request, a)
}
// AppendReleaseLockOwnerArgs appends the RELEASE_LOCKOWNER argop: the
// client whose lock owner dies and the owner itself.
func AppendReleaseLockOwnerArgs(b []byte, clientid uint64, owner []byte) []byte {
b = xdr.AppendUint32(b, OpReleaseLockOwner)
b = xdr.AppendUint64(b, clientid)
return xdr.AppendVarOpaque(b, owner)
}
// AppendDelegReturnArgs appends the DELEGRETURN argop: the stateid of the
// delegation the client gives back.
func AppendDelegReturnArgs(b []byte, st Stateid) []byte {
b = xdr.AppendUint32(b, OpDelegReturn)
return st.Append(b)
}
// AppendBackchannelCtlArgs appends the BACKCHANNEL_CTL argop: the program
// number of the back channel the client runs.
func AppendBackchannelCtlArgs(b []byte, program uint32) []byte {
b = xdr.AppendUint32(b, OpBackchannelCtl)
return xdr.AppendUint32(b, program)
}
// AppendBindConnToSessionArgs appends the BIND_CONN_TO_SESSION argop of
// RFC 7863: the session, the direction the connection should serve and
// the RDMA mode flag.
func AppendBindConnToSessionArgs(b []byte, id SessionID, dir uint32, rdma bool) []byte {
b = xdr.AppendUint32(b, OpBindConnToSession)
b = append(b, id[:]...)
b = xdr.AppendUint32(b, dir)
return xdr.AppendBool(b, rdma)
}
// AppendBindConnToSessionRes appends the result: the session and the
// direction the server granted.
func AppendBindConnToSessionRes(b []byte, id SessionID, dir uint32) []byte {
b = append(b, id[:]...)
return xdr.AppendUint32(b, dir)
}
// AppendFreeStateidArgs appends the FREE_STATEID argop: the lock stateid
// the client retires.
func AppendFreeStateidArgs(b []byte, st Stateid) []byte {
b = xdr.AppendUint32(b, OpFreeStateid)
return st.Append(b)
}
// AppendTestStateidArgs appends the TEST_STATEID argop: the stateids the
// client asks about.
func AppendTestStateidArgs(b []byte, sts []Stateid) []byte {
b = xdr.AppendUint32(b, OpTestStateid)
b = xdr.AppendUint32(b, uint32(len(sts)))
for _, st := range sts {
b = st.Append(b)
}
return b
}
// AppendTestStateidRes appends the result: one status per stateid, in the
// order the arguments named them.
func AppendTestStateidRes(b []byte, statuses []uint32) []byte {
b = xdr.AppendUint32(b, uint32(len(statuses)))
for _, s := range statuses {
b = xdr.AppendUint32(b, s)
}
return b
}